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 "libANGLE/renderer/vulkan/vk_cache_utils.h"
21 #include "vk_format_utils.h"
22 
23 namespace
24 {
25 constexpr unsigned int kComponentsPerVector = 4;
26 }  // anonymous namespace
27 
28 namespace rx
29 {
30 
31 namespace vk
32 {
33 namespace
34 {
35 // Checks to see if each format can be reinterpreted to an equivalent format in a different
36 // colorspace. If all supported formats can be reinterpreted, it returns true. Formats which are not
37 // supported at all are ignored and not counted as failures.
FormatReinterpretationSupported(const std::vector<GLenum> & optionalSizedFormats,const RendererVk * rendererVk,bool checkLinearColorspace)38 bool FormatReinterpretationSupported(const std::vector<GLenum> &optionalSizedFormats,
39                                      const RendererVk *rendererVk,
40                                      bool checkLinearColorspace)
41 {
42     for (GLenum glFormat : optionalSizedFormats)
43     {
44         const gl::TextureCaps &baseCaps = rendererVk->getNativeTextureCaps().get(glFormat);
45         if (baseCaps.texturable && baseCaps.filterable)
46         {
47             const Format &vkFormat = rendererVk->getFormat(glFormat);
48 
49             angle::FormatID reinterpretedFormatID =
50                 checkLinearColorspace ? ConvertToLinear(vkFormat.actualImageFormatID)
51                                       : ConvertToSRGB(vkFormat.actualImageFormatID);
52 
53             const Format &reinterpretedVkFormat = rendererVk->getFormat(reinterpretedFormatID);
54 
55             if (reinterpretedVkFormat.actualImageFormatID != reinterpretedFormatID)
56             {
57                 return false;
58             }
59 
60             if (!rendererVk->haveSameFormatFeatureBits(vkFormat.actualImageFormatID,
61                                                        reinterpretedFormatID))
62             {
63                 return false;
64             }
65         }
66     }
67 
68     return true;
69 }
70 
GetTextureSRGBDecodeSupport(const RendererVk * rendererVk)71 bool GetTextureSRGBDecodeSupport(const RendererVk *rendererVk)
72 {
73     static constexpr bool kLinearColorspace = true;
74 
75     // GL_SRGB and GL_SRGB_ALPHA unsized formats are also required by the spec, but the only valid
76     // type for them is GL_UNSIGNED_BYTE, so they are fully included in the sized formats listed
77     // here
78     std::vector<GLenum> optionalSizedSRGBFormats = {
79         GL_SRGB8,
80         GL_SRGB8_ALPHA8_EXT,
81         GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,
82         GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
83         GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
84         GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
85     };
86 
87     if (!FormatReinterpretationSupported(optionalSizedSRGBFormats, rendererVk, kLinearColorspace))
88     {
89         return false;
90     }
91 
92     return true;
93 }
94 
GetTextureSRGBOverrideSupport(const RendererVk * rendererVk,const gl::Extensions & supportedExtensions)95 bool GetTextureSRGBOverrideSupport(const RendererVk *rendererVk,
96                                    const gl::Extensions &supportedExtensions)
97 {
98     static constexpr bool kNonLinearColorspace = false;
99 
100     // If the given linear format is supported, we also need to support its corresponding nonlinear
101     // format. If the given linear format is NOT supported, we don't care about its corresponding
102     // nonlinear format.
103     std::vector<GLenum> optionalLinearFormats     = {GL_RGB8,
104                                                  GL_RGBA8,
105                                                  GL_COMPRESSED_RGB8_ETC2,
106                                                  GL_COMPRESSED_RGBA8_ETC2_EAC,
107                                                  GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
108                                                  GL_COMPRESSED_RGBA_ASTC_4x4,
109                                                  GL_COMPRESSED_RGBA_ASTC_5x4,
110                                                  GL_COMPRESSED_RGBA_ASTC_5x5,
111                                                  GL_COMPRESSED_RGBA_ASTC_6x5,
112                                                  GL_COMPRESSED_RGBA_ASTC_6x6,
113                                                  GL_COMPRESSED_RGBA_ASTC_8x5,
114                                                  GL_COMPRESSED_RGBA_ASTC_8x6,
115                                                  GL_COMPRESSED_RGBA_ASTC_8x8,
116                                                  GL_COMPRESSED_RGBA_ASTC_10x5,
117                                                  GL_COMPRESSED_RGBA_ASTC_10x6,
118                                                  GL_COMPRESSED_RGBA_ASTC_10x8,
119                                                  GL_COMPRESSED_RGBA_ASTC_10x10,
120                                                  GL_COMPRESSED_RGBA_ASTC_12x10,
121                                                  GL_COMPRESSED_RGBA_ASTC_12x12};
122     std::vector<GLenum> optionalS3TCLinearFormats = {
123         GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
124         GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT};
125     std::vector<GLenum> optionalR8LinearFormats   = {GL_R8};
126     std::vector<GLenum> optionalRG8LinearFormats  = {GL_RG8};
127     std::vector<GLenum> optionalBPTCLinearFormats = {GL_COMPRESSED_RGBA_BPTC_UNORM_EXT};
128 
129     if (!FormatReinterpretationSupported(optionalLinearFormats, rendererVk, kNonLinearColorspace))
130     {
131         return false;
132     }
133 
134     if (supportedExtensions.textureCompressionS3TCsRGB)
135     {
136         if (!FormatReinterpretationSupported(optionalS3TCLinearFormats, rendererVk,
137                                              kNonLinearColorspace))
138         {
139             return false;
140         }
141     }
142 
143     if (supportedExtensions.sRGBR8EXT)
144     {
145         if (!FormatReinterpretationSupported(optionalR8LinearFormats, rendererVk,
146                                              kNonLinearColorspace))
147         {
148             return false;
149         }
150     }
151 
152     if (supportedExtensions.sRGBRG8EXT)
153     {
154         if (!FormatReinterpretationSupported(optionalRG8LinearFormats, rendererVk,
155                                              kNonLinearColorspace))
156         {
157             return false;
158         }
159     }
160 
161     if (supportedExtensions.textureCompressionBPTC)
162     {
163         if (!FormatReinterpretationSupported(optionalBPTCLinearFormats, rendererVk,
164                                              kNonLinearColorspace))
165         {
166             return false;
167         }
168     }
169 
170     return true;
171 }
172 
HasTexelBufferSupport(const RendererVk * rendererVk,GLenum formatGL)173 bool HasTexelBufferSupport(const RendererVk *rendererVk, GLenum formatGL)
174 {
175     const Format &formatVk = rendererVk->getFormat(formatGL);
176 
177     return rendererVk->hasBufferFormatFeatureBits(
178         formatVk.actualBufferFormatID,
179         VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT);
180 }
181 
HasTextureBufferSupport(const RendererVk * rendererVk)182 bool HasTextureBufferSupport(const RendererVk *rendererVk)
183 {
184     // The following formats don't have mandatory UNIFORM_TEXEL_BUFFER support in Vulkan.
185     //
186     //     VK_FORMAT_R32G32B32_UINT
187     //     VK_FORMAT_R32G32B32_SINT
188     //     VK_FORMAT_R32G32B32_SFLOAT
189     //
190     // Additionally, the following formats don't have mandatory STORAGE_TEXEL_BUFFER support:
191     //
192     //     VK_FORMAT_R8_UINT
193     //     VK_FORMAT_R8_SINT
194     //     VK_FORMAT_R8_UNORM
195     //     VK_FORMAT_R8G8_UINT
196     //     VK_FORMAT_R8G8_SINT
197     //     VK_FORMAT_R8G8_UNORM
198     //     VK_FORMAT_R16_UINT
199     //     VK_FORMAT_R16_SINT
200     //     VK_FORMAT_R16_SFLOAT
201     //     VK_FORMAT_R16G16_UINT
202     //     VK_FORMAT_R16G16_SINT
203     //     VK_FORMAT_R16G16_SFLOAT
204     //     VK_FORMAT_R32G32B32_UINT
205     //     VK_FORMAT_R32G32B32_SINT
206     //     VK_FORMAT_R32G32B32_SFLOAT
207     //
208     // The formats that have mandatory support for both features (and don't need to be checked) are:
209     //
210     //     VK_FORMAT_R8G8B8A8_UINT
211     //     VK_FORMAT_R8G8B8A8_SINT
212     //     VK_FORMAT_R8G8B8A8_UNORM
213     //     VK_FORMAT_R16G16B16A16_UINT
214     //     VK_FORMAT_R16G16B16A16_SINT
215     //     VK_FORMAT_R16G16B16A16_SFLOAT
216     //     VK_FORMAT_R32_UINT
217     //     VK_FORMAT_R32_SINT
218     //     VK_FORMAT_R32_SFLOAT
219     //     VK_FORMAT_R32G32_UINT
220     //     VK_FORMAT_R32G32_SINT
221     //     VK_FORMAT_R32G32_SFLOAT
222     //     VK_FORMAT_R32G32B32A32_UINT
223     //     VK_FORMAT_R32G32B32A32_SINT
224     //     VK_FORMAT_R32G32B32A32_SFLOAT
225     //
226 
227     const std::array<GLenum, 12> &optionalFormats = {
228         GL_R8,   GL_R8I,  GL_R8UI,  GL_RG8,   GL_RG8I,  GL_RG8UI,
229         GL_R16F, GL_R16I, GL_R16UI, GL_RG16F, GL_RG16I, GL_RG16UI,
230     };
231 
232     for (GLenum formatGL : optionalFormats)
233     {
234         if (!HasTexelBufferSupport(rendererVk, formatGL))
235         {
236             return false;
237         }
238     }
239 
240     // TODO: RGB32 formats currently don't have STORAGE_TEXEL_BUFFER support on any known platform.
241     // Despite this limitation, we expose EXT_texture_buffer.  http://anglebug.com/3573
242     if (rendererVk->getFeatures().exposeNonConformantExtensionsAndVersions.enabled)
243     {
244         return true;
245     }
246 
247     const std::array<GLenum, 3> &optionalFormats2 = {
248         GL_RGB32F,
249         GL_RGB32I,
250         GL_RGB32UI,
251     };
252 
253     for (GLenum formatGL : optionalFormats2)
254     {
255         if (!HasTexelBufferSupport(rendererVk, formatGL))
256         {
257             return false;
258         }
259     }
260 
261     return true;
262 }
263 
CanSupportYuvInternalFormat(const RendererVk * rendererVk)264 bool CanSupportYuvInternalFormat(const RendererVk *rendererVk)
265 {
266     // The following formats are not mandatory in Vulkan, even when VK_KHR_sampler_ycbcr_conversion
267     // is supported. GL_ANGLE_yuv_internal_format requires support for sampling only the
268     // 8-bit 2-plane YUV format (VK_FORMAT_G8_B8R8_2PLANE_420_UNORM), if the ICD supports that we
269     // can expose the extension.
270     //
271     // Various test cases need multiple YUV formats. It would be preferrable to have support for the
272     // 3 plane 8 bit YUV format (VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM) as well.
273 
274     const Format &twoPlane8bitYuvFormat = rendererVk->getFormat(GL_G8_B8R8_2PLANE_420_UNORM_ANGLE);
275     bool twoPlane8bitYuvFormatSupported = rendererVk->hasImageFormatFeatureBits(
276         twoPlane8bitYuvFormat.actualImageFormatID, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
277 
278     const Format &threePlane8bitYuvFormat =
279         rendererVk->getFormat(GL_G8_B8_R8_3PLANE_420_UNORM_ANGLE);
280     bool threePlane8bitYuvFormatSupported = rendererVk->hasImageFormatFeatureBits(
281         threePlane8bitYuvFormat.actualImageFormatID, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
282 
283     return twoPlane8bitYuvFormatSupported && threePlane8bitYuvFormatSupported;
284 }
285 }  // namespace
286 }  // namespace vk
287 
288 template <typename LargerInt>
LimitToInt(const LargerInt physicalDeviceValue)289 GLint LimitToInt(const LargerInt physicalDeviceValue)
290 {
291     static_assert(sizeof(LargerInt) >= sizeof(int32_t), "Incorrect usage of LimitToInt");
292 
293     // Limit to INT_MAX / 2 instead of INT_MAX.  If the limit is queried as float, the imprecision
294     // in floating point can cause the value to exceed INT_MAX.  This trips dEQP up.
295     return static_cast<GLint>(std::min(
296         physicalDeviceValue, static_cast<LargerInt>(std::numeric_limits<int32_t>::max() / 2)));
297 }
298 
ensureCapsInitialized() const299 void RendererVk::ensureCapsInitialized() const
300 {
301     if (mCapsInitialized)
302         return;
303     mCapsInitialized = true;
304 
305     ASSERT(mCurrentQueueFamilyIndex < mQueueFamilyProperties.size());
306     const VkQueueFamilyProperties &queueFamilyProperties =
307         mQueueFamilyProperties[mCurrentQueueFamilyIndex];
308     const VkPhysicalDeviceLimits &limitsVk = mPhysicalDeviceProperties.limits;
309 
310     mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
311 
312     // Enable GL_EXT_buffer_storage
313     mNativeExtensions.bufferStorageEXT = true;
314 
315     // When ETC2/EAC formats are natively supported, enable ANGLE-specific extension string to
316     // expose them to WebGL. In other case, mark potentially-available ETC1 extension as emulated.
317     if ((mPhysicalDeviceFeatures.textureCompressionETC2 == VK_TRUE) &&
318         gl::DetermineCompressedTextureETCSupport(mNativeTextureCaps))
319     {
320         mNativeExtensions.compressedTextureETC = true;
321     }
322     else
323     {
324         mNativeLimitations.emulatedEtc1 = true;
325     }
326 
327     // Vulkan doesn't support ASTC 3D block textures, which are required by
328     // GL_OES_texture_compression_astc.
329     mNativeExtensions.textureCompressionASTCOES = false;
330     // Vulkan does not support sliced 3D ASTC textures either.
331     mNativeExtensions.textureCompressionSliced3dASTCKHR = false;
332 
333     // Vulkan doesn't guarantee HDR blocks decoding without VK_EXT_texture_compression_astc_hdr.
334     mNativeExtensions.textureCompressionASTCHDRKHR = false;
335 
336     // Enable EXT_compressed_ETC1_RGB8_sub_texture
337     mNativeExtensions.compressedETC1RGB8SubTexture = mNativeExtensions.compressedETC1RGB8TextureOES;
338 
339     // Enable this for simple buffer readback testing, but some functionality is missing.
340     // TODO(jmadill): Support full mapBufferRange extension.
341     mNativeExtensions.mapBufferOES           = true;
342     mNativeExtensions.mapBufferRange         = true;
343     mNativeExtensions.textureStorage         = true;
344     mNativeExtensions.drawBuffers            = true;
345     mNativeExtensions.fragDepth              = true;
346     mNativeExtensions.framebufferBlitANGLE   = true;
347     mNativeExtensions.framebufferMultisample = true;
348     mNativeExtensions.multisampledRenderToTexture =
349         getFeatures().enableMultisampledRenderToTexture.enabled;
350     mNativeExtensions.multisampledRenderToTexture2 =
351         getFeatures().enableMultisampledRenderToTexture.enabled;
352     mNativeExtensions.textureStorageMultisample2DArrayOES =
353         (limitsVk.standardSampleLocations == VK_TRUE);
354     mNativeExtensions.copyTexture           = true;
355     mNativeExtensions.copyTexture3d         = true;
356     mNativeExtensions.copyCompressedTexture = true;
357     mNativeExtensions.debugMarker           = true;
358     mNativeExtensions.robustness =
359         !IsSwiftshader(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID) &&
360         !IsARM(mPhysicalDeviceProperties.vendorID);
361     mNativeExtensions.discardFramebuffer    = true;
362     mNativeExtensions.textureBorderClampOES = getFeatures().supportsCustomBorderColorEXT.enabled;
363     mNativeExtensions.textureBorderClampEXT = getFeatures().supportsCustomBorderColorEXT.enabled;
364     // Enable EXT_texture_type_2_10_10_10_REV
365     mNativeExtensions.textureFormat2101010REV = true;
366 
367     // Enable ANGLE_base_vertex_base_instance
368     mNativeExtensions.baseVertexBaseInstance = true;
369 
370     // Enable OES/EXT_draw_elements_base_vertex
371     mNativeExtensions.drawElementsBaseVertexOES = true;
372     mNativeExtensions.drawElementsBaseVertexEXT = true;
373 
374     // Enable EXT_blend_minmax
375     mNativeExtensions.blendMinMax = true;
376 
377     // Enable OES/EXT_draw_buffers_indexed
378     mNativeExtensions.drawBuffersIndexedOES = mPhysicalDeviceFeatures.independentBlend == VK_TRUE;
379     mNativeExtensions.drawBuffersIndexedEXT = mNativeExtensions.drawBuffersIndexedOES;
380 
381     mNativeExtensions.eglImageOES                  = true;
382     mNativeExtensions.eglImageExternalOES          = true;
383     mNativeExtensions.eglImageExternalWrapModesEXT = true;
384     mNativeExtensions.eglImageExternalEssl3OES     = true;
385     mNativeExtensions.eglImageArray                = true;
386     mNativeExtensions.memoryObject                 = true;
387     mNativeExtensions.memoryObjectFd               = getFeatures().supportsExternalMemoryFd.enabled;
388     mNativeExtensions.memoryObjectFlagsANGLE       = true;
389     mNativeExtensions.memoryObjectFuchsiaANGLE =
390         getFeatures().supportsExternalMemoryFuchsia.enabled;
391 
392     mNativeExtensions.semaphore   = true;
393     mNativeExtensions.semaphoreFd = getFeatures().supportsExternalSemaphoreFd.enabled;
394     mNativeExtensions.semaphoreFuchsiaANGLE =
395         getFeatures().supportsExternalSemaphoreFuchsia.enabled;
396 
397     mNativeExtensions.vertexHalfFloatOES = true;
398 
399     // Enabled in HW if VK_EXT_vertex_attribute_divisor available, otherwise emulated
400     mNativeExtensions.instancedArraysANGLE = true;
401     mNativeExtensions.instancedArraysEXT   = true;
402 
403     // Only expose robust buffer access if the physical device supports it.
404     mNativeExtensions.robustBufferAccessBehavior =
405         (mPhysicalDeviceFeatures.robustBufferAccess == VK_TRUE);
406 
407     mNativeExtensions.eglSyncOES = true;
408 
409     mNativeExtensions.vertexAttribType1010102OES = true;
410 
411     // We use secondary command buffers almost everywhere and they require a feature to be
412     // able to execute in the presence of queries.  As a result, we won't support queries
413     // unless that feature is available.
414     mNativeExtensions.occlusionQueryBoolean =
415         vk::CommandBuffer::SupportsQueries(mPhysicalDeviceFeatures);
416 
417     // From the Vulkan specs:
418     // > The number of valid bits in a timestamp value is determined by the
419     // > VkQueueFamilyProperties::timestampValidBits property of the queue on which the timestamp is
420     // > written. Timestamps are supported on any queue which reports a non-zero value for
421     // > timestampValidBits via vkGetPhysicalDeviceQueueFamilyProperties.
422     mNativeExtensions.disjointTimerQuery          = queueFamilyProperties.timestampValidBits > 0;
423     mNativeExtensions.queryCounterBitsTimeElapsed = queueFamilyProperties.timestampValidBits;
424     mNativeExtensions.queryCounterBitsTimestamp   = queueFamilyProperties.timestampValidBits;
425 
426     mNativeExtensions.textureFilterAnisotropic =
427         mPhysicalDeviceFeatures.samplerAnisotropy && limitsVk.maxSamplerAnisotropy > 1.0f;
428     mNativeExtensions.maxTextureAnisotropy =
429         mNativeExtensions.textureFilterAnisotropic ? limitsVk.maxSamplerAnisotropy : 0.0f;
430 
431     // Vulkan natively supports non power-of-two textures
432     mNativeExtensions.textureNPOTOES = true;
433 
434     mNativeExtensions.texture3DOES = true;
435 
436     // Vulkan natively supports standard derivatives
437     mNativeExtensions.standardDerivativesOES = true;
438 
439     // Vulkan natively supports texture LOD
440     mNativeExtensions.shaderTextureLOD = true;
441 
442     // Vulkan natively supports noperspective interpolation
443     mNativeExtensions.noperspectiveInterpolationNV = true;
444 
445     // Vulkan natively supports 32-bit indices, entry in kIndexTypeMap
446     mNativeExtensions.elementIndexUintOES = true;
447 
448     mNativeExtensions.fboRenderMipmapOES = true;
449 
450     // We support getting image data for Textures and Renderbuffers.
451     mNativeExtensions.getImageANGLE = true;
452 
453     // Implemented in the translator
454     mNativeExtensions.shaderNonConstGlobalInitializersEXT = true;
455 
456     // Implemented in the front end
457     mNativeExtensions.separateShaderObjects = true;
458 
459     // Vulkan has no restrictions of the format of cubemaps, so if the proper formats are supported,
460     // creating a cube of any of these formats should be implicitly supported.
461     mNativeExtensions.depthTextureCubeMapOES =
462         mNativeExtensions.depthTextureOES && mNativeExtensions.packedDepthStencilOES;
463 
464     // Vulkan natively supports format reinterpretation, but we still require support for all
465     // formats we may reinterpret to
466     mNativeExtensions.textureSRGBOverride =
467         vk::GetTextureSRGBOverrideSupport(this, mNativeExtensions);
468     mNativeExtensions.textureSRGBDecode = vk::GetTextureSRGBDecodeSupport(this);
469 
470     // EXT_srgb_write_control requires image_format_list
471     mNativeExtensions.sRGBWriteControl = getFeatures().supportsImageFormatList.enabled;
472 
473     // Vulkan natively supports io interface block.
474     mNativeExtensions.shaderIoBlocksOES = true;
475     mNativeExtensions.shaderIoBlocksEXT = true;
476 
477     mNativeExtensions.gpuShader5EXT = vk::CanSupportGPUShader5EXT(mPhysicalDeviceFeatures);
478 
479     mNativeExtensions.textureFilteringCHROMIUM = getFeatures().supportsFilteringPrecision.enabled;
480 
481     // Only expose texture cubemap array if the physical device supports it.
482     mNativeExtensions.textureCubeMapArrayOES = getFeatures().supportsImageCubeArray.enabled;
483     mNativeExtensions.textureCubeMapArrayEXT = mNativeExtensions.textureCubeMapArrayOES;
484 
485     mNativeExtensions.shadowSamplersEXT = true;
486 
487     // Enable EXT_external_buffer on Andoid. External buffers are implemented using Android hadware
488     // buffer (struct AHardwareBuffer).
489     mNativeExtensions.externalBufferEXT = IsAndroid() && GetAndroidSDKVersion() >= 26;
490 
491     // From the Vulkan specs:
492     // sampleRateShading specifies whether Sample Shading and multisample interpolation are
493     // supported. If this feature is not enabled, the sampleShadingEnable member of the
494     // VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE and the
495     // minSampleShading member is ignored. This also specifies whether shader modules can declare
496     // the SampleRateShading capability
497     bool supportSampleRateShading      = mPhysicalDeviceFeatures.sampleRateShading == VK_TRUE;
498     mNativeExtensions.sampleShadingOES = supportSampleRateShading;
499 
500     // From the SPIR-V spec at 3.21. BuiltIn, SampleId and SamplePosition needs
501     // SampleRateShading. https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html
502     // To replace non-constant index to constant 0 index, this extension assumes that ANGLE only
503     // supports the number of samples less than or equal to 32.
504     constexpr unsigned int kNotSupportedSampleCounts = VK_SAMPLE_COUNT_64_BIT;
505     mNativeExtensions.sampleVariablesOES =
506         supportSampleRateShading && vk_gl::GetMaxSampleCount(kNotSupportedSampleCounts) == 0;
507 
508     // Enable EXT_unpack_subimage
509     mNativeExtensions.unpackSubimage = true;
510 
511     // Enable NV_pack_subimage
512     mNativeExtensions.packSubimage = true;
513 
514     mNativeCaps.minInterpolationOffset          = limitsVk.minInterpolationOffset;
515     mNativeCaps.maxInterpolationOffset          = limitsVk.maxInterpolationOffset;
516     mNativeCaps.subPixelInterpolationOffsetBits = limitsVk.subPixelInterpolationOffsetBits;
517 
518     // From the Vulkan spec:
519     //
520     // > The values minInterpolationOffset and maxInterpolationOffset describe the closed interval
521     // > of supported interpolation offsets : [ minInterpolationOffset, maxInterpolationOffset ].
522     // > The ULP is determined by subPixelInterpolationOffsetBits. If
523     // > subPixelInterpolationOffsetBits is 4, this provides increments of(1 / 2^4) = 0.0625, and
524     // > thus the range of supported interpolation offsets would be[-0.5, 0.4375]
525     //
526     // OES_shader_multisample_interpolation requires a maximum value of -0.5 for
527     // MIN_FRAGMENT_INTERPOLATION_OFFSET_OES and minimum 0.5 for
528     // MAX_FRAGMENT_INTERPOLATION_OFFSET_OES.  Vulkan has an identical limit for
529     // minInterpolationOffset, but its limit for maxInterpolationOffset is 0.5-(1/ULP).
530     // OES_shader_multisample_interpolation is therefore only supported if
531     // maxInterpolationOffset is at least 0.5.
532     //
533     // It's suspected that the GL spec is not as precise as Vulkan's in this regard and that the
534     // requirements really meant to match.  The extension is exposed as non-conformant either way to
535     // increase testing coverage).  Discussion with the GL working group ongoing at
536     // https://gitlab.khronos.org/opengl/API/-/issues/149
537     mNativeExtensions.multisampleInterpolationOES =
538         mNativeExtensions.sampleVariablesOES &&
539         (mNativeCaps.maxInterpolationOffset >= 0.5 ||
540          mFeatures.exposeNonConformantExtensionsAndVersions.enabled);
541 
542     // https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
543     mNativeCaps.maxElementIndex  = std::numeric_limits<GLuint>::max() - 1;
544     mNativeCaps.max3DTextureSize = LimitToInt(limitsVk.maxImageDimension3D);
545     mNativeCaps.max2DTextureSize =
546         std::min(limitsVk.maxFramebufferWidth, limitsVk.maxImageDimension2D);
547     mNativeCaps.maxArrayTextureLayers = LimitToInt(limitsVk.maxImageArrayLayers);
548     mNativeCaps.maxLODBias            = limitsVk.maxSamplerLodBias;
549     mNativeCaps.maxCubeMapTextureSize = LimitToInt(limitsVk.maxImageDimensionCube);
550     mNativeCaps.maxRenderbufferSize =
551         std::min({limitsVk.maxImageDimension2D, limitsVk.maxFramebufferWidth,
552                   limitsVk.maxFramebufferHeight});
553     mNativeCaps.minAliasedPointSize = std::max(1.0f, limitsVk.pointSizeRange[0]);
554     mNativeCaps.maxAliasedPointSize = limitsVk.pointSizeRange[1];
555 
556     mNativeCaps.minAliasedLineWidth = 1.0f;
557     mNativeCaps.maxAliasedLineWidth = 1.0f;
558 
559     mNativeCaps.maxDrawBuffers =
560         std::min(limitsVk.maxColorAttachments, limitsVk.maxFragmentOutputAttachments);
561     mNativeCaps.maxFramebufferWidth  = LimitToInt(limitsVk.maxFramebufferWidth);
562     mNativeCaps.maxFramebufferHeight = LimitToInt(limitsVk.maxFramebufferHeight);
563     mNativeCaps.maxColorAttachments  = LimitToInt(limitsVk.maxColorAttachments);
564     mNativeCaps.maxViewportWidth     = LimitToInt(limitsVk.maxViewportDimensions[0]);
565     mNativeCaps.maxViewportHeight    = LimitToInt(limitsVk.maxViewportDimensions[1]);
566     mNativeCaps.maxSampleMaskWords   = LimitToInt(limitsVk.maxSampleMaskWords);
567     mNativeCaps.maxColorTextureSamples =
568         limitsVk.sampledImageColorSampleCounts & vk_gl::kSupportedSampleCounts;
569     mNativeCaps.maxDepthTextureSamples =
570         limitsVk.sampledImageDepthSampleCounts & vk_gl::kSupportedSampleCounts;
571     mNativeCaps.maxIntegerSamples =
572         limitsVk.sampledImageIntegerSampleCounts & vk_gl::kSupportedSampleCounts;
573 
574     mNativeCaps.maxVertexAttributes     = LimitToInt(limitsVk.maxVertexInputAttributes);
575     mNativeCaps.maxVertexAttribBindings = LimitToInt(limitsVk.maxVertexInputBindings);
576     // Offset and stride are stored as uint16_t in PackedAttribDesc.
577     mNativeCaps.maxVertexAttribRelativeOffset =
578         std::min((1u << kAttributeOffsetMaxBits) - 1, limitsVk.maxVertexInputAttributeOffset);
579     mNativeCaps.maxVertexAttribStride =
580         std::min(static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()),
581                  limitsVk.maxVertexInputBindingStride);
582 
583     mNativeCaps.maxElementsIndices  = std::numeric_limits<GLint>::max();
584     mNativeCaps.maxElementsVertices = std::numeric_limits<GLint>::max();
585 
586     // Looks like all floats are IEEE according to the docs here:
587     // https://www.khronos.org/registry/vulkan/specs/1.0-wsi_extensions/html/vkspec.html#spirvenv-precision-operation
588     mNativeCaps.vertexHighpFloat.setIEEEFloat();
589     mNativeCaps.vertexMediumpFloat.setIEEEFloat();
590     mNativeCaps.vertexLowpFloat.setIEEEFloat();
591     mNativeCaps.fragmentHighpFloat.setIEEEFloat();
592     mNativeCaps.fragmentMediumpFloat.setIEEEFloat();
593     mNativeCaps.fragmentLowpFloat.setIEEEFloat();
594 
595     // Can't find documentation on the int precision in Vulkan.
596     mNativeCaps.vertexHighpInt.setTwosComplementInt(32);
597     mNativeCaps.vertexMediumpInt.setTwosComplementInt(32);
598     mNativeCaps.vertexLowpInt.setTwosComplementInt(32);
599     mNativeCaps.fragmentHighpInt.setTwosComplementInt(32);
600     mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32);
601     mNativeCaps.fragmentLowpInt.setTwosComplementInt(32);
602 
603     // Compute shader limits.
604     mNativeCaps.maxComputeWorkGroupCount[0] = LimitToInt(limitsVk.maxComputeWorkGroupCount[0]);
605     mNativeCaps.maxComputeWorkGroupCount[1] = LimitToInt(limitsVk.maxComputeWorkGroupCount[1]);
606     mNativeCaps.maxComputeWorkGroupCount[2] = LimitToInt(limitsVk.maxComputeWorkGroupCount[2]);
607     mNativeCaps.maxComputeWorkGroupSize[0]  = LimitToInt(limitsVk.maxComputeWorkGroupSize[0]);
608     mNativeCaps.maxComputeWorkGroupSize[1]  = LimitToInt(limitsVk.maxComputeWorkGroupSize[1]);
609     mNativeCaps.maxComputeWorkGroupSize[2]  = LimitToInt(limitsVk.maxComputeWorkGroupSize[2]);
610     mNativeCaps.maxComputeWorkGroupInvocations =
611         LimitToInt(limitsVk.maxComputeWorkGroupInvocations);
612     mNativeCaps.maxComputeSharedMemorySize = LimitToInt(limitsVk.maxComputeSharedMemorySize);
613 
614     // TODO(lucferron): This is something we'll need to implement custom in the back-end.
615     // Vulkan doesn't do any waiting for you, our back-end code is going to manage sync objects,
616     // and we'll have to check that we've exceeded the max wait timeout. Also, this is ES 3.0 so
617     // we'll defer the implementation until we tackle the next version.
618     // mNativeCaps.maxServerWaitTimeout
619 
620     GLuint maxUniformBlockSize = limitsVk.maxUniformBufferRange;
621 
622     // Clamp the maxUniformBlockSize to 64KB (majority of devices support up to this size
623     // currently), on AMD the maxUniformBufferRange is near uint32_t max.
624     maxUniformBlockSize = std::min(0x10000u, maxUniformBlockSize);
625 
626     const GLuint maxUniformVectors = maxUniformBlockSize / (sizeof(GLfloat) * kComponentsPerVector);
627     const GLuint maxUniformComponents = maxUniformVectors * kComponentsPerVector;
628 
629     // Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
630     // support is the max buffer range divided by the size of a single uniform (4X float).
631     mNativeCaps.maxVertexUniformVectors   = maxUniformVectors;
632     mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
633     for (gl::ShaderType shaderType : gl::AllShaderTypes())
634     {
635         mNativeCaps.maxShaderUniformComponents[shaderType] = maxUniformComponents;
636     }
637     mNativeCaps.maxUniformLocations = maxUniformVectors;
638 
639     // Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
640     // uniforms.
641     constexpr uint32_t kTotalReservedPerStageUniformBuffers =
642         kReservedDriverUniformBindingCount + kReservedPerStageDefaultUniformBindingCount;
643     constexpr uint32_t kTotalReservedUniformBuffers =
644         kReservedDriverUniformBindingCount + kReservedDefaultUniformBindingCount;
645 
646     const int32_t maxPerStageUniformBuffers = LimitToInt(
647         limitsVk.maxPerStageDescriptorUniformBuffers - kTotalReservedPerStageUniformBuffers);
648     const int32_t maxCombinedUniformBuffers =
649         LimitToInt(limitsVk.maxDescriptorSetUniformBuffers - kTotalReservedUniformBuffers);
650     for (gl::ShaderType shaderType : gl::AllShaderTypes())
651     {
652         mNativeCaps.maxShaderUniformBlocks[shaderType] = maxPerStageUniformBuffers;
653     }
654     mNativeCaps.maxCombinedUniformBlocks = maxCombinedUniformBuffers;
655 
656     mNativeCaps.maxUniformBufferBindings = maxCombinedUniformBuffers;
657     mNativeCaps.maxUniformBlockSize      = maxUniformBlockSize;
658     mNativeCaps.uniformBufferOffsetAlignment =
659         static_cast<GLint>(limitsVk.minUniformBufferOffsetAlignment);
660 
661     // Note that Vulkan currently implements textures as combined image+samplers, so the limit is
662     // the minimum of supported samplers and sampled images.
663     const uint32_t maxPerStageTextures = std::min(limitsVk.maxPerStageDescriptorSamplers,
664                                                   limitsVk.maxPerStageDescriptorSampledImages);
665     const uint32_t maxCombinedTextures =
666         std::min(limitsVk.maxDescriptorSetSamplers, limitsVk.maxDescriptorSetSampledImages);
667     for (gl::ShaderType shaderType : gl::AllShaderTypes())
668     {
669         mNativeCaps.maxShaderTextureImageUnits[shaderType] = LimitToInt(maxPerStageTextures);
670     }
671     mNativeCaps.maxCombinedTextureImageUnits = LimitToInt(maxCombinedTextures);
672 
673     uint32_t maxPerStageStorageBuffers    = limitsVk.maxPerStageDescriptorStorageBuffers;
674     uint32_t maxVertexStageStorageBuffers = maxPerStageStorageBuffers;
675     uint32_t maxCombinedStorageBuffers    = limitsVk.maxDescriptorSetStorageBuffers;
676 
677     // A number of storage buffer slots are used in the vertex shader to emulate transform feedback.
678     // Note that Vulkan requires maxPerStageDescriptorStorageBuffers to be at least 4 (i.e. the same
679     // as gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS).
680     // TODO(syoussefi): This should be conditioned to transform feedback extension not being
681     // present.  http://anglebug.com/3206.
682     // TODO(syoussefi): If geometry shader is supported, emulation will be done at that stage, and
683     // so the reserved storage buffers should be accounted in that stage.  http://anglebug.com/3606
684     static_assert(
685         gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS == 4,
686         "Limit to ES2.0 if supported SSBO count < supporting transform feedback buffer count");
687     if (mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
688     {
689         ASSERT(maxVertexStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
690         maxVertexStageStorageBuffers -= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
691         maxCombinedStorageBuffers -= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
692 
693         // Cap the per-stage limit of the other stages to the combined limit, in case the combined
694         // limit is now lower than that.
695         maxPerStageStorageBuffers = std::min(maxPerStageStorageBuffers, maxCombinedStorageBuffers);
696     }
697 
698     // Reserve up to IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS storage buffers in the fragment and
699     // compute stages for atomic counters.  This is only possible if the number of per-stage storage
700     // buffers is greater than 4, which is the required GLES minimum for compute.
701     //
702     // For each stage, we'll either not support atomic counter buffers, or support exactly
703     // IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS.  This is due to restrictions in the shader
704     // translator where we can't know how many atomic counter buffers we would really need after
705     // linking so we can't create a packed buffer array.
706     //
707     // For the vertex stage, we could support atomic counters without storage buffers, but that's
708     // likely not very useful, so we use the same limit (4 + MAX_ATOMIC_COUNTER_BUFFERS) for the
709     // vertex stage to determine if we would want to add support for atomic counter buffers.
710     constexpr uint32_t kMinimumStorageBuffersForAtomicCounterBufferSupport =
711         gl::limits::kMinimumComputeStorageBuffers +
712         gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS;
713     uint32_t maxVertexStageAtomicCounterBuffers = 0;
714     uint32_t maxPerStageAtomicCounterBuffers    = 0;
715     uint32_t maxCombinedAtomicCounterBuffers    = 0;
716 
717     if (maxPerStageStorageBuffers >= kMinimumStorageBuffersForAtomicCounterBufferSupport)
718     {
719         maxPerStageAtomicCounterBuffers = gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS;
720         maxCombinedAtomicCounterBuffers = gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS;
721     }
722 
723     if (maxVertexStageStorageBuffers >= kMinimumStorageBuffersForAtomicCounterBufferSupport)
724     {
725         maxVertexStageAtomicCounterBuffers = gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS;
726     }
727 
728     maxVertexStageStorageBuffers -= maxVertexStageAtomicCounterBuffers;
729     maxPerStageStorageBuffers -= maxPerStageAtomicCounterBuffers;
730     maxCombinedStorageBuffers -= maxCombinedAtomicCounterBuffers;
731 
732     mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
733         mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics
734             ? LimitToInt(maxVertexStageStorageBuffers)
735             : 0;
736     mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
737         mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? LimitToInt(maxPerStageStorageBuffers)
738                                                          : 0;
739     mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Compute] =
740         LimitToInt(maxPerStageStorageBuffers);
741     mNativeCaps.maxCombinedShaderStorageBlocks = LimitToInt(maxCombinedStorageBuffers);
742 
743     mNativeCaps.maxShaderStorageBufferBindings = LimitToInt(maxCombinedStorageBuffers);
744     mNativeCaps.maxShaderStorageBlockSize      = limitsVk.maxStorageBufferRange;
745     mNativeCaps.shaderStorageBufferOffsetAlignment =
746         LimitToInt(static_cast<uint32_t>(limitsVk.minStorageBufferOffsetAlignment));
747 
748     mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Vertex] =
749         mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics
750             ? LimitToInt(maxVertexStageAtomicCounterBuffers)
751             : 0;
752     mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Fragment] =
753         mPhysicalDeviceFeatures.fragmentStoresAndAtomics
754             ? LimitToInt(maxPerStageAtomicCounterBuffers)
755             : 0;
756     mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Compute] =
757         LimitToInt(maxPerStageAtomicCounterBuffers);
758     mNativeCaps.maxCombinedAtomicCounterBuffers = LimitToInt(maxCombinedAtomicCounterBuffers);
759 
760     mNativeCaps.maxAtomicCounterBufferBindings = LimitToInt(maxCombinedAtomicCounterBuffers);
761     // Emulated as storage buffers, atomic counter buffers have the same size limit.  However, the
762     // limit is a signed integer and values above int max will end up as a negative size.
763     mNativeCaps.maxAtomicCounterBufferSize = LimitToInt(limitsVk.maxStorageBufferRange);
764 
765     // There is no particular limit to how many atomic counters there can be, other than the size of
766     // a storage buffer.  We nevertheless limit this to something reasonable (4096 arbitrarily).
767     const int32_t maxAtomicCounters =
768         std::min<int32_t>(4096, limitsVk.maxStorageBufferRange / sizeof(uint32_t));
769     for (gl::ShaderType shaderType : gl::AllShaderTypes())
770     {
771         mNativeCaps.maxShaderAtomicCounters[shaderType] = maxAtomicCounters;
772     }
773 
774     // Set maxShaderAtomicCounters to zero if atomic is not supported.
775     if (!mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
776     {
777         mNativeCaps.maxShaderAtomicCounters[gl::ShaderType::Vertex] = 0;
778     }
779     if (!mPhysicalDeviceFeatures.fragmentStoresAndAtomics)
780     {
781         mNativeCaps.maxShaderAtomicCounters[gl::ShaderType::Fragment] = 0;
782     }
783 
784     mNativeCaps.maxCombinedAtomicCounters = maxAtomicCounters;
785 
786     // GL Images correspond to Vulkan Storage Images.
787     const int32_t maxPerStageImages = LimitToInt(limitsVk.maxPerStageDescriptorStorageImages);
788     const int32_t maxCombinedImages = LimitToInt(limitsVk.maxDescriptorSetStorageImages);
789     const int32_t maxVertexPipelineImages =
790         mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageImages : 0;
791 
792     mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Vertex]         = maxVertexPipelineImages;
793     mNativeCaps.maxShaderImageUniforms[gl::ShaderType::TessControl]    = maxVertexPipelineImages;
794     mNativeCaps.maxShaderImageUniforms[gl::ShaderType::TessEvaluation] = maxVertexPipelineImages;
795     mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Geometry]       = maxVertexPipelineImages;
796     mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Fragment] =
797         mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageImages : 0;
798     mNativeCaps.maxShaderImageUniforms[gl::ShaderType::Compute] = maxPerStageImages;
799 
800     mNativeCaps.maxCombinedImageUniforms = maxCombinedImages;
801     mNativeCaps.maxImageUnits            = maxCombinedImages;
802 
803     mNativeCaps.minProgramTexelOffset         = limitsVk.minTexelOffset;
804     mNativeCaps.maxProgramTexelOffset         = limitsVk.maxTexelOffset;
805     mNativeCaps.minProgramTextureGatherOffset = limitsVk.minTexelGatherOffset;
806     mNativeCaps.maxProgramTextureGatherOffset = limitsVk.maxTexelGatherOffset;
807 
808     // There is no additional limit to the combined number of components.  We can have up to a
809     // maximum number of uniform buffers, each having the maximum number of components.  Note that
810     // this limit includes both components in and out of uniform buffers.
811     //
812     // This value is limited to INT_MAX to avoid overflow when queried from glGetIntegerv().
813     const uint64_t maxCombinedUniformComponents =
814         std::min<uint64_t>(static_cast<uint64_t>(maxPerStageUniformBuffers +
815                                                  kReservedPerStageDefaultUniformBindingCount) *
816                                maxUniformComponents,
817                            std::numeric_limits<GLint>::max());
818     for (gl::ShaderType shaderType : gl::AllShaderTypes())
819     {
820         mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
821     }
822 
823     // Total number of resources available to the user are as many as Vulkan allows minus everything
824     // that ANGLE uses internally.  That is, one dynamic uniform buffer used per stage for default
825     // uniforms and a single dynamic uniform buffer for driver uniforms.  Additionally, Vulkan uses
826     // up to IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS + 1 buffers for transform feedback (Note:
827     // +1 is for the "counter" buffer of transform feedback, which will be necessary for transform
828     // feedback extension and ES3.2 transform feedback emulation, but is not yet present).
829     constexpr uint32_t kReservedPerStageUniformBufferCount = 1;
830     constexpr uint32_t kReservedPerStageBindingCount =
831         kReservedDriverUniformBindingCount + kReservedPerStageUniformBufferCount +
832         gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS + 1;
833 
834     // Note: maxPerStageResources is required to be at least the sum of per stage UBOs, SSBOs etc
835     // which total a minimum of 44 resources, so no underflow is possible here.  Limit the total
836     // number of resources reported by Vulkan to 2 billion though to avoid seeing negative numbers
837     // in applications that take the value as signed int (including dEQP).
838     const uint32_t maxPerStageResources = limitsVk.maxPerStageResources;
839     mNativeCaps.maxCombinedShaderOutputResources =
840         LimitToInt(maxPerStageResources - kReservedPerStageBindingCount);
841 
842     // Reserve 1 extra varying for ANGLEPosition when GLLineRasterization is enabled
843     constexpr GLint kReservedVaryingComponentsForGLLineRasterization = 4;
844     // Reserve 1 extra varying for transform feedback capture of gl_Position.
845     constexpr GLint kReservedVaryingComponentsForTransformFeedbackExtension = 4;
846 
847     GLint reservedVaryingComponentCount = 0;
848 
849     if (getFeatures().basicGLLineRasterization.enabled)
850     {
851         reservedVaryingComponentCount += kReservedVaryingComponentsForGLLineRasterization;
852     }
853     if (getFeatures().supportsTransformFeedbackExtension.enabled)
854     {
855         reservedVaryingComponentCount += kReservedVaryingComponentsForTransformFeedbackExtension;
856     }
857 
858     // The max varying vectors should not include gl_Position.
859     // The gles2.0 section 2.10 states that "gl_Position is not a varying variable and does
860     // not count against this limit.", but the Vulkan spec has no such mention in its Built-in
861     // vars section. It is implicit that we need to actually reserve it for Vulkan in that case.
862     //
863     // Note that this exception for gl_Position does not apply to MAX_VERTEX_OUTPUT_COMPONENTS and
864     // similar limits.
865     const GLint reservedVaryingVectorCount = reservedVaryingComponentCount / 4 + 1;
866 
867     const GLint maxVaryingCount =
868         std::min(limitsVk.maxVertexOutputComponents, limitsVk.maxFragmentInputComponents);
869     mNativeCaps.maxVaryingVectors =
870         LimitToInt((maxVaryingCount / kComponentsPerVector) - reservedVaryingVectorCount);
871     mNativeCaps.maxVertexOutputComponents =
872         LimitToInt(limitsVk.maxVertexOutputComponents) - reservedVaryingComponentCount;
873     mNativeCaps.maxFragmentInputComponents =
874         LimitToInt(limitsVk.maxFragmentInputComponents) - reservedVaryingComponentCount;
875 
876     mNativeCaps.maxTransformFeedbackInterleavedComponents =
877         gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
878     mNativeCaps.maxTransformFeedbackSeparateAttributes =
879         gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
880     mNativeCaps.maxTransformFeedbackSeparateComponents =
881         gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
882 
883     mNativeCaps.minProgramTexelOffset = limitsVk.minTexelOffset;
884     mNativeCaps.maxProgramTexelOffset = LimitToInt(limitsVk.maxTexelOffset);
885 
886     const uint32_t sampleCounts =
887         limitsVk.framebufferColorSampleCounts & limitsVk.framebufferDepthSampleCounts &
888         limitsVk.framebufferStencilSampleCounts & vk_gl::kSupportedSampleCounts;
889 
890     mNativeCaps.maxSamples            = LimitToInt(vk_gl::GetMaxSampleCount(sampleCounts));
891     mNativeCaps.maxFramebufferSamples = mNativeCaps.maxSamples;
892 
893     mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits;
894 
895     // Important games are not checking supported extensions properly, and are confusing the
896     // GL_EXT_shader_framebuffer_fetch_non_coherent as the GL_EXT_shader_framebuffer_fetch
897     // extension.  Therefore, don't enable the extension on Arm and Qualcomm.
898     // https://issuetracker.google.com/issues/186643966
899     if (!(IsARM(mPhysicalDeviceProperties.vendorID) ||
900           IsQualcomm(mPhysicalDeviceProperties.vendorID)))
901     {
902         // Enable GL_EXT_shader_framebuffer_fetch_non_coherent
903         // For supporting this extension, gl::IMPLEMENTATION_MAX_DRAW_BUFFERS is used.
904         mNativeExtensions.shaderFramebufferFetchNonCoherentEXT =
905             mNativeCaps.maxDrawBuffers >= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS;
906     }
907 
908     // Enable Program Binary extension.
909     mNativeExtensions.getProgramBinaryOES = true;
910     mNativeCaps.programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
911 
912     // Enable GL_NV_pixel_buffer_object extension.
913     mNativeExtensions.pixelBufferObjectNV = true;
914 
915     // Enable GL_NV_fence extension.
916     mNativeExtensions.fenceNV = true;
917 
918     // Enable GL_EXT_copy_image
919     mNativeExtensions.copyImageEXT = true;
920 
921     // GL_EXT_clip_control
922     mNativeExtensions.clipControlEXT = true;
923 
924     // Enable GL_EXT_texture_buffer and OES variant.  Nearly all formats required for this extension
925     // are also required to have the UNIFORM_TEXEL_BUFFER feature bit in Vulkan, except for
926     // R32G32B32_SFLOAT/UINT/SINT which are optional.  For many formats, the STORAGE_TEXEL_BUFFER
927     // feature is optional though.  This extension is exposed only if the formats specified in
928     // EXT_texture_buffer support the necessary feature bits.
929     if (vk::HasTextureBufferSupport(this))
930     {
931         mNativeExtensions.textureBufferOES = true;
932         mNativeExtensions.textureBufferEXT = true;
933         mNativeCaps.maxTextureBufferSize   = LimitToInt(limitsVk.maxTexelBufferElements);
934         mNativeCaps.textureBufferOffsetAlignment =
935             LimitToInt(limitsVk.minTexelBufferOffsetAlignment);
936     }
937 
938     // Atomic image operations in the vertex and fragment shaders require the
939     // vertexPipelineStoresAndAtomics and fragmentStoresAndAtomics Vulkan features respectively.
940     // If either of these features is not present, the number of image uniforms for that stage is
941     // advertized as zero, so image atomic operations support can be agnostic of shader stages.
942     //
943     // GL_OES_shader_image_atomic requires that image atomic functions have support for r32i and
944     // r32ui formats.  These formats have mandatory support for STORAGE_IMAGE_ATOMIC and
945     // STORAGE_TEXEL_BUFFER_ATOMIC features in Vulkan.  Additionally, it requires that
946     // imageAtomicExchange supports r32f, which is emulated in ANGLE transforming the shader to
947     // expect r32ui instead.
948     mNativeExtensions.shaderImageAtomicOES = true;
949 
950     // Geometry shaders are required for ES 3.2.
951     // We don't support GS when we are emulating line raster due to the tricky position varying.
952     if (mPhysicalDeviceFeatures.geometryShader && !mFeatures.basicGLLineRasterization.enabled)
953     {
954         // TODO: geometry shader support is incomplete.  http://anglebug.com/3571
955         bool geometryShader = mFeatures.supportsTransformFeedbackExtension.enabled &&
956                               mFeatures.exposeNonConformantExtensionsAndVersions.enabled;
957         mNativeExtensions.geometryShaderEXT = geometryShader;
958         mNativeExtensions.geometryShaderOES = geometryShader;
959         mNativeCaps.maxFramebufferLayers    = LimitToInt(limitsVk.maxFramebufferLayers);
960 
961         // If the provoking vertex feature is enabled, angle specifies to use
962         // the "last" convention in order to match GL behavior. Otherwise, use
963         // "first" as vulkan follows this convention for provoking vertex.
964         mNativeCaps.layerProvokingVertex = (mFeatures.provokingVertex.enabled)
965                                                ? GL_LAST_VERTEX_CONVENTION_EXT
966                                                : GL_FIRST_VERTEX_CONVENTION_EXT;
967 
968         mNativeCaps.maxGeometryInputComponents =
969             LimitToInt(limitsVk.maxGeometryInputComponents) - reservedVaryingComponentCount;
970         mNativeCaps.maxGeometryOutputComponents =
971             LimitToInt(limitsVk.maxGeometryOutputComponents) - reservedVaryingComponentCount;
972         mNativeCaps.maxGeometryOutputVertices = LimitToInt(limitsVk.maxGeometryOutputVertices);
973         mNativeCaps.maxGeometryTotalOutputComponents =
974             LimitToInt(limitsVk.maxGeometryTotalOutputComponents);
975         mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Geometry] =
976             mNativeCaps.maxCombinedShaderOutputResources;
977         mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::Geometry] =
978             maxCombinedAtomicCounterBuffers;
979         mNativeCaps.maxGeometryShaderInvocations =
980             LimitToInt(limitsVk.maxGeometryShaderInvocations);
981     }
982 
983     // We don't support TS when we are emulating line raster due to the tricky position varying.
984     if (mPhysicalDeviceFeatures.tessellationShader && !mFeatures.basicGLLineRasterization.enabled)
985     {
986         constexpr uint32_t kReservedTessellationDefaultUniformBindingCount = 2;
987 
988         // TODO: tessellation shader support is incomplete.  http://anglebug.com/3572
989         mNativeExtensions.tessellationShaderEXT =
990             mFeatures.supportsTransformFeedbackExtension.enabled &&
991             mFeatures.exposeNonConformantExtensionsAndVersions.enabled;
992         mNativeCaps.maxPatchVertices = LimitToInt(limitsVk.maxTessellationPatchSize);
993         mNativeCaps.maxTessPatchComponents =
994             LimitToInt(limitsVk.maxTessellationControlPerPatchOutputComponents);
995         mNativeCaps.maxTessGenLevel = LimitToInt(limitsVk.maxTessellationGenerationLevel);
996 
997         mNativeCaps.maxTessControlInputComponents =
998             LimitToInt(limitsVk.maxTessellationControlPerVertexInputComponents);
999         mNativeCaps.maxTessControlOutputComponents =
1000             LimitToInt(limitsVk.maxTessellationControlPerVertexOutputComponents);
1001         mNativeCaps.maxTessControlTotalOutputComponents =
1002             LimitToInt(limitsVk.maxTessellationControlTotalOutputComponents);
1003         mNativeCaps.maxTessEvaluationInputComponents =
1004             LimitToInt(limitsVk.maxTessellationEvaluationInputComponents);
1005         mNativeCaps.maxTessEvaluationOutputComponents =
1006             LimitToInt(limitsVk.maxTessellationEvaluationOutputComponents);
1007 
1008         // There is 1 default uniform binding used per tessellation stages.
1009         mNativeCaps.maxCombinedUniformBlocks = LimitToInt(
1010             mNativeCaps.maxCombinedUniformBlocks + kReservedTessellationDefaultUniformBindingCount);
1011         mNativeCaps.maxUniformBufferBindings = LimitToInt(
1012             mNativeCaps.maxUniformBufferBindings + kReservedTessellationDefaultUniformBindingCount);
1013 
1014         mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::TessControl] =
1015             mNativeCaps.maxCombinedShaderOutputResources;
1016         mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::TessControl] =
1017             maxCombinedAtomicCounterBuffers;
1018 
1019         mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::TessEvaluation] =
1020             mNativeCaps.maxCombinedShaderOutputResources;
1021         mNativeCaps.maxShaderAtomicCounterBuffers[gl::ShaderType::TessEvaluation] =
1022             maxCombinedAtomicCounterBuffers;
1023     }
1024 
1025     // GL_APPLE_clip_distance/GL_EXT_clip_cull_distance
1026     // From the EXT_clip_cull_distance extension spec:
1027     //
1028     // > Modify Section 7.2, "Built-In Constants" (p. 126)
1029     // >
1030     // > const mediump int gl_MaxClipDistances = 8;
1031     // > const mediump int gl_MaxCullDistances = 8;
1032     // > const mediump int gl_MaxCombinedClipAndCullDistances = 8;
1033     constexpr uint32_t kMaxClipDistancePerSpec                = 8;
1034     constexpr uint32_t kMaxCullDistancePerSpec                = 8;
1035     constexpr uint32_t kMaxCombinedClipAndCullDistancePerSpec = 8;
1036 
1037     // TODO: http://anglebug.com/5466
1038     // After implementing EXT_geometry_shader, EXT_clip_cull_distance should be additionally
1039     // implemented to support the geometry shader. Until then, EXT_clip_cull_distance is enabled
1040     // only in the experimental cases.
1041     if (mPhysicalDeviceFeatures.shaderClipDistance &&
1042         limitsVk.maxClipDistances >= kMaxClipDistancePerSpec)
1043     {
1044         mNativeExtensions.clipDistanceAPPLE = true;
1045         mNativeCaps.maxClipDistances =
1046             std::min<GLuint>(limitsVk.maxClipDistances, gl::IMPLEMENTATION_MAX_CLIP_DISTANCES);
1047 
1048         if (mPhysicalDeviceFeatures.shaderCullDistance &&
1049             limitsVk.maxCullDistances >= kMaxCullDistancePerSpec &&
1050             limitsVk.maxCombinedClipAndCullDistances >= kMaxCombinedClipAndCullDistancePerSpec)
1051         {
1052             mNativeExtensions.clipCullDistanceEXT       = true;
1053             mNativeCaps.maxCullDistances                = limitsVk.maxCullDistances;
1054             mNativeCaps.maxCombinedClipAndCullDistances = limitsVk.maxCombinedClipAndCullDistances;
1055         }
1056     }
1057 
1058     // GL_EXT_blend_func_extended
1059     mNativeExtensions.blendFuncExtended        = (mPhysicalDeviceFeatures.dualSrcBlend == VK_TRUE);
1060     mNativeExtensions.maxDualSourceDrawBuffers = LimitToInt(limitsVk.maxFragmentDualSrcAttachments);
1061 
1062     // GL_ANGLE_relaxed_vertex_attribute_type
1063     mNativeExtensions.relaxedVertexAttributeTypeANGLE = true;
1064 
1065     // GL_OVR_multiview*.  Bresenham line emulation does not work with multiview.  There's no
1066     // limitation in Vulkan to restrict an application to multiview 1.
1067     mNativeExtensions.multiview =
1068         mMultiviewFeatures.multiview && mFeatures.bresenhamLineRasterization.enabled;
1069     mNativeExtensions.multiview2 = mNativeExtensions.multiview;
1070     mNativeExtensions.maxViews   = mMultiviewProperties.maxMultiviewViewCount;
1071 
1072     // GL_ANGLE_yuv_internal_format
1073     mNativeExtensions.yuvInternalFormatANGLE =
1074         getFeatures().supportsYUVSamplerConversion.enabled && vk::CanSupportYuvInternalFormat(this);
1075 }
1076 
1077 namespace vk
1078 {
1079 
CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures & features)1080 bool CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures &features)
1081 {
1082     // We use the following Vulkan features to implement EXT_gpu_shader5:
1083     // - shaderImageGatherExtended: textureGatherOffset with non-constant offset and
1084     //   textureGatherOffsets family of functions.
1085     // - shaderSampledImageArrayDynamicIndexing and shaderUniformBufferArrayDynamicIndexing:
1086     //   dynamically uniform indices for samplers and uniform buffers.
1087     return features.shaderImageGatherExtended && features.shaderSampledImageArrayDynamicIndexing &&
1088            features.shaderUniformBufferArrayDynamicIndexing;
1089 }
1090 
1091 }  // namespace vk
1092 
1093 namespace egl_vk
1094 {
1095 
1096 namespace
1097 {
1098 
ComputeMaximumPBufferPixels(const VkPhysicalDeviceProperties & physicalDeviceProperties)1099 EGLint ComputeMaximumPBufferPixels(const VkPhysicalDeviceProperties &physicalDeviceProperties)
1100 {
1101     // EGLints are signed 32-bit integers, it's fairly easy to overflow them, especially since
1102     // Vulkan's minimum guaranteed VkImageFormatProperties::maxResourceSize is 2^31 bytes.
1103     constexpr uint64_t kMaxValueForEGLint =
1104         static_cast<uint64_t>(std::numeric_limits<EGLint>::max());
1105 
1106     // TODO(geofflang): Compute the maximum size of a pbuffer by using the maxResourceSize result
1107     // from vkGetPhysicalDeviceImageFormatProperties for both the color and depth stencil format and
1108     // the exact image creation parameters that would be used to create the pbuffer. Because it is
1109     // always safe to return out-of-memory errors on pbuffer allocation, it's fine to simply return
1110     // the number of pixels in a max width by max height pbuffer for now. http://anglebug.com/2622
1111 
1112     // Storing the result of squaring a 32-bit unsigned int in a 64-bit unsigned int is safe.
1113     static_assert(std::is_same<decltype(physicalDeviceProperties.limits.maxImageDimension2D),
1114                                uint32_t>::value,
1115                   "physicalDeviceProperties.limits.maxImageDimension2D expected to be a uint32_t.");
1116     const uint64_t maxDimensionsSquared =
1117         static_cast<uint64_t>(physicalDeviceProperties.limits.maxImageDimension2D) *
1118         static_cast<uint64_t>(physicalDeviceProperties.limits.maxImageDimension2D);
1119 
1120     return static_cast<EGLint>(std::min(maxDimensionsSquared, kMaxValueForEGLint));
1121 }
1122 
1123 // Generates a basic config for a combination of color format, depth stencil format and sample
1124 // count.
GenerateDefaultConfig(DisplayVk * display,const gl::InternalFormat & colorFormat,const gl::InternalFormat & depthStencilFormat,EGLint sampleCount)1125 egl::Config GenerateDefaultConfig(DisplayVk *display,
1126                                   const gl::InternalFormat &colorFormat,
1127                                   const gl::InternalFormat &depthStencilFormat,
1128                                   EGLint sampleCount)
1129 {
1130     const RendererVk *renderer = display->getRenderer();
1131 
1132     const VkPhysicalDeviceProperties &physicalDeviceProperties =
1133         renderer->getPhysicalDeviceProperties();
1134     gl::Version maxSupportedESVersion = renderer->getMaxSupportedESVersion();
1135 
1136     // ES3 features are required to emulate ES1
1137     EGLint es1Support = (maxSupportedESVersion.major >= 3 ? EGL_OPENGL_ES_BIT : 0);
1138     EGLint es2Support = (maxSupportedESVersion.major >= 2 ? EGL_OPENGL_ES2_BIT : 0);
1139     EGLint es3Support = (maxSupportedESVersion.major >= 3 ? EGL_OPENGL_ES3_BIT : 0);
1140 
1141     egl::Config config;
1142 
1143     config.renderTargetFormat = colorFormat.internalFormat;
1144     config.depthStencilFormat = depthStencilFormat.internalFormat;
1145     config.bufferSize         = colorFormat.pixelBytes * 8;
1146     config.redSize            = colorFormat.redBits;
1147     config.greenSize          = colorFormat.greenBits;
1148     config.blueSize           = colorFormat.blueBits;
1149     config.alphaSize          = colorFormat.alphaBits;
1150     config.alphaMaskSize      = 0;
1151     config.bindToTextureRGB   = colorFormat.format == GL_RGB;
1152     config.bindToTextureRGBA  = colorFormat.format == GL_RGBA || colorFormat.format == GL_BGRA_EXT;
1153     config.colorBufferType    = EGL_RGB_BUFFER;
1154     config.configCaveat       = GetConfigCaveat(colorFormat.internalFormat);
1155     config.conformant         = es1Support | es2Support | es3Support;
1156     config.depthSize          = depthStencilFormat.depthBits;
1157     config.stencilSize        = depthStencilFormat.stencilBits;
1158     config.level              = 0;
1159     config.matchNativePixmap  = EGL_NONE;
1160     config.maxPBufferWidth    = physicalDeviceProperties.limits.maxImageDimension2D;
1161     config.maxPBufferHeight   = physicalDeviceProperties.limits.maxImageDimension2D;
1162     config.maxPBufferPixels   = ComputeMaximumPBufferPixels(physicalDeviceProperties);
1163     config.maxSwapInterval    = 1;
1164     config.minSwapInterval    = 0;
1165     config.nativeRenderable   = EGL_TRUE;
1166     config.nativeVisualID     = static_cast<EGLint>(GetNativeVisualID(colorFormat));
1167     config.nativeVisualType   = EGL_NONE;
1168     config.renderableType     = es1Support | es2Support | es3Support;
1169     config.sampleBuffers      = (sampleCount > 0) ? 1 : 0;
1170     config.samples            = sampleCount;
1171     config.surfaceType        = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
1172     // Vulkan surfaces use a different origin than OpenGL, always prefer to be flipped vertically if
1173     // possible.
1174     config.optimalOrientation    = EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE;
1175     config.transparentType       = EGL_NONE;
1176     config.transparentRedValue   = 0;
1177     config.transparentGreenValue = 0;
1178     config.transparentBlueValue  = 0;
1179     config.colorComponentType =
1180         gl_egl::GLComponentTypeToEGLColorComponentType(colorFormat.componentType);
1181 
1182     // Vulkan always supports off-screen rendering.  Check the config with display to see if it can
1183     // also have window support.  If not, the following call should automatically remove
1184     // EGL_WINDOW_BIT.
1185     display->checkConfigSupport(&config);
1186 
1187     return config;
1188 }
1189 
1190 }  // anonymous namespace
1191 
GenerateConfigs(const GLenum * colorFormats,size_t colorFormatsCount,const GLenum * depthStencilFormats,size_t depthStencilFormatCount,DisplayVk * display)1192 egl::ConfigSet GenerateConfigs(const GLenum *colorFormats,
1193                                size_t colorFormatsCount,
1194                                const GLenum *depthStencilFormats,
1195                                size_t depthStencilFormatCount,
1196                                DisplayVk *display)
1197 {
1198     ASSERT(colorFormatsCount > 0);
1199     ASSERT(display != nullptr);
1200 
1201     gl::SupportedSampleSet colorSampleCounts;
1202     gl::SupportedSampleSet depthStencilSampleCounts;
1203     gl::SupportedSampleSet sampleCounts;
1204 
1205     const VkPhysicalDeviceLimits &limits =
1206         display->getRenderer()->getPhysicalDeviceProperties().limits;
1207     const uint32_t depthStencilSampleCountsLimit = limits.framebufferDepthSampleCounts &
1208                                                    limits.framebufferStencilSampleCounts &
1209                                                    vk_gl::kSupportedSampleCounts;
1210 
1211     vk_gl::AddSampleCounts(limits.framebufferColorSampleCounts & vk_gl::kSupportedSampleCounts,
1212                            &colorSampleCounts);
1213     vk_gl::AddSampleCounts(depthStencilSampleCountsLimit, &depthStencilSampleCounts);
1214 
1215     // Always support 0 samples
1216     colorSampleCounts.insert(0);
1217     depthStencilSampleCounts.insert(0);
1218 
1219     std::set_intersection(colorSampleCounts.begin(), colorSampleCounts.end(),
1220                           depthStencilSampleCounts.begin(), depthStencilSampleCounts.end(),
1221                           std::inserter(sampleCounts, sampleCounts.begin()));
1222 
1223     egl::ConfigSet configSet;
1224 
1225     for (size_t colorFormatIdx = 0; colorFormatIdx < colorFormatsCount; colorFormatIdx++)
1226     {
1227         const gl::InternalFormat &colorFormatInfo =
1228             gl::GetSizedInternalFormatInfo(colorFormats[colorFormatIdx]);
1229         ASSERT(colorFormatInfo.sized);
1230 
1231         for (size_t depthStencilFormatIdx = 0; depthStencilFormatIdx < depthStencilFormatCount;
1232              depthStencilFormatIdx++)
1233         {
1234             const gl::InternalFormat &depthStencilFormatInfo =
1235                 gl::GetSizedInternalFormatInfo(depthStencilFormats[depthStencilFormatIdx]);
1236             ASSERT(depthStencilFormats[depthStencilFormatIdx] == GL_NONE ||
1237                    depthStencilFormatInfo.sized);
1238 
1239             const gl::SupportedSampleSet *configSampleCounts = &sampleCounts;
1240             // If there is no depth/stencil buffer, use the color samples set.
1241             if (depthStencilFormats[depthStencilFormatIdx] == GL_NONE)
1242             {
1243                 configSampleCounts = &colorSampleCounts;
1244             }
1245             // If there is no color buffer, use the depth/stencil samples set.
1246             else if (colorFormats[colorFormatIdx] == GL_NONE)
1247             {
1248                 configSampleCounts = &depthStencilSampleCounts;
1249             }
1250 
1251             for (EGLint sampleCount : *configSampleCounts)
1252             {
1253                 egl::Config config = GenerateDefaultConfig(display, colorFormatInfo,
1254                                                            depthStencilFormatInfo, sampleCount);
1255                 configSet.add(config);
1256             }
1257         }
1258     }
1259 
1260     return configSet;
1261 }
1262 
1263 }  // namespace egl_vk
1264 
1265 }  // namespace rx
1266