• 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     // 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