• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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