blob: e8df0ace3070862314c8e9e12e131acb36a11e21 [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
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400340 if (border != 0)
341 {
342 return gl::error(GL_INVALID_VALUE, false);
343 }
344
345 if (level > context->getMaximumTextureLevel())
346 {
347 return gl::error(GL_INVALID_VALUE, false);
348 }
349
350 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
351
352 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
353 {
354 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
355 }
356
357 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
358 {
359 return gl::error(GL_INVALID_OPERATION, false);
360 }
361
362 gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
363 GLenum colorbufferInternalFormat = source->getInternalFormat();
364 gl::Texture *texture = NULL;
365 GLenum textureInternalFormat = GL_NONE;
366 bool textureCompressed = false;
367 bool textureIsDepth = false;
368 GLint textureLevelWidth = 0;
369 GLint textureLevelHeight = 0;
370 GLint textureLevelDepth = 0;
371 switch (target)
372 {
373 case GL_TEXTURE_2D:
374 {
375 gl::Texture2D *texture2d = context->getTexture2D();
376 if (texture2d)
377 {
378 textureInternalFormat = texture2d->getInternalFormat(level);
379 textureCompressed = texture2d->isCompressed(level);
380 textureIsDepth = texture2d->isDepth(level);
381 textureLevelWidth = texture2d->getWidth(level);
382 textureLevelHeight = texture2d->getHeight(level);
383 textureLevelDepth = 1;
384 texture = texture2d;
385 }
386 }
387 break;
388
389 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
390 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
391 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
392 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
393 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
394 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
395 {
396 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
397 if (textureCube)
398 {
399 textureInternalFormat = textureCube->getInternalFormat(target, level);
400 textureCompressed = textureCube->isCompressed(target, level);
401 textureIsDepth = false;
402 textureLevelWidth = textureCube->getWidth(target, level);
403 textureLevelHeight = textureCube->getHeight(target, level);
404 textureLevelDepth = 1;
405 texture = textureCube;
406 }
407 }
408 break;
409
410 case GL_TEXTURE_2D_ARRAY:
411 {
412 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
413 if (texture2dArray)
414 {
415 textureInternalFormat = texture2dArray->getInternalFormat(level);
416 textureCompressed = texture2dArray->isCompressed(level);
417 textureIsDepth = texture2dArray->isDepth(level);
418 textureLevelWidth = texture2dArray->getWidth(level);
419 textureLevelHeight = texture2dArray->getHeight(level);
420 textureLevelDepth = texture2dArray->getDepth(level);
421 texture = texture2dArray;
422 }
423 }
424 break;
425
426 case GL_TEXTURE_3D:
427 {
428 gl::Texture3D *texture3d = context->getTexture3D();
429 if (texture3d)
430 {
431 textureInternalFormat = texture3d->getInternalFormat(level);
432 textureCompressed = texture3d->isCompressed(level);
433 textureIsDepth = texture3d->isDepth(level);
434 textureLevelWidth = texture3d->getWidth(level);
435 textureLevelHeight = texture3d->getHeight(level);
436 textureLevelDepth = texture3d->getDepth(level);
437 texture = texture3d;
438 }
439 }
440 break;
441
442 default:
443 return gl::error(GL_INVALID_ENUM, false);
444 }
445
446 if (!texture)
447 {
448 return gl::error(GL_INVALID_OPERATION, false);
449 }
450
451 if (texture->isImmutable() && !isSubImage)
452 {
453 return gl::error(GL_INVALID_OPERATION, false);
454 }
455
456 if (textureIsDepth)
457 {
458 return gl::error(GL_INVALID_OPERATION, false);
459 }
460
461 if (textureCompressed)
462 {
463 if ((width % 4 != 0 && width != textureLevelWidth) ||
464 (height % 4 != 0 && height != textureLevelHeight))
465 {
466 return gl::error(GL_INVALID_OPERATION, false);
467 }
468 }
469
470 if (isSubImage)
471 {
472 if (xoffset + width > textureLevelWidth ||
473 yoffset + height > textureLevelHeight ||
474 zoffset >= textureLevelDepth)
475 {
476 return gl::error(GL_INVALID_VALUE, false);
477 }
478
479 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
480 context->getClientVersion()))
481 {
482 return gl::error(GL_INVALID_OPERATION, false);
483 }
484 }
485
Geoff Lang784a8fd2013-09-24 12:33:16 -0400486 // If width or height is zero, it is a no-op. Return false without setting an error.
487 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488}
489
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400490bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400491 GLsizei width, GLsizei height, GLsizei depth)
492{
493 if (width < 1 || height < 1 || depth < 1 || levels < 1)
494 {
495 return gl::error(GL_INVALID_VALUE, false);
496 }
497
498 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
499 {
500 return gl::error(GL_INVALID_OPERATION, false);
501 }
502
503 gl::Texture *texture = NULL;
504 switch (target)
505 {
506 case GL_TEXTURE_2D:
507 {
508 texture = context->getTexture2D();
509
510 if (width > (context->getMaximum2DTextureDimension()) ||
511 height > (context->getMaximum2DTextureDimension()))
512 {
513 return gl::error(GL_INVALID_VALUE, false);
514 }
515 }
516 break;
517
518 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
519 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
520 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
521 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
522 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
523 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
524 {
525 texture = context->getTextureCubeMap();
526
527 if (width != height)
528 {
529 return gl::error(GL_INVALID_VALUE, false);
530 }
531
532 if (width > (context->getMaximumCubeTextureDimension()))
533 {
534 return gl::error(GL_INVALID_VALUE, false);
535 }
536 }
537 break;
538
539 case GL_TEXTURE_3D:
540 {
541 texture = context->getTexture3D();
542
543 if (width > (context->getMaximum3DTextureDimension()) ||
544 height > (context->getMaximum3DTextureDimension()) ||
545 depth > (context->getMaximum3DTextureDimension()))
546 {
547 return gl::error(GL_INVALID_VALUE, false);
548 }
549 }
550 break;
551
552 case GL_TEXTURE_2D_ARRAY:
553 {
554 texture = context->getTexture2DArray();
555
556 if (width > (context->getMaximum2DTextureDimension()) ||
557 height > (context->getMaximum2DTextureDimension()) ||
558 depth > (context->getMaximum2DArrayTextureLayers()))
559 {
560 return gl::error(GL_INVALID_VALUE, false);
561 }
562 }
563 break;
564
565 default:
566 return gl::error(GL_INVALID_ENUM, false);
567 }
568
569 if (!texture || texture->id() == 0)
570 {
571 return gl::error(GL_INVALID_OPERATION, false);
572 }
573
574 if (texture->isImmutable())
575 {
576 return gl::error(GL_INVALID_OPERATION, false);
577 }
578
579 if (!gl::IsValidInternalFormat(internalformat, context))
580 {
581 return gl::error(GL_INVALID_ENUM, false);
582 }
583
584 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
585 {
586 return gl::error(GL_INVALID_ENUM, false);
587 }
588
589 return true;
590}
591
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400592bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400593 GLenum textarget, GLuint texture, GLint level, GLint layer,
594 bool layerCall)
595{
596 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
597 {
598 return gl::error(GL_INVALID_ENUM, false);
599 }
600
601 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
602 {
603 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
604 if (colorAttachment >= context->getMaximumRenderTargets())
605 {
606 return gl::error(GL_INVALID_VALUE, false);
607 }
608 }
609 else
610 {
611 switch (attachment)
612 {
613 case GL_DEPTH_ATTACHMENT:
614 case GL_STENCIL_ATTACHMENT:
615 case GL_DEPTH_STENCIL_ATTACHMENT:
616 break;
617 default:
618 return gl::error(GL_INVALID_ENUM, false);
619 }
620 }
621
622 if (texture != 0)
623 {
624 gl::Texture *tex = context->getTexture(texture);
625
626 if (tex == NULL)
627 {
628 return gl::error(GL_INVALID_OPERATION, false);
629 }
630
631 if (level < 0)
632 {
633 return gl::error(GL_INVALID_VALUE, false);
634 }
635
636 if (layer < 0)
637 {
638 return gl::error(GL_INVALID_VALUE, false);
639 }
640
641 if (!layerCall)
642 {
643 switch (textarget)
644 {
645 case GL_TEXTURE_2D:
646 {
647 if (level > gl::log2(context->getMaximum2DTextureDimension()))
648 {
649 return gl::error(GL_INVALID_VALUE, false);
650 }
651 if (tex->getTarget() != GL_TEXTURE_2D)
652 {
653 return gl::error(GL_INVALID_OPERATION, false);
654 }
655 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
656 if (tex2d->isCompressed(level))
657 {
658 return gl::error(GL_INVALID_OPERATION, false);
659 }
660 break;
661 }
662
663 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
664 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
665 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
666 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
667 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
668 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
669 {
670 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
671 {
672 return gl::error(GL_INVALID_VALUE, false);
673 }
674 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
675 {
676 return gl::error(GL_INVALID_OPERATION, false);
677 }
678 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
679 if (texcube->isCompressed(textarget, level))
680 {
681 return gl::error(GL_INVALID_OPERATION, false);
682 }
683 break;
684 }
685
686 default:
687 return gl::error(GL_INVALID_ENUM, false);
688 }
689 }
690 else
691 {
692 switch (tex->getTarget())
693 {
694 case GL_TEXTURE_2D_ARRAY:
695 {
696 if (level > gl::log2(context->getMaximum2DTextureDimension()))
697 {
698 return gl::error(GL_INVALID_VALUE, false);
699 }
700
701 if (layer >= context->getMaximum2DArrayTextureLayers())
702 {
703 return gl::error(GL_INVALID_VALUE, false);
704 }
705
706 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
707 if (texArray->isCompressed(level))
708 {
709 return gl::error(GL_INVALID_OPERATION, false);
710 }
711
712 break;
713 }
714
715 case GL_TEXTURE_3D:
716 {
717 if (level > gl::log2(context->getMaximum3DTextureDimension()))
718 {
719 return gl::error(GL_INVALID_VALUE, false);
720 }
721
722 if (layer >= context->getMaximum3DTextureDimension())
723 {
724 return gl::error(GL_INVALID_VALUE, false);
725 }
726
727 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
728 if (tex3d->isCompressed(level))
729 {
730 return gl::error(GL_INVALID_OPERATION, false);
731 }
732
733 break;
734 }
735
736 default:
737 return gl::error(GL_INVALID_OPERATION, false);
738 }
739 }
740 }
741
742 gl::Framebuffer *framebuffer = NULL;
743 GLuint framebufferHandle = 0;
744 if (target == GL_READ_FRAMEBUFFER)
745 {
746 framebuffer = context->getReadFramebuffer();
747 framebufferHandle = context->getReadFramebufferHandle();
748 }
749 else
750 {
751 framebuffer = context->getDrawFramebuffer();
752 framebufferHandle = context->getDrawFramebufferHandle();
753 }
754
755 if (framebufferHandle == 0 || !framebuffer)
756 {
757 return gl::error(GL_INVALID_OPERATION, false);
758 }
759
760 return true;
761}
762
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400763bool ValidES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764{
765 switch (format)
766 {
767 case GL_RGBA:
768 switch (type)
769 {
770 case GL_UNSIGNED_BYTE:
771 break;
772 case GL_UNSIGNED_INT_2_10_10_10_REV:
773 if (internalFormat != GL_RGB10_A2)
774 {
775 return false;
776 }
777 break;
778 default:
779 return false;
780 }
781 break;
782 case GL_RGBA_INTEGER:
783 switch (type)
784 {
785 case GL_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400786 if (gl::GetComponentType(internalFormat, 3) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 {
788 return false;
789 }
790 break;
791 case GL_UNSIGNED_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400792 if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793 {
794 return false;
795 }
796 break;
797 default:
798 return false;
799 }
800 break;
801 case GL_BGRA_EXT:
802 switch (type)
803 {
804 case GL_UNSIGNED_BYTE:
805 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
806 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
807 break;
808 default:
809 return false;
810 }
811 break;
812 default:
813 return false;
814 }
815 return true;
816}
817
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400818bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400819 const GLenum* attachments)
820{
821 bool defaultFramebuffer = false;
822
823 switch (target)
824 {
825 case GL_DRAW_FRAMEBUFFER:
826 case GL_FRAMEBUFFER:
827 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
828 break;
829 case GL_READ_FRAMEBUFFER:
830 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
831 break;
832 default:
833 return gl::error(GL_INVALID_ENUM, false);
834 }
835
836 for (int i = 0; i < numAttachments; ++i)
837 {
838 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
839 {
840 if (defaultFramebuffer)
841 {
842 return gl::error(GL_INVALID_ENUM, false);
843 }
844
845 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
846 {
847 return gl::error(GL_INVALID_OPERATION, false);
848 }
849 }
850 else
851 {
852 switch (attachments[i])
853 {
854 case GL_DEPTH_ATTACHMENT:
855 case GL_STENCIL_ATTACHMENT:
856 case GL_DEPTH_STENCIL_ATTACHMENT:
857 if (defaultFramebuffer)
858 {
859 return gl::error(GL_INVALID_ENUM, false);
860 }
861 break;
862 case GL_COLOR:
863 case GL_DEPTH:
864 case GL_STENCIL:
865 if (!defaultFramebuffer)
866 {
867 return gl::error(GL_INVALID_ENUM, false);
868 }
869 break;
870 default:
871 return gl::error(GL_INVALID_ENUM, false);
872 }
873 }
874 }
875
876 return true;
877}
878
879}