diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/validationES31.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/validationES31.cpp | 1935 |
1 files changed, 1935 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/validationES31.cpp b/gfx/angle/checkout/src/libANGLE/validationES31.cpp new file mode 100644 index 0000000000..fc55e31cd5 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/validationES31.cpp @@ -0,0 +1,1935 @@ +// +// Copyright (c) 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. +// + +// validationES31.cpp: Validation functions for OpenGL ES 3.1 entry point parameters + +#include "libANGLE/validationES31_autogen.h" + +#include "libANGLE/Context.h" +#include "libANGLE/ErrorStrings.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2_autogen.h" +#include "libANGLE/validationES3_autogen.h" + +#include "common/utilities.h" + +using namespace angle; + +namespace gl +{ +using namespace err; + +namespace +{ + +bool ValidateNamedProgramInterface(GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_BUFFER_VARIABLE: + case GL_SHADER_STORAGE_BLOCK: + return true; + default: + return false; + } +} + +bool ValidateLocationProgramInterface(GLenum programInterface) +{ + switch (programInterface) + { + case GL_UNIFORM: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + return true; + default: + return false; + } +} + +bool ValidateProgramInterface(GLenum programInterface) +{ + return (programInterface == GL_ATOMIC_COUNTER_BUFFER || + ValidateNamedProgramInterface(programInterface)); +} + +bool ValidateProgramResourceProperty(const Context *context, GLenum prop) +{ + ASSERT(context); + switch (prop) + { + case GL_ACTIVE_VARIABLES: + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + + case GL_ARRAY_SIZE: + + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + + case GL_BUFFER_DATA_SIZE: + + case GL_LOCATION: + + case GL_NAME_LENGTH: + + case GL_OFFSET: + + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + + case GL_TYPE: + return true; + + case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: + return context->getExtensions().geometryShader; + + case GL_LOCATION_INDEX_EXT: + return context->getExtensions().blendFuncExtended; + + default: + return false; + } +} + +// GLES 3.10 spec: Page 82 -- Table 7.2 +bool ValidateProgramResourcePropertyByInterface(GLenum prop, GLenum programInterface) +{ + switch (prop) + { + case GL_ACTIVE_VARIABLES: + case GL_BUFFER_BINDING: + case GL_NUM_ACTIVE_VARIABLES: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_ARRAY_SIZE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_ARRAY_STRIDE: + case GL_BLOCK_INDEX: + case GL_IS_ROW_MAJOR: + case GL_MATRIX_STRIDE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_ATOMIC_COUNTER_BUFFER_INDEX: + { + if (programInterface == GL_UNIFORM) + { + return true; + } + return false; + } + + case GL_BUFFER_DATA_SIZE: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_LOCATION: + { + return ValidateLocationProgramInterface(programInterface); + } + + case GL_LOCATION_INDEX_EXT: + { + // EXT_blend_func_extended + return (programInterface == GL_PROGRAM_OUTPUT); + } + + case GL_NAME_LENGTH: + { + return ValidateNamedProgramInterface(programInterface); + } + + case GL_OFFSET: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + case GL_REFERENCED_BY_VERTEX_SHADER: + case GL_REFERENCED_BY_FRAGMENT_SHADER: + case GL_REFERENCED_BY_COMPUTE_SHADER: + case GL_REFERENCED_BY_GEOMETRY_SHADER_EXT: + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM: + case GL_UNIFORM_BLOCK: + return true; + default: + return false; + } + } + + case GL_TOP_LEVEL_ARRAY_SIZE: + case GL_TOP_LEVEL_ARRAY_STRIDE: + { + if (programInterface == GL_BUFFER_VARIABLE) + { + return true; + } + return false; + } + + case GL_TYPE: + { + switch (programInterface) + { + case GL_BUFFER_VARIABLE: + case GL_PROGRAM_INPUT: + case GL_PROGRAM_OUTPUT: + case GL_TRANSFORM_FEEDBACK_VARYING: + case GL_UNIFORM: + return true; + default: + return false; + } + } + + default: + return false; + } +} + +bool ValidateProgramResourceIndex(const Program *programObject, + GLenum programInterface, + GLuint index) +{ + switch (programInterface) + { + case GL_PROGRAM_INPUT: + return (index < static_cast<GLuint>(programObject->getActiveAttributeCount())); + + case GL_PROGRAM_OUTPUT: + return (index < static_cast<GLuint>(programObject->getOutputResourceCount())); + + case GL_UNIFORM: + return (index < static_cast<GLuint>(programObject->getActiveUniformCount())); + + case GL_BUFFER_VARIABLE: + return (index < static_cast<GLuint>(programObject->getActiveBufferVariableCount())); + + case GL_SHADER_STORAGE_BLOCK: + return (index < static_cast<GLuint>(programObject->getActiveShaderStorageBlockCount())); + + case GL_UNIFORM_BLOCK: + return (index < programObject->getActiveUniformBlockCount()); + + case GL_ATOMIC_COUNTER_BUFFER: + return (index < programObject->getActiveAtomicCounterBufferCount()); + + case GL_TRANSFORM_FEEDBACK_VARYING: + return (index < static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount())); + + default: + UNREACHABLE(); + return false; + } +} + +bool ValidateProgramUniform(Context *context, + GLenum valueType, + GLuint program, + GLint location, + GLsizei count) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformValue(context, valueType, uniform->type); +} + +bool ValidateProgramUniformMatrix(Context *context, + GLenum valueType, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniformMatrixValue(context, valueType, uniform->type); +} + +bool ValidateVertexAttribFormatCommon(Context *context, GLuint relativeOffset) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const Caps &caps = context->getCaps(); + if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset)) + { + context->validationError(GL_INVALID_VALUE, kRelativeOffsetTooLarge); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getState().getVertexArrayId() == 0) + { + context->validationError(GL_INVALID_OPERATION, kDefaultVertexArray); + return false; + } + + return true; +} + +} // anonymous namespace + +bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (!ValidateIndexedStateQuery(context, target, index, nullptr)) + { + return false; + } + + return true; +} + +bool ValidateGetBooleani_vRobustANGLE(Context *context, + GLenum target, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLboolean *data) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (!ValidateRobustEntryPoint(context, bufSize)) + { + return false; + } + + GLsizei numParams = 0; + + if (!ValidateIndexedStateQuery(context, target, index, &numParams)) + { + return false; + } + + if (!ValidateRobustBufferSize(context, bufSize, numParams)) + { + return false; + } + + SetRobustLengthParam(length, numParams); + return true; +} + +bool ValidateDrawIndirectBase(Context *context, PrimitiveMode mode, const void *indirect) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + // Here the third parameter 1 is only to pass the count validation. + if (!ValidateDrawBase(context, mode)) + { + return false; + } + + const State &state = context->getState(); + + // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING, + // DRAW_INDIRECT_BUFFER or to any enabled vertex array. + if (!state.getVertexArrayId()) + { + context->validationError(GL_INVALID_OPERATION, kDefaultVertexArray); + return false; + } + + Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + if (!drawIndirectBuffer) + { + context->validationError(GL_INVALID_OPERATION, kDrawIndirectBufferNotBound); + return false; + } + + // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic + // machine units, of uint. + GLint64 offset = reinterpret_cast<GLint64>(indirect); + if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0) + { + context->validationError(GL_INVALID_VALUE, kInvalidIndirectOffset); + return false; + } + + return true; +} + +bool ValidateDrawArraysIndirect(Context *context, PrimitiveMode mode, const void *indirect) +{ + const State &state = context->getState(); + TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isActive() && + !curTransformFeedback->isPaused()) + { + // EXT_geometry_shader allows transform feedback to work with all draw commands. + // [EXT_geometry_shader] Section 12.1, "Transform Feedback" + if (context->getExtensions().geometryShader) + { + if (!ValidateTransformFeedbackPrimitiveMode( + context, curTransformFeedback->getPrimitiveMode(), mode)) + { + context->validationError(GL_INVALID_OPERATION, kInvalidDrawModeTransformFeedback); + return false; + } + } + else + { + // An INVALID_OPERATION error is generated if transform feedback is active and not + // paused. + context->validationError(GL_INVALID_OPERATION, + kUnsupportedDrawModeForTransformFeedback); + return false; + } + } + + if (!ValidateDrawIndirectBase(context, mode, indirect)) + return false; + + Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect)); + // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand + // which's size is 4 * sizeof(uint). + auto checkedSum = checkedOffset + 4 * sizeof(GLuint); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize())) + { + context->validationError(GL_INVALID_OPERATION, kParamOverflow); + return false; + } + + return true; +} + +bool ValidateDrawElementsIndirect(Context *context, + PrimitiveMode mode, + DrawElementsType type, + const void *indirect) +{ + if (!ValidateDrawElementsBase(context, mode, type)) + { + return false; + } + + const State &state = context->getState(); + const VertexArray *vao = state.getVertexArray(); + Buffer *elementArrayBuffer = vao->getElementArrayBuffer(); + if (!elementArrayBuffer) + { + context->validationError(GL_INVALID_OPERATION, kMustHaveElementArrayBinding); + return false; + } + + if (!ValidateDrawIndirectBase(context, mode, indirect)) + return false; + + Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect); + CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect)); + // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand + // which's size is 5 * sizeof(uint). + auto checkedSum = checkedOffset + 5 * sizeof(GLuint); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize())) + { + context->validationError(GL_INVALID_OPERATION, kParamOverflow); + return false; + } + + return true; +} + +bool ValidateProgramUniform1i(Context *context, GLuint program, GLint location, GLint v0) +{ + return ValidateProgramUniform1iv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2i(Context *context, GLuint program, GLint location, GLint v0, GLint v1) +{ + GLint xy[2] = {v0, v1}; + return ValidateProgramUniform2iv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2) +{ + GLint xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3iv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4i(Context *context, + GLuint program, + GLint location, + GLint v0, + GLint v1, + GLint v2, + GLint v3) +{ + GLint xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4iv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1ui(Context *context, GLuint program, GLint location, GLuint v0) +{ + return ValidateProgramUniform1uiv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1) +{ + GLuint xy[2] = {v0, v1}; + return ValidateProgramUniform2uiv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2) +{ + GLuint xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3uiv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4ui(Context *context, + GLuint program, + GLint location, + GLuint v0, + GLuint v1, + GLuint v2, + GLuint v3) +{ + GLuint xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4uiv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1f(Context *context, GLuint program, GLint location, GLfloat v0) +{ + return ValidateProgramUniform1fv(context, program, location, 1, &v0); +} + +bool ValidateProgramUniform2f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1) +{ + GLfloat xy[2] = {v0, v1}; + return ValidateProgramUniform2fv(context, program, location, 1, xy); +} + +bool ValidateProgramUniform3f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2) +{ + GLfloat xyz[3] = {v0, v1, v2}; + return ValidateProgramUniform3fv(context, program, location, 1, xyz); +} + +bool ValidateProgramUniform4f(Context *context, + GLuint program, + GLint location, + GLfloat v0, + GLfloat v1, + GLfloat v2, + GLfloat v3) +{ + GLfloat xyzw[4] = {v0, v1, v2, v3}; + return ValidateProgramUniform4fv(context, program, location, 1, xyzw); +} + +bool ValidateProgramUniform1iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + // Check for ES31 program uniform entry points + if (context->getClientVersion() < Version(3, 1)) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const LinkedUniform *uniform = nullptr; + Program *programObject = GetValidProgram(context, program); + return ValidateUniformCommonBase(context, programObject, location, count, &uniform) && + ValidateUniform1ivValue(context, uniform->type, count, value); +} + +bool ValidateProgramUniform2iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4iv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLint *value) +{ + return ValidateProgramUniform(context, GL_INT_VEC4, program, location, count); +} + +bool ValidateProgramUniform1uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT, program, location, count); +} + +bool ValidateProgramUniform2uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4uiv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLuint *value) +{ + return ValidateProgramUniform(context, GL_UNSIGNED_INT_VEC4, program, location, count); +} + +bool ValidateProgramUniform1fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT, program, location, count); +} + +bool ValidateProgramUniform2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC2, program, location, count); +} + +bool ValidateProgramUniform3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC3, program, location, count); +} + +bool ValidateProgramUniform4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + const GLfloat *value) +{ + return ValidateProgramUniform(context, GL_FLOAT_VEC4, program, location, count); +} + +bool ValidateProgramUniformMatrix2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix2x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2x3, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3x2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix2x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT2x4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4x2fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4x2, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix3x4fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT3x4, program, location, count, + transpose); +} + +bool ValidateProgramUniformMatrix4x3fv(Context *context, + GLuint program, + GLint location, + GLsizei count, + GLboolean transpose, + const GLfloat *value) +{ + return ValidateProgramUniformMatrix(context, GL_FLOAT_MAT4x3, program, location, count, + transpose); +} + +bool ValidateGetTexLevelParameterfv(Context *context, + TextureTarget target, + GLint level, + GLenum pname, + GLfloat *params) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr); +} + +bool ValidateGetTexLevelParameterfvRobustANGLE(Context *context, + TextureTarget target, + GLint level, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLfloat *params) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetTexLevelParameteriv(Context *context, + TextureTarget target, + GLint level, + GLenum pname, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr); +} + +bool ValidateGetTexLevelParameterivRobustANGLE(Context *context, + TextureTarget target, + GLint level, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateTexStorage2DMultisample(Context *context, + TextureType target, + GLsizei samples, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLboolean fixedSampleLocations) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return ValidateTexStorage2DMultisampleBase(context, target, samples, internalFormat, width, + height); +} + +bool ValidateTexStorageMem2DMultisampleEXT(Context *context, + TextureType target, + GLsizei samples, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLboolean fixedSampleLocations, + GLuint memory, + GLuint64 offset) +{ + if (!context->getExtensions().memoryObject) + { + context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); + return false; + } + + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return ValidateGetMultisamplefvBase(context, pname, index, val); +} + +bool ValidateGetMultisamplefvRobustANGLE(Context *context, + GLenum pname, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLfloat *val) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateFramebufferParameteri(Context *context, GLenum target, GLenum pname, GLint param) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (!ValidFramebufferTarget(context, target)) + { + context->validationError(GL_INVALID_ENUM, kInvalidFramebufferTarget); + return false; + } + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + { + GLint maxWidth = context->getCaps().maxFramebufferWidth; + if (param < 0 || param > maxWidth) + { + context->validationError(GL_INVALID_VALUE, kExceedsFramebufferWidth); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + { + GLint maxHeight = context->getCaps().maxFramebufferHeight; + if (param < 0 || param > maxHeight) + { + context->validationError(GL_INVALID_VALUE, kExceedsFramebufferHeight); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + { + GLint maxSamples = context->getCaps().maxFramebufferSamples; + if (param < 0 || param > maxSamples) + { + context->validationError(GL_INVALID_VALUE, kExceedsFramebufferSamples); + return false; + } + break; + } + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + { + break; + } + case GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT: + { + if (!context->getExtensions().geometryShader) + { + context->validationError(GL_INVALID_ENUM, kGeometryShaderExtensionNotEnabled); + return false; + } + GLint maxLayers = context->getCaps().maxFramebufferLayers; + if (param < 0 || param > maxLayers) + { + context->validationError(GL_INVALID_VALUE, kInvalidFramebufferLayer); + return false; + } + break; + } + default: + { + context->validationError(GL_INVALID_ENUM, kInvalidPname); + return false; + } + } + + const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + if (framebuffer->id() == 0) + { + context->validationError(GL_INVALID_OPERATION, kDefaultFramebuffer); + return false; + } + return true; +} + +bool ValidateGetFramebufferParameteriv(Context *context, GLenum target, GLenum pname, GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (!ValidFramebufferTarget(context, target)) + { + context->validationError(GL_INVALID_ENUM, kInvalidFramebufferTarget); + return false; + } + + switch (pname) + { + case GL_FRAMEBUFFER_DEFAULT_WIDTH: + case GL_FRAMEBUFFER_DEFAULT_HEIGHT: + case GL_FRAMEBUFFER_DEFAULT_SAMPLES: + case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: + break; + case GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT: + if (!context->getExtensions().geometryShader) + { + context->validationError(GL_INVALID_ENUM, kGeometryShaderExtensionNotEnabled); + return false; + } + break; + default: + context->validationError(GL_INVALID_ENUM, kInvalidPname); + return false; + } + + const Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->id() == 0) + { + context->validationError(GL_INVALID_OPERATION, kDefaultFramebuffer); + return false; + } + return true; +} + +bool ValidateGetFramebufferParameterivRobustANGLE(Context *context, + GLenum target, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramResourceIndex(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateNamedProgramInterface(programInterface)) + { + context->validationError(GL_INVALID_ENUM, kInvalidProgramInterface); + return false; + } + + return true; +} + +bool ValidateBindVertexBuffer(Context *context, + GLuint bindingIndex, + GLuint buffer, + GLintptr offset, + GLsizei stride) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (!context->isBufferGenerated(buffer)) + { + context->validationError(GL_INVALID_OPERATION, kObjectNotGenerated); + return false; + } + + const Caps &caps = context->getCaps(); + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->validationError(GL_INVALID_VALUE, kExceedsMaxVertexAttribBindings); + return false; + } + + if (offset < 0) + { + context->validationError(GL_INVALID_VALUE, kNegativeOffset); + return false; + } + + if (stride < 0 || stride > caps.maxVertexAttribStride) + { + context->validationError(GL_INVALID_VALUE, kExceedsMaxVertexAttribStride); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 244: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getState().getVertexArrayId() == 0) + { + context->validationError(GL_INVALID_OPERATION, kDefaultVertexArray); + return false; + } + + return true; +} + +bool ValidateVertexBindingDivisor(Context *context, GLuint bindingIndex, GLuint divisor) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const Caps &caps = context->getCaps(); + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->validationError(GL_INVALID_VALUE, kExceedsMaxVertexAttribBindings); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getState().getVertexArrayId() == 0) + { + context->validationError(GL_INVALID_OPERATION, kDefaultVertexArray); + return false; + } + + return true; +} + +bool ValidateVertexAttribFormat(Context *context, + GLuint attribindex, + GLint size, + VertexAttribType type, + GLboolean normalized, + GLuint relativeoffset) +{ + if (!ValidateVertexAttribFormatCommon(context, relativeoffset)) + { + return false; + } + + return ValidateFloatVertexFormat(context, attribindex, size, type); +} + +bool ValidateVertexAttribIFormat(Context *context, + GLuint attribindex, + GLint size, + VertexAttribType type, + GLuint relativeoffset) +{ + if (!ValidateVertexAttribFormatCommon(context, relativeoffset)) + { + return false; + } + + return ValidateIntegerVertexFormat(context, attribindex, size, type); +} + +bool ValidateVertexAttribBinding(Context *context, GLuint attribIndex, GLuint bindingIndex) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + // [OpenGL ES 3.1] Section 10.3.1 page 243: + // An INVALID_OPERATION error is generated if the default vertex array object is bound. + if (context->getState().getVertexArrayId() == 0) + { + context->validationError(GL_INVALID_OPERATION, kDefaultVertexArray); + return false; + } + + const Caps &caps = context->getCaps(); + if (attribIndex >= caps.maxVertexAttributes) + { + context->validationError(GL_INVALID_VALUE, kIndexExceedsMaxVertexAttribute); + return false; + } + + if (bindingIndex >= caps.maxVertexAttribBindings) + { + context->validationError(GL_INVALID_VALUE, kExceedsMaxVertexAttribBindings); + return false; + } + + return true; +} + +bool ValidateGetProgramResourceName(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei bufSize, + GLsizei *length, + GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateNamedProgramInterface(programInterface)) + { + context->validationError(GL_INVALID_ENUM, kInvalidProgramInterface); + return false; + } + + if (!ValidateProgramResourceIndex(programObject, programInterface, index)) + { + context->validationError(GL_INVALID_VALUE, kInvalidProgramResourceIndex); + return false; + } + + if (bufSize < 0) + { + context->validationError(GL_INVALID_VALUE, kNegativeBufferSize); + return false; + } + + return true; +} + +bool ValidateDispatchCompute(Context *context, + GLuint numGroupsX, + GLuint numGroupsY, + GLuint numGroupsZ) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const State &state = context->getState(); + Program *program = state.getLinkedProgram(context); + + if (program == nullptr || !program->hasLinkedShaderStage(ShaderType::Compute)) + { + context->validationError(GL_INVALID_OPERATION, kNoActiveProgramWithComputeShader); + return false; + } + + const Caps &caps = context->getCaps(); + if (numGroupsX > caps.maxComputeWorkGroupCount[0]) + { + context->validationError(GL_INVALID_VALUE, kExceedsComputeWorkGroupCountX); + return false; + } + if (numGroupsY > caps.maxComputeWorkGroupCount[1]) + { + context->validationError(GL_INVALID_VALUE, kExceedsComputeWorkGroupCountY); + return false; + } + if (numGroupsZ > caps.maxComputeWorkGroupCount[2]) + { + context->validationError(GL_INVALID_VALUE, kExceedsComputeWorkGroupCountZ); + return false; + } + + return true; +} + +bool ValidateDispatchComputeIndirect(Context *context, GLintptr indirect) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + const State &state = context->getState(); + Program *program = state.getLinkedProgram(context); + + if (program == nullptr || !program->hasLinkedShaderStage(ShaderType::Compute)) + { + context->validationError(GL_INVALID_OPERATION, kNoActiveProgramWithComputeShader); + return false; + } + + if (indirect < 0) + { + context->validationError(GL_INVALID_VALUE, kNegativeOffset); + return false; + } + + if ((indirect & (sizeof(GLuint) - 1)) != 0) + { + context->validationError(GL_INVALID_VALUE, kOffsetMustBeMultipleOfUint); + return false; + } + + Buffer *dispatchIndirectBuffer = state.getTargetBuffer(BufferBinding::DispatchIndirect); + if (!dispatchIndirectBuffer) + { + context->validationError(GL_INVALID_OPERATION, kDispatchIndirectBufferNotBound); + return false; + } + + CheckedNumeric<GLuint64> checkedOffset(static_cast<GLuint64>(indirect)); + auto checkedSum = checkedOffset + static_cast<GLuint64>(3 * sizeof(GLuint)); + if (!checkedSum.IsValid() || + checkedSum.ValueOrDie() > static_cast<GLuint64>(dispatchIndirectBuffer->getSize())) + { + context->validationError(GL_INVALID_OPERATION, kInsufficientBufferSize); + return false; + } + + return true; +} + +bool ValidateBindImageTexture(Context *context, + GLuint unit, + GLuint texture, + GLint level, + GLboolean layered, + GLint layer, + GLenum access, + GLenum format) +{ + GLuint maxImageUnits = context->getCaps().maxImageUnits; + if (unit >= maxImageUnits) + { + context->validationError(GL_INVALID_VALUE, kExceedsMaxImageUnits); + return false; + } + + if (level < 0) + { + context->validationError(GL_INVALID_VALUE, kNegativeLevel); + return false; + } + + if (layer < 0) + { + context->validationError(GL_INVALID_VALUE, kNegativeLayer); + return false; + } + + if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE) + { + context->validationError(GL_INVALID_ENUM, kInvalidImageAccess); + return false; + } + + switch (format) + { + case GL_RGBA32F: + case GL_RGBA16F: + case GL_R32F: + case GL_RGBA32UI: + case GL_RGBA16UI: + case GL_RGBA8UI: + case GL_R32UI: + case GL_RGBA32I: + case GL_RGBA16I: + case GL_RGBA8I: + case GL_R32I: + case GL_RGBA8: + case GL_RGBA8_SNORM: + break; + default: + context->validationError(GL_INVALID_VALUE, kInvalidImageFormat); + return false; + } + + if (texture != 0) + { + Texture *tex = context->getTexture(texture); + + if (tex == nullptr) + { + context->validationError(GL_INVALID_VALUE, kMissingTextureName); + return false; + } + + if (!tex->getImmutableFormat()) + { + context->validationError(GL_INVALID_OPERATION, kTextureIsNotImmutable); + return false; + } + } + + return true; +} + +bool ValidateGetProgramResourceLocation(Context *context, + GLuint program, + GLenum programInterface, + const GLchar *name) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!programObject->isLinked()) + { + context->validationError(GL_INVALID_OPERATION, kProgramNotLinked); + return false; + } + + if (!ValidateLocationProgramInterface(programInterface)) + { + context->validationError(GL_INVALID_ENUM, kInvalidProgramInterface); + return false; + } + return true; +} + +bool ValidateGetProgramResourceiv(Context *context, + GLuint program, + GLenum programInterface, + GLuint index, + GLsizei propCount, + const GLenum *props, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + if (!ValidateProgramInterface(programInterface)) + { + context->validationError(GL_INVALID_ENUM, kInvalidProgramInterface); + return false; + } + if (propCount <= 0) + { + context->validationError(GL_INVALID_VALUE, kInvalidPropCount); + return false; + } + if (bufSize < 0) + { + context->validationError(GL_INVALID_VALUE, kNegativeBufSize); + return false; + } + if (!ValidateProgramResourceIndex(programObject, programInterface, index)) + { + context->validationError(GL_INVALID_VALUE, kInvalidProgramResourceIndex); + return false; + } + for (GLsizei i = 0; i < propCount; i++) + { + if (!ValidateProgramResourceProperty(context, props[i])) + { + context->validationError(GL_INVALID_ENUM, kInvalidProgramResourceProperty); + return false; + } + if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface)) + { + context->validationError(GL_INVALID_OPERATION, kInvalidPropertyForProgramInterface); + return false; + } + } + return true; +} + +bool ValidateGetProgramInterfaceiv(Context *context, + GLuint program, + GLenum programInterface, + GLenum pname, + GLint *params) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + Program *programObject = GetValidProgram(context, program); + if (programObject == nullptr) + { + return false; + } + + if (!ValidateProgramInterface(programInterface)) + { + context->validationError(GL_INVALID_ENUM, kInvalidProgramInterface); + return false; + } + + switch (pname) + { + case GL_ACTIVE_RESOURCES: + case GL_MAX_NAME_LENGTH: + case GL_MAX_NUM_ACTIVE_VARIABLES: + break; + + default: + context->validationError(GL_INVALID_ENUM, kInvalidPname); + return false; + } + + if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER) + { + context->validationError(GL_INVALID_OPERATION, kAtomicCounterResourceName); + return false; + } + + if (pname == GL_MAX_NUM_ACTIVE_VARIABLES) + { + switch (programInterface) + { + case GL_ATOMIC_COUNTER_BUFFER: + case GL_SHADER_STORAGE_BLOCK: + case GL_UNIFORM_BLOCK: + break; + + default: + context->validationError(GL_INVALID_OPERATION, kMaxActiveVariablesInterface); + return false; + } + } + + return true; +} + +bool ValidateGetProgramInterfaceivRobustANGLE(Context *context, + GLuint program, + GLenum programInterface, + GLenum pname, + GLsizei bufSize, + GLsizei *length, + GLint *params) +{ + UNIMPLEMENTED(); + return false; +} + +static bool ValidateGenOrDeleteES31(Context *context, GLint n) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return ValidateGenOrDelete(context, n); +} + +bool ValidateGenProgramPipelines(Context *context, GLint n, GLuint *) +{ + return ValidateGenOrDeleteES31(context, n); +} + +bool ValidateDeleteProgramPipelines(Context *context, GLint n, const GLuint *) +{ + return ValidateGenOrDeleteES31(context, n); +} + +bool ValidateBindProgramPipeline(Context *context, GLuint pipeline) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (!context->isProgramPipelineGenerated(pipeline)) + { + context->validationError(GL_INVALID_OPERATION, kObjectNotGenerated); + return false; + } + + return true; +} + +bool ValidateIsProgramPipeline(Context *context, GLuint pipeline) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return true; +} + +bool ValidateUseProgramStages(Context *context, GLuint pipeline, GLbitfield stages, GLuint program) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateActiveShaderProgram(Context *context, GLuint pipeline, GLuint program) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateCreateShaderProgramv(Context *context, + ShaderType type, + GLsizei count, + const GLchar *const *strings) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramPipelineiv(Context *context, GLuint pipeline, GLenum pname, GLint *params) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateValidateProgramPipeline(Context *context, GLuint pipeline) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramPipelineInfoLog(Context *context, + GLuint pipeline, + GLsizei bufSize, + GLsizei *length, + GLchar *infoLog) +{ + UNIMPLEMENTED(); + return false; +} + +bool ValidateMemoryBarrier(Context *context, GLbitfield barriers) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (barriers == GL_ALL_BARRIER_BITS) + { + return true; + } + + GLbitfield supported_barrier_bits = + GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT | + GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_COMMAND_BARRIER_BIT | + GL_PIXEL_BUFFER_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT | + GL_FRAMEBUFFER_BARRIER_BIT | GL_TRANSFORM_FEEDBACK_BARRIER_BIT | + GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT; + if (barriers == 0 || (barriers & ~supported_barrier_bits) != 0) + { + context->validationError(GL_INVALID_VALUE, kInvalidMemoryBarrierBit); + return false; + } + + return true; +} + +bool ValidateMemoryBarrierByRegion(Context *context, GLbitfield barriers) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + if (barriers == GL_ALL_BARRIER_BITS) + { + return true; + } + + GLbitfield supported_barrier_bits = GL_ATOMIC_COUNTER_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT | + GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | + GL_SHADER_STORAGE_BARRIER_BIT | + GL_TEXTURE_FETCH_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT; + if (barriers == 0 || (barriers & ~supported_barrier_bits) != 0) + { + context->validationError(GL_INVALID_VALUE, kInvalidMemoryBarrierBit); + return false; + } + + return true; +} + +bool ValidateSampleMaski(Context *context, GLuint maskNumber, GLbitfield mask) +{ + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + + return ValidateSampleMaskiBase(context, maskNumber, mask); +} + +bool ValidateFramebufferTextureEXT(Context *context, + GLenum target, + GLenum attachment, + GLuint texture, + GLint level) +{ + if (!context->getExtensions().geometryShader) + { + context->validationError(GL_INVALID_OPERATION, kGeometryShaderExtensionNotEnabled); + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + + // [EXT_geometry_shader] Section 9.2.8 "Attaching Texture Images to a Framebuffer" + // An INVALID_VALUE error is generated if <texture> is not the name of a texture object. + // We put this validation before ValidateFramebufferTextureBase because it is an + // INVALID_OPERATION error for both FramebufferTexture2D and FramebufferTextureLayer: + // [OpenGL ES 3.1] Chapter 9.2.8 (FramebufferTexture2D) + // An INVALID_OPERATION error is generated if texture is not zero, and does not name an + // existing texture object of type matching textarget. + // [OpenGL ES 3.1 Chapter 9.2.8 (FramebufferTextureLayer) + // An INVALID_OPERATION error is generated if texture is non-zero and is not the name of a + // three-dimensional or two-dimensional array texture. + if (tex == nullptr) + { + context->validationError(GL_INVALID_VALUE, kInvalidTextureName); + return false; + } + + if (!ValidMipLevel(context, tex->getType(), level)) + { + context->validationError(GL_INVALID_VALUE, kInvalidMipLevel); + return false; + } + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + return true; +} + +// GL_OES_texture_storage_multisample_2d_array +bool ValidateTexStorage3DMultisampleOES(Context *context, + TextureType target, + GLsizei samples, + GLenum sizedinternalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLboolean fixedsamplelocations) +{ + if (!context->getExtensions().textureStorageMultisample2DArray) + { + context->validationError(GL_INVALID_ENUM, kMultisampleArrayExtensionRequired); + return false; + } + + if (target != TextureType::_2DMultisampleArray) + { + context->validationError(GL_INVALID_ENUM, kTargetMustBeTexture2DMultisampleArrayOES); + return false; + } + + if (width < 1 || height < 1 || depth < 1) + { + context->validationError(GL_INVALID_VALUE, kNegativeSize); + return false; + } + + return ValidateTexStorageMultisample(context, target, samples, sizedinternalformat, width, + height); +} + +bool ValidateTexStorageMem3DMultisampleEXT(Context *context, + TextureType target, + GLsizei samples, + GLenum internalFormat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLboolean fixedSampleLocations, + GLuint memory, + GLuint64 offset) +{ + if (!context->getExtensions().memoryObject) + { + context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); + return false; + } + + UNIMPLEMENTED(); + return false; +} + +bool ValidateGetProgramResourceLocationIndexEXT(Context *context, + GLuint program, + GLenum programInterface, + const char *name) +{ + if (!context->getExtensions().blendFuncExtended) + { + context->validationError(GL_INVALID_OPERATION, kExtensionNotEnabled); + return false; + } + if (context->getClientVersion() < ES_3_1) + { + context->validationError(GL_INVALID_OPERATION, kES31Required); + return false; + } + if (programInterface != GL_PROGRAM_OUTPUT) + { + context->validationError(GL_INVALID_ENUM, kProgramInterfaceMustBeProgramOutput); + return false; + } + Program *programObject = GetValidProgram(context, program); + if (!programObject) + { + return false; + } + if (!programObject->isLinked()) + { + context->validationError(GL_INVALID_OPERATION, kProgramNotLinked); + return false; + } + return true; +} + +} // namespace gl |