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(¤tInternalFormat, ¤tFormat, ¤tType);
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