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