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 221 kB image not shown  

Quelle  validationES2.cpp   Sprache: C

 
//
// Copyright 2013 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.
//

// validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters

#include "libANGLE/validationES2_autogen.h"

#include <cstdint>

#include "common/mathutil.h"
#include "common/string_utils.h"
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/ErrorStrings.h"
#include "libANGLE/Fence.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/MemoryObject.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/Shader.h"
#include "libANGLE/Texture.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/VertexArray.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/validationES.h"
#include "libANGLE/validationES2.h"
#include "libANGLE/validationES3_autogen.h"

namespace gl
{
using namespace err;

namespace
{

bool IsPartialBlit(const Context *context,
                   const FramebufferAttachment *readBuffer,
                   const FramebufferAttachment *writeBuffer,
                   GLint srcX0,
                   GLint srcY0,
                   GLint srcX1,
                   GLint srcY1,
                   GLint dstX0,
                   GLint dstY0,
                   GLint dstX1,
                   GLint dstY1)
{
    const Extents &writeSize = writeBuffer->getSize();
    const Extents &readSize  = readBuffer->getSize();

    if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width ||
        dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height)
    {
        return true;
    }

    if (context->getState().isScissorTestEnabled())
    {
        const Rectangle &scissor = context->getState().getScissor();
        return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
               scissor.height < writeSize.height;
    }

    return false;
}

bool IsValidCopyTextureSourceInternalFormatEnum(GLenum internalFormat)
{
    // Table 1.1 from the CHROMIUM_copy_texture spec
    switch (GetUnsizedFormat(internalFormat))
    {
        case GL_RED:
        case GL_ALPHA:
        case GL_LUMINANCE:
        case GL_LUMINANCE_ALPHA:
        case GL_RGB:
        case GL_RGBA:
        case GL_RGB8:
        case GL_RGBA8:
        case GL_BGRA_EXT:
        case GL_BGRA8_EXT:
            return true;

        default:
            return false;
    }
}

bool IsValidCopySubTextureSourceInternalFormat(GLenum internalFormat)
{
    return IsValidCopyTextureSourceInternalFormatEnum(internalFormat);
}

bool IsValidCopyTextureDestinationInternalFormatEnum(GLint internalFormat)
{
    // Table 1.0 from the CHROMIUM_copy_texture spec
    switch (internalFormat)
    {
        case GL_ALPHA:
        case GL_BGRA8_EXT:
        case GL_BGRA_EXT:
        case GL_LUMINANCE:
        case GL_LUMINANCE_ALPHA:
        case GL_R11F_G11F_B10F:
        case GL_R16F:
        case GL_R32F:
        case GL_R8:
        case GL_R8UI:
        case GL_RG16F:
        case GL_RG32F:
        case GL_RG8:
        case GL_RG8UI:
        case GL_RGB:
        case GL_RGB10_A2:
        case GL_RGB16F:
        case GL_RGB32F:
        case GL_RGB565:
        case GL_RGB5_A1:
        case GL_RGB8:
        case GL_RGB8UI:
        case GL_RGB9_E5:
        case GL_RGBA:
        case GL_RGBA16F:
        case GL_RGBA32F:
        case GL_RGBA4:
        case GL_RGBA8:
        case GL_RGBA8UI:
        case GL_RGBX8_ANGLE:
        case GL_SRGB8:
        case GL_SRGB8_ALPHA8:
        case GL_SRGB_ALPHA_EXT:
        case GL_SRGB_EXT:
            return true;

        default:
            return false;
    }
}

bool IsValidCopySubTextureDestionationInternalFormat(GLenum internalFormat)
{
    return IsValidCopyTextureDestinationInternalFormatEnum(internalFormat);
}

bool IsValidCopyTextureDestinationFormatType(const Context *context,
                                             angle::EntryPoint entryPoint,
                                             GLint internalFormat,
                                             GLenum type)
{
    if (!IsValidCopyTextureDestinationInternalFormatEnum(internalFormat))
    {
        context->validationErrorF(entryPoint, GL_INVALID_OPERATION, kInvalidInternalFormat,
                                  internalFormat);
        return false;
    }

    if (!ValidES3FormatCombination(GetUnsizedFormat(internalFormat), type, internalFormat))
    {
        context->validationError(entryPoint, GL_INVALID_OPERATION, kMismatchedTypeAndFormat);
        return false;
    }

    const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
    if (!internalFormatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
    {
        context->validationErrorF(entryPoint, GL_INVALID_OPERATION, kInvalidInternalFormat,
                                  internalFormat);
        return false;
    }

    return true;
}

bool IsValidCopyTextureDestinationTargetEnum(const Context *context, TextureTarget target)
{
    switch (target)
    {
        case TextureTarget::_2D:
        case TextureTarget::CubeMapNegativeX:
        case TextureTarget::CubeMapNegativeY:
        case TextureTarget::CubeMapNegativeZ:
        case TextureTarget::CubeMapPositiveX:
        case TextureTarget::CubeMapPositiveY:
        case TextureTarget::CubeMapPositiveZ:
            return true;

        case TextureTarget::Rectangle:
            return context->getExtensions().textureRectangleANGLE;

        default:
            return false;
    }
}

bool IsValidCopyTextureDestinationTarget(const Context *context,
                                         TextureType textureType,
                                         TextureTarget target)
{
    return TextureTargetToType(target) == textureType;
}

bool IsValidCopyTextureSourceTarget(const Context *context, TextureType type)
{
    switch (type)
    {
        case TextureType::_2D:
            return true;
        case TextureType::Rectangle:
            return context->getExtensions().textureRectangleANGLE;
        case TextureType::External:
            return context->getExtensions().EGLImageExternalOES;
        case TextureType::VideoImage:
            return context->getExtensions().videoTextureWEBGL;
        default:
            return false;
    }
}

bool IsValidCopyTextureSourceLevel(const Context *context, TextureType type, GLint level)
{
    if (!ValidMipLevel(context, type, level))
    {
        return false;
    }

    if (level > 0 && context->getClientVersion() < ES_3_0)
    {
        return false;
    }

    return true;
}

bool IsValidCopyTextureDestinationLevel(const Context *context,
                                        angle::EntryPoint entryPoint,
                                        TextureType type,
                                        GLint level,
                                        GLsizei width,
                                        GLsizei height,
                                        bool isSubImage)
{
    if (!ValidMipLevel(context, type, level))
    {
        return false;
    }

    if (!ValidImageSizeParameters(context, entryPoint, type, level, width, height, 1, isSubImage))
    {
        return false;
    }

    const Caps &caps = context->getCaps();
    switch (type)
    {
        case TextureType::_2D:
            return width <= (caps.max2DTextureSize >> level) &&
                   height <= (caps.max2DTextureSize >> level);
        case TextureType::Rectangle:
            ASSERT(level == 0);
            return width <= (caps.max2DTextureSize >> level) &&
                   height <= (caps.max2DTextureSize >> level);

        case TextureType::CubeMap:
            return width <= (caps.maxCubeMapTextureSize >> level) &&
                   height <= (caps.maxCubeMapTextureSize >> level);
        default:
            return true;
    }
}

bool IsValidStencilFunc(GLenum func)
{
    switch (func)
    {
        case GL_NEVER:
        case GL_ALWAYS:
        case GL_LESS:
        case GL_LEQUAL:
        case GL_EQUAL:
        case GL_GEQUAL:
        case GL_GREATER:
        case GL_NOTEQUAL:
            return true;

        default:
            return false;
    }
}

bool IsValidStencilFace(GLenum face)
{
    switch (face)
    {
        case GL_FRONT:
        case GL_BACK:
        case GL_FRONT_AND_BACK:
            return true;

        default:
            return false;
    }
}

bool IsValidStencilOp(GLenum op)
{
    switch (op)
    {
        case GL_ZERO:
        case GL_KEEP:
        case GL_REPLACE:
        case GL_INCR:
        case GL_DECR:
        case GL_INVERT:
        case GL_INCR_WRAP:
        case GL_DECR_WRAP:
            return true;

        default:
            return false;
    }
}

static inline bool Valid1to4ComponentFloatColorBufferFormat(const Context *context, GLenum format)
{
    return (context->getExtensions().textureFloatOES &&
            (format == GL_RGBA32F || format == GL_RGB32F || format == GL_RG32F ||
             format == GL_R32F)) ||
           (context->getExtensions().textureHalfFloatOES &&
            (format == GL_RGBA16F || format == GL_RGB16F || format == GL_RG16F ||
             format == GL_R16F));
}

static inline bool Valid2to4ComponentFloatColorBufferFormat(const Context *context, GLenum format)
{
    return (context->getExtensions().textureFloatOES &&
            (format == GL_RGBA32F || format == GL_RGB32F || format == GL_RG32F)) ||
           (context->getExtensions().textureHalfFloatOES &&
            (format == GL_RGBA16F || format == GL_RGB16F || format == GL_RG16F));
}

static inline bool Valid3to4ComponentFloatColorBufferFormat(const Context *context, GLenum format)
{
    return (context->getExtensions().textureFloatOES &&
            (format == GL_RGBA32F || format == GL_RGB32F)) ||
           (context->getExtensions().textureHalfFloatOES &&
            (format == GL_RGBA16F || format == GL_RGB16F));
}

static inline bool Valid4ComponentFloatColorBufferFormat(const Context *context, GLenum format)
{
    return (context->getExtensions().textureFloatOES && format == GL_RGBA32F) ||
           (context->getExtensions().textureHalfFloatOES && format == GL_RGBA16F);
}

bool ValidateES2CopyTexImageParameters(const Context *context,
                                       angle::EntryPoint entryPoint,
                                       TextureTarget target,
                                       GLint level,
                                       GLenum internalformat,
                                       bool isSubImage,
                                       GLint xoffset,
                                       GLint yoffset,
                                       GLint x,
                                       GLint y,
                                       GLsizei width,
                                       GLsizei height,
                                       GLint border)
{
    if (!ValidTexture2DDestinationTarget(context, target))
    {
        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
        return false;
    }

    TextureType texType = TextureTargetToType(target);
    if (!ValidImageSizeParameters(context, entryPoint, texType, level, width, height, 1,
                                  isSubImage))
    {
        // Error is already handled.
        return false;
    }

    Format textureFormat = Format::Invalid();
    if (!ValidateCopyTexImageParametersBase(context, entryPoint, target, level, internalformat,
                                            isSubImage, xoffset, yoffset, 0, x, y, width, height,
                                            border, &textureFormat))
    {
        return false;
    }

    ASSERT(textureFormat.valid() || !isSubImage);

    const Framebuffer *framebuffer = context->getState().getReadFramebuffer();
    GLenum colorbufferFormat =
        framebuffer->getReadColorAttachment()->getFormat().info->sizedInternalFormat;
    const auto &formatInfo = *textureFormat.info;

    // ValidateCopyTexImageParametersBase rejects compressed formats with GL_INVALID_OPERATION.
    ASSERT(!formatInfo.compressed);
    ASSERT(!GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE).compressed);

    // ValidateCopyTexImageParametersBase rejects depth formats with GL_INVALID_OPERATION.
    ASSERT(!formatInfo.depthBits);
    ASSERT(!GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE).depthBits);

    // [OpenGL ES 2.0.24] table 3.9
    if (isSubImage)
    {
        switch (formatInfo.format)
        {
            case GL_ALPHA:
                if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
                    colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES &&
                    colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    !Valid4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_LUMINANCE:
                if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
                    colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
                    colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGRA8_EXT &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid1to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_RED_EXT:
                if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
                    colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
                    colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_R32F &&
                    colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
                    colorbufferFormat != GL_RGBA32F && colorbufferFormat != GL_BGRA8_EXT &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid1to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_RG_EXT:
                if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
                    colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
                    colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES &&
                    colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
                    colorbufferFormat != GL_RGBA32F && colorbufferFormat != GL_BGRA8_EXT &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid2to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_RGB:
                if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
                    colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGB32F &&
                    colorbufferFormat != GL_RGBA32F && colorbufferFormat != GL_BGRA8_EXT &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid3to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_LUMINANCE_ALPHA:
            case GL_RGBA:
                if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGBA32F &&
                    colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    !Valid4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            default:
                context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                return false;
        }

        if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloatOES)
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
            return false;
        }
    }
    else
    {
        switch (internalformat)
        {
            case GL_ALPHA:
                if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
                    colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
                    colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    !Valid4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_LUMINANCE:
            case GL_RED_EXT:
                if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
                    colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
                    colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid1to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_RG_EXT:
                if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
                    colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
                    colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
                    colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid2to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_RGB:
                if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
                    colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX &&
                    colorbufferFormat != GL_BGRX8_ANGLEX && colorbufferFormat != GL_RGBX8_ANGLE &&
                    !Valid3to4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            case GL_LUMINANCE_ALPHA:
            case GL_RGBA:
                if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
                    colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
                    colorbufferFormat != GL_BGR5_A1_ANGLEX && colorbufferFormat != GL_RGBA16F &&
                    !Valid4ComponentFloatColorBufferFormat(context, colorbufferFormat))
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }
                break;
            default:
                context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                          internalformat);
                return false;
        }
    }

    // If width or height is zero, it is a no-op.  Return false without setting an error.
    return (width > 0 && height > 0);
}

bool ValidCap(const Context *context, GLenum cap, bool queryOnly)
{
    switch (cap)
    {
        // EXT_multisample_compatibility
        case GL_MULTISAMPLE_EXT:
        case GL_SAMPLE_ALPHA_TO_ONE_EXT:
            return context->getExtensions().multisampleCompatibilityEXT;

        case GL_CULL_FACE:
        case GL_POLYGON_OFFSET_FILL:
        case GL_SAMPLE_ALPHA_TO_COVERAGE:
        case GL_SAMPLE_COVERAGE:
        case GL_SCISSOR_TEST:
        case GL_STENCIL_TEST:
        case GL_DEPTH_TEST:
        case GL_BLEND:
        case GL_DITHER:
            return true;

        case GL_PRIMITIVE_RESTART_FIXED_INDEX:
        case GL_RASTERIZER_DISCARD:
            return (context->getClientMajorVersion() >= 3);

        case GL_DEBUG_OUTPUT_SYNCHRONOUS:
        case GL_DEBUG_OUTPUT:
            return context->getExtensions().debugKHR;

        case GL_BIND_GENERATES_RESOURCE_CHROMIUM:
            return queryOnly && context->getExtensions().bindGeneratesResourceCHROMIUM;

        case GL_CLIENT_ARRAYS_ANGLE:
            return queryOnly && context->getExtensions().clientArraysANGLE;

        case GL_FRAMEBUFFER_SRGB_EXT:
            return context->getExtensions().sRGBWriteControlEXT;

        case GL_SAMPLE_MASK:
            return context->getClientVersion() >= Version(3, 1);

        case GL_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
            return queryOnly && context->getExtensions().robustResourceInitializationANGLE;

        case GL_TEXTURE_RECTANGLE_ANGLE:
            return context->isWebGL();

        // GL_APPLE_clip_distance/GL_EXT_clip_cull_distance
        case GL_CLIP_DISTANCE0_EXT:
        case GL_CLIP_DISTANCE1_EXT:
        case GL_CLIP_DISTANCE2_EXT:
        case GL_CLIP_DISTANCE3_EXT:
        case GL_CLIP_DISTANCE4_EXT:
        case GL_CLIP_DISTANCE5_EXT:
        case GL_CLIP_DISTANCE6_EXT:
        case GL_CLIP_DISTANCE7_EXT:
            if (context->getExtensions().clipDistanceAPPLE ||
                context->getExtensions().clipCullDistanceEXT)
            {
                return true;
            }
            break;
        case GL_SAMPLE_SHADING:
            return context->getExtensions().sampleShadingOES;
        case GL_SHADING_RATE_PRESERVE_ASPECT_RATIO_QCOM:
            return context->getExtensions().shadingRateQCOM;

        // COLOR_LOGIC_OP is in GLES1, but exposed through an ANGLE extension.
        case GL_COLOR_LOGIC_OP:
            return context->getClientVersion() < Version(2, 0) ||
                   context->getExtensions().logicOpANGLE;

        default:
            break;
    }

    // GLES1 emulation: GLES1-specific caps after this point
    if (context->getClientVersion().major != 1)
    {
        return false;
    }

    switch (cap)
    {
        case GL_ALPHA_TEST:
        case GL_VERTEX_ARRAY:
        case GL_NORMAL_ARRAY:
        case GL_COLOR_ARRAY:
        case GL_TEXTURE_COORD_ARRAY:
        case GL_TEXTURE_2D:
        case GL_LIGHTING:
        case GL_LIGHT0:
        case GL_LIGHT1:
        case GL_LIGHT2:
        case GL_LIGHT3:
        case GL_LIGHT4:
        case GL_LIGHT5:
        case GL_LIGHT6:
        case GL_LIGHT7:
        case GL_NORMALIZE:
        case GL_RESCALE_NORMAL:
        case GL_COLOR_MATERIAL:
        case GL_CLIP_PLANE0:
        case GL_CLIP_PLANE1:
        case GL_CLIP_PLANE2:
        case GL_CLIP_PLANE3:
        case GL_CLIP_PLANE4:
        case GL_CLIP_PLANE5:
        case GL_FOG:
        case GL_POINT_SMOOTH:
        case GL_LINE_SMOOTH:
            return context->getClientVersion() < Version(2, 0);
        case GL_POINT_SIZE_ARRAY_OES:
            return context->getClientVersion() < Version(2, 0) &&
                   context->getExtensions().pointSizeArrayOES;
        case GL_TEXTURE_CUBE_MAP:
            return context->getClientVersion() < Version(2, 0) &&
                   context->getExtensions().textureCubeMapOES;
        case GL_POINT_SPRITE_OES:
            return context->getClientVersion() < Version(2, 0) &&
                   context->getExtensions().pointSpriteOES;
        default:
            return false;
    }
}

// Return true if a character belongs to the ASCII subset as defined in GLSL ES 1.0 spec section
// 3.1.
bool IsValidESSLCharacter(unsigned char c)
{
    // Printing characters are valid except " $ ` @ \ ' DEL.
    if (c >= 32 && c <= 126 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' &&
        c != '\'')
    {
        return true;
    }

    // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid.
    if (c >= 9 && c <= 13)
    {
        return true;
    }

    return false;
}

bool IsValidESSLString(const char *str, size_t len)
{
    for (size_t i = 0; i < len; i++)
    {
        if (!IsValidESSLCharacter(str[i]))
        {
            return false;
        }
    }

    return true;
}

bool ValidateWebGLNamePrefix(const Context *context,
                             angle::EntryPoint entryPoint,
                             const GLchar *name)
{
    ASSERT(context->isWebGL());

    // WebGL 1.0 [Section 6.16] GLSL Constructs
    // Identifiers starting with "webgl_" and "_webgl_" are reserved for use by WebGL.
    if (strncmp(name, "webgl_", 6) == 0 || strncmp(name, "_webgl_", 7) == 0)
    {
        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                 kWebglBindAttribLocationReservedPrefix);
        return false;
    }

    return true;
}

bool ValidateWebGLNameLength(const Context *context, angle::EntryPoint entryPoint, size_t length)
{
    ASSERT(context->isWebGL());

    if (context->isWebGL1() && length > 256)
    {
        // WebGL 1.0 [Section 6.21] Maxmimum Uniform and Attribute Location Lengths
        // WebGL imposes a limit of 256 characters on the lengths of uniform and attribute
        // locations.
        context->validationError(entryPoint, GL_INVALID_VALUE, kWebglNameLengthLimitExceeded);

        return false;
    }
    else if (length > 1024)
    {
        // WebGL 2.0 [Section 4.3.2] WebGL 2.0 imposes a limit of 1024 characters on the lengths of
        // uniform and attribute locations.
        context->validationError(entryPoint, GL_INVALID_VALUE, kWebgl2NameLengthLimitExceeded);
        return false;
    }

    return true;
}

bool ValidBlendFunc(const Context *context, GLenum val)
{
    const Extensions &ext = context->getExtensions();

    // these are always valid for src and dst.
    switch (val)
    {
        case GL_ZERO:
        case GL_ONE:
        case GL_SRC_COLOR:
        case GL_ONE_MINUS_SRC_COLOR:
        case GL_DST_COLOR:
        case GL_ONE_MINUS_DST_COLOR:
        case GL_SRC_ALPHA:
        case GL_ONE_MINUS_SRC_ALPHA:
        case GL_DST_ALPHA:
        case GL_ONE_MINUS_DST_ALPHA:
        case GL_CONSTANT_COLOR:
        case GL_ONE_MINUS_CONSTANT_COLOR:
        case GL_CONSTANT_ALPHA:
        case GL_ONE_MINUS_CONSTANT_ALPHA:
            return true;

        // EXT_blend_func_extended.
        case GL_SRC1_COLOR_EXT:
        case GL_SRC1_ALPHA_EXT:
        case GL_ONE_MINUS_SRC1_COLOR_EXT:
        case GL_ONE_MINUS_SRC1_ALPHA_EXT:
        case GL_SRC_ALPHA_SATURATE_EXT:
            return ext.blendFuncExtendedEXT;

        default:
            return false;
    }
}

bool ValidSrcBlendFunc(const Context *context, GLenum val)
{
    if (ValidBlendFunc(context, val))
        return true;

    if (val == GL_SRC_ALPHA_SATURATE)
        return true;

    return false;
}

bool ValidDstBlendFunc(const Context *context, GLenum val)
{
    if (ValidBlendFunc(context, val))
        return true;

    if (val == GL_SRC_ALPHA_SATURATE)
    {
        if (context->getClientMajorVersion() >= 3)
            return true;
    }

    return false;
}

bool ValidateES2TexImageParameters(const Context *context,
                                   angle::EntryPoint entryPoint,
                                   TextureTarget target,
                                   GLint level,
                                   GLenum internalformat,
                                   bool isCompressed,
                                   bool isSubImage,
                                   GLint xoffset,
                                   GLint yoffset,
                                   GLsizei width,
                                   GLsizei height,
                                   GLint border,
                                   GLenum format,
                                   GLenum type,
                                   GLsizei imageSize,
                                   const void *pixels)
{
    if (!ValidTexture2DDestinationTarget(context, target))
    {
        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
        return false;
    }

    return ValidateES2TexImageParametersBase(context, entryPoint, target, level, internalformat,
                                             isCompressed, isSubImage, xoffset, yoffset, width,
                                             height, border, format, type, imageSize, pixels);
}

}  // anonymous namespace

bool ValidateES2TexImageParametersBase(const Context *context,
                                       angle::EntryPoint entryPoint,
                                       TextureTarget target,
                                       GLint level,
                                       GLenum internalformat,
                                       bool isCompressed,
                                       bool isSubImage,
                                       GLint xoffset,
                                       GLint yoffset,
                                       GLsizei width,
                                       GLsizei height,
                                       GLint border,
                                       GLenum format,
                                       GLenum type,
                                       GLsizei imageSize,
                                       const void *pixels)
{

    TextureType texType = TextureTargetToType(target);
    if (!ValidImageSizeParameters(context, entryPoint, texType, level, width, height, 1,
                                  isSubImage))
    {
        // Error already handled.
        return false;
    }

    if (!ValidMipLevel(context, texType, level))
    {
        context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
        return false;
    }

    if ((xoffset < 0 || std::numeric_limits<GLsizei>::max() - xoffset < width) ||
        (yoffset < 0 || std::numeric_limits<GLsizei>::max() - yoffset < height))
    {
        context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
        return false;
    }

    const Caps &caps = context->getCaps();

    switch (texType)
    {
        case TextureType::_2D:
        case TextureType::External:
        case TextureType::VideoImage:
            if (width > (caps.max2DTextureSize >> level) ||
                height > (caps.max2DTextureSize >> level))
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
                return false;
            }
            break;

        case TextureType::Rectangle:
            ASSERT(level == 0);
            if (width > caps.maxRectangleTextureSize || height > caps.maxRectangleTextureSize)
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
                return false;
            }
            if (isCompressed)
            {
                context->validationError(entryPoint, GL_INVALID_ENUM, kRectangleTextureCompressed);
                return false;
            }
            break;

        case TextureType::CubeMap:
            if (!isSubImage && width != height)
            {
                context->validationError(entryPoint, GL_INVALID_VALUE,
                                         kCubemapFacesEqualDimensions);
                return false;
            }

            if (width > (caps.maxCubeMapTextureSize >> level) ||
                height > (caps.maxCubeMapTextureSize >> level))
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
                return false;
            }
            break;

        default:
            context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
            return false;
    }

    Texture *texture = context->getTextureByType(texType);
    if (!texture)
    {
        context->validationError(entryPoint, GL_INVALID_OPERATION, kBufferNotBound);
        return false;
    }

    // Verify zero border
    if (border != 0)
    {
        context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidBorder);
        return false;
    }

    bool nonEqualFormatsAllowed = false;

    if (isCompressed)
    {
        GLenum actualInternalFormat =
            isSubImage ? texture->getFormat(target, level).info->sizedInternalFormat
                       : internalformat;

        const InternalFormat &internalFormatInfo = GetSizedInternalFormatInfo(actualInternalFormat);

        if (!internalFormatInfo.compressed && !internalFormatInfo.paletted)
        {
            context->validationErrorF(entryPoint, GL_INVALID_ENUM, kInvalidInternalFormat,
                                      internalformat);
            return false;
        }

        if (!internalFormatInfo.textureSupport(context->getClientVersion(),
                                               context->getExtensions()))
        {
            context->validationErrorF(entryPoint, GL_INVALID_ENUM, kInvalidInternalFormat,
                                      internalformat);
            return false;
        }

        if (isSubImage)
        {
            // From OpenGL ES Version 1.1.12, section 3.7.4 Compressed Paletted
            // Textures:
            //
            // Subimages may not be specified for compressed paletted textures.
            // Calling CompressedTexSubImage2D with any of the PALETTE*
            // arguments in table 3.11 will generate an INVALID OPERATION error.
            if (internalFormatInfo.paletted)
            {
                context->validationErrorF(entryPoint, GL_INVALID_OPERATION, kInvalidInternalFormat,
                                          internalformat);
                return false;
            }

            // From the OES_compressed_ETC1_RGB8_texture spec:
            //
            // INVALID_OPERATION is generated by CompressedTexSubImage2D, TexSubImage2D, or
            // CopyTexSubImage2D if the texture image <level> bound to <target> has internal format
            // ETC1_RGB8_OES.
            //
            // This is relaxed if GL_EXT_compressed_ETC1_RGB8_sub_texture is supported.
            if (IsETC1Format(actualInternalFormat) &&
                !context->getExtensions().compressedETC1RGB8SubTextureEXT)
            {
                context->validationErrorF(entryPoint, GL_INVALID_OPERATION, kInvalidInternalFormat,
                                          internalformat);
                return false;
            }

            if (!ValidCompressedSubImageSize(context, actualInternalFormat, xoffset, yoffset, 0,
                                             width, height, 1, texture->getWidth(target, level),
                                             texture->getHeight(target, level),
                                             texture->getDepth(target, level)))
            {
                context->validationError(entryPoint, GL_INVALID_OPERATION,
                                         kInvalidCompressedImageSize);
                return false;
            }

            if (format != actualInternalFormat)
            {
                context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                return false;
            }
        }
        else
        {
            if (!ValidCompressedImageSize(context, actualInternalFormat, level, width, height, 1))
            {
                context->validationError(entryPoint, GL_INVALID_OPERATION,
                                         kInvalidCompressedImageSize);
                return false;
            }
        }
    }
    else
    {
        // validate <type> by itself (used as secondary key below)
        switch (type)
        {
            case GL_UNSIGNED_BYTE:
            case GL_UNSIGNED_SHORT_5_6_5:
            case GL_UNSIGNED_SHORT_4_4_4_4:
            case GL_UNSIGNED_SHORT_5_5_5_1:
            case GL_UNSIGNED_SHORT:
            case GL_UNSIGNED_INT:
            case GL_UNSIGNED_INT_24_8_OES:
            case GL_HALF_FLOAT_OES:
            case GL_FLOAT:
                break;
            case GL_UNSIGNED_INT_2_10_10_10_REV_EXT:
                if (!context->getExtensions().textureType2101010REVEXT)
                {
                    context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported, type);
                    return false;
                }
                break;
            default:
                context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidType);
                return false;
        }

        // validate <format> + <type> combinations
        // - invalid <format> -> sets INVALID_ENUM
        // - invalid <format>+<type> combination -> sets INVALID_OPERATION
        switch (format)
        {
            case GL_ALPHA:
            case GL_LUMINANCE:
            case GL_LUMINANCE_ALPHA:
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                    case GL_FLOAT:
                    case GL_HALF_FLOAT_OES:
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_RED:
            case GL_RG:
                if (!context->getExtensions().textureRgEXT)
                {
                    context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                              format);
                    return false;
                }
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                        break;
                    case GL_FLOAT:
                        if (!context->getExtensions().textureFloatOES)
                        {
                            context->validationErrorF(entryPoint, GL_INVALID_ENUM,
                                                      kEnumNotSupported, type);
                            return false;
                        }
                        break;
                    case GL_HALF_FLOAT_OES:
                        if (!context->getExtensions().textureFloatOES &&
                            !context->getExtensions().textureHalfFloatOES)
                        {
                            context->validationErrorF(entryPoint, GL_INVALID_ENUM,
                                                      kEnumNotSupported, type);
                            return false;
                        }
                        break;
                    case GL_SHORT:
                    case GL_UNSIGNED_SHORT:
                        if (!context->getExtensions().textureNorm16EXT)
                        {
                            context->validationErrorF(entryPoint, GL_INVALID_ENUM,
                                                      kEnumNotSupported, type);
                            return false;
                        }
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_RGB:
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                    case GL_UNSIGNED_SHORT_5_6_5:
                    case GL_UNSIGNED_INT_2_10_10_10_REV_EXT:
                    case GL_FLOAT:
                    case GL_HALF_FLOAT_OES:
                        break;
                    case GL_SHORT:
                    case GL_UNSIGNED_SHORT:
                        if (!context->getExtensions().textureNorm16EXT)
                        {
                            context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                     kMismatchedTypeAndFormat);
                            return false;
                        }
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_RGBA:
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                    case GL_UNSIGNED_SHORT_4_4_4_4:
                    case GL_UNSIGNED_SHORT_5_5_5_1:
                    case GL_FLOAT:
                    case GL_HALF_FLOAT_OES:
                    case GL_UNSIGNED_INT_2_10_10_10_REV_EXT:
                        break;
                    case GL_SHORT:
                    case GL_UNSIGNED_SHORT:
                        if (!context->getExtensions().textureNorm16EXT)
                        {
                            context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                     kMismatchedTypeAndFormat);
                            return false;
                        }
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_BGRA_EXT:
                if (!context->getExtensions().textureFormatBGRA8888EXT)
                {
                    context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                              format);
                    return false;
                }
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_SRGB_EXT:
            case GL_SRGB_ALPHA_EXT:
                if (!context->getExtensions().sRGBEXT)
                {
                    context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                              format);
                    return false;
                }
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_DEPTH_COMPONENT:
                switch (type)
                {
                    case GL_UNSIGNED_SHORT:
                    case GL_UNSIGNED_INT:
                        break;
                    case GL_FLOAT:
                        if (!context->getExtensions().depthBufferFloat2NV)
                        {
                            context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                     kMismatchedTypeAndFormat);
                            return false;
                        }
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_DEPTH_STENCIL_OES:
                switch (type)
                {
                    case GL_UNSIGNED_INT_24_8_OES:
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            case GL_STENCIL_INDEX:
                switch (type)
                {
                    case GL_UNSIGNED_BYTE:
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                }
                break;
            default:
                context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported, format);
                return false;
        }

        switch (format)
        {
            case GL_DEPTH_COMPONENT:
            case GL_DEPTH_STENCIL_OES:
                if (!context->getExtensions().depthTextureANGLE &&
                    !((context->getExtensions().packedDepthStencilOES ||
                       context->getExtensions().depthTextureCubeMapOES) &&
                      context->getExtensions().depthTextureOES))
                {
                    context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                              format);
                    return false;
                }

                switch (target)
                {
                    case TextureTarget::_2D:
                        break;
                    case TextureTarget::CubeMapNegativeX:
                    case TextureTarget::CubeMapNegativeY:
                    case TextureTarget::CubeMapNegativeZ:
                    case TextureTarget::CubeMapPositiveX:
                    case TextureTarget::CubeMapPositiveY:
                    case TextureTarget::CubeMapPositiveZ:
                        if (!context->getExtensions().depthTextureCubeMapOES)
                        {
                            context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                     kMismatchedTargetAndFormat);
                            return false;
                        }
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTargetAndFormat);
                        return false;
                }

                // OES_depth_texture supports loading depth data and multiple levels,
                // but ANGLE_depth_texture does not
                if (!context->getExtensions().depthTextureOES)
                {
                    if (pixels != nullptr)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kPixelDataNotNull);
                        return false;
                    }
                    if (level != 0)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION, kLevelNotZero);
                        return false;
                    }
                }
                break;
            case GL_STENCIL_INDEX:
                if (!context->getExtensions().textureStencil8OES)
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormat);
                    return false;
                }

                switch (target)
                {
                    case TextureTarget::_2D:
                    case TextureTarget::_2DArray:
                    case TextureTarget::CubeMapNegativeX:
                    case TextureTarget::CubeMapNegativeY:
                    case TextureTarget::CubeMapNegativeZ:
                    case TextureTarget::CubeMapPositiveX:
                    case TextureTarget::CubeMapPositiveY:
                    case TextureTarget::CubeMapPositiveZ:
                        break;
                    default:
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTargetAndFormat);
                        return false;
                }

                if (internalformat != GL_STENCIL_INDEX8)
                {
                    context->validationError(entryPoint, GL_INVALID_OPERATION,
                                             kMismatchedTargetAndFormat);
                    return false;
                }
                break;
            default:
                break;
        }

        if (!isSubImage)
        {
            switch (internalformat)
            {
                // Core ES 2.0 formats
                case GL_ALPHA:
                case GL_LUMINANCE:
                case GL_LUMINANCE_ALPHA:
                case GL_RGB:
                case GL_RGBA:
                    break;

                case GL_RGBA32F:
                    if (!context->getExtensions().colorBufferFloatRgbaCHROMIUM)
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }

                    nonEqualFormatsAllowed = true;

                    if (type != GL_FLOAT)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                    }
                    if (format != GL_RGBA)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                    }
                    break;

                case GL_RGB32F:
                    if (!context->getExtensions().colorBufferFloatRgbCHROMIUM)
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }

                    nonEqualFormatsAllowed = true;

                    if (type != GL_FLOAT)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                    }
                    if (format != GL_RGB)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                    }
                    break;

                case GL_BGRA_EXT:
                    if (!context->getExtensions().textureFormatBGRA8888EXT)
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }
                    break;

                case GL_DEPTH_COMPONENT:
                    if (!(context->getExtensions().depthTextureAny()))
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }
                    break;

                case GL_DEPTH_STENCIL:
                    if (!(context->getExtensions().depthTextureANGLE ||
                          context->getExtensions().packedDepthStencilOES ||
                          context->getExtensions().depthTextureCubeMapOES))
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }
                    break;

                case GL_STENCIL_INDEX8:
                    if (!context->getExtensions().textureStencil8OES)
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }
                    break;

                case GL_RED:
                case GL_RG:
                    if (!context->getExtensions().textureRgEXT)
                    {
                        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
                        return false;
                    }
                    break;

                case GL_SRGB_EXT:
                case GL_SRGB_ALPHA_EXT:
                    if (!context->getExtensions().sRGBEXT)
                    {
                        context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                                  internalformat);
                        return false;
                    }
                    break;

                case GL_RGB10_A2_EXT:
                    if (!context->getExtensions().textureType2101010REVEXT)
                    {
                        context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                                  internalformat);
                        return false;
                    }

                    if (type != GL_UNSIGNED_INT_2_10_10_10_REV_EXT || format != GL_RGBA)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kMismatchedTypeAndFormat);
                        return false;
                    }

                    nonEqualFormatsAllowed = true;

                    break;

                case GL_RGB5_A1:
                    if (context->getExtensions().textureType2101010REVEXT &&
                        type == GL_UNSIGNED_INT_2_10_10_10_REV_EXT && format == GL_RGBA)
                    {
                        nonEqualFormatsAllowed = true;
                    }

                    break;

                case GL_RGBX8_ANGLE:
                    if (context->getExtensions().rgbxInternalFormatANGLE &&
                        type == GL_UNSIGNED_BYTE && format == GL_RGB)
                    {
                        nonEqualFormatsAllowed = true;
                    }

                    break;

                case GL_R16_EXT:
                case GL_RG16_EXT:
                case GL_RGB16_EXT:
                case GL_RGBA16_EXT:
                case GL_R16_SNORM_EXT:
                case GL_RG16_SNORM_EXT:
                case GL_RGB16_SNORM_EXT:
                case GL_RGBA16_SNORM_EXT:
                    if (!context->getExtensions().textureNorm16EXT)
                    {
                        context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                                  internalformat);
                        return false;
                    }
                    break;
                default:
                    // Compressed formats are not valid internal formats for glTexImage*D
                    context->validationErrorF(entryPoint, GL_INVALID_VALUE, kInvalidInternalFormat,
                                              internalformat);
                    return false;
            }
        }

        if (type == GL_FLOAT)
        {
            if (!context->getExtensions().textureFloatOES)
            {
                context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported, type);
                return false;
            }
        }
        else if (type == GL_HALF_FLOAT_OES)
        {
            if (!context->getExtensions().textureHalfFloatOES)
            {
                context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported, type);
                return false;
            }
        }
    }

    if (isSubImage)
    {
        const InternalFormat &textureInternalFormat = *texture->getFormat(target, level).info;
        if (textureInternalFormat.internalFormat == GL_NONE)
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidTextureLevel);
            return false;
        }

        if (format != textureInternalFormat.format)
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION, err::kTextureFormatMismatch);
            return false;
        }

        if (context->isWebGL())
        {
            if (GetInternalFormatInfo(format, type).sizedInternalFormat !=
                textureInternalFormat.sizedInternalFormat)
            {
                context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureTypeMismatch);
                return false;
            }
        }

        if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
            static_cast<size_t>(yoffset + height) > texture->getHeight(target, level))
        {
            context->validationError(entryPoint, GL_INVALID_VALUE, kOffsetOverflow);
            return false;
        }

        if (width > 0 && height > 0 && pixels == nullptr &&
            context->getState().getTargetBuffer(BufferBinding::PixelUnpack) == nullptr)
        {
            context->validationError(entryPoint, GL_INVALID_VALUE, kPixelDataNull);
            return false;
        }
    }
    else
    {
        if (texture->getImmutableFormat())
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION, kTextureIsImmutable);
            return false;
        }
    }

    // From GL_CHROMIUM_color_buffer_float_rgb[a]:
    // GL_RGB[A] / GL_RGB[A]32F becomes an allowable format / internalformat parameter pair for
    // TexImage2D. The restriction in section 3.7.1 of the OpenGL ES 2.0 spec that the
    // internalformat parameter and format parameter of TexImage2D must match is lifted for this
    // case.
    if (!isSubImage && !isCompressed && internalformat != format && !nonEqualFormatsAllowed)
    {
        context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidFormatCombination);
        return false;
    }

    GLenum sizeCheckFormat = isSubImage ? format : internalformat;
    return ValidImageDataSize(context, entryPoint, texType, width, height, 1, sizeCheckFormat, type,
                              pixels, imageSize);
}

bool ValidateES2TexStorageParametersBase(const Context *context,
                                         angle::EntryPoint entryPoint,
                                         TextureType target,
                                         GLsizei levels,
                                         GLenum internalformat,
                                         GLsizei width,
                                         GLsizei height)
{
    if (target != TextureType::_2D && target != TextureType::CubeMap &&
        target != TextureType::Rectangle)
    {
        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidTextureTarget);
        return false;
    }

    if (width < 1 || height < 1 || levels < 1)
    {
        context->validationError(entryPoint, GL_INVALID_VALUE, kTextureSizeTooSmall);
        return false;
    }

    if (target == TextureType::CubeMap && width != height)
    {
        context->validationError(entryPoint, GL_INVALID_VALUE, kCubemapFacesEqualDimensions);
        return false;
    }

    if (levels != 1 && levels != log2(std::max(width, height)) + 1)
    {
        context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidMipLevels);
        return false;
    }

    const InternalFormat &formatInfo = GetSizedInternalFormatInfo(internalformat);
    if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE)
    {
        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
        return false;
    }

    const Caps &caps = context->getCaps();

    switch (target)
    {
        case TextureType::_2D:
            if (width > caps.max2DTextureSize || height > caps.max2DTextureSize)
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
                return false;
            }
            break;
        case TextureType::Rectangle:
            if (levels != 1)
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kInvalidMipLevel);
                return false;
            }

            if (width > caps.maxRectangleTextureSize || height > caps.maxRectangleTextureSize)
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
                return false;
            }
            if (formatInfo.compressed)
            {
                context->validationError(entryPoint, GL_INVALID_ENUM, kRectangleTextureCompressed);
                return false;
            }
            break;
        case TextureType::CubeMap:
            if (width > caps.maxCubeMapTextureSize || height > caps.maxCubeMapTextureSize)
            {
                context->validationError(entryPoint, GL_INVALID_VALUE, kResourceMaxTextureSize);
                return false;
            }
            break;
        case TextureType::InvalidEnum:
            context->validationError(entryPoint, GL_INVALID_ENUM, kEnumInvalid);
            return false;
        default:
            context->validationErrorF(entryPoint, GL_INVALID_ENUM, kEnumNotSupported,
                                      ToGLenum(target));
            return false;
    }

    if (levels != 1 && !context->getExtensions().textureNpotOES)
    {
        if (!isPow2(width) || !isPow2(height))
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION, kDimensionsMustBePow2);
            return false;
        }
    }

    if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
    {
        context->validationError(entryPoint, GL_INVALID_ENUM, kInvalidFormat);
        return false;
    }

    // Even with OES_texture_npot, some compressed formats may impose extra restrictions.
    if (formatInfo.compressed)
    {
        if (!ValidCompressedImageSize(context, formatInfo.internalFormat, 0, width, height, 1))
        {
            context->validationError(entryPoint, GL_INVALID_OPERATION, kInvalidCompressedImageSize);
            return false;
        }
    }

    switch (internalformat)
    {
        case GL_DEPTH_COMPONENT16:
        case GL_DEPTH_COMPONENT32_OES:
            switch (target)
            {
                case TextureType::_2D:
                    break;
                case TextureType::CubeMap:
                    if (!context->getExtensions().depthTextureCubeMapOES)
                    {
                        context->validationError(entryPoint, GL_INVALID_OPERATION,
                                                 kInvalidTextureTarget);
                        return false;
                    }
                    break;
                default:
--> --------------------

--> maximum size reached

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

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

¤ Dauer der Verarbeitung: 0.23 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.