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