blob: 71d8633e4e1f705473a3706546e4cbc24cb29996 [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
490 if (width == 0 || height == 0)
491 {
492 return false;
493 }
494
495 // Verify zero border
496 if (border != 0)
497 {
498 return gl::error(GL_INVALID_VALUE, false);
499 }
500
501 // Validate dimensions based on Context limits and validate the texture
502 if (level > context->getMaximumTextureLevel())
503 {
504 return gl::error(GL_INVALID_VALUE, false);
505 }
506
507 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
508
509 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
510 {
511 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
512 }
513
514 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
515 {
516 return gl::error(GL_INVALID_OPERATION, false);
517 }
518
519 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
520 gl::Texture *texture = NULL;
521 GLenum textureFormat = GL_RGBA;
522
523 switch (target)
524 {
525 case GL_TEXTURE_2D:
526 {
527 if (width > (context->getMaximum2DTextureDimension() >> level) ||
528 height > (context->getMaximum2DTextureDimension() >> level))
529 {
530 return gl::error(GL_INVALID_VALUE, false);
531 }
532
533 gl::Texture2D *tex2d = context->getTexture2D();
534 if (tex2d)
535 {
536 if (isSubImage && !validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
537 {
538 return false; // error already registered by validateSubImageParams
539 }
540 texture = tex2d;
541 textureFormat = gl::GetFormat(tex2d->getInternalFormat(level), context->getClientVersion());
542 }
543 }
544 break;
545
546 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
547 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
548 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
549 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
550 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
551 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
552 {
553 if (!isSubImage && width != height)
554 {
555 return gl::error(GL_INVALID_VALUE, false);
556 }
557
558 if (width > (context->getMaximumCubeTextureDimension() >> level) ||
559 height > (context->getMaximumCubeTextureDimension() >> level))
560 {
561 return gl::error(GL_INVALID_VALUE, false);
562 }
563
564 gl::TextureCubeMap *texcube = context->getTextureCubeMap();
565 if (texcube)
566 {
567 if (isSubImage && !validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
568 {
569 return false; // error already registered by validateSubImageParams
570 }
571 texture = texcube;
572 textureFormat = gl::GetFormat(texcube->getInternalFormat(target, level), context->getClientVersion());
573 }
574 }
575 break;
576
577 default:
578 return gl::error(GL_INVALID_ENUM, false);
579 }
580
581 if (!texture)
582 {
583 return gl::error(GL_INVALID_OPERATION, false);
584 }
585
586 if (texture->isImmutable() && !isSubImage)
587 {
588 return gl::error(GL_INVALID_OPERATION, false);
589 }
590
591
592 // [OpenGL ES 2.0.24] table 3.9
593 if (isSubImage)
594 {
595 switch (textureFormat)
596 {
597 case GL_ALPHA:
598 if (colorbufferFormat != GL_ALPHA8_EXT &&
599 colorbufferFormat != GL_RGBA4 &&
600 colorbufferFormat != GL_RGB5_A1 &&
601 colorbufferFormat != GL_RGBA8_OES)
602 {
603 return gl::error(GL_INVALID_OPERATION, false);
604 }
605 break;
606 case GL_LUMINANCE:
607 case GL_RGB:
608 if (colorbufferFormat != GL_RGB565 &&
609 colorbufferFormat != GL_RGB8_OES &&
610 colorbufferFormat != GL_RGBA4 &&
611 colorbufferFormat != GL_RGB5_A1 &&
612 colorbufferFormat != GL_RGBA8_OES)
613 {
614 return gl::error(GL_INVALID_OPERATION, false);
615 }
616 break;
617 case GL_LUMINANCE_ALPHA:
618 case GL_RGBA:
619 if (colorbufferFormat != GL_RGBA4 &&
620 colorbufferFormat != GL_RGB5_A1 &&
621 colorbufferFormat != GL_RGBA8_OES)
622 {
623 return gl::error(GL_INVALID_OPERATION, false);
624 }
625 break;
626 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
627 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
628 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
629 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
630 return gl::error(GL_INVALID_OPERATION, false);
631 case GL_DEPTH_COMPONENT:
632 case GL_DEPTH_STENCIL_OES:
633 return gl::error(GL_INVALID_OPERATION, false);
634 default:
635 return gl::error(GL_INVALID_OPERATION, false);
636 }
637 }
638 else
639 {
640 switch (internalformat)
641 {
642 case GL_ALPHA:
643 if (colorbufferFormat != GL_ALPHA8_EXT &&
644 colorbufferFormat != GL_RGBA4 &&
645 colorbufferFormat != GL_RGB5_A1 &&
646 colorbufferFormat != GL_BGRA8_EXT &&
647 colorbufferFormat != GL_RGBA8_OES)
648 {
649 return gl::error(GL_INVALID_OPERATION, false);
650 }
651 break;
652 case GL_LUMINANCE:
653 case GL_RGB:
654 if (colorbufferFormat != GL_RGB565 &&
655 colorbufferFormat != GL_RGB8_OES &&
656 colorbufferFormat != GL_RGBA4 &&
657 colorbufferFormat != GL_RGB5_A1 &&
658 colorbufferFormat != GL_BGRA8_EXT &&
659 colorbufferFormat != GL_RGBA8_OES)
660 {
661 return gl::error(GL_INVALID_OPERATION, false);
662 }
663 break;
664 case GL_LUMINANCE_ALPHA:
665 case GL_RGBA:
666 if (colorbufferFormat != GL_RGBA4 &&
667 colorbufferFormat != GL_RGB5_A1 &&
668 colorbufferFormat != GL_BGRA8_EXT &&
669 colorbufferFormat != GL_RGBA8_OES)
670 {
671 return gl::error(GL_INVALID_OPERATION, false);
672 }
673 break;
674 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
675 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
676 if (context->supportsDXT1Textures())
677 {
678 return gl::error(GL_INVALID_OPERATION, false);
679 }
680 else
681 {
682 return gl::error(GL_INVALID_ENUM, false);
683 }
684 break;
685 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
686 if (context->supportsDXT3Textures())
687 {
688 return gl::error(GL_INVALID_OPERATION, false);
689 }
690 else
691 {
692 return gl::error(GL_INVALID_ENUM, false);
693 }
694 break;
695 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
696 if (context->supportsDXT5Textures())
697 {
698 return gl::error(GL_INVALID_OPERATION, false);
699 }
700 else
701 {
702 return gl::error(GL_INVALID_ENUM, false);
703 }
704 break;
705 case GL_DEPTH_COMPONENT:
706 case GL_DEPTH_COMPONENT16:
707 case GL_DEPTH_COMPONENT32_OES:
708 case GL_DEPTH_STENCIL_OES:
709 case GL_DEPTH24_STENCIL8_OES:
710 if (context->supportsDepthTextures())
711 {
712 return gl::error(GL_INVALID_OPERATION, false);
713 }
714 else
715 {
716 return gl::error(GL_INVALID_ENUM, false);
717 }
718 default:
719 return gl::error(GL_INVALID_ENUM, false);
720 }
721 }
722
723 return true;
724}
725
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400726bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400727 GLsizei width, GLsizei height)
728{
729 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
730 {
731 return gl::error(GL_INVALID_ENUM, false);
732 }
733
734 if (width < 1 || height < 1 || levels < 1)
735 {
736 return gl::error(GL_INVALID_VALUE, false);
737 }
738
739 if (target == GL_TEXTURE_CUBE_MAP && width != height)
740 {
741 return gl::error(GL_INVALID_VALUE, false);
742 }
743
744 if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
745 {
746 return gl::error(GL_INVALID_OPERATION, false);
747 }
748
749 GLenum format = gl::GetFormat(internalformat, context->getClientVersion());
750 GLenum type = gl::GetType(internalformat, context->getClientVersion());
751
752 if (format == GL_NONE || type == GL_NONE)
753 {
754 return gl::error(GL_INVALID_ENUM, false);
755 }
756
757 switch (target)
758 {
759 case GL_TEXTURE_2D:
760 if (width > context->getMaximum2DTextureDimension() ||
761 height > context->getMaximum2DTextureDimension())
762 {
763 return gl::error(GL_INVALID_VALUE, false);
764 }
765 break;
766 case GL_TEXTURE_CUBE_MAP:
767 if (width > context->getMaximumCubeTextureDimension() ||
768 height > context->getMaximumCubeTextureDimension())
769 {
770 return gl::error(GL_INVALID_VALUE, false);
771 }
772 break;
773 default:
774 return gl::error(GL_INVALID_ENUM, false);
775 }
776
777 if (levels != 1 && !context->supportsNonPower2Texture())
778 {
779 if (!gl::isPow2(width) || !gl::isPow2(height))
780 {
781 return gl::error(GL_INVALID_OPERATION, false);
782 }
783 }
784
785 switch (internalformat)
786 {
787 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
788 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
789 if (!context->supportsDXT1Textures())
790 {
791 return gl::error(GL_INVALID_ENUM, false);
792 }
793 break;
794 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
795 if (!context->supportsDXT3Textures())
796 {
797 return gl::error(GL_INVALID_ENUM, false);
798 }
799 break;
800 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
801 if (!context->supportsDXT5Textures())
802 {
803 return gl::error(GL_INVALID_ENUM, false);
804 }
805 break;
806 case GL_RGBA32F_EXT:
807 case GL_RGB32F_EXT:
808 case GL_ALPHA32F_EXT:
809 case GL_LUMINANCE32F_EXT:
810 case GL_LUMINANCE_ALPHA32F_EXT:
811 if (!context->supportsFloat32Textures())
812 {
813 return gl::error(GL_INVALID_ENUM, false);
814 }
815 break;
816 case GL_RGBA16F_EXT:
817 case GL_RGB16F_EXT:
818 case GL_ALPHA16F_EXT:
819 case GL_LUMINANCE16F_EXT:
820 case GL_LUMINANCE_ALPHA16F_EXT:
821 if (!context->supportsFloat16Textures())
822 {
823 return gl::error(GL_INVALID_ENUM, false);
824 }
825 break;
826 case GL_DEPTH_COMPONENT16:
827 case GL_DEPTH_COMPONENT32_OES:
828 case GL_DEPTH24_STENCIL8_OES:
829 if (!context->supportsDepthTextures())
830 {
831 return gl::error(GL_INVALID_ENUM, false);
832 }
833 if (target != GL_TEXTURE_2D)
834 {
835 return gl::error(GL_INVALID_OPERATION, false);
836 }
837 // ANGLE_depth_texture only supports 1-level textures
838 if (levels != 1)
839 {
840 return gl::error(GL_INVALID_OPERATION, false);
841 }
842 break;
843 default:
844 break;
845 }
846
847 gl::Texture *texture = NULL;
848 switch(target)
849 {
850 case GL_TEXTURE_2D:
851 texture = context->getTexture2D();
852 break;
853 case GL_TEXTURE_CUBE_MAP:
854 texture = context->getTextureCubeMap();
855 break;
856 default:
857 UNREACHABLE();
858 }
859
860 if (!texture || texture->id() == 0)
861 {
862 return gl::error(GL_INVALID_OPERATION, false);
863 }
864
865 if (texture->isImmutable())
866 {
867 return gl::error(GL_INVALID_OPERATION, false);
868 }
869
870 return true;
871}
872
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400873bool ValidateES2FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400874 GLenum textarget, GLuint texture, GLint level)
875{
876 META_ASSERT(GL_DRAW_FRAMEBUFFER == GL_DRAW_FRAMEBUFFER_ANGLE && GL_READ_FRAMEBUFFER == GL_READ_FRAMEBUFFER_ANGLE);
877
878 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
879 {
880 return gl::error(GL_INVALID_ENUM, false);
881 }
882
883 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
884 {
885 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
886 if (colorAttachment >= context->getMaximumRenderTargets())
887 {
888 return gl::error(GL_INVALID_VALUE, false);
889 }
890 }
891 else
892 {
893 switch (attachment)
894 {
895 case GL_DEPTH_ATTACHMENT:
896 case GL_STENCIL_ATTACHMENT:
897 break;
898 default:
899 return gl::error(GL_INVALID_ENUM, false);
900 }
901 }
902
903 if (texture != 0)
904 {
905 gl::Texture *tex = context->getTexture(texture);
906
907 if (tex == NULL)
908 {
909 return gl::error(GL_INVALID_OPERATION, false);
910 }
911
912 switch (textarget)
913 {
914 case GL_TEXTURE_2D:
915 {
916 if (tex->getTarget() != GL_TEXTURE_2D)
917 {
918 return gl::error(GL_INVALID_OPERATION, false);
919 }
920 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
921 if (tex2d->isCompressed(level))
922 {
923 return gl::error(GL_INVALID_OPERATION, false);
924 }
925 break;
926 }
927
928 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
929 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
930 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
931 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
932 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
933 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
934 {
935 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
936 {
937 return gl::error(GL_INVALID_OPERATION, false);
938 }
939 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
940 if (texcube->isCompressed(textarget, level))
941 {
942 return gl::error(GL_INVALID_OPERATION, false);
943 }
944 break;
945 }
946
947 default:
948 return gl::error(GL_INVALID_ENUM, false);
949 }
950
951 if (level != 0)
952 {
953 return gl::error(GL_INVALID_VALUE, false);
954 }
955 }
956
957 gl::Framebuffer *framebuffer = NULL;
958 GLuint framebufferHandle = 0;
959 if (target == GL_READ_FRAMEBUFFER)
960 {
961 framebuffer = context->getReadFramebuffer();
962 framebufferHandle = context->getReadFramebufferHandle();
963 }
964 else
965 {
966 framebuffer = context->getDrawFramebuffer();
967 framebufferHandle = context->getDrawFramebufferHandle();
968 }
969
970 if (framebufferHandle == 0 || !framebuffer)
971 {
972 return gl::error(GL_INVALID_OPERATION, false);
973 }
974
975 return true;
976}
977
978// check for combinations of format and type that are valid for ReadPixels
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400979bool ValidES2ReadFormatType(GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400980{
981 switch (format)
982 {
983 case GL_RGBA:
984 switch (type)
985 {
986 case GL_UNSIGNED_BYTE:
987 break;
988 default:
989 return false;
990 }
991 break;
992 case GL_BGRA_EXT:
993 switch (type)
994 {
995 case GL_UNSIGNED_BYTE:
996 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
997 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
998 break;
999 default:
1000 return false;
1001 }
1002 break;
1003 default:
1004 return false;
1005 }
1006 return true;
1007}
1008
1009}