• 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 "libANGLE/Texture.h"
12 #include "libANGLE/formatutils.h"
13 #include "libANGLE/renderer/load_functions_table.h"
14 #include "libANGLE/renderer/vulkan/ContextVk.h"
15 #include "libANGLE/renderer/vulkan/RendererVk.h"
16 #include "libANGLE/renderer/vulkan/vk_caps_utils.h"
17 
18 namespace rx
19 {
20 namespace
21 {
FillTextureFormatCaps(RendererVk * renderer,angle::FormatID formatID,gl::TextureCaps * outTextureCaps)22 void FillTextureFormatCaps(RendererVk *renderer,
23                            angle::FormatID formatID,
24                            gl::TextureCaps *outTextureCaps)
25 {
26     const VkPhysicalDeviceLimits &physicalDeviceLimits =
27         renderer->getPhysicalDeviceProperties().limits;
28     bool hasColorAttachmentFeatureBit =
29         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
30     bool hasDepthAttachmentFeatureBit = renderer->hasImageFormatFeatureBits(
31         formatID, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
32 
33     outTextureCaps->texturable =
34         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
35     outTextureCaps->filterable = renderer->hasImageFormatFeatureBits(
36         formatID, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
37     outTextureCaps->blendable =
38         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT);
39 
40     // For renderbuffer and texture attachments we require transfer and sampling for
41     // GLES 2.0 CopyTexImage support. Sampling is also required for other features like
42     // blits and EGLImages.
43     outTextureCaps->textureAttachment =
44         outTextureCaps->texturable &&
45         (hasColorAttachmentFeatureBit || hasDepthAttachmentFeatureBit);
46     outTextureCaps->renderbuffer = outTextureCaps->textureAttachment;
47 
48     if (outTextureCaps->renderbuffer)
49     {
50         if (hasColorAttachmentFeatureBit)
51         {
52             vk_gl::AddSampleCounts(physicalDeviceLimits.framebufferColorSampleCounts,
53                                    &outTextureCaps->sampleCounts);
54         }
55         if (hasDepthAttachmentFeatureBit)
56         {
57             // Some drivers report different depth and stencil sample counts.  We'll AND those
58             // counts together, limiting all depth and/or stencil formats to the lower number of
59             // sample counts.
60             vk_gl::AddSampleCounts((physicalDeviceLimits.framebufferDepthSampleCounts &
61                                     physicalDeviceLimits.framebufferStencilSampleCounts),
62                                    &outTextureCaps->sampleCounts);
63         }
64     }
65 }
66 
HasFullBufferFormatSupport(RendererVk * renderer,angle::FormatID formatID)67 bool HasFullBufferFormatSupport(RendererVk *renderer, angle::FormatID formatID)
68 {
69     // Note: GL_EXT_texture_buffer support uses the same vkBufferFormat that is determined by
70     // Format::initBufferFallback, which uses this function.  That relies on the fact that formats
71     // required for GL_EXT_texture_buffer all have mandatory VERTEX_BUFFER feature support in
72     // Vulkan.  If this function is changed to test for more features in such a way that makes any
73     // of those formats use a fallback format, the implementation of GL_EXT_texture_buffer must be
74     // modified not to use vkBufferFormat.
75     return renderer->hasBufferFormatFeatureBits(formatID, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
76 }
77 
78 using SupportTest = bool (*)(RendererVk *renderer, angle::FormatID formatID);
79 
80 template <class FormatInitInfo>
FindSupportedFormat(RendererVk * renderer,const FormatInitInfo * info,size_t skip,int numInfo,SupportTest hasSupport)81 int FindSupportedFormat(RendererVk *renderer,
82                         const FormatInitInfo *info,
83                         size_t skip,
84                         int numInfo,
85                         SupportTest hasSupport)
86 {
87     ASSERT(numInfo > 0);
88     const int last = numInfo - 1;
89 
90     for (int i = static_cast<int>(skip); i < last; ++i)
91     {
92         ASSERT(info[i].format != angle::FormatID::NONE);
93         if (hasSupport(renderer, info[i].format))
94             return i;
95     }
96 
97     if (skip > 0 && !hasSupport(renderer, info[last].format))
98     {
99         // We couldn't find a valid fallback, try again without skip
100         return FindSupportedFormat(renderer, info, 0, numInfo, hasSupport);
101     }
102 
103     ASSERT(info[last].format != angle::FormatID::NONE);
104     ASSERT(hasSupport(renderer, info[last].format));
105     return last;
106 }
107 
HasNonFilterableTextureFormatSupport(RendererVk * renderer,angle::FormatID formatID)108 bool HasNonFilterableTextureFormatSupport(RendererVk *renderer, angle::FormatID formatID)
109 {
110     constexpr uint32_t kBitsColor =
111         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
112     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
113 
114     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
115            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
116 }
117 }  // anonymous namespace
118 
119 namespace vk
120 {
121 // Format implementation.
Format()122 Format::Format()
123     : mIntendedFormatID(angle::FormatID::NONE),
124       mIntendedGLFormat(GL_NONE),
125       mActualSampleOnlyImageFormatID(angle::FormatID::NONE),
126       mActualRenderableImageFormatID(angle::FormatID::NONE),
127       mActualBufferFormatID(angle::FormatID::NONE),
128       mActualCompressedBufferFormatID(angle::FormatID::NONE),
129       mImageInitializerFunction(nullptr),
130       mTextureLoadFunctions(),
131       mRenderableTextureLoadFunctions(),
132       mVertexLoadFunction(nullptr),
133       mCompressedVertexLoadFunction(nullptr),
134       mVertexLoadRequiresConversion(false),
135       mCompressedVertexLoadRequiresConversion(false),
136       mVkBufferFormatIsPacked(false),
137       mVkFormatIsInt(false),
138       mVkFormatIsUnsigned(false)
139 {}
140 
initImageFallback(RendererVk * renderer,const ImageFormatInitInfo * info,int numInfo)141 void Format::initImageFallback(RendererVk *renderer, const ImageFormatInitInfo *info, int numInfo)
142 {
143     size_t skip                 = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
144     SupportTest testFunction    = HasNonRenderableTextureFormatSupport;
145     const angle::Format &format = angle::Format::Get(info[0].format);
146     if (format.isInt() || (format.isFloat() && format.redBits >= 32))
147     {
148         // Integer formats don't support filtering in GL, so don't test for it.
149         // Filtering of 32-bit float textures is not supported on Android, and
150         // it's enabled by the extension OES_texture_float_linear, which is
151         // enabled automatically by examining format capabilities.
152         testFunction = HasNonFilterableTextureFormatSupport;
153     }
154 
155     int i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
156     mActualSampleOnlyImageFormatID = info[i].format;
157     mImageInitializerFunction      = info[i].initializer;
158 
159     // Set renderable format.
160     if (testFunction != HasNonFilterableTextureFormatSupport &&
161         !(format.isSnorm() && format.channelCount == 3) && !format.isBlock)
162     {
163         // Rendering to RGB SNORM textures is not supported on Android.
164         // Compressed textures also need to perform this check.
165         testFunction = HasFullTextureFormatSupport;
166         i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
167         mActualRenderableImageFormatID = info[i].format;
168     }
169 }
170 
initBufferFallback(RendererVk * renderer,const BufferFormatInitInfo * info,int numInfo,int compressedStartIndex)171 void Format::initBufferFallback(RendererVk *renderer,
172                                 const BufferFormatInitInfo *info,
173                                 int numInfo,
174                                 int compressedStartIndex)
175 {
176     {
177         size_t skip = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
178         int i       = FindSupportedFormat(renderer, info, skip, compressedStartIndex,
179                                           HasFullBufferFormatSupport);
180 
181         mActualBufferFormatID         = info[i].format;
182         mVkBufferFormatIsPacked       = info[i].vkFormatIsPacked;
183         mVertexLoadFunction           = info[i].vertexLoadFunction;
184         mVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
185     }
186 
187     if (renderer->getFeatures().compressVertexData.enabled && compressedStartIndex < numInfo)
188     {
189         int i = FindSupportedFormat(renderer, info, compressedStartIndex, numInfo,
190                                     HasFullBufferFormatSupport);
191 
192         mActualCompressedBufferFormatID         = info[i].format;
193         mVkCompressedBufferFormatIsPacked       = info[i].vkFormatIsPacked;
194         mCompressedVertexLoadFunction           = info[i].vertexLoadFunction;
195         mCompressedVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
196     }
197 }
198 
getVertexInputAlignment(bool compressed) const199 size_t Format::getVertexInputAlignment(bool compressed) const
200 {
201     const angle::Format &bufferFormat = getActualBufferFormat(compressed);
202     size_t pixelBytes                 = bufferFormat.pixelBytes;
203     return mVkBufferFormatIsPacked ? pixelBytes : (pixelBytes / bufferFormat.channelCount);
204 }
205 
HasEmulatedImageChannels(const angle::Format & intendedFormat,const angle::Format & actualFormat)206 bool HasEmulatedImageChannels(const angle::Format &intendedFormat,
207                               const angle::Format &actualFormat)
208 {
209     return (intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0) ||
210            (intendedFormat.blueBits == 0 && actualFormat.blueBits > 0) ||
211            (intendedFormat.greenBits == 0 && actualFormat.greenBits > 0) ||
212            (intendedFormat.depthBits == 0 && actualFormat.depthBits > 0) ||
213            (intendedFormat.stencilBits == 0 && actualFormat.stencilBits > 0);
214 }
215 
HasEmulatedImageFormat(angle::FormatID intendedFormatID,angle::FormatID actualFormatID)216 bool HasEmulatedImageFormat(angle::FormatID intendedFormatID, angle::FormatID actualFormatID)
217 {
218     return actualFormatID != intendedFormatID;
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 
operator !=(const Format & lhs,const Format & rhs)226 bool operator!=(const Format &lhs, const Format &rhs)
227 {
228     return &lhs != &rhs;
229 }
230 
231 // FormatTable implementation.
FormatTable()232 FormatTable::FormatTable() {}
233 
~FormatTable()234 FormatTable::~FormatTable() {}
235 
initialize(RendererVk * renderer,gl::TextureCapsMap * outTextureCapsMap)236 void FormatTable::initialize(RendererVk *renderer, gl::TextureCapsMap *outTextureCapsMap)
237 {
238     for (size_t formatIndex = 0; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
239     {
240         Format &format                           = mFormatData[formatIndex];
241         const auto intendedFormatID              = static_cast<angle::FormatID>(formatIndex);
242         const angle::Format &intendedAngleFormat = angle::Format::Get(intendedFormatID);
243 
244         format.initialize(renderer, intendedAngleFormat);
245         format.mIntendedFormatID = intendedFormatID;
246 
247         if (!format.valid())
248         {
249             continue;
250         }
251 
252         // No sample-able or render-able formats, so nothing left to do. This includes skipping the
253         // rest of the loop for buffer-only formats, since they are not texturable.
254         if (format.mActualSampleOnlyImageFormatID == angle::FormatID::NONE)
255         {
256             continue;
257         }
258 
259         bool transcodeEtcToBc = false;
260         if (renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
261             IsETCFormat(intendedFormatID) &&
262             !angle::Format::Get(format.mActualSampleOnlyImageFormatID).isBlock)
263         {
264             // Check BC format support
265             angle::FormatID bcFormat = GetTranscodeBCFormatID(intendedFormatID);
266             if (HasNonRenderableTextureFormatSupport(renderer, bcFormat))
267             {
268                 format.mActualSampleOnlyImageFormatID = bcFormat;
269                 transcodeEtcToBc                      = true;
270             }
271         }
272 
273         if (format.mActualRenderableImageFormatID == angle::FormatID::NONE)
274         {
275             // If renderable format was not set, it means there is no fallback format for
276             // renderable. We populate this the same formatID as sampleOnly formatID so that
277             // getActualFormatID() will be simpler.
278             format.mActualRenderableImageFormatID = format.mActualSampleOnlyImageFormatID;
279         }
280 
281         gl::TextureCaps textureCaps;
282         FillTextureFormatCaps(renderer, format.mActualSampleOnlyImageFormatID, &textureCaps);
283 
284         if (textureCaps.texturable)
285         {
286             format.mTextureLoadFunctions = GetLoadFunctionsMap(
287                 format.mIntendedGLFormat,
288                 transcodeEtcToBc ? intendedFormatID : format.mActualSampleOnlyImageFormatID);
289         }
290 
291         if (format.mActualRenderableImageFormatID == format.mActualSampleOnlyImageFormatID)
292         {
293             outTextureCapsMap->set(intendedFormatID, textureCaps);
294             format.mRenderableTextureLoadFunctions = format.mTextureLoadFunctions;
295         }
296         else
297         {
298             FillTextureFormatCaps(renderer, format.mActualRenderableImageFormatID, &textureCaps);
299             outTextureCapsMap->set(intendedFormatID, textureCaps);
300             if (textureCaps.texturable)
301             {
302                 format.mRenderableTextureLoadFunctions = GetLoadFunctionsMap(
303                     format.mIntendedGLFormat, format.mActualRenderableImageFormatID);
304             }
305         }
306     }
307 }
308 
GetImageCopyBufferAlignment(angle::FormatID actualFormatID)309 size_t GetImageCopyBufferAlignment(angle::FormatID actualFormatID)
310 {
311     // vkCmdCopyBufferToImage must have an offset that is a multiple of 4 as well as a multiple
312     // of the texel size (if uncompressed) or pixel block size (if compressed).
313     // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html
314     //
315     // We need lcm(4, texelSize) (lcm = least common multiplier).  For compressed images,
316     // |texelSize| would contain the block size.  Since 4 is constant, this can be calculated as:
317     //
318     //                      | texelSize             texelSize % 4 == 0
319     //                      | 4 * texelSize         texelSize % 4 == 1
320     // lcm(4, texelSize) = <
321     //                      | 2 * texelSize         texelSize % 4 == 2
322     //                      | 4 * texelSize         texelSize % 4 == 3
323     //
324     // This means:
325     //
326     // - texelSize % 2 != 0 gives a 4x multiplier
327     // - else texelSize % 4 != 0 gives a 2x multiplier
328     // - else there's no multiplier.
329     //
330     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
331 
332     ASSERT(actualFormat.pixelBytes != 0);
333     const size_t texelSize  = actualFormat.pixelBytes;
334     const size_t multiplier = texelSize % 2 != 0 ? 4 : texelSize % 4 != 0 ? 2 : 1;
335     const size_t alignment  = multiplier * texelSize;
336 
337     return alignment;
338 }
339 
GetValidImageCopyBufferAlignment(angle::FormatID intendedFormatID,angle::FormatID actualFormatID)340 size_t GetValidImageCopyBufferAlignment(angle::FormatID intendedFormatID,
341                                         angle::FormatID actualFormatID)
342 {
343     constexpr size_t kMinimumAlignment = 16;
344     return (intendedFormatID == angle::FormatID::NONE)
345                ? kMinimumAlignment
346                : GetImageCopyBufferAlignment(actualFormatID);
347 }
348 
GetMaximalImageUsageFlags(RendererVk * renderer,angle::FormatID formatID)349 VkImageUsageFlags GetMaximalImageUsageFlags(RendererVk *renderer, angle::FormatID formatID)
350 {
351     constexpr VkFormatFeatureFlags kImageUsageFeatureBits =
352         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
353         VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
354         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
355     VkFormatFeatureFlags featureBits =
356         renderer->getImageFormatFeatureBits(formatID, kImageUsageFeatureBits);
357     VkImageUsageFlags imageUsageFlags = 0;
358     if (featureBits & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
359         imageUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
360     if (featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
361         imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
362     if (featureBits & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
363         imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
364     if (featureBits & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
365         imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
366     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
367         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
368     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
369         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
370     imageUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
371     return imageUsageFlags;
372 }
373 }  // namespace vk
374 
HasFullTextureFormatSupport(RendererVk * renderer,angle::FormatID formatID)375 bool HasFullTextureFormatSupport(RendererVk *renderer, angle::FormatID formatID)
376 {
377     constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
378                                     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
379                                     VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
380 
381     // In OpenGL ES, all renderable formats except 32-bit floating-point support blending.
382     // 32-bit floating-point case validation is handled by ANGLE's frontend.
383     uint32_t kBitsColorFull = kBitsColor;
384     switch (formatID)
385     {
386         case angle::FormatID::R32_FLOAT:
387         case angle::FormatID::R32G32_FLOAT:
388         case angle::FormatID::R32G32B32A32_FLOAT:
389             break;
390         default:
391             kBitsColorFull |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
392             break;
393     }
394 
395     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
396 
397     return renderer->hasImageFormatFeatureBits(formatID, kBitsColorFull) ||
398            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
399 }
400 
HasNonRenderableTextureFormatSupport(RendererVk * renderer,angle::FormatID formatID)401 bool HasNonRenderableTextureFormatSupport(RendererVk *renderer, angle::FormatID formatID)
402 {
403     constexpr uint32_t kBitsColor =
404         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
405     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
406 
407     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
408            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
409 }
410 
411 // Checks if it is a ETC texture format
IsETCFormat(angle::FormatID formatID)412 bool IsETCFormat(angle::FormatID formatID)
413 {
414     return formatID >= angle::FormatID::EAC_R11G11_SNORM_BLOCK &&
415            formatID <= angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK;
416 }
417 // Checks if it is a BC texture format
IsBCFormat(angle::FormatID formatID)418 bool IsBCFormat(angle::FormatID formatID)
419 {
420     return formatID >= angle::FormatID::BC1_RGBA_UNORM_BLOCK &&
421            formatID <= angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK;
422 }
423 
424 static constexpr angle::FormatID kEtcToBcFormatMapping[] = {
425     angle::FormatID::BC5_RG_SNORM_BLOCK,         // EAC_R11G11_SNORM
426     angle::FormatID::BC5_RG_UNORM_BLOCK,         // EAC_R11G11_UNORM
427     angle::FormatID::BC4_RED_SNORM_BLOCK,        // EAC_R11_SNORM
428     angle::FormatID::BC4_RED_UNORM_BLOCK,        // EAC_R11_UNORM_BLOCK
429     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC1_LOSSY_DECODE_R8G8B8_UNORM
430     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC1_R8G8B8_UNORM
431     angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK,  // ETC2_R8G8B8A1_SRGB
432     angle::FormatID::BC1_RGBA_UNORM_BLOCK,       // ETC2_R8G8B8A1_UNORM
433     angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK,  // ETC2_R8G8B8A8_SRGB
434     angle::FormatID::BC3_RGBA_UNORM_BLOCK,       // ETC2_R8G8B8A8_UNORM
435     angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK,   // ETC2_R8G8B8_SRGB
436     angle::FormatID::BC1_RGB_UNORM_BLOCK,        // ETC2_R8G8B8_UNORM
437 };
438 
GetTranscodeBCFormatID(angle::FormatID formatID)439 angle::FormatID GetTranscodeBCFormatID(angle::FormatID formatID)
440 {
441     ASSERT(IsETCFormat(formatID));
442     return kEtcToBcFormatMapping[static_cast<uint32_t>(formatID) -
443                                  static_cast<uint32_t>(angle::FormatID::EAC_R11G11_SNORM_BLOCK)];
444 }
445 
GetSwizzleStateComponent(const gl::SwizzleState & swizzleState,GLenum component)446 GLenum GetSwizzleStateComponent(const gl::SwizzleState &swizzleState, GLenum component)
447 {
448     switch (component)
449     {
450         case GL_RED:
451             return swizzleState.swizzleRed;
452         case GL_GREEN:
453             return swizzleState.swizzleGreen;
454         case GL_BLUE:
455             return swizzleState.swizzleBlue;
456         case GL_ALPHA:
457             return swizzleState.swizzleAlpha;
458         default:
459             return component;
460     }
461 }
462 
ApplySwizzle(const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & toApply)463 gl::SwizzleState ApplySwizzle(const gl::SwizzleState &formatSwizzle,
464                               const gl::SwizzleState &toApply)
465 {
466     gl::SwizzleState result;
467 
468     result.swizzleRed   = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleRed);
469     result.swizzleGreen = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleGreen);
470     result.swizzleBlue  = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleBlue);
471     result.swizzleAlpha = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleAlpha);
472 
473     return result;
474 }
475 
GetFormatSwizzle(const angle::Format & angleFormat,const bool sized)476 gl::SwizzleState GetFormatSwizzle(const angle::Format &angleFormat, const bool sized)
477 {
478     gl::SwizzleState internalSwizzle;
479 
480     if (angleFormat.isLUMA())
481     {
482         GLenum swizzleRGB, swizzleA;
483         if (angleFormat.luminanceBits > 0)
484         {
485             swizzleRGB = GL_RED;
486             swizzleA   = (angleFormat.alphaBits > 0 ? GL_GREEN : GL_ONE);
487         }
488         else
489         {
490             swizzleRGB = GL_ZERO;
491             swizzleA   = GL_RED;
492         }
493         internalSwizzle.swizzleRed   = swizzleRGB;
494         internalSwizzle.swizzleGreen = swizzleRGB;
495         internalSwizzle.swizzleBlue  = swizzleRGB;
496         internalSwizzle.swizzleAlpha = swizzleA;
497     }
498     else
499     {
500         if (angleFormat.hasDepthOrStencilBits())
501         {
502             // In OES_depth_texture/ARB_depth_texture, depth
503             // textures are treated as luminance.
504             // If the internalformat was not sized, use OES_depth_texture behavior
505             bool hasGB = angleFormat.depthBits > 0 && !sized;
506 
507             internalSwizzle.swizzleRed   = GL_RED;
508             internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
509             internalSwizzle.swizzleBlue  = hasGB ? GL_RED : GL_ZERO;
510             internalSwizzle.swizzleAlpha = GL_ONE;
511         }
512         else
513         {
514             // Color bits are all zero for blocked formats
515             if (!angleFormat.isBlock)
516             {
517                 // Set any missing channel to default in case the emulated format has that channel.
518                 internalSwizzle.swizzleRed   = angleFormat.redBits > 0 ? GL_RED : GL_ZERO;
519                 internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO;
520                 internalSwizzle.swizzleBlue  = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO;
521                 internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE;
522             }
523         }
524     }
525 
526     return internalSwizzle;
527 }
528 }  // namespace rx
529