1 // Copyright 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expresso or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "VkFormatUtils.h"
16
17 #include <unordered_map>
18
19 namespace gfxstream {
20 namespace vk {
21 #include "host-common/logging.h"
22 #include "vulkan/vk_enum_string_helper.h"
23
24 namespace {
25
26 struct FormatPlaneLayout {
27 uint32_t horizontalSubsampling = 1;
28 uint32_t verticalSubsampling = 1;
29 uint32_t sampleIncrementBytes = 0;
30 VkImageAspectFlags aspectMask = 0;
31 };
32
33 struct FormatPlaneLayouts {
34 uint32_t horizontalAlignmentPixels = 1;
35 std::vector<FormatPlaneLayout> planeLayouts;
36 };
37
getFormatPlaneLayoutsMap()38 const std::unordered_map<VkFormat, FormatPlaneLayouts>& getFormatPlaneLayoutsMap() {
39 static const auto* kPlaneLayoutsMap = []() {
40 auto* map = new std::unordered_map<VkFormat, FormatPlaneLayouts>({
41 {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
42 {
43 .horizontalAlignmentPixels = 2,
44 .planeLayouts =
45 {
46 {
47 .horizontalSubsampling = 1,
48 .verticalSubsampling = 1,
49 .sampleIncrementBytes = 2,
50 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT,
51 },
52 {
53 .horizontalSubsampling = 2,
54 .verticalSubsampling = 2,
55 .sampleIncrementBytes = 4,
56 .aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT,
57 },
58 },
59 }},
60 {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
61 {
62 .horizontalAlignmentPixels = 2,
63 .planeLayouts =
64 {
65 {
66 .horizontalSubsampling = 1,
67 .verticalSubsampling = 1,
68 .sampleIncrementBytes = 1,
69 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT,
70 },
71 {
72 .horizontalSubsampling = 2,
73 .verticalSubsampling = 2,
74 .sampleIncrementBytes = 2,
75 .aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT,
76 },
77 },
78 }},
79 {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
80 {
81 .horizontalAlignmentPixels = 1,
82 .planeLayouts =
83 {
84 {
85 .horizontalSubsampling = 1,
86 .verticalSubsampling = 1,
87 .sampleIncrementBytes = 1,
88 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT,
89 },
90 {
91 .horizontalSubsampling = 2,
92 .verticalSubsampling = 2,
93 .sampleIncrementBytes = 1,
94 .aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT,
95 },
96 {
97 .horizontalSubsampling = 2,
98 .verticalSubsampling = 2,
99 .sampleIncrementBytes = 1,
100 .aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT,
101 },
102 },
103 }},
104 });
105
106 #define ADD_SINGLE_PLANE_FORMAT_INFO(format, bpp) \
107 (*map)[format] = FormatPlaneLayouts{ \
108 .horizontalAlignmentPixels = 1, \
109 .planeLayouts = \
110 { \
111 { \
112 .horizontalSubsampling = 1, \
113 .verticalSubsampling = 1, \
114 .sampleIncrementBytes = bpp, \
115 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, \
116 }, \
117 }, \
118 };
119 LIST_VK_FORMATS_LINEAR(ADD_SINGLE_PLANE_FORMAT_INFO)
120 #undef ADD_SINGLE_PLANE_FORMAT_INFO
121
122 return map;
123 }();
124 return *kPlaneLayoutsMap;
125 }
126
alignToPower2(uint32_t val,uint32_t align)127 inline uint32_t alignToPower2(uint32_t val, uint32_t align) {
128 return (val + (align - 1)) & ~(align - 1);
129 }
130
131 } // namespace
132
getFormatPlaneLayouts(VkFormat format)133 const FormatPlaneLayouts* getFormatPlaneLayouts(VkFormat format) {
134 const auto& formatPlaneLayoutsMap = getFormatPlaneLayoutsMap();
135
136 auto it = formatPlaneLayoutsMap.find(format);
137 if (it == formatPlaneLayoutsMap.end()) {
138 return nullptr;
139 }
140 return &it->second;
141 }
142
getFormatTransferInfo(VkFormat format,uint32_t width,uint32_t height,VkDeviceSize * outStagingBufferCopySize,std::vector<VkBufferImageCopy> * outBufferImageCopies)143 bool getFormatTransferInfo(VkFormat format, uint32_t width, uint32_t height,
144 VkDeviceSize* outStagingBufferCopySize,
145 std::vector<VkBufferImageCopy>* outBufferImageCopies) {
146 const FormatPlaneLayouts* formatInfo = getFormatPlaneLayouts(format);
147 if (formatInfo == nullptr) {
148 ERR("Unhandled format: %s", string_VkFormat(format));
149 return false;
150 }
151
152 const uint32_t alignedWidth = alignToPower2(width, formatInfo->horizontalAlignmentPixels);
153 const uint32_t alignedHeight = height;
154 uint32_t cumulativeOffset = 0;
155 uint32_t cumulativeSize = 0;
156 for (const FormatPlaneLayout& planeInfo : formatInfo->planeLayouts) {
157 const uint32_t planeOffset = cumulativeOffset;
158 const uint32_t planeWidth = alignedWidth / planeInfo.horizontalSubsampling;
159 const uint32_t planeHeight = alignedHeight / planeInfo.verticalSubsampling;
160 const uint32_t planeBpp = planeInfo.sampleIncrementBytes;
161 const uint32_t planeStrideTexels = planeWidth;
162 const uint32_t planeStrideBytes = planeStrideTexels * planeBpp;
163 const uint32_t planeSize = planeHeight * planeStrideBytes;
164 if (outBufferImageCopies) {
165 outBufferImageCopies->emplace_back(VkBufferImageCopy{
166 .bufferOffset = planeOffset,
167 .bufferRowLength = planeStrideTexels,
168 .bufferImageHeight = 0,
169 .imageSubresource =
170 {
171 .aspectMask = planeInfo.aspectMask,
172 .mipLevel = 0,
173 .baseArrayLayer = 0,
174 .layerCount = 1,
175 },
176 .imageOffset =
177 {
178 .x = 0,
179 .y = 0,
180 .z = 0,
181 },
182 .imageExtent =
183 {
184 .width = planeWidth,
185 .height = planeHeight,
186 .depth = 1,
187 },
188 });
189 }
190 cumulativeOffset += planeSize;
191 cumulativeSize += planeSize;
192 }
193 if (outStagingBufferCopySize) {
194 *outStagingBufferCopySize = cumulativeSize;
195 }
196
197 return true;
198 }
199
200 } // namespace vk
201 } // namespace gfxstream
202