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