| // |
| // 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 "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> |
| |
| 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; |
| #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; |
| } |
| } |
| } |