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