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