blob: 0e9d48d04d0ba05d9774315dc3102a15678505f8 [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
Geoff Lang34dbb6f2013-08-05 15:05:47 -040063bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -040064 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillefb2a6f2013-09-24 10:22:42 -040065 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Geoff Lange8ebe7f2013-08-05 15:03:13 -040066{
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
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400249 if (isCompressed)
250 {
251 if ((width % 4 != 0 && width != textureLevelWidth) ||
252 (height % 4 != 0 && height != textureLevelHeight))
253 {
254 return gl::error(GL_INVALID_OPERATION, false);
255 }
256 }
257
258 if (width == 0 || height == 0 || depth == 0)
259 {
260 return false;
261 }
262
263 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
264 {
265 return gl::error(GL_INVALID_VALUE, false);
266 }
267
268 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
269 std::numeric_limits<GLsizei>::max() - yoffset < height ||
270 std::numeric_limits<GLsizei>::max() - zoffset < depth)
271 {
272 return gl::error(GL_INVALID_VALUE, false);
273 }
274
275 if (xoffset + width > textureLevelWidth ||
276 yoffset + height > textureLevelHeight ||
277 zoffset + depth > textureLevelDepth)
278 {
279 return gl::error(GL_INVALID_VALUE, false);
280 }
281 }
282
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400283 // Check for pixel unpack buffer related API errors
284 gl::Buffer *pixelUnpackBuffer = context->getPixelUnpackBuffer();
285 if (pixelUnpackBuffer != NULL)
286 {
287 // ...the data would be unpacked from the buffer object such that the memory reads required
288 // would exceed the data store size.
289 size_t widthSize = static_cast<size_t>(width);
290 size_t heightSize = static_cast<size_t>(height);
291 size_t depthSize = static_cast<size_t>(depth);
292 size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(actualInternalFormat, context->getClientVersion()));
293
294 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
295 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
296 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
297 {
298 // Overflow past the end of the buffer
299 return gl::error(GL_INVALID_OPERATION, false);
300 }
301
302 size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes;
303 size_t offset = reinterpret_cast<size_t>(pixels);
304
305 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->size())))
306 {
307 // Overflow past the end of the buffer
308 return gl::error(GL_INVALID_OPERATION, false);
309 }
310
311 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
312 // indicated by type.
313 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type));
314
315 if ((offset % dataBytesPerPixel) != 0)
316 {
317 return gl::error(GL_INVALID_OPERATION, false);
318 }
319
320 // TODO: ...the buffer object's data store is currently mapped.
321 }
322
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400323 return true;
324}
325
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400326bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400327 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
328 GLsizei width, GLsizei height, GLint border)
329{
330 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
331 {
332 return gl::error(GL_INVALID_VALUE, false);
333 }
334
335 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
336 {
337 return gl::error(GL_INVALID_VALUE, false);
338 }
339
340 if (width == 0 || height == 0)
341 {
342 return false;
343 }
344
345 if (border != 0)
346 {
347 return gl::error(GL_INVALID_VALUE, false);
348 }
349
350 if (level > context->getMaximumTextureLevel())
351 {
352 return gl::error(GL_INVALID_VALUE, false);
353 }
354
355 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
356
357 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
358 {
359 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
360 }
361
362 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
363 {
364 return gl::error(GL_INVALID_OPERATION, false);
365 }
366
367 gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
368 GLenum colorbufferInternalFormat = source->getInternalFormat();
369 gl::Texture *texture = NULL;
370 GLenum textureInternalFormat = GL_NONE;
371 bool textureCompressed = false;
372 bool textureIsDepth = false;
373 GLint textureLevelWidth = 0;
374 GLint textureLevelHeight = 0;
375 GLint textureLevelDepth = 0;
376 switch (target)
377 {
378 case GL_TEXTURE_2D:
379 {
380 gl::Texture2D *texture2d = context->getTexture2D();
381 if (texture2d)
382 {
383 textureInternalFormat = texture2d->getInternalFormat(level);
384 textureCompressed = texture2d->isCompressed(level);
385 textureIsDepth = texture2d->isDepth(level);
386 textureLevelWidth = texture2d->getWidth(level);
387 textureLevelHeight = texture2d->getHeight(level);
388 textureLevelDepth = 1;
389 texture = texture2d;
390 }
391 }
392 break;
393
394 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
395 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
396 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
397 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
398 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
399 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
400 {
401 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
402 if (textureCube)
403 {
404 textureInternalFormat = textureCube->getInternalFormat(target, level);
405 textureCompressed = textureCube->isCompressed(target, level);
406 textureIsDepth = false;
407 textureLevelWidth = textureCube->getWidth(target, level);
408 textureLevelHeight = textureCube->getHeight(target, level);
409 textureLevelDepth = 1;
410 texture = textureCube;
411 }
412 }
413 break;
414
415 case GL_TEXTURE_2D_ARRAY:
416 {
417 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
418 if (texture2dArray)
419 {
420 textureInternalFormat = texture2dArray->getInternalFormat(level);
421 textureCompressed = texture2dArray->isCompressed(level);
422 textureIsDepth = texture2dArray->isDepth(level);
423 textureLevelWidth = texture2dArray->getWidth(level);
424 textureLevelHeight = texture2dArray->getHeight(level);
425 textureLevelDepth = texture2dArray->getDepth(level);
426 texture = texture2dArray;
427 }
428 }
429 break;
430
431 case GL_TEXTURE_3D:
432 {
433 gl::Texture3D *texture3d = context->getTexture3D();
434 if (texture3d)
435 {
436 textureInternalFormat = texture3d->getInternalFormat(level);
437 textureCompressed = texture3d->isCompressed(level);
438 textureIsDepth = texture3d->isDepth(level);
439 textureLevelWidth = texture3d->getWidth(level);
440 textureLevelHeight = texture3d->getHeight(level);
441 textureLevelDepth = texture3d->getDepth(level);
442 texture = texture3d;
443 }
444 }
445 break;
446
447 default:
448 return gl::error(GL_INVALID_ENUM, false);
449 }
450
451 if (!texture)
452 {
453 return gl::error(GL_INVALID_OPERATION, false);
454 }
455
456 if (texture->isImmutable() && !isSubImage)
457 {
458 return gl::error(GL_INVALID_OPERATION, false);
459 }
460
461 if (textureIsDepth)
462 {
463 return gl::error(GL_INVALID_OPERATION, false);
464 }
465
466 if (textureCompressed)
467 {
468 if ((width % 4 != 0 && width != textureLevelWidth) ||
469 (height % 4 != 0 && height != textureLevelHeight))
470 {
471 return gl::error(GL_INVALID_OPERATION, false);
472 }
473 }
474
475 if (isSubImage)
476 {
477 if (xoffset + width > textureLevelWidth ||
478 yoffset + height > textureLevelHeight ||
479 zoffset >= textureLevelDepth)
480 {
481 return gl::error(GL_INVALID_VALUE, false);
482 }
483
484 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
485 context->getClientVersion()))
486 {
487 return gl::error(GL_INVALID_OPERATION, false);
488 }
489 }
490
491 return true;
492}
493
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400494bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400495 GLsizei width, GLsizei height, GLsizei depth)
496{
497 if (width < 1 || height < 1 || depth < 1 || levels < 1)
498 {
499 return gl::error(GL_INVALID_VALUE, false);
500 }
501
502 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
503 {
504 return gl::error(GL_INVALID_OPERATION, false);
505 }
506
507 gl::Texture *texture = NULL;
508 switch (target)
509 {
510 case GL_TEXTURE_2D:
511 {
512 texture = context->getTexture2D();
513
514 if (width > (context->getMaximum2DTextureDimension()) ||
515 height > (context->getMaximum2DTextureDimension()))
516 {
517 return gl::error(GL_INVALID_VALUE, false);
518 }
519 }
520 break;
521
522 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
523 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
524 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
525 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
526 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
527 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
528 {
529 texture = context->getTextureCubeMap();
530
531 if (width != height)
532 {
533 return gl::error(GL_INVALID_VALUE, false);
534 }
535
536 if (width > (context->getMaximumCubeTextureDimension()))
537 {
538 return gl::error(GL_INVALID_VALUE, false);
539 }
540 }
541 break;
542
543 case GL_TEXTURE_3D:
544 {
545 texture = context->getTexture3D();
546
547 if (width > (context->getMaximum3DTextureDimension()) ||
548 height > (context->getMaximum3DTextureDimension()) ||
549 depth > (context->getMaximum3DTextureDimension()))
550 {
551 return gl::error(GL_INVALID_VALUE, false);
552 }
553 }
554 break;
555
556 case GL_TEXTURE_2D_ARRAY:
557 {
558 texture = context->getTexture2DArray();
559
560 if (width > (context->getMaximum2DTextureDimension()) ||
561 height > (context->getMaximum2DTextureDimension()) ||
562 depth > (context->getMaximum2DArrayTextureLayers()))
563 {
564 return gl::error(GL_INVALID_VALUE, false);
565 }
566 }
567 break;
568
569 default:
570 return gl::error(GL_INVALID_ENUM, false);
571 }
572
573 if (!texture || texture->id() == 0)
574 {
575 return gl::error(GL_INVALID_OPERATION, false);
576 }
577
578 if (texture->isImmutable())
579 {
580 return gl::error(GL_INVALID_OPERATION, false);
581 }
582
583 if (!gl::IsValidInternalFormat(internalformat, context))
584 {
585 return gl::error(GL_INVALID_ENUM, false);
586 }
587
588 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
589 {
590 return gl::error(GL_INVALID_ENUM, false);
591 }
592
593 return true;
594}
595
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400596bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400597 GLenum textarget, GLuint texture, GLint level, GLint layer,
598 bool layerCall)
599{
600 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
601 {
602 return gl::error(GL_INVALID_ENUM, false);
603 }
604
605 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
606 {
607 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
608 if (colorAttachment >= context->getMaximumRenderTargets())
609 {
610 return gl::error(GL_INVALID_VALUE, false);
611 }
612 }
613 else
614 {
615 switch (attachment)
616 {
617 case GL_DEPTH_ATTACHMENT:
618 case GL_STENCIL_ATTACHMENT:
619 case GL_DEPTH_STENCIL_ATTACHMENT:
620 break;
621 default:
622 return gl::error(GL_INVALID_ENUM, false);
623 }
624 }
625
626 if (texture != 0)
627 {
628 gl::Texture *tex = context->getTexture(texture);
629
630 if (tex == NULL)
631 {
632 return gl::error(GL_INVALID_OPERATION, false);
633 }
634
635 if (level < 0)
636 {
637 return gl::error(GL_INVALID_VALUE, false);
638 }
639
640 if (layer < 0)
641 {
642 return gl::error(GL_INVALID_VALUE, false);
643 }
644
645 if (!layerCall)
646 {
647 switch (textarget)
648 {
649 case GL_TEXTURE_2D:
650 {
651 if (level > gl::log2(context->getMaximum2DTextureDimension()))
652 {
653 return gl::error(GL_INVALID_VALUE, false);
654 }
655 if (tex->getTarget() != GL_TEXTURE_2D)
656 {
657 return gl::error(GL_INVALID_OPERATION, false);
658 }
659 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
660 if (tex2d->isCompressed(level))
661 {
662 return gl::error(GL_INVALID_OPERATION, false);
663 }
664 break;
665 }
666
667 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
668 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
669 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
670 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
671 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
672 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
673 {
674 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
675 {
676 return gl::error(GL_INVALID_VALUE, false);
677 }
678 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
679 {
680 return gl::error(GL_INVALID_OPERATION, false);
681 }
682 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
683 if (texcube->isCompressed(textarget, level))
684 {
685 return gl::error(GL_INVALID_OPERATION, false);
686 }
687 break;
688 }
689
690 default:
691 return gl::error(GL_INVALID_ENUM, false);
692 }
693 }
694 else
695 {
696 switch (tex->getTarget())
697 {
698 case GL_TEXTURE_2D_ARRAY:
699 {
700 if (level > gl::log2(context->getMaximum2DTextureDimension()))
701 {
702 return gl::error(GL_INVALID_VALUE, false);
703 }
704
705 if (layer >= context->getMaximum2DArrayTextureLayers())
706 {
707 return gl::error(GL_INVALID_VALUE, false);
708 }
709
710 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
711 if (texArray->isCompressed(level))
712 {
713 return gl::error(GL_INVALID_OPERATION, false);
714 }
715
716 break;
717 }
718
719 case GL_TEXTURE_3D:
720 {
721 if (level > gl::log2(context->getMaximum3DTextureDimension()))
722 {
723 return gl::error(GL_INVALID_VALUE, false);
724 }
725
726 if (layer >= context->getMaximum3DTextureDimension())
727 {
728 return gl::error(GL_INVALID_VALUE, false);
729 }
730
731 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
732 if (tex3d->isCompressed(level))
733 {
734 return gl::error(GL_INVALID_OPERATION, false);
735 }
736
737 break;
738 }
739
740 default:
741 return gl::error(GL_INVALID_OPERATION, false);
742 }
743 }
744 }
745
746 gl::Framebuffer *framebuffer = NULL;
747 GLuint framebufferHandle = 0;
748 if (target == GL_READ_FRAMEBUFFER)
749 {
750 framebuffer = context->getReadFramebuffer();
751 framebufferHandle = context->getReadFramebufferHandle();
752 }
753 else
754 {
755 framebuffer = context->getDrawFramebuffer();
756 framebufferHandle = context->getDrawFramebufferHandle();
757 }
758
759 if (framebufferHandle == 0 || !framebuffer)
760 {
761 return gl::error(GL_INVALID_OPERATION, false);
762 }
763
764 return true;
765}
766
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400767bool ValidES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768{
769 switch (format)
770 {
771 case GL_RGBA:
772 switch (type)
773 {
774 case GL_UNSIGNED_BYTE:
775 break;
776 case GL_UNSIGNED_INT_2_10_10_10_REV:
777 if (internalFormat != GL_RGB10_A2)
778 {
779 return false;
780 }
781 break;
782 default:
783 return false;
784 }
785 break;
786 case GL_RGBA_INTEGER:
787 switch (type)
788 {
789 case GL_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400790 if (gl::GetComponentType(internalFormat, 3) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 {
792 return false;
793 }
794 break;
795 case GL_UNSIGNED_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400796 if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 {
798 return false;
799 }
800 break;
801 default:
802 return false;
803 }
804 break;
805 case GL_BGRA_EXT:
806 switch (type)
807 {
808 case GL_UNSIGNED_BYTE:
809 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
810 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
811 break;
812 default:
813 return false;
814 }
815 break;
816 default:
817 return false;
818 }
819 return true;
820}
821
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400822bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400823 const GLenum* attachments)
824{
825 bool defaultFramebuffer = false;
826
827 switch (target)
828 {
829 case GL_DRAW_FRAMEBUFFER:
830 case GL_FRAMEBUFFER:
831 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
832 break;
833 case GL_READ_FRAMEBUFFER:
834 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
835 break;
836 default:
837 return gl::error(GL_INVALID_ENUM, false);
838 }
839
840 for (int i = 0; i < numAttachments; ++i)
841 {
842 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
843 {
844 if (defaultFramebuffer)
845 {
846 return gl::error(GL_INVALID_ENUM, false);
847 }
848
849 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
850 {
851 return gl::error(GL_INVALID_OPERATION, false);
852 }
853 }
854 else
855 {
856 switch (attachments[i])
857 {
858 case GL_DEPTH_ATTACHMENT:
859 case GL_STENCIL_ATTACHMENT:
860 case GL_DEPTH_STENCIL_ATTACHMENT:
861 if (defaultFramebuffer)
862 {
863 return gl::error(GL_INVALID_ENUM, false);
864 }
865 break;
866 case GL_COLOR:
867 case GL_DEPTH:
868 case GL_STENCIL:
869 if (!defaultFramebuffer)
870 {
871 return gl::error(GL_INVALID_ENUM, false);
872 }
873 break;
874 default:
875 return gl::error(GL_INVALID_ENUM, false);
876 }
877 }
878 }
879
880 return true;
881}
882
883}