summaryrefslogtreecommitdiff
path: root/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp')
-rw-r--r--Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp1017
1 files changed, 1017 insertions, 0 deletions
diff --git a/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp
new file mode 100644
index 000000000..15cf6271a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -0,0 +1,1017 @@
+//
+// Copyright (c) 2012-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// renderergl_utils.cpp: Conversion functions and other utility routines
+// specific to the OpenGL renderer.
+
+#include "libANGLE/renderer/gl/renderergl_utils.h"
+
+#include <limits>
+
+#include "common/mathutil.h"
+#include "libANGLE/Buffer.h"
+#include "libANGLE/Caps.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/WorkaroundsGL.h"
+#include "libANGLE/renderer/gl/formatutilsgl.h"
+
+#include <algorithm>
+#include <sstream>
+
+using angle::CheckedNumeric;
+
+namespace rx
+{
+VendorID GetVendorID(const FunctionsGL *functions)
+{
+ std::string nativeVendorString(reinterpret_cast<const char *>(functions->getString(GL_VENDOR)));
+ if (nativeVendorString.find("Intel") != std::string::npos)
+ {
+ return VENDOR_ID_INTEL;
+ }
+ else if (nativeVendorString.find("NVIDIA") != std::string::npos)
+ {
+ return VENDOR_ID_NVIDIA;
+ }
+ else if (nativeVendorString.find("ATI") != std::string::npos ||
+ nativeVendorString.find("AMD") != std::string::npos)
+ {
+ return VENDOR_ID_AMD;
+ }
+ else if (nativeVendorString.find("Qualcomm") != std::string::npos)
+ {
+ return VENDOR_ID_QUALCOMM;
+ }
+ else
+ {
+ return VENDOR_ID_UNKNOWN;
+ }
+}
+
+namespace nativegl_gl
+{
+
+static bool MeetsRequirements(const FunctionsGL *functions, const nativegl::SupportRequirement &requirements)
+{
+ for (const std::string &extension : requirements.requiredExtensions)
+ {
+ if (!functions->hasExtension(extension))
+ {
+ return false;
+ }
+ }
+
+ if (functions->version >= requirements.version)
+ {
+ return true;
+ }
+ else if (!requirements.versionExtensions.empty())
+ {
+ for (const std::string &extension : requirements.versionExtensions)
+ {
+ if (!functions->hasExtension(extension))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, GLenum internalFormat)
+{
+ gl::TextureCaps textureCaps;
+
+ const nativegl::InternalFormat &formatInfo = nativegl::GetInternalFormatInfo(internalFormat, functions->standard);
+ textureCaps.texturable = MeetsRequirements(functions, formatInfo.texture);
+ textureCaps.filterable = textureCaps.texturable && MeetsRequirements(functions, formatInfo.filter);
+ textureCaps.renderable = MeetsRequirements(functions, formatInfo.framebufferAttachment);
+
+ // glGetInternalformativ is not available until version 4.2 but may be available through the 3.0
+ // extension GL_ARB_internalformat_query
+ if (textureCaps.renderable && functions->getInternalformativ)
+ {
+ GLint numSamples = 0;
+ functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &numSamples);
+
+ if (numSamples > 0)
+ {
+ std::vector<GLint> samples(numSamples);
+ functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_SAMPLES,
+ static_cast<GLsizei>(samples.size()), &samples[0]);
+ for (size_t sampleIndex = 0; sampleIndex < samples.size(); sampleIndex++)
+ {
+ textureCaps.sampleCounts.insert(samples[sampleIndex]);
+ }
+ }
+ }
+
+ return textureCaps;
+}
+
+static GLint QuerySingleGLInt(const FunctionsGL *functions, GLenum name)
+{
+ GLint result = 0;
+ functions->getIntegerv(name, &result);
+ return result;
+}
+
+static GLint QuerySingleIndexGLInt(const FunctionsGL *functions, GLenum name, GLuint index)
+{
+ GLint result;
+ functions->getIntegeri_v(name, index, &result);
+ return result;
+}
+
+static GLint QueryGLIntRange(const FunctionsGL *functions, GLenum name, size_t index)
+{
+ GLint result[2] = {};
+ functions->getIntegerv(name, result);
+ return result[index];
+}
+
+static GLint64 QuerySingleGLInt64(const FunctionsGL *functions, GLenum name)
+{
+ GLint64 result = 0;
+ functions->getInteger64v(name, &result);
+ return result;
+}
+
+static GLfloat QuerySingleGLFloat(const FunctionsGL *functions, GLenum name)
+{
+ GLfloat result = 0.0f;
+ functions->getFloatv(name, &result);
+ return result;
+}
+
+static GLfloat QueryGLFloatRange(const FunctionsGL *functions, GLenum name, size_t index)
+{
+ GLfloat result[2] = {};
+ functions->getFloatv(name, result);
+ return result[index];
+}
+
+static gl::TypePrecision QueryTypePrecision(const FunctionsGL *functions, GLenum shaderType, GLenum precisionType)
+{
+ gl::TypePrecision precision;
+ functions->getShaderPrecisionFormat(shaderType, precisionType, precision.range, &precision.precision);
+ return precision;
+}
+
+static GLint QueryQueryValue(const FunctionsGL *functions, GLenum target, GLenum name)
+{
+ GLint result;
+ functions->getQueryiv(target, name, &result);
+ return result;
+}
+
+static void LimitVersion(gl::Version *curVersion, const gl::Version &maxVersion)
+{
+ if (*curVersion >= maxVersion)
+ {
+ *curVersion = maxVersion;
+ }
+}
+
+void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap,
+ gl::Extensions *extensions, gl::Version *maxSupportedESVersion)
+{
+ // Texture format support checks
+ const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
+ for (GLenum internalFormat : allFormats)
+ {
+ gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat);
+ textureCapsMap->insert(internalFormat, textureCaps);
+
+ if (gl::GetInternalFormatInfo(internalFormat).compressed)
+ {
+ caps->compressedTextureFormats.push_back(internalFormat);
+ }
+ }
+
+ // Start by assuming ES3.1 support and work down
+ *maxSupportedESVersion = gl::Version(3, 1);
+
+ // Table 6.28, implementation dependent values
+ if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->hasGLExtension("GL_ARB_ES3_compatibility") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxElementIndex = QuerySingleGLInt64(functions, GL_MAX_ELEMENT_INDEX);
+ }
+ else
+ {
+ // Doesn't affect ES3 support, can use a pre-defined limit
+ caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max());
+ }
+
+ if (functions->isAtLeastGL(gl::Version(1, 2)) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_texture_3D"))
+ {
+ caps->max3DTextureSize = QuerySingleGLInt(functions, GL_MAX_3D_TEXTURE_SIZE);
+ }
+ else
+ {
+ // Can't support ES3 without 3D textures
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ caps->max2DTextureSize = QuerySingleGLInt(functions, GL_MAX_TEXTURE_SIZE); // GL 1.0 / ES 2.0
+ caps->maxCubeMapTextureSize = QuerySingleGLInt(functions, GL_MAX_CUBE_MAP_TEXTURE_SIZE); // GL 1.3 / ES 2.0
+
+ if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_texture_array") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxArrayTextureLayers = QuerySingleGLInt(functions, GL_MAX_ARRAY_TEXTURE_LAYERS);
+ }
+ else
+ {
+ // Can't support ES3 without array textures
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLExtension("GL_EXT_texture_lod_bias") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxLODBias = QuerySingleGLFloat(functions, GL_MAX_TEXTURE_LOD_BIAS);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_object") ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxRenderbufferSize = QuerySingleGLInt(functions, GL_MAX_RENDERBUFFER_SIZE);
+ caps->maxColorAttachments = QuerySingleGLInt(functions, GL_MAX_COLOR_ATTACHMENTS);
+ }
+ else
+ {
+ // Can't support ES2 without framebuffers and renderbuffers
+ LimitVersion(maxSupportedESVersion, gl::Version(0, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(2, 0)) || functions->hasGLExtension("ARB_draw_buffers") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_draw_buffers"))
+ {
+ caps->maxDrawBuffers = QuerySingleGLInt(functions, GL_MAX_DRAW_BUFFERS);
+ }
+ else
+ {
+ // Framebuffer is required to have at least one drawbuffer even if the extension is not
+ // supported
+ caps->maxDrawBuffers = 1;
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ caps->maxViewportWidth = QueryGLIntRange(functions, GL_MAX_VIEWPORT_DIMS, 0); // GL 1.0 / ES 2.0
+ caps->maxViewportHeight = QueryGLIntRange(functions, GL_MAX_VIEWPORT_DIMS, 1); // GL 1.0 / ES 2.0
+
+ if (functions->standard == STANDARD_GL_DESKTOP &&
+ (functions->profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0)
+ {
+ // Desktop GL core profile deprecated the GL_ALIASED_POINT_SIZE_RANGE query. Use
+ // GL_POINT_SIZE_RANGE instead.
+ caps->minAliasedPointSize = QueryGLFloatRange(functions, GL_POINT_SIZE_RANGE, 0);
+ caps->maxAliasedPointSize = QueryGLFloatRange(functions, GL_POINT_SIZE_RANGE, 1);
+ }
+ else
+ {
+ caps->minAliasedPointSize = QueryGLFloatRange(functions, GL_ALIASED_POINT_SIZE_RANGE, 0);
+ caps->maxAliasedPointSize = QueryGLFloatRange(functions, GL_ALIASED_POINT_SIZE_RANGE, 1);
+ }
+
+ caps->minAliasedLineWidth = QueryGLFloatRange(functions, GL_ALIASED_LINE_WIDTH_RANGE, 0); // GL 1.2 / ES 2.0
+ caps->maxAliasedLineWidth = QueryGLFloatRange(functions, GL_ALIASED_LINE_WIDTH_RANGE, 1); // GL 1.2 / ES 2.0
+
+ // Table 6.29, implementation dependent values (cont.)
+ if (functions->isAtLeastGL(gl::Version(1, 2)) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxElementsIndices = QuerySingleGLInt(functions, GL_MAX_ELEMENTS_INDICES);
+ caps->maxElementsVertices = QuerySingleGLInt(functions, GL_MAX_ELEMENTS_VERTICES);
+ }
+ else
+ {
+ // Doesn't impact supported version
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 1)) ||
+ functions->hasGLExtension("GL_ARB_get_program_binary") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) ||
+ functions->hasGLExtension("GL_OES_get_program_binary"))
+ {
+ // Able to support the GL_PROGRAM_BINARY_ANGLE format as long as another program binary
+ // format is available.
+ GLint numBinaryFormats = QuerySingleGLInt(functions, GL_NUM_PROGRAM_BINARY_FORMATS_OES);
+ if (numBinaryFormats > 0)
+ {
+ caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
+ }
+ }
+ else
+ {
+ // Doesn't impact supported version
+ }
+
+ // glGetShaderPrecisionFormat is not available until desktop GL version 4.1 or GL_ARB_ES2_compatibility exists
+ if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->vertexHighpFloat = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_HIGH_FLOAT);
+ caps->vertexMediumpFloat = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_MEDIUM_FLOAT);
+ caps->vertexLowpFloat = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_LOW_FLOAT);
+ caps->fragmentHighpFloat = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_HIGH_FLOAT);
+ caps->fragmentMediumpFloat = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT);
+ caps->fragmentLowpFloat = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_LOW_FLOAT);
+ caps->vertexHighpInt = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_HIGH_INT);
+ caps->vertexMediumpInt = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_MEDIUM_INT);
+ caps->vertexLowpInt = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_LOW_INT);
+ caps->fragmentHighpInt = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_HIGH_INT);
+ caps->fragmentMediumpInt = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_MEDIUM_INT);
+ caps->fragmentLowpInt = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_LOW_INT);
+ }
+ else
+ {
+ // Doesn't impact supported version, set some default values
+ caps->vertexHighpFloat.setIEEEFloat();
+ caps->vertexMediumpFloat.setIEEEFloat();
+ caps->vertexLowpFloat.setIEEEFloat();
+ caps->fragmentHighpFloat.setIEEEFloat();
+ caps->fragmentMediumpFloat.setIEEEFloat();
+ caps->fragmentLowpFloat.setIEEEFloat();
+ caps->vertexHighpInt.setTwosComplementInt(32);
+ caps->vertexMediumpInt.setTwosComplementInt(32);
+ caps->vertexLowpInt.setTwosComplementInt(32);
+ caps->fragmentHighpInt.setTwosComplementInt(32);
+ caps->fragmentMediumpInt.setTwosComplementInt(32);
+ caps->fragmentLowpInt.setTwosComplementInt(32);
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 2)) || functions->hasGLExtension("GL_ARB_sync") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxServerWaitTimeout = QuerySingleGLInt64(functions, GL_MAX_SERVER_WAIT_TIMEOUT);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Table 6.31, implementation dependent vertex shader limits
+ if (functions->isAtLeastGL(gl::Version(2, 0)) ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxVertexAttributes = QuerySingleGLInt(functions, GL_MAX_VERTEX_ATTRIBS);
+ caps->maxVertexUniformComponents = QuerySingleGLInt(functions, GL_MAX_VERTEX_UNIFORM_COMPONENTS);
+ caps->maxVertexTextureImageUnits = QuerySingleGLInt(functions, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+ }
+ else
+ {
+ // Can't support ES2 version without these caps
+ LimitVersion(maxSupportedESVersion, gl::Version(0, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxVertexUniformVectors = QuerySingleGLInt(functions, GL_MAX_VERTEX_UNIFORM_VECTORS);
+ }
+ else
+ {
+ // Doesn't limit ES version, GL_MAX_VERTEX_UNIFORM_COMPONENTS / 4 is acceptable.
+ caps->maxVertexUniformVectors = caps->maxVertexUniformComponents / 4;
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 1)) || functions->hasGLExtension("GL_ARB_uniform_buffer_object") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxVertexUniformBlocks = QuerySingleGLInt(functions, GL_MAX_VERTEX_UNIFORM_BLOCKS);
+ }
+ else
+ {
+ // Can't support ES3 without uniform blocks
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 2)) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxVertexOutputComponents = QuerySingleGLInt(functions, GL_MAX_VERTEX_OUTPUT_COMPONENTS);
+ }
+ else
+ {
+ // There doesn't seem, to be a desktop extension to add this cap, maybe it could be given a safe limit
+ // instead of limiting the supported ES version.
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Table 6.32, implementation dependent fragment shader limits
+ if (functions->isAtLeastGL(gl::Version(2, 0)) ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxFragmentUniformComponents = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS);
+ caps->maxTextureImageUnits = QuerySingleGLInt(functions, GL_MAX_TEXTURE_IMAGE_UNITS);
+ }
+ else
+ {
+ // Can't support ES2 version without these caps
+ LimitVersion(maxSupportedESVersion, gl::Version(0, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxFragmentUniformVectors = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_UNIFORM_VECTORS);
+ }
+ else
+ {
+ // Doesn't limit ES version, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS / 4 is acceptable.
+ caps->maxFragmentUniformVectors = caps->maxFragmentUniformComponents / 4;
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 1)) || functions->hasGLExtension("GL_ARB_uniform_buffer_object") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxFragmentUniformBlocks = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_UNIFORM_BLOCKS);
+ }
+ else
+ {
+ // Can't support ES3 without uniform blocks
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 2)) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxFragmentInputComponents = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_INPUT_COMPONENTS);
+ }
+ else
+ {
+ // There doesn't seem, to be a desktop extension to add this cap, maybe it could be given a safe limit
+ // instead of limiting the supported ES version.
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 0)) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->minProgramTexelOffset = QuerySingleGLInt(functions, GL_MIN_PROGRAM_TEXEL_OFFSET);
+ caps->maxProgramTexelOffset = QuerySingleGLInt(functions, GL_MAX_PROGRAM_TEXEL_OFFSET);
+ }
+ else
+ {
+ // Can't support ES3 without texel offset, could possibly be emulated in the shader
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Table 6.33, implementation dependent aggregate shader limits
+ if (functions->isAtLeastGL(gl::Version(3, 1)) || functions->hasGLExtension("GL_ARB_uniform_buffer_object") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxUniformBufferBindings = QuerySingleGLInt(functions, GL_MAX_UNIFORM_BUFFER_BINDINGS);
+ caps->maxUniformBlockSize = QuerySingleGLInt64(functions, GL_MAX_UNIFORM_BLOCK_SIZE);
+ caps->uniformBufferOffsetAlignment = QuerySingleGLInt(functions, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
+ caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentInputComponents;
+ caps->maxCombinedVertexUniformComponents = QuerySingleGLInt64(functions, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS);
+ caps->maxCombinedFragmentUniformComponents = QuerySingleGLInt64(functions, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS);
+ }
+ else
+ {
+ // Can't support ES3 without uniform blocks
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 0)) ||
+ functions->hasGLExtension("GL_ARB_ES2_compatibility") ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxVaryingComponents = QuerySingleGLInt(functions, GL_MAX_VARYING_COMPONENTS);
+ }
+ else if (functions->isAtLeastGL(gl::Version(2, 0)))
+ {
+ caps->maxVaryingComponents = QuerySingleGLInt(functions, GL_MAX_VARYING_FLOATS);
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(0, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") ||
+ functions->isAtLeastGLES(gl::Version(2, 0)))
+ {
+ caps->maxVaryingVectors = QuerySingleGLInt(functions, GL_MAX_VARYING_VECTORS);
+ }
+ else
+ {
+ // Doesn't limit ES version, GL_MAX_VARYING_COMPONENTS / 4 is acceptable.
+ caps->maxVaryingVectors = caps->maxVaryingComponents / 4;
+ }
+
+ // Determine the max combined texture image units by adding the vertex and fragment limits. If
+ // the real cap is queried, it would contain the limits for shader types that are not available to ES.
+ caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits;
+
+ // Table 6.34, implementation dependent transform feedback limits
+ if (functions->isAtLeastGL(gl::Version(4, 0)) ||
+ functions->hasGLExtension("GL_ARB_transform_feedback2") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ caps->maxTransformFeedbackInterleavedComponents = QuerySingleGLInt(functions, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
+ caps->maxTransformFeedbackSeparateAttributes = QuerySingleGLInt(functions, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
+ caps->maxTransformFeedbackSeparateComponents = QuerySingleGLInt(functions, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
+ }
+ else
+ {
+ // Can't support ES3 without transform feedback
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Table 6.35, Framebuffer Dependent Values
+ if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_multisample") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_multisampled_render_to_texture"))
+ {
+ caps->maxSamples = QuerySingleGLInt(functions, GL_MAX_SAMPLES);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Check if index constant sampler array indexing is supported
+ if (!functions->isAtLeastGL(gl::Version(4, 0)) &&
+ !functions->isAtLeastGLES(gl::Version(2, 0)) &&
+ !functions->hasExtension("GL_ARB_gpu_shader5"))
+ {
+ // This should also be required for ES2 but there are some driver support index constant
+ // sampler array indexing without meeting the requirements above. Don't limit their ES
+ // version as it would break WebGL for some users.
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Check if sampler objects are supported
+ if (!functions->isAtLeastGL(gl::Version(3, 3)) &&
+ !functions->hasGLExtension("GL_ARB_sampler_objects") &&
+ !functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ // Can't support ES3 without sampler objects
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Can't support ES3 without texture swizzling
+ if (!functions->isAtLeastGL(gl::Version(3, 3)) &&
+ !functions->hasGLExtension("GL_ARB_texture_swizzle") &&
+ !functions->hasGLExtension("GL_EXT_texture_swizzle") &&
+ !functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+
+ // Texture swizzling is required to work around the luminance texture format not being
+ // present in the core profile
+ if (functions->profile & GL_CONTEXT_CORE_PROFILE_BIT)
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(0, 0));
+ }
+ }
+
+ // Can't support ES3 without the GLSL packing builtins. We have a workaround for all
+ // desktop OpenGL versions starting from 3.3 with the bit packing extension.
+ if (!functions->isAtLeastGL(gl::Version(4, 2)) &&
+ !(functions->isAtLeastGL(gl::Version(3, 2)) &&
+ functions->hasGLExtension("GL_ARB_shader_bit_encoding")) &&
+ !functions->hasGLExtension("GL_ARB_shading_language_packing") &&
+ !functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // ES3 needs to support explicit layout location qualifiers, while it might be possible to
+ // fake them in our side, we currently don't support that.
+ if (!functions->isAtLeastGL(gl::Version(3, 3)) &&
+ !functions->hasGLExtension("GL_ARB_explicit_attrib_location") &&
+ !functions->isAtLeastGLES(gl::Version(3, 0)))
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_texture_multisample"))
+ {
+ caps->maxFramebufferWidth = QuerySingleGLInt(functions, GL_MAX_FRAMEBUFFER_WIDTH);
+ caps->maxFramebufferHeight = QuerySingleGLInt(functions, GL_MAX_FRAMEBUFFER_HEIGHT);
+ caps->maxFramebufferSamples = QuerySingleGLInt(functions, GL_MAX_FRAMEBUFFER_SAMPLES);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(3, 2)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_texture_multisample"))
+ {
+ caps->maxSampleMaskWords = QuerySingleGLInt(functions, GL_MAX_SAMPLE_MASK_WORDS);
+ caps->maxColorTextureSamples = QuerySingleGLInt(functions, GL_MAX_COLOR_TEXTURE_SAMPLES);
+ caps->maxDepthTextureSamples = QuerySingleGLInt(functions, GL_MAX_DEPTH_TEXTURE_SAMPLES);
+ caps->maxIntegerSamples = QuerySingleGLInt(functions, GL_MAX_INTEGER_SAMPLES);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_vertex_attrib_binding"))
+ {
+ caps->maxVertexAttribRelativeOffset =
+ QuerySingleGLInt(functions, GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET);
+ caps->maxVertexAttribBindings = QuerySingleGLInt(functions, GL_MAX_VERTEX_ATTRIB_BINDINGS);
+ caps->maxVertexAttribStride = QuerySingleGLInt(functions, GL_MAX_VERTEX_ATTRIB_STRIDE);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 2)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_shader_storage_buffer_object"))
+ {
+ caps->maxCombinedShaderOutputResources =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES);
+ caps->maxFragmentShaderStorageBlocks =
+ QuerySingleGLInt(functions, GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS);
+ caps->maxVertexShaderStorageBlocks =
+ QuerySingleGLInt(functions, GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS);
+ caps->maxShaderStorageBufferBindings =
+ QuerySingleGLInt(functions, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
+ caps->maxShaderStorageBlockSize =
+ QuerySingleGLInt64(functions, GL_MAX_SHADER_STORAGE_BLOCK_SIZE);
+ caps->maxCombinedShaderStorageBlocks =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS);
+ caps->shaderStorageBufferOffsetAlignment =
+ QuerySingleGLInt(functions, GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_compute_shader"))
+ {
+ for (GLuint index = 0u; index < 3u; ++index)
+ {
+ caps->maxComputeWorkGroupCount[index] =
+ QuerySingleIndexGLInt(functions, GL_MAX_COMPUTE_WORK_GROUP_COUNT, index);
+
+ caps->maxComputeWorkGroupSize[index] =
+ QuerySingleIndexGLInt(functions, GL_MAX_COMPUTE_WORK_GROUP_SIZE, index);
+ }
+ caps->maxComputeWorkGroupInvocations =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS);
+ caps->maxComputeUniformBlocks = QuerySingleGLInt(functions, GL_MAX_COMPUTE_UNIFORM_BLOCKS);
+ caps->maxComputeTextureImageUnits =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS);
+ caps->maxComputeSharedMemorySize =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
+ caps->maxComputeUniformComponents =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_UNIFORM_COMPONENTS);
+ caps->maxComputeAtomicCounterBuffers =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS);
+ caps->maxComputeAtomicCounters =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_ATOMIC_COUNTERS);
+ caps->maxComputeImageUniforms = QuerySingleGLInt(functions, GL_MAX_COMPUTE_IMAGE_UNIFORMS);
+ caps->maxCombinedComputeUniformComponents =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS);
+ caps->maxComputeShaderStorageBlocks =
+ QuerySingleGLInt(functions, GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_explicit_uniform_location"))
+ {
+ caps->maxUniformLocations = QuerySingleGLInt(functions, GL_MAX_UNIFORM_LOCATIONS);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 0)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_texture_gather"))
+ {
+ caps->minProgramTextureGatherOffset =
+ QuerySingleGLInt(functions, GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET);
+ caps->maxProgramTextureGatherOffset =
+ QuerySingleGLInt(functions, GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 2)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_shader_image_load_store"))
+ {
+ caps->maxVertexImageUniforms = QuerySingleGLInt(functions, GL_MAX_VERTEX_IMAGE_UNIFORMS);
+ caps->maxFragmentImageUniforms =
+ QuerySingleGLInt(functions, GL_MAX_FRAGMENT_IMAGE_UNIFORMS);
+ caps->maxImageUnits = QuerySingleGLInt(functions, GL_MAX_IMAGE_UNITS);
+ caps->maxCombinedImageUniforms =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_IMAGE_UNIFORMS);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ if (functions->isAtLeastGL(gl::Version(4, 2)) || functions->isAtLeastGLES(gl::Version(3, 1)) ||
+ functions->hasGLExtension("GL_ARB_shader_atomic_counters"))
+ {
+ caps->maxVertexAtomicCounterBuffers =
+ QuerySingleGLInt(functions, GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS);
+ caps->maxVertexAtomicCounters = QuerySingleGLInt(functions, GL_MAX_VERTEX_ATOMIC_COUNTERS);
+ caps->maxFragmentAtomicCounterBuffers =
+ QuerySingleGLInt(functions, GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS);
+ caps->maxFragmentAtomicCounters =
+ QuerySingleGLInt(functions, GL_MAX_FRAGMENT_ATOMIC_COUNTERS);
+ caps->maxAtomicCounterBufferBindings =
+ QuerySingleGLInt(functions, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS);
+ caps->maxAtomicCounterBufferSize =
+ QuerySingleGLInt(functions, GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE);
+ caps->maxCombinedAtomicCounterBuffers =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS);
+ caps->maxCombinedAtomicCounters =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_ATOMIC_COUNTERS);
+ }
+ else
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(3, 0));
+ }
+
+ // TODO(geofflang): The gl-uniform-arrays WebGL conformance test struggles to complete on time
+ // if the max uniform vectors is too large. Artificially limit the maximum until the test is
+ // updated.
+ caps->maxVertexUniformVectors = std::min(1024u, caps->maxVertexUniformVectors);
+ caps->maxVertexUniformComponents =
+ std::min(caps->maxVertexUniformVectors * 4, caps->maxVertexUniformComponents);
+ caps->maxFragmentUniformVectors = std::min(1024u, caps->maxFragmentUniformVectors);
+ caps->maxFragmentUniformComponents =
+ std::min(caps->maxFragmentUniformVectors * 4, caps->maxFragmentUniformComponents);
+
+ // If it is not possible to support reading buffer data back, a shadow copy of the buffers must
+ // be held. This disallows writing to buffers indirectly through transform feedback, thus
+ // disallowing ES3.
+ if (!CanMapBufferForRead(functions))
+ {
+ LimitVersion(maxSupportedESVersion, gl::Version(2, 0));
+ }
+
+ // Extension support
+ extensions->setTextureExtensionSupport(*textureCapsMap);
+ extensions->elementIndexUint = functions->standard == STANDARD_GL_DESKTOP ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_element_index_uint");
+ extensions->getProgramBinary = caps->programBinaryFormats.size() > 0;
+ extensions->readFormatBGRA = functions->isAtLeastGL(gl::Version(1, 2)) || functions->hasGLExtension("GL_EXT_bgra") ||
+ functions->hasGLESExtension("GL_EXT_read_format_bgra");
+ extensions->mapBuffer = functions->isAtLeastGL(gl::Version(1, 5)) ||
+ functions->hasGLESExtension("GL_OES_mapbuffer");
+ extensions->mapBufferRange = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_map_buffer_range") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_map_buffer_range");
+ extensions->textureNPOT = functions->standard == STANDARD_GL_DESKTOP ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_texture_npot");
+ extensions->drawBuffers = functions->isAtLeastGL(gl::Version(2, 0)) || functions->hasGLExtension("ARB_draw_buffers") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_draw_buffers");
+ extensions->textureStorage = true;
+ extensions->textureFilterAnisotropic = functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") || functions->hasGLESExtension("GL_EXT_texture_filter_anisotropic");
+ extensions->occlusionQueryBoolean =
+ functions->isAtLeastGL(gl::Version(1, 5)) ||
+ functions->hasGLExtension("GL_ARB_occlusion_query2") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) ||
+ functions->hasGLESExtension("GL_EXT_occlusion_query_boolean");
+ extensions->maxTextureAnisotropy = extensions->textureFilterAnisotropic ? QuerySingleGLFloat(functions, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0.0f;
+ extensions->fence = functions->hasGLExtension("GL_NV_fence") || functions->hasGLESExtension("GL_NV_fence");
+ extensions->blendMinMax = functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLExtension("GL_EXT_blend_minmax") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_blend_minmax");
+ extensions->framebufferBlit = (functions->blitFramebuffer != nullptr);
+ extensions->framebufferMultisample = caps->maxSamples > 0;
+ extensions->standardDerivatives = functions->isAtLeastGL(gl::Version(2, 0)) || functions->hasGLExtension("GL_ARB_fragment_shader") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_standard_derivatives");
+ extensions->shaderTextureLOD = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_shader_texture_lod") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_shader_texture_lod");
+ extensions->fragDepth = functions->standard == STANDARD_GL_DESKTOP ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_frag_depth");
+ extensions->fboRenderMipmap = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_object") ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_fbo_render_mipmap");
+ extensions->instancedArrays = functions->isAtLeastGL(gl::Version(3, 1)) ||
+ (functions->hasGLExtension("GL_ARB_instanced_arrays") &&
+ (functions->hasGLExtension("GL_ARB_draw_instanced") ||
+ functions->hasGLExtension("GL_EXT_draw_instanced"))) ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) ||
+ functions->hasGLESExtension("GL_EXT_instanced_arrays");
+ extensions->unpackSubimage = functions->standard == STANDARD_GL_DESKTOP ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) ||
+ functions->hasGLESExtension("GL_EXT_unpack_subimage");
+ extensions->packSubimage = functions->standard == STANDARD_GL_DESKTOP ||
+ functions->isAtLeastGLES(gl::Version(3, 0)) ||
+ functions->hasGLESExtension("GL_NV_pack_subimage");
+ extensions->debugMarker =
+ functions->isAtLeastGL(gl::Version(4, 3)) || functions->hasGLExtension("GL_KHR_debug") ||
+ functions->isAtLeastGLES(gl::Version(3, 2)) || functions->hasGLESExtension("GL_KHR_debug");
+ if (functions->isAtLeastGL(gl::Version(3, 3)) ||
+ functions->hasGLExtension("GL_ARB_timer_query") ||
+ functions->hasGLESExtension("GL_EXT_disjoint_timer_query"))
+ {
+ extensions->disjointTimerQuery = true;
+ extensions->queryCounterBitsTimeElapsed =
+ QueryQueryValue(functions, GL_TIME_ELAPSED, GL_QUERY_COUNTER_BITS);
+ extensions->queryCounterBitsTimestamp =
+ QueryQueryValue(functions, GL_TIMESTAMP, GL_QUERY_COUNTER_BITS);
+ }
+
+ // the EXT_multisample_compatibility is written against ES3.1 but can apply
+ // to earlier versions so therefore we're only checking for the extension string
+ // and not the specific GLES version.
+ extensions->multisampleCompatibility = functions->isAtLeastGL(gl::Version(1, 3)) ||
+ functions->hasGLESExtension("GL_EXT_multisample_compatibility");
+
+ extensions->framebufferMixedSamples =
+ functions->hasGLExtension("GL_NV_framebuffer_mixed_samples") ||
+ functions->hasGLESExtension("GL_NV_framebuffer_mixed_samples");
+
+ extensions->robustness = functions->isAtLeastGL(gl::Version(4, 5)) ||
+ functions->hasGLExtension("GL_KHR_robustness") ||
+ functions->hasGLExtension("GL_ARB_robustness") ||
+ functions->isAtLeastGLES(gl::Version(3, 2)) ||
+ functions->hasGLESExtension("GL_KHR_robustness") ||
+ functions->hasGLESExtension("GL_EXT_robustness");
+
+ // NV_path_rendering
+ // We also need interface query which is available in
+ // >= 4.3 core or ARB_interface_query or >= GLES 3.1
+ const bool canEnableGLPathRendering =
+ functions->hasGLExtension("GL_NV_path_rendering") &&
+ (functions->hasGLExtension("GL_ARB_program_interface_query") ||
+ functions->isAtLeastGL(gl::Version(4, 3)));
+
+ const bool canEnableESPathRendering =
+ functions->hasGLESExtension("GL_NV_path_rendering") &&
+ functions->isAtLeastGLES(gl::Version(3, 1));
+
+ extensions->pathRendering = canEnableGLPathRendering || canEnableESPathRendering;
+}
+
+void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds)
+{
+ VendorID vendor = GetVendorID(functions);
+
+ // Don't use 1-bit alpha formats on desktop GL with AMD or Intel drivers.
+ workarounds->avoid1BitAlphaTextureFormats =
+ functions->standard == STANDARD_GL_DESKTOP &&
+ (vendor == VENDOR_ID_AMD || vendor == VENDOR_ID_INTEL);
+
+ workarounds->rgba4IsNotSupportedForColorRendering =
+ functions->standard == STANDARD_GL_DESKTOP && vendor == VENDOR_ID_INTEL;
+
+ workarounds->emulateAbsIntFunction = vendor == VENDOR_ID_INTEL;
+
+ workarounds->addAndTrueToLoopCondition = vendor == VENDOR_ID_INTEL;
+
+ workarounds->emulateIsnanFloat = vendor == VENDOR_ID_INTEL;
+
+ workarounds->doesSRGBClearsOnLinearFramebufferAttachments =
+ functions->standard == STANDARD_GL_DESKTOP &&
+ (vendor == VENDOR_ID_INTEL || vendor == VENDOR_ID_AMD);
+
+#if defined(ANGLE_PLATFORM_APPLE)
+ workarounds->doWhileGLSLCausesGPUHang = true;
+ workarounds->useUnusedBlocksWithStandardOrSharedLayout = true;
+#endif
+
+ workarounds->finishDoesNotCauseQueriesToBeAvailable =
+ functions->standard == STANDARD_GL_DESKTOP && vendor == VENDOR_ID_NVIDIA;
+
+ // TODO(cwallez): Disable this workaround for MacOSX versions 10.9 or later.
+ workarounds->alwaysCallUseProgramAfterLink = true;
+
+ workarounds->unpackOverlappingRowsSeparatelyUnpackBuffer = vendor == VENDOR_ID_NVIDIA;
+ workarounds->packOverlappingRowsSeparatelyPackBuffer = vendor == VENDOR_ID_NVIDIA;
+
+ workarounds->initializeCurrentVertexAttributes = vendor == VENDOR_ID_NVIDIA;
+
+#if defined(ANGLE_PLATFORM_APPLE)
+ workarounds->unpackLastRowSeparatelyForPaddingInclusion = true;
+ workarounds->packLastRowSeparatelyForPaddingInclusion = true;
+#else
+ workarounds->unpackLastRowSeparatelyForPaddingInclusion = vendor == VENDOR_ID_NVIDIA;
+ workarounds->packLastRowSeparatelyForPaddingInclusion = vendor == VENDOR_ID_NVIDIA;
+#endif
+}
+
+}
+
+bool CanMapBufferForRead(const FunctionsGL *functions)
+{
+ return (functions->mapBufferRange != nullptr) ||
+ (functions->mapBuffer != nullptr && functions->standard == STANDARD_GL_DESKTOP);
+}
+
+uint8_t *MapBufferRangeWithFallback(const FunctionsGL *functions,
+ GLenum target,
+ size_t offset,
+ size_t length,
+ GLbitfield access)
+{
+ if (functions->mapBufferRange != nullptr)
+ {
+ return reinterpret_cast<uint8_t *>(
+ functions->mapBufferRange(target, offset, length, access));
+ }
+ else if (functions->mapBuffer != nullptr &&
+ (functions->standard == STANDARD_GL_DESKTOP || access == GL_MAP_WRITE_BIT))
+ {
+ // Only the read and write bits are supported
+ ASSERT((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) != 0);
+
+ GLenum accessEnum = 0;
+ if (access == (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))
+ {
+ accessEnum = GL_READ_WRITE;
+ }
+ else if (access == GL_MAP_READ_BIT)
+ {
+ accessEnum = GL_READ_ONLY;
+ }
+ else if (access == GL_MAP_WRITE_BIT)
+ {
+ accessEnum = GL_WRITE_ONLY;
+ }
+ else
+ {
+ UNREACHABLE();
+ return nullptr;
+ }
+
+ return reinterpret_cast<uint8_t *>(functions->mapBuffer(target, accessEnum)) + offset;
+ }
+ else
+ {
+ // No options available
+ UNREACHABLE();
+ return nullptr;
+ }
+}
+
+gl::ErrorOrResult<bool> ShouldApplyLastRowPaddingWorkaround(const gl::Extents &size,
+ const gl::PixelStoreStateBase &state,
+ GLenum format,
+ GLenum type,
+ bool is3D,
+ const void *pixels)
+{
+ if (state.pixelBuffer.get() == nullptr)
+ {
+ return false;
+ }
+
+ // We are using an pack or unpack buffer, compute what the driver thinks is going to be the
+ // last byte read or written. If it is past the end of the buffer, we will need to use the
+ // workaround otherwise the driver will generate INVALID_OPERATION and not do the operation.
+ CheckedNumeric<size_t> checkedEndByte;
+ CheckedNumeric<size_t> pixelBytes;
+ size_t rowPitch;
+
+ const gl::InternalFormat &glFormat =
+ gl::GetInternalFormatInfo(gl::GetSizedInternalFormat(format, type));
+ ANGLE_TRY_RESULT(glFormat.computePackUnpackEndByte(type, size, state, is3D), checkedEndByte);
+ ANGLE_TRY_RESULT(glFormat.computeRowPitch(type, size.width, state.alignment, state.rowLength),
+ rowPitch);
+ pixelBytes = glFormat.computePixelBytes(type);
+
+ checkedEndByte += reinterpret_cast<intptr_t>(pixels);
+
+ // At this point checkedEndByte is the actual last byte read.
+ // The driver adds an extra row padding (if any), mimic it.
+ ANGLE_TRY_CHECKED_MATH(pixelBytes);
+ if (pixelBytes.ValueOrDie() * size.width < rowPitch)
+ {
+ checkedEndByte += rowPitch - pixelBytes * size.width;
+ }
+
+ ANGLE_TRY_CHECKED_MATH(checkedEndByte);
+
+ return checkedEndByte.ValueOrDie() > static_cast<size_t>(state.pixelBuffer->getSize());
+}
+}