Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/angle/checkout/src/libANGLE/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 113 kB image not shown  

Quelle  validationES31.cpp   Sprache: 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() && tex->getType() != gl::TextureType::Buffer)
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION,
                                     kTextureIsNeitherImmutableNorTextureBuffer);
            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,
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=100 G=98

¤ Dauer der Verarbeitung: 0.45 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.