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