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 // validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters
      9 
     10 #include "libGLESv2/validationES3.h"
     11 #include "libGLESv2/validationES.h"
     12 #include "libGLESv2/Context.h"
     13 #include "libGLESv2/Texture.h"
     14 #include "libGLESv2/Framebuffer.h"
     15 #include "libGLESv2/Renderbuffer.h"
     16 #include "libGLESv2/formatutils.h"
     17 #include "libGLESv2/main.h"
     18 
     19 #include "common/mathutil.h"
     20 
     21 namespace gl
     22 {
     23 
     24 bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
     25                                    GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
     26                                    GLint border, GLenum format, GLenum type, const GLvoid *pixels)
     27 {
     28     if (!ValidTexture2DDestinationTarget(context, target))
     29     {
     30         return gl::error(GL_INVALID_ENUM, false);
     31     }
     32 
     33     // Validate image size
     34     if (!ValidImageSize(context, target, level, width, height, depth))
     35     {
     36         return gl::error(GL_INVALID_VALUE, false);
     37     }
     38 
     39     // Verify zero border
     40     if (border != 0)
     41     {
     42         return gl::error(GL_INVALID_VALUE, false);
     43     }
     44 
     45     if (xoffset < 0 || yoffset < 0 || zoffset < 0 ||
     46         std::numeric_limits<GLsizei>::max() - xoffset < width ||
     47         std::numeric_limits<GLsizei>::max() - yoffset < height ||
     48         std::numeric_limits<GLsizei>::max() - zoffset < depth)
     49     {
     50         return gl::error(GL_INVALID_VALUE, false);
     51     }
     52 
     53     gl::Texture *texture = NULL;
     54     bool textureCompressed = false;
     55     GLenum textureInternalFormat = GL_NONE;
     56     GLint textureLevelWidth = 0;
     57     GLint textureLevelHeight = 0;
     58     GLint textureLevelDepth = 0;
     59     switch (target)
     60     {
     61       case GL_TEXTURE_2D:
     62         {
     63             if (width > (context->getMaximum2DTextureDimension() >> level) ||
     64                 height > (context->getMaximum2DTextureDimension() >> level))
     65             {
     66                 return gl::error(GL_INVALID_VALUE, false);
     67             }
     68 
     69             gl::Texture2D *texture2d = context->getTexture2D();
     70             if (texture2d)
     71             {
     72                 textureCompressed = texture2d->isCompressed(level);
     73                 textureInternalFormat = texture2d->getInternalFormat(level);
     74                 textureLevelWidth = texture2d->getWidth(level);
     75                 textureLevelHeight = texture2d->getHeight(level);
     76                 textureLevelDepth = 1;
     77                 texture = texture2d;
     78             }
     79         }
     80         break;
     81 
     82       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     83       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     84       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     85       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     86       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     87       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
     88         {
     89             if (!isSubImage && width != height)
     90             {
     91                 return gl::error(GL_INVALID_VALUE, false);
     92             }
     93 
     94             if (width > (context->getMaximumCubeTextureDimension() >> level))
     95             {
     96                 return gl::error(GL_INVALID_VALUE, false);
     97             }
     98 
     99             gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
    100             if (textureCube)
    101             {
    102                 textureCompressed = textureCube->isCompressed(target, level);
    103                 textureInternalFormat = textureCube->getInternalFormat(target, level);
    104                 textureLevelWidth = textureCube->getWidth(target, level);
    105                 textureLevelHeight = textureCube->getHeight(target, level);
    106                 textureLevelDepth = 1;
    107                 texture = textureCube;
    108             }
    109         }
    110         break;
    111 
    112       case GL_TEXTURE_3D:
    113         {
    114             if (width > (context->getMaximum3DTextureDimension() >> level) ||
    115                 height > (context->getMaximum3DTextureDimension() >> level) ||
    116                 depth > (context->getMaximum3DTextureDimension() >> level))
    117             {
    118                 return gl::error(GL_INVALID_VALUE, false);
    119             }
    120 
    121             gl::Texture3D *texture3d = context->getTexture3D();
    122             if (texture3d)
    123             {
    124                 textureCompressed = texture3d->isCompressed(level);
    125                 textureInternalFormat = texture3d->getInternalFormat(level);
    126                 textureLevelWidth = texture3d->getWidth(level);
    127                 textureLevelHeight = texture3d->getHeight(level);
    128                 textureLevelDepth = texture3d->getDepth(level);
    129                 texture = texture3d;
    130             }
    131         }
    132         break;
    133 
    134         case GL_TEXTURE_2D_ARRAY:
    135           {
    136               if (width > (context->getMaximum2DTextureDimension() >> level) ||
    137                   height > (context->getMaximum2DTextureDimension() >> level) ||
    138                   depth > (context->getMaximum2DArrayTextureLayers() >> level))
    139               {
    140                   return gl::error(GL_INVALID_VALUE, false);
    141               }
    142 
    143               gl::Texture2DArray *texture2darray = context->getTexture2DArray();
    144               if (texture2darray)
    145               {
    146                   textureCompressed = texture2darray->isCompressed(level);
    147                   textureInternalFormat = texture2darray->getInternalFormat(level);
    148                   textureLevelWidth = texture2darray->getWidth(level);
    149                   textureLevelHeight = texture2darray->getHeight(level);
    150                   textureLevelDepth = texture2darray->getLayers(level);
    151                   texture = texture2darray;
    152               }
    153           }
    154           break;
    155 
    156       default:
    157         return gl::error(GL_INVALID_ENUM, false);
    158     }
    159 
    160     if (!texture)
    161     {
    162         return gl::error(GL_INVALID_OPERATION, false);
    163     }
    164 
    165     if (texture->isImmutable() && !isSubImage)
    166     {
    167         return gl::error(GL_INVALID_OPERATION, false);
    168     }
    169 
    170     // Validate texture formats
    171     GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
    172     int clientVersion = context->getClientVersion();
    173     if (isCompressed)
    174     {
    175         if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
    176         {
    177             return gl::error(GL_INVALID_OPERATION, false);
    178         }
    179 
    180         if (!gl::IsFormatCompressed(actualInternalFormat, clientVersion))
    181         {
    182             return gl::error(GL_INVALID_ENUM, false);
    183         }
    184 
    185         if (target == GL_TEXTURE_3D)
    186         {
    187             return gl::error(GL_INVALID_OPERATION, false);
    188         }
    189     }
    190     else
    191     {
    192         // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
    193         // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
    194         if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
    195             !gl::IsValidFormat(format, clientVersion) ||
    196             !gl::IsValidType(type, clientVersion))
    197         {
    198             return gl::error(GL_INVALID_ENUM, false);
    199         }
    200 
    201         if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, clientVersion))
    202         {
    203             return gl::error(GL_INVALID_OPERATION, false);
    204         }
    205 
    206         if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
    207         {
    208             return gl::error(GL_INVALID_OPERATION, false);
    209         }
    210     }
    211 
    212     // Validate sub image parameters
    213     if (isSubImage)
    214     {
    215         if (isCompressed != textureCompressed)
    216         {
    217             return gl::error(GL_INVALID_OPERATION, false);
    218         }
    219 
    220         if (isCompressed)
    221         {
    222             if ((width % 4 != 0 && width != textureLevelWidth) ||
    223                 (height % 4 != 0 && height != textureLevelHeight))
    224             {
    225                 return gl::error(GL_INVALID_OPERATION, false);
    226             }
    227         }
    228 
    229         if (width == 0 || height == 0 || depth == 0)
    230         {
    231             return false;
    232         }
    233 
    234         if (xoffset < 0 || yoffset < 0 || zoffset < 0)
    235         {
    236             return gl::error(GL_INVALID_VALUE, false);
    237         }
    238 
    239         if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
    240             std::numeric_limits<GLsizei>::max() - yoffset < height ||
    241             std::numeric_limits<GLsizei>::max() - zoffset < depth)
    242         {
    243             return gl::error(GL_INVALID_VALUE, false);
    244         }
    245 
    246         if (xoffset + width > textureLevelWidth ||
    247             yoffset + height > textureLevelHeight ||
    248             zoffset + depth > textureLevelDepth)
    249         {
    250             return gl::error(GL_INVALID_VALUE, false);
    251         }
    252     }
    253 
    254     // Check for pixel unpack buffer related API errors
    255     gl::Buffer *pixelUnpackBuffer = context->getPixelUnpackBuffer();
    256     if (pixelUnpackBuffer != NULL)
    257     {
    258         // ...the data would be unpacked from the buffer object such that the memory reads required
    259         // would exceed the data store size.
    260         size_t widthSize = static_cast<size_t>(width);
    261         size_t heightSize = static_cast<size_t>(height);
    262         size_t depthSize = static_cast<size_t>(depth);
    263         GLenum sizedFormat = gl::IsSizedInternalFormat(actualInternalFormat, clientVersion) ?
    264                              actualInternalFormat :
    265                              gl::GetSizedInternalFormat(actualInternalFormat, type, clientVersion);
    266 
    267         size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(sizedFormat, clientVersion));
    268 
    269         if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
    270             !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
    271             !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
    272         {
    273             // Overflow past the end of the buffer
    274             return gl::error(GL_INVALID_OPERATION, false);
    275         }
    276 
    277         size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes;
    278         size_t offset = reinterpret_cast<size_t>(pixels);
    279 
    280         if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
    281             ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->size())))
    282         {
    283             // Overflow past the end of the buffer
    284             return gl::error(GL_INVALID_OPERATION, false);
    285         }
    286 
    287         // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
    288         // indicated by type.
    289         size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type));
    290 
    291         if ((offset % dataBytesPerPixel) != 0)
    292         {
    293             return gl::error(GL_INVALID_OPERATION, false);
    294         }
    295 
    296         // ...the buffer object's data store is currently mapped.
    297         if (pixelUnpackBuffer->mapped())
    298         {
    299             return gl::error(GL_INVALID_OPERATION, false);
    300         }
    301     }
    302 
    303     return true;
    304 }
    305 
    306 bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
    307                                        bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
    308                                        GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
    309 {
    310     GLenum textureInternalFormat;
    311     if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
    312                                             xoffset, yoffset, zoffset, x, y, width, height,
    313                                             border, &textureInternalFormat))
    314     {
    315         return false;
    316     }
    317 
    318     gl::Framebuffer *framebuffer = context->getReadFramebuffer();
    319 
    320     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
    321     {
    322         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
    323     }
    324 
    325     if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
    326     {
    327         return gl::error(GL_INVALID_OPERATION, false);
    328     }
    329 
    330     gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
    331     GLenum colorbufferInternalFormat = source->getInternalFormat();
    332 
    333     if (isSubImage)
    334     {
    335         if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
    336                                                 context->getReadFramebufferHandle(),
    337                                                 context->getClientVersion()))
    338         {
    339             return gl::error(GL_INVALID_OPERATION, false);
    340         }
    341     }
    342     else
    343     {
    344         if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat,
    345                                                 context->getReadFramebufferHandle(),
    346                                                 context->getClientVersion()))
    347         {
    348             return gl::error(GL_INVALID_OPERATION, false);
    349         }
    350     }
    351 
    352     // If width or height is zero, it is a no-op.  Return false without setting an error.
    353     return (width > 0 && height > 0);
    354 }
    355 
    356 bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
    357                                      GLsizei width, GLsizei height, GLsizei depth)
    358 {
    359     if (width < 1 || height < 1 || depth < 1 || levels < 1)
    360     {
    361         return gl::error(GL_INVALID_VALUE, false);
    362     }
    363 
    364     if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
    365     {
    366         return gl::error(GL_INVALID_OPERATION, false);
    367     }
    368 
    369     gl::Texture *texture = NULL;
    370     switch (target)
    371     {
    372       case GL_TEXTURE_2D:
    373         {
    374             texture = context->getTexture2D();
    375 
    376             if (width > (context->getMaximum2DTextureDimension()) ||
    377                 height > (context->getMaximum2DTextureDimension()))
    378             {
    379                 return gl::error(GL_INVALID_VALUE, false);
    380             }
    381         }
    382         break;
    383 
    384       case GL_TEXTURE_CUBE_MAP:
    385         {
    386             texture = context->getTextureCubeMap();
    387 
    388             if (width != height)
    389             {
    390                 return gl::error(GL_INVALID_VALUE, false);
    391             }
    392 
    393             if (width > (context->getMaximumCubeTextureDimension()))
    394             {
    395                 return gl::error(GL_INVALID_VALUE, false);
    396             }
    397         }
    398         break;
    399 
    400       case GL_TEXTURE_3D:
    401         {
    402             texture = context->getTexture3D();
    403 
    404             if (width > (context->getMaximum3DTextureDimension()) ||
    405                 height > (context->getMaximum3DTextureDimension()) ||
    406                 depth > (context->getMaximum3DTextureDimension()))
    407             {
    408                 return gl::error(GL_INVALID_VALUE, false);
    409             }
    410         }
    411         break;
    412 
    413       case GL_TEXTURE_2D_ARRAY:
    414         {
    415             texture = context->getTexture2DArray();
    416 
    417             if (width > (context->getMaximum2DTextureDimension()) ||
    418                 height > (context->getMaximum2DTextureDimension()) ||
    419                 depth > (context->getMaximum2DArrayTextureLayers()))
    420             {
    421                 return gl::error(GL_INVALID_VALUE, false);
    422             }
    423         }
    424         break;
    425 
    426       default:
    427         return gl::error(GL_INVALID_ENUM, false);
    428     }
    429 
    430     if (!texture || texture->id() == 0)
    431     {
    432         return gl::error(GL_INVALID_OPERATION, false);
    433     }
    434 
    435     if (texture->isImmutable())
    436     {
    437         return gl::error(GL_INVALID_OPERATION, false);
    438     }
    439 
    440     if (!gl::IsValidInternalFormat(internalformat, context))
    441     {
    442         return gl::error(GL_INVALID_ENUM, false);
    443     }
    444 
    445     if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
    446     {
    447         return gl::error(GL_INVALID_ENUM, false);
    448     }
    449 
    450     return true;
    451 }
    452 
    453 bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
    454                                              GLenum textarget, GLuint texture, GLint level, GLint layer,
    455                                              bool layerCall)
    456 {
    457     if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
    458     {
    459         return gl::error(GL_INVALID_ENUM, false);
    460     }
    461 
    462     if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
    463     {
    464         const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
    465         if (colorAttachment >= context->getMaximumRenderTargets())
    466         {
    467             return gl::error(GL_INVALID_VALUE, false);
    468         }
    469     }
    470     else
    471     {
    472         switch (attachment)
    473         {
    474           case GL_DEPTH_ATTACHMENT:
    475           case GL_STENCIL_ATTACHMENT:
    476           case GL_DEPTH_STENCIL_ATTACHMENT:
    477             break;
    478           default:
    479             return gl::error(GL_INVALID_ENUM, false);
    480         }
    481     }
    482 
    483     if (texture != 0)
    484     {
    485         gl::Texture *tex = context->getTexture(texture);
    486 
    487         if (tex == NULL)
    488         {
    489             return gl::error(GL_INVALID_OPERATION, false);
    490         }
    491 
    492         if (level < 0)
    493         {
    494             return gl::error(GL_INVALID_VALUE, false);
    495         }
    496 
    497         if (layer < 0)
    498         {
    499             return gl::error(GL_INVALID_VALUE, false);
    500         }
    501 
    502         if (!layerCall)
    503         {
    504             switch (textarget)
    505             {
    506               case GL_TEXTURE_2D:
    507                 {
    508                     if (level > gl::log2(context->getMaximum2DTextureDimension()))
    509                     {
    510                         return gl::error(GL_INVALID_VALUE, false);
    511                     }
    512                     if (tex->getTarget() != GL_TEXTURE_2D)
    513                     {
    514                         return gl::error(GL_INVALID_OPERATION, false);
    515                     }
    516                     gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
    517                     if (tex2d->isCompressed(level))
    518                     {
    519                         return gl::error(GL_INVALID_OPERATION, false);
    520                     }
    521                     break;
    522                 }
    523 
    524               case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
    525               case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
    526               case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
    527               case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
    528               case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
    529               case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
    530                 {
    531                     if (level > gl::log2(context->getMaximumCubeTextureDimension()))
    532                     {
    533                         return gl::error(GL_INVALID_VALUE, false);
    534                     }
    535                     if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
    536                     {
    537                         return gl::error(GL_INVALID_OPERATION, false);
    538                     }
    539                     gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
    540                     if (texcube->isCompressed(textarget, level))
    541                     {
    542                         return gl::error(GL_INVALID_OPERATION, false);
    543                     }
    544                     break;
    545                 }
    546 
    547               default:
    548                 return gl::error(GL_INVALID_ENUM, false);
    549             }
    550         }
    551         else
    552         {
    553             switch (tex->getTarget())
    554             {
    555               case GL_TEXTURE_2D_ARRAY:
    556                 {
    557                     if (level > gl::log2(context->getMaximum2DTextureDimension()))
    558                     {
    559                         return gl::error(GL_INVALID_VALUE, false);
    560                     }
    561 
    562                     if (layer >= context->getMaximum2DArrayTextureLayers())
    563                     {
    564                         return gl::error(GL_INVALID_VALUE, false);
    565                     }
    566 
    567                     gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
    568                     if (texArray->isCompressed(level))
    569                     {
    570                         return gl::error(GL_INVALID_OPERATION, false);
    571                     }
    572 
    573                     break;
    574                 }
    575 
    576               case GL_TEXTURE_3D:
    577                 {
    578                     if (level > gl::log2(context->getMaximum3DTextureDimension()))
    579                     {
    580                         return gl::error(GL_INVALID_VALUE, false);
    581                     }
    582 
    583                     if (layer >= context->getMaximum3DTextureDimension())
    584                     {
    585                         return gl::error(GL_INVALID_VALUE, false);
    586                     }
    587 
    588                     gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
    589                     if (tex3d->isCompressed(level))
    590                     {
    591                         return gl::error(GL_INVALID_OPERATION, false);
    592                     }
    593 
    594                     break;
    595                 }
    596 
    597               default:
    598                 return gl::error(GL_INVALID_OPERATION, false);
    599             }
    600         }
    601     }
    602 
    603     gl::Framebuffer *framebuffer = NULL;
    604     GLuint framebufferHandle = 0;
    605     if (target == GL_READ_FRAMEBUFFER)
    606     {
    607         framebuffer = context->getReadFramebuffer();
    608         framebufferHandle = context->getReadFramebufferHandle();
    609     }
    610     else
    611     {
    612         framebuffer = context->getDrawFramebuffer();
    613         framebufferHandle = context->getDrawFramebufferHandle();
    614     }
    615 
    616     if (framebufferHandle == 0 || !framebuffer)
    617     {
    618         return gl::error(GL_INVALID_OPERATION, false);
    619     }
    620 
    621     return true;
    622 }
    623 
    624 bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
    625 {
    626     switch (format)
    627     {
    628       case GL_RGBA:
    629         switch (type)
    630         {
    631           case GL_UNSIGNED_BYTE:
    632             break;
    633           case GL_UNSIGNED_INT_2_10_10_10_REV:
    634             if (internalFormat != GL_RGB10_A2)
    635             {
    636                 return false;
    637             }
    638             break;
    639           case GL_FLOAT:
    640             if (gl::GetComponentType(internalFormat, 3) != GL_FLOAT)
    641             {
    642                 return false;
    643             }
    644             break;
    645           default:
    646             return false;
    647         }
    648         break;
    649       case GL_RGBA_INTEGER:
    650         switch (type)
    651         {
    652           case GL_INT:
    653             if (gl::GetComponentType(internalFormat, 3) != GL_INT)
    654             {
    655                 return false;
    656             }
    657             break;
    658           case GL_UNSIGNED_INT:
    659             if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
    660             {
    661                 return false;
    662             }
    663             break;
    664           default:
    665             return false;
    666         }
    667         break;
    668       case GL_BGRA_EXT:
    669         switch (type)
    670         {
    671           case GL_UNSIGNED_BYTE:
    672           case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
    673           case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
    674             break;
    675           default:
    676             return false;
    677         }
    678         break;
    679       case GL_RG_EXT:
    680       case GL_RED_EXT:
    681         if (!context->supportsRGTextures())
    682         {
    683             return false;
    684         }
    685         switch (type)
    686         {
    687         case GL_UNSIGNED_BYTE:
    688             break;
    689         default:
    690             return false;
    691         }
    692         break;
    693       default:
    694         return false;
    695     }
    696     return true;
    697 }
    698 
    699 bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
    700                                              const GLenum* attachments)
    701 {
    702     bool defaultFramebuffer = false;
    703 
    704     switch (target)
    705     {
    706       case GL_DRAW_FRAMEBUFFER:
    707       case GL_FRAMEBUFFER:
    708         defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
    709         break;
    710       case GL_READ_FRAMEBUFFER:
    711         defaultFramebuffer = context->getReadFramebufferHandle() == 0;
    712         break;
    713       default:
    714         return gl::error(GL_INVALID_ENUM, false);
    715     }
    716 
    717     for (int i = 0; i < numAttachments; ++i)
    718     {
    719         if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
    720         {
    721             if (defaultFramebuffer)
    722             {
    723                 return gl::error(GL_INVALID_ENUM, false);
    724             }
    725 
    726             if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
    727             {
    728                 return gl::error(GL_INVALID_OPERATION, false);
    729             }
    730         }
    731         else
    732         {
    733             switch (attachments[i])
    734             {
    735               case GL_DEPTH_ATTACHMENT:
    736               case GL_STENCIL_ATTACHMENT:
    737               case GL_DEPTH_STENCIL_ATTACHMENT:
    738                 if (defaultFramebuffer)
    739                 {
    740                     return gl::error(GL_INVALID_ENUM, false);
    741                 }
    742                 break;
    743               case GL_COLOR:
    744               case GL_DEPTH:
    745               case GL_STENCIL:
    746                 if (!defaultFramebuffer)
    747                 {
    748                     return gl::error(GL_INVALID_ENUM, false);
    749                 }
    750                 break;
    751               default:
    752                 return gl::error(GL_INVALID_ENUM, false);
    753             }
    754         }
    755     }
    756 
    757     return true;
    758 }
    759 
    760 }
    761