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