• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_format_utils:
7 //   Helper for Vulkan format code.
8 
9 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
10 
11 #include "libANGLE/Texture.h"
12 #include "libANGLE/formatutils.h"
13 #include "libANGLE/renderer/load_functions_table.h"
14 #include "libANGLE/renderer/vulkan/ContextVk.h"
15 #include "libANGLE/renderer/vulkan/RendererVk.h"
16 #include "libANGLE/renderer/vulkan/vk_caps_utils.h"
17 
18 namespace rx
19 {
20 namespace
21 {
FillTextureFormatCaps(RendererVk * renderer,VkFormat format,gl::TextureCaps * outTextureCaps)22 void FillTextureFormatCaps(RendererVk *renderer, VkFormat format, gl::TextureCaps *outTextureCaps)
23 {
24     const VkPhysicalDeviceLimits &physicalDeviceLimits =
25         renderer->getPhysicalDeviceProperties().limits;
26     bool hasColorAttachmentFeatureBit =
27         renderer->hasImageFormatFeatureBits(format, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
28     bool hasDepthAttachmentFeatureBit =
29         renderer->hasImageFormatFeatureBits(format, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
30 
31     outTextureCaps->texturable =
32         renderer->hasImageFormatFeatureBits(format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
33     outTextureCaps->filterable = renderer->hasImageFormatFeatureBits(
34         format, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
35     outTextureCaps->blendable =
36         renderer->hasImageFormatFeatureBits(format, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT);
37 
38     // For renderbuffer and texture attachments we require transfer and sampling for
39     // GLES 2.0 CopyTexImage support. Sampling is also required for other features like
40     // blits and EGLImages.
41     outTextureCaps->textureAttachment =
42         outTextureCaps->texturable &&
43         (hasColorAttachmentFeatureBit || hasDepthAttachmentFeatureBit);
44     outTextureCaps->renderbuffer = outTextureCaps->textureAttachment;
45 
46     if (outTextureCaps->renderbuffer)
47     {
48         if (hasColorAttachmentFeatureBit)
49         {
50             vk_gl::AddSampleCounts(physicalDeviceLimits.framebufferColorSampleCounts,
51                                    &outTextureCaps->sampleCounts);
52         }
53         if (hasDepthAttachmentFeatureBit)
54         {
55             // Some drivers report different depth and stencil sample counts.  We'll AND those
56             // counts together, limiting all depth and/or stencil formats to the lower number of
57             // sample counts.
58             vk_gl::AddSampleCounts((physicalDeviceLimits.framebufferDepthSampleCounts &
59                                     physicalDeviceLimits.framebufferStencilSampleCounts),
60                                    &outTextureCaps->sampleCounts);
61         }
62     }
63 }
64 
HasFullBufferFormatSupport(RendererVk * renderer,VkFormat vkFormat)65 bool HasFullBufferFormatSupport(RendererVk *renderer, VkFormat vkFormat)
66 {
67     return renderer->hasBufferFormatFeatureBits(vkFormat, VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
68 }
69 
70 using SupportTest = bool (*)(RendererVk *renderer, VkFormat vkFormat);
71 
72 template <class FormatInitInfo>
FindSupportedFormat(RendererVk * renderer,const FormatInitInfo * info,size_t skip,int numInfo,SupportTest hasSupport)73 int FindSupportedFormat(RendererVk *renderer,
74                         const FormatInitInfo *info,
75                         size_t skip,
76                         int numInfo,
77                         SupportTest hasSupport)
78 {
79     ASSERT(numInfo > 0);
80     const int last = numInfo - 1;
81 
82     for (int i = static_cast<int>(skip); i < last; ++i)
83     {
84         ASSERT(info[i].format != angle::FormatID::NONE);
85         if (hasSupport(renderer, info[i].vkFormat))
86             return i;
87     }
88 
89     if (skip > 0 && !hasSupport(renderer, info[last].vkFormat))
90     {
91         // We couldn't find a valid fallback, try again without skip
92         return FindSupportedFormat(renderer, info, 0, numInfo, hasSupport);
93     }
94 
95     ASSERT(info[last].format != angle::FormatID::NONE);
96     ASSERT(hasSupport(renderer, info[last].vkFormat));
97     return last;
98 }
99 
100 }  // anonymous namespace
101 
102 namespace vk
103 {
104 
105 // Format implementation.
Format()106 Format::Format()
107     : intendedFormatID(angle::FormatID::NONE),
108       internalFormat(GL_NONE),
109       actualImageFormatID(angle::FormatID::NONE),
110       vkImageFormat(VK_FORMAT_UNDEFINED),
111       actualBufferFormatID(angle::FormatID::NONE),
112       vkBufferFormat(VK_FORMAT_UNDEFINED),
113       imageInitializerFunction(nullptr),
114       textureLoadFunctions(),
115       vertexLoadRequiresConversion(false),
116       vkBufferFormatIsPacked(false),
117       vkFormatIsInt(false),
118       vkFormatIsUnsigned(false)
119 {}
120 
initImageFallback(RendererVk * renderer,const ImageFormatInitInfo * info,int numInfo)121 void Format::initImageFallback(RendererVk *renderer, const ImageFormatInitInfo *info, int numInfo)
122 {
123     size_t skip                 = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
124     SupportTest testFunction    = HasFullTextureFormatSupport;
125     const angle::Format &format = angle::Format::Get(info[0].format);
126     if (format.isInt() || (format.isFloat() && format.redBits >= 32))
127     {
128         // Integer formats don't support filtering in GL, so don't test for it.
129         // Filtering of 32-bit float textures is not supported on Android, and
130         // it's enabled by the extension OES_texture_float_linear, which is
131         // enabled automatically by examining format capabilities.
132         testFunction = HasNonFilterableTextureFormatSupport;
133     }
134     if (format.isSnorm() || format.isBlock)
135     {
136         // Rendering to SNORM textures is not supported on Android, and it's
137         // enabled by the extension EXT_render_snorm.
138         // Compressed textures also need to perform this check.
139         testFunction = HasNonRenderableTextureFormatSupport;
140     }
141     int i = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo), testFunction);
142 
143     actualImageFormatID      = info[i].format;
144     vkImageFormat            = info[i].vkFormat;
145     imageInitializerFunction = info[i].initializer;
146 }
147 
initBufferFallback(RendererVk * renderer,const BufferFormatInitInfo * info,int numInfo)148 void Format::initBufferFallback(RendererVk *renderer, const BufferFormatInitInfo *info, int numInfo)
149 {
150     size_t skip = renderer->getFeatures().forceFallbackFormat.enabled ? 1 : 0;
151     int i       = FindSupportedFormat(renderer, info, skip, static_cast<uint32_t>(numInfo),
152                                 HasFullBufferFormatSupport);
153 
154     actualBufferFormatID         = info[i].format;
155     vkBufferFormat               = info[i].vkFormat;
156     vkBufferFormatIsPacked       = info[i].vkFormatIsPacked;
157     vertexLoadFunction           = info[i].vertexLoadFunction;
158     vertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
159 }
160 
getImageCopyBufferAlignment() const161 size_t Format::getImageCopyBufferAlignment() const
162 {
163     // vkCmdCopyBufferToImage must have an offset that is a multiple of 4 as well as a multiple
164     // of the texel size (if uncompressed) or pixel block size (if compressed).
165     // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html
166     //
167     // We need lcm(4, texelSize) (lcm = least common multiplier).  For compressed images,
168     // |texelSize| would contain the block size.  Since 4 is constant, this can be calculated as:
169     //
170     //                      | texelSize             texelSize % 4 == 0
171     //                      | 4 * texelSize         texelSize % 4 == 1
172     // lcm(4, texelSize) = <
173     //                      | 2 * texelSize         texelSize % 4 == 2
174     //                      | 4 * texelSize         texelSize % 4 == 3
175     //
176     // This means:
177     //
178     // - texelSize % 2 != 0 gives a 4x multiplier
179     // - else texelSize % 4 != 0 gives a 2x multiplier
180     // - else there's no multiplier.
181     //
182     const angle::Format &format = actualImageFormat();
183 
184     ASSERT(format.pixelBytes != 0);
185     const size_t texelSize  = format.pixelBytes;
186     const size_t multiplier = texelSize % 2 != 0 ? 4 : texelSize % 4 != 0 ? 2 : 1;
187     const size_t alignment  = multiplier * texelSize;
188 
189     return alignment;
190 }
191 
hasEmulatedImageChannels() const192 bool Format::hasEmulatedImageChannels() const
193 {
194     const angle::Format &angleFmt   = intendedFormat();
195     const angle::Format &textureFmt = actualImageFormat();
196 
197     return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
198            (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
199            (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
200            (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
201            (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
202 }
203 
operator ==(const Format & lhs,const Format & rhs)204 bool operator==(const Format &lhs, const Format &rhs)
205 {
206     return &lhs == &rhs;
207 }
208 
operator !=(const Format & lhs,const Format & rhs)209 bool operator!=(const Format &lhs, const Format &rhs)
210 {
211     return &lhs != &rhs;
212 }
213 
214 // FormatTable implementation.
FormatTable()215 FormatTable::FormatTable() {}
216 
~FormatTable()217 FormatTable::~FormatTable() {}
218 
initialize(RendererVk * renderer,gl::TextureCapsMap * outTextureCapsMap,std::vector<GLenum> * outCompressedTextureFormats)219 void FormatTable::initialize(RendererVk *renderer,
220                              gl::TextureCapsMap *outTextureCapsMap,
221                              std::vector<GLenum> *outCompressedTextureFormats)
222 {
223     for (size_t formatIndex = 0; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
224     {
225         vk::Format &format               = mFormatData[formatIndex];
226         const auto formatID              = static_cast<angle::FormatID>(formatIndex);
227         const angle::Format &angleFormat = angle::Format::Get(formatID);
228 
229         format.initialize(renderer, angleFormat);
230         const GLenum internalFormat = format.internalFormat;
231         format.intendedFormatID     = formatID;
232 
233         if (!format.valid())
234         {
235             continue;
236         }
237 
238         gl::TextureCaps textureCaps;
239         FillTextureFormatCaps(renderer, format.vkImageFormat, &textureCaps);
240         outTextureCapsMap->set(formatID, textureCaps);
241 
242         if (textureCaps.texturable)
243         {
244             format.textureLoadFunctions =
245                 GetLoadFunctionsMap(internalFormat, format.actualImageFormatID);
246         }
247 
248         if (angleFormat.isBlock)
249         {
250             outCompressedTextureFormats->push_back(internalFormat);
251         }
252     }
253 }
254 
GetMaximalImageUsageFlags(RendererVk * renderer,VkFormat format)255 VkImageUsageFlags GetMaximalImageUsageFlags(RendererVk *renderer, VkFormat format)
256 {
257     constexpr VkFormatFeatureFlags kImageUsageFeatureBits =
258         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
259         VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
260         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
261     VkFormatFeatureFlags featureBits =
262         renderer->getImageFormatFeatureBits(format, kImageUsageFeatureBits);
263     VkImageUsageFlags imageUsageFlags = 0;
264     if (featureBits & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
265         imageUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
266     if (featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
267         imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
268     if (featureBits & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
269         imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
270     if (featureBits & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
271         imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
272     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
273         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
274     if (featureBits & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
275         imageUsageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
276     imageUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
277     return imageUsageFlags;
278 }
279 
280 }  // namespace vk
281 
HasFullTextureFormatSupport(RendererVk * renderer,VkFormat vkFormat)282 bool HasFullTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat)
283 {
284     constexpr uint32_t kBitsColor = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
285                                     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
286                                     VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
287     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
288 
289     return renderer->hasImageFormatFeatureBits(vkFormat, kBitsColor) ||
290            renderer->hasImageFormatFeatureBits(vkFormat, kBitsDepth);
291 }
292 
HasNonFilterableTextureFormatSupport(RendererVk * renderer,VkFormat vkFormat)293 bool HasNonFilterableTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat)
294 {
295     constexpr uint32_t kBitsColor =
296         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
297     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
298 
299     return renderer->hasImageFormatFeatureBits(vkFormat, kBitsColor) ||
300            renderer->hasImageFormatFeatureBits(vkFormat, kBitsDepth);
301 }
302 
HasNonRenderableTextureFormatSupport(RendererVk * renderer,VkFormat vkFormat)303 bool HasNonRenderableTextureFormatSupport(RendererVk *renderer, VkFormat vkFormat)
304 {
305     constexpr uint32_t kBitsColor =
306         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
307     constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
308 
309     return renderer->hasImageFormatFeatureBits(vkFormat, kBitsColor) ||
310            renderer->hasImageFormatFeatureBits(vkFormat, kBitsDepth);
311 }
312 
GetVertexInputAlignment(const vk::Format & format)313 size_t GetVertexInputAlignment(const vk::Format &format)
314 {
315     const angle::Format &bufferFormat = format.actualBufferFormat();
316     size_t pixelBytes                 = bufferFormat.pixelBytes;
317     return format.vkBufferFormatIsPacked ? pixelBytes : (pixelBytes / bufferFormat.channelCount);
318 }
319 
GetSwizzleStateComponent(const gl::SwizzleState & swizzleState,GLenum component)320 GLenum GetSwizzleStateComponent(const gl::SwizzleState &swizzleState, GLenum component)
321 {
322     switch (component)
323     {
324         case GL_RED:
325             return swizzleState.swizzleRed;
326         case GL_GREEN:
327             return swizzleState.swizzleGreen;
328         case GL_BLUE:
329             return swizzleState.swizzleBlue;
330         case GL_ALPHA:
331             return swizzleState.swizzleAlpha;
332         default:
333             return component;
334     }
335 }
336 
337 // Places the swizzle obtained by applying second after first into out.
ComposeSwizzleState(const gl::SwizzleState & first,const gl::SwizzleState & second,gl::SwizzleState * out)338 void ComposeSwizzleState(const gl::SwizzleState &first,
339                          const gl::SwizzleState &second,
340                          gl::SwizzleState *out)
341 {
342     out->swizzleRed   = GetSwizzleStateComponent(first, second.swizzleRed);
343     out->swizzleGreen = GetSwizzleStateComponent(first, second.swizzleGreen);
344     out->swizzleBlue  = GetSwizzleStateComponent(first, second.swizzleBlue);
345     out->swizzleAlpha = GetSwizzleStateComponent(first, second.swizzleAlpha);
346 }
347 
MapSwizzleState(const ContextVk * contextVk,const vk::Format & format,const bool sized,const gl::SwizzleState & swizzleState,gl::SwizzleState * swizzleStateOut)348 void MapSwizzleState(const ContextVk *contextVk,
349                      const vk::Format &format,
350                      const bool sized,
351                      const gl::SwizzleState &swizzleState,
352                      gl::SwizzleState *swizzleStateOut)
353 {
354     const angle::Format &angleFormat = format.intendedFormat();
355 
356     gl::SwizzleState internalSwizzle;
357 
358     if (angleFormat.isLUMA())
359     {
360         GLenum swizzleRGB, swizzleA;
361         if (angleFormat.luminanceBits > 0)
362         {
363             swizzleRGB = GL_RED;
364             swizzleA   = (angleFormat.alphaBits > 0 ? GL_GREEN : GL_ONE);
365         }
366         else
367         {
368             swizzleRGB = GL_ZERO;
369             swizzleA   = GL_RED;
370         }
371         internalSwizzle.swizzleRed   = swizzleRGB;
372         internalSwizzle.swizzleGreen = swizzleRGB;
373         internalSwizzle.swizzleBlue  = swizzleRGB;
374         internalSwizzle.swizzleAlpha = swizzleA;
375     }
376     else
377     {
378         if (angleFormat.hasDepthOrStencilBits())
379         {
380             bool hasRed = angleFormat.depthBits > 0;
381             // In OES_depth_texture/ARB_depth_texture, depth
382             // textures are treated as luminance.
383             // If the internalformat was not sized, use OES_depth_texture behavior
384             bool hasGB = hasRed && !sized;
385 
386             internalSwizzle.swizzleRed   = hasRed ? GL_RED : GL_ZERO;
387             internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
388             internalSwizzle.swizzleBlue  = hasGB ? GL_RED : GL_ZERO;
389             internalSwizzle.swizzleAlpha = GL_ONE;
390         }
391         else
392         {
393             // Color bits are all zero for blocked formats
394             if (!angleFormat.isBlock)
395             {
396                 // Set any missing channel to default in case the emulated format has that channel.
397                 internalSwizzle.swizzleRed   = angleFormat.redBits > 0 ? GL_RED : GL_ZERO;
398                 internalSwizzle.swizzleGreen = angleFormat.greenBits > 0 ? GL_GREEN : GL_ZERO;
399                 internalSwizzle.swizzleBlue  = angleFormat.blueBits > 0 ? GL_BLUE : GL_ZERO;
400                 internalSwizzle.swizzleAlpha = angleFormat.alphaBits > 0 ? GL_ALPHA : GL_ONE;
401             }
402         }
403     }
404     ComposeSwizzleState(internalSwizzle, swizzleState, swizzleStateOut);
405 }
406 }  // namespace rx
407