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