Home | History | Annotate | Download | only in libGLESv2
      1 #include "precompiled.h"
      2 //
      3 // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style license that can be
      5 // found in the LICENSE file.
      6 //
      7 
      8 // validationES.h: Validation functions for generic OpenGL ES entry point parameters
      9 
     10 #include "libGLESv2/validationES.h"
     11 #include "libGLESv2/validationES2.h"
     12 #include "libGLESv2/validationES3.h"
     13 #include "libGLESv2/Context.h"
     14 #include "libGLESv2/Texture.h"
     15 #include "libGLESv2/Framebuffer.h"
     16 #include "libGLESv2/Renderbuffer.h"
     17 #include "libGLESv2/formatutils.h"
     18 #include "libGLESv2/main.h"
     19 #include "libGLESv2/Query.h"
     20 #include "libGLESv2/ProgramBinary.h"
     21 
     22 #include "common/mathutil.h"
     23 #include "common/utilities.h"
     24 
     25 namespace gl
     26 {
     27 
     28 bool ValidCap(const Context *context, GLenum cap)
     29 {
     30     switch (cap)
     31     {
     32       case GL_CULL_FACE:
     33       case GL_POLYGON_OFFSET_FILL:
     34       case GL_SAMPLE_ALPHA_TO_COVERAGE:
     35       case GL_SAMPLE_COVERAGE:
     36       case GL_SCISSOR_TEST:
     37       case GL_STENCIL_TEST:
     38       case GL_DEPTH_TEST:
     39       case GL_BLEND:
     40       case GL_DITHER:
     41         return true;
     42       case GL_PRIMITIVE_RESTART_FIXED_INDEX:
     43       case GL_RASTERIZER_DISCARD:
     44         return (context->getClientVersion() >= 3);
     45       default:
     46         return false;
     47     }
     48 }
     49 
     50 bool ValidTextureTarget(const Context *context, GLenum target)
     51 {
     52     switch (target)
     53     {
     54       case GL_TEXTURE_2D:
     55       case GL_TEXTURE_CUBE_MAP:
     56         return true;
     57 
     58       case GL_TEXTURE_3D:
     59       case GL_TEXTURE_2D_ARRAY:
     60         return (context->getClientVersion() >= 3);
     61 
     62       default:
     63         return false;
     64     }
     65 }
     66 
     67 // This function differs from ValidTextureTarget in that the target must be
     68 // usable as the destination of a 2D operation-- so a cube face is valid, but
     69 // GL_TEXTURE_CUBE_MAP is not.
     70 // Note: duplicate of IsInternalTextureTarget
     71 bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
     72 {
     73     switch (target)
     74     {
     75       case GL_TEXTURE_2D:
     76       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     77       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     78       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     79       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     80       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     81       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
     82         return true;
     83       case GL_TEXTURE_2D_ARRAY:
     84       case GL_TEXTURE_3D:
     85         return (context->getClientVersion() >= 3);
     86       default:
     87         return false;
     88     }
     89 }
     90 
     91 bool ValidFramebufferTarget(GLenum target)
     92 {
     93     META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
     94 
     95     switch (target)
     96     {
     97       case GL_FRAMEBUFFER:      return true;
     98       case GL_READ_FRAMEBUFFER: return true;
     99       case GL_DRAW_FRAMEBUFFER: return true;
    100       default:                  return false;
    101     }
    102 }
    103 
    104 bool ValidBufferTarget(const Context *context, GLenum target)
    105 {
    106     switch (target)
    107     {
    108       case GL_ARRAY_BUFFER:
    109       case GL_ELEMENT_ARRAY_BUFFER:
    110         return true;
    111 
    112       case GL_PIXEL_PACK_BUFFER:
    113       case GL_PIXEL_UNPACK_BUFFER:
    114         return context->supportsPBOs();
    115 
    116       case GL_COPY_READ_BUFFER:
    117       case GL_COPY_WRITE_BUFFER:
    118       case GL_TRANSFORM_FEEDBACK_BUFFER:
    119       case GL_UNIFORM_BUFFER:
    120         return (context->getClientVersion() >= 3);
    121 
    122       default:
    123         return false;
    124     }
    125 }
    126 
    127 bool ValidBufferParameter(const Context *context, GLenum pname)
    128 {
    129     switch (pname)
    130     {
    131       case GL_BUFFER_USAGE:
    132       case GL_BUFFER_SIZE:
    133         return true;
    134 
    135       // GL_BUFFER_MAP_POINTER is a special case, and may only be
    136       // queried with GetBufferPointerv
    137       case GL_BUFFER_ACCESS_FLAGS:
    138       case GL_BUFFER_MAPPED:
    139       case GL_BUFFER_MAP_OFFSET:
    140       case GL_BUFFER_MAP_LENGTH:
    141         return (context->getClientVersion() >= 3);
    142 
    143       default:
    144         return false;
    145     }
    146 }
    147 
    148 bool ValidMipLevel(const Context *context, GLenum target, GLint level)
    149 {
    150     int maxLevel = 0;
    151     switch (target)
    152     {
    153       case GL_TEXTURE_2D:                  maxLevel = context->getMaximum2DTextureLevel();      break;
    154       case GL_TEXTURE_CUBE_MAP:
    155       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
    156       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
    157       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
    158       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
    159       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
    160       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxLevel = context->getMaximumCubeTextureLevel();    break;
    161       case GL_TEXTURE_3D:                  maxLevel = context->getMaximum3DTextureLevel();      break;
    162       case GL_TEXTURE_2D_ARRAY:            maxLevel = context->getMaximum2DArrayTextureLevel(); break;
    163       default: UNREACHABLE();
    164     }
    165 
    166     return level < maxLevel;
    167 }
    168 
    169 bool ValidImageSize(const gl::Context *context, GLenum target, GLint level,
    170                     GLsizei width, GLsizei height, GLsizei depth)
    171 {
    172     if (level < 0 || width < 0 || height < 0 || depth < 0)
    173     {
    174         return false;
    175     }
    176 
    177     if (!context->supportsNonPower2Texture() &&
    178         (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
    179     {
    180         return false;
    181     }
    182 
    183     if (!ValidMipLevel(context, target, level))
    184     {
    185         return false;
    186     }
    187 
    188     return true;
    189 }
    190 
    191 bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
    192 {
    193     GLuint clientVersion = context->getClientVersion();
    194     if (!IsFormatCompressed(internalFormat, clientVersion))
    195     {
    196         return false;
    197     }
    198 
    199     GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion);
    200     GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion);
    201     if (width  < 0 || (width  > blockWidth  && width  % blockWidth  != 0) ||
    202         height < 0 || (height > blockHeight && height % blockHeight != 0))
    203     {
    204         return false;
    205     }
    206 
    207     return true;
    208 }
    209 
    210 bool ValidQueryType(const Context *context, GLenum queryType)
    211 {
    212     META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
    213     META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
    214 
    215     switch (queryType)
    216     {
    217       case GL_ANY_SAMPLES_PASSED:
    218       case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
    219         return true;
    220       case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
    221         return (context->getClientVersion() >= 3);
    222       default:
    223         return false;
    224     }
    225 }
    226 
    227 bool ValidProgram(const Context *context, GLuint id)
    228 {
    229     // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
    230     // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
    231     // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
    232 
    233     if (context->getProgram(id) != NULL)
    234     {
    235         return true;
    236     }
    237     else if (context->getShader(id) != NULL)
    238     {
    239         // ID is the wrong type
    240         return gl::error(GL_INVALID_OPERATION, false);
    241     }
    242     else
    243     {
    244         // No shader/program object has this ID
    245         return gl::error(GL_INVALID_VALUE, false);
    246     }
    247 }
    248 
    249 bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
    250                                            GLenum internalformat, GLsizei width, GLsizei height,
    251                                            bool angleExtension)
    252 {
    253     switch (target)
    254     {
    255       case GL_RENDERBUFFER:
    256         break;
    257       default:
    258         return gl::error(GL_INVALID_ENUM, false);
    259     }
    260 
    261     if (width < 0 || height < 0 || samples < 0)
    262     {
    263         return gl::error(GL_INVALID_VALUE, false);
    264     }
    265 
    266     if (!gl::IsValidInternalFormat(internalformat, context))
    267     {
    268         return gl::error(GL_INVALID_ENUM, false);
    269     }
    270 
    271     // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
    272     // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
    273     // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
    274     // internal format must be sized and not an integer format if samples is greater than zero.
    275     if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
    276     {
    277         return gl::error(GL_INVALID_ENUM, false);
    278     }
    279 
    280     GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
    281     if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
    282     {
    283         return gl::error(GL_INVALID_OPERATION, false);
    284     }
    285 
    286     if (!gl::IsColorRenderingSupported(internalformat, context) &&
    287         !gl::IsDepthRenderingSupported(internalformat, context) &&
    288         !gl::IsStencilRenderingSupported(internalformat, context))
    289     {
    290         return gl::error(GL_INVALID_ENUM, false);
    291     }
    292 
    293     if (std::max(width, height) > context->getMaximumRenderbufferDimension())
    294     {
    295         return gl::error(GL_INVALID_VALUE, false);
    296     }
    297 
    298     // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
    299     // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
    300     // states that samples must be less than or equal to the maximum samples for the specified
    301     // internal format.
    302     if (angleExtension)
    303     {
    304         if (samples > context->getMaxSupportedSamples())
    305         {
    306             return gl::error(GL_INVALID_VALUE, false);
    307         }
    308     }
    309     else
    310     {
    311         if (samples > context->getMaxSupportedFormatSamples(internalformat))
    312         {
    313             return gl::error(GL_INVALID_VALUE, false);
    314         }
    315     }
    316 
    317     GLuint handle = context->getRenderbufferHandle();
    318     if (handle == 0)
    319     {
    320         return gl::error(GL_INVALID_OPERATION, false);
    321     }
    322 
    323     return true;
    324 }
    325 
    326 bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
    327                                                GLenum renderbuffertarget, GLuint renderbuffer)
    328 {
    329     gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
    330     GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
    331 
    332     if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
    333     {
    334         return gl::error(GL_INVALID_OPERATION, false);
    335     }
    336 
    337     if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
    338     {
    339         const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
    340 
    341         if (colorAttachment >= context->getMaximumRenderTargets())
    342         {
    343             return gl::error(GL_INVALID_VALUE, false);
    344         }
    345     }
    346     else
    347     {
    348         switch (attachment)
    349         {
    350           case GL_DEPTH_ATTACHMENT:
    351             break;
    352           case GL_STENCIL_ATTACHMENT:
    353             break;
    354           case GL_DEPTH_STENCIL_ATTACHMENT:
    355             if (context->getClientVersion() < 3)
    356             {
    357                 return gl::error(GL_INVALID_ENUM, false);
    358             }
    359             break;
    360           default:
    361             return gl::error(GL_INVALID_ENUM, false);
    362         }
    363     }
    364 
    365     // [OpenGL ES 2.0.25] Section 4.4.3 page 112
    366     // [OpenGL ES 3.0.2] Section 4.4.2 page 201
    367     // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
    368     // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
    369     if (renderbuffer != 0)
    370     {
    371         if (!context->getRenderbuffer(renderbuffer))
    372         {
    373             return gl::error(GL_INVALID_OPERATION, false);
    374         }
    375     }
    376 
    377     return true;
    378 }
    379 
    380 static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
    381                           GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    382                           GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
    383 {
    384     if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
    385         dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
    386         srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
    387     {
    388         return true;
    389     }
    390     else if (context->isScissorTestEnabled())
    391     {
    392         int scissorX, scissorY, scissorWidth, scissorHeight;
    393         context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
    394 
    395         return scissorX > 0 || scissorY > 0 ||
    396                scissorWidth < writeBuffer->getWidth() ||
    397                scissorHeight < writeBuffer->getHeight();
    398     }
    399     else
    400     {
    401         return false;
    402     }
    403 }
    404 
    405 bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    406                                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
    407                                        GLenum filter, bool fromAngleExtension)
    408 {
    409     switch (filter)
    410     {
    411       case GL_NEAREST:
    412         break;
    413       case GL_LINEAR:
    414         if (fromAngleExtension)
    415         {
    416             return gl::error(GL_INVALID_ENUM, false);
    417         }
    418         break;
    419       default:
    420         return gl::error(GL_INVALID_ENUM, false);
    421     }
    422 
    423     if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
    424     {
    425         return gl::error(GL_INVALID_VALUE, false);
    426     }
    427 
    428     if (mask == 0)
    429     {
    430         // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
    431         // buffers are copied.
    432         return false;
    433     }
    434 
    435     if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
    436     {
    437         ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
    438         return gl::error(GL_INVALID_OPERATION, false);
    439     }
    440 
    441     // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
    442     // color buffer, leaving only nearest being unfiltered from above
    443     if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
    444     {
    445         return gl::error(GL_INVALID_OPERATION, false);
    446     }
    447 
    448     if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
    449     {
    450         if (fromAngleExtension)
    451         {
    452             ERR("Blits with the same source and destination framebuffer are not supported by this "
    453                 "implementation.");
    454         }
    455         return gl::error(GL_INVALID_OPERATION, false);
    456     }
    457 
    458     gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
    459     gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
    460     if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
    461         !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
    462     {
    463         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
    464     }
    465 
    466     if (drawFramebuffer->getSamples() != 0)
    467     {
    468         return gl::error(GL_INVALID_OPERATION, false);
    469     }
    470 
    471     bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
    472 
    473     GLuint clientVersion = context->getClientVersion();
    474 
    475     if (mask & GL_COLOR_BUFFER_BIT)
    476     {
    477         gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
    478         gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
    479 
    480         if (readColorBuffer && drawColorBuffer)
    481         {
    482             GLenum readInternalFormat = readColorBuffer->getActualFormat();
    483             GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
    484 
    485             for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
    486             {
    487                 if (drawFramebuffer->isEnabledColorAttachment(i))
    488                 {
    489                     GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
    490                     GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
    491 
    492                     // The GL ES 3.0.2 spec (pg 193) states that:
    493                     // 1) If the read buffer is fixed point format, the draw buffer must be as well
    494                     // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
    495                     // 3) If the read buffer is a signed integer format, the draw buffer must be as well
    496                     if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
    497                         !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
    498                     {
    499                         return gl::error(GL_INVALID_OPERATION, false);
    500                     }
    501 
    502                     if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
    503                     {
    504                         return gl::error(GL_INVALID_OPERATION, false);
    505                     }
    506 
    507                     if (readComponentType == GL_INT && drawComponentType != GL_INT)
    508                     {
    509                         return gl::error(GL_INVALID_OPERATION, false);
    510                     }
    511 
    512                     if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
    513                     {
    514                         return gl::error(GL_INVALID_OPERATION, false);
    515                     }
    516                 }
    517             }
    518 
    519             if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
    520             {
    521                 return gl::error(GL_INVALID_OPERATION, false);
    522             }
    523 
    524             if (fromAngleExtension)
    525             {
    526                 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
    527                 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
    528                 {
    529                     return gl::error(GL_INVALID_OPERATION, false);
    530                 }
    531 
    532                 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
    533                 {
    534                     if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
    535                     {
    536                         if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
    537                             drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
    538                         {
    539                             return gl::error(GL_INVALID_OPERATION, false);
    540                         }
    541 
    542                         if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
    543                         {
    544                             return gl::error(GL_INVALID_OPERATION, false);
    545                         }
    546                     }
    547                 }
    548                 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
    549                                                                         srcX0, srcY0, srcX1, srcY1,
    550                                                                         dstX0, dstY0, dstX1, dstY1))
    551                 {
    552                     return gl::error(GL_INVALID_OPERATION, false);
    553                 }
    554             }
    555         }
    556     }
    557 
    558     if (mask & GL_DEPTH_BUFFER_BIT)
    559     {
    560         gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
    561         gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
    562 
    563         if (readDepthBuffer && drawDepthBuffer)
    564         {
    565             if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
    566             {
    567                 return gl::error(GL_INVALID_OPERATION, false);
    568             }
    569 
    570             if (readDepthBuffer->getSamples() > 0 && !sameBounds)
    571             {
    572                 return gl::error(GL_INVALID_OPERATION, false);
    573             }
    574 
    575             if (fromAngleExtension)
    576             {
    577                 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
    578                                   srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
    579                 {
    580                     ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
    581                     return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
    582                 }
    583 
    584                 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
    585                 {
    586                     return gl::error(GL_INVALID_OPERATION, false);
    587                 }
    588             }
    589         }
    590     }
    591 
    592     if (mask & GL_STENCIL_BUFFER_BIT)
    593     {
    594         gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
    595         gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
    596 
    597         if (readStencilBuffer && drawStencilBuffer)
    598         {
    599             if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
    600             {
    601                 return gl::error(GL_INVALID_OPERATION, false);
    602             }
    603 
    604             if (readStencilBuffer->getSamples() > 0 && !sameBounds)
    605             {
    606                 return gl::error(GL_INVALID_OPERATION, false);
    607             }
    608 
    609             if (fromAngleExtension)
    610             {
    611                 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
    612                                   srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
    613                 {
    614                     ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
    615                     return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
    616                 }
    617 
    618                 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
    619                 {
    620                     return gl::error(GL_INVALID_OPERATION, false);
    621                 }
    622             }
    623         }
    624     }
    625 
    626     return true;
    627 }
    628 
    629 bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
    630 {
    631     switch (pname)
    632     {
    633       case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
    634       case GL_VERTEX_ATTRIB_ARRAY_SIZE:
    635       case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
    636       case GL_VERTEX_ATTRIB_ARRAY_TYPE:
    637       case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
    638       case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
    639       case GL_CURRENT_VERTEX_ATTRIB:
    640         return true;
    641 
    642       case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
    643         // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
    644         // the same constant.
    645         META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
    646         return true;
    647 
    648       case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
    649         return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
    650 
    651       default:
    652         return gl::error(GL_INVALID_ENUM, false);
    653     }
    654 }
    655 
    656 bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
    657 {
    658     switch (pname)
    659     {
    660       case GL_TEXTURE_WRAP_R:
    661       case GL_TEXTURE_SWIZZLE_R:
    662       case GL_TEXTURE_SWIZZLE_G:
    663       case GL_TEXTURE_SWIZZLE_B:
    664       case GL_TEXTURE_SWIZZLE_A:
    665       case GL_TEXTURE_BASE_LEVEL:
    666       case GL_TEXTURE_MAX_LEVEL:
    667       case GL_TEXTURE_COMPARE_MODE:
    668       case GL_TEXTURE_COMPARE_FUNC:
    669       case GL_TEXTURE_MIN_LOD:
    670       case GL_TEXTURE_MAX_LOD:
    671         if (context->getClientVersion() < 3)
    672         {
    673             return gl::error(GL_INVALID_ENUM, false);
    674         }
    675         break;
    676 
    677       default: break;
    678     }
    679 
    680     switch (pname)
    681     {
    682       case GL_TEXTURE_WRAP_S:
    683       case GL_TEXTURE_WRAP_T:
    684       case GL_TEXTURE_WRAP_R:
    685         switch (param)
    686         {
    687           case GL_REPEAT:
    688           case GL_CLAMP_TO_EDGE:
    689           case GL_MIRRORED_REPEAT:
    690             return true;
    691           default:
    692             return gl::error(GL_INVALID_ENUM, false);
    693         }
    694 
    695       case GL_TEXTURE_MIN_FILTER:
    696         switch (param)
    697         {
    698           case GL_NEAREST:
    699           case GL_LINEAR:
    700           case GL_NEAREST_MIPMAP_NEAREST:
    701           case GL_LINEAR_MIPMAP_NEAREST:
    702           case GL_NEAREST_MIPMAP_LINEAR:
    703           case GL_LINEAR_MIPMAP_LINEAR:
    704             return true;
    705           default:
    706             return gl::error(GL_INVALID_ENUM, false);
    707         }
    708         break;
    709 
    710       case GL_TEXTURE_MAG_FILTER:
    711         switch (param)
    712         {
    713           case GL_NEAREST:
    714           case GL_LINEAR:
    715             return true;
    716           default:
    717             return gl::error(GL_INVALID_ENUM, false);
    718         }
    719         break;
    720 
    721       case GL_TEXTURE_USAGE_ANGLE:
    722         switch (param)
    723         {
    724           case GL_NONE:
    725           case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
    726             return true;
    727           default:
    728             return gl::error(GL_INVALID_ENUM, false);
    729         }
    730         break;
    731 
    732       case GL_TEXTURE_MAX_ANISOTROPY_EXT:
    733         if (!context->supportsTextureFilterAnisotropy())
    734         {
    735             return gl::error(GL_INVALID_ENUM, false);
    736         }
    737 
    738         // we assume the parameter passed to this validation method is truncated, not rounded
    739         if (param < 1)
    740         {
    741             return gl::error(GL_INVALID_VALUE, false);
    742         }
    743         return true;
    744 
    745       case GL_TEXTURE_MIN_LOD:
    746       case GL_TEXTURE_MAX_LOD:
    747         // any value is permissible
    748         return true;
    749 
    750       case GL_TEXTURE_COMPARE_MODE:
    751         // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
    752         switch (param)
    753         {
    754           case GL_NONE:
    755           case GL_COMPARE_REF_TO_TEXTURE:
    756             return true;
    757           default:
    758             return gl::error(GL_INVALID_ENUM, false);
    759         }
    760         break;
    761 
    762       case GL_TEXTURE_COMPARE_FUNC:
    763         // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
    764         switch (param)
    765         {
    766           case GL_LEQUAL:
    767           case GL_GEQUAL:
    768           case GL_LESS:
    769           case GL_GREATER:
    770           case GL_EQUAL:
    771           case GL_NOTEQUAL:
    772           case GL_ALWAYS:
    773           case GL_NEVER:
    774             return true;
    775           default:
    776             return gl::error(GL_INVALID_ENUM, false);
    777         }
    778         break;
    779 
    780       case GL_TEXTURE_SWIZZLE_R:
    781       case GL_TEXTURE_SWIZZLE_G:
    782       case GL_TEXTURE_SWIZZLE_B:
    783       case GL_TEXTURE_SWIZZLE_A:
    784         switch (param)
    785         {
    786           case GL_RED:
    787           case GL_GREEN:
    788           case GL_BLUE:
    789           case GL_ALPHA:
    790           case GL_ZERO:
    791           case GL_ONE:
    792             return true;
    793           default:
    794             return gl::error(GL_INVALID_ENUM, false);
    795         }
    796         break;
    797 
    798       case GL_TEXTURE_BASE_LEVEL:
    799       case GL_TEXTURE_MAX_LEVEL:
    800         if (param < 0)
    801         {
    802             return gl::error(GL_INVALID_VALUE, false);
    803         }
    804         return true;
    805 
    806       default:
    807         return gl::error(GL_INVALID_ENUM, false);
    808     }
    809 }
    810 
    811 bool ValidateSamplerObjectParameter(GLenum pname)
    812 {
    813     switch (pname)
    814     {
    815       case GL_TEXTURE_MIN_FILTER:
    816       case GL_TEXTURE_MAG_FILTER:
    817       case GL_TEXTURE_WRAP_S:
    818       case GL_TEXTURE_WRAP_T:
    819       case GL_TEXTURE_WRAP_R:
    820       case GL_TEXTURE_MIN_LOD:
    821       case GL_TEXTURE_MAX_LOD:
    822       case GL_TEXTURE_COMPARE_MODE:
    823       case GL_TEXTURE_COMPARE_FUNC:
    824         return true;
    825 
    826       default:
    827         return gl::error(GL_INVALID_ENUM, false);
    828     }
    829 }
    830 
    831 bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
    832                                   GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
    833 {
    834     gl::Framebuffer *framebuffer = context->getReadFramebuffer();
    835     ASSERT(framebuffer);
    836 
    837     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
    838     {
    839         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
    840     }
    841 
    842     if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
    843     {
    844         return gl::error(GL_INVALID_OPERATION, false);
    845     }
    846 
    847     if (!framebuffer->getReadColorbuffer())
    848     {
    849         return gl::error(GL_INVALID_OPERATION, false);
    850     }
    851 
    852     GLenum currentInternalFormat, currentFormat, currentType;
    853     int clientVersion = context->getClientVersion();
    854 
    855     context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
    856 
    857     bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
    858                                                  ValidES3ReadFormatType(context, currentInternalFormat, format, type);
    859 
    860     if (!(currentFormat == format && currentType == type) && !validReadFormat)
    861     {
    862         return gl::error(GL_INVALID_OPERATION, false);
    863     }
    864 
    865     GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
    866                                  GetSizedInternalFormat(format, type, clientVersion);
    867 
    868     GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
    869     // sized query sanity check
    870     if (bufSize)
    871     {
    872         int requiredSize = outputPitch * height;
    873         if (requiredSize > *bufSize)
    874         {
    875             return gl::error(GL_INVALID_OPERATION, false);
    876         }
    877     }
    878 
    879     return true;
    880 }
    881 
    882 bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
    883 {
    884     if (!ValidQueryType(context, target))
    885     {
    886         return gl::error(GL_INVALID_ENUM, false);
    887     }
    888 
    889     if (id == 0)
    890     {
    891         return gl::error(GL_INVALID_OPERATION, false);
    892     }
    893 
    894     // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
    895     // of zero, if the active query object name for <target> is non-zero (for the
    896     // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
    897     // the active query for either target is non-zero), if <id> is the name of an
    898     // existing query object whose type does not match <target>, or if <id> is the
    899     // active query object name for any query type, the error INVALID_OPERATION is
    900     // generated.
    901 
    902     // Ensure no other queries are active
    903     // NOTE: If other queries than occlusion are supported, we will need to check
    904     // separately that:
    905     //    a) The query ID passed is not the current active query for any target/type
    906     //    b) There are no active queries for the requested target (and in the case
    907     //       of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
    908     //       no query may be active for either if glBeginQuery targets either.
    909     if (context->isQueryActive())
    910     {
    911         return gl::error(GL_INVALID_OPERATION, false);
    912     }
    913 
    914     Query *queryObject = context->getQuery(id, true, target);
    915 
    916     // check that name was obtained with glGenQueries
    917     if (!queryObject)
    918     {
    919         return gl::error(GL_INVALID_OPERATION, false);
    920     }
    921 
    922     // check for type mismatch
    923     if (queryObject->getType() != target)
    924     {
    925         return gl::error(GL_INVALID_OPERATION, false);
    926     }
    927 
    928     return true;
    929 }
    930 
    931 bool ValidateEndQuery(gl::Context *context, GLenum target)
    932 {
    933     if (!ValidQueryType(context, target))
    934     {
    935         return gl::error(GL_INVALID_ENUM, false);
    936     }
    937 
    938     const Query *queryObject = context->getActiveQuery(target);
    939 
    940     if (queryObject == NULL)
    941     {
    942         return gl::error(GL_INVALID_OPERATION, false);
    943     }
    944 
    945     if (!queryObject->isStarted())
    946     {
    947         return gl::error(GL_INVALID_OPERATION, false);
    948     }
    949 
    950     return true;
    951 }
    952 
    953 static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
    954                                       GLint location, GLsizei count, LinkedUniform **uniformOut)
    955 {
    956     if (count < 0)
    957     {
    958         return gl::error(GL_INVALID_VALUE, false);
    959     }
    960 
    961     gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
    962     if (!programBinary)
    963     {
    964         return gl::error(GL_INVALID_OPERATION, false);
    965     }
    966 
    967     if (location == -1)
    968     {
    969         // Silently ignore the uniform command
    970         return false;
    971     }
    972 
    973     if (!programBinary->isValidUniformLocation(location))
    974     {
    975         return gl::error(GL_INVALID_OPERATION, false);
    976     }
    977 
    978     LinkedUniform *uniform = programBinary->getUniformByLocation(location);
    979 
    980     // attempting to write an array to a non-array uniform is an INVALID_OPERATION
    981     if (uniform->elementCount() == 1 && count > 1)
    982     {
    983         return gl::error(GL_INVALID_OPERATION, false);
    984     }
    985 
    986     *uniformOut = uniform;
    987     return true;
    988 }
    989 
    990 bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
    991 {
    992     // Check for ES3 uniform entry points
    993     if (UniformComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
    994     {
    995         return gl::error(GL_INVALID_OPERATION, false);
    996     }
    997 
    998     LinkedUniform *uniform = NULL;
    999     if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
   1000     {
   1001         return false;
   1002     }
   1003 
   1004     GLenum targetBoolType = UniformBoolVectorType(uniformType);
   1005     bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
   1006     if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
   1007     {
   1008         return gl::error(GL_INVALID_OPERATION, false);
   1009     }
   1010 
   1011     return true;
   1012 }
   1013 
   1014 bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
   1015                            GLboolean transpose)
   1016 {
   1017     // Check for ES3 uniform entry points
   1018     int rows = VariableRowCount(matrixType);
   1019     int cols = VariableColumnCount(matrixType);
   1020     if (rows != cols && context->getClientVersion() < 3)
   1021     {
   1022         return gl::error(GL_INVALID_OPERATION, false);
   1023     }
   1024 
   1025     if (transpose != GL_FALSE && context->getClientVersion() < 3)
   1026     {
   1027         return gl::error(GL_INVALID_VALUE, false);
   1028     }
   1029 
   1030     LinkedUniform *uniform = NULL;
   1031     if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
   1032     {
   1033         return false;
   1034     }
   1035 
   1036     if (uniform->type != matrixType)
   1037     {
   1038         return gl::error(GL_INVALID_OPERATION, false);
   1039     }
   1040 
   1041     return true;
   1042 }
   1043 
   1044 bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
   1045 {
   1046     if (!context->getQueryParameterInfo(pname, nativeType, numParams))
   1047     {
   1048         return gl::error(GL_INVALID_ENUM, false);
   1049     }
   1050 
   1051     if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
   1052     {
   1053         unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
   1054 
   1055         if (colorAttachment >= context->getMaximumRenderTargets())
   1056         {
   1057             return gl::error(GL_INVALID_OPERATION, false);
   1058         }
   1059     }
   1060 
   1061     switch (pname)
   1062     {
   1063       case GL_TEXTURE_BINDING_2D:
   1064       case GL_TEXTURE_BINDING_CUBE_MAP:
   1065       case GL_TEXTURE_BINDING_3D:
   1066       case GL_TEXTURE_BINDING_2D_ARRAY:
   1067         if (context->getActiveSampler() >= context->getMaximumCombinedTextureImageUnits())
   1068         {
   1069             return gl::error(GL_INVALID_OPERATION, false);
   1070         }
   1071         break;
   1072 
   1073       case GL_IMPLEMENTATION_COLOR_READ_TYPE:
   1074       case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
   1075         {
   1076             Framebuffer *framebuffer = context->getReadFramebuffer();
   1077             ASSERT(framebuffer);
   1078             if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
   1079             {
   1080                 return gl::error(GL_INVALID_OPERATION, false);
   1081             }
   1082 
   1083             FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
   1084             if (!attachment)
   1085             {
   1086                 return gl::error(GL_INVALID_OPERATION, false);
   1087             }
   1088         }
   1089         break;
   1090 
   1091       default:
   1092         break;
   1093     }
   1094 
   1095     // pname is valid, but there are no parameters to return
   1096     if (numParams == 0)
   1097     {
   1098         return false;
   1099     }
   1100 
   1101     return true;
   1102 }
   1103 
   1104 bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
   1105                                         GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
   1106                                         GLint border, GLenum *textureFormatOut)
   1107 {
   1108 
   1109     if (!ValidTexture2DDestinationTarget(context, target))
   1110     {
   1111         return gl::error(GL_INVALID_ENUM, false);
   1112     }
   1113 
   1114     if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
   1115     {
   1116         return gl::error(GL_INVALID_VALUE, false);
   1117     }
   1118 
   1119     if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
   1120     {
   1121         return gl::error(GL_INVALID_VALUE, false);
   1122     }
   1123 
   1124     if (border != 0)
   1125     {
   1126         return gl::error(GL_INVALID_VALUE, false);
   1127     }
   1128 
   1129     if (!ValidMipLevel(context, target, level))
   1130     {
   1131         return gl::error(GL_INVALID_VALUE, false);
   1132     }
   1133 
   1134     gl::Framebuffer *framebuffer = context->getReadFramebuffer();
   1135     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
   1136     {
   1137         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
   1138     }
   1139 
   1140     if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
   1141     {
   1142         return gl::error(GL_INVALID_OPERATION, false);
   1143     }
   1144 
   1145     gl::Texture *texture = NULL;
   1146     GLenum textureInternalFormat = GL_NONE;
   1147     bool textureCompressed = false;
   1148     bool textureIsDepth = false;
   1149     GLint textureLevelWidth = 0;
   1150     GLint textureLevelHeight = 0;
   1151     GLint textureLevelDepth = 0;
   1152     int maxDimension = 0;
   1153 
   1154     switch (target)
   1155     {
   1156       case GL_TEXTURE_2D:
   1157         {
   1158             gl::Texture2D *texture2d = context->getTexture2D();
   1159             if (texture2d)
   1160             {
   1161                 textureInternalFormat = texture2d->getInternalFormat(level);
   1162                 textureCompressed = texture2d->isCompressed(level);
   1163                 textureIsDepth = texture2d->isDepth(level);
   1164                 textureLevelWidth = texture2d->getWidth(level);
   1165                 textureLevelHeight = texture2d->getHeight(level);
   1166                 textureLevelDepth = 1;
   1167                 texture = texture2d;
   1168                 maxDimension = context->getMaximum2DTextureDimension();
   1169             }
   1170         }
   1171         break;
   1172 
   1173       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   1174       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   1175       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   1176       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   1177       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   1178       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   1179         {
   1180             gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
   1181             if (textureCube)
   1182             {
   1183                 textureInternalFormat = textureCube->getInternalFormat(target, level);
   1184                 textureCompressed = textureCube->isCompressed(target, level);
   1185                 textureIsDepth = false;
   1186                 textureLevelWidth = textureCube->getWidth(target, level);
   1187                 textureLevelHeight = textureCube->getHeight(target, level);
   1188                 textureLevelDepth = 1;
   1189                 texture = textureCube;
   1190                 maxDimension = context->getMaximumCubeTextureDimension();
   1191             }
   1192         }
   1193         break;
   1194 
   1195       case GL_TEXTURE_2D_ARRAY:
   1196         {
   1197             gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
   1198             if (texture2dArray)
   1199             {
   1200                 textureInternalFormat = texture2dArray->getInternalFormat(level);
   1201                 textureCompressed = texture2dArray->isCompressed(level);
   1202                 textureIsDepth = texture2dArray->isDepth(level);
   1203                 textureLevelWidth = texture2dArray->getWidth(level);
   1204                 textureLevelHeight = texture2dArray->getHeight(level);
   1205                 textureLevelDepth = texture2dArray->getLayers(level);
   1206                 texture = texture2dArray;
   1207                 maxDimension = context->getMaximum2DTextureDimension();
   1208             }
   1209         }
   1210         break;
   1211 
   1212       case GL_TEXTURE_3D:
   1213         {
   1214             gl::Texture3D *texture3d = context->getTexture3D();
   1215             if (texture3d)
   1216             {
   1217                 textureInternalFormat = texture3d->getInternalFormat(level);
   1218                 textureCompressed = texture3d->isCompressed(level);
   1219                 textureIsDepth = texture3d->isDepth(level);
   1220                 textureLevelWidth = texture3d->getWidth(level);
   1221                 textureLevelHeight = texture3d->getHeight(level);
   1222                 textureLevelDepth = texture3d->getDepth(level);
   1223                 texture = texture3d;
   1224                 maxDimension = context->getMaximum3DTextureDimension();
   1225             }
   1226         }
   1227         break;
   1228 
   1229       default:
   1230         return gl::error(GL_INVALID_ENUM, false);
   1231     }
   1232 
   1233     if (!texture)
   1234     {
   1235         return gl::error(GL_INVALID_OPERATION, false);
   1236     }
   1237 
   1238     if (texture->isImmutable() && !isSubImage)
   1239     {
   1240         return gl::error(GL_INVALID_OPERATION, false);
   1241     }
   1242 
   1243     if (textureIsDepth)
   1244     {
   1245         return gl::error(GL_INVALID_OPERATION, false);
   1246     }
   1247 
   1248     if (textureCompressed)
   1249     {
   1250         int clientVersion = context->getClientVersion();
   1251         GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat, clientVersion);
   1252         GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat, clientVersion);
   1253 
   1254         if (((width % blockWidth) != 0 && width != textureLevelWidth) ||
   1255             ((height % blockHeight) != 0 && height != textureLevelHeight))
   1256         {
   1257             return gl::error(GL_INVALID_OPERATION, false);
   1258         }
   1259     }
   1260 
   1261     if (isSubImage)
   1262     {
   1263         if (xoffset + width > textureLevelWidth ||
   1264             yoffset + height > textureLevelHeight ||
   1265             zoffset >= textureLevelDepth)
   1266         {
   1267             return gl::error(GL_INVALID_VALUE, false);
   1268         }
   1269     }
   1270     else
   1271     {
   1272         if (IsCubemapTextureTarget(target) && width != height)
   1273         {
   1274             return gl::error(GL_INVALID_VALUE, false);
   1275         }
   1276 
   1277         if (!IsValidInternalFormat(internalformat, context))
   1278         {
   1279             return gl::error(GL_INVALID_ENUM, false);
   1280         }
   1281 
   1282         int maxLevelDimension = (maxDimension >> level);
   1283         if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
   1284         {
   1285             return gl::error(GL_INVALID_VALUE, false);
   1286         }
   1287     }
   1288 
   1289     *textureFormatOut = textureInternalFormat;
   1290     return true;
   1291 }
   1292 
   1293 }
   1294