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