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 namespace {
22
23 struct FormatPlaneLayout {
24 uint32_t horizontalSubsampling = 1;
25 uint32_t verticalSubsampling = 1;
26 uint32_t sampleIncrementBytes = 0;
27 VkImageAspectFlags aspectMask = 0;
28 };
29
30 struct FormatPlaneLayouts {
31 uint32_t horizontalAlignmentPixels = 1;
32 std::vector<FormatPlaneLayout> planeLayouts;
33 };
34
getFormatPlaneLayoutsMap()35 const std::unordered_map<VkFormat, FormatPlaneLayouts>& getFormatPlaneLayoutsMap() {
36 static const auto* kPlaneLayoutsMap = []() {
37 auto* map = new std::unordered_map<VkFormat, FormatPlaneLayouts>({
38 {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
39 {
40 .horizontalAlignmentPixels = 2,
41 .planeLayouts =
42 {
43 {
44 .horizontalSubsampling = 1,
45 .verticalSubsampling = 1,
46 .sampleIncrementBytes = 2,
47 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT,
48 },
49 {
50 .horizontalSubsampling = 2,
51 .verticalSubsampling = 2,
52 .sampleIncrementBytes = 4,
53 .aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT,
54 },
55 },
56 }},
57 {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
58 {
59 .horizontalAlignmentPixels = 2,
60 .planeLayouts =
61 {
62 {
63 .horizontalSubsampling = 1,
64 .verticalSubsampling = 1,
65 .sampleIncrementBytes = 1,
66 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT,
67 },
68 {
69 .horizontalSubsampling = 2,
70 .verticalSubsampling = 2,
71 .sampleIncrementBytes = 2,
72 .aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT,
73 },
74 },
75 }},
76 {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
77 {
78 .horizontalAlignmentPixels = 32,
79 .planeLayouts =
80 {
81 {
82 .horizontalSubsampling = 1,
83 .verticalSubsampling = 1,
84 .sampleIncrementBytes = 1,
85 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT,
86 },
87 {
88 .horizontalSubsampling = 2,
89 .verticalSubsampling = 2,
90 .sampleIncrementBytes = 1,
91 .aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT,
92 },
93 {
94 .horizontalSubsampling = 2,
95 .verticalSubsampling = 2,
96 .sampleIncrementBytes = 1,
97 .aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT,
98 },
99 },
100 }},
101 });
102
103 #define ADD_SINGLE_PLANE_FORMAT_INFO(format, bpp) \
104 (*map)[format] = FormatPlaneLayouts{ \
105 .horizontalAlignmentPixels = 1, \
106 .planeLayouts = \
107 { \
108 { \
109 .horizontalSubsampling = 1, \
110 .verticalSubsampling = 1, \
111 .sampleIncrementBytes = bpp, \
112 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, \
113 }, \
114 }, \
115 };
116 LIST_VK_FORMATS_LINEAR(ADD_SINGLE_PLANE_FORMAT_INFO)
117 #undef ADD_SINGLE_PLANE_FORMAT_INFO
118
119 return map;
120 }();
121 return *kPlaneLayoutsMap;
122 }
123
alignToPower2(uint32_t val,uint32_t align)124 inline uint32_t alignToPower2(uint32_t val, uint32_t align) {
125 return (val + (align - 1)) & ~(align - 1);
126 }
127
128 } // namespace
129
getFormatPlaneLayouts(VkFormat format)130 const FormatPlaneLayouts* getFormatPlaneLayouts(VkFormat format) {
131 const auto& formatPlaneLayoutsMap = getFormatPlaneLayoutsMap();
132
133 auto it = formatPlaneLayoutsMap.find(format);
134 if (it == formatPlaneLayoutsMap.end()) {
135 return nullptr;
136 }
137 return &it->second;
138 }
139
getFormatTransferInfo(VkFormat format,uint32_t width,uint32_t height,VkDeviceSize * outStagingBufferCopySize,std::vector<VkBufferImageCopy> * outBufferImageCopies)140 bool getFormatTransferInfo(VkFormat format, uint32_t width, uint32_t height,
141 VkDeviceSize* outStagingBufferCopySize,
142 std::vector<VkBufferImageCopy>* outBufferImageCopies) {
143 const FormatPlaneLayouts* formatInfo = getFormatPlaneLayouts(format);
144 if (formatInfo == nullptr) {
145 ERR("Unhandled format: %s", string_VkFormat(format));
146 return false;
147 }
148
149 const uint32_t alignedWidth = alignToPower2(width, formatInfo->horizontalAlignmentPixels);
150 const uint32_t alignedHeight = height;
151 uint32_t cumulativeOffset = 0;
152 uint32_t cumulativeSize = 0;
153 for (const FormatPlaneLayout& planeInfo : formatInfo->planeLayouts) {
154 const uint32_t planeOffset = cumulativeOffset;
155 const uint32_t planeWidth = alignedWidth / planeInfo.horizontalSubsampling;
156 const uint32_t planeHeight = alignedHeight / planeInfo.verticalSubsampling;
157 const uint32_t planeBpp = planeInfo.sampleIncrementBytes;
158 const uint32_t planeStrideTexels = planeWidth;
159 const uint32_t planeStrideBytes = planeStrideTexels * planeBpp;
160 const uint32_t planeSize = planeHeight * planeStrideBytes;
161 if (outBufferImageCopies) {
162 outBufferImageCopies->emplace_back(VkBufferImageCopy{
163 .bufferOffset = planeOffset,
164 .bufferRowLength = planeStrideTexels,
165 .bufferImageHeight = 0,
166 .imageSubresource =
167 {
168 .aspectMask = planeInfo.aspectMask,
169 .mipLevel = 0,
170 .baseArrayLayer = 0,
171 .layerCount = 1,
172 },
173 .imageOffset =
174 {
175 .x = 0,
176 .y = 0,
177 .z = 0,
178 },
179 .imageExtent =
180 {
181 .width = planeWidth,
182 .height = planeHeight,
183 .depth = 1,
184 },
185 });
186 }
187 cumulativeOffset += planeSize;
188 cumulativeSize += planeSize;
189 }
190 if (outStagingBufferCopySize) {
191 *outStagingBufferCopySize = cumulativeSize;
192 }
193
194 return true;
195 }
196
197 } // namespace vk
198 } // namespace gfxstream
199