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