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