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