| // | |
| // Copyright 2019 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. | |
| // | |
| // validationESEXT.cpp: Validation functions for OpenGL ES extension entry points. | |
| #include "libANGLE/validationESEXT_autogen.h" | |
| #include "libANGLE/Context.h" | |
| #include "libANGLE/ErrorStrings.h" | |
| #include "libANGLE/MemoryObject.h" | |
| #include "libANGLE/validationES.h" | |
| #include "libANGLE/validationES2.h" | |
| #include "libANGLE/validationES3.h" | |
| #include "libANGLE/validationES31.h" | |
| #include "libANGLE/validationES32.h" | |
| namespace gl | |
| { | |
| using namespace err; | |
| namespace | |
| { | |
| template <typename ObjectT> | |
| bool ValidateGetImageFormatAndType(const Context *context, ObjectT *obj, GLenum format, GLenum type) | |
| { | |
| GLenum implFormat = obj->getImplementationColorReadFormat(context); | |
| if (!ValidES3Format(format) && (format != implFormat || format == GL_NONE)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidFormat); | |
| return false; | |
| } | |
| GLenum implType = obj->getImplementationColorReadType(context); | |
| if (!ValidES3Type(type) && (type != implType || type == GL_NONE)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| // Format/type combinations are not yet validated. | |
| return true; | |
| } | |
| bool IsValidImageLayout(ImageLayout layout) | |
| { | |
| switch (layout) | |
| { | |
| case ImageLayout::Undefined: | |
| case ImageLayout::General: | |
| case ImageLayout::ColorAttachment: | |
| case ImageLayout::DepthStencilAttachment: | |
| case ImageLayout::DepthStencilReadOnlyAttachment: | |
| case ImageLayout::ShaderReadOnly: | |
| case ImageLayout::TransferSrc: | |
| case ImageLayout::TransferDst: | |
| case ImageLayout::DepthReadOnlyStencilAttachment: | |
| case ImageLayout::DepthAttachmentStencilReadOnly: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| bool IsValidMemoryObjectParamater(const Context *context, GLenum pname) | |
| { | |
| switch (pname) | |
| { | |
| case GL_DEDICATED_MEMORY_OBJECT_EXT: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| bool ValidateObjectIdentifierAndName(const Context *context, GLenum identifier, GLuint name) | |
| { | |
| bool isGLES11 = context->getClientVersion() == Version(1, 1); | |
| bool isGLES3 = context->getClientMajorVersion() >= 3; | |
| bool isGLES31 = context->getClientVersion() >= Version(3, 1); | |
| switch (identifier) | |
| { | |
| case GL_BUFFER_OBJECT_EXT: | |
| if (context->getBuffer({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidBufferName); | |
| return false; | |
| } | |
| return true; | |
| case GL_SHADER_OBJECT_EXT: | |
| if (isGLES11) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getShader({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidShaderName); | |
| return false; | |
| } | |
| return true; | |
| case GL_PROGRAM_OBJECT_EXT: | |
| if (isGLES11) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getProgramNoResolveLink({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidProgramName); | |
| return false; | |
| } | |
| return true; | |
| case GL_VERTEX_ARRAY_OBJECT_EXT: | |
| if (!isGLES3 && !context->getExtensions().vertexArrayObjectOES) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getVertexArray({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidVertexArrayName); | |
| return false; | |
| } | |
| return true; | |
| case GL_QUERY_OBJECT_EXT: | |
| if (!isGLES3 && !context->getExtensions().occlusionQueryBoolean) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getQuery({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidQueryName); | |
| return false; | |
| } | |
| return true; | |
| case GL_TRANSFORM_FEEDBACK: | |
| if (!isGLES3) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getTransformFeedback({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidTransformFeedbackName); | |
| return false; | |
| } | |
| return true; | |
| case GL_SAMPLER: | |
| if (!isGLES3) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getSampler({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidSamplerName); | |
| return false; | |
| } | |
| return true; | |
| case GL_TEXTURE: | |
| if (context->getTexture({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidTextureName); | |
| return false; | |
| } | |
| return true; | |
| case GL_RENDERBUFFER: | |
| if (!context->isRenderbuffer({name})) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidRenderbufferName); | |
| return false; | |
| } | |
| return true; | |
| case GL_FRAMEBUFFER: | |
| if (context->getFramebuffer({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidFramebufferName); | |
| return false; | |
| } | |
| return true; | |
| case GL_PROGRAM_PIPELINE_OBJECT_EXT: | |
| if (!isGLES31 && !context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidType); | |
| return false; | |
| } | |
| if (context->getProgramPipeline({name}) == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kInvalidProgramPipelineName); | |
| return false; | |
| } | |
| return true; | |
| default: | |
| context->validationError(GL_INVALID_ENUM, kInvalidIndentifier); | |
| return false; | |
| } | |
| } | |
| } // namespace | |
| bool ValidateGetTexImageANGLE(const Context *context, | |
| TextureTarget target, | |
| GLint level, | |
| GLenum format, | |
| GLenum type, | |
| const void *pixels) | |
| { | |
| if (!context->getExtensions().getImageANGLE) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kGetImageExtensionNotEnabled); | |
| return false; | |
| } | |
| if (!ValidTexture2DDestinationTarget(context, target) && | |
| !ValidTexture3DDestinationTarget(context, target)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidTextureTarget); | |
| return false; | |
| } | |
| if (level < 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kNegativeLevel); | |
| return false; | |
| } | |
| TextureType textureType = TextureTargetToType(target); | |
| if (!ValidMipLevel(context, textureType, level)) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidMipLevel); | |
| return false; | |
| } | |
| Texture *texture = context->getTextureByTarget(target); | |
| if (!ValidateGetImageFormatAndType(context, texture, format, type)) | |
| { | |
| return false; | |
| } | |
| GLsizei width = static_cast<GLsizei>(texture->getWidth(target, level)); | |
| GLsizei height = static_cast<GLsizei>(texture->getHeight(target, level)); | |
| if (!ValidatePixelPack(context, format, type, 0, 0, width, height, -1, nullptr, pixels)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateGetRenderbufferImageANGLE(const Context *context, | |
| GLenum target, | |
| GLenum format, | |
| GLenum type, | |
| const void *pixels) | |
| { | |
| if (!context->getExtensions().getImageANGLE) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kGetImageExtensionNotEnabled); | |
| return false; | |
| } | |
| if (target != GL_RENDERBUFFER) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidRenderbufferTarget); | |
| return false; | |
| } | |
| Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); | |
| if (!ValidateGetImageFormatAndType(context, renderbuffer, format, type)) | |
| { | |
| return false; | |
| } | |
| GLsizei width = renderbuffer->getWidth(); | |
| GLsizei height = renderbuffer->getHeight(); | |
| if (!ValidatePixelPack(context, format, type, 0, 0, width, height, -1, nullptr, pixels)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateDrawElementsBaseVertexEXT(const Context *context, | |
| PrimitiveMode mode, | |
| GLsizei count, | |
| DrawElementsType type, | |
| const void *indices, | |
| GLint basevertex) | |
| { | |
| if (!context->getExtensions().drawElementsBaseVertexAny()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDrawElementsCommon(context, mode, count, type, indices, 1); | |
| } | |
| bool ValidateDrawElementsInstancedBaseVertexEXT(const Context *context, | |
| PrimitiveMode mode, | |
| GLsizei count, | |
| DrawElementsType type, | |
| const void *indices, | |
| GLsizei instancecount, | |
| GLint basevertex) | |
| { | |
| if (!context->getExtensions().drawElementsBaseVertexAny()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, instancecount); | |
| } | |
| bool ValidateDrawRangeElementsBaseVertexEXT(const Context *context, | |
| PrimitiveMode mode, | |
| GLuint start, | |
| GLuint end, | |
| GLsizei count, | |
| DrawElementsType type, | |
| const void *indices, | |
| GLint basevertex) | |
| { | |
| if (!context->getExtensions().drawElementsBaseVertexAny()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| if (end < start) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidElementRange); | |
| return false; | |
| } | |
| if (!ValidateDrawElementsCommon(context, mode, count, type, indices, 0)) | |
| { | |
| return false; | |
| } | |
| // Skip range checks for no-op calls. | |
| if (count <= 0) | |
| { | |
| return true; | |
| } | |
| // Note that resolving the index range is a bit slow. We should probably optimize this. | |
| IndexRange indexRange; | |
| ANGLE_VALIDATION_TRY(context->getState().getVertexArray()->getIndexRange(context, type, count, | |
| indices, &indexRange)); | |
| if (indexRange.end > end || indexRange.start < start) | |
| { | |
| // GL spec says that behavior in this case is undefined - generating an error is fine. | |
| context->validationError(GL_INVALID_OPERATION, kExceedsElementRange); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateMultiDrawElementsBaseVertexEXT(const Context *context, | |
| PrimitiveMode mode, | |
| const GLsizei *count, | |
| DrawElementsType type, | |
| const void *const *indices, | |
| GLsizei drawcount, | |
| const GLint *basevertex) | |
| { | |
| return true; | |
| } | |
| bool ValidateDrawElementsBaseVertexOES(const Context *context, | |
| PrimitiveMode mode, | |
| GLsizei count, | |
| DrawElementsType type, | |
| const void *indices, | |
| GLint basevertex) | |
| { | |
| if (!context->getExtensions().drawElementsBaseVertexAny()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDrawElementsCommon(context, mode, count, type, indices, 1); | |
| } | |
| bool ValidateDrawElementsInstancedBaseVertexOES(const Context *context, | |
| PrimitiveMode mode, | |
| GLsizei count, | |
| DrawElementsType type, | |
| const void *indices, | |
| GLsizei instancecount, | |
| GLint basevertex) | |
| { | |
| if (!context->getExtensions().drawElementsBaseVertexAny()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, instancecount); | |
| } | |
| bool ValidateDrawRangeElementsBaseVertexOES(const Context *context, | |
| PrimitiveMode mode, | |
| GLuint start, | |
| GLuint end, | |
| GLsizei count, | |
| DrawElementsType type, | |
| const void *indices, | |
| GLint basevertex) | |
| { | |
| if (!context->getExtensions().drawElementsBaseVertexAny()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| if (end < start) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidElementRange); | |
| return false; | |
| } | |
| if (!ValidateDrawElementsCommon(context, mode, count, type, indices, 0)) | |
| { | |
| return false; | |
| } | |
| // Skip range checks for no-op calls. | |
| if (count <= 0) | |
| { | |
| return true; | |
| } | |
| // Note that resolving the index range is a bit slow. We should probably optimize this. | |
| IndexRange indexRange; | |
| ANGLE_VALIDATION_TRY(context->getState().getVertexArray()->getIndexRange(context, type, count, | |
| indices, &indexRange)); | |
| if (indexRange.end > end || indexRange.start < start) | |
| { | |
| // GL spec says that behavior in this case is undefined - generating an error is fine. | |
| context->validationError(GL_INVALID_OPERATION, kExceedsElementRange); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // GL_KHR_blend_equation_advanced | |
| bool ValidateBlendBarrierKHR(const Context *context) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| bool ValidateBlendEquationSeparateiEXT(const Context *context, | |
| GLuint buf, | |
| GLenum modeRGB, | |
| GLenum modeAlpha) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendEquationSeparatei(context, buf, modeRGB, modeAlpha); | |
| } | |
| bool ValidateBlendEquationiEXT(const Context *context, GLuint buf, GLenum mode) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendEquationi(context, buf, mode); | |
| } | |
| bool ValidateBlendFuncSeparateiEXT(const Context *context, | |
| GLuint buf, | |
| GLenum srcRGB, | |
| GLenum dstRGB, | |
| GLenum srcAlpha, | |
| GLenum dstAlpha) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendFuncSeparatei(context, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); | |
| } | |
| bool ValidateBlendFunciEXT(const Context *context, GLuint buf, GLenum src, GLenum dst) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendFunci(context, buf, src, dst); | |
| } | |
| bool ValidateColorMaskiEXT(const Context *context, | |
| GLuint index, | |
| GLboolean r, | |
| GLboolean g, | |
| GLboolean b, | |
| GLboolean a) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateColorMaski(context, index, r, g, b, a); | |
| } | |
| bool ValidateDisableiEXT(const Context *context, GLenum target, GLuint index) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDisablei(context, target, index); | |
| } | |
| bool ValidateEnableiEXT(const Context *context, GLenum target, GLuint index) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateEnablei(context, target, index); | |
| } | |
| bool ValidateIsEnablediEXT(const Context *context, GLenum target, GLuint index) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateIsEnabledi(context, target, index); | |
| } | |
| bool ValidateBlendEquationSeparateiOES(const Context *context, | |
| GLuint buf, | |
| GLenum modeRGB, | |
| GLenum modeAlpha) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendEquationSeparatei(context, buf, modeRGB, modeAlpha); | |
| } | |
| bool ValidateBlendEquationiOES(const Context *context, GLuint buf, GLenum mode) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendEquationi(context, buf, mode); | |
| } | |
| bool ValidateBlendFuncSeparateiOES(const Context *context, | |
| GLuint buf, | |
| GLenum srcRGB, | |
| GLenum dstRGB, | |
| GLenum srcAlpha, | |
| GLenum dstAlpha) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendFuncSeparatei(context, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); | |
| } | |
| bool ValidateBlendFunciOES(const Context *context, GLuint buf, GLenum src, GLenum dst) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBlendFunci(context, buf, src, dst); | |
| } | |
| bool ValidateColorMaskiOES(const Context *context, | |
| GLuint index, | |
| GLboolean r, | |
| GLboolean g, | |
| GLboolean b, | |
| GLboolean a) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateColorMaski(context, index, r, g, b, a); | |
| } | |
| bool ValidateDisableiOES(const Context *context, GLenum target, GLuint index) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDisablei(context, target, index); | |
| } | |
| bool ValidateEnableiOES(const Context *context, GLenum target, GLuint index) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateEnablei(context, target, index); | |
| } | |
| bool ValidateIsEnablediOES(const Context *context, GLenum target, GLuint index) | |
| { | |
| if (!context->getExtensions().drawBuffersIndexedOES) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateIsEnabledi(context, target, index); | |
| } | |
| bool ValidateGetInteger64vEXT(const Context *context, GLenum pname, const GLint64 *data) | |
| { | |
| if (!context->getExtensions().disjointTimerQuery) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| GLenum nativeType = GL_NONE; | |
| unsigned int numParams = 0; | |
| if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateCopyImageSubDataEXT(const Context *context, | |
| GLuint srcName, | |
| GLenum srcTarget, | |
| GLint srcLevel, | |
| GLint srcX, | |
| GLint srcY, | |
| GLint srcZ, | |
| GLuint dstName, | |
| GLenum dstTarget, | |
| GLint dstLevel, | |
| GLint dstX, | |
| GLint dstY, | |
| GLint dstZ, | |
| GLsizei srcWidth, | |
| GLsizei srcHeight, | |
| GLsizei srcDepth) | |
| { | |
| if (!context->getExtensions().copyImageEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateCopyImageSubDataBase(context, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, | |
| dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, | |
| srcHeight, srcDepth); | |
| } | |
| bool ValidateCopyImageSubDataOES(const Context *context, | |
| GLuint srcName, | |
| GLenum srcTarget, | |
| GLint srcLevel, | |
| GLint srcX, | |
| GLint srcY, | |
| GLint srcZ, | |
| GLuint dstName, | |
| GLenum dstTarget, | |
| GLint dstLevel, | |
| GLint dstX, | |
| GLint dstY, | |
| GLint dstZ, | |
| GLsizei srcWidth, | |
| GLsizei srcHeight, | |
| GLsizei srcDepth) | |
| { | |
| if (!context->getExtensions().copyImageEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateCopyImageSubDataBase(context, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, | |
| dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, | |
| srcHeight, srcDepth); | |
| } | |
| bool ValidateBufferStorageMemEXT(const Context *context, | |
| TextureType target, | |
| GLsizeiptr size, | |
| MemoryObjectID memory, | |
| GLuint64 offset) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateCreateMemoryObjectsEXT(const Context *context, | |
| GLsizei n, | |
| const MemoryObjectID *memoryObjects) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGenOrDelete(context, n); | |
| } | |
| bool ValidateDeleteMemoryObjectsEXT(const Context *context, | |
| GLsizei n, | |
| const MemoryObjectID *memoryObjects) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGenOrDelete(context, n); | |
| } | |
| bool ValidateGetMemoryObjectParameterivEXT(const Context *context, | |
| MemoryObjectID memoryObject, | |
| GLenum pname, | |
| const GLint *params) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| const MemoryObject *memory = context->getMemoryObject(memoryObject); | |
| if (memory == nullptr) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidMemoryObject); | |
| } | |
| if (!IsValidMemoryObjectParamater(context, pname)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidMemoryObjectParameter); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateGetUnsignedBytevEXT(const Context *context, GLenum pname, const GLubyte *data) | |
| { | |
| if (!context->getExtensions().memoryObject && !context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateGetUnsignedBytei_vEXT(const Context *context, | |
| GLenum target, | |
| GLuint index, | |
| const GLubyte *data) | |
| { | |
| if (!context->getExtensions().memoryObject && !context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateIsMemoryObjectEXT(const Context *context, MemoryObjectID memoryObject) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateMemoryObjectParameterivEXT(const Context *context, | |
| MemoryObjectID memoryObject, | |
| GLenum pname, | |
| const GLint *params) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| const MemoryObject *memory = context->getMemoryObject(memoryObject); | |
| if (memory == nullptr) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidMemoryObject); | |
| return false; | |
| } | |
| if (memory->isImmutable()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kImmutableMemoryObject); | |
| return false; | |
| } | |
| if (!IsValidMemoryObjectParamater(context, pname)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidMemoryObjectParameter); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateTexStorageMem2DEXT(const Context *context, | |
| TextureType target, | |
| GLsizei levels, | |
| GLenum internalFormat, | |
| GLsizei width, | |
| GLsizei height, | |
| MemoryObjectID memory, | |
| GLuint64 offset) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| return ValidateES2TexStorageParametersBase(context, target, levels, internalFormat, width, | |
| height); | |
| } | |
| ASSERT(context->getClientMajorVersion() >= 3); | |
| return ValidateES3TexStorage2DParameters(context, target, levels, internalFormat, width, height, | |
| 1); | |
| } | |
| bool ValidateTexStorageMem3DEXT(const Context *context, | |
| TextureType target, | |
| GLsizei levels, | |
| GLenum internalFormat, | |
| GLsizei width, | |
| GLsizei height, | |
| GLsizei depth, | |
| MemoryObjectID memory, | |
| GLuint64 offset) | |
| { | |
| if (!context->getExtensions().memoryObject) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateImportMemoryFdEXT(const Context *context, | |
| MemoryObjectID memory, | |
| GLuint64 size, | |
| HandleType handleType, | |
| GLint fd) | |
| { | |
| if (!context->getExtensions().memoryObjectFd) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| switch (handleType) | |
| { | |
| case HandleType::OpaqueFd: | |
| break; | |
| default: | |
| context->validationError(GL_INVALID_ENUM, kInvalidHandleType); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateImportMemoryZirconHandleANGLE(const Context *context, | |
| MemoryObjectID memory, | |
| GLuint64 size, | |
| HandleType handleType, | |
| GLuint handle) | |
| { | |
| if (!context->getExtensions().memoryObjectFuchsiaANGLE) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| switch (handleType) | |
| { | |
| case HandleType::ZirconVmo: | |
| break; | |
| default: | |
| context->validationError(GL_INVALID_ENUM, kInvalidHandleType); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateDeleteSemaphoresEXT(const Context *context, GLsizei n, const SemaphoreID *semaphores) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGenOrDelete(context, n); | |
| } | |
| bool ValidateGenSemaphoresEXT(const Context *context, GLsizei n, const SemaphoreID *semaphores) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGenOrDelete(context, n); | |
| } | |
| bool ValidateGetSemaphoreParameterui64vEXT(const Context *context, | |
| SemaphoreID semaphore, | |
| GLenum pname, | |
| const GLuint64 *params) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateIsSemaphoreEXT(const Context *context, SemaphoreID semaphore) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateSemaphoreParameterui64vEXT(const Context *context, | |
| SemaphoreID semaphore, | |
| GLenum pname, | |
| const GLuint64 *params) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateSignalSemaphoreEXT(const Context *context, | |
| SemaphoreID semaphore, | |
| GLuint numBufferBarriers, | |
| const BufferID *buffers, | |
| GLuint numTextureBarriers, | |
| const TextureID *textures, | |
| const GLenum *dstLayouts) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| for (GLuint i = 0; i < numTextureBarriers; ++i) | |
| { | |
| if (!IsValidImageLayout(FromGLenum<ImageLayout>(dstLayouts[i]))) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidImageLayout); | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool ValidateWaitSemaphoreEXT(const Context *context, | |
| SemaphoreID semaphore, | |
| GLuint numBufferBarriers, | |
| const BufferID *buffers, | |
| GLuint numTextureBarriers, | |
| const TextureID *textures, | |
| const GLenum *srcLayouts) | |
| { | |
| if (!context->getExtensions().semaphore) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| for (GLuint i = 0; i < numTextureBarriers; ++i) | |
| { | |
| if (!IsValidImageLayout(FromGLenum<ImageLayout>(srcLayouts[i]))) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidImageLayout); | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool ValidateImportSemaphoreFdEXT(const Context *context, | |
| SemaphoreID semaphore, | |
| HandleType handleType, | |
| GLint fd) | |
| { | |
| if (!context->getExtensions().semaphoreFd) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| switch (handleType) | |
| { | |
| case HandleType::OpaqueFd: | |
| break; | |
| default: | |
| context->validationError(GL_INVALID_ENUM, kInvalidHandleType); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateGetSamplerParameterIivEXT(const Context *context, | |
| SamplerID samplerPacked, | |
| GLenum pname, | |
| const GLint *params) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateGetSamplerParameterBase(context, samplerPacked, pname, nullptr); | |
| } | |
| bool ValidateGetSamplerParameterIuivEXT(const Context *context, | |
| SamplerID samplerPacked, | |
| GLenum pname, | |
| const GLuint *params) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateGetSamplerParameterBase(context, samplerPacked, pname, nullptr); | |
| } | |
| bool ValidateGetTexParameterIivEXT(const Context *context, | |
| TextureType targetPacked, | |
| GLenum pname, | |
| const GLint *params) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateGetTexParameterBase(context, targetPacked, pname, nullptr); | |
| } | |
| bool ValidateGetTexParameterIuivEXT(const Context *context, | |
| TextureType targetPacked, | |
| GLenum pname, | |
| const GLuint *params) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateGetTexParameterBase(context, targetPacked, pname, nullptr); | |
| } | |
| bool ValidateSamplerParameterIivEXT(const Context *context, | |
| SamplerID samplerPacked, | |
| GLenum pname, | |
| const GLint *param) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateSamplerParameterBase(context, samplerPacked, pname, -1, true, param); | |
| } | |
| bool ValidateSamplerParameterIuivEXT(const Context *context, | |
| SamplerID samplerPacked, | |
| GLenum pname, | |
| const GLuint *param) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateSamplerParameterBase(context, samplerPacked, pname, -1, true, param); | |
| } | |
| bool ValidateTexParameterIivEXT(const Context *context, | |
| TextureType targetPacked, | |
| GLenum pname, | |
| const GLint *params) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateTexParameterBase(context, targetPacked, pname, -1, true, params); | |
| } | |
| bool ValidateTexParameterIuivEXT(const Context *context, | |
| TextureType targetPacked, | |
| GLenum pname, | |
| const GLuint *params) | |
| { | |
| if (context->getClientMajorVersion() < 3) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kES3Required); | |
| return false; | |
| } | |
| return ValidateTexParameterBase(context, targetPacked, pname, -1, true, params); | |
| } | |
| bool ValidateImportSemaphoreZirconHandleANGLE(const Context *context, | |
| SemaphoreID semaphore, | |
| HandleType handleType, | |
| GLuint handle) | |
| { | |
| if (!context->getExtensions().semaphoreFuchsiaANGLE) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| switch (handleType) | |
| { | |
| case HandleType::ZirconEvent: | |
| break; | |
| default: | |
| context->validationError(GL_INVALID_ENUM, kInvalidHandleType); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateFramebufferFetchBarrierEXT(const Context *context) | |
| { | |
| return true; | |
| } | |
| bool ValidatePatchParameteriEXT(const Context *context, GLenum pname, GLint value) | |
| { | |
| if (!context->getExtensions().tessellationShaderEXT) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kTessellationShaderExtensionNotEnabled); | |
| return false; | |
| } | |
| if (pname != GL_PATCH_VERTICES) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidPname); | |
| return false; | |
| } | |
| if (value <= 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidValueNonPositive); | |
| return false; | |
| } | |
| if (value > context->getCaps().maxPatchVertices) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidValueExceedsMaxPatchSize); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateTexStorageMemFlags2DANGLE(const Context *context, | |
| TextureType targetPacked, | |
| GLsizei levels, | |
| GLenum internalFormat, | |
| GLsizei width, | |
| GLsizei height, | |
| MemoryObjectID memoryPacked, | |
| GLuint64 offset, | |
| GLbitfield createFlags, | |
| GLbitfield usageFlags) | |
| { | |
| if (!context->getExtensions().memoryObjectFlagsANGLE) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| if (!ValidateTexStorageMem2DEXT(context, targetPacked, levels, internalFormat, width, height, | |
| memoryPacked, offset)) | |
| { | |
| return false; | |
| } | |
| // |createFlags| and |usageFlags| must only have bits specified by the extension. | |
| constexpr GLbitfield kAllCreateFlags = | |
| GL_CREATE_SPARSE_BINDING_BIT_ANGLE | GL_CREATE_SPARSE_RESIDENCY_BIT_ANGLE | | |
| GL_CREATE_SPARSE_ALIASED_BIT_ANGLE | GL_CREATE_MUTABLE_FORMAT_BIT_ANGLE | | |
| GL_CREATE_CUBE_COMPATIBLE_BIT_ANGLE | GL_CREATE_ALIAS_BIT_ANGLE | | |
| GL_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_ANGLE | GL_CREATE_2D_ARRAY_COMPATIBLE_BIT_ANGLE | | |
| GL_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_ANGLE | GL_CREATE_EXTENDED_USAGE_BIT_ANGLE | | |
| GL_CREATE_PROTECTED_BIT_ANGLE | GL_CREATE_DISJOINT_BIT_ANGLE | | |
| GL_CREATE_CORNER_SAMPLED_BIT_ANGLE | GL_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_ANGLE | | |
| GL_CREATE_SUBSAMPLED_BIT_ANGLE; | |
| if ((createFlags & ~kAllCreateFlags) != 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidExternalCreateFlags); | |
| return false; | |
| } | |
| constexpr GLbitfield kAllUsageFlags = | |
| GL_USAGE_TRANSFER_SRC_BIT_ANGLE | GL_USAGE_TRANSFER_DST_BIT_ANGLE | | |
| GL_USAGE_SAMPLED_BIT_ANGLE | GL_USAGE_STORAGE_BIT_ANGLE | | |
| GL_USAGE_COLOR_ATTACHMENT_BIT_ANGLE | GL_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT_ANGLE | | |
| GL_USAGE_TRANSIENT_ATTACHMENT_BIT_ANGLE | GL_USAGE_INPUT_ATTACHMENT_BIT_ANGLE | | |
| GL_USAGE_SHADING_RATE_IMAGE_BIT_ANGLE | GL_USAGE_FRAGMENT_DENSITY_MAP_BIT_ANGLE; | |
| if ((usageFlags & ~kAllUsageFlags) != 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidExternalUsageFlags); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateTexStorageMemFlags2DMultisampleANGLE(const Context *context, | |
| TextureType targetPacked, | |
| GLsizei samples, | |
| GLenum internalFormat, | |
| GLsizei width, | |
| GLsizei height, | |
| GLboolean fixedSampleLocations, | |
| MemoryObjectID memoryPacked, | |
| GLuint64 offset, | |
| GLbitfield createFlags, | |
| GLbitfield usageFlags) | |
| { | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateTexStorageMemFlags3DANGLE(const Context *context, | |
| TextureType targetPacked, | |
| GLsizei levels, | |
| GLenum internalFormat, | |
| GLsizei width, | |
| GLsizei height, | |
| GLsizei depth, | |
| MemoryObjectID memoryPacked, | |
| GLuint64 offset, | |
| GLbitfield createFlags, | |
| GLbitfield usageFlags) | |
| { | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| bool ValidateTexStorageMemFlags3DMultisampleANGLE(const Context *context, | |
| TextureType targetPacked, | |
| GLsizei samples, | |
| GLenum internalFormat, | |
| GLsizei width, | |
| GLsizei height, | |
| GLsizei depth, | |
| GLboolean fixedSampleLocations, | |
| MemoryObjectID memoryPacked, | |
| GLuint64 offset, | |
| GLbitfield createFlags, | |
| GLbitfield usageFlags) | |
| { | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| // GL_EXT_buffer_storage | |
| bool ValidateBufferStorageEXT(const Context *context, | |
| BufferBinding targetPacked, | |
| GLsizeiptr size, | |
| const void *data, | |
| GLbitfield flags) | |
| { | |
| if (!context->isValidBufferBinding(targetPacked)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidBufferTypes); | |
| return false; | |
| } | |
| if (size <= 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kNonPositiveSize); | |
| return false; | |
| } | |
| constexpr GLbitfield kAllUsageFlags = | |
| (GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | | |
| GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT | GL_CLIENT_STORAGE_BIT_EXT); | |
| if ((flags & ~kAllUsageFlags) != 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidBufferUsageFlags); | |
| return false; | |
| } | |
| if (((flags & GL_MAP_PERSISTENT_BIT_EXT) != 0) && | |
| ((flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidBufferUsageFlags); | |
| return false; | |
| } | |
| if (((flags & GL_MAP_COHERENT_BIT_EXT) != 0) && ((flags & GL_MAP_PERSISTENT_BIT_EXT) == 0)) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kInvalidBufferUsageFlags); | |
| return false; | |
| } | |
| Buffer *buffer = context->getState().getTargetBuffer(targetPacked); | |
| if (buffer == nullptr) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kBufferNotBound); | |
| return false; | |
| } | |
| if (buffer->isImmutable()) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kBufferImmutable); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // GL_EXT_clip_control | |
| bool ValidateClipControlEXT(const Context *context, GLenum origin, GLenum depth) | |
| { | |
| if ((origin != GL_LOWER_LEFT_EXT) && (origin != GL_UPPER_LEFT_EXT)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidOriginEnum); | |
| return false; | |
| } | |
| if ((depth != GL_NEGATIVE_ONE_TO_ONE_EXT) && (depth != GL_ZERO_TO_ONE_EXT)) | |
| { | |
| context->validationError(GL_INVALID_ENUM, kInvalidDepthEnum); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // GL_EXT_external_buffer | |
| bool ValidateBufferStorageExternalEXT(const Context *context, | |
| BufferBinding targetPacked, | |
| GLintptr offset, | |
| GLsizeiptr size, | |
| GLeglClientBufferEXT clientBuffer, | |
| GLbitfield flags) | |
| { | |
| if (!ValidateBufferStorageEXT(context, targetPacked, size, nullptr, flags)) | |
| { | |
| return false; | |
| } | |
| if (offset != 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kExternalBufferInvalidOffset); | |
| return false; | |
| } | |
| if (clientBuffer == nullptr && size > 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kClientBufferInvalid); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ValidateNamedBufferStorageExternalEXT(const Context *context, | |
| GLuint buffer, | |
| GLintptr offset, | |
| GLsizeiptr size, | |
| GLeglClientBufferEXT clientBuffer, | |
| GLbitfield flags) | |
| { | |
| UNIMPLEMENTED(); | |
| return false; | |
| } | |
| // GL_EXT_primitive_bounding_box | |
| bool ValidatePrimitiveBoundingBoxEXT(const Context *context, | |
| GLfloat minX, | |
| GLfloat minY, | |
| GLfloat minZ, | |
| GLfloat minW, | |
| GLfloat maxX, | |
| GLfloat maxY, | |
| GLfloat maxZ, | |
| GLfloat maxW) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| // GL_EXT_separate_shader_objects | |
| bool ValidateActiveShaderProgramEXT(const Context *context, | |
| ProgramPipelineID pipelinePacked, | |
| ShaderProgramID programPacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateActiveShaderProgramBase(context, pipelinePacked, programPacked); | |
| } | |
| bool ValidateBindProgramPipelineEXT(const Context *context, ProgramPipelineID pipelinePacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateBindProgramPipelineBase(context, pipelinePacked); | |
| } | |
| bool ValidateCreateShaderProgramvEXT(const Context *context, | |
| ShaderType typePacked, | |
| GLsizei count, | |
| const GLchar **strings) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateCreateShaderProgramvBase(context, typePacked, count, strings); | |
| } | |
| bool ValidateDeleteProgramPipelinesEXT(const Context *context, | |
| GLsizei n, | |
| const ProgramPipelineID *pipelinesPacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateDeleteProgramPipelinesBase(context, n, pipelinesPacked); | |
| } | |
| bool ValidateGenProgramPipelinesEXT(const Context *context, | |
| GLsizei n, | |
| const ProgramPipelineID *pipelinesPacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGenProgramPipelinesBase(context, n, pipelinesPacked); | |
| } | |
| bool ValidateGetProgramPipelineInfoLogEXT(const Context *context, | |
| ProgramPipelineID pipelinePacked, | |
| GLsizei bufSize, | |
| const GLsizei *length, | |
| const GLchar *infoLog) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGetProgramPipelineInfoLogBase(context, pipelinePacked, bufSize, length, infoLog); | |
| } | |
| bool ValidateGetProgramPipelineivEXT(const Context *context, | |
| ProgramPipelineID pipelinePacked, | |
| GLenum pname, | |
| const GLint *params) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateGetProgramPipelineivBase(context, pipelinePacked, pname, params); | |
| } | |
| bool ValidateIsProgramPipelineEXT(const Context *context, ProgramPipelineID pipelinePacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateIsProgramPipelineBase(context, pipelinePacked); | |
| } | |
| bool ValidateProgramParameteriEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| GLenum pname, | |
| GLint value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramParameteriBase(context, programPacked, pname, value); | |
| } | |
| bool ValidateProgramUniform1fEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLfloat v0) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform1fBase(context, programPacked, locationPacked, v0); | |
| } | |
| bool ValidateProgramUniform1fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform1fvBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform1iEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLint v0) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform1iBase(context, programPacked, locationPacked, v0); | |
| } | |
| bool ValidateProgramUniform1ivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLint *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform1ivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform1uiEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLuint v0) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform1uiBase(context, programPacked, locationPacked, v0); | |
| } | |
| bool ValidateProgramUniform1uivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLuint *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform1uivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform2fEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLfloat v0, | |
| GLfloat v1) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform2fBase(context, programPacked, locationPacked, v0, v1); | |
| } | |
| bool ValidateProgramUniform2fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform2fvBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform2iEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLint v0, | |
| GLint v1) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform2iBase(context, programPacked, locationPacked, v0, v1); | |
| } | |
| bool ValidateProgramUniform2ivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLint *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform2ivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform2uiEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLuint v0, | |
| GLuint v1) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform2uiBase(context, programPacked, locationPacked, v0, v1); | |
| } | |
| bool ValidateProgramUniform2uivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLuint *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform2uivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform3fEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLfloat v0, | |
| GLfloat v1, | |
| GLfloat v2) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform3fBase(context, programPacked, locationPacked, v0, v1, v2); | |
| } | |
| bool ValidateProgramUniform3fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform3fvBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform3iEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLint v0, | |
| GLint v1, | |
| GLint v2) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform3iBase(context, programPacked, locationPacked, v0, v1, v2); | |
| } | |
| bool ValidateProgramUniform3ivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLint *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform3ivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform3uiEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLuint v0, | |
| GLuint v1, | |
| GLuint v2) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform3uiBase(context, programPacked, locationPacked, v0, v1, v2); | |
| } | |
| bool ValidateProgramUniform3uivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLuint *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform3uivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform4fEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLfloat v0, | |
| GLfloat v1, | |
| GLfloat v2, | |
| GLfloat v3) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform4fBase(context, programPacked, locationPacked, v0, v1, v2, v3); | |
| } | |
| bool ValidateProgramUniform4fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform4fvBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform4iEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLint v0, | |
| GLint v1, | |
| GLint v2, | |
| GLint v3) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform4iBase(context, programPacked, locationPacked, v0, v1, v2, v3); | |
| } | |
| bool ValidateProgramUniform4ivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLint *value) | |
| { | |
| return ValidateProgramUniform4ivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniform4uiEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLuint v0, | |
| GLuint v1, | |
| GLuint v2, | |
| GLuint v3) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniform4uiBase(context, programPacked, locationPacked, v0, v1, v2, v3); | |
| } | |
| bool ValidateProgramUniform4uivEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| const GLuint *value) | |
| { | |
| return ValidateProgramUniform4uivBase(context, programPacked, locationPacked, count, value); | |
| } | |
| bool ValidateProgramUniformMatrix2fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix2fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix2x3fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix2x3fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix2x4fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix2x4fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix3fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix3fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix3x2fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix3x2fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix3x4fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix3x4fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix4fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix4fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix4x2fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix4x2fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateProgramUniformMatrix4x3fvEXT(const Context *context, | |
| ShaderProgramID programPacked, | |
| UniformLocation locationPacked, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateProgramUniformMatrix4x3fvBase(context, programPacked, locationPacked, count, | |
| transpose, value); | |
| } | |
| bool ValidateUseProgramStagesEXT(const Context *context, | |
| ProgramPipelineID pipelinePacked, | |
| GLbitfield stages, | |
| ShaderProgramID programPacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateUseProgramStagesBase(context, pipelinePacked, stages, programPacked); | |
| } | |
| bool ValidateValidateProgramPipelineEXT(const Context *context, ProgramPipelineID pipelinePacked) | |
| { | |
| if (!context->getExtensions().separateShaderObjects) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| return ValidateValidateProgramPipelineBase(context, pipelinePacked); | |
| } | |
| // GL_EXT_debug_label | |
| bool ValidateGetObjectLabelEXT(const Context *context, | |
| GLenum type, | |
| GLuint object, | |
| GLsizei bufSize, | |
| const GLsizei *length, | |
| const GLchar *label) | |
| { | |
| if (!context->getExtensions().debugLabel) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| if (bufSize < 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kNegativeBufferSize); | |
| return false; | |
| } | |
| return ValidateObjectIdentifierAndName(context, type, object); | |
| } | |
| bool ValidateLabelObjectEXT(const Context *context, | |
| GLenum type, | |
| GLuint object, | |
| GLsizei length, | |
| const GLchar *label) | |
| { | |
| if (!context->getExtensions().debugLabel) | |
| { | |
| context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); | |
| return false; | |
| } | |
| if (length < 0) | |
| { | |
| context->validationError(GL_INVALID_VALUE, kNegativeLength); | |
| return false; | |
| } | |
| return ValidateObjectIdentifierAndName(context, type, object); | |
| } | |
| } // namespace gl |