blob: 8c6b53159ee1247f05d106ac624dc62e053ba289 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#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/Context.h"
12#include "libGLESv2/Texture.h"
13#include "libGLESv2/Framebuffer.h"
14#include "libGLESv2/Renderbuffer.h"
15#include "libGLESv2/formatutils.h"
16#include "libGLESv2/main.h"
17
18#include "common/mathutil.h"
19
20namespace gl
21{
22
23static bool validImageSize(const gl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth)
24{
25 if (level < 0 || width < 0 || height < 0 || depth < 0)
26 {
27 return false;
28 }
29
30 if (context->supportsNonPower2Texture())
31 {
32 return true;
33 }
34
35 if (level == 0)
36 {
37 return true;
38 }
39
40 if (gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth))
41 {
42 return true;
43 }
44
45 return false;
46}
47
48static bool validCompressedImageSize(GLsizei width, GLsizei height)
49{
50 if (width != 1 && width != 2 && width % 4 != 0)
51 {
52 return false;
53 }
54
55 if (height != 1 && height != 2 && height % 4 != 0)
56 {
57 return false;
58 }
59
60 return true;
61}
62
63bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
64 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
65 GLint border, GLenum format, GLenum type)
66{
67 // Validate image size
68 if (!validImageSize(context, level, width, height, depth))
69 {
70 return gl::error(GL_INVALID_VALUE, false);
71 }
72
73 if (isCompressed && !validCompressedImageSize(width, height))
74 {
75 return gl::error(GL_INVALID_OPERATION, false);
76 }
77
78 // Verify zero border
79 if (border != 0)
80 {
81 return gl::error(GL_INVALID_VALUE, false);
82 }
83
84 // Validate dimensions based on Context limits and validate the texture
85 if (level > context->getMaximumTextureLevel())
86 {
87 return gl::error(GL_INVALID_VALUE, false);
88 }
89
90 gl::Texture *texture = NULL;
91 bool textureCompressed = false;
92 GLenum textureInternalFormat = GL_NONE;
93 GLint textureLevelWidth = 0;
94 GLint textureLevelHeight = 0;
95 GLint textureLevelDepth = 0;
96 switch (target)
97 {
98 case GL_TEXTURE_2D:
99 {
100 if (width > (context->getMaximum2DTextureDimension() >> level) ||
101 height > (context->getMaximum2DTextureDimension() >> level))
102 {
103 return gl::error(GL_INVALID_VALUE, false);
104 }
105
106 gl::Texture2D *texture2d = context->getTexture2D();
107 if (texture2d)
108 {
109 textureCompressed = texture2d->isCompressed(level);
110 textureInternalFormat = texture2d->getInternalFormat(level);
111 textureLevelWidth = texture2d->getWidth(level);
112 textureLevelHeight = texture2d->getHeight(level);
113 textureLevelDepth = 1;
114 texture = texture2d;
115 }
116 }
117 break;
118
119 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
120 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
121 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
122 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
123 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
124 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
125 {
126 if (!isSubImage && width != height)
127 {
128 return gl::error(GL_INVALID_VALUE, false);
129 }
130
131 if (width > (context->getMaximumCubeTextureDimension() >> level))
132 {
133 return gl::error(GL_INVALID_VALUE, false);
134 }
135
136 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
137 if (textureCube)
138 {
139 textureCompressed = textureCube->isCompressed(target, level);
140 textureInternalFormat = textureCube->getInternalFormat(target, level);
141 textureLevelWidth = textureCube->getWidth(target, level);
142 textureLevelHeight = textureCube->getHeight(target, level);
143 textureLevelDepth = 1;
144 texture = textureCube;
145 }
146 }
147 break;
148
149 case GL_TEXTURE_3D:
150 {
151 if (width > (context->getMaximum3DTextureDimension() >> level) ||
152 height > (context->getMaximum3DTextureDimension() >> level) ||
153 depth > (context->getMaximum3DTextureDimension() >> level))
154 {
155 return gl::error(GL_INVALID_VALUE, false);
156 }
157
158 gl::Texture3D *texture3d = context->getTexture3D();
159 if (texture3d)
160 {
161 textureCompressed = texture3d->isCompressed(level);
162 textureInternalFormat = texture3d->getInternalFormat(level);
163 textureLevelWidth = texture3d->getWidth(level);
164 textureLevelHeight = texture3d->getHeight(level);
165 textureLevelDepth = texture3d->getDepth(level);
166 texture = texture3d;
167 }
168 }
169 break;
170
171 case GL_TEXTURE_2D_ARRAY:
172 {
173 if (width > (context->getMaximum2DTextureDimension() >> level) ||
174 height > (context->getMaximum2DTextureDimension() >> level) ||
175 depth > (context->getMaximum2DArrayTextureLayers() >> level))
176 {
177 return gl::error(GL_INVALID_VALUE, false);
178 }
179
180 gl::Texture2DArray *texture2darray = context->getTexture2DArray();
181 if (texture2darray)
182 {
183 textureCompressed = texture2darray->isCompressed(level);
184 textureInternalFormat = texture2darray->getInternalFormat(level);
185 textureLevelWidth = texture2darray->getWidth(level);
186 textureLevelHeight = texture2darray->getHeight(level);
187 textureLevelDepth = texture2darray->getDepth(level);
188 texture = texture2darray;
189 }
190 }
191 break;
192
193 default:
194 return gl::error(GL_INVALID_ENUM, false);
195 }
196
197 if (!texture)
198 {
199 return gl::error(GL_INVALID_OPERATION, false);
200 }
201
202 if (texture->isImmutable() && !isSubImage)
203 {
204 return gl::error(GL_INVALID_OPERATION, false);
205 }
206
207 // Validate texture formats
208 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
209 if (isCompressed)
210 {
211 if (!gl::IsFormatCompressed(actualInternalFormat, context->getClientVersion()))
212 {
213 return gl::error(GL_INVALID_ENUM, false);
214 }
215
216 if (target == GL_TEXTURE_3D)
217 {
218 return gl::error(GL_INVALID_OPERATION, false);
219 }
220 }
221 else
222 {
223 if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
224 !gl::IsValidFormat(format, context->getClientVersion()) ||
225 !gl::IsValidType(type, context->getClientVersion()))
226 {
227 return gl::error(GL_INVALID_ENUM, false);
228 }
229
230 if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion()))
231 {
232 return gl::error(GL_INVALID_OPERATION, false);
233 }
234
235 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
236 {
237 return gl::error(GL_INVALID_OPERATION, false);
238 }
239 }
240
241 // Validate sub image parameters
242 if (isSubImage)
243 {
244 if (isCompressed != textureCompressed)
245 {
246 return gl::error(GL_INVALID_OPERATION, false);
247 }
248
249 if (format != GL_NONE)
250 {
251 GLenum internalformat = gl::GetSizedInternalFormat(format, type, context->getClientVersion());
252 if (internalformat != textureInternalFormat)
253 {
254 return gl::error(GL_INVALID_OPERATION, false);
255 }
256 }
257
258 if (isCompressed)
259 {
260 if ((width % 4 != 0 && width != textureLevelWidth) ||
261 (height % 4 != 0 && height != textureLevelHeight))
262 {
263 return gl::error(GL_INVALID_OPERATION, false);
264 }
265 }
266
267 if (width == 0 || height == 0 || depth == 0)
268 {
269 return false;
270 }
271
272 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
273 {
274 return gl::error(GL_INVALID_VALUE, false);
275 }
276
277 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
278 std::numeric_limits<GLsizei>::max() - yoffset < height ||
279 std::numeric_limits<GLsizei>::max() - zoffset < depth)
280 {
281 return gl::error(GL_INVALID_VALUE, false);
282 }
283
284 if (xoffset + width > textureLevelWidth ||
285 yoffset + height > textureLevelHeight ||
286 zoffset + depth > textureLevelDepth)
287 {
288 return gl::error(GL_INVALID_VALUE, false);
289 }
290 }
291
292 return true;
293}
294
295bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
296 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
297 GLsizei width, GLsizei height, GLint border)
298{
299 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
300 {
301 return gl::error(GL_INVALID_VALUE, false);
302 }
303
304 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
305 {
306 return gl::error(GL_INVALID_VALUE, false);
307 }
308
309 if (width == 0 || height == 0)
310 {
311 return false;
312 }
313
314 if (border != 0)
315 {
316 return gl::error(GL_INVALID_VALUE, false);
317 }
318
319 if (level > context->getMaximumTextureLevel())
320 {
321 return gl::error(GL_INVALID_VALUE, false);
322 }
323
324 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
325
326 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
327 {
328 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
329 }
330
331 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
332 {
333 return gl::error(GL_INVALID_OPERATION, false);
334 }
335
336 gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
337 GLenum colorbufferInternalFormat = source->getInternalFormat();
338 gl::Texture *texture = NULL;
339 GLenum textureInternalFormat = GL_NONE;
340 bool textureCompressed = false;
341 bool textureIsDepth = false;
342 GLint textureLevelWidth = 0;
343 GLint textureLevelHeight = 0;
344 GLint textureLevelDepth = 0;
345 switch (target)
346 {
347 case GL_TEXTURE_2D:
348 {
349 gl::Texture2D *texture2d = context->getTexture2D();
350 if (texture2d)
351 {
352 textureInternalFormat = texture2d->getInternalFormat(level);
353 textureCompressed = texture2d->isCompressed(level);
354 textureIsDepth = texture2d->isDepth(level);
355 textureLevelWidth = texture2d->getWidth(level);
356 textureLevelHeight = texture2d->getHeight(level);
357 textureLevelDepth = 1;
358 texture = texture2d;
359 }
360 }
361 break;
362
363 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
364 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
365 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
366 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
367 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
368 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
369 {
370 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
371 if (textureCube)
372 {
373 textureInternalFormat = textureCube->getInternalFormat(target, level);
374 textureCompressed = textureCube->isCompressed(target, level);
375 textureIsDepth = false;
376 textureLevelWidth = textureCube->getWidth(target, level);
377 textureLevelHeight = textureCube->getHeight(target, level);
378 textureLevelDepth = 1;
379 texture = textureCube;
380 }
381 }
382 break;
383
384 case GL_TEXTURE_2D_ARRAY:
385 {
386 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
387 if (texture2dArray)
388 {
389 textureInternalFormat = texture2dArray->getInternalFormat(level);
390 textureCompressed = texture2dArray->isCompressed(level);
391 textureIsDepth = texture2dArray->isDepth(level);
392 textureLevelWidth = texture2dArray->getWidth(level);
393 textureLevelHeight = texture2dArray->getHeight(level);
394 textureLevelDepth = texture2dArray->getDepth(level);
395 texture = texture2dArray;
396 }
397 }
398 break;
399
400 case GL_TEXTURE_3D:
401 {
402 gl::Texture3D *texture3d = context->getTexture3D();
403 if (texture3d)
404 {
405 textureInternalFormat = texture3d->getInternalFormat(level);
406 textureCompressed = texture3d->isCompressed(level);
407 textureIsDepth = texture3d->isDepth(level);
408 textureLevelWidth = texture3d->getWidth(level);
409 textureLevelHeight = texture3d->getHeight(level);
410 textureLevelDepth = texture3d->getDepth(level);
411 texture = texture3d;
412 }
413 }
414 break;
415
416 default:
417 return gl::error(GL_INVALID_ENUM, false);
418 }
419
420 if (!texture)
421 {
422 return gl::error(GL_INVALID_OPERATION, false);
423 }
424
425 if (texture->isImmutable() && !isSubImage)
426 {
427 return gl::error(GL_INVALID_OPERATION, false);
428 }
429
430 if (textureIsDepth)
431 {
432 return gl::error(GL_INVALID_OPERATION, false);
433 }
434
435 if (textureCompressed)
436 {
437 if ((width % 4 != 0 && width != textureLevelWidth) ||
438 (height % 4 != 0 && height != textureLevelHeight))
439 {
440 return gl::error(GL_INVALID_OPERATION, false);
441 }
442 }
443
444 if (isSubImage)
445 {
446 if (xoffset + width > textureLevelWidth ||
447 yoffset + height > textureLevelHeight ||
448 zoffset >= textureLevelDepth)
449 {
450 return gl::error(GL_INVALID_VALUE, false);
451 }
452
453 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
454 context->getClientVersion()))
455 {
456 return gl::error(GL_INVALID_OPERATION, false);
457 }
458 }
459
460 return true;
461}
462
463bool validateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
464 GLsizei width, GLsizei height, GLsizei depth)
465{
466 if (width < 1 || height < 1 || depth < 1 || levels < 1)
467 {
468 return gl::error(GL_INVALID_VALUE, false);
469 }
470
471 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
472 {
473 return gl::error(GL_INVALID_OPERATION, false);
474 }
475
476 gl::Texture *texture = NULL;
477 switch (target)
478 {
479 case GL_TEXTURE_2D:
480 {
481 texture = context->getTexture2D();
482
483 if (width > (context->getMaximum2DTextureDimension()) ||
484 height > (context->getMaximum2DTextureDimension()))
485 {
486 return gl::error(GL_INVALID_VALUE, false);
487 }
488 }
489 break;
490
491 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
492 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
493 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
494 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
495 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
496 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
497 {
498 texture = context->getTextureCubeMap();
499
500 if (width != height)
501 {
502 return gl::error(GL_INVALID_VALUE, false);
503 }
504
505 if (width > (context->getMaximumCubeTextureDimension()))
506 {
507 return gl::error(GL_INVALID_VALUE, false);
508 }
509 }
510 break;
511
512 case GL_TEXTURE_3D:
513 {
514 texture = context->getTexture3D();
515
516 if (width > (context->getMaximum3DTextureDimension()) ||
517 height > (context->getMaximum3DTextureDimension()) ||
518 depth > (context->getMaximum3DTextureDimension()))
519 {
520 return gl::error(GL_INVALID_VALUE, false);
521 }
522 }
523 break;
524
525 case GL_TEXTURE_2D_ARRAY:
526 {
527 texture = context->getTexture2DArray();
528
529 if (width > (context->getMaximum2DTextureDimension()) ||
530 height > (context->getMaximum2DTextureDimension()) ||
531 depth > (context->getMaximum2DArrayTextureLayers()))
532 {
533 return gl::error(GL_INVALID_VALUE, false);
534 }
535 }
536 break;
537
538 default:
539 return gl::error(GL_INVALID_ENUM, false);
540 }
541
542 if (!texture || texture->id() == 0)
543 {
544 return gl::error(GL_INVALID_OPERATION, false);
545 }
546
547 if (texture->isImmutable())
548 {
549 return gl::error(GL_INVALID_OPERATION, false);
550 }
551
552 if (!gl::IsValidInternalFormat(internalformat, context))
553 {
554 return gl::error(GL_INVALID_ENUM, false);
555 }
556
557 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
558 {
559 return gl::error(GL_INVALID_ENUM, false);
560 }
561
562 return true;
563}
564
565bool validateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
566 GLenum textarget, GLuint texture, GLint level, GLint layer,
567 bool layerCall)
568{
569 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
570 {
571 return gl::error(GL_INVALID_ENUM, false);
572 }
573
574 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
575 {
576 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
577 if (colorAttachment >= context->getMaximumRenderTargets())
578 {
579 return gl::error(GL_INVALID_VALUE, false);
580 }
581 }
582 else
583 {
584 switch (attachment)
585 {
586 case GL_DEPTH_ATTACHMENT:
587 case GL_STENCIL_ATTACHMENT:
588 case GL_DEPTH_STENCIL_ATTACHMENT:
589 break;
590 default:
591 return gl::error(GL_INVALID_ENUM, false);
592 }
593 }
594
595 if (texture != 0)
596 {
597 gl::Texture *tex = context->getTexture(texture);
598
599 if (tex == NULL)
600 {
601 return gl::error(GL_INVALID_OPERATION, false);
602 }
603
604 if (level < 0)
605 {
606 return gl::error(GL_INVALID_VALUE, false);
607 }
608
609 if (layer < 0)
610 {
611 return gl::error(GL_INVALID_VALUE, false);
612 }
613
614 if (!layerCall)
615 {
616 switch (textarget)
617 {
618 case GL_TEXTURE_2D:
619 {
620 if (level > gl::log2(context->getMaximum2DTextureDimension()))
621 {
622 return gl::error(GL_INVALID_VALUE, false);
623 }
624 if (tex->getTarget() != GL_TEXTURE_2D)
625 {
626 return gl::error(GL_INVALID_OPERATION, false);
627 }
628 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
629 if (tex2d->isCompressed(level))
630 {
631 return gl::error(GL_INVALID_OPERATION, false);
632 }
633 break;
634 }
635
636 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
637 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
638 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
639 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
640 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
641 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
642 {
643 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
644 {
645 return gl::error(GL_INVALID_VALUE, false);
646 }
647 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
648 {
649 return gl::error(GL_INVALID_OPERATION, false);
650 }
651 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
652 if (texcube->isCompressed(textarget, level))
653 {
654 return gl::error(GL_INVALID_OPERATION, false);
655 }
656 break;
657 }
658
659 default:
660 return gl::error(GL_INVALID_ENUM, false);
661 }
662 }
663 else
664 {
665 switch (tex->getTarget())
666 {
667 case GL_TEXTURE_2D_ARRAY:
668 {
669 if (level > gl::log2(context->getMaximum2DTextureDimension()))
670 {
671 return gl::error(GL_INVALID_VALUE, false);
672 }
673
674 if (layer >= context->getMaximum2DArrayTextureLayers())
675 {
676 return gl::error(GL_INVALID_VALUE, false);
677 }
678
679 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
680 if (texArray->isCompressed(level))
681 {
682 return gl::error(GL_INVALID_OPERATION, false);
683 }
684
685 break;
686 }
687
688 case GL_TEXTURE_3D:
689 {
690 if (level > gl::log2(context->getMaximum3DTextureDimension()))
691 {
692 return gl::error(GL_INVALID_VALUE, false);
693 }
694
695 if (layer >= context->getMaximum3DTextureDimension())
696 {
697 return gl::error(GL_INVALID_VALUE, false);
698 }
699
700 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
701 if (tex3d->isCompressed(level))
702 {
703 return gl::error(GL_INVALID_OPERATION, false);
704 }
705
706 break;
707 }
708
709 default:
710 return gl::error(GL_INVALID_OPERATION, false);
711 }
712 }
713 }
714
715 gl::Framebuffer *framebuffer = NULL;
716 GLuint framebufferHandle = 0;
717 if (target == GL_READ_FRAMEBUFFER)
718 {
719 framebuffer = context->getReadFramebuffer();
720 framebufferHandle = context->getReadFramebufferHandle();
721 }
722 else
723 {
724 framebuffer = context->getDrawFramebuffer();
725 framebufferHandle = context->getDrawFramebufferHandle();
726 }
727
728 if (framebufferHandle == 0 || !framebuffer)
729 {
730 return gl::error(GL_INVALID_OPERATION, false);
731 }
732
733 return true;
734}
735
736bool validES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
737{
738 switch (format)
739 {
740 case GL_RGBA:
741 switch (type)
742 {
743 case GL_UNSIGNED_BYTE:
744 break;
745 case GL_UNSIGNED_INT_2_10_10_10_REV:
746 if (internalFormat != GL_RGB10_A2)
747 {
748 return false;
749 }
750 break;
751 default:
752 return false;
753 }
754 break;
755 case GL_RGBA_INTEGER:
756 switch (type)
757 {
758 case GL_INT:
759 if (!gl::IsSignedIntegerFormat(internalFormat, 3))
760 {
761 return false;
762 }
763 break;
764 case GL_UNSIGNED_INT:
765 if (!gl::IsUnsignedIntegerFormat(internalFormat, 3))
766 {
767 return false;
768 }
769 break;
770 default:
771 return false;
772 }
773 break;
774 case GL_BGRA_EXT:
775 switch (type)
776 {
777 case GL_UNSIGNED_BYTE:
778 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
779 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
780 break;
781 default:
782 return false;
783 }
784 break;
785 default:
786 return false;
787 }
788 return true;
789}
790
791bool validateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
792 const GLenum* attachments)
793{
794 bool defaultFramebuffer = false;
795
796 switch (target)
797 {
798 case GL_DRAW_FRAMEBUFFER:
799 case GL_FRAMEBUFFER:
800 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
801 break;
802 case GL_READ_FRAMEBUFFER:
803 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
804 break;
805 default:
806 return gl::error(GL_INVALID_ENUM, false);
807 }
808
809 for (int i = 0; i < numAttachments; ++i)
810 {
811 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
812 {
813 if (defaultFramebuffer)
814 {
815 return gl::error(GL_INVALID_ENUM, false);
816 }
817
818 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
819 {
820 return gl::error(GL_INVALID_OPERATION, false);
821 }
822 }
823 else
824 {
825 switch (attachments[i])
826 {
827 case GL_DEPTH_ATTACHMENT:
828 case GL_STENCIL_ATTACHMENT:
829 case GL_DEPTH_STENCIL_ATTACHMENT:
830 if (defaultFramebuffer)
831 {
832 return gl::error(GL_INVALID_ENUM, false);
833 }
834 break;
835 case GL_COLOR:
836 case GL_DEPTH:
837 case GL_STENCIL:
838 if (!defaultFramebuffer)
839 {
840 return gl::error(GL_INVALID_ENUM, false);
841 }
842 break;
843 default:
844 return gl::error(GL_INVALID_ENUM, false);
845 }
846 }
847 }
848
849 return true;
850}
851
852}