1 //
2 // Copyright 2018 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_utils:
7 // Helper functions for the Vulkan Caps.
8 //
9
10 #include "libANGLE/renderer/vulkan/vk_caps_utils.h"
11
12 #include <type_traits>
13
14 #include "common/utilities.h"
15 #include "libANGLE/Caps.h"
16 #include "libANGLE/formatutils.h"
17 #include "libANGLE/renderer/driver_utils.h"
18 #include "libANGLE/renderer/vulkan/DisplayVk.h"
19 #include "libANGLE/renderer/vulkan/RendererVk.h"
20 #include "vk_format_utils.h"
21
22 namespace
23 {
24 constexpr unsigned int kComponentsPerVector = 4;
25 } // anonymous namespace
26
27 namespace rx
28 {
29
LimitToInt(const uint32_t physicalDeviceValue)30 GLint LimitToInt(const uint32_t physicalDeviceValue)
31 {
32 // Limit to INT_MAX / 2 instead of INT_MAX. If the limit is queried as float, the imprecision
33 // in floating point can cause the value to exceed INT_MAX. This trips dEQP up.
34 return std::min(physicalDeviceValue,
35 static_cast<uint32_t>(std::numeric_limits<int32_t>::max() / 2));
36 }
37
ensureCapsInitialized() const38 void RendererVk::ensureCapsInitialized() const
39 {
40 if (mCapsInitialized)
41 return;
42 mCapsInitialized = true;
43
44 ASSERT(mCurrentQueueFamilyIndex < mQueueFamilyProperties.size());
45 const VkQueueFamilyProperties &queueFamilyProperties =
46 mQueueFamilyProperties[mCurrentQueueFamilyIndex];
47 const VkPhysicalDeviceLimits &limitsVk = mPhysicalDeviceProperties.limits;
48
49 mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
50
51 // TODO: http://anglebug.com/3609
52 // Due to a dEQP bug, this extension cannot be exposed until EXT_texture_sRGB_decode is
53 // implemented
54 mNativeExtensions.sRGBR8EXT = false;
55
56 // To ensure that ETC2/EAC formats are enabled only on hardware that supports them natively,
57 // this flag is not set by the function above and must be set explicitly. It exposes
58 // ANGLE_compressed_texture_etc extension string.
59 mNativeExtensions.compressedTextureETC =
60 (mPhysicalDeviceFeatures.textureCompressionETC2 == VK_TRUE) &&
61 gl::DetermineCompressedTextureETCSupport(mNativeTextureCaps);
62
63 // Vulkan doesn't support ASTC 3D block textures, which are required by
64 // GL_OES_texture_compression_astc.
65 mNativeExtensions.textureCompressionASTCOES = false;
66
67 // Vulkan doesn't guarantee HDR blocks decoding without VK_EXT_texture_compression_astc_hdr.
68 mNativeExtensions.textureCompressionASTCHDRKHR = false;
69
70 // Vulkan supports sliced 3D ASTC texture uploads when ASTC is supported.
71 mNativeExtensions.textureCompressionSliced3dASTCKHR =
72 mNativeExtensions.textureCompressionASTCLDRKHR;
73
74 // Enable EXT_compressed_ETC1_RGB8_sub_texture
75 mNativeExtensions.compressedETC1RGB8SubTexture = mNativeExtensions.compressedETC1RGB8TextureOES;
76
77 // Enable this for simple buffer readback testing, but some functionality is missing.
78 // TODO(jmadill): Support full mapBufferRange extension.
79 mNativeExtensions.mapBufferOES = true;
80 mNativeExtensions.mapBufferRange = true;
81 mNativeExtensions.textureStorage = true;
82 mNativeExtensions.drawBuffers = true;
83 mNativeExtensions.fragDepth = true;
84 mNativeExtensions.framebufferBlit = true;
85 mNativeExtensions.framebufferMultisample = true;
86 mNativeExtensions.copyTexture = true;
87 mNativeExtensions.copyCompressedTexture = true;
88 mNativeExtensions.debugMarker = true;
89 mNativeExtensions.robustness =
90 !IsSwiftshader(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID);
91 mNativeExtensions.textureBorderClampOES = false; // not implemented yet
92 mNativeExtensions.translatedShaderSource = true;
93 mNativeExtensions.discardFramebuffer = true;
94
95 // Enable EXT_texture_type_2_10_10_10_REV
96 mNativeExtensions.textureFormat2101010REV = true;
97
98 // Enable ANGLE_base_vertex_base_instance
99 mNativeExtensions.baseVertexBaseInstance = true;
100
101 // Enable OES/EXT_draw_elements_base_vertex
102 mNativeExtensions.drawElementsBaseVertexOES = true;
103 mNativeExtensions.drawElementsBaseVertexEXT = true;
104
105 // Enable EXT_blend_minmax
106 mNativeExtensions.blendMinMax = true;
107
108 mNativeExtensions.eglImageOES = true;
109 mNativeExtensions.eglImageExternalOES = true;
110 mNativeExtensions.eglImageExternalWrapModesEXT = true;
111 mNativeExtensions.eglImageExternalEssl3OES = true;
112 mNativeExtensions.eglImageArray = true;
113 mNativeExtensions.memoryObject = true;
114 mNativeExtensions.memoryObjectFd = getFeatures().supportsExternalMemoryFd.enabled;
115 mNativeExtensions.memoryObjectFuchsiaANGLE =
116 getFeatures().supportsExternalMemoryFuchsia.enabled;
117
118 mNativeExtensions.semaphore = true;
119 mNativeExtensions.semaphoreFd = getFeatures().supportsExternalSemaphoreFd.enabled;
120 mNativeExtensions.semaphoreFuchsiaANGLE =
121 getFeatures().supportsExternalSemaphoreFuchsia.enabled;
122
123 mNativeExtensions.vertexHalfFloatOES = true;
124
125 // Enabled in HW if VK_EXT_vertex_attribute_divisor available, otherwise emulated
126 mNativeExtensions.instancedArraysANGLE = true;
127 mNativeExtensions.instancedArraysEXT = true;
128
129 // Only expose robust buffer access if the physical device supports it.
130 mNativeExtensions.robustBufferAccessBehavior =
131 (mPhysicalDeviceFeatures.robustBufferAccess == VK_TRUE);
132
133 mNativeExtensions.eglSyncOES = true;
134
135 mNativeExtensions.vertexAttribType1010102OES = true;
136
137 // We use secondary command buffers almost everywhere and they require a feature to be
138 // able to execute in the presence of queries. As a result, we won't support queries
139 // unless that feature is available.
140 mNativeExtensions.occlusionQueryBoolean =
141 vk::CommandBuffer::SupportsQueries(mPhysicalDeviceFeatures);
142
143 // From the Vulkan specs:
144 // > The number of valid bits in a timestamp value is determined by the
145 // > VkQueueFamilyProperties::timestampValidBits property of the queue on which the timestamp is
146 // > written. Timestamps are supported on any queue which reports a non-zero value for
147 // > timestampValidBits via vkGetPhysicalDeviceQueueFamilyProperties.
148 mNativeExtensions.disjointTimerQuery = queueFamilyProperties.timestampValidBits > 0;
149 mNativeExtensions.queryCounterBitsTimeElapsed = queueFamilyProperties.timestampValidBits;
150 mNativeExtensions.queryCounterBitsTimestamp = queueFamilyProperties.timestampValidBits;
151
152 mNativeExtensions.textureFilterAnisotropic =
153 mPhysicalDeviceFeatures.samplerAnisotropy && limitsVk.maxSamplerAnisotropy > 1.0f;
154 mNativeExtensions.maxTextureAnisotropy =
155 mNativeExtensions.textureFilterAnisotropic ? limitsVk.maxSamplerAnisotropy : 0.0f;
156
157 // Vulkan natively supports non power-of-two textures
158 mNativeExtensions.textureNPOTOES = true;
159
160 mNativeExtensions.texture3DOES = true;
161
162 // Vulkan natively supports standard derivatives
163 mNativeExtensions.standardDerivativesOES = true;
164
165 // Vulkan natively supports noperspective interpolation
166 mNativeExtensions.noperspectiveInterpolationNV = true;
167
168 // Vulkan natively supports 32-bit indices, entry in kIndexTypeMap
169 mNativeExtensions.elementIndexUintOES = true;
170
171 mNativeExtensions.fboRenderMipmapOES = true;
172
173 // We support getting image data for Textures and Renderbuffers.
174 mNativeExtensions.getImageANGLE = true;
175
176 // Implemented in the translator
177 mNativeExtensions.shaderNonConstGlobalInitializersEXT = true;
178
179 // Vulkan has no restrictions of the format of cubemaps, so if the proper formats are supported,
180 // creating a cube of any of these formats should be implicitly supported.
181 mNativeExtensions.depthTextureCubeMapOES =
182 mNativeExtensions.depthTextureOES && mNativeExtensions.packedDepthStencilOES;
183
184 // Vulkan natively supports format reinterpretation
185 mNativeExtensions.textureSRGBOverride = mNativeExtensions.sRGB;
186
187 mNativeExtensions.gpuShader5EXT = vk::CanSupportGPUShader5EXT(mPhysicalDeviceFeatures);
188
189 mNativeExtensions.textureFilteringCHROMIUM = getFeatures().supportsFilteringPrecision.enabled;
190
191 // https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
192 mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1;
193 mNativeCaps.max3DTextureSize = LimitToInt(limitsVk.maxImageDimension3D);
194 mNativeCaps.max2DTextureSize =
195 std::min(limitsVk.maxFramebufferWidth, limitsVk.maxImageDimension2D);
196 mNativeCaps.maxArrayTextureLayers = LimitToInt(limitsVk.maxImageArrayLayers);
197 mNativeCaps.maxLODBias = limitsVk.maxSamplerLodBias;
198 mNativeCaps.maxCubeMapTextureSize = LimitToInt(limitsVk.maxImageDimensionCube);
199 mNativeCaps.maxRenderbufferSize =
200 std::min({limitsVk.maxImageDimension2D, limitsVk.maxFramebufferWidth,
201 limitsVk.maxFramebufferHeight});
202 mNativeCaps.minAliasedPointSize = std::max(1.0f, limitsVk.pointSizeRange[0]);
203 mNativeCaps.maxAliasedPointSize = limitsVk.pointSizeRange[1];
204
205 mNativeCaps.minAliasedLineWidth = 1.0f;
206 mNativeCaps.maxAliasedLineWidth = 1.0f;
207
208 mNativeCaps.maxDrawBuffers =
209 std::min(limitsVk.maxColorAttachments, limitsVk.maxFragmentOutputAttachments);
210 mNativeCaps.maxFramebufferWidth = LimitToInt(limitsVk.maxFramebufferWidth);
211 mNativeCaps.maxFramebufferHeight = LimitToInt(limitsVk.maxFramebufferHeight);
212 mNativeCaps.maxColorAttachments = LimitToInt(limitsVk.maxColorAttachments);
213 mNativeCaps.maxViewportWidth = LimitToInt(limitsVk.maxViewportDimensions[0]);
214 mNativeCaps.maxViewportHeight = LimitToInt(limitsVk.maxViewportDimensions[1]);
215 mNativeCaps.maxSampleMaskWords = LimitToInt(limitsVk.maxSampleMaskWords);
216 mNativeCaps.maxColorTextureSamples =
217 limitsVk.sampledImageColorSampleCounts & vk_gl::kSupportedSampleCounts;
218 mNativeCaps.maxDepthTextureSamples =
219 limitsVk.sampledImageDepthSampleCounts & vk_gl::kSupportedSampleCounts;
220 // TODO (ianelliott): Should mask this with vk_gl::kSupportedSampleCounts, but it causes
221 // end2end test failures with SwiftShader because SwiftShader returns a sample count of 1 in
222 // sampledImageIntegerSampleCounts.
223 // See: http://anglebug.com/4197
224 mNativeCaps.maxIntegerSamples = limitsVk.sampledImageIntegerSampleCounts;
225
226 mNativeCaps.maxVertexAttributes = LimitToInt(limitsVk.maxVertexInputAttributes);
227 mNativeCaps.maxVertexAttribBindings = LimitToInt(limitsVk.maxVertexInputBindings);
228 // Offset and stride are stored as uint16_t in PackedAttribDesc.
229 mNativeCaps.maxVertexAttribRelativeOffset =
230 std::min(static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()),
231 limitsVk.maxVertexInputAttributeOffset);
232 mNativeCaps.maxVertexAttribStride =
233 std::min(static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()),
234 limitsVk.maxVertexInputBindingStride);
235
236 mNativeCaps.maxElementsIndices = std::numeric_limits<GLint>::max();
237 mNativeCaps.maxElementsVertices = std::numeric_limits<GLint>::max();
238
239 // Looks like all floats are IEEE according to the docs here:
240 // https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#spirvenv-precision-operation
241 mNativeCaps.vertexHighpFloat.setIEEEFloat();
242 mNativeCaps.vertexMediumpFloat.setIEEEFloat();
243 mNativeCaps.vertexLowpFloat.setIEEEFloat();
244 mNativeCaps.fragmentHighpFloat.setIEEEFloat();
245 mNativeCaps.fragmentMediumpFloat.setIEEEFloat();
246 mNativeCaps.fragmentLowpFloat.setIEEEFloat();
247
248 // Can't find documentation on the int precision in Vulkan.
249 mNativeCaps.vertexHighpInt.setTwosComplementInt(32);
250 mNativeCaps.vertexMediumpInt.setTwosComplementInt(32);
251 mNativeCaps.vertexLowpInt.setTwosComplementInt(32);
252 mNativeCaps.fragmentHighpInt.setTwosComplementInt(32);
253 mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32);
254 mNativeCaps.fragmentLowpInt.setTwosComplementInt(32);
255
256 // Compute shader limits.
257 mNativeCaps.maxComputeWorkGroupCount[0] = LimitToInt(limitsVk.maxComputeWorkGroupCount[0]);
258 mNativeCaps.maxComputeWorkGroupCount[1] = LimitToInt(limitsVk.maxComputeWorkGroupCount[1]);
259 mNativeCaps.maxComputeWorkGroupCount[2] = LimitToInt(limitsVk.maxComputeWorkGroupCount[2]);
260 mNativeCaps.maxComputeWorkGroupSize[0] = LimitToInt(limitsVk.maxComputeWorkGroupSize[0]);
261 mNativeCaps.maxComputeWorkGroupSize[1] = LimitToInt(limitsVk.maxComputeWorkGroupSize[1]);
262 mNativeCaps.maxComputeWorkGroupSize[2] = LimitToInt(limitsVk.maxComputeWorkGroupSize[2]);
263 mNativeCaps.maxComputeWorkGroupInvocations =
264 LimitToInt(limitsVk.maxComputeWorkGroupInvocations);
265 mNativeCaps.maxComputeSharedMemorySize = LimitToInt(limitsVk.maxComputeSharedMemorySize);
266
267 // TODO(lucferron): This is something we'll need to implement custom in the back-end.
268 // Vulkan doesn't do any waiting for you, our back-end code is going to manage sync objects,
269 // and we'll have to check that we've exceeded the max wait timeout. Also, this is ES 3.0 so
270 // we'll defer the implementation until we tackle the next version.
271 // mNativeCaps.maxServerWaitTimeout
272
273 GLuint maxUniformBlockSize = limitsVk.maxUniformBufferRange;
274
275 // Clamp the maxUniformBlockSize to 64KB (majority of devices support up to this size
276 // currently), on AMD the maxUniformBufferRange is near uint32_t max.
277 maxUniformBlockSize = std::min(0x10000u, maxUniformBlockSize);
278
279 const GLuint maxUniformVectors = maxUniformBlockSize / (sizeof(GLfloat) * kComponentsPerVector);
280 const GLuint maxUniformComponents = maxUniformVectors * kComponentsPerVector;
281
282 // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
283 // support is the max buffer range divided by the size of a single uniform (4X float).
284 mNativeCaps.maxVertexUniformVectors = maxUniformVectors;
285 mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
286 mNativeCaps.maxFragmentInputComponents = maxUniformComponents;
287 for (gl::ShaderType shaderType : gl::AllShaderTypes())
288 {
289 mNativeCaps.maxShaderUniformComponents[shaderType] = maxUniformComponents;
290 }
291 mNativeCaps.maxUniformLocations = maxUniformVectors;
292
293 // Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
294 // uniforms.
295 constexpr uint32_t kTotalReservedPerStageUniformBuffers =
296 kReservedDriverUniformBindingCount + kReservedPerStageDefaultUniformBindingCount;
297 constexpr uint32_t kTotalReservedUniformBuffers =
298 kReservedDriverUniformBindingCount + kReservedDefaultUniformBindingCount;
299
300 const int32_t maxPerStageUniformBuffers = LimitToInt(
301 limitsVk.maxPerStageDescriptorUniformBuffers - kTotalReservedPerStageUniformBuffers);
302 const int32_t maxCombinedUniformBuffers =
303 LimitToInt(limitsVk.maxDescriptorSetUniformBuffers - kTotalReservedUniformBuffers);
304 for (gl::ShaderType shaderType : gl::AllShaderTypes())
305 {
306 mNativeCaps.maxShaderUniformBlocks[shaderType] = maxPerStageUniformBuffers;
307 }
308 mNativeCaps.maxCombinedUniformBlocks = maxCombinedUniformBuffers;
309
310 mNativeCaps.maxUniformBufferBindings = maxCombinedUniformBuffers;
311 mNativeCaps.maxUniformBlockSize = maxUniformBlockSize;
312 mNativeCaps.uniformBufferOffsetAlignment =
313 static_cast<GLint>(limitsVk.minUniformBufferOffsetAlignment);
314
315 // Note that Vulkan currently implements textures as combined image+samplers, so the limit is
316 // the minimum of supported samplers and sampled images.
317 const uint32_t maxPerStageTextures = std::min(limitsVk.maxPerStageDescriptorSamplers,
318 limitsVk.maxPerStageDescriptorSampledImages);
319 const uint32_t maxCombinedTextures =
320 std::min(limitsVk.maxDescriptorSetSamplers, limitsVk.maxDescriptorSetSampledImages);
321 for (gl::ShaderType shaderType : gl::AllShaderTypes())
322 {
323 mNativeCaps.maxShaderTextureImageUnits[shaderType] = LimitToInt(maxPerStageTextures);
324 }
325 mNativeCaps.maxCombinedTextureImageUnits = LimitToInt(maxCombinedTextures);
326
327 uint32_t maxPerStageStorageBuffers = limitsVk.maxPerStageDescriptorStorageBuffers;
328 uint32_t maxVertexStageStorageBuffers = maxPerStageStorageBuffers;
329 uint32_t maxCombinedStorageBuffers = limitsVk.maxDescriptorSetStorageBuffers;
330
331 // A number of storage buffer slots are used in the vertex shader to emulate transform feedback.
332 // Note that Vulkan requires maxPerStageDescriptorStorageBuffers to be at least 4 (i.e. the same
333 // as gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS).
334 // TODO(syoussefi): This should be conditioned to transform feedback extension not being
335 // present. http://anglebug.com/3206.
336 // TODO(syoussefi): If geometry shader is supported, emulation will be done at that stage, and
337 // so the reserved storage buffers should be accounted in that stage. http://anglebug.com/3606
338 static_assert(
339 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS == 4,
340 "Limit to ES2.0 if supported SSBO count < supporting transform feedback buffer count");
341 if (mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
342 {
343 ASSERT(maxVertexStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
344 maxVertexStageStorageBuffers -= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
345 maxCombinedStorageBuffers -= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
346
347 // Cap the per-stage limit of the other stages to the combined limit, in case the combined
348 // limit is now lower than that.
349 maxPerStageStorageBuffers = std::min(maxPerStageStorageBuffers, maxCombinedStorageBuffers);
350 }
351
352 // Reserve up to IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS storage buffers in the fragment and
353 // compute stages for atomic counters. This is only possible if the number of per-stage storage
354 // buffers is greater than 4, which is the required GLES minimum for compute.
355 //
356 // For each stage, we'll either not support atomic counter buffers, or support exactly
357 // IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS. This is due to restrictions in the shader
358 // translator where we can't know how many atomic counter buffers we would really need after
359 // linking so we can't create a packed buffer array.
360 //
361 // For the vertex stage, we could support atomic counters without storage buffers, but that's
362 // likely not very useful, so we use the same limit (4 + MAX_ATOMIC_COUNTER_BUFFERS) for the
363 // vertex stage to determine if we would want to add support for atomic counter buffers.
364 constexpr uint32_t kMinimumStorageBuffersForAtomicCounterBufferSupport =
365 gl::limits::kMinimumComputeStorageBuffers + gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS;
366 uint32_t maxVertexStageAtomicCounterBuffers = 0;
367 uint32_t maxPerStageAtomicCounterBuffers = 0;
368 uint32_t maxCombinedAtomicCounterBuffers = 0;
369
370 if (maxPerStageStorageBuffers >= kMinimumStorageBuffersForAtomicCounterBufferSupport)
371 {
372 maxPerStageAtomicCounterBuffers = gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS;
373 maxCombinedAtomicCounterBuffers = gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS;
374 }
375
376 if (maxVertexStageStorageBuffers >= kMinimumStorageBuffersForAtomicCounterBufferSupport)
377 {
378 maxVertexStageAtomicCounterBuffers = gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS;
379 }
380
381 maxVertexStageStorageBuffers -= maxVertexStageAtomicCounterBuffers;
382 maxPerStageStorageBuffers -= maxPerStageAtomicCounterBuffers;
383 maxCombinedStorageBuffers -= maxCombinedAtomicCounterBuffers;
384
385 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
386 mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics
387 ? LimitToInt(maxVertexStageStorageBuffers)
388 : 0;
389 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
390 mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? LimitToInt(maxPerStageStorageBuffers)
391 : 0;
392 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Compute] =
393 LimitToInt(maxPerStageStorageBuffers);
394 mNativeCaps.maxCombinedShaderStorageBlocks = LimitToInt(maxCombinedStorageBuffers);
395
396 mNativeCaps.maxShaderStorageBufferBindings = LimitToInt(maxCombinedStorageBuffers);
397 mNativeCaps.maxShaderStorageBlockSize = limitsVk.maxStorageBufferRange;
398 mNativeCaps.shaderStorageBufferOffsetAlignment =
399 LimitToInt(static_cast<uint32_t>(limitsVk.minStorageBufferOffsetAlignment));
400
401 mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Vertex] =
402 mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics
403 ? LimitToInt(maxVertexStageAtomicCounterBuffers)
404 : 0;
405 mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Fragment] =
406 mPhysicalDeviceFeatures.fragmentStoresAndAtomics
407 ? LimitToInt(maxPerStageAtomicCounterBuffers)
408 : 0;
409 mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Compute] =
410 LimitToInt(maxPerStageAtomicCounterBuffers);
411 mNativeCaps.maxCombinedAtomicCounterBuffers = LimitToInt(maxCombinedAtomicCounterBuffers);
412
413 mNativeCaps.maxAtomicCounterBufferBindings = LimitToInt(maxCombinedAtomicCounterBuffers);
414 // Emulated as storage buffers, atomic counter buffers have the same size limit. However, the
415 // limit is a signed integer and values above int max will end up as a negative size.
416 mNativeCaps.maxAtomicCounterBufferSize = LimitToInt(limitsVk.maxStorageBufferRange);
417
418 // There is no particular limit to how many atomic counters there can be, other than the size of
419 // a storage buffer. We nevertheless limit this to something sane (4096 arbitrarily).
420 const int32_t maxAtomicCounters =
421 std::min<int32_t>(4096, limitsVk.maxStorageBufferRange / sizeof(uint32_t));
422 for (gl::ShaderType shaderType : gl::AllShaderTypes())
423 {
424 mNativeCaps.maxShaderAtomicCounters[shaderType] = maxAtomicCounters;
425 }
426 mNativeCaps.maxCombinedAtomicCounters = maxAtomicCounters;
427
428 // GL Images correspond to Vulkan Storage Images.
429 const int32_t maxPerStageImages = LimitToInt(limitsVk.maxPerStageDescriptorStorageImages);
430 const int32_t maxCombinedImages = LimitToInt(limitsVk.maxDescriptorSetStorageImages);
431
432 mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Vertex] =
433 mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageImages : 0;
434 mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Fragment] =
435 mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageImages : 0;
436 mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Geometry] =
437 mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageImages : 0;
438 mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Compute] = maxPerStageImages;
439
440 mNativeCaps.maxCombinedImageUniforms = maxCombinedImages;
441 mNativeCaps.maxImageUnits = maxCombinedImages;
442
443 mNativeCaps.minProgramTexelOffset = limitsVk.minTexelOffset;
444 mNativeCaps.maxProgramTexelOffset = limitsVk.maxTexelOffset;
445 mNativeCaps.minProgramTextureGatherOffset = limitsVk.minTexelGatherOffset;
446 mNativeCaps.maxProgramTextureGatherOffset = limitsVk.maxTexelGatherOffset;
447
448 // There is no additional limit to the combined number of components. We can have up to a
449 // maximum number of uniform buffers, each having the maximum number of components. Note that
450 // this limit includes both components in and out of uniform buffers.
451 const uint32_t maxCombinedUniformComponents =
452 (maxPerStageUniformBuffers + kReservedPerStageDefaultUniformBindingCount) *
453 maxUniformComponents;
454 for (gl::ShaderType shaderType : gl::AllShaderTypes())
455 {
456 mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
457 }
458
459 // Total number of resources available to the user are as many as Vulkan allows minus everything
460 // that ANGLE uses internally. That is, one dynamic uniform buffer used per stage for default
461 // uniforms and a single dynamic uniform buffer for driver uniforms. Additionally, Vulkan uses
462 // up to IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS + 1 buffers for transform feedback (Note:
463 // +1 is for the "counter" buffer of transform feedback, which will be necessary for transform
464 // feedback extension and ES3.2 transform feedback emulation, but is not yet present).
465 constexpr uint32_t kReservedPerStageUniformBufferCount = 1;
466 constexpr uint32_t kReservedPerStageBindingCount =
467 kReservedDriverUniformBindingCount + kReservedPerStageUniformBufferCount +
468 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS + 1;
469
470 // Note: maxPerStageResources is required to be at least the sum of per stage UBOs, SSBOs etc
471 // which total a minimum of 44 resources, so no underflow is possible here. Limit the total
472 // number of resources reported by Vulkan to 2 billion though to avoid seeing negative numbers
473 // in applications that take the value as signed int (including dEQP).
474 const uint32_t maxPerStageResources = limitsVk.maxPerStageResources;
475 mNativeCaps.maxCombinedShaderOutputResources =
476 LimitToInt(maxPerStageResources - kReservedPerStageBindingCount);
477
478 // The max vertex output components should not include gl_Position.
479 // The gles2.0 section 2.10 states that "gl_Position is not a varying variable and does
480 // not count against this limit.", but the Vulkan spec has no such mention in its Built-in
481 // vars section. It is implicit that we need to actually reserve it for Vulkan in that case.
482 GLint reservedVaryingVectorCount = 1;
483
484 // reserve 1 extra for ANGLEPosition when GLLineRasterization is enabled
485 constexpr GLint kRservedVaryingForGLLineRasterization = 1;
486 // reserve 2 extra for builtin varables when feedback is enabled
487 // possible capturable out varable: gl_Position, gl_PointSize
488 // https://www.khronos.org/registry/OpenGL/specs/es/3.1/GLSL_ES_Specification_3.10.withchanges.pdf
489 // page 105
490 constexpr GLint kReservedVaryingForTransformFeedbackExtension = 2;
491
492 if (getFeatures().basicGLLineRasterization.enabled)
493 {
494 reservedVaryingVectorCount += kRservedVaryingForGLLineRasterization;
495 }
496 if (getFeatures().supportsTransformFeedbackExtension.enabled)
497 {
498 reservedVaryingVectorCount += kReservedVaryingForTransformFeedbackExtension;
499 }
500
501 const GLint maxVaryingCount =
502 std::min(limitsVk.maxVertexOutputComponents, limitsVk.maxFragmentInputComponents);
503 mNativeCaps.maxVaryingVectors =
504 LimitToInt((maxVaryingCount / kComponentsPerVector) - reservedVaryingVectorCount);
505 mNativeCaps.maxVertexOutputComponents = LimitToInt(limitsVk.maxVertexOutputComponents);
506
507 mNativeCaps.maxTransformFeedbackInterleavedComponents =
508 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
509 mNativeCaps.maxTransformFeedbackSeparateAttributes =
510 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
511 mNativeCaps.maxTransformFeedbackSeparateComponents =
512 gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
513
514 mNativeCaps.minProgramTexelOffset = limitsVk.minTexelOffset;
515 mNativeCaps.maxProgramTexelOffset = LimitToInt(limitsVk.maxTexelOffset);
516
517 const uint32_t sampleCounts =
518 limitsVk.framebufferColorSampleCounts & limitsVk.framebufferDepthSampleCounts &
519 limitsVk.framebufferStencilSampleCounts & vk_gl::kSupportedSampleCounts;
520
521 mNativeCaps.maxSamples = LimitToInt(vk_gl::GetMaxSampleCount(sampleCounts));
522 mNativeCaps.maxFramebufferSamples = mNativeCaps.maxSamples;
523
524 mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits;
525
526 // Enable Program Binary extension.
527 mNativeExtensions.getProgramBinaryOES = true;
528 mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
529
530 // Enable GL_NV_pixel_buffer_object extension.
531 mNativeExtensions.pixelBufferObjectNV = true;
532
533 // Enable GL_NV_fence extension.
534 mNativeExtensions.fenceNV = true;
535
536 // Geometry shader is optional.
537 if (mPhysicalDeviceFeatures.geometryShader)
538 {
539 // TODO : Remove below comment when http://anglebug.com/3571 will be completed
540 // mNativeExtensions.geometryShader = true;
541 mNativeCaps.maxFramebufferLayers = LimitToInt(limitsVk.maxFramebufferLayers);
542 mNativeCaps.layerProvokingVertex = GL_LAST_VERTEX_CONVENTION_EXT;
543
544 mNativeCaps.maxGeometryInputComponents = LimitToInt(limitsVk.maxGeometryInputComponents);
545 mNativeCaps.maxGeometryOutputComponents = LimitToInt(limitsVk.maxGeometryOutputComponents);
546 mNativeCaps.maxGeometryOutputVertices = LimitToInt(limitsVk.maxGeometryOutputVertices);
547 mNativeCaps.maxGeometryTotalOutputComponents =
548 LimitToInt(limitsVk.maxGeometryTotalOutputComponents);
549 mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Geometry] =
550 mNativeCaps.maxCombinedShaderOutputResources;
551 mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Geometry] =
552 maxCombinedAtomicCounterBuffers;
553 mNativeCaps.maxGeometryShaderInvocations =
554 LimitToInt(limitsVk.maxGeometryShaderInvocations);
555 }
556
557 // GL_APPLE_clip_distance/GL_EXT_clip_cull_distance
558 if (mPhysicalDeviceFeatures.shaderClipDistance && limitsVk.maxClipDistances >= 8)
559 {
560 mNativeExtensions.clipDistanceAPPLE = true;
561 mNativeCaps.maxClipDistances =
562 std::min<GLuint>(limitsVk.maxClipDistances, gl::IMPLEMENTATION_MAX_CLIP_DISTANCES);
563 }
564 }
565
566 namespace vk
567 {
568
CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures & features)569 bool CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures &features)
570 {
571 // We use the following Vulkan features to implement EXT_gpu_shader5:
572 // - shaderImageGatherExtended: textureGatherOffset with non-constant offset and
573 // textureGatherOffsets family of functions.
574 // - shaderSampledImageArrayDynamicIndexing and shaderUniformBufferArrayDynamicIndexing:
575 // dynamically uniform indices for samplers and uniform buffers.
576 // - shaderStorageBufferArrayDynamicIndexing: While EXT_gpu_shader5 doesn't require dynamically
577 // uniform indices on storage buffers, we need it as we emulate atomic counter buffers with
578 // storage buffers (and atomic counter buffers *can* be indexed in that way).
579 return features.shaderImageGatherExtended && features.shaderSampledImageArrayDynamicIndexing &&
580 features.shaderUniformBufferArrayDynamicIndexing &&
581 features.shaderStorageBufferArrayDynamicIndexing;
582 }
583
584 } // namespace vk
585
586 namespace egl_vk
587 {
588
589 namespace
590 {
591
ComputeMaximumPBufferPixels(const VkPhysicalDeviceProperties & physicalDeviceProperties)592 EGLint ComputeMaximumPBufferPixels(const VkPhysicalDeviceProperties &physicalDeviceProperties)
593 {
594 // EGLints are signed 32-bit integers, it's fairly easy to overflow them, especially since
595 // Vulkan's minimum guaranteed VkImageFormatProperties::maxResourceSize is 2^31 bytes.
596 constexpr uint64_t kMaxValueForEGLint =
597 static_cast<uint64_t>(std::numeric_limits<EGLint>::max());
598
599 // TODO(geofflang): Compute the maximum size of a pbuffer by using the maxResourceSize result
600 // from vkGetPhysicalDeviceImageFormatProperties for both the color and depth stencil format and
601 // the exact image creation parameters that would be used to create the pbuffer. Because it is
602 // always safe to return out-of-memory errors on pbuffer allocation, it's fine to simply return
603 // the number of pixels in a max width by max height pbuffer for now. http://anglebug.com/2622
604
605 // Storing the result of squaring a 32-bit unsigned int in a 64-bit unsigned int is safe.
606 static_assert(std::is_same<decltype(physicalDeviceProperties.limits.maxImageDimension2D),
607 uint32_t>::value,
608 "physicalDeviceProperties.limits.maxImageDimension2D expected to be a uint32_t.");
609 const uint64_t maxDimensionsSquared =
610 static_cast<uint64_t>(physicalDeviceProperties.limits.maxImageDimension2D) *
611 static_cast<uint64_t>(physicalDeviceProperties.limits.maxImageDimension2D);
612
613 return static_cast<EGLint>(std::min(maxDimensionsSquared, kMaxValueForEGLint));
614 }
615
616 // Generates a basic config for a combination of color format, depth stencil format and sample
617 // count.
GenerateDefaultConfig(const RendererVk * renderer,const gl::InternalFormat & colorFormat,const gl::InternalFormat & depthStencilFormat,EGLint sampleCount)618 egl::Config GenerateDefaultConfig(const RendererVk *renderer,
619 const gl::InternalFormat &colorFormat,
620 const gl::InternalFormat &depthStencilFormat,
621 EGLint sampleCount)
622 {
623 const VkPhysicalDeviceProperties &physicalDeviceProperties =
624 renderer->getPhysicalDeviceProperties();
625 gl::Version maxSupportedESVersion = renderer->getMaxSupportedESVersion();
626
627 // ES3 features are required to emulate ES1
628 EGLint es1Support = (maxSupportedESVersion.major >= 3 ? EGL_OPENGL_ES_BIT : 0);
629 EGLint es2Support = (maxSupportedESVersion.major >= 2 ? EGL_OPENGL_ES2_BIT : 0);
630 EGLint es3Support = (maxSupportedESVersion.major >= 3 ? EGL_OPENGL_ES3_BIT : 0);
631
632 egl::Config config;
633
634 config.renderTargetFormat = colorFormat.internalFormat;
635 config.depthStencilFormat = depthStencilFormat.internalFormat;
636 config.bufferSize = colorFormat.pixelBytes * 8;
637 config.redSize = colorFormat.redBits;
638 config.greenSize = colorFormat.greenBits;
639 config.blueSize = colorFormat.blueBits;
640 config.alphaSize = colorFormat.alphaBits;
641 config.alphaMaskSize = 0;
642 config.bindToTextureRGB = colorFormat.format == GL_RGB;
643 config.bindToTextureRGBA = colorFormat.format == GL_RGBA || colorFormat.format == GL_BGRA_EXT;
644 config.colorBufferType = EGL_RGB_BUFFER;
645 config.configCaveat = GetConfigCaveat(colorFormat.internalFormat);
646 config.conformant = es1Support | es2Support | es3Support;
647 config.depthSize = depthStencilFormat.depthBits;
648 config.stencilSize = depthStencilFormat.stencilBits;
649 config.level = 0;
650 config.matchNativePixmap = EGL_NONE;
651 config.maxPBufferWidth = physicalDeviceProperties.limits.maxImageDimension2D;
652 config.maxPBufferHeight = physicalDeviceProperties.limits.maxImageDimension2D;
653 config.maxPBufferPixels = ComputeMaximumPBufferPixels(physicalDeviceProperties);
654 config.maxSwapInterval = 1;
655 config.minSwapInterval = 0;
656 config.nativeRenderable = EGL_TRUE;
657 config.nativeVisualID = static_cast<EGLint>(GetNativeVisualID(colorFormat));
658 config.nativeVisualType = EGL_NONE;
659 config.renderableType = es1Support | es2Support | es3Support;
660 config.sampleBuffers = (sampleCount > 0) ? 1 : 0;
661 config.samples = sampleCount;
662 config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
663 // Vulkan surfaces use a different origin than OpenGL, always prefer to be flipped vertically if
664 // possible.
665 config.optimalOrientation = EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
666 config.transparentType = EGL_NONE;
667 config.transparentRedValue = 0;
668 config.transparentGreenValue = 0;
669 config.transparentBlueValue = 0;
670 config.colorComponentType =
671 gl_egl::GLComponentTypeToEGLColorComponentType(colorFormat.componentType);
672
673 return config;
674 }
675
676 } // anonymous namespace
677
GenerateConfigs(const GLenum * colorFormats,size_t colorFormatsCount,const GLenum * depthStencilFormats,size_t depthStencilFormatCount,DisplayVk * display)678 egl::ConfigSet GenerateConfigs(const GLenum *colorFormats,
679 size_t colorFormatsCount,
680 const GLenum *depthStencilFormats,
681 size_t depthStencilFormatCount,
682 DisplayVk *display)
683 {
684 ASSERT(colorFormatsCount > 0);
685 ASSERT(display != nullptr);
686
687 gl::SupportedSampleSet colorSampleCounts;
688 gl::SupportedSampleSet depthStencilSampleCounts;
689 gl::SupportedSampleSet sampleCounts;
690
691 const VkPhysicalDeviceLimits &limits =
692 display->getRenderer()->getPhysicalDeviceProperties().limits;
693 const uint32_t depthStencilSampleCountsLimit = limits.framebufferDepthSampleCounts &
694 limits.framebufferStencilSampleCounts &
695 vk_gl::kSupportedSampleCounts;
696
697 vk_gl::AddSampleCounts(limits.framebufferColorSampleCounts & vk_gl::kSupportedSampleCounts,
698 &colorSampleCounts);
699 vk_gl::AddSampleCounts(depthStencilSampleCountsLimit, &depthStencilSampleCounts);
700
701 // Always support 0 samples
702 colorSampleCounts.insert(0);
703 depthStencilSampleCounts.insert(0);
704
705 std::set_intersection(colorSampleCounts.begin(), colorSampleCounts.end(),
706 depthStencilSampleCounts.begin(), depthStencilSampleCounts.end(),
707 std::inserter(sampleCounts, sampleCounts.begin()));
708
709 egl::ConfigSet configSet;
710
711 for (size_t colorFormatIdx = 0; colorFormatIdx < colorFormatsCount; colorFormatIdx++)
712 {
713 const gl::InternalFormat &colorFormatInfo =
714 gl::GetSizedInternalFormatInfo(colorFormats[colorFormatIdx]);
715 ASSERT(colorFormatInfo.sized);
716
717 for (size_t depthStencilFormatIdx = 0; depthStencilFormatIdx < depthStencilFormatCount;
718 depthStencilFormatIdx++)
719 {
720 const gl::InternalFormat &depthStencilFormatInfo =
721 gl::GetSizedInternalFormatInfo(depthStencilFormats[depthStencilFormatIdx]);
722 ASSERT(depthStencilFormats[depthStencilFormatIdx] == GL_NONE ||
723 depthStencilFormatInfo.sized);
724
725 const gl::SupportedSampleSet *configSampleCounts = &sampleCounts;
726 // If there is no depth/stencil buffer, use the color samples set.
727 if (depthStencilFormats[depthStencilFormatIdx] == GL_NONE)
728 {
729 configSampleCounts = &colorSampleCounts;
730 }
731 // If there is no color buffer, use the depth/stencil samples set.
732 else if (colorFormats[colorFormatIdx] == GL_NONE)
733 {
734 configSampleCounts = &depthStencilSampleCounts;
735 }
736
737 for (EGLint sampleCount : *configSampleCounts)
738 {
739 egl::Config config = GenerateDefaultConfig(display->getRenderer(), colorFormatInfo,
740 depthStencilFormatInfo, sampleCount);
741 if (display->checkConfigSupport(&config))
742 {
743 configSet.add(config);
744 }
745 }
746 }
747 }
748
749 return configSet;
750 }
751
752 } // namespace egl_vk
753
754 } // namespace rx
755