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