3157 lines
113 KiB
C++
3157 lines
113 KiB
C++
//
|
|
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
|
|
// 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/ProgramExecutable.h"
|
|
#include "libANGLE/VertexArray.h"
|
|
#include "libANGLE/validationES.h"
|
|
#include "libANGLE/validationES2_autogen.h"
|
|
#include "libANGLE/validationES31.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,
|
|
angle::EntryPoint entryPoint,
|
|
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().geometryShaderAny() ||
|
|
context->getClientVersion() >= ES_3_2;
|
|
|
|
case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT:
|
|
case GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT:
|
|
case GL_IS_PER_PATCH_EXT:
|
|
return context->getExtensions().tessellationShaderEXT ||
|
|
context->getClientVersion() >= ES_3_2;
|
|
|
|
case GL_LOCATION_INDEX_EXT:
|
|
return context->getExtensions().blendFuncExtendedEXT;
|
|
|
|
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:
|
|
case GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT:
|
|
case GL_REFERENCED_BY_TESS_EVALUATION_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;
|
|
}
|
|
}
|
|
case GL_IS_PER_PATCH_EXT:
|
|
switch (programInterface)
|
|
{
|
|
case GL_PROGRAM_INPUT:
|
|
case GL_PROGRAM_OUTPUT:
|
|
return true;
|
|
}
|
|
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->getState().getProgramInputs().size()));
|
|
|
|
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 ValidateProgramUniformBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum valueType,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count)
|
|
{
|
|
const LinkedUniform *uniform = nullptr;
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
return ValidateUniformCommonBase(context, entryPoint, programObject, location, count,
|
|
&uniform) &&
|
|
ValidateUniformValue(context, entryPoint, valueType, uniform->type);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrixBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum valueType,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose)
|
|
{
|
|
const LinkedUniform *uniform = nullptr;
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
return ValidateUniformCommonBase(context, entryPoint, programObject, location, count,
|
|
&uniform) &&
|
|
ValidateUniformMatrixValue(context, entryPoint, valueType, uniform->type);
|
|
}
|
|
|
|
bool ValidateVertexAttribFormatCommon(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint relativeOffset)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
const Caps &caps = context->getCaps();
|
|
if (relativeOffset > static_cast<GLuint>(caps.maxVertexAttribRelativeOffset))
|
|
{
|
|
context->validationError(entryPoint, 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().value == 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultVertexArray);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
bool ValidateGetBooleani_v(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLuint index,
|
|
const GLboolean *data)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1 && !context->getExtensions().drawBuffersIndexedAny())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kES31OrDrawBuffersIndexedExtensionNotAvailable);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateIndexedStateQuery(context, entryPoint, target, index, nullptr))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetBooleani_vRobustANGLE(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLuint index,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLboolean *data)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1 && !context->getExtensions().drawBuffersIndexedAny())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kES31OrDrawBuffersIndexedExtensionNotAvailable);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateRobustEntryPoint(context, entryPoint, bufSize))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
GLsizei numParams = 0;
|
|
|
|
if (!ValidateIndexedStateQuery(context, entryPoint, target, index, &numParams))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateRobustBufferSize(context, entryPoint, bufSize, numParams))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SetRobustLengthParam(length, numParams);
|
|
return true;
|
|
}
|
|
|
|
bool ValidateDrawIndirectBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
PrimitiveMode mode,
|
|
const void *indirect)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
// Here the third parameter 1 is only to pass the count validation.
|
|
if (!ValidateDrawBase(context, entryPoint, 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().value == 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultVertexArray);
|
|
return false;
|
|
}
|
|
|
|
if (context->getStateCache().hasAnyActiveClientAttrib())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kClientDataInVertexArray);
|
|
return false;
|
|
}
|
|
|
|
Buffer *drawIndirectBuffer = state.getTargetBuffer(BufferBinding::DrawIndirect);
|
|
if (!drawIndirectBuffer)
|
|
{
|
|
context->validationError(entryPoint, 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(entryPoint, GL_INVALID_VALUE, kInvalidIndirectOffset);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateDrawArraysIndirect(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
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().geometryShaderAny() || context->getClientVersion() >= ES_3_2)
|
|
{
|
|
if (!ValidateTransformFeedbackPrimitiveMode(
|
|
context, entryPoint, curTransformFeedback->getPrimitiveMode(), mode))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kInvalidDrawModeTransformFeedback);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// An INVALID_OPERATION error is generated if transform feedback is active and not
|
|
// paused.
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kUnsupportedDrawModeForTransformFeedback);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!ValidateDrawIndirectBase(context, entryPoint, 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(entryPoint, GL_INVALID_OPERATION, kParamOverflow);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateDrawElementsIndirect(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
PrimitiveMode mode,
|
|
DrawElementsType type,
|
|
const void *indirect)
|
|
{
|
|
if (!ValidateDrawElementsBase(context, entryPoint, mode, type))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const State &state = context->getState();
|
|
const VertexArray *vao = state.getVertexArray();
|
|
Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
|
|
if (!elementArrayBuffer)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kMustHaveElementArrayBinding);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateDrawIndirectBase(context, entryPoint, 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(entryPoint, GL_INVALID_OPERATION, kParamOverflow);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateMultiDrawIndirectBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLsizei drawcount,
|
|
GLsizei stride)
|
|
{
|
|
if (!context->getExtensions().multiDrawIndirectEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
|
|
// An INVALID_VALUE error is generated if stride is neither 0 nor a multiple of 4.
|
|
if ((stride & 3) != 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidDrawBufferValue);
|
|
return false;
|
|
}
|
|
|
|
// An INVALID_VALUE error is generated if drawcount is not positive.
|
|
if (drawcount <= 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidValueNonPositive);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateProgramUniform1iBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLint v0)
|
|
{
|
|
return ValidateProgramUniform1ivBase(context, entryPoint, program, location, 1, &v0);
|
|
}
|
|
|
|
bool ValidateProgramUniform2iBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLint v0,
|
|
GLint v1)
|
|
{
|
|
GLint xy[2] = {v0, v1};
|
|
return ValidateProgramUniform2ivBase(context, entryPoint, program, location, 1, xy);
|
|
}
|
|
|
|
bool ValidateProgramUniform3iBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLint v0,
|
|
GLint v1,
|
|
GLint v2)
|
|
{
|
|
GLint xyz[3] = {v0, v1, v2};
|
|
return ValidateProgramUniform3ivBase(context, entryPoint, program, location, 1, xyz);
|
|
}
|
|
|
|
bool ValidateProgramUniform4iBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLint v0,
|
|
GLint v1,
|
|
GLint v2,
|
|
GLint v3)
|
|
{
|
|
GLint xyzw[4] = {v0, v1, v2, v3};
|
|
return ValidateProgramUniform4ivBase(context, entryPoint, program, location, 1, xyzw);
|
|
}
|
|
|
|
bool ValidateProgramUniform1uiBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLuint v0)
|
|
{
|
|
return ValidateProgramUniform1uivBase(context, entryPoint, program, location, 1, &v0);
|
|
}
|
|
|
|
bool ValidateProgramUniform2uiBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLuint v0,
|
|
GLuint v1)
|
|
{
|
|
GLuint xy[2] = {v0, v1};
|
|
return ValidateProgramUniform2uivBase(context, entryPoint, program, location, 1, xy);
|
|
}
|
|
|
|
bool ValidateProgramUniform3uiBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLuint v0,
|
|
GLuint v1,
|
|
GLuint v2)
|
|
{
|
|
GLuint xyz[3] = {v0, v1, v2};
|
|
return ValidateProgramUniform3uivBase(context, entryPoint, program, location, 1, xyz);
|
|
}
|
|
|
|
bool ValidateProgramUniform4uiBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLuint v0,
|
|
GLuint v1,
|
|
GLuint v2,
|
|
GLuint v3)
|
|
{
|
|
GLuint xyzw[4] = {v0, v1, v2, v3};
|
|
return ValidateProgramUniform4uivBase(context, entryPoint, program, location, 1, xyzw);
|
|
}
|
|
|
|
bool ValidateProgramUniform1fBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLfloat v0)
|
|
{
|
|
return ValidateProgramUniform1fvBase(context, entryPoint, program, location, 1, &v0);
|
|
}
|
|
|
|
bool ValidateProgramUniform2fBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLfloat v0,
|
|
GLfloat v1)
|
|
{
|
|
GLfloat xy[2] = {v0, v1};
|
|
return ValidateProgramUniform2fvBase(context, entryPoint, program, location, 1, xy);
|
|
}
|
|
|
|
bool ValidateProgramUniform3fBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLfloat v0,
|
|
GLfloat v1,
|
|
GLfloat v2)
|
|
{
|
|
GLfloat xyz[3] = {v0, v1, v2};
|
|
return ValidateProgramUniform3fvBase(context, entryPoint, program, location, 1, xyz);
|
|
}
|
|
|
|
bool ValidateProgramUniform4fBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLfloat v0,
|
|
GLfloat v1,
|
|
GLfloat v2,
|
|
GLfloat v3)
|
|
{
|
|
GLfloat xyzw[4] = {v0, v1, v2, v3};
|
|
return ValidateProgramUniform4fvBase(context, entryPoint, program, location, 1, xyzw);
|
|
}
|
|
|
|
bool ValidateProgramUniform1ivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
const LinkedUniform *uniform = nullptr;
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
return ValidateUniformCommonBase(context, entryPoint, programObject, location, count,
|
|
&uniform) &&
|
|
ValidateUniform1ivValue(context, entryPoint, uniform->type, count, value);
|
|
}
|
|
|
|
bool ValidateProgramUniform2ivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_INT_VEC2, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniform3ivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_INT_VEC3, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniform4ivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_INT_VEC4, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniform1uivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_UNSIGNED_INT, program, location,
|
|
count);
|
|
}
|
|
|
|
bool ValidateProgramUniform2uivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_UNSIGNED_INT_VEC2, program, location,
|
|
count);
|
|
}
|
|
|
|
bool ValidateProgramUniform3uivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_UNSIGNED_INT_VEC3, program, location,
|
|
count);
|
|
}
|
|
|
|
bool ValidateProgramUniform4uivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_UNSIGNED_INT_VEC4, program, location,
|
|
count);
|
|
}
|
|
|
|
bool ValidateProgramUniform1fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_FLOAT, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniform2fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_FLOAT_VEC2, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniform3fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_FLOAT_VEC3, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniform4fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformBase(context, entryPoint, GL_FLOAT_VEC4, program, location, count);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix2fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT2, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix3fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT3, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix4fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT4, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix2x3fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT2x3, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix3x2fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT3x2, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix2x4fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT2x4, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix4x2fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT4x2, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix3x4fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT3x4, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix4x3fvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
UniformLocation location,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
return ValidateProgramUniformMatrixBase(context, entryPoint, GL_FLOAT_MAT4x3, program, location,
|
|
count, transpose);
|
|
}
|
|
|
|
bool ValidateGetTexLevelParameterfv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureTarget target,
|
|
GLint level,
|
|
GLenum pname,
|
|
const GLfloat *params)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGetTexLevelParameterBase(context, entryPoint, target, level, pname, nullptr);
|
|
}
|
|
|
|
bool ValidateGetTexLevelParameterfvRobustANGLE(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureTarget target,
|
|
GLint level,
|
|
GLenum pname,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLfloat *params)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateGetTexLevelParameteriv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureTarget target,
|
|
GLint level,
|
|
GLenum pname,
|
|
const GLint *params)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGetTexLevelParameterBase(context, entryPoint, target, level, pname, nullptr);
|
|
}
|
|
|
|
bool ValidateGetTexLevelParameterivRobustANGLE(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureTarget target,
|
|
GLint level,
|
|
GLenum pname,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLint *params)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateTexStorage2DMultisample(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLsizei samples,
|
|
GLenum internalFormat,
|
|
GLsizei width,
|
|
GLsizei height,
|
|
GLboolean fixedSampleLocations)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexStorage2DMultisampleBase(context, entryPoint, target, samples, internalFormat,
|
|
width, height);
|
|
}
|
|
|
|
bool ValidateTexStorageMem2DMultisampleEXT(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLsizei samples,
|
|
GLenum internalFormat,
|
|
GLsizei width,
|
|
GLsizei height,
|
|
GLboolean fixedSampleLocations,
|
|
MemoryObjectID memory,
|
|
GLuint64 offset)
|
|
{
|
|
if (!context->getExtensions().memoryObjectEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateGetMultisamplefv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum pname,
|
|
GLuint index,
|
|
const GLfloat *val)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGetMultisamplefvBase(context, entryPoint, pname, index, val);
|
|
}
|
|
|
|
bool ValidateGetMultisamplefvRobustANGLE(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum pname,
|
|
GLuint index,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLfloat *val)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateFramebufferParameteri(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLenum pname,
|
|
GLint param)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateFramebufferParameteriBase(context, entryPoint, target, pname, param);
|
|
}
|
|
|
|
bool ValidateGetFramebufferParameteriv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLenum pname,
|
|
const GLint *params)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGetFramebufferParameterivBase(context, entryPoint, target, pname, params);
|
|
}
|
|
|
|
bool ValidateGetFramebufferParameterivRobustANGLE(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLenum pname,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLint *params)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateGetProgramResourceIndex(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
const GLchar *name)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
if (programObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateNamedProgramInterface(programInterface))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramInterface);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateBindVertexBuffer(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint bindingIndex,
|
|
BufferID buffer,
|
|
GLintptr offset,
|
|
GLsizei stride)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
if (!context->isBufferGenerated(buffer))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kObjectNotGenerated);
|
|
return false;
|
|
}
|
|
|
|
const Caps &caps = context->getCaps();
|
|
if (bindingIndex >= static_cast<GLuint>(caps.maxVertexAttribBindings))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kExceedsMaxVertexAttribBindings);
|
|
return false;
|
|
}
|
|
|
|
if (offset < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
|
|
return false;
|
|
}
|
|
|
|
if (stride < 0 || stride > caps.maxVertexAttribStride)
|
|
{
|
|
context->validationError(entryPoint, 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().value == 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultVertexArray);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateVertexBindingDivisor(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint bindingIndex,
|
|
GLuint divisor)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
const Caps &caps = context->getCaps();
|
|
if (bindingIndex >= static_cast<GLuint>(caps.maxVertexAttribBindings))
|
|
{
|
|
context->validationError(entryPoint, 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().value == 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultVertexArray);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateVertexAttribFormat(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint attribindex,
|
|
GLint size,
|
|
VertexAttribType type,
|
|
GLboolean normalized,
|
|
GLuint relativeoffset)
|
|
{
|
|
if (!ValidateVertexAttribFormatCommon(context, entryPoint, relativeoffset))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ValidateFloatVertexFormat(context, entryPoint, attribindex, size, type);
|
|
}
|
|
|
|
bool ValidateVertexAttribIFormat(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint attribindex,
|
|
GLint size,
|
|
VertexAttribType type,
|
|
GLuint relativeoffset)
|
|
{
|
|
if (!ValidateVertexAttribFormatCommon(context, entryPoint, relativeoffset))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ValidateIntegerVertexFormat(context, entryPoint, attribindex, size, type);
|
|
}
|
|
|
|
bool ValidateVertexAttribBinding(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint attribIndex,
|
|
GLuint bindingIndex)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, 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().value == 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kDefaultVertexArray);
|
|
return false;
|
|
}
|
|
|
|
const Caps &caps = context->getCaps();
|
|
if (attribIndex >= static_cast<GLuint>(caps.maxVertexAttributes))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kIndexExceedsMaxVertexAttribute);
|
|
return false;
|
|
}
|
|
|
|
if (bindingIndex >= static_cast<GLuint>(caps.maxVertexAttribBindings))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kExceedsMaxVertexAttribBindings);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetProgramResourceName(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
GLuint index,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLchar *name)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
if (programObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateNamedProgramInterface(programInterface))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramInterface);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateProgramResourceIndex(programObject, programInterface, index))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidProgramResourceIndex);
|
|
return false;
|
|
}
|
|
|
|
if (bufSize < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateDispatchCompute(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint numGroupsX,
|
|
GLuint numGroupsY,
|
|
GLuint numGroupsZ)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
const State &state = context->getState();
|
|
const ProgramExecutable *executable = state.getProgramExecutable();
|
|
|
|
if (executable == nullptr || !executable->hasLinkedShaderStage(ShaderType::Compute))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kNoActiveProgramWithComputeShader);
|
|
return false;
|
|
}
|
|
|
|
const Caps &caps = context->getCaps();
|
|
if (numGroupsX > static_cast<GLuint>(caps.maxComputeWorkGroupCount[0]))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kExceedsComputeWorkGroupCountX);
|
|
return false;
|
|
}
|
|
if (numGroupsY > static_cast<GLuint>(caps.maxComputeWorkGroupCount[1]))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kExceedsComputeWorkGroupCountY);
|
|
return false;
|
|
}
|
|
if (numGroupsZ > static_cast<GLuint>(caps.maxComputeWorkGroupCount[2]))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kExceedsComputeWorkGroupCountZ);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateDispatchComputeIndirect(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLintptr indirect)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
const State &state = context->getState();
|
|
const ProgramExecutable *executable = state.getProgramExecutable();
|
|
|
|
if (executable == nullptr || !executable->hasLinkedShaderStage(ShaderType::Compute))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kNoActiveProgramWithComputeShader);
|
|
return false;
|
|
}
|
|
|
|
if (indirect < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeOffset);
|
|
return false;
|
|
}
|
|
|
|
if ((indirect & (sizeof(GLuint) - 1)) != 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kOffsetMustBeMultipleOfUint);
|
|
return false;
|
|
}
|
|
|
|
Buffer *dispatchIndirectBuffer = state.getTargetBuffer(BufferBinding::DispatchIndirect);
|
|
if (!dispatchIndirectBuffer)
|
|
{
|
|
context->validationError(entryPoint, 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(entryPoint, GL_INVALID_OPERATION, kInsufficientBufferSize);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateBindImageTexture(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint unit,
|
|
TextureID texture,
|
|
GLint level,
|
|
GLboolean layered,
|
|
GLint layer,
|
|
GLenum access,
|
|
GLenum format)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
GLuint maxImageUnits = static_cast<GLuint>(context->getCaps().maxImageUnits);
|
|
if (unit >= maxImageUnits)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kExceedsMaxImageUnits);
|
|
return false;
|
|
}
|
|
|
|
if (level < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeLevel);
|
|
return false;
|
|
}
|
|
|
|
if (layer < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeLayer);
|
|
return false;
|
|
}
|
|
|
|
if (access != GL_READ_ONLY && access != GL_WRITE_ONLY && access != GL_READ_WRITE)
|
|
{
|
|
context->validationError(entryPoint, 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(entryPoint, GL_INVALID_VALUE, kInvalidImageFormat);
|
|
return false;
|
|
}
|
|
|
|
if (texture.value != 0)
|
|
{
|
|
Texture *tex = context->getTexture(texture);
|
|
|
|
if (tex == nullptr)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kMissingTextureName);
|
|
return false;
|
|
}
|
|
|
|
if (!tex->getImmutableFormat())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureIsNotImmutable);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetProgramResourceLocation(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
const GLchar *name)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
if (programObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!programObject->isLinked())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateLocationProgramInterface(programInterface))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramInterface);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetProgramResourceiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
GLuint index,
|
|
GLsizei propCount,
|
|
const GLenum *props,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLint *params)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
if (programObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
if (!ValidateProgramInterface(programInterface))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramInterface);
|
|
return false;
|
|
}
|
|
if (propCount <= 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidPropCount);
|
|
return false;
|
|
}
|
|
if (bufSize < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufSize);
|
|
return false;
|
|
}
|
|
if (!ValidateProgramResourceIndex(programObject, programInterface, index))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidProgramResourceIndex);
|
|
return false;
|
|
}
|
|
for (GLsizei i = 0; i < propCount; i++)
|
|
{
|
|
if (!ValidateProgramResourceProperty(context, entryPoint, props[i]))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidProgramResourceProperty);
|
|
return false;
|
|
}
|
|
if (!ValidateProgramResourcePropertyByInterface(props[i], programInterface))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kInvalidPropertyForProgramInterface);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetProgramInterfaceiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
GLenum pname,
|
|
const GLint *params)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
if (programObject == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ValidateProgramInterface(programInterface))
|
|
{
|
|
context->validationError(entryPoint, 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(entryPoint, GL_INVALID_ENUM, kInvalidPname);
|
|
return false;
|
|
}
|
|
|
|
if (pname == GL_MAX_NAME_LENGTH && programInterface == GL_ATOMIC_COUNTER_BUFFER)
|
|
{
|
|
context->validationError(entryPoint, 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(entryPoint, GL_INVALID_OPERATION,
|
|
kMaxActiveVariablesInterface);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetProgramInterfaceivRobustANGLE(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
GLenum pname,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLint *params)
|
|
{
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateGenProgramPipelinesBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLsizei n,
|
|
const ProgramPipelineID *pipelines)
|
|
{
|
|
return ValidateGenOrDelete(context, entryPoint, n);
|
|
}
|
|
|
|
bool ValidateDeleteProgramPipelinesBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLsizei n,
|
|
const ProgramPipelineID *pipelines)
|
|
{
|
|
return ValidateGenOrDelete(context, entryPoint, n);
|
|
}
|
|
|
|
bool ValidateBindProgramPipelineBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline)
|
|
{
|
|
if (!context->isProgramPipelineGenerated({pipeline}))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kObjectNotGenerated);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateIsProgramPipelineBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool ValidateUseProgramStagesBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline,
|
|
GLbitfield stages,
|
|
ShaderProgramID programId)
|
|
{
|
|
// GL_INVALID_VALUE is generated if shaders contains set bits that are not recognized, and is
|
|
// not the reserved value GL_ALL_SHADER_BITS.
|
|
GLbitfield knownShaderBits =
|
|
GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT | GL_COMPUTE_SHADER_BIT;
|
|
|
|
if (context->getClientVersion() >= ES_3_2 || context->getExtensions().geometryShaderAny())
|
|
{
|
|
knownShaderBits |= GL_GEOMETRY_SHADER_BIT;
|
|
}
|
|
|
|
if (context->getClientVersion() >= ES_3_2 || context->getExtensions().tessellationShaderEXT)
|
|
{
|
|
knownShaderBits |= GL_TESS_CONTROL_SHADER_BIT;
|
|
knownShaderBits |= GL_TESS_EVALUATION_SHADER_BIT;
|
|
}
|
|
|
|
if ((stages & ~knownShaderBits) && (stages != GL_ALL_SHADER_BITS))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kUnrecognizedShaderStageBit);
|
|
return false;
|
|
}
|
|
|
|
// GL_INVALID_OPERATION is generated if pipeline is not a name previously returned from a call
|
|
// to glGenProgramPipelines or if such a name has been deleted by a call to
|
|
// glDeleteProgramPipelines.
|
|
if (!context->isProgramPipelineGenerated({pipeline}))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kObjectNotGenerated);
|
|
return false;
|
|
}
|
|
|
|
// If program is zero, or refers to a program object with no valid shader executable for a given
|
|
// stage, it is as if the pipeline object has no programmable stage configured for the indicated
|
|
// shader stages.
|
|
if (programId.value == 0)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Program *program = context->getProgramNoResolveLink(programId);
|
|
if (!program)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kProgramDoesNotExist);
|
|
return false;
|
|
}
|
|
|
|
// GL_INVALID_OPERATION is generated if program refers to a program object that was not linked
|
|
// with its GL_PROGRAM_SEPARABLE status set.
|
|
// resolveLink() may not have been called if glCreateShaderProgramv() was not used and
|
|
// glDetachShader() was not called.
|
|
program->resolveLink(context);
|
|
if (!program->isSeparable())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotSeparable);
|
|
return false;
|
|
}
|
|
|
|
// GL_INVALID_OPERATION is generated if program refers to a program object that has not been
|
|
// successfully linked.
|
|
if (!program->isLinked())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateActiveShaderProgramBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline,
|
|
ShaderProgramID programId)
|
|
{
|
|
// An INVALID_OPERATION error is generated if pipeline is not a name returned from a previous
|
|
// call to GenProgramPipelines or if such a name has since been deleted by
|
|
// DeleteProgramPipelines.
|
|
if (!context->isProgramPipelineGenerated({pipeline}))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kObjectNotGenerated);
|
|
return false;
|
|
}
|
|
|
|
// An INVALID_VALUE error is generated if program is not zero and is not the name of either a
|
|
// program or shader object.
|
|
if ((programId.value != 0) && !context->isProgram(programId) && !context->isShader(programId))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kProgramDoesNotExist);
|
|
return false;
|
|
}
|
|
|
|
// An INVALID_OPERATION error is generated if program is the name of a shader object.
|
|
if (context->isShader(programId))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kExpectedProgramName);
|
|
return false;
|
|
}
|
|
|
|
// An INVALID_OPERATION error is generated if program is not zero and has not been linked, or
|
|
// was last linked unsuccessfully. The active program is not modified.
|
|
Program *program = context->getProgramNoResolveLink(programId);
|
|
if ((programId.value != 0) && !program->isLinked())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateCreateShaderProgramvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderType type,
|
|
GLsizei count,
|
|
const GLchar *const *strings)
|
|
{
|
|
switch (type)
|
|
{
|
|
case ShaderType::InvalidEnum:
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidShaderType);
|
|
return false;
|
|
case ShaderType::Vertex:
|
|
case ShaderType::Fragment:
|
|
case ShaderType::Compute:
|
|
break;
|
|
case ShaderType::Geometry:
|
|
if (!context->getExtensions().geometryShaderAny() &&
|
|
context->getClientVersion() < ES_3_2)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidShaderType);
|
|
return false;
|
|
}
|
|
break;
|
|
case ShaderType::TessControl:
|
|
case ShaderType::TessEvaluation:
|
|
if (!context->getExtensions().tessellationShaderEXT &&
|
|
context->getClientVersion() < ES_3_2)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidShaderType);
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
|
|
// GL_INVALID_VALUE is generated if count is negative.
|
|
if (count < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeCount);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateCreateShaderProgramvBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderType type,
|
|
GLsizei count,
|
|
const GLchar **strings)
|
|
{
|
|
const GLchar *const *tmpStrings = strings;
|
|
return ValidateCreateShaderProgramvBase(context, entryPoint, type, count, tmpStrings);
|
|
}
|
|
|
|
bool ValidateGetProgramPipelineivBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline,
|
|
GLenum pname,
|
|
const GLint *params)
|
|
{
|
|
// An INVALID_OPERATION error is generated if pipeline is not a name returned from a previous
|
|
// call to GenProgramPipelines or if such a name has since been deleted by
|
|
// DeleteProgramPipelines.
|
|
if ((pipeline.value == 0) || (!context->isProgramPipelineGenerated(pipeline)))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramPipelineDoesNotExist);
|
|
return false;
|
|
}
|
|
|
|
// An INVALID_ENUM error is generated if pname is not ACTIVE_PROGRAM,
|
|
// INFO_LOG_LENGTH, VALIDATE_STATUS, or one of the type arguments in
|
|
// table 7.1.
|
|
switch (pname)
|
|
{
|
|
case GL_ACTIVE_PROGRAM:
|
|
case GL_INFO_LOG_LENGTH:
|
|
case GL_VALIDATE_STATUS:
|
|
case GL_VERTEX_SHADER:
|
|
case GL_FRAGMENT_SHADER:
|
|
case GL_COMPUTE_SHADER:
|
|
break;
|
|
case GL_GEOMETRY_SHADER:
|
|
return context->getExtensions().geometryShaderAny() ||
|
|
context->getClientVersion() >= ES_3_2;
|
|
case GL_TESS_CONTROL_SHADER:
|
|
case GL_TESS_EVALUATION_SHADER:
|
|
return context->getExtensions().tessellationShaderEXT ||
|
|
context->getClientVersion() >= ES_3_2;
|
|
|
|
default:
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidPname);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateValidateProgramPipelineBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline)
|
|
{
|
|
if (pipeline.value == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!context->isProgramPipelineGenerated(pipeline))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramPipelineDoesNotExist);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGetProgramPipelineInfoLogBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipeline,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLchar *infoLog)
|
|
{
|
|
if (bufSize < 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeBufferSize);
|
|
return false;
|
|
}
|
|
|
|
if (!context->isProgramPipelineGenerated(pipeline))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kProgramPipelineDoesNotExist);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateActiveShaderProgram(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked,
|
|
ShaderProgramID programPacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateActiveShaderProgramBase(context, entryPoint, pipelinePacked, programPacked);
|
|
}
|
|
|
|
bool ValidateBindProgramPipeline(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateBindProgramPipelineBase(context, entryPoint, pipelinePacked);
|
|
}
|
|
|
|
bool ValidateCreateShaderProgramv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderType typePacked,
|
|
GLsizei count,
|
|
const GLchar *const *strings)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateCreateShaderProgramvBase(context, entryPoint, typePacked, count, strings);
|
|
}
|
|
|
|
bool ValidateDeleteProgramPipelines(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLsizei n,
|
|
const ProgramPipelineID *pipelinesPacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateDeleteProgramPipelinesBase(context, entryPoint, n, pipelinesPacked);
|
|
}
|
|
|
|
bool ValidateGenProgramPipelines(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLsizei n,
|
|
const ProgramPipelineID *pipelinesPacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGenProgramPipelinesBase(context, entryPoint, n, pipelinesPacked);
|
|
}
|
|
|
|
bool ValidateGetProgramPipelineInfoLog(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked,
|
|
GLsizei bufSize,
|
|
const GLsizei *length,
|
|
const GLchar *infoLog)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGetProgramPipelineInfoLogBase(context, entryPoint, pipelinePacked, bufSize,
|
|
length, infoLog);
|
|
}
|
|
|
|
bool ValidateGetProgramPipelineiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked,
|
|
GLenum pname,
|
|
const GLint *params)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateGetProgramPipelineivBase(context, entryPoint, pipelinePacked, pname, params);
|
|
}
|
|
|
|
bool ValidateIsProgramPipeline(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateIsProgramPipelineBase(context, entryPoint, pipelinePacked);
|
|
}
|
|
|
|
bool ValidateProgramUniform1f(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLfloat v0)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform1fBase(context, entryPoint, programPacked, locationPacked, v0);
|
|
}
|
|
|
|
bool ValidateProgramUniform1fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform1fvBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform1i(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLint v0)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform1iBase(context, entryPoint, programPacked, locationPacked, v0);
|
|
}
|
|
|
|
bool ValidateProgramUniform1iv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform1ivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform1ui(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLuint v0)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform1uiBase(context, entryPoint, programPacked, locationPacked, v0);
|
|
}
|
|
|
|
bool ValidateProgramUniform1uiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform1uivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform2f(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLfloat v0,
|
|
GLfloat v1)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform2fBase(context, entryPoint, programPacked, locationPacked, v0, v1);
|
|
}
|
|
|
|
bool ValidateProgramUniform2fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform2fvBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform2i(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLint v0,
|
|
GLint v1)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform2iBase(context, entryPoint, programPacked, locationPacked, v0, v1);
|
|
}
|
|
|
|
bool ValidateProgramUniform2iv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform2ivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform2ui(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLuint v0,
|
|
GLuint v1)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform2uiBase(context, entryPoint, programPacked, locationPacked, v0,
|
|
v1);
|
|
}
|
|
|
|
bool ValidateProgramUniform2uiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform2uivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform3f(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLfloat v0,
|
|
GLfloat v1,
|
|
GLfloat v2)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform3fBase(context, entryPoint, programPacked, locationPacked, v0, v1,
|
|
v2);
|
|
}
|
|
|
|
bool ValidateProgramUniform3fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform3fvBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform3i(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLint v0,
|
|
GLint v1,
|
|
GLint v2)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform3iBase(context, entryPoint, programPacked, locationPacked, v0, v1,
|
|
v2);
|
|
}
|
|
|
|
bool ValidateProgramUniform3iv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform3ivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform3ui(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLuint v0,
|
|
GLuint v1,
|
|
GLuint v2)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform3uiBase(context, entryPoint, programPacked, locationPacked, v0, v1,
|
|
v2);
|
|
}
|
|
|
|
bool ValidateProgramUniform3uiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform3uivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform4f(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLfloat v0,
|
|
GLfloat v1,
|
|
GLfloat v2,
|
|
GLfloat v3)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform4fBase(context, entryPoint, programPacked, locationPacked, v0, v1,
|
|
v2, v3);
|
|
}
|
|
|
|
bool ValidateProgramUniform4fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform4fvBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform4i(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLint v0,
|
|
GLint v1,
|
|
GLint v2,
|
|
GLint v3)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform4iBase(context, entryPoint, programPacked, locationPacked, v0, v1,
|
|
v2, v3);
|
|
}
|
|
|
|
bool ValidateProgramUniform4iv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform4ivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniform4ui(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLuint v0,
|
|
GLuint v1,
|
|
GLuint v2,
|
|
GLuint v3)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform4uiBase(context, entryPoint, programPacked, locationPacked, v0, v1,
|
|
v2, v3);
|
|
}
|
|
|
|
bool ValidateProgramUniform4uiv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
const GLuint *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniform4uivBase(context, entryPoint, programPacked, locationPacked, count,
|
|
value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix2fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix2fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix2x3fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix2x3fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix2x4fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix2x4fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix3fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix3fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix3x2fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix3x2fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix3x4fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix3x4fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix4fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix4fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix4x2fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix4x2fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateProgramUniformMatrix4x3fv(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID programPacked,
|
|
UniformLocation locationPacked,
|
|
GLsizei count,
|
|
GLboolean transpose,
|
|
const GLfloat *value)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateProgramUniformMatrix4x3fvBase(context, entryPoint, programPacked, locationPacked,
|
|
count, transpose, value);
|
|
}
|
|
|
|
bool ValidateUseProgramStages(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked,
|
|
GLbitfield stages,
|
|
ShaderProgramID programPacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateUseProgramStagesBase(context, entryPoint, pipelinePacked, stages, programPacked);
|
|
}
|
|
|
|
bool ValidateValidateProgramPipeline(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ProgramPipelineID pipelinePacked)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateValidateProgramPipelineBase(context, entryPoint, pipelinePacked);
|
|
}
|
|
|
|
bool ValidateMemoryBarrier(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLbitfield barriers)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, 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 (context->getExtensions().bufferStorageEXT)
|
|
{
|
|
supported_barrier_bits |= GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT;
|
|
}
|
|
|
|
if (barriers == 0 || (barriers & ~supported_barrier_bits) != 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMemoryBarrierBit);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateMemoryBarrierByRegion(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLbitfield barriers)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, 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(entryPoint, GL_INVALID_VALUE, kInvalidMemoryBarrierBit);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateSampleMaski(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLuint maskNumber,
|
|
GLbitfield mask)
|
|
{
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
|
|
return ValidateSampleMaskiBase(context, entryPoint, maskNumber, mask);
|
|
}
|
|
|
|
bool ValidateMinSampleShadingOES(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLfloat value)
|
|
{
|
|
if (!context->getExtensions().sampleShadingOES)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateFramebufferTextureCommon(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLenum attachment,
|
|
TextureID texture,
|
|
GLint level)
|
|
{
|
|
if (texture.value != 0)
|
|
{
|
|
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(entryPoint, GL_INVALID_VALUE, kInvalidTextureName);
|
|
return false;
|
|
}
|
|
|
|
if (!ValidMipLevel(context, tex->getType(), level))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
|
|
return false;
|
|
}
|
|
|
|
// GLES spec 3.1, Section 9.2.8 "Attaching Texture Images to a Framebuffer"
|
|
// If textarget is TEXTURE_2D_MULTISAMPLE, then level must be zero.
|
|
if (tex->getType() == TextureType::_2DMultisample && level != 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kLevelNotZero);
|
|
return false;
|
|
}
|
|
|
|
// [OES_texture_storage_multisample_2d_array] Section 9.2.2 "Attaching Images to Framebuffer
|
|
// Objects"
|
|
// If texture is a two-dimensional multisample array texture, then level must be zero.
|
|
if (context->getExtensions().textureStorageMultisample2dArrayOES &&
|
|
tex->getType() == TextureType::_2DMultisampleArray && level != 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kLevelNotZero);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!ValidateFramebufferTextureBase(context, entryPoint, target, attachment, texture, level))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateFramebufferTextureEXT(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLenum attachment,
|
|
TextureID texture,
|
|
GLint level)
|
|
{
|
|
if (!context->getExtensions().geometryShaderEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kGeometryShaderExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
|
|
return ValidateFramebufferTextureCommon(context, entryPoint, target, attachment, texture,
|
|
level);
|
|
}
|
|
|
|
bool ValidateFramebufferTextureOES(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
GLenum target,
|
|
GLenum attachment,
|
|
TextureID texture,
|
|
GLint level)
|
|
{
|
|
if (!context->getExtensions().geometryShaderOES)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kGeometryShaderExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
|
|
return ValidateFramebufferTextureCommon(context, entryPoint, target, attachment, texture,
|
|
level);
|
|
}
|
|
|
|
// GL_OES_texture_storage_multisample_2d_array
|
|
bool ValidateTexStorage3DMultisampleOES(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLsizei samples,
|
|
GLenum sizedinternalformat,
|
|
GLsizei width,
|
|
GLsizei height,
|
|
GLsizei depth,
|
|
GLboolean fixedsamplelocations)
|
|
{
|
|
if (!context->getExtensions().textureStorageMultisample2dArrayOES)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kMultisampleArrayExtensionRequired);
|
|
return false;
|
|
}
|
|
|
|
if (target != TextureType::_2DMultisampleArray)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM,
|
|
kTargetMustBeTexture2DMultisampleArrayOES);
|
|
return false;
|
|
}
|
|
|
|
if (width < 1 || height < 1 || depth < 1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kNegativeSize);
|
|
return false;
|
|
}
|
|
|
|
if (depth > context->getCaps().maxArrayTextureLayers)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kTextureDepthOutOfRange);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexStorageMultisample(context, entryPoint, target, samples, sizedinternalformat,
|
|
width, height);
|
|
}
|
|
|
|
bool ValidateTexStorageMem3DMultisampleEXT(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLsizei samples,
|
|
GLenum internalFormat,
|
|
GLsizei width,
|
|
GLsizei height,
|
|
GLsizei depth,
|
|
GLboolean fixedSampleLocations,
|
|
MemoryObjectID memory,
|
|
GLuint64 offset)
|
|
{
|
|
if (!context->getExtensions().memoryObjectEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
|
|
UNIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool ValidateGetProgramResourceLocationIndexEXT(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
ShaderProgramID program,
|
|
GLenum programInterface,
|
|
const char *name)
|
|
{
|
|
if (!context->getExtensions().blendFuncExtendedEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kExtensionNotEnabled);
|
|
return false;
|
|
}
|
|
if (context->getClientVersion() < ES_3_1)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kES31Required);
|
|
return false;
|
|
}
|
|
if (programInterface != GL_PROGRAM_OUTPUT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kProgramInterfaceMustBeProgramOutput);
|
|
return false;
|
|
}
|
|
Program *programObject = GetValidProgram(context, entryPoint, program);
|
|
if (!programObject)
|
|
{
|
|
return false;
|
|
}
|
|
if (!programObject->isLinked())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kProgramNotLinked);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// GL_OES_texture_buffer
|
|
bool ValidateTexBufferOES(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLenum internalformat,
|
|
BufferID bufferPacked)
|
|
{
|
|
if (!context->getExtensions().textureBufferOES)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kTextureBufferExtensionNotAvailable);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexBufferBase(context, entryPoint, target, internalformat, bufferPacked);
|
|
}
|
|
|
|
bool ValidateTexBufferRangeOES(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLenum internalformat,
|
|
BufferID bufferPacked,
|
|
GLintptr offset,
|
|
GLsizeiptr size)
|
|
{
|
|
if (!context->getExtensions().textureBufferOES)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kTextureBufferExtensionNotAvailable);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexBufferRangeBase(context, entryPoint, target, internalformat, bufferPacked,
|
|
offset, size);
|
|
}
|
|
|
|
// GL_EXT_texture_buffer
|
|
bool ValidateTexBufferEXT(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLenum internalformat,
|
|
BufferID bufferPacked)
|
|
{
|
|
if (!context->getExtensions().textureBufferEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kTextureBufferExtensionNotAvailable);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexBufferBase(context, entryPoint, target, internalformat, bufferPacked);
|
|
}
|
|
|
|
bool ValidateTexBufferRangeEXT(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLenum internalformat,
|
|
BufferID bufferPacked,
|
|
GLintptr offset,
|
|
GLsizeiptr size)
|
|
{
|
|
if (!context->getExtensions().textureBufferEXT)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION,
|
|
kTextureBufferExtensionNotAvailable);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexBufferRangeBase(context, entryPoint, target, internalformat, bufferPacked,
|
|
offset, size);
|
|
}
|
|
|
|
bool ValidateTexBufferBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLenum internalformat,
|
|
BufferID bufferPacked)
|
|
{
|
|
if (target != TextureType::Buffer)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kTextureBufferTarget);
|
|
return false;
|
|
}
|
|
|
|
switch (internalformat)
|
|
{
|
|
case GL_R8:
|
|
case GL_R16F:
|
|
case GL_R32F:
|
|
case GL_R8I:
|
|
case GL_R16I:
|
|
case GL_R32I:
|
|
case GL_R8UI:
|
|
case GL_R16UI:
|
|
case GL_R32UI:
|
|
case GL_RG8:
|
|
case GL_RG16F:
|
|
case GL_RG32F:
|
|
case GL_RG8I:
|
|
case GL_RG16I:
|
|
case GL_RG32I:
|
|
case GL_RG8UI:
|
|
case GL_RG16UI:
|
|
case GL_RG32UI:
|
|
case GL_RGB32F:
|
|
case GL_RGB32I:
|
|
case GL_RGB32UI:
|
|
case GL_RGBA8:
|
|
case GL_RGBA16F:
|
|
case GL_RGBA32F:
|
|
case GL_RGBA8I:
|
|
case GL_RGBA16I:
|
|
case GL_RGBA32I:
|
|
case GL_RGBA8UI:
|
|
case GL_RGBA16UI:
|
|
case GL_RGBA32UI:
|
|
break;
|
|
|
|
default:
|
|
context->validationError(entryPoint, GL_INVALID_ENUM, kTextureBufferInternalFormat);
|
|
return false;
|
|
}
|
|
|
|
if (bufferPacked.value != 0)
|
|
{
|
|
if (!context->isBufferGenerated(bufferPacked))
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureBufferInvalidBuffer);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateTexBufferRangeBase(const Context *context,
|
|
angle::EntryPoint entryPoint,
|
|
TextureType target,
|
|
GLenum internalformat,
|
|
BufferID bufferPacked,
|
|
GLintptr offset,
|
|
GLsizeiptr size)
|
|
{
|
|
const Caps &caps = context->getCaps();
|
|
|
|
if (offset < 0 || (offset % caps.textureBufferOffsetAlignment) != 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kTextureBufferOffsetAlignment);
|
|
return false;
|
|
}
|
|
if (size <= 0)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kTextureBufferSize);
|
|
return false;
|
|
}
|
|
const Buffer *buffer = context->getBuffer(bufferPacked);
|
|
|
|
if (!buffer)
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotBound);
|
|
return false;
|
|
}
|
|
|
|
if (offset + size > buffer->getSize())
|
|
{
|
|
context->validationError(entryPoint, GL_INVALID_VALUE, kTextureBufferSizeOffset);
|
|
return false;
|
|
}
|
|
|
|
return ValidateTexBufferBase(context, entryPoint, target, internalformat, bufferPacked);
|
|
}
|
|
|
|
} // namespace gl
|