blob: 09bac01deb29aa77030a12549e7666fd88978f4b [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// validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters
9
10#include "libGLESv2/validationES2.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#include "common/utilities.h"
20
21namespace gl
22{
23
24static bool validImageSize(const gl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth)
25{
26 if (level < 0 || width < 0 || height < 0 || depth < 0)
27 {
28 return false;
29 }
30
31 if (context->supportsNonPower2Texture())
32 {
33 return true;
34 }
35
36 if (level == 0)
37 {
38 return true;
39 }
40
41 if (gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth))
42 {
43 return true;
44 }
45
46 return false;
47}
48
49static bool validCompressedImageSize(GLsizei width, GLsizei height)
50{
51 if (width != 1 && width != 2 && width % 4 != 0)
52 {
53 return false;
54 }
55
56 if (height != 1 && height != 2 && height % 4 != 0)
57 {
58 return false;
59 }
60
61 return true;
62}
63
64static bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height,
65 GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type,
66 gl::Texture2D *texture)
67{
68 if (!texture)
69 {
70 return gl::error(GL_INVALID_OPERATION, false);
71 }
72
73 if (compressed != texture->isCompressed(level))
74 {
75 return gl::error(GL_INVALID_OPERATION, false);
76 }
77
78 if (format != GL_NONE)
79 {
80 GLenum internalformat = gl::GetSizedInternalFormat(format, type, 2);
81 if (internalformat != texture->getInternalFormat(level))
82 {
83 return gl::error(GL_INVALID_OPERATION, false);
84 }
85 }
86
87 if (compressed)
88 {
89 if ((width % 4 != 0 && width != texture->getWidth(0)) ||
90 (height % 4 != 0 && height != texture->getHeight(0)))
91 {
92 return gl::error(GL_INVALID_OPERATION, false);
93 }
94 }
95
96 if (xoffset + width > texture->getWidth(level) ||
97 yoffset + height > texture->getHeight(level))
98 {
99 return gl::error(GL_INVALID_VALUE, false);
100 }
101
102 return true;
103}
104
105static bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height,
106 GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type,
107 gl::TextureCubeMap *texture)
108{
109 if (!texture)
110 {
111 return gl::error(GL_INVALID_OPERATION, false);
112 }
113
114 if (compressed != texture->isCompressed(target, level))
115 {
116 return gl::error(GL_INVALID_OPERATION, false);
117 }
118
119 if (format != GL_NONE)
120 {
121 GLenum internalformat = gl::GetSizedInternalFormat(format, type, 2);
122 if (internalformat != texture->getInternalFormat(target, level))
123 {
124 return gl::error(GL_INVALID_OPERATION, false);
125 }
126 }
127
128 if (compressed)
129 {
130 if ((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
131 (height % 4 != 0 && height != texture->getHeight(target, 0)))
132 {
133 return gl::error(GL_INVALID_OPERATION, false);
134 }
135 }
136
137 if (xoffset + width > texture->getWidth(target, level) ||
138 yoffset + height > texture->getHeight(target, level))
139 {
140 return gl::error(GL_INVALID_VALUE, false);
141 }
142
143 return true;
144}
145
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400146bool ValidateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400147 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
148 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
149{
150 if (!validImageSize(context, level, width, height, 1))
151 {
152 return gl::error(GL_INVALID_VALUE, false);
153 }
154
155 if (isCompressed && !validCompressedImageSize(width, height))
156 {
157 return gl::error(GL_INVALID_OPERATION, false);
158 }
159
160 if (level < 0 || xoffset < 0 ||
161 std::numeric_limits<GLsizei>::max() - xoffset < width ||
162 std::numeric_limits<GLsizei>::max() - yoffset < height)
163 {
164 return gl::error(GL_INVALID_VALUE, false);
165 }
166
167 if (!isSubImage && !isCompressed && internalformat != GLint(format))
168 {
169 return gl::error(GL_INVALID_OPERATION, false);
170 }
171
172 gl::Texture *texture = NULL;
173 bool textureCompressed = false;
174 GLenum textureInternalFormat = GL_NONE;
175 GLint textureLevelWidth = 0;
176 GLint textureLevelHeight = 0;
177 switch (target)
178 {
179 case GL_TEXTURE_2D:
180 {
181 if (width > (context->getMaximum2DTextureDimension() >> level) ||
182 height > (context->getMaximum2DTextureDimension() >> level))
183 {
184 return gl::error(GL_INVALID_VALUE, false);
185 }
186
187 gl::Texture2D *tex2d = context->getTexture2D();
188 if (tex2d)
189 {
190 textureCompressed = tex2d->isCompressed(level);
191 textureInternalFormat = tex2d->getInternalFormat(level);
192 textureLevelWidth = tex2d->getWidth(level);
193 textureLevelHeight = tex2d->getHeight(level);
194 texture = tex2d;
195 }
196
197 if (isSubImage && !validateSubImageParams2D(isCompressed, width, height, xoffset, yoffset,
198 level, format, type, tex2d))
199 {
200 return false;
201 }
202
203 texture = tex2d;
204 }
205 break;
206
207 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
208 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
209 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
210 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
211 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
212 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
213 {
214 if (!isSubImage && width != height)
215 {
216 return gl::error(GL_INVALID_VALUE, false);
217 }
218
219 if (width > (context->getMaximumCubeTextureDimension() >> level) ||
220 height > (context->getMaximumCubeTextureDimension() >> level))
221 {
222 return gl::error(GL_INVALID_VALUE, false);
223 }
224
225 gl::TextureCubeMap *texCube = context->getTextureCubeMap();
226 if (texCube)
227 {
228 textureCompressed = texCube->isCompressed(target, level);
229 textureInternalFormat = texCube->getInternalFormat(target, level);
230 textureLevelWidth = texCube->getWidth(target, level);
231 textureLevelHeight = texCube->getHeight(target, level);
232 texture = texCube;
233 }
234
235 if (isSubImage && !validateSubImageParamsCube(isCompressed, width, height, xoffset, yoffset,
236 target, level, format, type, texCube))
237 {
238 return false;
239 }
240 }
241 break;
242
243 default:
244 return gl::error(GL_INVALID_ENUM, false);
245 }
246
247 if (!texture)
248 {
249 return gl::error(GL_INVALID_OPERATION, false);
250 }
251
252 if (!isSubImage && texture->isImmutable())
253 {
254 return gl::error(GL_INVALID_OPERATION, false);
255 }
256
257 // Verify zero border
258 if (border != 0)
259 {
260 return gl::error(GL_INVALID_VALUE, false);
261 }
262
263 // Verify texture is not requesting more mip levels than are available.
264 if (level > context->getMaximumTextureLevel())
265 {
266 return gl::error(GL_INVALID_VALUE, false);
267 }
268
269 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
270 if (isCompressed)
271 {
272 switch (actualInternalFormat)
273 {
274 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
275 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
276 if (!context->supportsDXT1Textures())
277 {
278 return gl::error(GL_INVALID_ENUM, false);
279 }
280 break;
281 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
282 if (!context->supportsDXT3Textures())
283 {
284 return gl::error(GL_INVALID_ENUM, false);
285 }
286 break;
287 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
288 if (!context->supportsDXT5Textures())
289 {
290 return gl::error(GL_INVALID_ENUM, false);
291 }
292 break;
293 default:
294 return gl::error(GL_INVALID_ENUM, false);
295 }
296 }
297 else
298 {
299 // validate <type> by itself (used as secondary key below)
300 switch (type)
301 {
302 case GL_UNSIGNED_BYTE:
303 case GL_UNSIGNED_SHORT_5_6_5:
304 case GL_UNSIGNED_SHORT_4_4_4_4:
305 case GL_UNSIGNED_SHORT_5_5_5_1:
306 case GL_UNSIGNED_SHORT:
307 case GL_UNSIGNED_INT:
308 case GL_UNSIGNED_INT_24_8_OES:
309 case GL_HALF_FLOAT_OES:
310 case GL_FLOAT:
311 break;
312 default:
313 return gl::error(GL_INVALID_ENUM, false);
314 }
315
316 // validate <format> + <type> combinations
317 // - invalid <format> -> sets INVALID_ENUM
318 // - invalid <format>+<type> combination -> sets INVALID_OPERATION
319 switch (format)
320 {
321 case GL_ALPHA:
322 case GL_LUMINANCE:
323 case GL_LUMINANCE_ALPHA:
324 switch (type)
325 {
326 case GL_UNSIGNED_BYTE:
327 case GL_FLOAT:
328 case GL_HALF_FLOAT_OES:
329 break;
330 default:
331 return gl::error(GL_INVALID_OPERATION, false);
332 }
333 break;
334 case GL_RGB:
335 switch (type)
336 {
337 case GL_UNSIGNED_BYTE:
338 case GL_UNSIGNED_SHORT_5_6_5:
339 case GL_FLOAT:
340 case GL_HALF_FLOAT_OES:
341 break;
342 default:
343 return gl::error(GL_INVALID_OPERATION, false);
344 }
345 break;
346 case GL_RGBA:
347 switch (type)
348 {
349 case GL_UNSIGNED_BYTE:
350 case GL_UNSIGNED_SHORT_4_4_4_4:
351 case GL_UNSIGNED_SHORT_5_5_5_1:
352 case GL_FLOAT:
353 case GL_HALF_FLOAT_OES:
354 break;
355 default:
356 return gl::error(GL_INVALID_OPERATION, false);
357 }
358 break;
359 case GL_BGRA_EXT:
360 switch (type)
361 {
362 case GL_UNSIGNED_BYTE:
363 break;
364 default:
365 return gl::error(GL_INVALID_OPERATION, false);
366 }
367 break;
368 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below
369 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
370 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
371 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
372 break;
373 case GL_DEPTH_COMPONENT:
374 switch (type)
375 {
376 case GL_UNSIGNED_SHORT:
377 case GL_UNSIGNED_INT:
378 break;
379 default:
380 return gl::error(GL_INVALID_OPERATION, false);
381 }
382 break;
383 case GL_DEPTH_STENCIL_OES:
384 switch (type)
385 {
386 case GL_UNSIGNED_INT_24_8_OES:
387 break;
388 default:
389 return gl::error(GL_INVALID_OPERATION, false);
390 }
391 break;
392 default:
393 return gl::error(GL_INVALID_ENUM, false);
394 }
395
396 switch (format)
397 {
398 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
399 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
400 if (context->supportsDXT1Textures())
401 {
402 return gl::error(GL_INVALID_OPERATION, false);
403 }
404 else
405 {
406 return gl::error(GL_INVALID_ENUM, false);
407 }
408 break;
409 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
410 if (context->supportsDXT3Textures())
411 {
412 return gl::error(GL_INVALID_OPERATION, false);
413 }
414 else
415 {
416 return gl::error(GL_INVALID_ENUM, false);
417 }
418 break;
419 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
420 if (context->supportsDXT5Textures())
421 {
422 return gl::error(GL_INVALID_OPERATION, false);
423 }
424 else
425 {
426 return gl::error(GL_INVALID_ENUM, false);
427 }
428 break;
429 case GL_DEPTH_COMPONENT:
430 case GL_DEPTH_STENCIL_OES:
431 if (!context->supportsDepthTextures())
432 {
433 return gl::error(GL_INVALID_VALUE, false);
434 }
435 if (target != GL_TEXTURE_2D)
436 {
437 return gl::error(GL_INVALID_OPERATION, false);
438 }
439 // OES_depth_texture supports loading depth data and multiple levels,
440 // but ANGLE_depth_texture does not
441 if (pixels != NULL || level != 0)
442 {
443 return gl::error(GL_INVALID_OPERATION, false);
444 }
445 break;
446 default:
447 break;
448 }
449
450 if (type == GL_FLOAT)
451 {
452 if (!context->supportsFloat32Textures())
453 {
454 return gl::error(GL_INVALID_ENUM, false);
455 }
456 }
457 else if (type == GL_HALF_FLOAT_OES)
458 {
459 if (!context->supportsFloat16Textures())
460 {
461 return gl::error(GL_INVALID_ENUM, false);
462 }
463 }
464 }
465
466 return true;
467}
468
469
470
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400471bool ValidateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400472 GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
473 GLint border)
474{
475 if (!gl::IsInternalTextureTarget(target, context->getClientVersion()))
476 {
477 return gl::error(GL_INVALID_ENUM, false);
478 }
479
480 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
481 {
482 return gl::error(GL_INVALID_VALUE, false);
483 }
484
485 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
486 {
487 return gl::error(GL_INVALID_VALUE, false);
488 }
489
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400490 // Verify zero border
491 if (border != 0)
492 {
493 return gl::error(GL_INVALID_VALUE, false);
494 }
495
496 // Validate dimensions based on Context limits and validate the texture
497 if (level > context->getMaximumTextureLevel())
498 {
499 return gl::error(GL_INVALID_VALUE, false);
500 }
501
502 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
503
504 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
505 {
506 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
507 }
508
509 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
510 {
511 return gl::error(GL_INVALID_OPERATION, false);
512 }
513
514 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
515 gl::Texture *texture = NULL;
516 GLenum textureFormat = GL_RGBA;
517
518 switch (target)
519 {
520 case GL_TEXTURE_2D:
521 {
522 if (width > (context->getMaximum2DTextureDimension() >> level) ||
523 height > (context->getMaximum2DTextureDimension() >> level))
524 {
525 return gl::error(GL_INVALID_VALUE, false);
526 }
527
528 gl::Texture2D *tex2d = context->getTexture2D();
529 if (tex2d)
530 {
531 if (isSubImage && !validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
532 {
533 return false; // error already registered by validateSubImageParams
534 }
535 texture = tex2d;
536 textureFormat = gl::GetFormat(tex2d->getInternalFormat(level), context->getClientVersion());
537 }
538 }
539 break;
540
541 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
542 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
543 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
544 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
545 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
546 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
547 {
548 if (!isSubImage && width != height)
549 {
550 return gl::error(GL_INVALID_VALUE, false);
551 }
552
553 if (width > (context->getMaximumCubeTextureDimension() >> level) ||
554 height > (context->getMaximumCubeTextureDimension() >> level))
555 {
556 return gl::error(GL_INVALID_VALUE, false);
557 }
558
559 gl::TextureCubeMap *texcube = context->getTextureCubeMap();
560 if (texcube)
561 {
562 if (isSubImage && !validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
563 {
564 return false; // error already registered by validateSubImageParams
565 }
566 texture = texcube;
567 textureFormat = gl::GetFormat(texcube->getInternalFormat(target, level), context->getClientVersion());
568 }
569 }
570 break;
571
572 default:
573 return gl::error(GL_INVALID_ENUM, false);
574 }
575
576 if (!texture)
577 {
578 return gl::error(GL_INVALID_OPERATION, false);
579 }
580
581 if (texture->isImmutable() && !isSubImage)
582 {
583 return gl::error(GL_INVALID_OPERATION, false);
584 }
585
586
587 // [OpenGL ES 2.0.24] table 3.9
588 if (isSubImage)
589 {
590 switch (textureFormat)
591 {
592 case GL_ALPHA:
593 if (colorbufferFormat != GL_ALPHA8_EXT &&
594 colorbufferFormat != GL_RGBA4 &&
595 colorbufferFormat != GL_RGB5_A1 &&
596 colorbufferFormat != GL_RGBA8_OES)
597 {
598 return gl::error(GL_INVALID_OPERATION, false);
599 }
600 break;
601 case GL_LUMINANCE:
602 case GL_RGB:
603 if (colorbufferFormat != GL_RGB565 &&
604 colorbufferFormat != GL_RGB8_OES &&
605 colorbufferFormat != GL_RGBA4 &&
606 colorbufferFormat != GL_RGB5_A1 &&
607 colorbufferFormat != GL_RGBA8_OES)
608 {
609 return gl::error(GL_INVALID_OPERATION, false);
610 }
611 break;
612 case GL_LUMINANCE_ALPHA:
613 case GL_RGBA:
614 if (colorbufferFormat != GL_RGBA4 &&
615 colorbufferFormat != GL_RGB5_A1 &&
616 colorbufferFormat != GL_RGBA8_OES)
617 {
618 return gl::error(GL_INVALID_OPERATION, false);
619 }
620 break;
621 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
622 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
623 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
624 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
625 return gl::error(GL_INVALID_OPERATION, false);
626 case GL_DEPTH_COMPONENT:
627 case GL_DEPTH_STENCIL_OES:
628 return gl::error(GL_INVALID_OPERATION, false);
629 default:
630 return gl::error(GL_INVALID_OPERATION, false);
631 }
632 }
633 else
634 {
635 switch (internalformat)
636 {
637 case GL_ALPHA:
638 if (colorbufferFormat != GL_ALPHA8_EXT &&
639 colorbufferFormat != GL_RGBA4 &&
640 colorbufferFormat != GL_RGB5_A1 &&
641 colorbufferFormat != GL_BGRA8_EXT &&
642 colorbufferFormat != GL_RGBA8_OES)
643 {
644 return gl::error(GL_INVALID_OPERATION, false);
645 }
646 break;
647 case GL_LUMINANCE:
648 case GL_RGB:
649 if (colorbufferFormat != GL_RGB565 &&
650 colorbufferFormat != GL_RGB8_OES &&
651 colorbufferFormat != GL_RGBA4 &&
652 colorbufferFormat != GL_RGB5_A1 &&
653 colorbufferFormat != GL_BGRA8_EXT &&
654 colorbufferFormat != GL_RGBA8_OES)
655 {
656 return gl::error(GL_INVALID_OPERATION, false);
657 }
658 break;
659 case GL_LUMINANCE_ALPHA:
660 case GL_RGBA:
661 if (colorbufferFormat != GL_RGBA4 &&
662 colorbufferFormat != GL_RGB5_A1 &&
663 colorbufferFormat != GL_BGRA8_EXT &&
664 colorbufferFormat != GL_RGBA8_OES)
665 {
666 return gl::error(GL_INVALID_OPERATION, false);
667 }
668 break;
669 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
670 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
671 if (context->supportsDXT1Textures())
672 {
673 return gl::error(GL_INVALID_OPERATION, false);
674 }
675 else
676 {
677 return gl::error(GL_INVALID_ENUM, false);
678 }
679 break;
680 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
681 if (context->supportsDXT3Textures())
682 {
683 return gl::error(GL_INVALID_OPERATION, false);
684 }
685 else
686 {
687 return gl::error(GL_INVALID_ENUM, false);
688 }
689 break;
690 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
691 if (context->supportsDXT5Textures())
692 {
693 return gl::error(GL_INVALID_OPERATION, false);
694 }
695 else
696 {
697 return gl::error(GL_INVALID_ENUM, false);
698 }
699 break;
700 case GL_DEPTH_COMPONENT:
701 case GL_DEPTH_COMPONENT16:
702 case GL_DEPTH_COMPONENT32_OES:
703 case GL_DEPTH_STENCIL_OES:
704 case GL_DEPTH24_STENCIL8_OES:
705 if (context->supportsDepthTextures())
706 {
707 return gl::error(GL_INVALID_OPERATION, false);
708 }
709 else
710 {
711 return gl::error(GL_INVALID_ENUM, false);
712 }
713 default:
714 return gl::error(GL_INVALID_ENUM, false);
715 }
716 }
717
Geoff Lang784a8fd2013-09-24 12:33:16 -0400718 // If width or height is zero, it is a no-op. Return false without setting an error.
719 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720}
721
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400722bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723 GLsizei width, GLsizei height)
724{
725 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
726 {
727 return gl::error(GL_INVALID_ENUM, false);
728 }
729
730 if (width < 1 || height < 1 || levels < 1)
731 {
732 return gl::error(GL_INVALID_VALUE, false);
733 }
734
735 if (target == GL_TEXTURE_CUBE_MAP && width != height)
736 {
737 return gl::error(GL_INVALID_VALUE, false);
738 }
739
740 if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
741 {
742 return gl::error(GL_INVALID_OPERATION, false);
743 }
744
745 GLenum format = gl::GetFormat(internalformat, context->getClientVersion());
746 GLenum type = gl::GetType(internalformat, context->getClientVersion());
747
748 if (format == GL_NONE || type == GL_NONE)
749 {
750 return gl::error(GL_INVALID_ENUM, false);
751 }
752
753 switch (target)
754 {
755 case GL_TEXTURE_2D:
756 if (width > context->getMaximum2DTextureDimension() ||
757 height > context->getMaximum2DTextureDimension())
758 {
759 return gl::error(GL_INVALID_VALUE, false);
760 }
761 break;
762 case GL_TEXTURE_CUBE_MAP:
763 if (width > context->getMaximumCubeTextureDimension() ||
764 height > context->getMaximumCubeTextureDimension())
765 {
766 return gl::error(GL_INVALID_VALUE, false);
767 }
768 break;
769 default:
770 return gl::error(GL_INVALID_ENUM, false);
771 }
772
773 if (levels != 1 && !context->supportsNonPower2Texture())
774 {
775 if (!gl::isPow2(width) || !gl::isPow2(height))
776 {
777 return gl::error(GL_INVALID_OPERATION, false);
778 }
779 }
780
781 switch (internalformat)
782 {
783 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
784 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
785 if (!context->supportsDXT1Textures())
786 {
787 return gl::error(GL_INVALID_ENUM, false);
788 }
789 break;
790 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
791 if (!context->supportsDXT3Textures())
792 {
793 return gl::error(GL_INVALID_ENUM, false);
794 }
795 break;
796 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
797 if (!context->supportsDXT5Textures())
798 {
799 return gl::error(GL_INVALID_ENUM, false);
800 }
801 break;
802 case GL_RGBA32F_EXT:
803 case GL_RGB32F_EXT:
804 case GL_ALPHA32F_EXT:
805 case GL_LUMINANCE32F_EXT:
806 case GL_LUMINANCE_ALPHA32F_EXT:
807 if (!context->supportsFloat32Textures())
808 {
809 return gl::error(GL_INVALID_ENUM, false);
810 }
811 break;
812 case GL_RGBA16F_EXT:
813 case GL_RGB16F_EXT:
814 case GL_ALPHA16F_EXT:
815 case GL_LUMINANCE16F_EXT:
816 case GL_LUMINANCE_ALPHA16F_EXT:
817 if (!context->supportsFloat16Textures())
818 {
819 return gl::error(GL_INVALID_ENUM, false);
820 }
821 break;
822 case GL_DEPTH_COMPONENT16:
823 case GL_DEPTH_COMPONENT32_OES:
824 case GL_DEPTH24_STENCIL8_OES:
825 if (!context->supportsDepthTextures())
826 {
827 return gl::error(GL_INVALID_ENUM, false);
828 }
829 if (target != GL_TEXTURE_2D)
830 {
831 return gl::error(GL_INVALID_OPERATION, false);
832 }
833 // ANGLE_depth_texture only supports 1-level textures
834 if (levels != 1)
835 {
836 return gl::error(GL_INVALID_OPERATION, false);
837 }
838 break;
839 default:
840 break;
841 }
842
843 gl::Texture *texture = NULL;
844 switch(target)
845 {
846 case GL_TEXTURE_2D:
847 texture = context->getTexture2D();
848 break;
849 case GL_TEXTURE_CUBE_MAP:
850 texture = context->getTextureCubeMap();
851 break;
852 default:
853 UNREACHABLE();
854 }
855
856 if (!texture || texture->id() == 0)
857 {
858 return gl::error(GL_INVALID_OPERATION, false);
859 }
860
861 if (texture->isImmutable())
862 {
863 return gl::error(GL_INVALID_OPERATION, false);
864 }
865
866 return true;
867}
868
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400869bool ValidateES2FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400870 GLenum textarget, GLuint texture, GLint level)
871{
872 META_ASSERT(GL_DRAW_FRAMEBUFFER == GL_DRAW_FRAMEBUFFER_ANGLE && GL_READ_FRAMEBUFFER == GL_READ_FRAMEBUFFER_ANGLE);
873
874 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
875 {
876 return gl::error(GL_INVALID_ENUM, false);
877 }
878
879 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
880 {
881 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
882 if (colorAttachment >= context->getMaximumRenderTargets())
883 {
884 return gl::error(GL_INVALID_VALUE, false);
885 }
886 }
887 else
888 {
889 switch (attachment)
890 {
891 case GL_DEPTH_ATTACHMENT:
892 case GL_STENCIL_ATTACHMENT:
893 break;
894 default:
895 return gl::error(GL_INVALID_ENUM, false);
896 }
897 }
898
899 if (texture != 0)
900 {
901 gl::Texture *tex = context->getTexture(texture);
902
903 if (tex == NULL)
904 {
905 return gl::error(GL_INVALID_OPERATION, false);
906 }
907
908 switch (textarget)
909 {
910 case GL_TEXTURE_2D:
911 {
912 if (tex->getTarget() != GL_TEXTURE_2D)
913 {
914 return gl::error(GL_INVALID_OPERATION, false);
915 }
916 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
917 if (tex2d->isCompressed(level))
918 {
919 return gl::error(GL_INVALID_OPERATION, false);
920 }
921 break;
922 }
923
924 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
925 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
926 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
927 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
928 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
929 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
930 {
931 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
932 {
933 return gl::error(GL_INVALID_OPERATION, false);
934 }
935 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
936 if (texcube->isCompressed(textarget, level))
937 {
938 return gl::error(GL_INVALID_OPERATION, false);
939 }
940 break;
941 }
942
943 default:
944 return gl::error(GL_INVALID_ENUM, false);
945 }
946
947 if (level != 0)
948 {
949 return gl::error(GL_INVALID_VALUE, false);
950 }
951 }
952
953 gl::Framebuffer *framebuffer = NULL;
954 GLuint framebufferHandle = 0;
955 if (target == GL_READ_FRAMEBUFFER)
956 {
957 framebuffer = context->getReadFramebuffer();
958 framebufferHandle = context->getReadFramebufferHandle();
959 }
960 else
961 {
962 framebuffer = context->getDrawFramebuffer();
963 framebufferHandle = context->getDrawFramebufferHandle();
964 }
965
966 if (framebufferHandle == 0 || !framebuffer)
967 {
968 return gl::error(GL_INVALID_OPERATION, false);
969 }
970
971 return true;
972}
973
974// check for combinations of format and type that are valid for ReadPixels
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400975bool ValidES2ReadFormatType(GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400976{
977 switch (format)
978 {
979 case GL_RGBA:
980 switch (type)
981 {
982 case GL_UNSIGNED_BYTE:
983 break;
984 default:
985 return false;
986 }
987 break;
988 case GL_BGRA_EXT:
989 switch (type)
990 {
991 case GL_UNSIGNED_BYTE:
992 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
993 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
994 break;
995 default:
996 return false;
997 }
998 break;
999 default:
1000 return false;
1001 }
1002 return true;
1003}
1004
1005}