• 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/load_texture_border_functions_table.h"
15 #include "libANGLE/renderer/vulkan/ContextVk.h"
16 #include "libANGLE/renderer/vulkan/RendererVk.h"
17 #include "libANGLE/renderer/vulkan/vk_caps_utils.h"
18 
19 namespace rx
20 {
21 namespace
22 {
FillTextureFormatCaps(RendererVk * renderer,angle::FormatID formatID,gl::TextureCaps * outTextureCaps)23 void FillTextureFormatCaps(RendererVk *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(RendererVk * renderer,angle::FormatID formatID)68 bool HasFullBufferFormatSupport(RendererVk *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 (*)(RendererVk *renderer, angle::FormatID formatID);
80 
81 template <class FormatInitInfo>
FindSupportedFormat(RendererVk * renderer,const FormatInitInfo * info,size_t skip,int numInfo,SupportTest hasSupport)82 int FindSupportedFormat(RendererVk *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(RendererVk * renderer,angle::FormatID formatID)109 bool HasNonFilterableTextureFormatSupport(RendererVk *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     : intendedFormatID(angle::FormatID::NONE),
125       intendedGLFormat(GL_NONE),
126       actualImageFormatID(angle::FormatID::NONE),
127       actualBufferFormatID(angle::FormatID::NONE),
128       actualCompressedBufferFormatID(angle::FormatID::NONE),
129       imageInitializerFunction(nullptr),
130       textureLoadFunctions(),
131       vertexLoadFunction(nullptr),
132       compressedVertexLoadFunction(nullptr),
133       vertexLoadRequiresConversion(false),
134       compressedVertexLoadRequiresConversion(false),
135       vkBufferFormatIsPacked(false),
136       vkFormatIsInt(false),
137       vkFormatIsUnsigned(false)
138 {}
139 
initImageFallback(RendererVk * renderer,const ImageFormatInitInfo * info,int numInfo)140 void Format::initImageFallback(RendererVk *renderer, const ImageFormatInitInfo *info, int numInfo)
141 {
142     size_t skip                 = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
143     SupportTest testFunction    = HasFullTextureFormatSupport;
144     const angle::Format &format = angle::Format::Get(info[0].format);
145     if (format.isInt() || (format.isFloat() && format.redBits >= 32))
146     {
147         // Integer formats don't support filtering in GL, so don't test for it.
148         // Filtering of 32-bit float textures is not supported on Android, and
149         // it's enabled by the extension OES_texture_float_linear, which is
150         // enabled automatically by examining format capabilities.
151         testFunction = HasNonFilterableTextureFormatSupport;
152     }
153     if (format.isSnorm() || format.isBlock)
154     {
155         // Rendering to SNORM textures is not supported on Android, and it's
156         // enabled by the extension EXT_render_snorm.
157         // Compressed textures also need to perform this check.
158         testFunction = HasNonRenderableTextureFormatSupport;
159     }
160     int i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
161 
162     actualImageFormatID      = info[i].format;
163     imageInitializerFunction = info[i].initializer;
164 }
165 
initBufferFallback(RendererVk * renderer,const BufferFormatInitInfo * info,int numInfo,int compressedStartIndex)166 void Format::initBufferFallback(RendererVk *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         actualBufferFormatID         = info[i].format;
177         vkBufferFormatIsPacked       = info[i].vkFormatIsPacked;
178         vertexLoadFunction           = info[i].vertexLoadFunction;
179         vertexLoadRequiresConversion = 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         actualCompressedBufferFormatID         = info[i].format;
188         vkCompressedBufferFormatIsPacked       = info[i].vkFormatIsPacked;
189         compressedVertexLoadFunction           = info[i].vertexLoadFunction;
190         compressedVertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
191     }
192 }
193 
getImageCopyBufferAlignment() const194 size_t Format::getImageCopyBufferAlignment() const
195 {
196     // vkCmdCopyBufferToImage must have an offset that is a multiple of 4 as well as a multiple
197     // of the texel size (if uncompressed) or pixel block size (if compressed).
198     // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html
199     //
200     // We need lcm(4, texelSize) (lcm = least common multiplier).  For compressed images,
201     // |texelSize| would contain the block size.  Since 4 is constant, this can be calculated as:
202     //
203     //                      | texelSize             texelSize % 4 == 0
204     //                      | 4 * texelSize         texelSize % 4 == 1
205     // lcm(4, texelSize) = <
206     //                      | 2 * texelSize         texelSize % 4 == 2
207     //                      | 4 * texelSize         texelSize % 4 == 3
208     //
209     // This means:
210     //
211     // - texelSize % 2 != 0 gives a 4x multiplier
212     // - else texelSize % 4 != 0 gives a 2x multiplier
213     // - else there's no multiplier.
214     //
215     const angle::Format &format = actualImageFormat();
216 
217     ASSERT(format.pixelBytes != 0);
218     const size_t texelSize  = format.pixelBytes;
219     const size_t multiplier = texelSize % 2 != 0 ? 4 : texelSize % 4 != 0 ? 2 : 1;
220     const size_t alignment  = multiplier * texelSize;
221 
222     return alignment;
223 }
224 
getValidImageCopyBufferAlignment() const225 size_t Format::getValidImageCopyBufferAlignment() const
226 {
227     constexpr size_t kMinimumAlignment = 16;
228     return (intendedFormatID == angle::FormatID::NONE) ? kMinimumAlignment
229                                                        : getImageCopyBufferAlignment();
230 }
231 
hasEmulatedImageChannels() const232 bool Format::hasEmulatedImageChannels() const
233 {
234     const angle::Format &angleFmt   = intendedFormat();
235     const angle::Format &textureFmt = actualImageFormat();
236 
237     return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
238            (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
239            (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
240            (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
241            (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
242 }
243 
operator ==(const Format & lhs,const Format & rhs)244 bool operator==(const Format &lhs, const Format &rhs)
245 {
246     return &lhs == &rhs;
247 }
248 
operator !=(const Format & lhs,const Format & rhs)249 bool operator!=(const Format &lhs, const Format &rhs)
250 {
251     return &lhs != &rhs;
252 }
253 
254 // FormatTable implementation.
FormatTable()255 FormatTable::FormatTable() {}
256 
~FormatTable()257 FormatTable::~FormatTable() {}
258 
initialize(RendererVk * renderer,gl::TextureCapsMap * outTextureCapsMap,std::vector<GLenum> * outCompressedTextureFormats)259 void FormatTable::initialize(RendererVk *renderer,
260                              gl::TextureCapsMap *outTextureCapsMap,
261                              std::vector<GLenum> *outCompressedTextureFormats)
262 {
263     for (size_t formatIndex = 0; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
264     {
265         Format &format                   = mFormatData[formatIndex];
266         const auto formatID              = static_cast<angle::FormatID>(formatIndex);
267         const angle::Format &angleFormat = angle::Format::Get(formatID);
268 
269         format.initialize(renderer, angleFormat);
270         format.intendedFormatID = formatID;
271 
272         if (!format.valid())
273         {
274             continue;
275         }
276 
277         gl::TextureCaps textureCaps;
278         FillTextureFormatCaps(renderer, format.actualImageFormatID, &textureCaps);
279         outTextureCapsMap->set(formatID, textureCaps);
280 
281         if (textureCaps.texturable)
282         {
283             format.textureLoadFunctions =
284                 GetLoadFunctionsMap(format.intendedGLFormat, format.actualImageFormatID);
285             format.textureBorderLoadFunctions = GetLoadTextureBorderFunctionsMap(
286                 format.intendedGLFormat, format.actualImageFormatID);
287         }
288 
289         if (angleFormat.isBlock)
290         {
291             outCompressedTextureFormats->push_back(format.intendedGLFormat);
292         }
293     }
294 }
295 
GetMaximalImageUsageFlags(RendererVk * renderer,angle::FormatID formatID)296 VkImageUsageFlags GetMaximalImageUsageFlags(RendererVk *renderer, angle::FormatID formatID)
297 {
298     constexpr VkFormatFeatureFlags kImageUsageFeatureBits =
299         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
300         VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
301         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
302     VkFormatFeatureFlags featureBits =
303         renderer->getImageFormatFeatureBits(formatID, kImageUsageFeatureBits);
304     VkImageUsageFlags imageUsageFlags = 0;
305     if (featureBits & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
306         imageUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
307     if (featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
308         imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
309     if (featureBits & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
310         imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
311     if (featureBits & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
312         imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
313     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
314         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
315     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
316         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
317     imageUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
318     return imageUsageFlags;
319 }
320 }  // namespace vk
321 
HasFullTextureFormatSupport(RendererVk * renderer,angle::FormatID formatID)322 bool HasFullTextureFormatSupport(RendererVk *renderer, angle::FormatID formatID)
323 {
324     constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
325                                     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
326                                     VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
327 
328     // In OpenGL ES, all renderable formats except 32-bit floating-point support blending.
329     // 32-bit floating-point case validation is handled by ANGLE's frontend.
330     uint32_t kBitsColorFull = kBitsColor;
331     switch (formatID)
332     {
333         case angle::FormatID::R32_FLOAT:
334         case angle::FormatID::R32G32_FLOAT:
335         case angle::FormatID::R32G32B32A32_FLOAT:
336             break;
337         default:
338             kBitsColorFull |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
339             break;
340     }
341 
342     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
343 
344     return renderer->hasImageFormatFeatureBits(formatID, kBitsColorFull) ||
345            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
346 }
347 
HasNonRenderableTextureFormatSupport(RendererVk * renderer,angle::FormatID formatID)348 bool HasNonRenderableTextureFormatSupport(RendererVk *renderer, angle::FormatID formatID)
349 {
350     constexpr uint32_t kBitsColor =
351         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
352     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
353 
354     return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) ||
355            renderer->hasImageFormatFeatureBits(formatID, kBitsDepth);
356 }
357 
GetVertexInputAlignment(const vk::Format & format,bool compressed)358 size_t GetVertexInputAlignment(const vk::Format &format, bool compressed)
359 {
360     const angle::Format &bufferFormat = format.actualBufferFormat(compressed);
361     size_t pixelBytes                 = bufferFormat.pixelBytes;
362     return format.vkBufferFormatIsPacked ? pixelBytes : (pixelBytes / bufferFormat.channelCount);
363 }
364 
GetSwizzleStateComponent(const gl::SwizzleState & swizzleState,GLenum component)365 GLenum GetSwizzleStateComponent(const gl::SwizzleState &swizzleState, GLenum component)
366 {
367     switch (component)
368     {
369         case GL_RED:
370             return swizzleState.swizzleRed;
371         case GL_GREEN:
372             return swizzleState.swizzleGreen;
373         case GL_BLUE:
374             return swizzleState.swizzleBlue;
375         case GL_ALPHA:
376             return swizzleState.swizzleAlpha;
377         default:
378             return component;
379     }
380 }
381 
ApplySwizzle(const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & toApply)382 gl::SwizzleState ApplySwizzle(const gl::SwizzleState &formatSwizzle,
383                               const gl::SwizzleState &toApply)
384 {
385     gl::SwizzleState result;
386 
387     result.swizzleRed   = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleRed);
388     result.swizzleGreen = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleGreen);
389     result.swizzleBlue  = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleBlue);
390     result.swizzleAlpha = GetSwizzleStateComponent(formatSwizzle, toApply.swizzleAlpha);
391 
392     return result;
393 }
394 
GetFormatSwizzle(const ContextVk * contextVk,const vk::Format & format,const bool sized)395 gl::SwizzleState GetFormatSwizzle(const ContextVk *contextVk,
396                                   const vk::Format &format,
397                                   const bool sized)
398 {
399     const angle::Format &angleFormat = format.intendedFormat();
400 
401     gl::SwizzleState internalSwizzle;
402 
403     if (angleFormat.isLUMA())
404     {
405         GLenum swizzleRGB, swizzleA;
406         if (angleFormat.luminanceBits > 0)
407         {
408             swizzleRGB = GL_RED;
409             swizzleA   = (angleFormat.alphaBits > 0 ? GL_GREEN : GL_ONE);
410         }
411         else
412         {
413             swizzleRGB = GL_ZERO;
414             swizzleA   = GL_RED;
415         }
416         internalSwizzle.swizzleRed   = swizzleRGB;
417         internalSwizzle.swizzleGreen = swizzleRGB;
418         internalSwizzle.swizzleBlue  = swizzleRGB;
419         internalSwizzle.swizzleAlpha = swizzleA;
420     }
421     else
422     {
423         if (angleFormat.hasDepthOrStencilBits())
424         {
425             // In OES_depth_texture/ARB_depth_texture, depth
426             // textures are treated as luminance.
427             // If the internalformat was not sized, use OES_depth_texture behavior
428             bool hasGB = (angleFormat.depthBits > 0) && !sized;
429 
430             internalSwizzle.swizzleRed   = GL_RED;
431             internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
432             internalSwizzle.swizzleBlue  = hasGB ? GL_RED : GL_ZERO;
433             internalSwizzle.swizzleAlpha = GL_ONE;
434         }
435         else
436         {
437             // Color bits are all zero for blocked formats
438             if (!angleFormat.isBlock)
439             {
440                 // Set any missing channel to default in case the emulated format has that channel.
441                 internalSwizzle.swizzleRed   = angleFormat.redBits > 0 ? GL_RED : GL_ZERO;
442                 internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO;
443                 internalSwizzle.swizzleBlue  = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO;
444                 internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE;
445             }
446         }
447     }
448 
449     return internalSwizzle;
450 }
451 }  // namespace rx
452