xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_format_utils:
7 //   Helper for Vulkan format code.
8 
9 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
10 
11 #include "image_util/loadimage.h"
12 #include "libANGLE/Texture.h"
13 #include "libANGLE/formatutils.h"
14 #include "libANGLE/renderer/load_functions_table.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/vk_caps_utils.h"
17 #include "libANGLE/renderer/vulkan/vk_renderer.h"
18 
19 namespace rx
20 {
21 namespace
22 {
FillTextureFormatCaps(vk::Renderer * renderer,angle::FormatID formatID,gl::TextureCaps * outTextureCaps)23 void FillTextureFormatCaps(vk::Renderer *renderer,
24                            angle::FormatID formatID,
25                            gl::TextureCaps *outTextureCaps)
26 {
27     const VkPhysicalDeviceLimits &physicalDeviceLimits =
28         renderer->getPhysicalDeviceProperties().limits;
29     bool hasColorAttachmentFeatureBit =
30         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
31     bool hasDepthAttachmentFeatureBit = renderer->hasImageFormatFeatureBits(
32         formatID, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
33 
34     outTextureCaps->texturable =
35         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
36     outTextureCaps->filterable = renderer->hasImageFormatFeatureBits(
37         formatID, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
38     outTextureCaps->blendable =
39         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT);
40 
41     // For renderbuffer and texture attachments we require transfer and sampling for
42     // GLES 2.0 CopyTexImage support. Sampling is also required for other features like
43     // blits and EGLImages.
44     outTextureCaps->textureAttachment =
45         outTextureCaps->texturable &&
46         (hasColorAttachmentFeatureBit || hasDepthAttachmentFeatureBit);
47     outTextureCaps->renderbuffer = outTextureCaps->textureAttachment;
48 
49     if (outTextureCaps->renderbuffer)
50     {
51         if (hasColorAttachmentFeatureBit)
52         {
53             vk_gl::AddSampleCounts(physicalDeviceLimits.framebufferColorSampleCounts,
54                                    &outTextureCaps->sampleCounts);
55         }
56         if (hasDepthAttachmentFeatureBit)
57         {
58             // Some drivers report different depth and stencil sample counts.  We'll AND those
59             // counts together, limiting all depth and/or stencil formats to the lower number of
60             // sample counts.
61             vk_gl::AddSampleCounts((physicalDeviceLimits.framebufferDepthSampleCounts &
62                                     physicalDeviceLimits.framebufferStencilSampleCounts),
63                                    &outTextureCaps->sampleCounts);
64         }
65     }
66 }
67 
HasFullBufferFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)68 bool HasFullBufferFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
69 {
70     // Note: GL_EXT_texture_buffer support uses the same vkBufferFormat that is determined by
71     // Format::initBufferFallback, which uses this function.  That relies on the fact that formats
72     // required for GL_EXT_texture_buffer all have mandatory VERTEX_BUFFER feature support in
73     // Vulkan.  If this function is changed to test for more features in such a way that makes any
74     // of those formats use a fallback format, the implementation of GL_EXT_texture_buffer must be
75     // modified not to use vkBufferFormat.
76     return renderer->hasBufferFormatFeatureBits(formatID, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
77 }
78 
79 using SupportTest = bool (*)(vk::Renderer *renderer, angle::FormatID formatID);
80 
81 template <class FormatInitInfo>
FindSupportedFormat(vk::Renderer * renderer,const FormatInitInfo * info,size_t skip,int numInfo,SupportTest hasSupport)82 int FindSupportedFormat(vk::Renderer *renderer,
83                         const FormatInitInfo *info,
84                         size_t skip,
85                         int numInfo,
86                         SupportTest hasSupport)
87 {
88     ASSERT(numInfo > 0);
89 
90     for (int i = static_cast<int>(skip); i < numInfo; ++i)
91     {
92         ASSERT(info[i].format != angle::FormatID::NONE);
93         if (hasSupport(renderer, info[i].format))
94         {
95             return i;
96         }
97     }
98 
99     // We couldn't find a valid fallback, ignore the skip and return 0
100     return 0;
101 }
102 
HasNonFilterableTextureFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)103 bool HasNonFilterableTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
104 {
105     constexpr uint32_t kBitsColor =
106         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
107     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
108 
109     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
110            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
111 }
112 }  // anonymous namespace
113 
114 namespace vk
115 {
116 // Format implementation.
Format()117 Format::Format()
118     : mIntendedFormatID(angle::FormatID::NONE),
119       mIntendedGLFormat(GL_NONE),
120       mActualSampleOnlyImageFormatID(angle::FormatID::NONE),
121       mActualRenderableImageFormatID(angle::FormatID::NONE),
122       mActualBufferFormatID(angle::FormatID::NONE),
123       mActualCompressedBufferFormatID(angle::FormatID::NONE),
124       mImageInitializerFunction(nullptr),
125       mTextureLoadFunctions(),
126       mRenderableTextureLoadFunctions(),
127       mVertexLoadFunction(nullptr),
128       mCompressedVertexLoadFunction(nullptr),
129       mVertexLoadRequiresConversion(false),
130       mCompressedVertexLoadRequiresConversion(false),
131       mVkBufferFormatIsPacked(false),
132       mVkFormatIsInt(false),
133       mVkFormatIsUnsigned(false)
134 {}
135 
initImageFallback(Renderer * renderer,const ImageFormatInitInfo * info,int numInfo)136 void Format::initImageFallback(Renderer *renderer, const ImageFormatInitInfo *info, int numInfo)
137 {
138     size_t skip                 = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
139     SupportTest testFunction    = HasNonRenderableTextureFormatSupport;
140     const angle::Format &format = angle::Format::Get(info[0].format);
141     if (format.isInt() || (format.isFloat() && format.redBits >= 32))
142     {
143         // Integer formats don't support filtering in GL, so don't test for it.
144         // Filtering of 32-bit float textures is not supported on Android, and
145         // it's enabled by the extension OES_texture_float_linear, which is
146         // enabled automatically by examining format capabilities.
147         testFunction = HasNonFilterableTextureFormatSupport;
148     }
149 
150     int i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
151     mActualSampleOnlyImageFormatID = info[i].format;
152     mImageInitializerFunction      = info[i].initializer;
153 
154     // Set renderable format.
155     if (testFunction != HasNonFilterableTextureFormatSupport &&
156         !(format.isSnorm() && format.channelCount == 3) && !format.isBlock)
157     {
158         // Rendering to RGB SNORM textures is not supported on Android.
159         // Compressed textures also need to perform this check.
160         testFunction = HasFullTextureFormatSupport;
161         i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
162         mActualRenderableImageFormatID = info[i].format;
163     }
164 }
165 
initBufferFallback(Renderer * renderer,const BufferFormatInitInfo * info,int numInfo,int compressedStartIndex)166 void Format::initBufferFallback(Renderer *renderer,
167                                 const BufferFormatInitInfo *info,
168                                 int numInfo,
169                                 int compressedStartIndex)
170 {
171     {
172         size_t skip = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
173         int i       = FindSupportedFormat(renderer, info, skip, compressedStartIndex,
174                                           HasFullBufferFormatSupport);
175 
176         mActualBufferFormatID         = info[i].format;
177         mVkBufferFormatIsPacked       = info[i].vkFormatIsPacked;
178         mVertexLoadFunction           = info[i].vertexLoadFunction;
179         mVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
180     }
181 
182     if (renderer->getFeatures().compressVertexData.enabled && compressedStartIndex < numInfo)
183     {
184         int i = FindSupportedFormat(renderer, info, compressedStartIndex, numInfo,
185                                     HasFullBufferFormatSupport);
186 
187         mActualCompressedBufferFormatID         = info[i].format;
188         mVkCompressedBufferFormatIsPacked       = info[i].vkFormatIsPacked;
189         mCompressedVertexLoadFunction           = info[i].vertexLoadFunction;
190         mCompressedVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
191     }
192 }
193 
getVertexInputAlignment(bool compressed) const194 size_t Format::getVertexInputAlignment(bool compressed) const
195 {
196     const angle::Format &bufferFormat = getActualBufferFormat(compressed);
197     size_t pixelBytes                 = bufferFormat.pixelBytes;
198     return mVkBufferFormatIsPacked ? pixelBytes : (pixelBytes / bufferFormat.channelCount);
199 }
200 
HasEmulatedImageChannels(const angle::Format & intendedFormat,const angle::Format & actualFormat)201 bool HasEmulatedImageChannels(const angle::Format &intendedFormat,
202                               const angle::Format &actualFormat)
203 {
204     return (intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0) ||
205            (intendedFormat.blueBits == 0 && actualFormat.blueBits > 0) ||
206            (intendedFormat.greenBits == 0 && actualFormat.greenBits > 0) ||
207            (intendedFormat.depthBits == 0 && actualFormat.depthBits > 0) ||
208            (intendedFormat.stencilBits == 0 && actualFormat.stencilBits > 0);
209 }
210 
HasEmulatedImageFormat(angle::FormatID intendedFormatID,angle::FormatID actualFormatID)211 bool HasEmulatedImageFormat(angle::FormatID intendedFormatID, angle::FormatID actualFormatID)
212 {
213     return actualFormatID != intendedFormatID;
214 }
215 
operator ==(const Format & lhs,const Format & rhs)216 bool operator==(const Format &lhs, const Format &rhs)
217 {
218     return &lhs == &rhs;
219 }
220 
operator !=(const Format & lhs,const Format & rhs)221 bool operator!=(const Format &lhs, const Format &rhs)
222 {
223     return &lhs != &rhs;
224 }
225 
226 // FormatTable implementation.
FormatTable()227 FormatTable::FormatTable() {}
228 
~FormatTable()229 FormatTable::~FormatTable() {}
230 
initialize(Renderer * renderer,gl::TextureCapsMap * outTextureCapsMap)231 void FormatTable::initialize(Renderer *renderer, gl::TextureCapsMap *outTextureCapsMap)
232 {
233     for (size_t formatIndex = 0; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
234     {
235         Format &format                           = mFormatData[formatIndex];
236         const auto intendedFormatID              = static_cast<angle::FormatID>(formatIndex);
237         const angle::Format &intendedAngleFormat = angle::Format::Get(intendedFormatID);
238 
239         format.initialize(renderer, intendedAngleFormat);
240         format.mIntendedFormatID = intendedFormatID;
241 
242         if (!format.valid())
243         {
244             continue;
245         }
246 
247         // No sample-able or render-able formats, so nothing left to do. This includes skipping the
248         // rest of the loop for buffer-only formats, since they are not texturable.
249         if (format.mActualSampleOnlyImageFormatID == angle::FormatID::NONE)
250         {
251             continue;
252         }
253 
254         bool transcodeEtcToBc = false;
255         if (renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
256             IsETCFormat(intendedFormatID) &&
257             !angle::Format::Get(format.mActualSampleOnlyImageFormatID).isBlock)
258         {
259             // Check BC format support
260             angle::FormatID bcFormat = GetTranscodeBCFormatID(intendedFormatID);
261             if (HasNonRenderableTextureFormatSupport(renderer, bcFormat))
262             {
263                 format.mActualSampleOnlyImageFormatID = bcFormat;
264                 transcodeEtcToBc                      = true;
265             }
266         }
267 
268         if (format.mActualRenderableImageFormatID == angle::FormatID::NONE)
269         {
270             // If renderable format was not set, it means there is no fallback format for
271             // renderable. We populate this the same formatID as sampleOnly formatID so that
272             // getActualFormatID() will be simpler.
273             format.mActualRenderableImageFormatID = format.mActualSampleOnlyImageFormatID;
274         }
275 
276         gl::TextureCaps textureCaps;
277         FillTextureFormatCaps(renderer, format.mActualSampleOnlyImageFormatID, &textureCaps);
278 
279         if (textureCaps.texturable)
280         {
281             format.mTextureLoadFunctions = GetLoadFunctionsMap(
282                 format.mIntendedGLFormat,
283                 transcodeEtcToBc ? intendedFormatID : format.mActualSampleOnlyImageFormatID);
284         }
285 
286         if (format.mActualRenderableImageFormatID == format.mActualSampleOnlyImageFormatID)
287         {
288             outTextureCapsMap->set(intendedFormatID, textureCaps);
289             format.mRenderableTextureLoadFunctions = format.mTextureLoadFunctions;
290         }
291         else
292         {
293             FillTextureFormatCaps(renderer, format.mActualRenderableImageFormatID, &textureCaps);
294             outTextureCapsMap->set(intendedFormatID, textureCaps);
295             if (textureCaps.texturable)
296             {
297                 format.mRenderableTextureLoadFunctions = GetLoadFunctionsMap(
298                     format.mIntendedGLFormat, format.mActualRenderableImageFormatID);
299             }
300         }
301     }
302 }
303 
getOrAllocExternalFormatID(uint64_t externalFormat,VkFormat colorAttachmentFormat,VkFormatFeatureFlags formatFeatures)304 angle::FormatID ExternalFormatTable::getOrAllocExternalFormatID(uint64_t externalFormat,
305                                                                 VkFormat colorAttachmentFormat,
306                                                                 VkFormatFeatureFlags formatFeatures)
307 {
308     std::unique_lock<angle::SimpleMutex> lock(mExternalYuvFormatMutex);
309     for (size_t index = 0; index < mExternalYuvFormats.size(); index++)
310     {
311         if (mExternalYuvFormats[index].externalFormat == externalFormat)
312         {
313             // Found a match. Just return existing formatID
314             return angle::FormatID(ToUnderlying(angle::FormatID::EXTERNAL0) + index);
315         }
316     }
317 
318     if (mExternalYuvFormats.size() >= kMaxExternalFormatCountSupported)
319     {
320         ERR() << "ANGLE only suports maximum " << kMaxExternalFormatCountSupported
321               << " external renderable formats";
322         return angle::FormatID::NONE;
323     }
324 
325     mExternalYuvFormats.push_back({externalFormat, colorAttachmentFormat, formatFeatures});
326     return angle::FormatID(ToUnderlying(angle::FormatID::EXTERNAL0) + mExternalYuvFormats.size() -
327                            1);
328 }
329 
getExternalFormatInfo(angle::FormatID formatID) const330 const ExternalYuvFormatInfo &ExternalFormatTable::getExternalFormatInfo(
331     angle::FormatID formatID) const
332 {
333     ASSERT(formatID >= angle::FormatID::EXTERNAL0);
334     size_t index = ToUnderlying(formatID) - ToUnderlying(angle::FormatID::EXTERNAL0);
335     ASSERT(index < mExternalYuvFormats.size());
336     return mExternalYuvFormats[index];
337 }
338 
IsYUVExternalFormat(angle::FormatID formatID)339 bool IsYUVExternalFormat(angle::FormatID formatID)
340 {
341     return formatID >= angle::FormatID::EXTERNAL0 && formatID <= angle::FormatID::EXTERNAL7;
342 }
343 
GetImageCopyBufferAlignment(angle::FormatID actualFormatID)344 size_t GetImageCopyBufferAlignment(angle::FormatID actualFormatID)
345 {
346     // vkCmdCopyBufferToImage must have an offset that is a multiple of 4 as well as a multiple
347     // of the texel size (if uncompressed) or pixel block size (if compressed).
348     // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html
349     //
350     // We need lcm(4, texelSize) (lcm = least common multiplier).  For compressed images,
351     // |texelSize| would contain the block size.  Since 4 is constant, this can be calculated as:
352     //
353     //                      | texelSize             texelSize % 4 == 0
354     //                      | 4 * texelSize         texelSize % 4 == 1
355     // lcm(4, texelSize) = <
356     //                      | 2 * texelSize         texelSize % 4 == 2
357     //                      | 4 * texelSize         texelSize % 4 == 3
358     //
359     // This means:
360     //
361     // - texelSize % 2 != 0 gives a 4x multiplier
362     // - else texelSize % 4 != 0 gives a 2x multiplier
363     // - else there's no multiplier.
364     //
365     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
366 
367     ASSERT(actualFormat.pixelBytes != 0);
368     const size_t texelSize  = actualFormat.pixelBytes;
369     const size_t multiplier = texelSize % 2 != 0 ? 4 : texelSize % 4 != 0 ? 2 : 1;
370     const size_t alignment  = multiplier * texelSize;
371 
372     return alignment;
373 }
374 
GetValidImageCopyBufferAlignment(angle::FormatID intendedFormatID,angle::FormatID actualFormatID)375 size_t GetValidImageCopyBufferAlignment(angle::FormatID intendedFormatID,
376                                         angle::FormatID actualFormatID)
377 {
378     constexpr size_t kMinimumAlignment = 16;
379     return (intendedFormatID == angle::FormatID::NONE)
380                ? kMinimumAlignment
381                : GetImageCopyBufferAlignment(actualFormatID);
382 }
383 
GetMaximalImageUsageFlags(Renderer * renderer,angle::FormatID formatID)384 VkImageUsageFlags GetMaximalImageUsageFlags(Renderer *renderer, angle::FormatID formatID)
385 {
386     constexpr VkFormatFeatureFlags kImageUsageFeatureBits =
387         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
388         VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
389         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
390     VkFormatFeatureFlags featureBits =
391         renderer->getImageFormatFeatureBits(formatID, kImageUsageFeatureBits);
392     VkImageUsageFlags imageUsageFlags = 0;
393     if (featureBits & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
394         imageUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
395     if (featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
396         imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
397     if (featureBits & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
398         imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
399     if (featureBits & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
400         imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
401     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
402         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
403     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
404         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
405     imageUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
406     return imageUsageFlags;
407 }
408 
GetMinimalImageCreateFlags(Renderer * renderer,gl::TextureType textureType,VkImageUsageFlags usage)409 VkImageCreateFlags GetMinimalImageCreateFlags(Renderer *renderer,
410                                               gl::TextureType textureType,
411                                               VkImageUsageFlags usage)
412 {
413     switch (textureType)
414     {
415         case gl::TextureType::CubeMap:
416         case gl::TextureType::CubeMapArray:
417             return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
418 
419         case gl::TextureType::_3D:
420         {
421             // Slices of this image may be used as:
422             //
423             // - Render target: The VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT flag is needed for that.
424             // - Sampled or storage image: The VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT flag is
425             //   needed for this.  If VK_EXT_image_2d_view_of_3d is not supported, we tolerate the
426             //   VVL error as drivers seem to support this behavior anyway.
427             VkImageCreateFlags flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
428 
429             if ((usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0)
430             {
431                 if (renderer->getFeatures().supportsImage2dViewOf3d.enabled)
432                 {
433                     flags |= VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
434                 }
435             }
436             else if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0)
437             {
438                 if (renderer->getFeatures().supportsSampler2dViewOf3d.enabled)
439                 {
440                     flags |= VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
441                 }
442             }
443 
444             return flags;
445         }
446 
447         default:
448             return 0;
449     }
450 }
451 
452 }  // namespace vk
453 
HasFullTextureFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)454 bool HasFullTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
455 {
456     constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
457                                     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
458                                     VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
459 
460     // In OpenGL ES, all renderable formats except 32-bit floating-point support blending.
461     // 32-bit floating-point case validation is handled by ANGLE's frontend.
462     uint32_t kBitsColorFull = kBitsColor;
463     switch (formatID)
464     {
465         case angle::FormatID::R32_FLOAT:
466         case angle::FormatID::R32G32_FLOAT:
467         case angle::FormatID::R32G32B32A32_FLOAT:
468             break;
469         default:
470             kBitsColorFull |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
471             break;
472     }
473 
474     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
475 
476     return renderer->hasImageFormatFeatureBits(formatID, kBitsColorFull) ||
477            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
478 }
479 
HasNonRenderableTextureFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)480 bool HasNonRenderableTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
481 {
482     constexpr uint32_t kBitsColor =
483         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
484     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
485 
486     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
487            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
488 }
489 
490 // Checks if it is a ETC texture format
IsETCFormat(angle::FormatID formatID)491 bool IsETCFormat(angle::FormatID formatID)
492 {
493     return formatID >= angle::FormatID::EAC_R11G11_SNORM_BLOCK &&
494            formatID <= angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK;
495 }
496 // Checks if it is a BC texture format
IsBCFormat(angle::FormatID formatID)497 bool IsBCFormat(angle::FormatID formatID)
498 {
499     return formatID >= angle::FormatID::BC1_RGBA_UNORM_BLOCK &&
500            formatID <= angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK;
501 }
502 
503 static constexpr int kNumETCFormats = 12;
504 
505 static_assert((int)angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK ==
506               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + kNumETCFormats - 1);
507 
508 static_assert((int)angle::FormatID::EAC_R11G11_UNORM_BLOCK ==
509               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 1);
510 static_assert((int)angle::FormatID::EAC_R11_SNORM_BLOCK ==
511               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 2);
512 static_assert((int)angle::FormatID::EAC_R11_UNORM_BLOCK ==
513               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 3);
514 static_assert((int)angle::FormatID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK ==
515               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 4);
516 static_assert((int)angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK ==
517               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 5);
518 static_assert((int)angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK ==
519               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 6);
520 static_assert((int)angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK ==
521               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 7);
522 static_assert((int)angle::FormatID::ETC2_R8G8B8A8_SRGB_BLOCK ==
523               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 8);
524 static_assert((int)angle::FormatID::ETC2_R8G8B8A8_UNORM_BLOCK ==
525               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 9);
526 static_assert((int)angle::FormatID::ETC2_R8G8B8_SRGB_BLOCK ==
527               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 10);
528 
529 static const std::array<LoadImageFunction, kNumETCFormats> kEtcToBcLoadingFunc = {
530     angle::LoadEACRG11SToBC5,     // EAC_R11G11_SNORM
531     angle::LoadEACRG11ToBC5,      // EAC_R11G11_UNORM
532     angle::LoadEACR11SToBC4,      // EAC_R11_SNORM
533     angle::LoadEACR11ToBC4,       // EAC_R11_UNORM_BLOCK
534     angle::LoadETC1RGB8ToBC1,     // ETC1_LOSSY_DECODE_R8G8B8_UNORM
535     angle::LoadETC2RGB8ToBC1,     // ETC1_R8G8B8_UNORM
536     angle::LoadETC2SRGB8A1ToBC1,  // ETC2_R8G8B8A1_SRGB
537     angle::LoadETC2RGB8A1ToBC1,   // ETC2_R8G8B8A1_UNORM
538     angle::LoadETC2SRGBA8ToBC3,   // ETC2_R8G8B8A8_SRGB
539     angle::LoadETC2RGBA8ToBC3,    // ETC2_R8G8B8A8_UNORM
540     angle::LoadETC2SRGB8ToBC1,    // ETC2_R8G8B8_SRGB
541     angle::LoadETC2RGB8ToBC1,     // ETC2_R8G8B8_UNORM
542 };
543 
GetEtcToBcTransCodingFunc(angle::FormatID formatID)544 LoadImageFunctionInfo GetEtcToBcTransCodingFunc(angle::FormatID formatID)
545 {
546     ASSERT(IsETCFormat(formatID));
547     return LoadImageFunctionInfo(
548         kEtcToBcLoadingFunc[static_cast<uint32_t>(formatID) -
549                             static_cast<uint32_t>(angle::FormatID::EAC_R11G11_SNORM_BLOCK)],
550         true);
551 }
552 
553 static constexpr angle::FormatID kEtcToBcFormatMapping[] = {
554     angle::FormatID::BC5_RG_SNORM_BLOCK,         // EAC_R11G11_SNORM
555     angle::FormatID::BC5_RG_UNORM_BLOCK,         // EAC_R11G11_UNORM
556     angle::FormatID::BC4_RED_SNORM_BLOCK,        // EAC_R11_SNORM
557     angle::FormatID::BC4_RED_UNORM_BLOCK,        // EAC_R11_UNORM_BLOCK
558     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC1_LOSSY_DECODE_R8G8B8_UNORM
559     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC1_R8G8B8_UNORM
560     angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK,  // ETC2_R8G8B8A1_SRGB
561     angle::FormatID::BC1_RGBA_UNORM_BLOCK,       // ETC2_R8G8B8A1_UNORM
562     angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK,  // ETC2_R8G8B8A8_SRGB
563     angle::FormatID::BC3_RGBA_UNORM_BLOCK,       // ETC2_R8G8B8A8_UNORM
564     angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK,   // ETC2_R8G8B8_SRGB
565     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC2_R8G8B8_UNORM
566 };
567 
GetTranscodeBCFormatID(angle::FormatID formatID)568 angle::FormatID GetTranscodeBCFormatID(angle::FormatID formatID)
569 {
570     ASSERT(IsETCFormat(formatID));
571     return kEtcToBcFormatMapping[static_cast<uint32_t>(formatID) -
572                                  static_cast<uint32_t>(angle::FormatID::EAC_R11G11_SNORM_BLOCK)];
573 }
574 
AdjustASTCFormatForHDR(const vk::Renderer * renderer,VkFormat vkFormat)575 VkFormat AdjustASTCFormatForHDR(const vk::Renderer *renderer, VkFormat vkFormat)
576 {
577     ASSERT(renderer != nullptr);
578     const bool hdrEnabled = renderer->getFeatures().supportsTextureCompressionAstcHdr.enabled;
579 
580     if (hdrEnabled == false)
581     {
582         return vkFormat;
583     }
584 
585     // When KHR_texture_compression_astc_hdr is enabled,
586     // VK_FORMAT_ASTC_nxm_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_nxm_SFLOAT_BLOCK
587     auto transformFormat = [](VkFormat vkFormat) -> VkFormat {
588         if (vkFormat >= VK_FORMAT_ASTC_4x4_UNORM_BLOCK &&
589             vkFormat <= VK_FORMAT_ASTC_12x12_UNORM_BLOCK && (vkFormat & 1) == 1)
590         {
591             return static_cast<VkFormat>(((vkFormat - VK_FORMAT_ASTC_4x4_UNORM_BLOCK) >> 1) +
592                                          VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK);
593         }
594         return vkFormat;
595     };
596 
597     static_assert(
598         transformFormat(VK_FORMAT_ASTC_4x4_UNORM_BLOCK) == VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK,
599         "VK_FORMAT_ASTC_4x4_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK");
600     static_assert(
601         transformFormat(VK_FORMAT_ASTC_5x4_UNORM_BLOCK) == VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK,
602         "VK_FORMAT_ASTC_5x4_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK");
603     static_assert(
604         transformFormat(VK_FORMAT_ASTC_5x5_UNORM_BLOCK) == VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK,
605         "VK_FORMAT_ASTC_5x5_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK");
606     static_assert(
607         transformFormat(VK_FORMAT_ASTC_6x5_UNORM_BLOCK) == VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK,
608         "VK_FORMAT_ASTC_6x5_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK");
609     static_assert(
610         transformFormat(VK_FORMAT_ASTC_6x6_UNORM_BLOCK) == VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK,
611         "VK_FORMAT_ASTC_6x6_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK");
612     static_assert(
613         transformFormat(VK_FORMAT_ASTC_8x5_UNORM_BLOCK) == VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK,
614         "VK_FORMAT_ASTC_8x5_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK");
615     static_assert(
616         transformFormat(VK_FORMAT_ASTC_8x6_UNORM_BLOCK) == VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK,
617         "VK_FORMAT_ASTC_8x6_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK");
618     static_assert(
619         transformFormat(VK_FORMAT_ASTC_8x8_UNORM_BLOCK) == VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK,
620         "VK_FORMAT_ASTC_8x8_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK");
621     static_assert(
622         transformFormat(VK_FORMAT_ASTC_10x5_UNORM_BLOCK) == VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK,
623         "VK_FORMAT_ASTC_10x5_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK");
624     static_assert(
625         transformFormat(VK_FORMAT_ASTC_10x6_UNORM_BLOCK) == VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK,
626         "VK_FORMAT_ASTC_10x6_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK");
627     static_assert(
628         transformFormat(VK_FORMAT_ASTC_10x8_UNORM_BLOCK) == VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK,
629         "VK_FORMAT_ASTC_10x8_UNORM_BLOCK should be converted to VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK");
630     static_assert(
631         transformFormat(VK_FORMAT_ASTC_10x10_UNORM_BLOCK) == VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK,
632         "VK_FORMAT_ASTC_10x10_UNORM_BLOCK should be converted to"
633         "VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK");
634     static_assert(
635         transformFormat(VK_FORMAT_ASTC_12x10_UNORM_BLOCK) == VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK,
636         "VK_FORMAT_ASTC_12x10_UNORM_BLOCK should be converted to"
637         "VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK");
638     static_assert(
639         transformFormat(VK_FORMAT_ASTC_12x12_UNORM_BLOCK) == VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK,
640         "VK_FORMAT_ASTC_12x12_UNORM_BLOCK should be converted to"
641         "VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK");
642 
643     return transformFormat(vkFormat);
644 }
645 
GetSwizzleStateComponent(const gl::SwizzleState & swizzleState,GLenum component)646 GLenum GetSwizzleStateComponent(const gl::SwizzleState &swizzleState, GLenum component)
647 {
648     switch (component)
649     {
650         case GL_RED:
651             return swizzleState.swizzleRed;
652         case GL_GREEN:
653             return swizzleState.swizzleGreen;
654         case GL_BLUE:
655             return swizzleState.swizzleBlue;
656         case GL_ALPHA:
657             return swizzleState.swizzleAlpha;
658         default:
659             return component;
660     }
661 }
662 
ApplySwizzle(const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & toApply)663 gl::SwizzleState ApplySwizzle(const gl::SwizzleState &formatSwizzle,
664                               const gl::SwizzleState &toApply)
665 {
666     gl::SwizzleState result;
667 
668     result.swizzleRed   = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleRed);
669     result.swizzleGreen = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleGreen);
670     result.swizzleBlue  = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleBlue);
671     result.swizzleAlpha = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleAlpha);
672 
673     return result;
674 }
675 
GetFormatSwizzle(const angle::Format & angleFormat,const bool sized)676 gl::SwizzleState GetFormatSwizzle(const angle::Format &angleFormat, const bool sized)
677 {
678     gl::SwizzleState internalSwizzle;
679 
680     if (angleFormat.isLUMA())
681     {
682         GLenum swizzleRGB, swizzleA;
683         if (angleFormat.luminanceBits > 0)
684         {
685             swizzleRGB = GL_RED;
686             swizzleA   = (angleFormat.alphaBits > 0 ? GL_GREEN : GL_ONE);
687         }
688         else
689         {
690             swizzleRGB = GL_ZERO;
691             swizzleA   = GL_RED;
692         }
693         internalSwizzle.swizzleRed   = swizzleRGB;
694         internalSwizzle.swizzleGreen = swizzleRGB;
695         internalSwizzle.swizzleBlue  = swizzleRGB;
696         internalSwizzle.swizzleAlpha = swizzleA;
697     }
698     else
699     {
700         if (angleFormat.hasDepthOrStencilBits())
701         {
702             // In OES_depth_texture/ARB_depth_texture, depth
703             // textures are treated as luminance.
704             // If the internalformat was not sized, use OES_depth_texture behavior
705             bool hasGB = angleFormat.depthBits > 0 && !sized;
706 
707             internalSwizzle.swizzleRed   = GL_RED;
708             internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
709             internalSwizzle.swizzleBlue  = hasGB ? GL_RED : GL_ZERO;
710             internalSwizzle.swizzleAlpha = GL_ONE;
711         }
712         else
713         {
714             // Color bits are all zero for blocked formats
715             if (!angleFormat.isBlock)
716             {
717                 // Set any missing channel to default in case the emulated format has that channel.
718                 internalSwizzle.swizzleRed   = angleFormat.redBits > 0 ? GL_RED : GL_ZERO;
719                 internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO;
720                 internalSwizzle.swizzleBlue  = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO;
721                 internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE;
722             }
723         }
724     }
725 
726     return internalSwizzle;
727 }
728 }  // namespace rx
729