• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     const int last = numInfo - 1;
90 
91     for (int i = static_cast<int>(skip); i < last; ++i)
92     {
93         ASSERT(info[i].format != angle::FormatID::NONE);
94         if (hasSupport(renderer, info[i].format))
95             return i;
96     }
97 
98     if (skip > 0 && !hasSupport(renderer, info[last].format))
99     {
100         // We couldn't find a valid fallback, try again without skip
101         return FindSupportedFormat(renderer, info, 0, numInfo, hasSupport);
102     }
103 
104     ASSERT(info[last].format != angle::FormatID::NONE);
105     ASSERT(hasSupport(renderer, info[last].format));
106     return last;
107 }
108 
HasNonFilterableTextureFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)109 bool HasNonFilterableTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
110 {
111     constexpr uint32_t kBitsColor =
112         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
113     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
114 
115     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
116            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
117 }
118 }  // anonymous namespace
119 
120 namespace vk
121 {
122 // Format implementation.
Format()123 Format::Format()
124     : mIntendedFormatID(angle::FormatID::NONE),
125       mIntendedGLFormat(GL_NONE),
126       mActualSampleOnlyImageFormatID(angle::FormatID::NONE),
127       mActualRenderableImageFormatID(angle::FormatID::NONE),
128       mActualBufferFormatID(angle::FormatID::NONE),
129       mActualCompressedBufferFormatID(angle::FormatID::NONE),
130       mImageInitializerFunction(nullptr),
131       mTextureLoadFunctions(),
132       mRenderableTextureLoadFunctions(),
133       mVertexLoadFunction(nullptr),
134       mCompressedVertexLoadFunction(nullptr),
135       mVertexLoadRequiresConversion(false),
136       mCompressedVertexLoadRequiresConversion(false),
137       mVkBufferFormatIsPacked(false),
138       mVkFormatIsInt(false),
139       mVkFormatIsUnsigned(false)
140 {}
141 
initImageFallback(Renderer * renderer,const ImageFormatInitInfo * info,int numInfo)142 void Format::initImageFallback(Renderer *renderer, const ImageFormatInitInfo *info, int numInfo)
143 {
144     size_t skip                 = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
145     SupportTest testFunction    = HasNonRenderableTextureFormatSupport;
146     const angle::Format &format = angle::Format::Get(info[0].format);
147     if (format.isInt() || (format.isFloat() && format.redBits >= 32))
148     {
149         // Integer formats don't support filtering in GL, so don't test for it.
150         // Filtering of 32-bit float textures is not supported on Android, and
151         // it's enabled by the extension OES_texture_float_linear, which is
152         // enabled automatically by examining format capabilities.
153         testFunction = HasNonFilterableTextureFormatSupport;
154     }
155 
156     int i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
157     mActualSampleOnlyImageFormatID = info[i].format;
158     mImageInitializerFunction      = info[i].initializer;
159 
160     // Set renderable format.
161     if (testFunction != HasNonFilterableTextureFormatSupport &&
162         !(format.isSnorm() && format.channelCount == 3) && !format.isBlock)
163     {
164         // Rendering to RGB SNORM textures is not supported on Android.
165         // Compressed textures also need to perform this check.
166         testFunction = HasFullTextureFormatSupport;
167         i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
168         mActualRenderableImageFormatID = info[i].format;
169     }
170 }
171 
initBufferFallback(Renderer * renderer,const BufferFormatInitInfo * info,int numInfo,int compressedStartIndex)172 void Format::initBufferFallback(Renderer *renderer,
173                                 const BufferFormatInitInfo *info,
174                                 int numInfo,
175                                 int compressedStartIndex)
176 {
177     {
178         size_t skip = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
179         int i       = FindSupportedFormat(renderer, info, skip, compressedStartIndex,
180                                           HasFullBufferFormatSupport);
181 
182         mActualBufferFormatID         = info[i].format;
183         mVkBufferFormatIsPacked       = info[i].vkFormatIsPacked;
184         mVertexLoadFunction           = info[i].vertexLoadFunction;
185         mVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
186     }
187 
188     if (renderer->getFeatures().compressVertexData.enabled && compressedStartIndex < numInfo)
189     {
190         int i = FindSupportedFormat(renderer, info, compressedStartIndex, numInfo,
191                                     HasFullBufferFormatSupport);
192 
193         mActualCompressedBufferFormatID         = info[i].format;
194         mVkCompressedBufferFormatIsPacked       = info[i].vkFormatIsPacked;
195         mCompressedVertexLoadFunction           = info[i].vertexLoadFunction;
196         mCompressedVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
197     }
198 }
199 
getVertexInputAlignment(bool compressed) const200 size_t Format::getVertexInputAlignment(bool compressed) const
201 {
202     const angle::Format &bufferFormat = getActualBufferFormat(compressed);
203     size_t pixelBytes                 = bufferFormat.pixelBytes;
204     return mVkBufferFormatIsPacked ? pixelBytes : (pixelBytes / bufferFormat.channelCount);
205 }
206 
HasEmulatedImageChannels(const angle::Format & intendedFormat,const angle::Format & actualFormat)207 bool HasEmulatedImageChannels(const angle::Format &intendedFormat,
208                               const angle::Format &actualFormat)
209 {
210     return (intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0) ||
211            (intendedFormat.blueBits == 0 && actualFormat.blueBits > 0) ||
212            (intendedFormat.greenBits == 0 && actualFormat.greenBits > 0) ||
213            (intendedFormat.depthBits == 0 && actualFormat.depthBits > 0) ||
214            (intendedFormat.stencilBits == 0 && actualFormat.stencilBits > 0);
215 }
216 
HasEmulatedImageFormat(angle::FormatID intendedFormatID,angle::FormatID actualFormatID)217 bool HasEmulatedImageFormat(angle::FormatID intendedFormatID, angle::FormatID actualFormatID)
218 {
219     return actualFormatID != intendedFormatID;
220 }
221 
operator ==(const Format & lhs,const Format & rhs)222 bool operator==(const Format &lhs, const Format &rhs)
223 {
224     return &lhs == &rhs;
225 }
226 
operator !=(const Format & lhs,const Format & rhs)227 bool operator!=(const Format &lhs, const Format &rhs)
228 {
229     return &lhs != &rhs;
230 }
231 
232 // FormatTable implementation.
FormatTable()233 FormatTable::FormatTable() {}
234 
~FormatTable()235 FormatTable::~FormatTable() {}
236 
initialize(Renderer * renderer,gl::TextureCapsMap * outTextureCapsMap)237 void FormatTable::initialize(Renderer *renderer, gl::TextureCapsMap *outTextureCapsMap)
238 {
239     for (size_t formatIndex = 0; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
240     {
241         Format &format                           = mFormatData[formatIndex];
242         const auto intendedFormatID              = static_cast<angle::FormatID>(formatIndex);
243         const angle::Format &intendedAngleFormat = angle::Format::Get(intendedFormatID);
244 
245         format.initialize(renderer, intendedAngleFormat);
246         format.mIntendedFormatID = intendedFormatID;
247 
248         if (!format.valid())
249         {
250             continue;
251         }
252 
253         // No sample-able or render-able formats, so nothing left to do. This includes skipping the
254         // rest of the loop for buffer-only formats, since they are not texturable.
255         if (format.mActualSampleOnlyImageFormatID == angle::FormatID::NONE)
256         {
257             continue;
258         }
259 
260         bool transcodeEtcToBc = false;
261         if (renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
262             IsETCFormat(intendedFormatID) &&
263             !angle::Format::Get(format.mActualSampleOnlyImageFormatID).isBlock)
264         {
265             // Check BC format support
266             angle::FormatID bcFormat = GetTranscodeBCFormatID(intendedFormatID);
267             if (HasNonRenderableTextureFormatSupport(renderer, bcFormat))
268             {
269                 format.mActualSampleOnlyImageFormatID = bcFormat;
270                 transcodeEtcToBc                      = true;
271             }
272         }
273 
274         if (format.mActualRenderableImageFormatID == angle::FormatID::NONE)
275         {
276             // If renderable format was not set, it means there is no fallback format for
277             // renderable. We populate this the same formatID as sampleOnly formatID so that
278             // getActualFormatID() will be simpler.
279             format.mActualRenderableImageFormatID = format.mActualSampleOnlyImageFormatID;
280         }
281 
282         gl::TextureCaps textureCaps;
283         FillTextureFormatCaps(renderer, format.mActualSampleOnlyImageFormatID, &textureCaps);
284 
285         if (textureCaps.texturable)
286         {
287             format.mTextureLoadFunctions = GetLoadFunctionsMap(
288                 format.mIntendedGLFormat,
289                 transcodeEtcToBc ? intendedFormatID : format.mActualSampleOnlyImageFormatID);
290         }
291 
292         if (format.mActualRenderableImageFormatID == format.mActualSampleOnlyImageFormatID)
293         {
294             outTextureCapsMap->set(intendedFormatID, textureCaps);
295             format.mRenderableTextureLoadFunctions = format.mTextureLoadFunctions;
296         }
297         else
298         {
299             FillTextureFormatCaps(renderer, format.mActualRenderableImageFormatID, &textureCaps);
300             outTextureCapsMap->set(intendedFormatID, textureCaps);
301             if (textureCaps.texturable)
302             {
303                 format.mRenderableTextureLoadFunctions = GetLoadFunctionsMap(
304                     format.mIntendedGLFormat, format.mActualRenderableImageFormatID);
305             }
306         }
307     }
308 }
309 
getOrAllocExternalFormatID(uint64_t externalFormat,VkFormat colorAttachmentFormat,VkFormatFeatureFlags formatFeatures)310 angle::FormatID ExternalFormatTable::getOrAllocExternalFormatID(uint64_t externalFormat,
311                                                                 VkFormat colorAttachmentFormat,
312                                                                 VkFormatFeatureFlags formatFeatures)
313 {
314     std::unique_lock<angle::SimpleMutex> lock(mExternalYuvFormatMutex);
315     for (size_t index = 0; index < mExternalYuvFormats.size(); index++)
316     {
317         if (mExternalYuvFormats[index].externalFormat == externalFormat)
318         {
319             // Found a match. Just return existing formatID
320             return angle::FormatID(ToUnderlying(angle::FormatID::EXTERNAL0) + index);
321         }
322     }
323 
324     if (mExternalYuvFormats.size() >= kMaxExternalFormatCountSupported)
325     {
326         ERR() << "ANGLE only suports maximum " << kMaxExternalFormatCountSupported
327               << " external renderable formats";
328         return angle::FormatID::NONE;
329     }
330 
331     mExternalYuvFormats.push_back({externalFormat, colorAttachmentFormat, formatFeatures});
332     return angle::FormatID(ToUnderlying(angle::FormatID::EXTERNAL0) + mExternalYuvFormats.size() -
333                            1);
334 }
335 
getExternalFormatInfo(angle::FormatID formatID) const336 const ExternalYuvFormatInfo &ExternalFormatTable::getExternalFormatInfo(
337     angle::FormatID formatID) const
338 {
339     ASSERT(formatID >= angle::FormatID::EXTERNAL0);
340     size_t index = ToUnderlying(formatID) - ToUnderlying(angle::FormatID::EXTERNAL0);
341     ASSERT(index < mExternalYuvFormats.size());
342     return mExternalYuvFormats[index];
343 }
344 
IsYUVExternalFormat(angle::FormatID formatID)345 bool IsYUVExternalFormat(angle::FormatID formatID)
346 {
347     return formatID >= angle::FormatID::EXTERNAL0 && formatID <= angle::FormatID::EXTERNAL7;
348 }
349 
GetImageCopyBufferAlignment(angle::FormatID actualFormatID)350 size_t GetImageCopyBufferAlignment(angle::FormatID actualFormatID)
351 {
352     // vkCmdCopyBufferToImage must have an offset that is a multiple of 4 as well as a multiple
353     // of the texel size (if uncompressed) or pixel block size (if compressed).
354     // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html
355     //
356     // We need lcm(4, texelSize) (lcm = least common multiplier).  For compressed images,
357     // |texelSize| would contain the block size.  Since 4 is constant, this can be calculated as:
358     //
359     //                      | texelSize             texelSize % 4 == 0
360     //                      | 4 * texelSize         texelSize % 4 == 1
361     // lcm(4, texelSize) = <
362     //                      | 2 * texelSize         texelSize % 4 == 2
363     //                      | 4 * texelSize         texelSize % 4 == 3
364     //
365     // This means:
366     //
367     // - texelSize % 2 != 0 gives a 4x multiplier
368     // - else texelSize % 4 != 0 gives a 2x multiplier
369     // - else there's no multiplier.
370     //
371     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
372 
373     ASSERT(actualFormat.pixelBytes != 0);
374     const size_t texelSize  = actualFormat.pixelBytes;
375     const size_t multiplier = texelSize % 2 != 0 ? 4 : texelSize % 4 != 0 ? 2 : 1;
376     const size_t alignment  = multiplier * texelSize;
377 
378     return alignment;
379 }
380 
GetValidImageCopyBufferAlignment(angle::FormatID intendedFormatID,angle::FormatID actualFormatID)381 size_t GetValidImageCopyBufferAlignment(angle::FormatID intendedFormatID,
382                                         angle::FormatID actualFormatID)
383 {
384     constexpr size_t kMinimumAlignment = 16;
385     return (intendedFormatID == angle::FormatID::NONE)
386                ? kMinimumAlignment
387                : GetImageCopyBufferAlignment(actualFormatID);
388 }
389 
GetMaximalImageUsageFlags(Renderer * renderer,angle::FormatID formatID)390 VkImageUsageFlags GetMaximalImageUsageFlags(Renderer *renderer, angle::FormatID formatID)
391 {
392     constexpr VkFormatFeatureFlags kImageUsageFeatureBits =
393         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
394         VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
395         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
396     VkFormatFeatureFlags featureBits =
397         renderer->getImageFormatFeatureBits(formatID, kImageUsageFeatureBits);
398     VkImageUsageFlags imageUsageFlags = 0;
399     if (featureBits & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
400         imageUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
401     if (featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
402         imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
403     if (featureBits & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
404         imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
405     if (featureBits & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
406         imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
407     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
408         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
409     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
410         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
411     imageUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
412     return imageUsageFlags;
413 }
414 
GetMinimalImageCreateFlags(Renderer * renderer,gl::TextureType textureType,VkImageUsageFlags usage)415 VkImageCreateFlags GetMinimalImageCreateFlags(Renderer *renderer,
416                                               gl::TextureType textureType,
417                                               VkImageUsageFlags usage)
418 {
419     switch (textureType)
420     {
421         case gl::TextureType::CubeMap:
422         case gl::TextureType::CubeMapArray:
423             return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
424 
425         case gl::TextureType::_3D:
426         {
427             // Slices of this image may be used as:
428             //
429             // - Render target: The VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT flag is needed for that.
430             // - Sampled or storage image: The VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT flag is
431             //   needed for this.  If VK_EXT_image_2d_view_of_3d is not supported, we tolerate the
432             //   VVL error as drivers seem to support this behavior anyway.
433             VkImageCreateFlags flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
434 
435             if ((usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0)
436             {
437                 if (renderer->getFeatures().supportsImage2dViewOf3d.enabled)
438                 {
439                     flags |= VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
440                 }
441             }
442             else if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0)
443             {
444                 if (renderer->getFeatures().supportsSampler2dViewOf3d.enabled)
445                 {
446                     flags |= VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
447                 }
448             }
449 
450             return flags;
451         }
452 
453         default:
454             return 0;
455     }
456 }
457 
458 }  // namespace vk
459 
HasFullTextureFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)460 bool HasFullTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
461 {
462     constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
463                                     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
464                                     VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
465 
466     // In OpenGL ES, all renderable formats except 32-bit floating-point support blending.
467     // 32-bit floating-point case validation is handled by ANGLE's frontend.
468     uint32_t kBitsColorFull = kBitsColor;
469     switch (formatID)
470     {
471         case angle::FormatID::R32_FLOAT:
472         case angle::FormatID::R32G32_FLOAT:
473         case angle::FormatID::R32G32B32A32_FLOAT:
474             break;
475         default:
476             kBitsColorFull |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
477             break;
478     }
479 
480     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
481 
482     return renderer->hasImageFormatFeatureBits(formatID, kBitsColorFull) ||
483            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
484 }
485 
HasNonRenderableTextureFormatSupport(vk::Renderer * renderer,angle::FormatID formatID)486 bool HasNonRenderableTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
487 {
488     constexpr uint32_t kBitsColor =
489         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
490     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
491 
492     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
493            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
494 }
495 
496 // Checks if it is a ETC texture format
IsETCFormat(angle::FormatID formatID)497 bool IsETCFormat(angle::FormatID formatID)
498 {
499     return formatID >= angle::FormatID::EAC_R11G11_SNORM_BLOCK &&
500            formatID <= angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK;
501 }
502 // Checks if it is a BC texture format
IsBCFormat(angle::FormatID formatID)503 bool IsBCFormat(angle::FormatID formatID)
504 {
505     return formatID >= angle::FormatID::BC1_RGBA_UNORM_BLOCK &&
506            formatID <= angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK;
507 }
508 
509 static constexpr int kNumETCFormats = 12;
510 
511 static_assert((int)angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK ==
512               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + kNumETCFormats - 1);
513 
514 static_assert((int)angle::FormatID::EAC_R11G11_UNORM_BLOCK ==
515               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 1);
516 static_assert((int)angle::FormatID::EAC_R11_SNORM_BLOCK ==
517               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 2);
518 static_assert((int)angle::FormatID::EAC_R11_UNORM_BLOCK ==
519               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 3);
520 static_assert((int)angle::FormatID::ETC1_LOSSY_DECODE_R8G8B8_UNORM_BLOCK ==
521               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 4);
522 static_assert((int)angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK ==
523               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 5);
524 static_assert((int)angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK ==
525               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 6);
526 static_assert((int)angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK ==
527               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 7);
528 static_assert((int)angle::FormatID::ETC2_R8G8B8A8_SRGB_BLOCK ==
529               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 8);
530 static_assert((int)angle::FormatID::ETC2_R8G8B8A8_UNORM_BLOCK ==
531               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 9);
532 static_assert((int)angle::FormatID::ETC2_R8G8B8_SRGB_BLOCK ==
533               (int)angle::FormatID::EAC_R11G11_SNORM_BLOCK + 10);
534 
535 static const std::array<LoadImageFunction, kNumETCFormats> kEtcToBcLoadingFunc = {
536     angle::LoadEACRG11SToBC5,     // EAC_R11G11_SNORM
537     angle::LoadEACRG11ToBC5,      // EAC_R11G11_UNORM
538     angle::LoadEACR11SToBC4,      // EAC_R11_SNORM
539     angle::LoadEACR11ToBC4,       // EAC_R11_UNORM_BLOCK
540     angle::LoadETC1RGB8ToBC1,     // ETC1_LOSSY_DECODE_R8G8B8_UNORM
541     angle::LoadETC2RGB8ToBC1,     // ETC1_R8G8B8_UNORM
542     angle::LoadETC2SRGB8A1ToBC1,  // ETC2_R8G8B8A1_SRGB
543     angle::LoadETC2RGB8A1ToBC1,   // ETC2_R8G8B8A1_UNORM
544     angle::LoadETC2SRGBA8ToBC3,   // ETC2_R8G8B8A8_SRGB
545     angle::LoadETC2RGBA8ToBC3,    // ETC2_R8G8B8A8_UNORM
546     angle::LoadETC2SRGB8ToBC1,    // ETC2_R8G8B8_SRGB
547     angle::LoadETC2RGB8ToBC1,     // ETC2_R8G8B8_UNORM
548 };
549 
GetEtcToBcTransCodingFunc(angle::FormatID formatID)550 LoadImageFunctionInfo GetEtcToBcTransCodingFunc(angle::FormatID formatID)
551 {
552     ASSERT(IsETCFormat(formatID));
553     return LoadImageFunctionInfo(
554         kEtcToBcLoadingFunc[static_cast<uint32_t>(formatID) -
555                             static_cast<uint32_t>(angle::FormatID::EAC_R11G11_SNORM_BLOCK)],
556         true);
557 }
558 
559 static constexpr angle::FormatID kEtcToBcFormatMapping[] = {
560     angle::FormatID::BC5_RG_SNORM_BLOCK,         // EAC_R11G11_SNORM
561     angle::FormatID::BC5_RG_UNORM_BLOCK,         // EAC_R11G11_UNORM
562     angle::FormatID::BC4_RED_SNORM_BLOCK,        // EAC_R11_SNORM
563     angle::FormatID::BC4_RED_UNORM_BLOCK,        // EAC_R11_UNORM_BLOCK
564     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC1_LOSSY_DECODE_R8G8B8_UNORM
565     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC1_R8G8B8_UNORM
566     angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK,  // ETC2_R8G8B8A1_SRGB
567     angle::FormatID::BC1_RGBA_UNORM_BLOCK,       // ETC2_R8G8B8A1_UNORM
568     angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK,  // ETC2_R8G8B8A8_SRGB
569     angle::FormatID::BC3_RGBA_UNORM_BLOCK,       // ETC2_R8G8B8A8_UNORM
570     angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK,   // ETC2_R8G8B8_SRGB
571     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC2_R8G8B8_UNORM
572 };
573 
GetTranscodeBCFormatID(angle::FormatID formatID)574 angle::FormatID GetTranscodeBCFormatID(angle::FormatID formatID)
575 {
576     ASSERT(IsETCFormat(formatID));
577     return kEtcToBcFormatMapping[static_cast<uint32_t>(formatID) -
578                                  static_cast<uint32_t>(angle::FormatID::EAC_R11G11_SNORM_BLOCK)];
579 }
580 
GetSwizzleStateComponent(const gl::SwizzleState & swizzleState,GLenum component)581 GLenum GetSwizzleStateComponent(const gl::SwizzleState &swizzleState, GLenum component)
582 {
583     switch (component)
584     {
585         case GL_RED:
586             return swizzleState.swizzleRed;
587         case GL_GREEN:
588             return swizzleState.swizzleGreen;
589         case GL_BLUE:
590             return swizzleState.swizzleBlue;
591         case GL_ALPHA:
592             return swizzleState.swizzleAlpha;
593         default:
594             return component;
595     }
596 }
597 
ApplySwizzle(const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & toApply)598 gl::SwizzleState ApplySwizzle(const gl::SwizzleState &formatSwizzle,
599                               const gl::SwizzleState &toApply)
600 {
601     gl::SwizzleState result;
602 
603     result.swizzleRed   = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleRed);
604     result.swizzleGreen = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleGreen);
605     result.swizzleBlue  = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleBlue);
606     result.swizzleAlpha = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleAlpha);
607 
608     return result;
609 }
610 
GetFormatSwizzle(const angle::Format & angleFormat,const bool sized)611 gl::SwizzleState GetFormatSwizzle(const angle::Format &angleFormat, const bool sized)
612 {
613     gl::SwizzleState internalSwizzle;
614 
615     if (angleFormat.isLUMA())
616     {
617         GLenum swizzleRGB, swizzleA;
618         if (angleFormat.luminanceBits > 0)
619         {
620             swizzleRGB = GL_RED;
621             swizzleA   = (angleFormat.alphaBits > 0 ? GL_GREEN : GL_ONE);
622         }
623         else
624         {
625             swizzleRGB = GL_ZERO;
626             swizzleA   = GL_RED;
627         }
628         internalSwizzle.swizzleRed   = swizzleRGB;
629         internalSwizzle.swizzleGreen = swizzleRGB;
630         internalSwizzle.swizzleBlue  = swizzleRGB;
631         internalSwizzle.swizzleAlpha = swizzleA;
632     }
633     else
634     {
635         if (angleFormat.hasDepthOrStencilBits())
636         {
637             // In OES_depth_texture/ARB_depth_texture, depth
638             // textures are treated as luminance.
639             // If the internalformat was not sized, use OES_depth_texture behavior
640             bool hasGB = angleFormat.depthBits > 0 && !sized;
641 
642             internalSwizzle.swizzleRed   = GL_RED;
643             internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
644             internalSwizzle.swizzleBlue  = hasGB ? GL_RED : GL_ZERO;
645             internalSwizzle.swizzleAlpha = GL_ONE;
646         }
647         else
648         {
649             // Color bits are all zero for blocked formats
650             if (!angleFormat.isBlock)
651             {
652                 // Set any missing channel to default in case the emulated format has that channel.
653                 internalSwizzle.swizzleRed   = angleFormat.redBits > 0 ? GL_RED : GL_ZERO;
654                 internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO;
655                 internalSwizzle.swizzleBlue  = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO;
656                 internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE;
657             }
658         }
659     }
660 
661     return internalSwizzle;
662 }
663 }  // namespace rx
664