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