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