// // Copyright 2016 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. // // queryutils.cpp: Utilities for querying values from GL objects #include "libANGLE/queryutils.h" #include "common/utilities.h" #include "libANGLE/Buffer.h" #include "libANGLE/Config.h" #include "libANGLE/Context.h" #include "libANGLE/Display.h" #include "libANGLE/EGLSync.h" #include "libANGLE/Fence.h" #include "libANGLE/Framebuffer.h" #include "libANGLE/GLES1State.h" #include "libANGLE/MemoryObject.h" #include "libANGLE/Program.h" #include "libANGLE/Renderbuffer.h" #include "libANGLE/Sampler.h" #include "libANGLE/Shader.h" #include "libANGLE/Surface.h" #include "libANGLE/Texture.h" #include "libANGLE/Uniform.h" #include "libANGLE/VertexAttribute.h" #include "libANGLE/queryconversions.h" namespace gl { namespace { template ColorGeneric ConvertToColor(const GLfloat *params) { if (isPureInteger) { UNREACHABLE(); return ColorGeneric(ColorI()); } else { return ColorGeneric(ColorF::fromData(params)); } } template ColorGeneric ConvertToColor(const GLint *params) { if (isPureInteger) { return ColorGeneric(ColorI(params[0], params[1], params[2], params[3])); } else { return ColorGeneric(ColorF(normalizedToFloat(params[0]), normalizedToFloat(params[1]), normalizedToFloat(params[2]), normalizedToFloat(params[3]))); } } template ColorGeneric ConvertToColor(const GLuint *params) { if (isPureInteger) { return ColorGeneric(ColorUI(params[0], params[1], params[2], params[3])); } else { UNREACHABLE(); return ColorGeneric(ColorF()); } } template void ConvertFromColor(const ColorGeneric &color, GLfloat *outParams) { if (isPureInteger) { UNREACHABLE(); } else { ASSERT(color.type == ColorGeneric::Type::Float); color.colorF.writeData(outParams); } } template void ConvertFromColor(const ColorGeneric &color, GLint *outParams) { if (isPureInteger) { ASSERT(color.type == ColorGeneric::Type::Int); outParams[0] = color.colorI.red; outParams[1] = color.colorI.green; outParams[2] = color.colorI.blue; outParams[3] = color.colorI.alpha; } else { ASSERT(color.type == ColorGeneric::Type::Float); outParams[0] = floatToNormalized(color.colorF.red); outParams[1] = floatToNormalized(color.colorF.green); outParams[2] = floatToNormalized(color.colorF.blue); outParams[3] = floatToNormalized(color.colorF.alpha); } } template void ConvertFromColor(const ColorGeneric &color, GLuint *outParams) { if (isPureInteger) { ASSERT(color.type == ColorGeneric::Type::UInt); outParams[0] = color.colorUI.red; outParams[1] = color.colorUI.green; outParams[2] = color.colorUI.blue; outParams[3] = color.colorUI.alpha; } else { UNREACHABLE(); } } template void QueryTexLevelParameterBase(const Texture *texture, TextureTarget target, GLint level, GLenum pname, ParamType *params) { ASSERT(texture != nullptr); const InternalFormat *info = texture->getTextureState().getImageDesc(target, level).format.info; switch (pname) { case GL_TEXTURE_RED_TYPE: *params = CastFromGLintStateValue( pname, info->redBits ? info->componentType : GL_NONE); break; case GL_TEXTURE_GREEN_TYPE: *params = CastFromGLintStateValue( pname, info->greenBits ? info->componentType : GL_NONE); break; case GL_TEXTURE_BLUE_TYPE: *params = CastFromGLintStateValue( pname, info->blueBits ? info->componentType : GL_NONE); break; case GL_TEXTURE_ALPHA_TYPE: *params = CastFromGLintStateValue( pname, info->alphaBits ? info->componentType : GL_NONE); break; case GL_TEXTURE_DEPTH_TYPE: *params = CastFromGLintStateValue( pname, info->depthBits ? info->componentType : GL_NONE); break; case GL_TEXTURE_RED_SIZE: *params = CastFromGLintStateValue(pname, info->redBits); break; case GL_TEXTURE_GREEN_SIZE: *params = CastFromGLintStateValue(pname, info->greenBits); break; case GL_TEXTURE_BLUE_SIZE: *params = CastFromGLintStateValue(pname, info->blueBits); break; case GL_TEXTURE_ALPHA_SIZE: *params = CastFromGLintStateValue(pname, info->alphaBits); break; case GL_TEXTURE_DEPTH_SIZE: *params = CastFromGLintStateValue(pname, info->depthBits); break; case GL_TEXTURE_STENCIL_SIZE: *params = CastFromGLintStateValue(pname, info->stencilBits); break; case GL_TEXTURE_SHARED_SIZE: *params = CastFromGLintStateValue(pname, info->sharedBits); break; case GL_TEXTURE_INTERNAL_FORMAT: *params = CastFromGLintStateValue( pname, info->internalFormat ? info->internalFormat : GL_RGBA); break; case GL_TEXTURE_WIDTH: *params = CastFromGLintStateValue( pname, static_cast(texture->getWidth(target, level))); break; case GL_TEXTURE_HEIGHT: *params = CastFromGLintStateValue( pname, static_cast(texture->getHeight(target, level))); break; case GL_TEXTURE_DEPTH: *params = CastFromGLintStateValue( pname, static_cast(texture->getDepth(target, level))); break; case GL_TEXTURE_SAMPLES: *params = CastFromStateValue(pname, texture->getSamples(target, level)); break; case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS: *params = CastFromStateValue( pname, static_cast(texture->getFixedSampleLocations(target, level))); break; case GL_TEXTURE_COMPRESSED: *params = CastFromStateValue(pname, static_cast(info->compressed)); break; case GL_MEMORY_SIZE_ANGLE: *params = CastFromStateValue(pname, texture->getLevelMemorySize(target, level)); break; case GL_RESOURCE_INITIALIZED_ANGLE: *params = CastFromGLintStateValue( pname, texture->initState(ImageIndex::MakeFromTarget(target, level)) == InitState::Initialized); break; case GL_TEXTURE_BUFFER_DATA_STORE_BINDING: *params = CastFromStateValue( pname, static_cast(texture->getBuffer().id().value)); break; case GL_TEXTURE_BUFFER_OFFSET: *params = CastFromStateValue( pname, static_cast(texture->getBuffer().getOffset())); break; case GL_TEXTURE_BUFFER_SIZE: *params = CastFromStateValue( pname, static_cast(GetBoundBufferAvailableSize(texture->getBuffer()))); break; default: UNREACHABLE(); break; } } // This function is needed to handle fixed_point data. // It can be used when some pname need special conversion from int/float/bool to fixed_point. template QueryT CastFromSpecialValue(GLenum pname, const ParamType param) { if (isGLfixed) { return static_cast(ConvertFloatToFixed(CastFromStateValue(pname, param))); } else { return CastFromStateValue(pname, param); } } template void QueryTexParameterBase(const Context *context, const Texture *texture, GLenum pname, ParamType *params) { ASSERT(texture != nullptr); switch (pname) { case GL_TEXTURE_MAG_FILTER: *params = CastFromGLintStateValue(pname, texture->getMagFilter()); break; case GL_TEXTURE_MIN_FILTER: *params = CastFromGLintStateValue(pname, texture->getMinFilter()); break; case GL_TEXTURE_WRAP_S: *params = CastFromGLintStateValue(pname, texture->getWrapS()); break; case GL_TEXTURE_WRAP_T: *params = CastFromGLintStateValue(pname, texture->getWrapT()); break; case GL_TEXTURE_WRAP_R: *params = CastFromGLintStateValue(pname, texture->getWrapR()); break; case GL_TEXTURE_IMMUTABLE_FORMAT: *params = CastFromGLintStateValue(pname, texture->getImmutableFormat()); break; case GL_TEXTURE_IMMUTABLE_LEVELS: *params = CastFromGLintStateValue(pname, texture->getImmutableLevels()); break; case GL_TEXTURE_USAGE_ANGLE: *params = CastFromGLintStateValue(pname, texture->getUsage()); break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: *params = CastFromSpecialValue(pname, texture->getMaxAnisotropy()); break; case GL_TEXTURE_SWIZZLE_R: *params = CastFromGLintStateValue(pname, texture->getSwizzleRed()); break; case GL_TEXTURE_SWIZZLE_G: *params = CastFromGLintStateValue(pname, texture->getSwizzleGreen()); break; case GL_TEXTURE_SWIZZLE_B: *params = CastFromGLintStateValue(pname, texture->getSwizzleBlue()); break; case GL_TEXTURE_SWIZZLE_A: *params = CastFromGLintStateValue(pname, texture->getSwizzleAlpha()); break; case GL_TEXTURE_BASE_LEVEL: *params = CastFromGLintStateValue(pname, texture->getBaseLevel()); break; case GL_TEXTURE_MAX_LEVEL: *params = CastFromGLintStateValue(pname, texture->getMaxLevel()); break; case GL_TEXTURE_MIN_LOD: *params = CastFromSpecialValue(pname, texture->getMinLod()); break; case GL_TEXTURE_MAX_LOD: *params = CastFromSpecialValue(pname, texture->getMaxLod()); break; case GL_TEXTURE_COMPARE_MODE: *params = CastFromGLintStateValue(pname, texture->getCompareMode()); break; case GL_TEXTURE_COMPARE_FUNC: *params = CastFromGLintStateValue(pname, texture->getCompareFunc()); break; case GL_TEXTURE_SRGB_DECODE_EXT: *params = CastFromGLintStateValue(pname, texture->getSRGBDecode()); break; case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT: *params = CastFromGLintStateValue(pname, texture->getSRGBOverride()); break; case GL_DEPTH_STENCIL_TEXTURE_MODE: *params = CastFromGLintStateValue(pname, texture->getDepthStencilTextureMode()); break; case GL_TEXTURE_CROP_RECT_OES: { const gl::Rectangle &crop = texture->getCrop(); params[0] = CastFromSpecialValue(pname, crop.x); params[1] = CastFromSpecialValue(pname, crop.y); params[2] = CastFromSpecialValue(pname, crop.width); params[3] = CastFromSpecialValue(pname, crop.height); break; } case GL_GENERATE_MIPMAP: *params = CastFromGLintStateValue(pname, texture->getGenerateMipmapHint()); break; case GL_MEMORY_SIZE_ANGLE: *params = CastFromSpecialValue(pname, texture->getMemorySize()); break; case GL_TEXTURE_BORDER_COLOR: ConvertFromColor(texture->getBorderColor(), params); break; case GL_TEXTURE_NATIVE_ID_ANGLE: *params = CastFromSpecialValue(pname, texture->getNativeID()); break; case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = CastFromGLintStateValue( pname, texture->getImplementationColorReadFormat(context)); break; case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = CastFromGLintStateValue( pname, texture->getImplementationColorReadType(context)); break; case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: *params = CastFromGLintStateValue(pname, GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE); break; case GL_RESOURCE_INITIALIZED_ANGLE: *params = CastFromGLintStateValue( pname, texture->initState() == InitState::Initialized); break; case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES: *params = CastFromGLintStateValue( pname, texture->getRequiredTextureImageUnits(context)); break; default: UNREACHABLE(); break; } } // this function is needed to handle OES_FIXED_POINT. // Some pname values can take in GLfixed values and may need to be converted template ReturnType ConvertTexParam(GLenum pname, const ParamType param) { if (isGLfixed) { return CastQueryValueTo(pname, ConvertFixedToFloat(static_cast(param))); } else { return CastQueryValueTo(pname, param); } } template void SetTexParameterBase(Context *context, Texture *texture, GLenum pname, const ParamType *params) { ASSERT(texture != nullptr); switch (pname) { case GL_TEXTURE_WRAP_S: texture->setWrapS(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_WRAP_T: texture->setWrapT(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_WRAP_R: texture->setWrapR(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MIN_FILTER: texture->setMinFilter(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MAG_FILTER: texture->setMagFilter(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->setMaxAnisotropy(context, ConvertTexParam(pname, params[0])); break; case GL_TEXTURE_COMPARE_MODE: texture->setCompareMode(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_COMPARE_FUNC: texture->setCompareFunc(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_SWIZZLE_R: texture->setSwizzleRed(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_SWIZZLE_G: texture->setSwizzleGreen(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_SWIZZLE_B: texture->setSwizzleBlue(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_SWIZZLE_A: texture->setSwizzleAlpha(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_BASE_LEVEL: { (void)(texture->setBaseLevel( context, clampCast(CastQueryValueTo(pname, params[0])))); break; } case GL_TEXTURE_MAX_LEVEL: texture->setMaxLevel(context, clampCast(CastQueryValueTo(pname, params[0]))); break; case GL_TEXTURE_MIN_LOD: texture->setMinLod(context, CastQueryValueTo(pname, params[0])); break; case GL_TEXTURE_MAX_LOD: texture->setMaxLod(context, CastQueryValueTo(pname, params[0])); break; case GL_DEPTH_STENCIL_TEXTURE_MODE: texture->setDepthStencilTextureMode(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_SRGB_DECODE_EXT: texture->setSRGBDecode(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT: texture->setSRGBOverride(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_CROP_RECT_OES: texture->setCrop(gl::Rectangle(ConvertTexParam(pname, params[0]), ConvertTexParam(pname, params[1]), ConvertTexParam(pname, params[2]), ConvertTexParam(pname, params[3]))); break; case GL_GENERATE_MIPMAP: texture->setGenerateMipmapHint(ConvertToGLenum(params[0])); break; case GL_TEXTURE_BORDER_COLOR: texture->setBorderColor(context, ConvertToColor(params)); break; case GL_RESOURCE_INITIALIZED_ANGLE: texture->setInitState(ConvertToBool(params[0]) ? InitState::Initialized : InitState::MayNeedInit); break; default: UNREACHABLE(); break; } } template void QuerySamplerParameterBase(const Sampler *sampler, GLenum pname, ParamType *params) { switch (pname) { case GL_TEXTURE_MIN_FILTER: *params = CastFromGLintStateValue(pname, sampler->getMinFilter()); break; case GL_TEXTURE_MAG_FILTER: *params = CastFromGLintStateValue(pname, sampler->getMagFilter()); break; case GL_TEXTURE_WRAP_S: *params = CastFromGLintStateValue(pname, sampler->getWrapS()); break; case GL_TEXTURE_WRAP_T: *params = CastFromGLintStateValue(pname, sampler->getWrapT()); break; case GL_TEXTURE_WRAP_R: *params = CastFromGLintStateValue(pname, sampler->getWrapR()); break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: *params = CastFromStateValue(pname, sampler->getMaxAnisotropy()); break; case GL_TEXTURE_MIN_LOD: *params = CastFromStateValue(pname, sampler->getMinLod()); break; case GL_TEXTURE_MAX_LOD: *params = CastFromStateValue(pname, sampler->getMaxLod()); break; case GL_TEXTURE_COMPARE_MODE: *params = CastFromGLintStateValue(pname, sampler->getCompareMode()); break; case GL_TEXTURE_COMPARE_FUNC: *params = CastFromGLintStateValue(pname, sampler->getCompareFunc()); break; case GL_TEXTURE_SRGB_DECODE_EXT: *params = CastFromGLintStateValue(pname, sampler->getSRGBDecode()); break; case GL_TEXTURE_BORDER_COLOR: ConvertFromColor(sampler->getBorderColor(), params); break; default: UNREACHABLE(); break; } } template void SetSamplerParameterBase(Context *context, Sampler *sampler, GLenum pname, const ParamType *params) { switch (pname) { case GL_TEXTURE_WRAP_S: sampler->setWrapS(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_WRAP_T: sampler->setWrapT(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_WRAP_R: sampler->setWrapR(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MIN_FILTER: sampler->setMinFilter(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MAG_FILTER: sampler->setMagFilter(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MAX_ANISOTROPY_EXT: sampler->setMaxAnisotropy(context, CastQueryValueTo(pname, params[0])); break; case GL_TEXTURE_COMPARE_MODE: sampler->setCompareMode(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_COMPARE_FUNC: sampler->setCompareFunc(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_MIN_LOD: sampler->setMinLod(context, CastQueryValueTo(pname, params[0])); break; case GL_TEXTURE_MAX_LOD: sampler->setMaxLod(context, CastQueryValueTo(pname, params[0])); break; case GL_TEXTURE_SRGB_DECODE_EXT: sampler->setSRGBDecode(context, ConvertToGLenum(pname, params[0])); break; case GL_TEXTURE_BORDER_COLOR: sampler->setBorderColor(context, ConvertToColor(params)); break; default: UNREACHABLE(); break; } sampler->onStateChange(angle::SubjectMessage::ContentsChanged); } // Warning: you should ensure binding really matches attrib.bindingIndex before using this function. template void QueryVertexAttribBase(const VertexAttribute &attrib, const VertexBinding &binding, const CurrentDataType (¤tValueData)[CurrentValueCount], GLenum pname, ParamType *params) { switch (pname) { case GL_CURRENT_VERTEX_ATTRIB: for (size_t i = 0; i < CurrentValueCount; ++i) { params[i] = CastFromStateValue(pname, currentValueData[i]); } break; case GL_VERTEX_ATTRIB_ARRAY_ENABLED: *params = CastFromStateValue(pname, static_cast(attrib.enabled)); break; case GL_VERTEX_ATTRIB_ARRAY_SIZE: *params = CastFromGLintStateValue(pname, attrib.format->channelCount); break; case GL_VERTEX_ATTRIB_ARRAY_STRIDE: *params = CastFromGLintStateValue(pname, attrib.vertexAttribArrayStride); break; case GL_VERTEX_ATTRIB_ARRAY_TYPE: *params = CastFromGLintStateValue( pname, gl::ToGLenum(attrib.format->vertexAttribType)); break; case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: *params = CastFromStateValue(pname, static_cast(attrib.format->isNorm())); break; case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: *params = CastFromGLintStateValue(pname, binding.getBuffer().id().value); break; case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: *params = CastFromStateValue(pname, binding.getDivisor()); break; case GL_VERTEX_ATTRIB_ARRAY_INTEGER: *params = CastFromGLintStateValue(pname, attrib.format->isPureInt()); break; case GL_VERTEX_ATTRIB_BINDING: *params = CastFromGLintStateValue(pname, attrib.bindingIndex); break; case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: *params = CastFromGLintStateValue(pname, attrib.relativeOffset); break; default: UNREACHABLE(); break; } } template void QueryBufferParameterBase(const Buffer *buffer, GLenum pname, ParamType *params) { ASSERT(buffer != nullptr); switch (pname) { case GL_BUFFER_USAGE: *params = CastFromGLintStateValue(pname, ToGLenum(buffer->getUsage())); break; case GL_BUFFER_SIZE: *params = CastFromStateValue(pname, buffer->getSize()); break; case GL_BUFFER_ACCESS_FLAGS: *params = CastFromGLintStateValue(pname, buffer->getAccessFlags()); break; case GL_BUFFER_ACCESS_OES: *params = CastFromGLintStateValue(pname, buffer->getAccess()); break; case GL_BUFFER_MAPPED: *params = CastFromStateValue(pname, buffer->isMapped()); break; case GL_BUFFER_MAP_OFFSET: *params = CastFromStateValue(pname, buffer->getMapOffset()); break; case GL_BUFFER_MAP_LENGTH: *params = CastFromStateValue(pname, buffer->getMapLength()); break; case GL_MEMORY_SIZE_ANGLE: *params = CastFromStateValue(pname, buffer->getMemorySize()); break; case GL_BUFFER_IMMUTABLE_STORAGE_EXT: *params = CastFromStateValue(pname, buffer->isImmutable()); break; case GL_BUFFER_STORAGE_FLAGS_EXT: *params = CastFromGLintStateValue(pname, buffer->getStorageExtUsageFlags()); break; case GL_RESOURCE_INITIALIZED_ANGLE: *params = CastFromStateValue( pname, ConvertToGLBoolean(buffer->initState() == InitState::Initialized)); break; default: UNREACHABLE(); break; } } GLint GetCommonVariableProperty(const sh::ShaderVariable &var, GLenum prop) { switch (prop) { case GL_TYPE: return clampCast(var.type); case GL_ARRAY_SIZE: // Queryable variables are guaranteed not to be arrays of arrays or arrays of structs, // see GLES 3.1 spec section 7.3.1.1 page 77. return clampCast(var.getBasicTypeElementCount()); case GL_NAME_LENGTH: // ES31 spec p84: This counts the terminating null char. return clampCast(var.name.size() + 1u); default: UNREACHABLE(); return GL_INVALID_VALUE; } } GLint GetInputResourceProperty(const Program *program, GLuint index, GLenum prop) { const sh::ShaderVariable &variable = program->getInputResource(index); switch (prop) { case GL_TYPE: case GL_ARRAY_SIZE: return GetCommonVariableProperty(variable, prop); case GL_NAME_LENGTH: return clampCast(program->getInputResourceName(index).size() + 1u); case GL_LOCATION: return variable.isBuiltIn() ? GL_INVALID_INDEX : variable.location; // The query is targeted at the set of active input variables used by the first shader stage // of program. If program contains multiple shader stages then input variables from any // stage other than the first will not be enumerated. Since we found the variable to get // this far, we know it exists in the first attached shader stage. case GL_REFERENCED_BY_VERTEX_SHADER: return program->getState().getFirstAttachedShaderStageType() == ShaderType::Vertex; case GL_REFERENCED_BY_FRAGMENT_SHADER: return program->getState().getFirstAttachedShaderStageType() == ShaderType::Fragment; case GL_REFERENCED_BY_COMPUTE_SHADER: return program->getState().getFirstAttachedShaderStageType() == ShaderType::Compute; case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: return program->getState().getFirstAttachedShaderStageType() == ShaderType::Geometry; case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT: return program->getState().getFirstAttachedShaderStageType() == ShaderType::TessControl; case GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT: return program->getState().getFirstAttachedShaderStageType() == ShaderType::TessEvaluation; case GL_IS_PER_PATCH_EXT: return variable.isPatch; default: UNREACHABLE(); return GL_INVALID_VALUE; } } GLint GetOutputResourceProperty(const Program *program, GLuint index, const GLenum prop) { const sh::ShaderVariable &outputVariable = program->getOutputResource(index); switch (prop) { case GL_TYPE: case GL_ARRAY_SIZE: return GetCommonVariableProperty(outputVariable, prop); case GL_NAME_LENGTH: return clampCast(program->getOutputResourceName(index).size() + 1u); case GL_LOCATION: return outputVariable.location; case GL_LOCATION_INDEX_EXT: // EXT_blend_func_extended if (program->getState().getLastAttachedShaderStageType() == gl::ShaderType::Fragment) { return program->getFragDataIndex(outputVariable.name); } return GL_INVALID_INDEX; // The set of active user-defined outputs from the final shader stage in this program. If // the final stage is a Fragment Shader, then this represents the fragment outputs that get // written to individual color buffers. If the program only contains a Compute Shader, then // there are no user-defined outputs. case GL_REFERENCED_BY_VERTEX_SHADER: return program->getState().getLastAttachedShaderStageType() == ShaderType::Vertex; case GL_REFERENCED_BY_FRAGMENT_SHADER: return program->getState().getLastAttachedShaderStageType() == ShaderType::Fragment; case GL_REFERENCED_BY_COMPUTE_SHADER: return program->getState().getLastAttachedShaderStageType() == ShaderType::Compute; case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: return program->getState().getLastAttachedShaderStageType() == ShaderType::Geometry; case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT: return program->getState().getLastAttachedShaderStageType() == ShaderType::TessControl; case GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT: return program->getState().getLastAttachedShaderStageType() == ShaderType::TessEvaluation; case GL_IS_PER_PATCH_EXT: return outputVariable.isPatch; default: UNREACHABLE(); return GL_INVALID_VALUE; } } GLint GetTransformFeedbackVaryingResourceProperty(const Program *program, GLuint index, const GLenum prop) { const auto &tfVariable = program->getTransformFeedbackVaryingResource(index); switch (prop) { case GL_TYPE: return clampCast(tfVariable.type); case GL_ARRAY_SIZE: return clampCast(tfVariable.size()); case GL_NAME_LENGTH: return clampCast(tfVariable.nameWithArrayIndex().size() + 1); default: UNREACHABLE(); return GL_INVALID_VALUE; } } GLint QueryProgramInterfaceActiveResources(const Program *program, GLenum programInterface) { switch (programInterface) { case GL_PROGRAM_INPUT: return clampCast(program->getState().getProgramInputs().size()); case GL_PROGRAM_OUTPUT: return clampCast(program->getState().getOutputVariables().size()); case GL_UNIFORM: return clampCast(program->getState().getUniforms().size()); case GL_UNIFORM_BLOCK: return clampCast(program->getState().getUniformBlocks().size()); case GL_ATOMIC_COUNTER_BUFFER: return clampCast(program->getState().getAtomicCounterBuffers().size()); case GL_BUFFER_VARIABLE: return clampCast(program->getState().getBufferVariables().size()); case GL_SHADER_STORAGE_BLOCK: return clampCast(program->getState().getShaderStorageBlocks().size()); case GL_TRANSFORM_FEEDBACK_VARYING: return clampCast(program->getTransformFeedbackVaryingCount()); default: UNREACHABLE(); return 0; } } template GLint FindMaxSize(const std::vector &resources, M member) { GLint max = 0; for (const T &resource : resources) { max = std::max(max, clampCast((resource.*member).size())); } return max; } GLint QueryProgramInterfaceMaxNameLength(const Program *program, GLenum programInterface) { GLint maxNameLength = 0; switch (programInterface) { case GL_PROGRAM_INPUT: maxNameLength = program->getInputResourceMaxNameSize(); break; case GL_PROGRAM_OUTPUT: maxNameLength = program->getOutputResourceMaxNameSize(); break; case GL_UNIFORM: maxNameLength = FindMaxSize(program->getState().getUniforms(), &LinkedUniform::name); break; case GL_UNIFORM_BLOCK: return program->getActiveUniformBlockMaxNameLength(); case GL_BUFFER_VARIABLE: maxNameLength = FindMaxSize(program->getState().getBufferVariables(), &BufferVariable::name); break; case GL_SHADER_STORAGE_BLOCK: return program->getActiveShaderStorageBlockMaxNameLength(); case GL_TRANSFORM_FEEDBACK_VARYING: return clampCast(program->getTransformFeedbackVaryingMaxLength()); default: UNREACHABLE(); return 0; } // This length includes an extra character for the null terminator. return (maxNameLength == 0 ? 0 : maxNameLength + 1); } GLint QueryProgramInterfaceMaxNumActiveVariables(const Program *program, GLenum programInterface) { switch (programInterface) { case GL_UNIFORM_BLOCK: return FindMaxSize(program->getState().getUniformBlocks(), &InterfaceBlock::memberIndexes); case GL_ATOMIC_COUNTER_BUFFER: return FindMaxSize(program->getState().getAtomicCounterBuffers(), &AtomicCounterBuffer::memberIndexes); case GL_SHADER_STORAGE_BLOCK: return FindMaxSize(program->getState().getShaderStorageBlocks(), &InterfaceBlock::memberIndexes); default: UNREACHABLE(); return 0; } } GLenum GetUniformPropertyEnum(GLenum prop) { switch (prop) { case GL_UNIFORM_TYPE: return GL_TYPE; case GL_UNIFORM_SIZE: return GL_ARRAY_SIZE; case GL_UNIFORM_NAME_LENGTH: return GL_NAME_LENGTH; case GL_UNIFORM_BLOCK_INDEX: return GL_BLOCK_INDEX; case GL_UNIFORM_OFFSET: return GL_OFFSET; case GL_UNIFORM_ARRAY_STRIDE: return GL_ARRAY_STRIDE; case GL_UNIFORM_MATRIX_STRIDE: return GL_MATRIX_STRIDE; case GL_UNIFORM_IS_ROW_MAJOR: return GL_IS_ROW_MAJOR; default: return prop; } } GLenum GetUniformBlockPropertyEnum(GLenum prop) { switch (prop) { case GL_UNIFORM_BLOCK_BINDING: return GL_BUFFER_BINDING; case GL_UNIFORM_BLOCK_DATA_SIZE: return GL_BUFFER_DATA_SIZE; case GL_UNIFORM_BLOCK_NAME_LENGTH: return GL_NAME_LENGTH; case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: return GL_NUM_ACTIVE_VARIABLES; case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: return GL_ACTIVE_VARIABLES; case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: return GL_REFERENCED_BY_VERTEX_SHADER; case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: return GL_REFERENCED_BY_FRAGMENT_SHADER; default: return prop; } } void GetShaderVariableBufferResourceProperty(const ShaderVariableBuffer &buffer, GLenum pname, GLint *params, GLsizei bufSize, GLsizei *outputPosition) { switch (pname) { case GL_BUFFER_BINDING: params[(*outputPosition)++] = buffer.binding; break; case GL_BUFFER_DATA_SIZE: params[(*outputPosition)++] = clampCast(buffer.dataSize); break; case GL_NUM_ACTIVE_VARIABLES: params[(*outputPosition)++] = buffer.numActiveVariables(); break; case GL_ACTIVE_VARIABLES: for (size_t memberIndex = 0; memberIndex < buffer.memberIndexes.size() && *outputPosition < bufSize; ++memberIndex) { params[(*outputPosition)++] = clampCast(buffer.memberIndexes[memberIndex]); } break; case GL_REFERENCED_BY_VERTEX_SHADER: params[(*outputPosition)++] = static_cast(buffer.isActive(ShaderType::Vertex)); break; case GL_REFERENCED_BY_FRAGMENT_SHADER: params[(*outputPosition)++] = static_cast(buffer.isActive(ShaderType::Fragment)); break; case GL_REFERENCED_BY_COMPUTE_SHADER: params[(*outputPosition)++] = static_cast(buffer.isActive(ShaderType::Compute)); break; case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: params[(*outputPosition)++] = static_cast(buffer.isActive(ShaderType::Geometry)); break; case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT: params[(*outputPosition)++] = static_cast(buffer.isActive(ShaderType::TessControl)); break; case GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT: params[(*outputPosition)++] = static_cast(buffer.isActive(ShaderType::TessEvaluation)); break; default: UNREACHABLE(); break; } } void GetInterfaceBlockResourceProperty(const InterfaceBlock &block, GLenum pname, GLint *params, GLsizei bufSize, GLsizei *outputPosition) { if (pname == GL_NAME_LENGTH) { params[(*outputPosition)++] = clampCast(block.nameWithArrayIndex().size() + 1); return; } GetShaderVariableBufferResourceProperty(block, pname, params, bufSize, outputPosition); } void GetUniformBlockResourceProperty(const Program *program, GLuint blockIndex, GLenum pname, GLint *params, GLsizei bufSize, GLsizei *outputPosition) { ASSERT(*outputPosition < bufSize); const auto &block = program->getUniformBlockByIndex(blockIndex); GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition); } void GetShaderStorageBlockResourceProperty(const Program *program, GLuint blockIndex, GLenum pname, GLint *params, GLsizei bufSize, GLsizei *outputPosition) { ASSERT(*outputPosition < bufSize); const auto &block = program->getShaderStorageBlockByIndex(blockIndex); GetInterfaceBlockResourceProperty(block, pname, params, bufSize, outputPosition); } void GetAtomicCounterBufferResourceProperty(const Program *program, GLuint index, GLenum pname, GLint *params, GLsizei bufSize, GLsizei *outputPosition) { ASSERT(*outputPosition < bufSize); const auto &buffer = program->getState().getAtomicCounterBuffers()[index]; GetShaderVariableBufferResourceProperty(buffer, pname, params, bufSize, outputPosition); } bool IsTextureEnvEnumParameter(TextureEnvParameter pname) { switch (pname) { case TextureEnvParameter::Mode: case TextureEnvParameter::CombineRgb: case TextureEnvParameter::CombineAlpha: case TextureEnvParameter::Src0Rgb: case TextureEnvParameter::Src1Rgb: case TextureEnvParameter::Src2Rgb: case TextureEnvParameter::Src0Alpha: case TextureEnvParameter::Src1Alpha: case TextureEnvParameter::Src2Alpha: case TextureEnvParameter::Op0Rgb: case TextureEnvParameter::Op1Rgb: case TextureEnvParameter::Op2Rgb: case TextureEnvParameter::Op0Alpha: case TextureEnvParameter::Op1Alpha: case TextureEnvParameter::Op2Alpha: case TextureEnvParameter::PointCoordReplace: return true; default: return false; } } } // namespace void QueryFramebufferAttachmentParameteriv(const Context *context, const Framebuffer *framebuffer, GLenum attachment, GLenum pname, GLint *params) { ASSERT(framebuffer); const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(context, attachment); if (attachmentObject == nullptr) { // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE // is NONE, then querying any other pname will generate INVALID_ENUM. // ES 3.0.2 spec pg 235 states that if the attachment type is none, // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an // INVALID_OPERATION for all other pnames switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: *params = GL_NONE; break; case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: *params = 0; break; default: UNREACHABLE(); break; } return; } switch (pname) { case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: *params = attachmentObject->type(); break; case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: *params = attachmentObject->id(); break; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: *params = attachmentObject->mipLevel(); break; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: { TextureTarget face = attachmentObject->cubeMapFace(); if (face != TextureTarget::InvalidEnum) { *params = ToGLenum(attachmentObject->cubeMapFace()); } else { // This happens when the attachment isn't a texture cube map face *params = GL_NONE; } } break; case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: *params = attachmentObject->getRedSize(); break; case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: *params = attachmentObject->getGreenSize(); break; case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: *params = attachmentObject->getBlueSize(); break; case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: *params = attachmentObject->getAlphaSize(); break; case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: *params = attachmentObject->getDepthSize(); break; case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: *params = attachmentObject->getStencilSize(); break; case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: *params = attachmentObject->getComponentType(); break; case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: *params = attachmentObject->getColorEncoding(); break; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: *params = attachmentObject->layer(); break; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR: *params = attachmentObject->getNumViews(); break; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR: *params = attachmentObject->getBaseViewIndex(); break; case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT: *params = attachmentObject->isLayered(); break; case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT: if (attachmentObject->type() == GL_TEXTURE) { *params = attachmentObject->getSamples(); } else { *params = 0; } break; default: UNREACHABLE(); break; } } void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params) { QueryBufferParameterBase(buffer, pname, params); } void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params) { QueryBufferParameterBase(buffer, pname, params); } void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params) { switch (pname) { case GL_BUFFER_MAP_POINTER: *params = buffer->getMapPointer(); break; default: UNREACHABLE(); break; } } void QueryProgramiv(Context *context, const Program *program, GLenum pname, GLint *params) { ASSERT(program != nullptr || pname == GL_COMPLETION_STATUS_KHR); switch (pname) { case GL_DELETE_STATUS: *params = program->isFlaggedForDeletion(); return; case GL_LINK_STATUS: *params = program->isLinked(); return; case GL_COMPLETION_STATUS_KHR: if (context->isContextLost()) { *params = GL_TRUE; } else { *params = program->isLinking() ? GL_FALSE : GL_TRUE; } return; case GL_VALIDATE_STATUS: *params = program->isValidated(); return; case GL_INFO_LOG_LENGTH: *params = program->getExecutable().getInfoLogLength(); return; case GL_ATTACHED_SHADERS: *params = program->getAttachedShadersCount(); return; case GL_ACTIVE_ATTRIBUTES: *params = program->getActiveAttributeCount(); return; case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: *params = program->getActiveAttributeMaxLength(); return; case GL_ACTIVE_UNIFORMS: *params = program->getActiveUniformCount(); return; case GL_ACTIVE_UNIFORM_MAX_LENGTH: *params = program->getActiveUniformMaxLength(); return; case GL_PROGRAM_BINARY_LENGTH_OES: *params = context->getCaps().programBinaryFormats.empty() ? 0 : program->getBinaryLength(context); return; case GL_ACTIVE_UNIFORM_BLOCKS: *params = program->getActiveUniformBlockCount(); return; case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: *params = program->getActiveUniformBlockMaxNameLength(); break; case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: *params = program->getTransformFeedbackBufferMode(); break; case GL_TRANSFORM_FEEDBACK_VARYINGS: *params = clampCast(program->getTransformFeedbackVaryingCount()); break; case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: *params = program->getTransformFeedbackVaryingMaxLength(); break; case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: *params = program->getBinaryRetrievableHint(); break; case GL_PROGRAM_SEPARABLE: // From es31cSeparateShaderObjsTests.cpp: // ProgramParameteri PROGRAM_SEPARABLE // NOTE: The query for PROGRAM_SEPARABLE must query latched // state. In other words, the state of the binary after // it was linked. So in the tests below, the queries // should return the default state GL_FALSE since the // program has no linked binary. *params = program->isSeparable() && program->isLinked(); break; case GL_COMPUTE_WORK_GROUP_SIZE: { const sh::WorkGroupSize &localSize = program->getComputeShaderLocalSize(); params[0] = localSize[0]; params[1] = localSize[1]; params[2] = localSize[2]; } break; case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: *params = program->getActiveAtomicCounterBufferCount(); break; case GL_GEOMETRY_LINKED_INPUT_TYPE_EXT: *params = ToGLenum(program->getGeometryShaderInputPrimitiveType()); break; case GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT: *params = ToGLenum(program->getGeometryShaderOutputPrimitiveType()); break; case GL_GEOMETRY_LINKED_VERTICES_OUT_EXT: *params = program->getGeometryShaderMaxVertices(); break; case GL_GEOMETRY_SHADER_INVOCATIONS_EXT: *params = program->getGeometryShaderInvocations(); break; case GL_TESS_CONTROL_OUTPUT_VERTICES_EXT: *params = program->getTessControlShaderVertices(); break; case GL_TESS_GEN_MODE_EXT: *params = program->getTessGenMode(); break; case GL_TESS_GEN_SPACING_EXT: *params = program->getTessGenSpacing() ? program->getTessGenSpacing() : GL_EQUAL; break; case GL_TESS_GEN_VERTEX_ORDER: *params = program->getTessGenVertexOrder() ? program->getTessGenVertexOrder() : GL_CCW; break; case GL_TESS_GEN_POINT_MODE_EXT: *params = program->getTessGenPointMode() ? GL_TRUE : GL_FALSE; break; default: UNREACHABLE(); break; } } void QueryRenderbufferiv(const Context *context, const Renderbuffer *renderbuffer, GLenum pname, GLint *params) { ASSERT(renderbuffer != nullptr); switch (pname) { case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break; case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break; case GL_RENDERBUFFER_INTERNAL_FORMAT: // Special case the WebGL 1 DEPTH_STENCIL format. if (context->isWebGL1() && renderbuffer->getFormat().info->internalFormat == GL_DEPTH24_STENCIL8) { *params = GL_DEPTH_STENCIL; } else { *params = renderbuffer->getFormat().info->internalFormat; } break; case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break; case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break; case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break; case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break; case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break; case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break; case GL_RENDERBUFFER_SAMPLES_ANGLE: *params = renderbuffer->getState().getSamples(); break; case GL_MEMORY_SIZE_ANGLE: *params = renderbuffer->getMemorySize(); break; case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = static_cast(renderbuffer->getImplementationColorReadFormat(context)); break; case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = static_cast(renderbuffer->getImplementationColorReadType(context)); break; case GL_RESOURCE_INITIALIZED_ANGLE: *params = (renderbuffer->initState(ImageIndex()) == InitState::Initialized); break; default: UNREACHABLE(); break; } } void QueryShaderiv(const Context *context, Shader *shader, GLenum pname, GLint *params) { ASSERT(shader != nullptr || pname == GL_COMPLETION_STATUS_KHR); switch (pname) { case GL_SHADER_TYPE: *params = static_cast(ToGLenum(shader->getType())); return; case GL_DELETE_STATUS: *params = shader->isFlaggedForDeletion(); return; case GL_COMPILE_STATUS: *params = shader->isCompiled() ? GL_TRUE : GL_FALSE; return; case GL_COMPLETION_STATUS_KHR: if (context->isContextLost()) { *params = GL_TRUE; } else { *params = shader->isCompleted() ? GL_TRUE : GL_FALSE; } return; case GL_INFO_LOG_LENGTH: *params = shader->getInfoLogLength(); return; case GL_SHADER_SOURCE_LENGTH: *params = shader->getSourceLength(); return; case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE: *params = shader->getTranslatedSourceWithDebugInfoLength(); return; default: UNREACHABLE(); break; } } void QueryTexLevelParameterfv(const Texture *texture, TextureTarget target, GLint level, GLenum pname, GLfloat *params) { QueryTexLevelParameterBase(texture, target, level, pname, params); } void QueryTexLevelParameteriv(const Texture *texture, TextureTarget target, GLint level, GLenum pname, GLint *params) { QueryTexLevelParameterBase(texture, target, level, pname, params); } void QueryTexParameterfv(const Context *context, const Texture *texture, GLenum pname, GLfloat *params) { QueryTexParameterBase(context, texture, pname, params); } void QueryTexParameterxv(const Context *context, const Texture *texture, GLenum pname, GLfixed *params) { QueryTexParameterBase(context, texture, pname, params); } void QueryTexParameteriv(const Context *context, const Texture *texture, GLenum pname, GLint *params) { QueryTexParameterBase(context, texture, pname, params); } void QueryTexParameterIiv(const Context *context, const Texture *texture, GLenum pname, GLint *params) { QueryTexParameterBase(context, texture, pname, params); } void QueryTexParameterIuiv(const Context *context, const Texture *texture, GLenum pname, GLuint *params) { QueryTexParameterBase(context, texture, pname, params); } void QuerySamplerParameterfv(const Sampler *sampler, GLenum pname, GLfloat *params) { QuerySamplerParameterBase(sampler, pname, params); } void QuerySamplerParameteriv(const Sampler *sampler, GLenum pname, GLint *params) { QuerySamplerParameterBase(sampler, pname, params); } void QuerySamplerParameterIiv(const Sampler *sampler, GLenum pname, GLint *params) { QuerySamplerParameterBase(sampler, pname, params); } void QuerySamplerParameterIuiv(const Sampler *sampler, GLenum pname, GLuint *params) { QuerySamplerParameterBase(sampler, pname, params); } void QueryVertexAttribfv(const VertexAttribute &attrib, const VertexBinding &binding, const VertexAttribCurrentValueData ¤tValueData, GLenum pname, GLfloat *params) { QueryVertexAttribBase(attrib, binding, currentValueData.Values.FloatValues, pname, params); } void QueryVertexAttribiv(const VertexAttribute &attrib, const VertexBinding &binding, const VertexAttribCurrentValueData ¤tValueData, GLenum pname, GLint *params) { QueryVertexAttribBase(attrib, binding, currentValueData.Values.FloatValues, pname, params); } void QueryVertexAttribPointerv(const VertexAttribute &attrib, GLenum pname, void **pointer) { switch (pname) { case GL_VERTEX_ATTRIB_ARRAY_POINTER: *pointer = const_cast(attrib.pointer); break; default: UNREACHABLE(); break; } } void QueryVertexAttribIiv(const VertexAttribute &attrib, const VertexBinding &binding, const VertexAttribCurrentValueData ¤tValueData, GLenum pname, GLint *params) { QueryVertexAttribBase(attrib, binding, currentValueData.Values.IntValues, pname, params); } void QueryVertexAttribIuiv(const VertexAttribute &attrib, const VertexBinding &binding, const VertexAttribCurrentValueData ¤tValueData, GLenum pname, GLuint *params) { QueryVertexAttribBase(attrib, binding, currentValueData.Values.UnsignedIntValues, pname, params); } void QueryActiveUniformBlockiv(const Program *program, UniformBlockIndex uniformBlockIndex, GLenum pname, GLint *params) { GLenum prop = GetUniformBlockPropertyEnum(pname); QueryProgramResourceiv(program, GL_UNIFORM_BLOCK, uniformBlockIndex, 1, &prop, std::numeric_limits::max(), nullptr, params); } void QueryInternalFormativ(const TextureCaps &format, GLenum pname, GLsizei bufSize, GLint *params) { switch (pname) { case GL_NUM_SAMPLE_COUNTS: if (bufSize != 0) { *params = clampCast(format.sampleCounts.size()); } break; case GL_SAMPLES: { size_t returnCount = std::min(bufSize, format.sampleCounts.size()); auto sampleReverseIt = format.sampleCounts.rbegin(); for (size_t sampleIndex = 0; sampleIndex < returnCount; ++sampleIndex) { params[sampleIndex] = *sampleReverseIt++; } } break; default: UNREACHABLE(); break; } } void QueryFramebufferParameteriv(const Framebuffer *framebuffer, GLenum pname, GLint *params) { ASSERT(framebuffer); switch (pname) { case GL_FRAMEBUFFER_DEFAULT_WIDTH: *params = framebuffer->getDefaultWidth(); break; case GL_FRAMEBUFFER_DEFAULT_HEIGHT: *params = framebuffer->getDefaultHeight(); break; case GL_FRAMEBUFFER_DEFAULT_SAMPLES: *params = framebuffer->getDefaultSamples(); break; case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: *params = ConvertToGLBoolean(framebuffer->getDefaultFixedSampleLocations()); break; case GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT: *params = framebuffer->getDefaultLayers(); break; default: UNREACHABLE(); break; } } angle::Result QuerySynciv(const Context *context, const Sync *sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { ASSERT(sync != nullptr || pname == GL_SYNC_STATUS); // All queries return one value, exit early if the buffer can't fit anything. if (bufSize < 1) { if (length != nullptr) { *length = 0; } return angle::Result::Continue; } switch (pname) { case GL_OBJECT_TYPE: *values = clampCast(GL_SYNC_FENCE); break; case GL_SYNC_CONDITION: *values = clampCast(sync->getCondition()); break; case GL_SYNC_FLAGS: *values = clampCast(sync->getFlags()); break; case GL_SYNC_STATUS: if (context->isContextLost()) { *values = GL_SIGNALED; } else { ANGLE_TRY(sync->getStatus(context, values)); } break; default: UNREACHABLE(); break; } if (length != nullptr) { *length = 1; } return angle::Result::Continue; } void SetTexParameterx(Context *context, Texture *texture, GLenum pname, GLfixed param) { SetTexParameterBase(context, texture, pname, ¶m); } void SetTexParameterxv(Context *context, Texture *texture, GLenum pname, const GLfixed *params) { SetTexParameterBase(context, texture, pname, params); } void SetTexParameterf(Context *context, Texture *texture, GLenum pname, GLfloat param) { SetTexParameterBase(context, texture, pname, ¶m); } void SetTexParameterfv(Context *context, Texture *texture, GLenum pname, const GLfloat *params) { SetTexParameterBase(context, texture, pname, params); } void SetTexParameteri(Context *context, Texture *texture, GLenum pname, GLint param) { SetTexParameterBase(context, texture, pname, ¶m); } void SetTexParameteriv(Context *context, Texture *texture, GLenum pname, const GLint *params) { SetTexParameterBase(context, texture, pname, params); } void SetTexParameterIiv(Context *context, Texture *texture, GLenum pname, const GLint *params) { SetTexParameterBase(context, texture, pname, params); } void SetTexParameterIuiv(Context *context, Texture *texture, GLenum pname, const GLuint *params) { SetTexParameterBase(context, texture, pname, params); } void SetSamplerParameterf(Context *context, Sampler *sampler, GLenum pname, GLfloat param) { SetSamplerParameterBase(context, sampler, pname, ¶m); } void SetSamplerParameterfv(Context *context, Sampler *sampler, GLenum pname, const GLfloat *params) { SetSamplerParameterBase(context, sampler, pname, params); } void SetSamplerParameteri(Context *context, Sampler *sampler, GLenum pname, GLint param) { SetSamplerParameterBase(context, sampler, pname, ¶m); } void SetSamplerParameteriv(Context *context, Sampler *sampler, GLenum pname, const GLint *params) { SetSamplerParameterBase(context, sampler, pname, params); } void SetSamplerParameterIiv(Context *context, Sampler *sampler, GLenum pname, const GLint *params) { SetSamplerParameterBase(context, sampler, pname, params); } void SetSamplerParameterIuiv(Context *context, Sampler *sampler, GLenum pname, const GLuint *params) { SetSamplerParameterBase(context, sampler, pname, params); } void SetFramebufferParameteri(const Context *context, Framebuffer *framebuffer, GLenum pname, GLint param) { ASSERT(framebuffer); switch (pname) { case GL_FRAMEBUFFER_DEFAULT_WIDTH: framebuffer->setDefaultWidth(context, param); break; case GL_FRAMEBUFFER_DEFAULT_HEIGHT: framebuffer->setDefaultHeight(context, param); break; case GL_FRAMEBUFFER_DEFAULT_SAMPLES: framebuffer->setDefaultSamples(context, param); break; case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: framebuffer->setDefaultFixedSampleLocations(context, ConvertToBool(param)); break; case GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT: framebuffer->setDefaultLayers(param); break; default: UNREACHABLE(); break; } } void SetProgramParameteri(Program *program, GLenum pname, GLint value) { ASSERT(program); switch (pname) { case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: program->setBinaryRetrievableHint(ConvertToBool(value)); break; case GL_PROGRAM_SEPARABLE: program->setSeparable(ConvertToBool(value)); break; default: UNREACHABLE(); break; } } GLint GetUniformResourceProperty(const Program *program, GLuint index, const GLenum prop) { const auto &uniform = program->getUniformByIndex(index); GLenum resourceProp = GetUniformPropertyEnum(prop); switch (resourceProp) { case GL_TYPE: case GL_ARRAY_SIZE: case GL_NAME_LENGTH: return GetCommonVariableProperty(uniform, resourceProp); case GL_LOCATION: return program->getUniformLocation(uniform.name).value; case GL_BLOCK_INDEX: return (uniform.isAtomicCounter() ? -1 : uniform.bufferIndex); case GL_OFFSET: return uniform.blockInfo.offset; case GL_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; case GL_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; case GL_IS_ROW_MAJOR: return static_cast(uniform.blockInfo.isRowMajorMatrix); case GL_REFERENCED_BY_VERTEX_SHADER: return uniform.isActive(ShaderType::Vertex); case GL_REFERENCED_BY_FRAGMENT_SHADER: return uniform.isActive(ShaderType::Fragment); case GL_REFERENCED_BY_COMPUTE_SHADER: return uniform.isActive(ShaderType::Compute); case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: return uniform.isActive(ShaderType::Geometry); case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT: return uniform.isActive(ShaderType::TessControl); case GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT: return uniform.isActive(ShaderType::TessEvaluation); case GL_ATOMIC_COUNTER_BUFFER_INDEX: return (uniform.isAtomicCounter() ? uniform.bufferIndex : -1); default: UNREACHABLE(); return 0; } } GLint GetBufferVariableResourceProperty(const Program *program, GLuint index, const GLenum prop) { const BufferVariable &bufferVariable = program->getBufferVariableByIndex(index); switch (prop) { case GL_TYPE: case GL_ARRAY_SIZE: case GL_NAME_LENGTH: return GetCommonVariableProperty(bufferVariable, prop); case GL_BLOCK_INDEX: return bufferVariable.bufferIndex; case GL_OFFSET: return bufferVariable.blockInfo.offset; case GL_ARRAY_STRIDE: return bufferVariable.blockInfo.arrayStride; case GL_MATRIX_STRIDE: return bufferVariable.blockInfo.matrixStride; case GL_IS_ROW_MAJOR: return static_cast(bufferVariable.blockInfo.isRowMajorMatrix); case GL_REFERENCED_BY_VERTEX_SHADER: return bufferVariable.isActive(ShaderType::Vertex); case GL_REFERENCED_BY_FRAGMENT_SHADER: return bufferVariable.isActive(ShaderType::Fragment); case GL_REFERENCED_BY_COMPUTE_SHADER: return bufferVariable.isActive(ShaderType::Compute); case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: return bufferVariable.isActive(ShaderType::Geometry); case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT: return bufferVariable.isActive(ShaderType::TessControl); case GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT: return bufferVariable.isActive(ShaderType::TessEvaluation); case GL_TOP_LEVEL_ARRAY_SIZE: return bufferVariable.topLevelArraySize; case GL_TOP_LEVEL_ARRAY_STRIDE: return bufferVariable.blockInfo.topLevelArrayStride; default: UNREACHABLE(); return 0; } } GLuint QueryProgramResourceIndex(const Program *program, GLenum programInterface, const GLchar *name) { switch (programInterface) { case GL_PROGRAM_INPUT: return program->getInputResourceIndex(name); case GL_PROGRAM_OUTPUT: return program->getOutputResourceIndex(name); case GL_UNIFORM: return program->getState().getUniformIndexFromName(name); case GL_BUFFER_VARIABLE: return program->getState().getBufferVariableIndexFromName(name); case GL_SHADER_STORAGE_BLOCK: return program->getShaderStorageBlockIndex(name); case GL_UNIFORM_BLOCK: return program->getUniformBlockIndex(name); case GL_TRANSFORM_FEEDBACK_VARYING: return program->getTransformFeedbackVaryingResourceIndex(name); default: UNREACHABLE(); return GL_INVALID_INDEX; } } void QueryProgramResourceName(const Program *program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) { switch (programInterface) { case GL_PROGRAM_INPUT: program->getInputResourceName(index, bufSize, length, name); break; case GL_PROGRAM_OUTPUT: program->getOutputResourceName(index, bufSize, length, name); break; case GL_UNIFORM: program->getUniformResourceName(index, bufSize, length, name); break; case GL_BUFFER_VARIABLE: program->getBufferVariableResourceName(index, bufSize, length, name); break; case GL_SHADER_STORAGE_BLOCK: program->getActiveShaderStorageBlockName(index, bufSize, length, name); break; case GL_UNIFORM_BLOCK: program->getActiveUniformBlockName({index}, bufSize, length, name); break; case GL_TRANSFORM_FEEDBACK_VARYING: program->getTransformFeedbackVarying(index, bufSize, length, nullptr, nullptr, name); break; default: UNREACHABLE(); } } GLint QueryProgramResourceLocation(const Program *program, GLenum programInterface, const GLchar *name) { switch (programInterface) { case GL_PROGRAM_INPUT: return program->getInputResourceLocation(name); case GL_PROGRAM_OUTPUT: return program->getOutputResourceLocation(name); case GL_UNIFORM: return program->getUniformLocation(name).value; default: UNREACHABLE(); return -1; } } void QueryProgramResourceiv(const Program *program, GLenum programInterface, UniformBlockIndex index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) { if (!program->isLinked()) { return; } if (length != nullptr) { *length = 0; } if (bufSize == 0) { // No room to write the results return; } GLsizei pos = 0; for (GLsizei i = 0; i < propCount; i++) { switch (programInterface) { case GL_PROGRAM_INPUT: params[i] = GetInputResourceProperty(program, index.value, props[i]); ++pos; break; case GL_PROGRAM_OUTPUT: params[i] = GetOutputResourceProperty(program, index.value, props[i]); ++pos; break; case GL_UNIFORM: params[i] = GetUniformResourceProperty(program, index.value, props[i]); ++pos; break; case GL_BUFFER_VARIABLE: params[i] = GetBufferVariableResourceProperty(program, index.value, props[i]); ++pos; break; case GL_UNIFORM_BLOCK: GetUniformBlockResourceProperty(program, index.value, props[i], params, bufSize, &pos); break; case GL_SHADER_STORAGE_BLOCK: GetShaderStorageBlockResourceProperty(program, index.value, props[i], params, bufSize, &pos); break; case GL_ATOMIC_COUNTER_BUFFER: GetAtomicCounterBufferResourceProperty(program, index.value, props[i], params, bufSize, &pos); break; case GL_TRANSFORM_FEEDBACK_VARYING: params[i] = GetTransformFeedbackVaryingResourceProperty(program, index.value, props[i]); ++pos; break; default: UNREACHABLE(); params[i] = GL_INVALID_VALUE; } if (pos == bufSize) { // Most properties return one value, but GL_ACTIVE_VARIABLES returns an array of values. // This checks not to break buffer bounds for such case. break; } } if (length != nullptr) { *length = pos; } } void QueryProgramInterfaceiv(const Program *program, GLenum programInterface, GLenum pname, GLint *params) { switch (pname) { case GL_ACTIVE_RESOURCES: *params = QueryProgramInterfaceActiveResources(program, programInterface); break; case GL_MAX_NAME_LENGTH: *params = QueryProgramInterfaceMaxNameLength(program, programInterface); break; case GL_MAX_NUM_ACTIVE_VARIABLES: *params = QueryProgramInterfaceMaxNumActiveVariables(program, programInterface); break; default: UNREACHABLE(); } } angle::Result SetMemoryObjectParameteriv(const Context *context, MemoryObject *memoryObject, GLenum pname, const GLint *params) { switch (pname) { case GL_DEDICATED_MEMORY_OBJECT_EXT: ANGLE_TRY(memoryObject->setDedicatedMemory(context, ConvertToBool(params[0]))); break; default: UNREACHABLE(); } return angle::Result::Continue; } void QueryMemoryObjectParameteriv(const MemoryObject *memoryObject, GLenum pname, GLint *params) { switch (pname) { case GL_DEDICATED_MEMORY_OBJECT_EXT: *params = memoryObject->isDedicatedMemory(); break; default: UNREACHABLE(); } } ClientVertexArrayType ParamToVertexArrayType(GLenum param) { switch (param) { case GL_VERTEX_ARRAY: case GL_VERTEX_ARRAY_BUFFER_BINDING: case GL_VERTEX_ARRAY_STRIDE: case GL_VERTEX_ARRAY_SIZE: case GL_VERTEX_ARRAY_TYPE: case GL_VERTEX_ARRAY_POINTER: return ClientVertexArrayType::Vertex; case GL_NORMAL_ARRAY: case GL_NORMAL_ARRAY_BUFFER_BINDING: case GL_NORMAL_ARRAY_STRIDE: case GL_NORMAL_ARRAY_TYPE: case GL_NORMAL_ARRAY_POINTER: return ClientVertexArrayType::Normal; case GL_COLOR_ARRAY: case GL_COLOR_ARRAY_BUFFER_BINDING: case GL_COLOR_ARRAY_STRIDE: case GL_COLOR_ARRAY_SIZE: case GL_COLOR_ARRAY_TYPE: case GL_COLOR_ARRAY_POINTER: return ClientVertexArrayType::Color; case GL_POINT_SIZE_ARRAY_OES: case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: case GL_POINT_SIZE_ARRAY_STRIDE_OES: case GL_POINT_SIZE_ARRAY_TYPE_OES: case GL_POINT_SIZE_ARRAY_POINTER_OES: return ClientVertexArrayType::PointSize; case GL_TEXTURE_COORD_ARRAY: case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: case GL_TEXTURE_COORD_ARRAY_STRIDE: case GL_TEXTURE_COORD_ARRAY_SIZE: case GL_TEXTURE_COORD_ARRAY_TYPE: case GL_TEXTURE_COORD_ARRAY_POINTER: return ClientVertexArrayType::TextureCoord; default: UNREACHABLE(); return ClientVertexArrayType::InvalidEnum; } } void SetLightModelParameters(GLES1State *state, GLenum pname, const GLfloat *params) { LightModelParameters &lightModel = state->lightModelParameters(); switch (pname) { case GL_LIGHT_MODEL_AMBIENT: lightModel.color = ColorF::fromData(params); break; case GL_LIGHT_MODEL_TWO_SIDE: lightModel.twoSided = *params == 1.0f ? true : false; break; default: break; } } void GetLightModelParameters(const GLES1State *state, GLenum pname, GLfloat *params) { const LightModelParameters &lightModel = state->lightModelParameters(); switch (pname) { case GL_LIGHT_MODEL_TWO_SIDE: *params = lightModel.twoSided ? 1.0f : 0.0f; break; case GL_LIGHT_MODEL_AMBIENT: lightModel.color.writeData(params); break; default: break; } } bool IsLightModelTwoSided(const GLES1State *state) { return state->lightModelParameters().twoSided; } void SetLightParameters(GLES1State *state, GLenum light, LightParameter pname, const GLfloat *params) { uint32_t lightIndex = light - GL_LIGHT0; LightParameters &lightParams = state->lightParameters(lightIndex); switch (pname) { case LightParameter::Ambient: lightParams.ambient = ColorF::fromData(params); break; case LightParameter::Diffuse: lightParams.diffuse = ColorF::fromData(params); break; case LightParameter::Specular: lightParams.specular = ColorF::fromData(params); break; case LightParameter::Position: { angle::Mat4 mv = state->getModelviewMatrix(); angle::Vector4 transformedPos = mv.product(angle::Vector4(params[0], params[1], params[2], params[3])); lightParams.position[0] = transformedPos[0]; lightParams.position[1] = transformedPos[1]; lightParams.position[2] = transformedPos[2]; lightParams.position[3] = transformedPos[3]; } break; case LightParameter::SpotDirection: { angle::Mat4 mv = state->getModelviewMatrix(); angle::Vector4 transformedPos = mv.product(angle::Vector4(params[0], params[1], params[2], 0.0f)); lightParams.direction[0] = transformedPos[0]; lightParams.direction[1] = transformedPos[1]; lightParams.direction[2] = transformedPos[2]; } break; case LightParameter::SpotExponent: lightParams.spotlightExponent = *params; break; case LightParameter::SpotCutoff: lightParams.spotlightCutoffAngle = *params; break; case LightParameter::ConstantAttenuation: lightParams.attenuationConst = *params; break; case LightParameter::LinearAttenuation: lightParams.attenuationLinear = *params; break; case LightParameter::QuadraticAttenuation: lightParams.attenuationQuadratic = *params; break; default: return; } } void GetLightParameters(const GLES1State *state, GLenum light, LightParameter pname, GLfloat *params) { uint32_t lightIndex = light - GL_LIGHT0; const LightParameters &lightParams = state->lightParameters(lightIndex); switch (pname) { case LightParameter::Ambient: lightParams.ambient.writeData(params); break; case LightParameter::Diffuse: lightParams.diffuse.writeData(params); break; case LightParameter::Specular: lightParams.specular.writeData(params); break; case LightParameter::Position: memcpy(params, lightParams.position.data(), 4 * sizeof(GLfloat)); break; case LightParameter::SpotDirection: memcpy(params, lightParams.direction.data(), 3 * sizeof(GLfloat)); break; case LightParameter::SpotExponent: *params = lightParams.spotlightExponent; break; case LightParameter::SpotCutoff: *params = lightParams.spotlightCutoffAngle; break; case LightParameter::ConstantAttenuation: *params = lightParams.attenuationConst; break; case LightParameter::LinearAttenuation: *params = lightParams.attenuationLinear; break; case LightParameter::QuadraticAttenuation: *params = lightParams.attenuationQuadratic; break; default: break; } } void SetMaterialParameters(GLES1State *state, GLenum face, MaterialParameter pname, const GLfloat *params) { MaterialParameters &material = state->materialParameters(); switch (pname) { case MaterialParameter::Ambient: material.ambient = ColorF::fromData(params); break; case MaterialParameter::Diffuse: material.diffuse = ColorF::fromData(params); break; case MaterialParameter::AmbientAndDiffuse: material.ambient = ColorF::fromData(params); material.diffuse = ColorF::fromData(params); break; case MaterialParameter::Specular: material.specular = ColorF::fromData(params); break; case MaterialParameter::Emission: material.emissive = ColorF::fromData(params); break; case MaterialParameter::Shininess: material.specularExponent = *params; break; default: return; } } void GetMaterialParameters(const GLES1State *state, GLenum face, MaterialParameter pname, GLfloat *params) { const ColorF ¤tColor = state->getCurrentColor(); const MaterialParameters &material = state->materialParameters(); const bool colorMaterialEnabled = state->isColorMaterialEnabled(); switch (pname) { case MaterialParameter::Ambient: if (colorMaterialEnabled) { currentColor.writeData(params); } else { material.ambient.writeData(params); } break; case MaterialParameter::Diffuse: if (colorMaterialEnabled) { currentColor.writeData(params); } else { material.diffuse.writeData(params); } break; case MaterialParameter::Specular: material.specular.writeData(params); break; case MaterialParameter::Emission: material.emissive.writeData(params); break; case MaterialParameter::Shininess: *params = material.specularExponent; break; default: return; } } unsigned int GetLightModelParameterCount(GLenum pname) { switch (pname) { case GL_LIGHT_MODEL_AMBIENT: return 4; case GL_LIGHT_MODEL_TWO_SIDE: return 1; default: UNREACHABLE(); return 0; } } unsigned int GetLightParameterCount(LightParameter pname) { switch (pname) { case LightParameter::Ambient: case LightParameter::Diffuse: case LightParameter::AmbientAndDiffuse: case LightParameter::Specular: case LightParameter::Position: return 4; case LightParameter::SpotDirection: return 3; case LightParameter::SpotExponent: case LightParameter::SpotCutoff: case LightParameter::ConstantAttenuation: case LightParameter::LinearAttenuation: case LightParameter::QuadraticAttenuation: return 1; default: UNREACHABLE(); return 0; } } unsigned int GetMaterialParameterCount(MaterialParameter pname) { switch (pname) { case MaterialParameter::Ambient: case MaterialParameter::Diffuse: case MaterialParameter::AmbientAndDiffuse: case MaterialParameter::Specular: case MaterialParameter::Emission: return 4; case MaterialParameter::Shininess: return 1; default: UNREACHABLE(); return 0; } } void SetFogParameters(GLES1State *state, GLenum pname, const GLfloat *params) { FogParameters &fog = state->fogParameters(); switch (pname) { case GL_FOG_MODE: fog.mode = FromGLenum(static_cast(params[0])); break; case GL_FOG_DENSITY: fog.density = params[0]; break; case GL_FOG_START: fog.start = params[0]; break; case GL_FOG_END: fog.end = params[0]; break; case GL_FOG_COLOR: fog.color = ColorF::fromData(params); break; default: return; } } void GetFogParameters(const GLES1State *state, GLenum pname, GLfloat *params) { const FogParameters &fog = state->fogParameters(); switch (pname) { case GL_FOG_MODE: params[0] = static_cast(ToGLenum(fog.mode)); break; case GL_FOG_DENSITY: params[0] = fog.density; break; case GL_FOG_START: params[0] = fog.start; break; case GL_FOG_END: params[0] = fog.end; break; case GL_FOG_COLOR: fog.color.writeData(params); break; default: return; } } unsigned int GetFogParameterCount(GLenum pname) { switch (pname) { case GL_FOG_MODE: case GL_FOG_DENSITY: case GL_FOG_START: case GL_FOG_END: return 1; case GL_FOG_COLOR: return 4; default: return 0; } } unsigned int GetTextureEnvParameterCount(TextureEnvParameter pname) { switch (pname) { case TextureEnvParameter::Mode: case TextureEnvParameter::CombineRgb: case TextureEnvParameter::CombineAlpha: case TextureEnvParameter::Src0Rgb: case TextureEnvParameter::Src1Rgb: case TextureEnvParameter::Src2Rgb: case TextureEnvParameter::Src0Alpha: case TextureEnvParameter::Src1Alpha: case TextureEnvParameter::Src2Alpha: case TextureEnvParameter::Op0Rgb: case TextureEnvParameter::Op1Rgb: case TextureEnvParameter::Op2Rgb: case TextureEnvParameter::Op0Alpha: case TextureEnvParameter::Op1Alpha: case TextureEnvParameter::Op2Alpha: case TextureEnvParameter::RgbScale: case TextureEnvParameter::AlphaScale: case TextureEnvParameter::PointCoordReplace: return 1; case TextureEnvParameter::Color: return 4; default: return 0; } } void ConvertTextureEnvFromInt(TextureEnvParameter pname, const GLint *input, GLfloat *output) { if (IsTextureEnvEnumParameter(pname)) { ConvertGLenumValue(input[0], output); return; } switch (pname) { case TextureEnvParameter::RgbScale: case TextureEnvParameter::AlphaScale: output[0] = static_cast(input[0]); break; case TextureEnvParameter::Color: for (int i = 0; i < 4; i++) { output[i] = input[i] / 255.0f; } break; default: UNREACHABLE(); break; } } void ConvertTextureEnvFromFixed(TextureEnvParameter pname, const GLfixed *input, GLfloat *output) { if (IsTextureEnvEnumParameter(pname)) { ConvertGLenumValue(input[0], output); return; } switch (pname) { case TextureEnvParameter::RgbScale: case TextureEnvParameter::AlphaScale: output[0] = ConvertFixedToFloat(input[0]); break; case TextureEnvParameter::Color: for (int i = 0; i < 4; i++) { output[i] = ConvertFixedToFloat(input[i]); } break; default: UNREACHABLE(); break; } } void ConvertTextureEnvToInt(TextureEnvParameter pname, const GLfloat *input, GLint *output) { if (IsTextureEnvEnumParameter(pname)) { ConvertGLenumValue(input[0], output); return; } switch (pname) { case TextureEnvParameter::RgbScale: case TextureEnvParameter::AlphaScale: output[0] = static_cast(input[0]); break; case TextureEnvParameter::Color: for (int i = 0; i < 4; i++) { output[i] = static_cast(input[i] * 255.0f); } break; default: UNREACHABLE(); break; } } void ConvertTextureEnvToFixed(TextureEnvParameter pname, const GLfloat *input, GLfixed *output) { if (IsTextureEnvEnumParameter(pname)) { ConvertGLenumValue(input[0], output); return; } switch (pname) { case TextureEnvParameter::RgbScale: case TextureEnvParameter::AlphaScale: output[0] = ConvertFloatToFixed(input[0]); break; case TextureEnvParameter::Color: for (int i = 0; i < 4; i++) { output[i] = ConvertFloatToFixed(input[i]); } break; default: UNREACHABLE(); break; } } void SetTextureEnv(unsigned int unit, GLES1State *state, TextureEnvTarget target, TextureEnvParameter pname, const GLfloat *params) { TextureEnvironmentParameters &env = state->textureEnvironment(unit); GLenum asEnum = ConvertToGLenum(params[0]); switch (target) { case TextureEnvTarget::Env: switch (pname) { case TextureEnvParameter::Mode: env.mode = FromGLenum(asEnum); break; case TextureEnvParameter::CombineRgb: env.combineRgb = FromGLenum(asEnum); break; case TextureEnvParameter::CombineAlpha: env.combineAlpha = FromGLenum(asEnum); break; case TextureEnvParameter::Src0Rgb: env.src0Rgb = FromGLenum(asEnum); break; case TextureEnvParameter::Src1Rgb: env.src1Rgb = FromGLenum(asEnum); break; case TextureEnvParameter::Src2Rgb: env.src2Rgb = FromGLenum(asEnum); break; case TextureEnvParameter::Src0Alpha: env.src0Alpha = FromGLenum(asEnum); break; case TextureEnvParameter::Src1Alpha: env.src1Alpha = FromGLenum(asEnum); break; case TextureEnvParameter::Src2Alpha: env.src2Alpha = FromGLenum(asEnum); break; case TextureEnvParameter::Op0Rgb: env.op0Rgb = FromGLenum(asEnum); break; case TextureEnvParameter::Op1Rgb: env.op1Rgb = FromGLenum(asEnum); break; case TextureEnvParameter::Op2Rgb: env.op2Rgb = FromGLenum(asEnum); break; case TextureEnvParameter::Op0Alpha: env.op0Alpha = FromGLenum(asEnum); break; case TextureEnvParameter::Op1Alpha: env.op1Alpha = FromGLenum(asEnum); break; case TextureEnvParameter::Op2Alpha: env.op2Alpha = FromGLenum(asEnum); break; case TextureEnvParameter::Color: env.color = ColorF::fromData(params); break; case TextureEnvParameter::RgbScale: env.rgbScale = params[0]; break; case TextureEnvParameter::AlphaScale: env.alphaScale = params[0]; break; default: UNREACHABLE(); break; } break; case TextureEnvTarget::PointSprite: switch (pname) { case TextureEnvParameter::PointCoordReplace: env.pointSpriteCoordReplace = static_cast(params[0]); break; default: UNREACHABLE(); break; } break; default: UNREACHABLE(); break; } } void GetTextureEnv(unsigned int unit, const GLES1State *state, TextureEnvTarget target, TextureEnvParameter pname, GLfloat *params) { const TextureEnvironmentParameters &env = state->textureEnvironment(unit); switch (target) { case TextureEnvTarget::Env: switch (pname) { case TextureEnvParameter::Mode: ConvertPackedEnum(env.mode, params); break; case TextureEnvParameter::CombineRgb: ConvertPackedEnum(env.combineRgb, params); break; case TextureEnvParameter::CombineAlpha: ConvertPackedEnum(env.combineAlpha, params); break; case TextureEnvParameter::Src0Rgb: ConvertPackedEnum(env.src0Rgb, params); break; case TextureEnvParameter::Src1Rgb: ConvertPackedEnum(env.src1Rgb, params); break; case TextureEnvParameter::Src2Rgb: ConvertPackedEnum(env.src2Rgb, params); break; case TextureEnvParameter::Src0Alpha: ConvertPackedEnum(env.src0Alpha, params); break; case TextureEnvParameter::Src1Alpha: ConvertPackedEnum(env.src1Alpha, params); break; case TextureEnvParameter::Src2Alpha: ConvertPackedEnum(env.src2Alpha, params); break; case TextureEnvParameter::Op0Rgb: ConvertPackedEnum(env.op0Rgb, params); break; case TextureEnvParameter::Op1Rgb: ConvertPackedEnum(env.op1Rgb, params); break; case TextureEnvParameter::Op2Rgb: ConvertPackedEnum(env.op2Rgb, params); break; case TextureEnvParameter::Op0Alpha: ConvertPackedEnum(env.op0Alpha, params); break; case TextureEnvParameter::Op1Alpha: ConvertPackedEnum(env.op1Alpha, params); break; case TextureEnvParameter::Op2Alpha: ConvertPackedEnum(env.op2Alpha, params); break; case TextureEnvParameter::Color: env.color.writeData(params); break; case TextureEnvParameter::RgbScale: *params = env.rgbScale; break; case TextureEnvParameter::AlphaScale: *params = env.alphaScale; break; default: UNREACHABLE(); break; } break; case TextureEnvTarget::PointSprite: switch (pname) { case TextureEnvParameter::PointCoordReplace: *params = static_cast(env.pointSpriteCoordReplace); break; default: UNREACHABLE(); break; } break; default: UNREACHABLE(); break; } } unsigned int GetPointParameterCount(PointParameter pname) { switch (pname) { case PointParameter::PointSizeMin: case PointParameter::PointSizeMax: case PointParameter::PointFadeThresholdSize: return 1; case PointParameter::PointDistanceAttenuation: return 3; default: return 0; } } void SetPointParameter(GLES1State *state, PointParameter pname, const GLfloat *params) { PointParameters &pointParams = state->pointParameters(); switch (pname) { case PointParameter::PointSizeMin: pointParams.pointSizeMin = params[0]; break; case PointParameter::PointSizeMax: pointParams.pointSizeMax = params[0]; break; case PointParameter::PointFadeThresholdSize: pointParams.pointFadeThresholdSize = params[0]; break; case PointParameter::PointDistanceAttenuation: for (unsigned int i = 0; i < 3; i++) { pointParams.pointDistanceAttenuation[i] = params[i]; } break; default: UNREACHABLE(); } } void GetPointParameter(const GLES1State *state, PointParameter pname, GLfloat *params) { const PointParameters &pointParams = state->pointParameters(); switch (pname) { case PointParameter::PointSizeMin: params[0] = pointParams.pointSizeMin; break; case PointParameter::PointSizeMax: params[0] = pointParams.pointSizeMax; break; case PointParameter::PointFadeThresholdSize: params[0] = pointParams.pointFadeThresholdSize; break; case PointParameter::PointDistanceAttenuation: for (unsigned int i = 0; i < 3; i++) { params[i] = pointParams.pointDistanceAttenuation[i]; } break; default: UNREACHABLE(); } } void SetPointSize(GLES1State *state, GLfloat size) { PointParameters ¶ms = state->pointParameters(); params.pointSize = size; } void GetPointSize(const GLES1State *state, GLfloat *sizeOut) { const PointParameters ¶ms = state->pointParameters(); *sizeOut = params.pointSize; } unsigned int GetTexParameterCount(GLenum pname) { switch (pname) { case GL_TEXTURE_CROP_RECT_OES: case GL_TEXTURE_BORDER_COLOR: return 4; case GL_TEXTURE_MAG_FILTER: case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_WRAP_S: case GL_TEXTURE_WRAP_T: case GL_TEXTURE_USAGE_ANGLE: case GL_TEXTURE_MAX_ANISOTROPY_EXT: case GL_TEXTURE_IMMUTABLE_FORMAT: case GL_TEXTURE_WRAP_R: case GL_TEXTURE_IMMUTABLE_LEVELS: case GL_TEXTURE_SWIZZLE_R: case GL_TEXTURE_SWIZZLE_G: case GL_TEXTURE_SWIZZLE_B: case GL_TEXTURE_SWIZZLE_A: case GL_TEXTURE_BASE_LEVEL: case GL_TEXTURE_MAX_LEVEL: case GL_TEXTURE_MIN_LOD: case GL_TEXTURE_MAX_LOD: case GL_TEXTURE_COMPARE_MODE: case GL_TEXTURE_COMPARE_FUNC: case GL_TEXTURE_SRGB_DECODE_EXT: case GL_DEPTH_STENCIL_TEXTURE_MODE: case GL_TEXTURE_NATIVE_ID_ANGLE: return 1; default: return 0; } } bool GetQueryParameterInfo(const State &glState, GLenum pname, GLenum *type, unsigned int *numParams) { const Caps &caps = glState.getCaps(); const Extensions &extensions = glState.getExtensions(); GLint clientMajorVersion = glState.getClientMajorVersion(); // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due // to the fact that it is stored internally as a float, and so would require conversion // if returned from Context::getIntegerv. Since this conversion is already implemented // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling // application. switch (pname) { case GL_COMPRESSED_TEXTURE_FORMATS: { *type = GL_INT; *numParams = static_cast(caps.compressedTextureFormats.size()); return true; } case GL_SHADER_BINARY_FORMATS: { *type = GL_INT; *numParams = static_cast(caps.shaderBinaryFormats.size()); return true; } case GL_MAX_VERTEX_ATTRIBS: case GL_MAX_VERTEX_UNIFORM_VECTORS: case GL_MAX_VARYING_VECTORS: case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: case GL_MAX_TEXTURE_IMAGE_UNITS: case GL_MAX_FRAGMENT_UNIFORM_VECTORS: case GL_MAX_RENDERBUFFER_SIZE: case GL_NUM_SHADER_BINARY_FORMATS: case GL_NUM_COMPRESSED_TEXTURE_FORMATS: case GL_ARRAY_BUFFER_BINDING: case GL_FRAMEBUFFER_BINDING: // GL_FRAMEBUFFER_BINDING now equivalent to // GL_DRAW_FRAMEBUFFER_BINDING case GL_RENDERBUFFER_BINDING: case GL_CURRENT_PROGRAM: case GL_PACK_ALIGNMENT: case GL_UNPACK_ALIGNMENT: case GL_GENERATE_MIPMAP_HINT: case GL_TEXTURE_FILTERING_HINT_CHROMIUM: case GL_RED_BITS: case GL_GREEN_BITS: case GL_BLUE_BITS: case GL_ALPHA_BITS: case GL_DEPTH_BITS: case GL_STENCIL_BITS: case GL_ELEMENT_ARRAY_BUFFER_BINDING: case GL_CULL_FACE_MODE: case GL_FRONT_FACE: case GL_ACTIVE_TEXTURE: case GL_STENCIL_FUNC: case GL_STENCIL_VALUE_MASK: case GL_STENCIL_REF: case GL_STENCIL_FAIL: case GL_STENCIL_PASS_DEPTH_FAIL: case GL_STENCIL_PASS_DEPTH_PASS: case GL_STENCIL_BACK_FUNC: case GL_STENCIL_BACK_VALUE_MASK: case GL_STENCIL_BACK_REF: case GL_STENCIL_BACK_FAIL: case GL_STENCIL_BACK_PASS_DEPTH_FAIL: case GL_STENCIL_BACK_PASS_DEPTH_PASS: case GL_DEPTH_FUNC: case GL_BLEND_SRC_RGB: case GL_BLEND_SRC_ALPHA: case GL_BLEND_DST_RGB: case GL_BLEND_DST_ALPHA: case GL_BLEND_EQUATION_RGB: case GL_BLEND_EQUATION_ALPHA: case GL_STENCIL_WRITEMASK: case GL_STENCIL_BACK_WRITEMASK: case GL_STENCIL_CLEAR_VALUE: case GL_SUBPIXEL_BITS: case GL_MAX_TEXTURE_SIZE: case GL_MAX_CUBE_MAP_TEXTURE_SIZE: case GL_SAMPLE_BUFFERS: case GL_SAMPLES: case GL_IMPLEMENTATION_COLOR_READ_TYPE: case GL_IMPLEMENTATION_COLOR_READ_FORMAT: case GL_TEXTURE_BINDING_2D: case GL_TEXTURE_BINDING_CUBE_MAP: case GL_RESET_NOTIFICATION_STRATEGY_EXT: { *type = GL_INT; *numParams = 1; return true; } case GL_PACK_REVERSE_ROW_ORDER_ANGLE: { if (!extensions.packReverseRowOrder) { return false; } *type = GL_INT; *numParams = 1; return true; } case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE: case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: { if (!extensions.textureRectangle) { return false; } *type = GL_INT; *numParams = 1; return true; } case GL_MAX_DRAW_BUFFERS_EXT: case GL_MAX_COLOR_ATTACHMENTS_EXT: { if ((clientMajorVersion < 3) && !extensions.drawBuffers) { return false; } *type = GL_INT; *numParams = 1; return true; } case GL_MAX_VIEWPORT_DIMS: { *type = GL_INT; *numParams = 2; return true; } case GL_VIEWPORT: case GL_SCISSOR_BOX: { *type = GL_INT; *numParams = 4; return true; } case GL_SHADER_COMPILER: case GL_SAMPLE_COVERAGE_INVERT: case GL_DEPTH_WRITEMASK: case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled, case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries. case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as // bool-natural case GL_SAMPLE_COVERAGE: case GL_SCISSOR_TEST: case GL_STENCIL_TEST: case GL_DEPTH_TEST: case GL_BLEND: case GL_DITHER: case GL_CONTEXT_ROBUST_ACCESS_EXT: { *type = GL_BOOL; *numParams = 1; return true; } case GL_COLOR_WRITEMASK: { *type = GL_BOOL; *numParams = 4; return true; } case GL_POLYGON_OFFSET_FACTOR: case GL_POLYGON_OFFSET_UNITS: case GL_SAMPLE_COVERAGE_VALUE: case GL_DEPTH_CLEAR_VALUE: case GL_LINE_WIDTH: { *type = GL_FLOAT; *numParams = 1; return true; } case GL_ALIASED_LINE_WIDTH_RANGE: case GL_ALIASED_POINT_SIZE_RANGE: case GL_DEPTH_RANGE: { *type = GL_FLOAT; *numParams = 2; return true; } case GL_COLOR_CLEAR_VALUE: case GL_BLEND_COLOR: { *type = GL_FLOAT; *numParams = 4; return true; } case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: if (!extensions.textureFilterAnisotropic) { return false; } *type = GL_FLOAT; *numParams = 1; return true; case GL_TIMESTAMP_EXT: if (!extensions.disjointTimerQuery) { return false; } *type = GL_INT_64_ANGLEX; *numParams = 1; return true; case GL_GPU_DISJOINT_EXT: if (!extensions.disjointTimerQuery) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_COVERAGE_MODULATION_CHROMIUM: if (!extensions.framebufferMixedSamples) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_TEXTURE_BINDING_EXTERNAL_OES: if (!extensions.eglStreamConsumerExternalNV && !extensions.eglImageExternalOES) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_MAX_CLIP_DISTANCES_EXT: // case GL_MAX_CLIP_PLANES if (clientMajorVersion < 2) { break; } if (!extensions.clipDistanceAPPLE) { // NOTE(hqle): if client version is 1. GL_MAX_CLIP_DISTANCES_EXT is equal // to GL_MAX_CLIP_PLANES which is a valid enum. return false; } *type = GL_INT; *numParams = 1; return true; case GL_MAX_CULL_DISTANCES_EXT: case GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT: if (!extensions.clipCullDistanceEXT) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_CLIP_ORIGIN_EXT: case GL_CLIP_DEPTH_MODE_EXT: if (!extensions.clipControlEXT) { return false; } *type = GL_INT; *numParams = 1; return true; } if (glState.getClientType() == EGL_OPENGL_API) { switch (pname) { case GL_CONTEXT_FLAGS: case GL_CONTEXT_PROFILE_MASK: { *type = GL_INT; *numParams = 1; return true; } } } if (extensions.debug) { switch (pname) { case GL_DEBUG_LOGGED_MESSAGES: case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: case GL_DEBUG_GROUP_STACK_DEPTH: case GL_MAX_DEBUG_MESSAGE_LENGTH: case GL_MAX_DEBUG_LOGGED_MESSAGES: case GL_MAX_DEBUG_GROUP_STACK_DEPTH: case GL_MAX_LABEL_LENGTH: *type = GL_INT; *numParams = 1; return true; case GL_DEBUG_OUTPUT_SYNCHRONOUS: case GL_DEBUG_OUTPUT: *type = GL_BOOL; *numParams = 1; return true; } } if (extensions.multisampleCompatibility) { switch (pname) { case GL_MULTISAMPLE_EXT: case GL_SAMPLE_ALPHA_TO_ONE_EXT: *type = GL_BOOL; *numParams = 1; return true; } } if (extensions.bindGeneratesResource) { switch (pname) { case GL_BIND_GENERATES_RESOURCE_CHROMIUM: *type = GL_BOOL; *numParams = 1; return true; } } if (extensions.clientArrays) { switch (pname) { case GL_CLIENT_ARRAYS_ANGLE: *type = GL_BOOL; *numParams = 1; return true; } } if (extensions.sRGBWriteControl) { switch (pname) { case GL_FRAMEBUFFER_SRGB_EXT: *type = GL_BOOL; *numParams = 1; return true; } } if (extensions.robustResourceInitialization && pname == GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE) { *type = GL_BOOL; *numParams = 1; return true; } if (extensions.programCacheControl && pname == GL_PROGRAM_CACHE_ENABLED_ANGLE) { *type = GL_BOOL; *numParams = 1; return true; } if (extensions.parallelShaderCompile && pname == GL_MAX_SHADER_COMPILER_THREADS_KHR) { *type = GL_INT; *numParams = 1; return true; } if (extensions.blendFuncExtended && pname == GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT) { *type = GL_INT; *numParams = 1; return true; } // Check for ES3.0+ parameter names which are also exposed as ES2 extensions switch (pname) { // GL_DRAW_FRAMEBUFFER_BINDING equivalent to GL_FRAMEBUFFER_BINDING case GL_READ_FRAMEBUFFER_BINDING: if ((clientMajorVersion < 3) && !extensions.framebufferBlitAny()) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_NUM_PROGRAM_BINARY_FORMATS_OES: if ((clientMajorVersion < 3) && !extensions.getProgramBinaryOES) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_PROGRAM_BINARY_FORMATS_OES: if ((clientMajorVersion < 3) && !extensions.getProgramBinaryOES) { return false; } *type = GL_INT; *numParams = static_cast(caps.programBinaryFormats.size()); return true; case GL_PACK_ROW_LENGTH: case GL_PACK_SKIP_ROWS: case GL_PACK_SKIP_PIXELS: if ((clientMajorVersion < 3) && !extensions.packSubimage) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_UNPACK_ROW_LENGTH: case GL_UNPACK_SKIP_ROWS: case GL_UNPACK_SKIP_PIXELS: if ((clientMajorVersion < 3) && !extensions.unpackSubimage) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_VERTEX_ARRAY_BINDING: if ((clientMajorVersion < 3) && !extensions.vertexArrayObjectOES) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_PIXEL_PACK_BUFFER_BINDING: case GL_PIXEL_UNPACK_BUFFER_BINDING: if ((clientMajorVersion < 3) && !extensions.pixelBufferObjectNV) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_MAX_SAMPLES: { static_assert(GL_MAX_SAMPLES_ANGLE == GL_MAX_SAMPLES, "GL_MAX_SAMPLES_ANGLE not equal to GL_MAX_SAMPLES"); if ((clientMajorVersion < 3) && !(extensions.framebufferMultisample || extensions.multisampledRenderToTexture)) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: if ((clientMajorVersion < 3) && !extensions.standardDerivativesOES) { return false; } *type = GL_INT; *numParams = 1; return true; } case GL_TEXTURE_BINDING_3D: if ((clientMajorVersion < 3) && !extensions.texture3DOES) { return false; } *type = GL_INT; *numParams = 1; return true; case GL_MAX_3D_TEXTURE_SIZE: if ((clientMajorVersion < 3) && !extensions.texture3DOES) { return false; } *type = GL_INT; *numParams = 1; return true; } if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) { if ((glState.getClientVersion() < Version(3, 0)) && !extensions.drawBuffers) { return false; } *type = GL_INT; *numParams = 1; return true; } if ((extensions.multiview2 || extensions.multiview) && pname == GL_MAX_VIEWS_OVR) { *type = GL_INT; *numParams = 1; return true; } if (glState.getClientVersion() < Version(2, 0)) { switch (pname) { case GL_ALPHA_TEST_FUNC: case GL_CLIENT_ACTIVE_TEXTURE: case GL_MATRIX_MODE: case GL_MAX_TEXTURE_UNITS: case GL_MAX_MODELVIEW_STACK_DEPTH: case GL_MAX_PROJECTION_STACK_DEPTH: case GL_MAX_TEXTURE_STACK_DEPTH: case GL_MAX_LIGHTS: case GL_MAX_CLIP_PLANES: case GL_VERTEX_ARRAY_STRIDE: case GL_NORMAL_ARRAY_STRIDE: case GL_COLOR_ARRAY_STRIDE: case GL_TEXTURE_COORD_ARRAY_STRIDE: case GL_VERTEX_ARRAY_SIZE: case GL_COLOR_ARRAY_SIZE: case GL_TEXTURE_COORD_ARRAY_SIZE: case GL_VERTEX_ARRAY_TYPE: case GL_NORMAL_ARRAY_TYPE: case GL_COLOR_ARRAY_TYPE: case GL_TEXTURE_COORD_ARRAY_TYPE: case GL_VERTEX_ARRAY_BUFFER_BINDING: case GL_NORMAL_ARRAY_BUFFER_BINDING: case GL_COLOR_ARRAY_BUFFER_BINDING: case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING: case GL_POINT_SIZE_ARRAY_STRIDE_OES: case GL_POINT_SIZE_ARRAY_TYPE_OES: case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES: case GL_SHADE_MODEL: case GL_MODELVIEW_STACK_DEPTH: case GL_PROJECTION_STACK_DEPTH: case GL_TEXTURE_STACK_DEPTH: case GL_LOGIC_OP_MODE: case GL_BLEND_SRC: case GL_BLEND_DST: case GL_PERSPECTIVE_CORRECTION_HINT: case GL_POINT_SMOOTH_HINT: case GL_LINE_SMOOTH_HINT: case GL_FOG_HINT: *type = GL_INT; *numParams = 1; return true; case GL_ALPHA_TEST_REF: case GL_FOG_DENSITY: case GL_FOG_START: case GL_FOG_END: case GL_FOG_MODE: case GL_POINT_SIZE: case GL_POINT_SIZE_MIN: case GL_POINT_SIZE_MAX: case GL_POINT_FADE_THRESHOLD_SIZE: *type = GL_FLOAT; *numParams = 1; return true; case GL_SMOOTH_POINT_SIZE_RANGE: case GL_SMOOTH_LINE_WIDTH_RANGE: *type = GL_FLOAT; *numParams = 2; return true; case GL_CURRENT_COLOR: case GL_CURRENT_TEXTURE_COORDS: case GL_LIGHT_MODEL_AMBIENT: case GL_FOG_COLOR: *type = GL_FLOAT; *numParams = 4; return true; case GL_CURRENT_NORMAL: case GL_POINT_DISTANCE_ATTENUATION: *type = GL_FLOAT; *numParams = 3; return true; case GL_MODELVIEW_MATRIX: case GL_PROJECTION_MATRIX: case GL_TEXTURE_MATRIX: *type = GL_FLOAT; *numParams = 16; return true; case GL_LIGHT_MODEL_TWO_SIDE: *type = GL_BOOL; *numParams = 1; return true; } } if (glState.getClientVersion() < Version(3, 0)) { return false; } // Check for ES3.0+ parameter names switch (pname) { case GL_MAX_UNIFORM_BUFFER_BINDINGS: case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: case GL_UNIFORM_BUFFER_BINDING: case GL_TRANSFORM_FEEDBACK_BINDING: case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: case GL_COPY_READ_BUFFER_BINDING: case GL_COPY_WRITE_BUFFER_BINDING: case GL_SAMPLER_BINDING: case GL_READ_BUFFER: case GL_TEXTURE_BINDING_3D: case GL_TEXTURE_BINDING_2D_ARRAY: case GL_MAX_ARRAY_TEXTURE_LAYERS: case GL_MAX_VERTEX_UNIFORM_BLOCKS: case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: case GL_MAX_COMBINED_UNIFORM_BLOCKS: case GL_MAX_VERTEX_OUTPUT_COMPONENTS: case GL_MAX_FRAGMENT_INPUT_COMPONENTS: case GL_MAX_VARYING_COMPONENTS: case GL_MAX_VERTEX_UNIFORM_COMPONENTS: case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: case GL_MIN_PROGRAM_TEXEL_OFFSET: case GL_MAX_PROGRAM_TEXEL_OFFSET: case GL_NUM_EXTENSIONS: case GL_MAJOR_VERSION: case GL_MINOR_VERSION: case GL_MAX_ELEMENTS_INDICES: case GL_MAX_ELEMENTS_VERTICES: case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: case GL_UNPACK_IMAGE_HEIGHT: case GL_UNPACK_SKIP_IMAGES: case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES: { *type = GL_INT; *numParams = 1; return true; } case GL_MAX_ELEMENT_INDEX: case GL_MAX_UNIFORM_BLOCK_SIZE: case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: case GL_MAX_SERVER_WAIT_TIMEOUT: { *type = GL_INT_64_ANGLEX; *numParams = 1; return true; } case GL_TRANSFORM_FEEDBACK_ACTIVE: case GL_TRANSFORM_FEEDBACK_PAUSED: case GL_PRIMITIVE_RESTART_FIXED_INDEX: case GL_RASTERIZER_DISCARD: { *type = GL_BOOL; *numParams = 1; return true; } case GL_MAX_TEXTURE_LOD_BIAS: case GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES: case GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES: { *type = GL_FLOAT; *numParams = 1; return true; } } if (extensions.requestExtension) { switch (pname) { case GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE: *type = GL_INT; *numParams = 1; return true; } } if (extensions.textureMultisample) { switch (pname) { case GL_MAX_COLOR_TEXTURE_SAMPLES_ANGLE: case GL_MAX_INTEGER_SAMPLES_ANGLE: case GL_MAX_DEPTH_TEXTURE_SAMPLES_ANGLE: case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ANGLE: case GL_MAX_SAMPLE_MASK_WORDS: *type = GL_INT; *numParams = 1; return true; } } if (extensions.textureCubeMapArrayAny()) { switch (pname) { case GL_TEXTURE_BINDING_CUBE_MAP_ARRAY: *type = GL_INT; *numParams = 1; return true; } } if (extensions.textureBufferAny()) { switch (pname) { case GL_TEXTURE_BUFFER_BINDING: case GL_TEXTURE_BINDING_BUFFER: case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT: case GL_MAX_TEXTURE_BUFFER_SIZE: *type = GL_INT; *numParams = 1; return true; } } if (glState.getClientVersion() < Version(3, 1)) { return false; } // Check for ES3.1+ parameter names switch (pname) { case GL_ATOMIC_COUNTER_BUFFER_BINDING: case GL_DRAW_INDIRECT_BUFFER_BINDING: case GL_DISPATCH_INDIRECT_BUFFER_BINDING: case GL_MAX_FRAMEBUFFER_WIDTH: case GL_MAX_FRAMEBUFFER_HEIGHT: case GL_MAX_FRAMEBUFFER_SAMPLES: case GL_MAX_SAMPLE_MASK_WORDS: case GL_MAX_COLOR_TEXTURE_SAMPLES: case GL_MAX_DEPTH_TEXTURE_SAMPLES: case GL_MAX_INTEGER_SAMPLES: case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: case GL_MAX_VERTEX_ATTRIB_BINDINGS: case GL_MAX_VERTEX_ATTRIB_STRIDE: case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: case GL_MAX_VERTEX_ATOMIC_COUNTERS: case GL_MAX_VERTEX_IMAGE_UNIFORMS: case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: case GL_MAX_FRAGMENT_IMAGE_UNIFORMS: case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: case GL_MAX_COMPUTE_UNIFORM_BLOCKS: case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: case GL_MAX_COMPUTE_ATOMIC_COUNTERS: case GL_MAX_COMPUTE_IMAGE_UNIFORMS: case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: case GL_MAX_UNIFORM_LOCATIONS: case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: case GL_MAX_COMBINED_ATOMIC_COUNTERS: case GL_MAX_IMAGE_UNITS: case GL_MAX_COMBINED_IMAGE_UNIFORMS: case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: case GL_SHADER_STORAGE_BUFFER_BINDING: case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: case GL_TEXTURE_BINDING_2D_MULTISAMPLE: case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY: case GL_PROGRAM_PIPELINE_BINDING: *type = GL_INT; *numParams = 1; return true; case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: *type = GL_INT_64_ANGLEX; *numParams = 1; return true; case GL_SAMPLE_MASK: case GL_SAMPLE_SHADING: *type = GL_BOOL; *numParams = 1; return true; case GL_MIN_SAMPLE_SHADING_VALUE: *type = GL_FLOAT; *numParams = 1; return true; } if (extensions.geometryShader) { switch (pname) { case GL_MAX_FRAMEBUFFER_LAYERS_EXT: case GL_LAYER_PROVOKING_VERTEX_EXT: case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT: case GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT: case GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT: case GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT: case GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT: case GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT: case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT: case GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT: case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT: case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT: case GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT: case GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT: case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT: *type = GL_INT; *numParams = 1; return true; } } if (extensions.tessellationShaderEXT) { switch (pname) { case GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED: *type = GL_BOOL; *numParams = 1; return true; case GL_PATCH_VERTICES: case GL_MAX_PATCH_VERTICES_EXT: case GL_MAX_TESS_GEN_LEVEL_EXT: case GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT: case GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT: case GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT: case GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT: case GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT: case GL_MAX_TESS_PATCH_COMPONENTS_EXT: case GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT: case GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT: case GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT: case GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT: case GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT: case GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT: case GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT: case GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT: case GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT: case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT: case GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT: case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT: case GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT: case GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT: case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT: case GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT: *type = GL_INT; *numParams = 1; return true; } } return false; } void QueryProgramPipelineiv(const Context *context, ProgramPipeline *programPipeline, GLenum pname, GLint *params) { if (!params) { // Can't write the result anywhere, so just return immediately. return; } switch (pname) { case GL_ACTIVE_PROGRAM: { // the name of the active program object of the program pipeline object is returned in // params *params = 0; if (programPipeline) { const Program *program = programPipeline->getActiveShaderProgram(); if (program) { *params = program->id().value; } } break; } case GL_VERTEX_SHADER: { // the name of the current program object for the vertex shader type of the program // pipeline object is returned in params *params = 0; if (programPipeline) { const Program *program = programPipeline->getShaderProgram(ShaderType::Vertex); if (program) { *params = program->id().value; } } break; } case GL_FRAGMENT_SHADER: { // the name of the current program object for the fragment shader type of the program // pipeline object is returned in params *params = 0; if (programPipeline) { const Program *program = programPipeline->getShaderProgram(ShaderType::Fragment); if (program) { *params = program->id().value; } } break; } case GL_COMPUTE_SHADER: { // the name of the current program object for the compute shader type of the program // pipeline object is returned in params *params = 0; if (programPipeline) { const Program *program = programPipeline->getShaderProgram(ShaderType::Compute); if (program) { *params = program->id().value; } } break; } case GL_INFO_LOG_LENGTH: { // the length of the info log, including the null terminator, is returned in params. If // there is no info log, zero is returned. *params = 0; if (programPipeline) { *params = programPipeline->getExecutable().getInfoLogLength(); } break; } case GL_VALIDATE_STATUS: { // the validation status of pipeline, as determined by glValidateProgramPipeline, is // returned in params *params = 0; if (programPipeline) { *params = programPipeline->isValid(); } break; } default: break; } } } // namespace gl namespace egl { void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value) { ASSERT(config != nullptr); switch (attribute) { case EGL_BUFFER_SIZE: *value = config->bufferSize; break; case EGL_ALPHA_SIZE: *value = config->alphaSize; break; case EGL_BLUE_SIZE: *value = config->blueSize; break; case EGL_GREEN_SIZE: *value = config->greenSize; break; case EGL_RED_SIZE: *value = config->redSize; break; case EGL_DEPTH_SIZE: *value = config->depthSize; break; case EGL_STENCIL_SIZE: *value = config->stencilSize; break; case EGL_CONFIG_CAVEAT: *value = config->configCaveat; break; case EGL_CONFIG_ID: *value = config->configID; break; case EGL_LEVEL: *value = config->level; break; case EGL_NATIVE_RENDERABLE: *value = config->nativeRenderable; break; case EGL_NATIVE_VISUAL_ID: *value = config->nativeVisualID; break; case EGL_NATIVE_VISUAL_TYPE: *value = config->nativeVisualType; break; case EGL_SAMPLES: *value = config->samples; break; case EGL_SAMPLE_BUFFERS: *value = config->sampleBuffers; break; case EGL_SURFACE_TYPE: *value = config->surfaceType; break; case EGL_BIND_TO_TEXTURE_TARGET_ANGLE: *value = config->bindToTextureTarget; break; case EGL_TRANSPARENT_TYPE: *value = config->transparentType; break; case EGL_TRANSPARENT_BLUE_VALUE: *value = config->transparentBlueValue; break; case EGL_TRANSPARENT_GREEN_VALUE: *value = config->transparentGreenValue; break; case EGL_TRANSPARENT_RED_VALUE: *value = config->transparentRedValue; break; case EGL_BIND_TO_TEXTURE_RGB: *value = config->bindToTextureRGB; break; case EGL_BIND_TO_TEXTURE_RGBA: *value = config->bindToTextureRGBA; break; case EGL_MIN_SWAP_INTERVAL: *value = config->minSwapInterval; break; case EGL_MAX_SWAP_INTERVAL: *value = config->maxSwapInterval; break; case EGL_LUMINANCE_SIZE: *value = config->luminanceSize; break; case EGL_ALPHA_MASK_SIZE: *value = config->alphaMaskSize; break; case EGL_COLOR_BUFFER_TYPE: *value = config->colorBufferType; break; case EGL_RENDERABLE_TYPE: *value = config->renderableType; break; case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; case EGL_CONFORMANT: *value = config->conformant; break; case EGL_MAX_PBUFFER_WIDTH: *value = config->maxPBufferWidth; break; case EGL_MAX_PBUFFER_HEIGHT: *value = config->maxPBufferHeight; break; case EGL_MAX_PBUFFER_PIXELS: *value = config->maxPBufferPixels; break; case EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE: *value = config->optimalOrientation; break; case EGL_COLOR_COMPONENT_TYPE_EXT: *value = config->colorComponentType; break; case EGL_RECORDABLE_ANDROID: *value = config->recordable; break; case EGL_FRAMEBUFFER_TARGET_ANDROID: *value = config->framebufferTarget; break; default: UNREACHABLE(); break; } } void QueryContextAttrib(const gl::Context *context, EGLint attribute, EGLint *value) { switch (attribute) { case EGL_CONFIG_ID: if (context->getConfig() != EGL_NO_CONFIG_KHR) { *value = context->getConfig()->configID; } else { *value = 0; } break; case EGL_CONTEXT_CLIENT_TYPE: *value = context->getClientType(); break; case EGL_CONTEXT_CLIENT_VERSION: *value = context->getClientMajorVersion(); break; case EGL_RENDER_BUFFER: *value = context->getRenderBuffer(); break; case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: *value = context->isRobustResourceInitEnabled(); break; case EGL_CONTEXT_PRIORITY_LEVEL_IMG: *value = static_cast(context->getContextPriority()); break; default: UNREACHABLE(); break; } } egl::Error QuerySurfaceAttrib(const Display *display, const gl::Context *context, const Surface *surface, EGLint attribute, EGLint *value) { switch (attribute) { case EGL_GL_COLORSPACE: *value = surface->getGLColorspace(); break; case EGL_VG_ALPHA_FORMAT: *value = surface->getVGAlphaFormat(); break; case EGL_VG_COLORSPACE: *value = surface->getVGColorspace(); break; case EGL_CONFIG_ID: *value = surface->getConfig()->configID; break; case EGL_HEIGHT: ANGLE_TRY(surface->getUserHeight(display, value)); break; case EGL_HORIZONTAL_RESOLUTION: *value = surface->getHorizontalResolution(); break; case EGL_LARGEST_PBUFFER: // The EGL spec states that value is not written if the surface is not a pbuffer if (surface->getType() == EGL_PBUFFER_BIT) { *value = surface->getLargestPbuffer(); } break; case EGL_MIPMAP_TEXTURE: // The EGL spec states that value is not written if the surface is not a pbuffer if (surface->getType() == EGL_PBUFFER_BIT) { *value = surface->getMipmapTexture(); } break; case EGL_MIPMAP_LEVEL: // The EGL spec states that value is not written if the surface is not a pbuffer if (surface->getType() == EGL_PBUFFER_BIT) { *value = surface->getMipmapLevel(); } break; case EGL_MULTISAMPLE_RESOLVE: *value = surface->getMultisampleResolve(); break; case EGL_PIXEL_ASPECT_RATIO: *value = surface->getPixelAspectRatio(); break; case EGL_RENDER_BUFFER: *value = surface->getRenderBuffer(); break; case EGL_SWAP_BEHAVIOR: *value = surface->getSwapBehavior(); break; case EGL_TEXTURE_FORMAT: // The EGL spec states that value is not written if the surface is not a pbuffer if (surface->getType() == EGL_PBUFFER_BIT) { *value = ToEGLenum(surface->getTextureFormat()); } break; case EGL_TEXTURE_TARGET: // The EGL spec states that value is not written if the surface is not a pbuffer if (surface->getType() == EGL_PBUFFER_BIT) { *value = surface->getTextureTarget(); } break; case EGL_VERTICAL_RESOLUTION: *value = surface->getVerticalResolution(); break; case EGL_WIDTH: ANGLE_TRY(surface->getUserWidth(display, value)); break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: *value = surface->isPostSubBufferSupported(); break; case EGL_FIXED_SIZE_ANGLE: *value = surface->isFixedSize(); break; case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE: *value = surface->flexibleSurfaceCompatibilityRequested(); break; case EGL_SURFACE_ORIENTATION_ANGLE: *value = surface->getOrientation(); break; case EGL_DIRECT_COMPOSITION_ANGLE: *value = surface->directComposition(); break; case EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE: *value = surface->isRobustResourceInitEnabled(); break; case EGL_TIMESTAMPS_ANDROID: *value = surface->isTimestampsEnabled(); break; case EGL_BUFFER_AGE_EXT: ANGLE_TRY(surface->getBufferAge(context, value)); break; default: UNREACHABLE(); break; } return NoError(); } void SetSurfaceAttrib(Surface *surface, EGLint attribute, EGLint value) { switch (attribute) { case EGL_MIPMAP_LEVEL: surface->setMipmapLevel(value); break; case EGL_MULTISAMPLE_RESOLVE: surface->setMultisampleResolve(value); break; case EGL_SWAP_BEHAVIOR: surface->setSwapBehavior(value); break; case EGL_WIDTH: surface->setFixedWidth(value); break; case EGL_HEIGHT: surface->setFixedHeight(value); break; case EGL_TIMESTAMPS_ANDROID: surface->setTimestampsEnabled(value != EGL_FALSE); break; default: UNREACHABLE(); break; } } Error GetSyncAttrib(Display *display, Sync *sync, EGLint attribute, EGLint *value) { switch (attribute) { case EGL_SYNC_TYPE_KHR: *value = sync->getType(); return NoError(); case EGL_SYNC_STATUS_KHR: return sync->getStatus(display, value); case EGL_SYNC_CONDITION_KHR: *value = sync->getCondition(); return NoError(); default: break; } UNREACHABLE(); return NoError(); } } // namespace egl