• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "CompressedImageInfo.h"
16 
17 #include "aemu/base/ArraySize.h"
18 #include "stream-servers/vulkan/VkFormatUtils.h"
19 #include "stream-servers/vulkan/emulated_textures/shaders/DecompressionShaders.h"
20 
21 namespace gfxstream {
22 namespace vk {
23 namespace {
24 
25 #define _RETURN_ON_FAILURE(cmd)                                                                \
26     {                                                                                          \
27         VkResult result = cmd;                                                                 \
28         if (result != VK_SUCCESS) {                                                            \
29             WARN("Warning: %s %s:%d vulkan failure %d", __func__, __FILE__, __LINE__, result); \
30             return result;                                                                     \
31         }                                                                                      \
32     }
33 
34 using android::base::arraySize;
35 
36 struct Etc2PushConstant {
37     uint32_t compFormat;
38     uint32_t baseLayer;
39 };
40 
41 struct AstcPushConstant {
42     uint32_t blockSize[2];
43     uint32_t baseLayer;
44     uint32_t smallBlock;
45 };
46 
47 struct ShaderData {
48     const uint32_t* code;  // Pointer to shader's compiled spir-v code
49     const size_t size;     // size of the code in bytes
50 };
51 
52 struct ShaderGroup {
53     ShaderData shader1D;
54     ShaderData shader2D;
55     ShaderData shader3D;
56 };
57 
58 // Helper macro to declare the shader goups
59 #define DECLARE_SHADER_GROUP(Format)                                      \
60     constexpr ShaderGroup kShader##Format {                               \
61         .shader1D = {.code = decompression_shaders::Format##_1D,          \
62                      .size = sizeof(decompression_shaders::Format##_1D)}, \
63         .shader2D = {.code = decompression_shaders::Format##_2D,          \
64                      .size = sizeof(decompression_shaders::Format##_2D)}, \
65         .shader3D = {.code = decompression_shaders::Format##_3D,          \
66                      .size = sizeof(decompression_shaders::Format##_3D)}, \
67     }
68 
69 DECLARE_SHADER_GROUP(Astc);
70 DECLARE_SHADER_GROUP(EacR11Snorm);
71 DECLARE_SHADER_GROUP(EacR11Unorm);
72 DECLARE_SHADER_GROUP(EacRG11Snorm);
73 DECLARE_SHADER_GROUP(EacRG11Unorm);
74 DECLARE_SHADER_GROUP(Etc2RGB8);
75 DECLARE_SHADER_GROUP(Etc2RGBA8);
76 
77 #undef DECLARE_SHADER_GROUP
78 
79 // Returns the group of shaders that can decompress a given format, or null if none is found.
getShaderGroup(VkFormat format)80 const ShaderGroup* getShaderGroup(VkFormat format) {
81     switch (format) {
82         case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
83         case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
84         case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
85         case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
86         case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
87         case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
88         case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
89         case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
90         case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
91         case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
92         case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
93         case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
94         case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
95         case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
96         case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
97         case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
98         case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
99         case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
100         case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
101         case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
102         case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
103         case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
104         case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
105         case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
106         case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
107         case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
108         case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
109         case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
110             return &kShaderAstc;
111 
112         case VK_FORMAT_EAC_R11_SNORM_BLOCK:
113             return &kShaderEacR11Snorm;
114 
115         case VK_FORMAT_EAC_R11_UNORM_BLOCK:
116             return &kShaderEacR11Unorm;
117 
118         case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
119             return &kShaderEacRG11Snorm;
120 
121         case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
122             return &kShaderEacRG11Unorm;
123 
124         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
125         case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
126         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
127         case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
128             return &kShaderEtc2RGB8;
129 
130         case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
131         case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
132             return &kShaderEtc2RGBA8;
133 
134         default:
135             return nullptr;
136     }
137 }
138 
139 // Returns the shader that can decompress a given image format and type
getDecompressionShader(VkFormat format,VkImageType imageType)140 const ShaderData* getDecompressionShader(VkFormat format, VkImageType imageType) {
141     const ShaderGroup* group = getShaderGroup(format);
142     if (!group) return nullptr;
143 
144     switch (imageType) {
145         case VK_IMAGE_TYPE_1D:
146             return &group->shader1D;
147         case VK_IMAGE_TYPE_2D:
148             return &group->shader2D;
149         case VK_IMAGE_TYPE_3D:
150             return &group->shader3D;
151         default:
152             return nullptr;
153     }
154 }
155 
156 // Returns x / y, rounded up. E.g. ceil_div(7, 2) == 4
157 // Note the potential integer overflow for large numbers.
ceil_div(uint32_t x,uint32_t y)158 inline constexpr uint32_t ceil_div(uint32_t x, uint32_t y) { return (x + y - 1) / y; }
159 
createDefaultImageView(VulkanDispatch * vk,VkDevice device,VkImage image,VkFormat format,VkImageType imageType,uint32_t mipLevel,uint32_t layerCount)160 VkImageView createDefaultImageView(VulkanDispatch* vk, VkDevice device, VkImage image,
161                                    VkFormat format, VkImageType imageType, uint32_t mipLevel,
162                                    uint32_t layerCount) {
163     VkImageViewCreateInfo imageViewInfo = {};
164     imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
165     imageViewInfo.image = image;
166     switch (imageType) {
167         case VK_IMAGE_TYPE_1D:
168             imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
169             break;
170         case VK_IMAGE_TYPE_2D:
171             imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
172             break;
173         case VK_IMAGE_TYPE_3D:
174             imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
175             break;
176         default:
177             imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
178             break;
179     }
180     imageViewInfo.format = format;
181     imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
182     imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
183     imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
184     imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
185     imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
186     imageViewInfo.subresourceRange.baseMipLevel = mipLevel;
187     imageViewInfo.subresourceRange.levelCount = 1;
188     imageViewInfo.subresourceRange.baseArrayLayer = 0;
189     imageViewInfo.subresourceRange.layerCount = layerCount;
190     VkImageView imageView;
191     if (vk->vkCreateImageView(device, &imageViewInfo, nullptr, &imageView) != VK_SUCCESS) {
192         WARN("Warning: %s %s:%d failure", __func__, __FILE__, __LINE__);
193         return VK_NULL_HANDLE;
194     }
195     return imageView;
196 }
197 
getBlockSize(VkFormat format)198 VkExtent2D getBlockSize(VkFormat format) {
199     switch (format) {
200         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
201         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
202         case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
203         case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
204         case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
205         case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
206         case VK_FORMAT_EAC_R11_UNORM_BLOCK:
207         case VK_FORMAT_EAC_R11_SNORM_BLOCK:
208         case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
209         case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
210             return {4, 4};
211         case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
212         case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
213             return {4, 4};
214         case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
215         case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
216             return {5, 4};
217         case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
218         case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
219             return {5, 5};
220         case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
221         case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
222             return {6, 5};
223         case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
224         case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
225             return {6, 6};
226         case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
227         case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
228             return {8, 5};
229         case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
230         case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
231             return {8, 6};
232         case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
233         case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
234             return {8, 8};
235         case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
236         case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
237             return {10, 5};
238         case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
239         case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
240             return {10, 6};
241         case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
242         case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
243             return {10, 8};
244         case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
245         case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
246             return {10, 10};
247         case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
248         case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
249             return {12, 10};
250         case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
251         case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
252             return {12, 12};
253         default:
254             return {1, 1};
255     }
256 }
257 
258 // Returns whether a given memory barrier puts the image in a layout where it can be read from.
imageWillBecomeReadable(const VkImageMemoryBarrier & barrier)259 bool imageWillBecomeReadable(const VkImageMemoryBarrier& barrier) {
260     return barrier.oldLayout != VK_IMAGE_LAYOUT_UNDEFINED &&
261            (barrier.newLayout == VK_IMAGE_LAYOUT_GENERAL ||
262             barrier.newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
263             barrier.newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
264 }
265 
266 }  // namespace
267 
CompressedImageInfo(VkDevice device)268 CompressedImageInfo::CompressedImageInfo(VkDevice device) : mDevice(device) {}
269 
CompressedImageInfo(VkDevice device,const VkImageCreateInfo & createInfo)270 CompressedImageInfo::CompressedImageInfo(VkDevice device, const VkImageCreateInfo& createInfo)
271     : mDevice(device),
272       mCompressedFormat(createInfo.format),
273       mDecompressedFormat(getDecompressedFormat(mCompressedFormat)),
274       mCompressedMipmapsFormat(getCompressedMipmapsFormat(mCompressedFormat)),
275       mImageType(createInfo.imageType),
276       mExtent(createInfo.extent),
277       mBlock(getBlockSize(mCompressedFormat)),
278       mLayerCount(createInfo.arrayLayers),
279       mMipLevels(createInfo.mipLevels) {}
280 
281 // static
getDecompressedFormat(VkFormat compFmt)282 VkFormat CompressedImageInfo::getDecompressedFormat(VkFormat compFmt) {
283     switch (compFmt) {
284         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
285         case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
286         case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
287             return VK_FORMAT_R8G8B8A8_UNORM;
288         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
289         case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
290         case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
291             return VK_FORMAT_R8G8B8A8_SRGB;
292         case VK_FORMAT_EAC_R11_UNORM_BLOCK:
293             return VK_FORMAT_R16_UNORM;
294         case VK_FORMAT_EAC_R11_SNORM_BLOCK:
295             return VK_FORMAT_R16_SNORM;
296         case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
297             return VK_FORMAT_R16G16_UNORM;
298         case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
299             return VK_FORMAT_R16G16_SNORM;
300         case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
301         case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
302         case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
303         case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
304         case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
305         case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
306         case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
307         case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
308         case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
309         case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
310         case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
311         case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
312         case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
313         case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
314             return VK_FORMAT_R8G8B8A8_UNORM;
315         case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
316         case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
317         case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
318         case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
319         case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
320         case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
321         case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
322         case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
323         case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
324         case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
325         case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
326         case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
327         case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
328         case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
329             return VK_FORMAT_R8G8B8A8_SRGB;
330         default:
331             return compFmt;
332     }
333 }
334 
335 // static
getCompressedMipmapsFormat(VkFormat compFmt)336 VkFormat CompressedImageInfo::getCompressedMipmapsFormat(VkFormat compFmt) {
337     switch (compFmt) {
338         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
339         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
340         case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
341         case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
342             return VK_FORMAT_R16G16B16A16_UINT;
343         case VK_FORMAT_EAC_R11_UNORM_BLOCK:
344         case VK_FORMAT_EAC_R11_SNORM_BLOCK:
345             return VK_FORMAT_R32G32_UINT;
346         case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
347         case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
348         case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
349         case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
350         case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
351         case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
352         case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
353         case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
354         case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
355         case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
356         case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
357         case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
358         case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
359         case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
360         case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
361         case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
362         case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
363         case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
364         case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
365         case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
366         case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
367         case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
368         case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
369         case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
370         case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
371         case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
372         case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
373         case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
374         case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
375         case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
376         case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
377         case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
378             return VK_FORMAT_R32G32B32A32_UINT;
379         default:
380             return compFmt;
381     }
382 }
383 
384 // static
isEtc2(VkFormat format)385 bool CompressedImageInfo::isEtc2(VkFormat format) {
386     switch (format) {
387         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
388         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
389         case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
390         case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
391         case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
392         case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
393         case VK_FORMAT_EAC_R11_UNORM_BLOCK:
394         case VK_FORMAT_EAC_R11_SNORM_BLOCK:
395         case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
396         case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
397             return true;
398         default:
399             return false;
400     }
401 }
402 
403 // static
isAstc(VkFormat format)404 bool CompressedImageInfo::isAstc(VkFormat format) {
405     switch (format) {
406         case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
407         case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
408         case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
409         case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
410         case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
411         case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
412         case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
413         case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
414         case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
415         case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
416         case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
417         case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
418         case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
419         case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
420         case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
421         case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
422         case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
423         case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
424         case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
425         case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
426         case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
427         case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
428         case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
429         case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
430         case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
431         case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
432         case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
433         case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
434             return true;
435         default:
436             return false;
437     }
438 }
439 
440 // static
needEmulatedAlpha(VkFormat format)441 bool CompressedImageInfo::needEmulatedAlpha(VkFormat format) {
442     switch (format) {
443         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
444         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
445             return true;
446         default:
447             return false;
448     }
449 }
450 
isEtc2() const451 bool CompressedImageInfo::isEtc2() const { return isEtc2(mCompressedFormat); }
452 
isAstc() const453 bool CompressedImageInfo::isAstc() const { return isAstc(mCompressedFormat); }
454 
getDecompressedCreateInfo(const VkImageCreateInfo & createInfo) const455 VkImageCreateInfo CompressedImageInfo::getDecompressedCreateInfo(
456     const VkImageCreateInfo& createInfo) const {
457     VkImageCreateInfo result = createInfo;
458     result.format = mDecompressedFormat;
459     result.flags &= ~VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR;
460     result.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
461     result.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
462     return result;
463 }
464 
createCompressedMipmapImages(VulkanDispatch * vk,const VkImageCreateInfo & createInfo)465 void CompressedImageInfo::createCompressedMipmapImages(VulkanDispatch* vk,
466                                                        const VkImageCreateInfo& createInfo) {
467     if (!mCompressedMipmaps.empty()) {
468         return;
469     }
470 
471     VkImageCreateInfo createInfoCopy = createInfo;
472     createInfoCopy.format = mCompressedMipmapsFormat;
473     createInfoCopy.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
474     createInfoCopy.flags &= ~VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR;
475     createInfoCopy.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
476     createInfoCopy.mipLevels = 1;
477 
478     mCompressedMipmaps.resize(mMipLevels);
479     for (uint32_t i = 0; i < mMipLevels; i++) {
480         createInfoCopy.extent = compressedMipmapExtent(i);
481         vk->vkCreateImage(mDevice, &createInfoCopy, nullptr, mCompressedMipmaps.data() + i);
482     }
483 
484     // Get the size of all images (decompressed image and compressed mipmaps)
485     std::vector<VkDeviceSize> memSizes(mMipLevels + 1);
486     memSizes[0] = getImageSize(vk, mDecompressedImage);
487     for (size_t i = 0; i < mMipLevels; i++) {
488         memSizes[i + 1] = getImageSize(vk, mCompressedMipmaps[i]);
489     }
490 
491     // Initialize the memory offsets
492     mMemoryOffsets.resize(mMipLevels + 1);
493     for (size_t i = 0; i < mMipLevels + 1; i++) {
494         VkDeviceSize alignedSize = memSizes[i];
495         if (mAlignment != 0) {
496             alignedSize = ceil_div(alignedSize, mAlignment) * mAlignment;
497         }
498         mMemoryOffsets[i] = (i == 0 ? 0 : mMemoryOffsets[i - 1]) + alignedSize;
499     }
500 }
501 
initAstcCpuDecompression(VulkanDispatch * vk,VkPhysicalDevice physicalDevice)502 void CompressedImageInfo::initAstcCpuDecompression(VulkanDispatch* vk,
503                                                    VkPhysicalDevice physicalDevice) {
504     mAstcTexture = std::make_unique<AstcTexture>(vk, mDevice, physicalDevice, mExtent, mBlock.width,
505                                                  mBlock.height, &AstcCpuDecompressor::get());
506 }
507 
decompressIfNeeded(VulkanDispatch * vk,VkCommandBuffer commandBuffer,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,const VkImageMemoryBarrier & targetBarrier,std::vector<VkImageMemoryBarrier> & outputBarriers)508 bool CompressedImageInfo::decompressIfNeeded(VulkanDispatch* vk, VkCommandBuffer commandBuffer,
509                                              VkPipelineStageFlags srcStageMask,
510                                              VkPipelineStageFlags dstStageMask,
511                                              const VkImageMemoryBarrier& targetBarrier,
512                                              std::vector<VkImageMemoryBarrier>& outputBarriers) {
513     std::vector<VkImageMemoryBarrier> imageBarriers = getImageBarriers(targetBarrier);
514 
515     if (!imageWillBecomeReadable(targetBarrier)) {
516         // We're not going to read from the image, no need to decompress it.
517         // Apply the target barrier to the compressed mipmaps and the decompressed image.
518         outputBarriers.insert(outputBarriers.end(), imageBarriers.begin(), imageBarriers.end());
519         return false;
520     }
521 
522     VkResult result = initializeDecompressionPipeline(vk, mDevice);
523     if (result != VK_SUCCESS) {
524         WARN("Failed to initialize pipeline for texture decompression");
525         return false;
526     }
527 
528     // Transition the layout of all the compressed mipmaps so that the shader can read from them.
529     for (auto& barrier : imageBarriers) {
530         barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
531         barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
532     }
533 
534     // Transition the layout of the decompressed image so that we can write to it.
535     imageBarriers.back().srcAccessMask = 0;
536     imageBarriers.back().oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
537     imageBarriers.back().dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
538     imageBarriers.back().newLayout = VK_IMAGE_LAYOUT_GENERAL;
539 
540     // Do the layout transitions
541     vk->vkCmdPipelineBarrier(commandBuffer, srcStageMask, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
542                              0, nullptr, 0, nullptr, imageBarriers.size(), imageBarriers.data());
543 
544     // Run the decompression shader
545     decompress(vk, commandBuffer, getImageSubresourceRange(targetBarrier.subresourceRange));
546 
547     // Finally, transition the layout of all images to match the target barrier.
548     for (auto& barrier : imageBarriers) {
549         barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
550         barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
551         barrier.dstAccessMask = targetBarrier.dstAccessMask;
552         barrier.newLayout = targetBarrier.newLayout;
553     }
554     // (adjust the last barrier since it's for the decompressed image)
555     imageBarriers.back().srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
556 
557     // Do the layout transitions
558     vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dstStageMask, 0,
559                              0, nullptr, 0, nullptr, imageBarriers.size(), imageBarriers.data());
560 
561     return true;
562 }
563 
decompressOnCpu(VkCommandBuffer commandBuffer,uint8_t * srcAstcData,size_t astcDataSize,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkBufferImageCopy * pRegions,const VkDecoderContext & context)564 void CompressedImageInfo::decompressOnCpu(VkCommandBuffer commandBuffer, uint8_t* srcAstcData,
565                                           size_t astcDataSize, VkImage dstImage,
566                                           VkImageLayout dstImageLayout, uint32_t regionCount,
567                                           const VkBufferImageCopy* pRegions,
568                                           const VkDecoderContext& context) {
569     mAstcTexture->on_vkCmdCopyBufferToImage(commandBuffer, srcAstcData, astcDataSize, dstImage,
570                                             dstImageLayout, regionCount, pRegions, context);
571 }
572 
getMemoryRequirements() const573 VkMemoryRequirements CompressedImageInfo::getMemoryRequirements() const {
574     return {
575         .size = mMemoryOffsets.back(),
576         .alignment = mAlignment,
577     };
578 }
579 
bindCompressedMipmapsMemory(VulkanDispatch * vk,VkDeviceMemory memory,VkDeviceSize memoryOffset)580 VkResult CompressedImageInfo::bindCompressedMipmapsMemory(VulkanDispatch* vk, VkDeviceMemory memory,
581                                                           VkDeviceSize memoryOffset) {
582     VkResult result = VK_SUCCESS;
583     for (size_t i = 0; i < mCompressedMipmaps.size(); i++) {
584         VkResult res = vk->vkBindImageMemory(mDevice, mCompressedMipmaps[i], memory,
585                                              memoryOffset + mMemoryOffsets[i]);
586         if (res != VK_SUCCESS) result = res;
587     }
588     return result;
589 }
590 
getBufferImageCopy(const VkBufferImageCopy & origRegion) const591 VkBufferImageCopy CompressedImageInfo::getBufferImageCopy(
592     const VkBufferImageCopy& origRegion) const {
593     VkBufferImageCopy region = origRegion;
594     uint32_t mipLevel = region.imageSubresource.mipLevel;
595     region.imageSubresource.mipLevel = 0;
596     region.bufferRowLength /= mBlock.width;
597     region.bufferImageHeight /= mBlock.height;
598     region.imageOffset.x /= mBlock.width;
599     region.imageOffset.y /= mBlock.height;
600     region.imageExtent = compressedMipmapPortion(region.imageExtent, mipLevel);
601     return region;
602 }
603 
604 // static
getCompressedMipmapsImageCopy(const VkImageCopy & origRegion,const CompressedImageInfo & srcImg,const CompressedImageInfo & dstImg,bool needEmulatedSrc,bool needEmulatedDst)605 VkImageCopy CompressedImageInfo::getCompressedMipmapsImageCopy(const VkImageCopy& origRegion,
606                                                                const CompressedImageInfo& srcImg,
607                                                                const CompressedImageInfo& dstImg,
608                                                                bool needEmulatedSrc,
609                                                                bool needEmulatedDst) {
610     VkImageCopy region = origRegion;
611     if (needEmulatedSrc) {
612         uint32_t mipLevel = region.srcSubresource.mipLevel;
613         region.srcSubresource.mipLevel = 0;
614         region.srcOffset.x /= srcImg.mBlock.width;
615         region.srcOffset.y /= srcImg.mBlock.height;
616         region.extent = srcImg.compressedMipmapPortion(region.extent, mipLevel);
617     }
618     if (needEmulatedDst) {
619         region.dstSubresource.mipLevel = 0;
620         region.dstOffset.x /= dstImg.mBlock.width;
621         region.dstOffset.y /= dstImg.mBlock.height;
622     }
623     return region;
624 }
625 
destroy(VulkanDispatch * vk)626 void CompressedImageInfo::destroy(VulkanDispatch* vk) {
627     for (const auto& image : mCompressedMipmaps) {
628         vk->vkDestroyImage(mDevice, image, nullptr);
629     }
630     vk->vkDestroyDescriptorSetLayout(mDevice, mDecompDescriptorSetLayout, nullptr);
631     vk->vkDestroyDescriptorPool(mDevice, mDecompDescriptorPool, nullptr);
632     vk->vkDestroyShaderModule(mDevice, mDecompShader, nullptr);
633     vk->vkDestroyPipelineLayout(mDevice, mDecompPipelineLayout, nullptr);
634     vk->vkDestroyPipeline(mDevice, mDecompPipeline, nullptr);
635     for (const auto& imageView : mCompressedMipmapsImageViews) {
636         vk->vkDestroyImageView(mDevice, imageView, nullptr);
637     }
638     for (const auto& imageView : mDecompImageViews) {
639         vk->vkDestroyImageView(mDevice, imageView, nullptr);
640     }
641     vk->vkDestroyImage(mDevice, mDecompressedImage, nullptr);
642 }
643 
getImageSize(VulkanDispatch * vk,VkImage image)644 VkDeviceSize CompressedImageInfo::getImageSize(VulkanDispatch* vk, VkImage image) {
645     VkMemoryRequirements memRequirements;
646     vk->vkGetImageMemoryRequirements(mDevice, image, &memRequirements);
647     mAlignment = std::max(mAlignment, memRequirements.alignment);
648     return memRequirements.size;
649 }
650 
getImageBarriers(const VkImageMemoryBarrier & srcBarrier)651 std::vector<VkImageMemoryBarrier> CompressedImageInfo::getImageBarriers(
652     const VkImageMemoryBarrier& srcBarrier) {
653     const VkImageSubresourceRange range = getImageSubresourceRange(srcBarrier.subresourceRange);
654 
655     std::vector<VkImageMemoryBarrier> imageBarriers;
656     imageBarriers.reserve(range.levelCount + 1);
657 
658     // Add the barriers for the compressed mipmaps
659     VkImageMemoryBarrier mipmapBarrier = srcBarrier;
660     mipmapBarrier.subresourceRange.baseMipLevel = 0;
661     mipmapBarrier.subresourceRange.levelCount = 1;
662     imageBarriers.insert(imageBarriers.begin(), range.levelCount, mipmapBarrier);
663     for (uint32_t j = 0; j < range.levelCount; j++) {
664         imageBarriers[j].image = mCompressedMipmaps[range.baseMipLevel + j];
665     }
666 
667     // Add a barrier for the decompressed image
668     imageBarriers.push_back(srcBarrier);
669     imageBarriers.back().image = mDecompressedImage;
670 
671     return imageBarriers;
672 }
673 
getImageSubresourceRange(const VkImageSubresourceRange & range) const674 VkImageSubresourceRange CompressedImageInfo::getImageSubresourceRange(
675     const VkImageSubresourceRange& range) const {
676     VkImageSubresourceRange result = range;
677     if (result.levelCount == VK_REMAINING_MIP_LEVELS) {
678         result.levelCount = mMipLevels - range.baseMipLevel;
679     }
680     if (result.layerCount == VK_REMAINING_ARRAY_LAYERS) {
681         result.layerCount = mLayerCount - range.baseArrayLayer;
682     }
683     return result;
684 }
685 
initializeDecompressionPipeline(VulkanDispatch * vk,VkDevice device)686 VkResult CompressedImageInfo::initializeDecompressionPipeline(VulkanDispatch* vk, VkDevice device) {
687     if (mDecompPipeline != nullptr) {
688         return VK_SUCCESS;
689     }
690 
691     const ShaderData* shader = getDecompressionShader(mCompressedFormat, mImageType);
692     if (!shader) {
693         WARN("No decompression shader found for format %s and img type %s",
694              string_VkFormat(mCompressedFormat), string_VkImageType(mImageType));
695         return VK_ERROR_FORMAT_NOT_SUPPORTED;
696     }
697 
698     VkShaderModuleCreateInfo shaderInfo = {
699         .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
700         .codeSize = shader->size,
701         .pCode = shader->code,
702     };
703     _RETURN_ON_FAILURE(vk->vkCreateShaderModule(device, &shaderInfo, nullptr, &mDecompShader));
704 
705     VkDescriptorSetLayoutBinding dsLayoutBindings[] = {
706         {
707             .binding = 0,
708             .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
709             .descriptorCount = 1,
710             .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
711         },
712         {
713             .binding = 1,
714             .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
715             .descriptorCount = 1,
716             .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
717         },
718     };
719     VkDescriptorSetLayoutCreateInfo dsLayoutInfo = {
720         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
721         .bindingCount = 2,
722         .pBindings = dsLayoutBindings,
723     };
724     _RETURN_ON_FAILURE(vk->vkCreateDescriptorSetLayout(device, &dsLayoutInfo, nullptr,
725                                                        &mDecompDescriptorSetLayout));
726 
727     VkDescriptorPoolSize poolSize = {
728         .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
729         .descriptorCount = 2 * mMipLevels,
730     };
731     VkDescriptorPoolCreateInfo dsPoolInfo = {
732         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
733         .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
734         .maxSets = mMipLevels,
735         .poolSizeCount = 1,
736         .pPoolSizes = &poolSize,
737     };
738     _RETURN_ON_FAILURE(
739         vk->vkCreateDescriptorPool(device, &dsPoolInfo, nullptr, &mDecompDescriptorPool));
740 
741     std::vector<VkDescriptorSetLayout> layouts(mMipLevels, mDecompDescriptorSetLayout);
742 
743     VkDescriptorSetAllocateInfo dsInfo = {
744         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
745         .descriptorPool = mDecompDescriptorPool,
746         .descriptorSetCount = mMipLevels,
747         .pSetLayouts = layouts.data(),
748     };
749     mDecompDescriptorSets.resize(mMipLevels);
750     _RETURN_ON_FAILURE(vk->vkAllocateDescriptorSets(device, &dsInfo, mDecompDescriptorSets.data()));
751 
752     VkPushConstantRange pushConstant = {.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT};
753     if (isEtc2()) {
754         pushConstant.size = sizeof(Etc2PushConstant);
755     } else if (isAstc()) {
756         pushConstant.size = sizeof(AstcPushConstant);
757     }
758 
759     VkPipelineLayoutCreateInfo pipelineLayoutInfo = {
760         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
761         .setLayoutCount = 1,
762         .pSetLayouts = &mDecompDescriptorSetLayout,
763         .pushConstantRangeCount = 1,
764         .pPushConstantRanges = &pushConstant,
765     };
766     _RETURN_ON_FAILURE(
767         vk->vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &mDecompPipelineLayout));
768 
769     VkComputePipelineCreateInfo computePipelineInfo = {
770         .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
771         .stage = {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
772                   .stage = VK_SHADER_STAGE_COMPUTE_BIT,
773                   .module = mDecompShader,
774                   .pName = "main"},
775         .layout = mDecompPipelineLayout,
776     };
777     _RETURN_ON_FAILURE(vk->vkCreateComputePipelines(device, nullptr, 1, &computePipelineInfo,
778                                                     nullptr, &mDecompPipeline));
779 
780     VkFormat intermediateFormat = VK_FORMAT_R8G8B8A8_UINT;
781     switch (mCompressedFormat) {
782         case VK_FORMAT_EAC_R11_UNORM_BLOCK:
783         case VK_FORMAT_EAC_R11_SNORM_BLOCK:
784         case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
785         case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
786             intermediateFormat = mDecompressedFormat;
787             break;
788         default:
789             break;
790     }
791 
792     mCompressedMipmapsImageViews.resize(mMipLevels);
793     mDecompImageViews.resize(mMipLevels);
794 
795     VkDescriptorImageInfo compressedMipmapsDescriptorImageInfo = {.imageLayout =
796                                                                       VK_IMAGE_LAYOUT_GENERAL};
797     VkDescriptorImageInfo mDecompDescriptorImageInfo = {.imageLayout = VK_IMAGE_LAYOUT_GENERAL};
798     VkWriteDescriptorSet writeDescriptorSets[2] = {
799         {
800             .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
801             .dstBinding = 0,
802             .descriptorCount = 1,
803             .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
804             .pImageInfo = &compressedMipmapsDescriptorImageInfo,
805         },
806         {
807             .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
808             .dstBinding = 1,
809             .descriptorCount = 1,
810             .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
811             .pImageInfo = &mDecompDescriptorImageInfo,
812         }};
813 
814     for (uint32_t i = 0; i < mMipLevels; i++) {
815         mCompressedMipmapsImageViews[i] =
816             createDefaultImageView(vk, device, mCompressedMipmaps[i], mCompressedMipmapsFormat,
817                                    mImageType, 0, mLayerCount);
818         mDecompImageViews[i] = createDefaultImageView(
819             vk, device, mDecompressedImage, intermediateFormat, mImageType, i, mLayerCount);
820         compressedMipmapsDescriptorImageInfo.imageView = mCompressedMipmapsImageViews[i];
821         mDecompDescriptorImageInfo.imageView = mDecompImageViews[i];
822         writeDescriptorSets[0].dstSet = mDecompDescriptorSets[i];
823         writeDescriptorSets[1].dstSet = mDecompDescriptorSets[i];
824         vk->vkUpdateDescriptorSets(device, 2, writeDescriptorSets, 0, nullptr);
825     }
826     return VK_SUCCESS;
827 }
828 
decompress(VulkanDispatch * vk,VkCommandBuffer commandBuffer,const VkImageSubresourceRange & range)829 void CompressedImageInfo::decompress(VulkanDispatch* vk, VkCommandBuffer commandBuffer,
830                                      const VkImageSubresourceRange& range) {
831     vk->vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, mDecompPipeline);
832     uint32_t dispatchZ = mExtent.depth == 1 ? range.layerCount : mExtent.depth;
833 
834     if (isEtc2()) {
835         const Etc2PushConstant pushConstant = {
836             .compFormat = (uint32_t)mCompressedFormat,
837             .baseLayer = mExtent.depth == 1 ? range.baseArrayLayer : 0};
838         vk->vkCmdPushConstants(commandBuffer, mDecompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0,
839                                sizeof(pushConstant), &pushConstant);
840     } else if (isAstc()) {
841         uint32_t smallBlock = false;
842         switch (mCompressedFormat) {
843             case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
844             case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
845             case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
846             case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
847             case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
848             case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
849             case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
850             case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
851                 smallBlock = true;
852                 break;
853             default:
854                 break;
855         }
856         const AstcPushConstant pushConstant = {
857             .blockSize = {mBlock.width, mBlock.height},
858             .baseLayer = mExtent.depth == 1 ? range.baseArrayLayer : 0,
859             .smallBlock = smallBlock};
860         vk->vkCmdPushConstants(commandBuffer, mDecompPipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0,
861                                sizeof(pushConstant), &pushConstant);
862     }
863     for (uint32_t i = range.baseMipLevel; i < range.baseMipLevel + range.levelCount; i++) {
864         vk->vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,
865                                     mDecompPipelineLayout, 0, 1, mDecompDescriptorSets.data() + i,
866                                     0, nullptr);
867         VkExtent3D compExtent = compressedMipmapExtent(i);
868         vk->vkCmdDispatch(commandBuffer, compExtent.width, compExtent.height, dispatchZ);
869     }
870 }
871 
mipmapExtent(uint32_t level) const872 VkExtent3D CompressedImageInfo::mipmapExtent(uint32_t level) const {
873     return {
874         .width = std::max<uint32_t>(mExtent.width >> level, 1),
875         .height = std::max<uint32_t>(mExtent.height >> level, 1),
876         .depth = std::max<uint32_t>(mExtent.depth >> level, 1),
877     };
878 }
879 
compressedMipmapExtent(uint32_t level) const880 VkExtent3D CompressedImageInfo::compressedMipmapExtent(uint32_t level) const {
881     VkExtent3D result = mipmapExtent(level);
882     result.width = ceil_div(result.width, mBlock.width);
883     result.height = ceil_div(result.height, mBlock.height);
884     return result;
885 }
886 
compressedMipmapPortion(const VkExtent3D & origExtent,uint32_t level) const887 VkExtent3D CompressedImageInfo::compressedMipmapPortion(const VkExtent3D& origExtent,
888                                                         uint32_t level) const {
889     VkExtent3D maxExtent = compressedMipmapExtent(level);
890     return {
891         .width = std::min(ceil_div(origExtent.width, mBlock.width), maxExtent.width),
892         .height = std::min(ceil_div(origExtent.height, mBlock.height), maxExtent.height),
893         .depth = origExtent.depth,
894     };
895 }
896 
897 }  // namespace vk
898 }  // namespace gfxstream
899