Home | History | Annotate | Download | only in libGLESv2
      1 //
      2 // Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // validationES.h: Validation functions for generic OpenGL ES entry point parameters
      8 
      9 #include "libGLESv2/validationES.h"
     10 #include "libGLESv2/validationES2.h"
     11 #include "libGLESv2/validationES3.h"
     12 #include "libGLESv2/Context.h"
     13 #include "libGLESv2/Texture.h"
     14 #include "libGLESv2/Framebuffer.h"
     15 #include "libGLESv2/FramebufferAttachment.h"
     16 #include "libGLESv2/formatutils.h"
     17 #include "libGLESv2/main.h"
     18 #include "libGLESv2/Query.h"
     19 #include "libGLESv2/ProgramBinary.h"
     20 #include "libGLESv2/TransformFeedback.h"
     21 #include "libGLESv2/VertexArray.h"
     22 #include "libGLESv2/renderer/BufferImpl.h"
     23 
     24 #include "common/mathutil.h"
     25 #include "common/utilities.h"
     26 
     27 namespace gl
     28 {
     29 
     30 bool ValidCap(const Context *context, GLenum cap)
     31 {
     32     switch (cap)
     33     {
     34       case GL_CULL_FACE:
     35       case GL_POLYGON_OFFSET_FILL:
     36       case GL_SAMPLE_ALPHA_TO_COVERAGE:
     37       case GL_SAMPLE_COVERAGE:
     38       case GL_SCISSOR_TEST:
     39       case GL_STENCIL_TEST:
     40       case GL_DEPTH_TEST:
     41       case GL_BLEND:
     42       case GL_DITHER:
     43         return true;
     44       case GL_PRIMITIVE_RESTART_FIXED_INDEX:
     45       case GL_RASTERIZER_DISCARD:
     46         return (context->getClientVersion() >= 3);
     47       default:
     48         return false;
     49     }
     50 }
     51 
     52 bool ValidTextureTarget(const Context *context, GLenum target)
     53 {
     54     switch (target)
     55     {
     56       case GL_TEXTURE_2D:
     57       case GL_TEXTURE_CUBE_MAP:
     58         return true;
     59 
     60       case GL_TEXTURE_3D:
     61       case GL_TEXTURE_2D_ARRAY:
     62         return (context->getClientVersion() >= 3);
     63 
     64       default:
     65         return false;
     66     }
     67 }
     68 
     69 // This function differs from ValidTextureTarget in that the target must be
     70 // usable as the destination of a 2D operation-- so a cube face is valid, but
     71 // GL_TEXTURE_CUBE_MAP is not.
     72 // Note: duplicate of IsInternalTextureTarget
     73 bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
     74 {
     75     switch (target)
     76     {
     77       case GL_TEXTURE_2D:
     78       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     79       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     80       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     81       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     82       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     83       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
     84         return true;
     85       case GL_TEXTURE_2D_ARRAY:
     86       case GL_TEXTURE_3D:
     87         return (context->getClientVersion() >= 3);
     88       default:
     89         return false;
     90     }
     91 }
     92 
     93 bool ValidFramebufferTarget(GLenum target)
     94 {
     95     META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
     96 
     97     switch (target)
     98     {
     99       case GL_FRAMEBUFFER:      return true;
    100       case GL_READ_FRAMEBUFFER: return true;
    101       case GL_DRAW_FRAMEBUFFER: return true;
    102       default:                  return false;
    103     }
    104 }
    105 
    106 bool ValidBufferTarget(const Context *context, GLenum target)
    107 {
    108     switch (target)
    109     {
    110       case GL_ARRAY_BUFFER:
    111       case GL_ELEMENT_ARRAY_BUFFER:
    112         return true;
    113 
    114       case GL_PIXEL_PACK_BUFFER:
    115       case GL_PIXEL_UNPACK_BUFFER:
    116         return context->getExtensions().pixelBufferObject;
    117 
    118       case GL_COPY_READ_BUFFER:
    119       case GL_COPY_WRITE_BUFFER:
    120       case GL_TRANSFORM_FEEDBACK_BUFFER:
    121       case GL_UNIFORM_BUFFER:
    122         return (context->getClientVersion() >= 3);
    123 
    124       default:
    125         return false;
    126     }
    127 }
    128 
    129 bool ValidBufferParameter(const Context *context, GLenum pname)
    130 {
    131     switch (pname)
    132     {
    133       case GL_BUFFER_USAGE:
    134       case GL_BUFFER_SIZE:
    135         return true;
    136 
    137       // GL_BUFFER_MAP_POINTER is a special case, and may only be
    138       // queried with GetBufferPointerv
    139       case GL_BUFFER_ACCESS_FLAGS:
    140       case GL_BUFFER_MAPPED:
    141       case GL_BUFFER_MAP_OFFSET:
    142       case GL_BUFFER_MAP_LENGTH:
    143         return (context->getClientVersion() >= 3);
    144 
    145       default:
    146         return false;
    147     }
    148 }
    149 
    150 bool ValidMipLevel(const Context *context, GLenum target, GLint level)
    151 {
    152     size_t maxDimension = 0;
    153     switch (target)
    154     {
    155       case GL_TEXTURE_2D:                  maxDimension = context->getCaps().max2DTextureSize;       break;
    156       case GL_TEXTURE_CUBE_MAP:
    157       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
    158       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
    159       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
    160       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
    161       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
    162       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize;  break;
    163       case GL_TEXTURE_3D:                  maxDimension = context->getCaps().max3DTextureSize;       break;
    164       case GL_TEXTURE_2D_ARRAY:            maxDimension = context->getCaps().max2DTextureSize;       break;
    165       default: UNREACHABLE();
    166     }
    167 
    168     return level <= gl::log2(maxDimension);
    169 }
    170 
    171 bool ValidImageSize(const Context *context, GLenum target, GLint level,
    172                     GLsizei width, GLsizei height, GLsizei depth)
    173 {
    174     if (level < 0 || width < 0 || height < 0 || depth < 0)
    175     {
    176         return false;
    177     }
    178 
    179     if (!context->getExtensions().textureNPOT &&
    180         (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
    181     {
    182         return false;
    183     }
    184 
    185     if (!ValidMipLevel(context, target, level))
    186     {
    187         return false;
    188     }
    189 
    190     return true;
    191 }
    192 
    193 bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
    194 {
    195     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
    196     if (!formatInfo.compressed)
    197     {
    198         return false;
    199     }
    200 
    201     if (width  < 0 || (static_cast<GLuint>(width)  > formatInfo.compressedBlockWidth  && width  % formatInfo.compressedBlockWidth != 0) ||
    202         height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 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(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         context->recordError(Error(GL_INVALID_OPERATION));
    241         return false;
    242     }
    243     else
    244     {
    245         // No shader/program object has this ID
    246         context->recordError(Error(GL_INVALID_VALUE));
    247         return false;
    248     }
    249 }
    250 
    251 bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
    252 {
    253     if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
    254     {
    255         const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
    256 
    257         if (colorAttachment >= context->getCaps().maxColorAttachments)
    258         {
    259             context->recordError(Error(GL_INVALID_VALUE));
    260             return false;
    261         }
    262     }
    263     else
    264     {
    265         switch (attachment)
    266         {
    267           case GL_DEPTH_ATTACHMENT:
    268           case GL_STENCIL_ATTACHMENT:
    269             break;
    270 
    271           case GL_DEPTH_STENCIL_ATTACHMENT:
    272             if (context->getClientVersion() < 3)
    273             {
    274                 context->recordError(Error(GL_INVALID_ENUM));
    275                 return false;
    276             }
    277             break;
    278 
    279           default:
    280             context->recordError(Error(GL_INVALID_ENUM));
    281             return false;
    282         }
    283     }
    284 
    285     return true;
    286 }
    287 
    288 bool ValidateRenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
    289                                            GLenum internalformat, GLsizei width, GLsizei height,
    290                                            bool angleExtension)
    291 {
    292     switch (target)
    293     {
    294       case GL_RENDERBUFFER:
    295         break;
    296       default:
    297         context->recordError(Error(GL_INVALID_ENUM));
    298         return false;
    299     }
    300 
    301     if (width < 0 || height < 0 || samples < 0)
    302     {
    303         context->recordError(Error(GL_INVALID_VALUE));
    304         return false;
    305     }
    306 
    307     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
    308     if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
    309     {
    310         context->recordError(Error(GL_INVALID_ENUM));
    311         return false;
    312     }
    313 
    314     // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
    315     // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
    316     // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
    317     // internal format must be sized and not an integer format if samples is greater than zero.
    318     if (formatInfo.pixelBytes == 0)
    319     {
    320         context->recordError(Error(GL_INVALID_ENUM));
    321         return false;
    322     }
    323 
    324     if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
    325     {
    326         context->recordError(Error(GL_INVALID_OPERATION));
    327         return false;
    328     }
    329 
    330     const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
    331     if (!formatCaps.renderable)
    332     {
    333         context->recordError(Error(GL_INVALID_ENUM));
    334         return false;
    335     }
    336 
    337     if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
    338     {
    339         context->recordError(Error(GL_INVALID_VALUE));
    340         return false;
    341     }
    342 
    343     // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
    344     // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
    345     // states that samples must be less than or equal to the maximum samples for the specified
    346     // internal format.
    347     if (angleExtension)
    348     {
    349         ASSERT(context->getExtensions().framebufferMultisample);
    350         if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
    351         {
    352             context->recordError(Error(GL_INVALID_VALUE));
    353             return false;
    354         }
    355 
    356         // Check if this specific format supports enough samples
    357         if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
    358         {
    359             context->recordError(Error(GL_OUT_OF_MEMORY));
    360             return false;
    361         }
    362     }
    363     else
    364     {
    365         if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
    366         {
    367             context->recordError(Error(GL_INVALID_VALUE));
    368             return false;
    369         }
    370     }
    371 
    372     GLuint handle = context->getState().getRenderbufferId();
    373     if (handle == 0)
    374     {
    375         context->recordError(Error(GL_INVALID_OPERATION));
    376         return false;
    377     }
    378 
    379     return true;
    380 }
    381 
    382 bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
    383                                                GLenum renderbuffertarget, GLuint renderbuffer)
    384 {
    385     if (!ValidFramebufferTarget(target))
    386     {
    387         context->recordError(Error(GL_INVALID_ENUM));
    388         return false;
    389     }
    390 
    391     gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
    392     GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
    393 
    394     if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
    395     {
    396         context->recordError(Error(GL_INVALID_OPERATION));
    397         return false;
    398     }
    399 
    400     if (!ValidateAttachmentTarget(context, attachment))
    401     {
    402         return false;
    403     }
    404 
    405     // [OpenGL ES 2.0.25] Section 4.4.3 page 112
    406     // [OpenGL ES 3.0.2] Section 4.4.2 page 201
    407     // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
    408     // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
    409     if (renderbuffer != 0)
    410     {
    411         if (!context->getRenderbuffer(renderbuffer))
    412         {
    413             context->recordError(Error(GL_INVALID_OPERATION));
    414             return false;
    415         }
    416     }
    417 
    418     return true;
    419 }
    420 
    421 static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
    422                           GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    423                           GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
    424 {
    425     if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
    426         dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
    427         srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
    428     {
    429         return true;
    430     }
    431     else if (context->getState().isScissorTestEnabled())
    432     {
    433         const Rectangle &scissor = context->getState().getScissor();
    434 
    435         return scissor.x > 0 || scissor.y > 0 ||
    436                scissor.width < writeBuffer->getWidth() ||
    437                scissor.height < writeBuffer->getHeight();
    438     }
    439     else
    440     {
    441         return false;
    442     }
    443 }
    444 
    445 bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    446                                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
    447                                        GLenum filter, bool fromAngleExtension)
    448 {
    449     switch (filter)
    450     {
    451       case GL_NEAREST:
    452         break;
    453       case GL_LINEAR:
    454         if (fromAngleExtension)
    455         {
    456             context->recordError(Error(GL_INVALID_ENUM));
    457             return false;
    458         }
    459         break;
    460       default:
    461         context->recordError(Error(GL_INVALID_ENUM));
    462         return false;
    463     }
    464 
    465     if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
    466     {
    467         context->recordError(Error(GL_INVALID_VALUE));
    468         return false;
    469     }
    470 
    471     if (mask == 0)
    472     {
    473         // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
    474         // buffers are copied.
    475         return false;
    476     }
    477 
    478     if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
    479     {
    480         ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
    481         context->recordError(Error(GL_INVALID_OPERATION));
    482         return false;
    483     }
    484 
    485     // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
    486     // color buffer, leaving only nearest being unfiltered from above
    487     if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
    488     {
    489         context->recordError(Error(GL_INVALID_OPERATION));
    490         return false;
    491     }
    492 
    493     if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
    494     {
    495         if (fromAngleExtension)
    496         {
    497             ERR("Blits with the same source and destination framebuffer are not supported by this "
    498                 "implementation.");
    499         }
    500         context->recordError(Error(GL_INVALID_OPERATION));
    501         return false;
    502     }
    503 
    504     gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
    505     gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
    506     if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
    507         !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
    508     {
    509         context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
    510         return false;
    511     }
    512 
    513     if (drawFramebuffer->getSamples() != 0)
    514     {
    515         context->recordError(Error(GL_INVALID_OPERATION));
    516         return false;
    517     }
    518 
    519     bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
    520 
    521     if (mask & GL_COLOR_BUFFER_BIT)
    522     {
    523         gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
    524         gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
    525 
    526         if (readColorBuffer && drawColorBuffer)
    527         {
    528             GLenum readInternalFormat = readColorBuffer->getActualFormat();
    529             const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
    530 
    531             for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
    532             {
    533                 if (drawFramebuffer->isEnabledColorAttachment(i))
    534                 {
    535                     GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
    536                     const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
    537 
    538                     // The GL ES 3.0.2 spec (pg 193) states that:
    539                     // 1) If the read buffer is fixed point format, the draw buffer must be as well
    540                     // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
    541                     // 3) If the read buffer is a signed integer format, the draw buffer must be as well
    542                     if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
    543                         !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
    544                     {
    545                         context->recordError(Error(GL_INVALID_OPERATION));
    546                         return false;
    547                     }
    548 
    549                     if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
    550                     {
    551                         context->recordError(Error(GL_INVALID_OPERATION));
    552                         return false;
    553                     }
    554 
    555                     if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
    556                     {
    557                         context->recordError(Error(GL_INVALID_OPERATION));
    558                         return false;
    559                     }
    560 
    561                     if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
    562                     {
    563                         context->recordError(Error(GL_INVALID_OPERATION));
    564                         return false;
    565                     }
    566                 }
    567             }
    568 
    569             if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
    570             {
    571                 context->recordError(Error(GL_INVALID_OPERATION));
    572                 return false;
    573             }
    574 
    575             if (fromAngleExtension)
    576             {
    577                 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
    578                 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
    579                 {
    580                     context->recordError(Error(GL_INVALID_OPERATION));
    581                     return false;
    582                 }
    583 
    584                 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
    585                 {
    586                     if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
    587                     {
    588                         FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
    589                         ASSERT(attachment);
    590 
    591                         if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
    592                         {
    593                             context->recordError(Error(GL_INVALID_OPERATION));
    594                             return false;
    595                         }
    596 
    597                         if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
    598                         {
    599                             context->recordError(Error(GL_INVALID_OPERATION));
    600                             return false;
    601                         }
    602                     }
    603                 }
    604                 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
    605                                                                         srcX0, srcY0, srcX1, srcY1,
    606                                                                         dstX0, dstY0, dstX1, dstY1))
    607                 {
    608                     context->recordError(Error(GL_INVALID_OPERATION));
    609                     return false;
    610                 }
    611             }
    612         }
    613     }
    614 
    615     if (mask & GL_DEPTH_BUFFER_BIT)
    616     {
    617         gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
    618         gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
    619 
    620         if (readDepthBuffer && drawDepthBuffer)
    621         {
    622             if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
    623             {
    624                 context->recordError(Error(GL_INVALID_OPERATION));
    625                 return false;
    626             }
    627 
    628             if (readDepthBuffer->getSamples() > 0 && !sameBounds)
    629             {
    630                 context->recordError(Error(GL_INVALID_OPERATION));
    631                 return false;
    632             }
    633 
    634             if (fromAngleExtension)
    635             {
    636                 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
    637                                   srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
    638                 {
    639                     ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
    640                     context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
    641                     return false;
    642                 }
    643 
    644                 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
    645                 {
    646                     context->recordError(Error(GL_INVALID_OPERATION));
    647                     return false;
    648                 }
    649             }
    650         }
    651     }
    652 
    653     if (mask & GL_STENCIL_BUFFER_BIT)
    654     {
    655         gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
    656         gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
    657 
    658         if (readStencilBuffer && drawStencilBuffer)
    659         {
    660             if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
    661             {
    662                 context->recordError(Error(GL_INVALID_OPERATION));
    663                 return false;
    664             }
    665 
    666             if (readStencilBuffer->getSamples() > 0 && !sameBounds)
    667             {
    668                 context->recordError(Error(GL_INVALID_OPERATION));
    669                 return false;
    670             }
    671 
    672             if (fromAngleExtension)
    673             {
    674                 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
    675                                   srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
    676                 {
    677                     ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
    678                     context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
    679                     return false;
    680                 }
    681 
    682                 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
    683                 {
    684                     context->recordError(Error(GL_INVALID_OPERATION));
    685                     return false;
    686                 }
    687             }
    688         }
    689     }
    690 
    691     return true;
    692 }
    693 
    694 bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
    695 {
    696     switch (pname)
    697     {
    698       case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
    699       case GL_VERTEX_ATTRIB_ARRAY_SIZE:
    700       case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
    701       case GL_VERTEX_ATTRIB_ARRAY_TYPE:
    702       case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
    703       case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
    704       case GL_CURRENT_VERTEX_ATTRIB:
    705         return true;
    706 
    707       case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
    708         // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
    709         // the same constant.
    710         META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
    711         return true;
    712 
    713       case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
    714         if (context->getClientVersion() < 3)
    715         {
    716             context->recordError(Error(GL_INVALID_ENUM));
    717             return false;
    718         }
    719         return true;
    720 
    721       default:
    722         context->recordError(Error(GL_INVALID_ENUM));
    723         return false;
    724     }
    725 }
    726 
    727 bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
    728 {
    729     switch (pname)
    730     {
    731       case GL_TEXTURE_WRAP_R:
    732       case GL_TEXTURE_SWIZZLE_R:
    733       case GL_TEXTURE_SWIZZLE_G:
    734       case GL_TEXTURE_SWIZZLE_B:
    735       case GL_TEXTURE_SWIZZLE_A:
    736       case GL_TEXTURE_BASE_LEVEL:
    737       case GL_TEXTURE_MAX_LEVEL:
    738       case GL_TEXTURE_COMPARE_MODE:
    739       case GL_TEXTURE_COMPARE_FUNC:
    740       case GL_TEXTURE_MIN_LOD:
    741       case GL_TEXTURE_MAX_LOD:
    742         if (context->getClientVersion() < 3)
    743         {
    744             context->recordError(Error(GL_INVALID_ENUM));
    745             return false;
    746         }
    747         break;
    748 
    749       default: break;
    750     }
    751 
    752     switch (pname)
    753     {
    754       case GL_TEXTURE_WRAP_S:
    755       case GL_TEXTURE_WRAP_T:
    756       case GL_TEXTURE_WRAP_R:
    757         switch (param)
    758         {
    759           case GL_REPEAT:
    760           case GL_CLAMP_TO_EDGE:
    761           case GL_MIRRORED_REPEAT:
    762             return true;
    763           default:
    764             context->recordError(Error(GL_INVALID_ENUM));
    765             return false;
    766         }
    767 
    768       case GL_TEXTURE_MIN_FILTER:
    769         switch (param)
    770         {
    771           case GL_NEAREST:
    772           case GL_LINEAR:
    773           case GL_NEAREST_MIPMAP_NEAREST:
    774           case GL_LINEAR_MIPMAP_NEAREST:
    775           case GL_NEAREST_MIPMAP_LINEAR:
    776           case GL_LINEAR_MIPMAP_LINEAR:
    777             return true;
    778           default:
    779             context->recordError(Error(GL_INVALID_ENUM));
    780             return false;
    781         }
    782         break;
    783 
    784       case GL_TEXTURE_MAG_FILTER:
    785         switch (param)
    786         {
    787           case GL_NEAREST:
    788           case GL_LINEAR:
    789             return true;
    790           default:
    791             context->recordError(Error(GL_INVALID_ENUM));
    792             return false;
    793         }
    794         break;
    795 
    796       case GL_TEXTURE_USAGE_ANGLE:
    797         switch (param)
    798         {
    799           case GL_NONE:
    800           case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
    801             return true;
    802           default:
    803             context->recordError(Error(GL_INVALID_ENUM));
    804             return false;
    805         }
    806         break;
    807 
    808       case GL_TEXTURE_MAX_ANISOTROPY_EXT:
    809         if (!context->getExtensions().textureFilterAnisotropic)
    810         {
    811             context->recordError(Error(GL_INVALID_ENUM));
    812             return false;
    813         }
    814 
    815         // we assume the parameter passed to this validation method is truncated, not rounded
    816         if (param < 1)
    817         {
    818             context->recordError(Error(GL_INVALID_VALUE));
    819             return false;
    820         }
    821         return true;
    822 
    823       case GL_TEXTURE_MIN_LOD:
    824       case GL_TEXTURE_MAX_LOD:
    825         // any value is permissible
    826         return true;
    827 
    828       case GL_TEXTURE_COMPARE_MODE:
    829         // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
    830         switch (param)
    831         {
    832           case GL_NONE:
    833           case GL_COMPARE_REF_TO_TEXTURE:
    834             return true;
    835           default:
    836             context->recordError(Error(GL_INVALID_ENUM));
    837             return false;
    838         }
    839         break;
    840 
    841       case GL_TEXTURE_COMPARE_FUNC:
    842         // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
    843         switch (param)
    844         {
    845           case GL_LEQUAL:
    846           case GL_GEQUAL:
    847           case GL_LESS:
    848           case GL_GREATER:
    849           case GL_EQUAL:
    850           case GL_NOTEQUAL:
    851           case GL_ALWAYS:
    852           case GL_NEVER:
    853             return true;
    854           default:
    855             context->recordError(Error(GL_INVALID_ENUM));
    856             return false;
    857         }
    858         break;
    859 
    860       case GL_TEXTURE_SWIZZLE_R:
    861       case GL_TEXTURE_SWIZZLE_G:
    862       case GL_TEXTURE_SWIZZLE_B:
    863       case GL_TEXTURE_SWIZZLE_A:
    864         switch (param)
    865         {
    866           case GL_RED:
    867           case GL_GREEN:
    868           case GL_BLUE:
    869           case GL_ALPHA:
    870           case GL_ZERO:
    871           case GL_ONE:
    872             return true;
    873           default:
    874             context->recordError(Error(GL_INVALID_ENUM));
    875             return false;
    876         }
    877         break;
    878 
    879       case GL_TEXTURE_BASE_LEVEL:
    880       case GL_TEXTURE_MAX_LEVEL:
    881         if (param < 0)
    882         {
    883             context->recordError(Error(GL_INVALID_VALUE));
    884             return false;
    885         }
    886         return true;
    887 
    888       default:
    889         context->recordError(Error(GL_INVALID_ENUM));
    890         return false;
    891     }
    892 }
    893 
    894 bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
    895 {
    896     switch (pname)
    897     {
    898       case GL_TEXTURE_MIN_FILTER:
    899       case GL_TEXTURE_MAG_FILTER:
    900       case GL_TEXTURE_WRAP_S:
    901       case GL_TEXTURE_WRAP_T:
    902       case GL_TEXTURE_WRAP_R:
    903       case GL_TEXTURE_MIN_LOD:
    904       case GL_TEXTURE_MAX_LOD:
    905       case GL_TEXTURE_COMPARE_MODE:
    906       case GL_TEXTURE_COMPARE_FUNC:
    907         return true;
    908 
    909       default:
    910         context->recordError(Error(GL_INVALID_ENUM));
    911         return false;
    912     }
    913 }
    914 
    915 bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
    916                                   GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
    917 {
    918     gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
    919     ASSERT(framebuffer);
    920 
    921     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
    922     {
    923         context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
    924         return false;
    925     }
    926 
    927     if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
    928     {
    929         context->recordError(Error(GL_INVALID_OPERATION));
    930         return false;
    931     }
    932 
    933     if (!framebuffer->getReadColorbuffer())
    934     {
    935         context->recordError(Error(GL_INVALID_OPERATION));
    936         return false;
    937     }
    938 
    939     GLenum currentInternalFormat, currentFormat, currentType;
    940     GLuint clientVersion = context->getClientVersion();
    941 
    942     context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
    943 
    944     bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
    945                                                  ValidES3ReadFormatType(context, currentInternalFormat, format, type);
    946 
    947     if (!(currentFormat == format && currentType == type) && !validReadFormat)
    948     {
    949         context->recordError(Error(GL_INVALID_OPERATION));
    950         return false;
    951     }
    952 
    953     GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
    954     const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
    955 
    956     GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
    957     // sized query sanity check
    958     if (bufSize)
    959     {
    960         int requiredSize = outputPitch * height;
    961         if (requiredSize > *bufSize)
    962         {
    963             context->recordError(Error(GL_INVALID_OPERATION));
    964             return false;
    965         }
    966     }
    967 
    968     return true;
    969 }
    970 
    971 bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
    972 {
    973     if (!ValidQueryType(context, target))
    974     {
    975         context->recordError(Error(GL_INVALID_ENUM));
    976         return false;
    977     }
    978 
    979     if (id == 0)
    980     {
    981         context->recordError(Error(GL_INVALID_OPERATION));
    982         return false;
    983     }
    984 
    985     // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
    986     // of zero, if the active query object name for <target> is non-zero (for the
    987     // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
    988     // the active query for either target is non-zero), if <id> is the name of an
    989     // existing query object whose type does not match <target>, or if <id> is the
    990     // active query object name for any query type, the error INVALID_OPERATION is
    991     // generated.
    992 
    993     // Ensure no other queries are active
    994     // NOTE: If other queries than occlusion are supported, we will need to check
    995     // separately that:
    996     //    a) The query ID passed is not the current active query for any target/type
    997     //    b) There are no active queries for the requested target (and in the case
    998     //       of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
    999     //       no query may be active for either if glBeginQuery targets either.
   1000     if (context->getState().isQueryActive())
   1001     {
   1002         context->recordError(Error(GL_INVALID_OPERATION));
   1003         return false;
   1004     }
   1005 
   1006     Query *queryObject = context->getQuery(id, true, target);
   1007 
   1008     // check that name was obtained with glGenQueries
   1009     if (!queryObject)
   1010     {
   1011         context->recordError(Error(GL_INVALID_OPERATION));
   1012         return false;
   1013     }
   1014 
   1015     // check for type mismatch
   1016     if (queryObject->getType() != target)
   1017     {
   1018         context->recordError(Error(GL_INVALID_OPERATION));
   1019         return false;
   1020     }
   1021 
   1022     return true;
   1023 }
   1024 
   1025 bool ValidateEndQuery(gl::Context *context, GLenum target)
   1026 {
   1027     if (!ValidQueryType(context, target))
   1028     {
   1029         context->recordError(Error(GL_INVALID_ENUM));
   1030         return false;
   1031     }
   1032 
   1033     const Query *queryObject = context->getState().getActiveQuery(target);
   1034 
   1035     if (queryObject == NULL)
   1036     {
   1037         context->recordError(Error(GL_INVALID_OPERATION));
   1038         return false;
   1039     }
   1040 
   1041     return true;
   1042 }
   1043 
   1044 static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
   1045                                       GLint location, GLsizei count, LinkedUniform **uniformOut)
   1046 {
   1047     if (count < 0)
   1048     {
   1049         context->recordError(Error(GL_INVALID_VALUE));
   1050         return false;
   1051     }
   1052 
   1053     gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
   1054     if (!programBinary)
   1055     {
   1056         context->recordError(Error(GL_INVALID_OPERATION));
   1057         return false;
   1058     }
   1059 
   1060     if (location == -1)
   1061     {
   1062         // Silently ignore the uniform command
   1063         return false;
   1064     }
   1065 
   1066     if (!programBinary->isValidUniformLocation(location))
   1067     {
   1068         context->recordError(Error(GL_INVALID_OPERATION));
   1069         return false;
   1070     }
   1071 
   1072     LinkedUniform *uniform = programBinary->getUniformByLocation(location);
   1073 
   1074     // attempting to write an array to a non-array uniform is an INVALID_OPERATION
   1075     if (uniform->elementCount() == 1 && count > 1)
   1076     {
   1077         context->recordError(Error(GL_INVALID_OPERATION));
   1078         return false;
   1079     }
   1080 
   1081     *uniformOut = uniform;
   1082     return true;
   1083 }
   1084 
   1085 bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
   1086 {
   1087     // Check for ES3 uniform entry points
   1088     if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
   1089     {
   1090         context->recordError(Error(GL_INVALID_OPERATION));
   1091         return false;
   1092     }
   1093 
   1094     LinkedUniform *uniform = NULL;
   1095     if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
   1096     {
   1097         return false;
   1098     }
   1099 
   1100     GLenum targetBoolType = VariableBoolVectorType(uniformType);
   1101     bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
   1102     if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
   1103     {
   1104         context->recordError(Error(GL_INVALID_OPERATION));
   1105         return false;
   1106     }
   1107 
   1108     return true;
   1109 }
   1110 
   1111 bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
   1112                            GLboolean transpose)
   1113 {
   1114     // Check for ES3 uniform entry points
   1115     int rows = VariableRowCount(matrixType);
   1116     int cols = VariableColumnCount(matrixType);
   1117     if (rows != cols && context->getClientVersion() < 3)
   1118     {
   1119         context->recordError(Error(GL_INVALID_OPERATION));
   1120         return false;
   1121     }
   1122 
   1123     if (transpose != GL_FALSE && context->getClientVersion() < 3)
   1124     {
   1125         context->recordError(Error(GL_INVALID_VALUE));
   1126         return false;
   1127     }
   1128 
   1129     LinkedUniform *uniform = NULL;
   1130     if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
   1131     {
   1132         return false;
   1133     }
   1134 
   1135     if (uniform->type != matrixType)
   1136     {
   1137         context->recordError(Error(GL_INVALID_OPERATION));
   1138         return false;
   1139     }
   1140 
   1141     return true;
   1142 }
   1143 
   1144 bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
   1145 {
   1146     if (!context->getQueryParameterInfo(pname, nativeType, numParams))
   1147     {
   1148         context->recordError(Error(GL_INVALID_ENUM));
   1149         return false;
   1150     }
   1151 
   1152     if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
   1153     {
   1154         unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
   1155 
   1156         if (colorAttachment >= context->getCaps().maxDrawBuffers)
   1157         {
   1158             context->recordError(Error(GL_INVALID_OPERATION));
   1159             return false;
   1160         }
   1161     }
   1162 
   1163     switch (pname)
   1164     {
   1165       case GL_TEXTURE_BINDING_2D:
   1166       case GL_TEXTURE_BINDING_CUBE_MAP:
   1167       case GL_TEXTURE_BINDING_3D:
   1168       case GL_TEXTURE_BINDING_2D_ARRAY:
   1169         if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
   1170         {
   1171             context->recordError(Error(GL_INVALID_OPERATION));
   1172             return false;
   1173         }
   1174         break;
   1175 
   1176       case GL_IMPLEMENTATION_COLOR_READ_TYPE:
   1177       case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
   1178         {
   1179             Framebuffer *framebuffer = context->getState().getReadFramebuffer();
   1180             ASSERT(framebuffer);
   1181             if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
   1182             {
   1183                 context->recordError(Error(GL_INVALID_OPERATION));
   1184                 return false;
   1185             }
   1186 
   1187             FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
   1188             if (!attachment)
   1189             {
   1190                 context->recordError(Error(GL_INVALID_OPERATION));
   1191                 return false;
   1192             }
   1193         }
   1194         break;
   1195 
   1196       default:
   1197         break;
   1198     }
   1199 
   1200     // pname is valid, but there are no parameters to return
   1201     if (numParams == 0)
   1202     {
   1203         return false;
   1204     }
   1205 
   1206     return true;
   1207 }
   1208 
   1209 bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
   1210                                         GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
   1211                                         GLint border, GLenum *textureFormatOut)
   1212 {
   1213 
   1214     if (!ValidTexture2DDestinationTarget(context, target))
   1215     {
   1216         context->recordError(Error(GL_INVALID_ENUM));
   1217         return false;
   1218     }
   1219 
   1220     if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
   1221     {
   1222         context->recordError(Error(GL_INVALID_VALUE));
   1223         return false;
   1224     }
   1225 
   1226     if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
   1227     {
   1228         context->recordError(Error(GL_INVALID_VALUE));
   1229         return false;
   1230     }
   1231 
   1232     if (border != 0)
   1233     {
   1234         context->recordError(Error(GL_INVALID_VALUE));
   1235         return false;
   1236     }
   1237 
   1238     if (!ValidMipLevel(context, target, level))
   1239     {
   1240         context->recordError(Error(GL_INVALID_VALUE));
   1241         return false;
   1242     }
   1243 
   1244     gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
   1245     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
   1246     {
   1247         context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
   1248         return false;
   1249     }
   1250 
   1251     if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
   1252     {
   1253         context->recordError(Error(GL_INVALID_OPERATION));
   1254         return false;
   1255     }
   1256 
   1257     const gl::Caps &caps = context->getCaps();
   1258 
   1259     gl::Texture *texture = NULL;
   1260     GLenum textureInternalFormat = GL_NONE;
   1261     GLint textureLevelWidth = 0;
   1262     GLint textureLevelHeight = 0;
   1263     GLint textureLevelDepth = 0;
   1264     GLuint maxDimension = 0;
   1265 
   1266     switch (target)
   1267     {
   1268       case GL_TEXTURE_2D:
   1269         {
   1270             gl::Texture2D *texture2d = context->getTexture2D();
   1271             if (texture2d)
   1272             {
   1273                 textureInternalFormat = texture2d->getInternalFormat(level);
   1274                 textureLevelWidth = texture2d->getWidth(level);
   1275                 textureLevelHeight = texture2d->getHeight(level);
   1276                 textureLevelDepth = 1;
   1277                 texture = texture2d;
   1278                 maxDimension = caps.max2DTextureSize;
   1279             }
   1280         }
   1281         break;
   1282 
   1283       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   1284       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   1285       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   1286       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   1287       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   1288       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   1289         {
   1290             gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
   1291             if (textureCube)
   1292             {
   1293                 textureInternalFormat = textureCube->getInternalFormat(target, level);
   1294                 textureLevelWidth = textureCube->getWidth(target, level);
   1295                 textureLevelHeight = textureCube->getHeight(target, level);
   1296                 textureLevelDepth = 1;
   1297                 texture = textureCube;
   1298                 maxDimension = caps.maxCubeMapTextureSize;
   1299             }
   1300         }
   1301         break;
   1302 
   1303       case GL_TEXTURE_2D_ARRAY:
   1304         {
   1305             gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
   1306             if (texture2dArray)
   1307             {
   1308                 textureInternalFormat = texture2dArray->getInternalFormat(level);
   1309                 textureLevelWidth = texture2dArray->getWidth(level);
   1310                 textureLevelHeight = texture2dArray->getHeight(level);
   1311                 textureLevelDepth = texture2dArray->getLayers(level);
   1312                 texture = texture2dArray;
   1313                 maxDimension = caps.max2DTextureSize;
   1314             }
   1315         }
   1316         break;
   1317 
   1318       case GL_TEXTURE_3D:
   1319         {
   1320             gl::Texture3D *texture3d = context->getTexture3D();
   1321             if (texture3d)
   1322             {
   1323                 textureInternalFormat = texture3d->getInternalFormat(level);
   1324                 textureLevelWidth = texture3d->getWidth(level);
   1325                 textureLevelHeight = texture3d->getHeight(level);
   1326                 textureLevelDepth = texture3d->getDepth(level);
   1327                 texture = texture3d;
   1328                 maxDimension = caps.max3DTextureSize;
   1329             }
   1330         }
   1331         break;
   1332 
   1333       default:
   1334         context->recordError(Error(GL_INVALID_ENUM));
   1335         return false;
   1336     }
   1337 
   1338     if (!texture)
   1339     {
   1340         context->recordError(Error(GL_INVALID_OPERATION));
   1341         return false;
   1342     }
   1343 
   1344     if (texture->isImmutable() && !isSubImage)
   1345     {
   1346         context->recordError(Error(GL_INVALID_OPERATION));
   1347         return false;
   1348     }
   1349 
   1350     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
   1351 
   1352     if (formatInfo.depthBits > 0)
   1353     {
   1354         context->recordError(Error(GL_INVALID_OPERATION));
   1355         return false;
   1356     }
   1357 
   1358     if (formatInfo.compressed)
   1359     {
   1360         if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
   1361             ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
   1362         {
   1363             context->recordError(Error(GL_INVALID_OPERATION));
   1364             return false;
   1365         }
   1366     }
   1367 
   1368     if (isSubImage)
   1369     {
   1370         if (xoffset + width > textureLevelWidth ||
   1371             yoffset + height > textureLevelHeight ||
   1372             zoffset >= textureLevelDepth)
   1373         {
   1374             context->recordError(Error(GL_INVALID_VALUE));
   1375             return false;
   1376         }
   1377     }
   1378     else
   1379     {
   1380         if (IsCubemapTextureTarget(target) && width != height)
   1381         {
   1382             context->recordError(Error(GL_INVALID_VALUE));
   1383             return false;
   1384         }
   1385 
   1386         if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
   1387         {
   1388             context->recordError(Error(GL_INVALID_ENUM));
   1389             return false;
   1390         }
   1391 
   1392         int maxLevelDimension = (maxDimension >> level);
   1393         if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
   1394         {
   1395             context->recordError(Error(GL_INVALID_VALUE));
   1396             return false;
   1397         }
   1398     }
   1399 
   1400     *textureFormatOut = textureInternalFormat;
   1401     return true;
   1402 }
   1403 
   1404 static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
   1405 {
   1406     switch (mode)
   1407     {
   1408       case GL_POINTS:
   1409       case GL_LINES:
   1410       case GL_LINE_LOOP:
   1411       case GL_LINE_STRIP:
   1412       case GL_TRIANGLES:
   1413       case GL_TRIANGLE_STRIP:
   1414       case GL_TRIANGLE_FAN:
   1415         break;
   1416       default:
   1417         context->recordError(Error(GL_INVALID_ENUM));
   1418         return false;
   1419     }
   1420 
   1421     if (count < 0)
   1422     {
   1423         context->recordError(Error(GL_INVALID_VALUE));
   1424         return false;
   1425     }
   1426 
   1427     const State &state = context->getState();
   1428 
   1429     // Check for mapped buffers
   1430     if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
   1431     {
   1432         context->recordError(Error(GL_INVALID_OPERATION));
   1433         return false;
   1434     }
   1435 
   1436     const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
   1437     if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
   1438         state.getStencilRef() != state.getStencilBackRef() ||
   1439         depthStencilState.stencilMask != depthStencilState.stencilBackMask)
   1440     {
   1441         // Note: these separate values are not supported in WebGL, due to D3D's limitations.
   1442         // See Section 6.10 of the WebGL 1.0 spec
   1443         ERR("This ANGLE implementation does not support separate front/back stencil "
   1444             "writemasks, reference values, or stencil mask values.");
   1445         context->recordError(Error(GL_INVALID_OPERATION));
   1446         return false;
   1447     }
   1448 
   1449     const gl::Framebuffer *fbo = state.getDrawFramebuffer();
   1450     if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
   1451     {
   1452         context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
   1453         return false;
   1454     }
   1455 
   1456     if (state.getCurrentProgramId() == 0)
   1457     {
   1458         context->recordError(Error(GL_INVALID_OPERATION));
   1459         return false;
   1460     }
   1461 
   1462     gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
   1463     if (!programBinary->validateSamplers(NULL, context->getCaps()))
   1464     {
   1465         context->recordError(Error(GL_INVALID_OPERATION));
   1466         return false;
   1467     }
   1468 
   1469     // Buffer validations
   1470     const VertexArray *vao = state.getVertexArray();
   1471     for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
   1472     {
   1473         const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
   1474         bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
   1475         if (attribActive && attrib.enabled)
   1476         {
   1477             gl::Buffer *buffer = attrib.buffer.get();
   1478 
   1479             if (buffer)
   1480             {
   1481                 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
   1482                 GLint64 maxVertexElement = 0;
   1483 
   1484                 if (attrib.divisor > 0)
   1485                 {
   1486                     maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
   1487                 }
   1488                 else
   1489                 {
   1490                     maxVertexElement = static_cast<GLint64>(maxVertex);
   1491                 }
   1492 
   1493                 GLint64 attribDataSize = maxVertexElement * attribStride;
   1494 
   1495                 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
   1496                 // We can return INVALID_OPERATION if our vertex attribute does not have
   1497                 // enough backing data.
   1498                 if (attribDataSize > buffer->getSize())
   1499                 {
   1500                     context->recordError(Error(GL_INVALID_OPERATION));
   1501                     return false;
   1502                 }
   1503             }
   1504             else if (attrib.pointer == NULL)
   1505             {
   1506                 // This is an application error that would normally result in a crash,
   1507                 // but we catch it and return an error
   1508                 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
   1509                 return false;
   1510             }
   1511         }
   1512     }
   1513 
   1514     // No-op if zero count
   1515     return (count > 0);
   1516 }
   1517 
   1518 bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
   1519 {
   1520     if (first < 0)
   1521     {
   1522         context->recordError(Error(GL_INVALID_VALUE));
   1523         return false;
   1524     }
   1525 
   1526     const State &state = context->getState();
   1527     gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
   1528     if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
   1529         curTransformFeedback->getDrawMode() != mode)
   1530     {
   1531         // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
   1532         // that does not match the current transform feedback object's draw mode (if transform feedback
   1533         // is active), (3.0.2, section 2.14, pg 86)
   1534         context->recordError(Error(GL_INVALID_OPERATION));
   1535         return false;
   1536     }
   1537 
   1538     if (!ValidateDrawBase(context, mode, count, count, primcount))
   1539     {
   1540         return false;
   1541     }
   1542 
   1543     return true;
   1544 }
   1545 
   1546 bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
   1547 {
   1548     if (primcount < 0)
   1549     {
   1550         context->recordError(Error(GL_INVALID_VALUE));
   1551         return false;
   1552     }
   1553 
   1554     if (!ValidateDrawArrays(context, mode, first, count, primcount))
   1555     {
   1556         return false;
   1557     }
   1558 
   1559     // No-op if zero primitive count
   1560     return (primcount > 0);
   1561 }
   1562 
   1563 static bool ValidateDrawInstancedANGLE(Context *context)
   1564 {
   1565     // Verify there is at least one active attribute with a divisor of zero
   1566     const gl::State& state = context->getState();
   1567 
   1568     gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
   1569 
   1570     const VertexArray *vao = state.getVertexArray();
   1571     for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
   1572     {
   1573         const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
   1574         bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
   1575         if (active && attrib.divisor == 0)
   1576         {
   1577             return true;
   1578         }
   1579     }
   1580 
   1581     context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
   1582                                                      "has a divisor of zero."));
   1583     return false;
   1584 }
   1585 
   1586 bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
   1587 {
   1588     if (!ValidateDrawInstancedANGLE(context))
   1589     {
   1590         return false;
   1591     }
   1592 
   1593     return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
   1594 }
   1595 
   1596 bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
   1597                           const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
   1598 {
   1599     switch (type)
   1600     {
   1601       case GL_UNSIGNED_BYTE:
   1602       case GL_UNSIGNED_SHORT:
   1603         break;
   1604       case GL_UNSIGNED_INT:
   1605         if (!context->getExtensions().elementIndexUint)
   1606         {
   1607             context->recordError(Error(GL_INVALID_ENUM));
   1608             return false;
   1609         }
   1610         break;
   1611       default:
   1612         context->recordError(Error(GL_INVALID_ENUM));
   1613         return false;
   1614     }
   1615 
   1616     const State &state = context->getState();
   1617 
   1618     gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
   1619     if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
   1620     {
   1621         // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
   1622         // while transform feedback is active, (3.0.2, section 2.14, pg 86)
   1623         context->recordError(Error(GL_INVALID_OPERATION));
   1624         return false;
   1625     }
   1626 
   1627     // Check for mapped buffers
   1628     if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
   1629     {
   1630         context->recordError(Error(GL_INVALID_OPERATION));
   1631         return false;
   1632     }
   1633 
   1634     const gl::VertexArray *vao = state.getVertexArray();
   1635     const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
   1636     if (!indices && !elementArrayBuffer)
   1637     {
   1638         context->recordError(Error(GL_INVALID_OPERATION));
   1639         return false;
   1640     }
   1641 
   1642     if (elementArrayBuffer)
   1643     {
   1644         const gl::Type &typeInfo = gl::GetTypeInfo(type);
   1645 
   1646         GLint64 offset = reinterpret_cast<GLint64>(indices);
   1647         GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
   1648 
   1649         // check for integer overflows
   1650         if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
   1651             byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
   1652         {
   1653             context->recordError(Error(GL_OUT_OF_MEMORY));
   1654             return false;
   1655         }
   1656 
   1657         // Check for reading past the end of the bound buffer object
   1658         if (byteCount > elementArrayBuffer->getSize())
   1659         {
   1660             context->recordError(Error(GL_INVALID_OPERATION));
   1661             return false;
   1662         }
   1663     }
   1664     else if (!indices)
   1665     {
   1666         // Catch this programming error here
   1667         context->recordError(Error(GL_INVALID_OPERATION));
   1668         return false;
   1669     }
   1670 
   1671     // Use max index to validate if our vertex buffers are large enough for the pull.
   1672     // TODO: offer fast path, with disabled index validation.
   1673     // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
   1674     if (elementArrayBuffer)
   1675     {
   1676         unsigned int offset = reinterpret_cast<unsigned int>(indices);
   1677         if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
   1678         {
   1679             const void *dataPointer = elementArrayBuffer->getImplementation()->getData();
   1680             const uint8_t *offsetPointer = static_cast<const uint8_t *>(dataPointer) + offset;
   1681             *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
   1682         }
   1683     }
   1684     else
   1685     {
   1686         *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
   1687     }
   1688 
   1689     if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
   1690     {
   1691         return false;
   1692     }
   1693 
   1694     return true;
   1695 }
   1696 
   1697 bool ValidateDrawElementsInstanced(Context *context,
   1698                                    GLenum mode, GLsizei count, GLenum type,
   1699                                    const GLvoid *indices, GLsizei primcount,
   1700                                    rx::RangeUI *indexRangeOut)
   1701 {
   1702     if (primcount < 0)
   1703     {
   1704         context->recordError(Error(GL_INVALID_VALUE));
   1705         return false;
   1706     }
   1707 
   1708     if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
   1709     {
   1710         return false;
   1711     }
   1712 
   1713     // No-op zero primitive count
   1714     return (primcount > 0);
   1715 }
   1716 
   1717 bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
   1718                                         const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
   1719 {
   1720     if (!ValidateDrawInstancedANGLE(context))
   1721     {
   1722         return false;
   1723     }
   1724 
   1725     return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
   1726 }
   1727 
   1728 bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
   1729                                     GLuint texture, GLint level)
   1730 {
   1731     if (!ValidFramebufferTarget(target))
   1732     {
   1733         context->recordError(Error(GL_INVALID_ENUM));
   1734         return false;
   1735     }
   1736 
   1737     if (!ValidateAttachmentTarget(context, attachment))
   1738     {
   1739         return false;
   1740     }
   1741 
   1742     if (texture != 0)
   1743     {
   1744         gl::Texture *tex = context->getTexture(texture);
   1745 
   1746         if (tex == NULL)
   1747         {
   1748             context->recordError(Error(GL_INVALID_OPERATION));
   1749             return false;
   1750         }
   1751 
   1752         if (level < 0)
   1753         {
   1754             context->recordError(Error(GL_INVALID_VALUE));
   1755             return false;
   1756         }
   1757     }
   1758 
   1759     const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
   1760     GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
   1761 
   1762     if (framebufferHandle == 0 || !framebuffer)
   1763     {
   1764         context->recordError(Error(GL_INVALID_OPERATION));
   1765         return false;
   1766     }
   1767 
   1768     return true;
   1769 }
   1770 
   1771 bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
   1772                                   GLenum textarget, GLuint texture, GLint level)
   1773 {
   1774     // Attachments are required to be bound to level 0 in ES2
   1775     if (context->getClientVersion() < 3 && level != 0)
   1776     {
   1777         context->recordError(Error(GL_INVALID_VALUE));
   1778         return false;
   1779     }
   1780 
   1781     if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
   1782     {
   1783         return false;
   1784     }
   1785 
   1786     if (texture != 0)
   1787     {
   1788         gl::Texture *tex = context->getTexture(texture);
   1789         ASSERT(tex);
   1790 
   1791         const gl::Caps &caps = context->getCaps();
   1792 
   1793         switch (textarget)
   1794         {
   1795           case GL_TEXTURE_2D:
   1796             {
   1797                 if (level > gl::log2(caps.max2DTextureSize))
   1798                 {
   1799                     context->recordError(Error(GL_INVALID_VALUE));
   1800                     return false;
   1801                 }
   1802                 if (tex->getTarget() != GL_TEXTURE_2D)
   1803                 {
   1804                     context->recordError(Error(GL_INVALID_OPERATION));
   1805                     return false;
   1806                 }
   1807                 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
   1808                 if (tex2d->isCompressed(level))
   1809                 {
   1810                     context->recordError(Error(GL_INVALID_OPERATION));
   1811                     return false;
   1812                 }
   1813             }
   1814             break;
   1815 
   1816           case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   1817           case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   1818           case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   1819           case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   1820           case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   1821           case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   1822             {
   1823                 if (level > gl::log2(caps.maxCubeMapTextureSize))
   1824                 {
   1825                     context->recordError(Error(GL_INVALID_VALUE));
   1826                     return false;
   1827                 }
   1828                 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
   1829                 {
   1830                     context->recordError(Error(GL_INVALID_OPERATION));
   1831                     return false;
   1832                 }
   1833                 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
   1834                 if (texcube->isCompressed(textarget, level))
   1835                 {
   1836                     context->recordError(Error(GL_INVALID_OPERATION));
   1837                     return false;
   1838                 }
   1839             }
   1840             break;
   1841 
   1842           default:
   1843             context->recordError(Error(GL_INVALID_ENUM));
   1844             return false;
   1845         }
   1846     }
   1847 
   1848     return true;
   1849 }
   1850 
   1851 bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
   1852 {
   1853     if (program == 0)
   1854     {
   1855         context->recordError(Error(GL_INVALID_VALUE));
   1856         return false;
   1857     }
   1858 
   1859     gl::Program *programObject = context->getProgram(program);
   1860 
   1861     if (!programObject || !programObject->isLinked())
   1862     {
   1863         context->recordError(Error(GL_INVALID_OPERATION));
   1864         return false;
   1865     }
   1866 
   1867     gl::ProgramBinary *programBinary = programObject->getProgramBinary();
   1868     if (!programBinary)
   1869     {
   1870         context->recordError(Error(GL_INVALID_OPERATION));
   1871         return false;
   1872     }
   1873 
   1874     if (!programBinary->isValidUniformLocation(location))
   1875     {
   1876         context->recordError(Error(GL_INVALID_OPERATION));
   1877         return false;
   1878     }
   1879 
   1880     return true;
   1881 }
   1882 
   1883 bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
   1884 {
   1885     return ValidateGetUniformBase(context, program, location);
   1886 }
   1887 
   1888 bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
   1889 {
   1890     return ValidateGetUniformBase(context, program, location);
   1891 }
   1892 
   1893 static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
   1894 {
   1895     if (!ValidateGetUniformBase(context, program, location))
   1896     {
   1897         return false;
   1898     }
   1899 
   1900     gl::Program *programObject = context->getProgram(program);
   1901     ASSERT(programObject);
   1902     gl::ProgramBinary *programBinary = programObject->getProgramBinary();
   1903 
   1904     // sized queries -- ensure the provided buffer is large enough
   1905     LinkedUniform *uniform = programBinary->getUniformByLocation(location);
   1906     size_t requiredBytes = VariableExternalSize(uniform->type);
   1907     if (static_cast<size_t>(bufSize) < requiredBytes)
   1908     {
   1909         context->recordError(Error(GL_INVALID_OPERATION));
   1910         return false;
   1911     }
   1912 
   1913     return true;
   1914 }
   1915 
   1916 bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
   1917 {
   1918     return ValidateSizedGetUniform(context, program, location, bufSize);
   1919 }
   1920 
   1921 bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
   1922 {
   1923     return ValidateSizedGetUniform(context, program, location, bufSize);
   1924 }
   1925 
   1926 }
   1927