blob: 428d1385afb72ba04d44e042d6dc7942cd6d9485 [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 {
Geoff Langa836e482014-04-28 10:08:27 -040050 if ((width % 4 != 0 && width != texture->getWidth(level)) ||
51 (height % 4 != 0 && height != texture->getHeight(level)))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040052 {
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{
Shannon Woods4dfed832014-03-17 20:03:39 -0400460 if (!ValidTexture2DDestinationTarget(context, target))
461 {
462 return gl::error(GL_INVALID_ENUM, false);
463 }
464
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400465 if (!gl::IsInternalTextureTarget(target, context->getClientVersion()))
466 {
467 return gl::error(GL_INVALID_ENUM, false);
468 }
469
470 if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
471 {
472 return gl::error(GL_INVALID_VALUE, false);
473 }
474
475 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
476 {
477 return gl::error(GL_INVALID_VALUE, false);
478 }
479
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400480 // Verify zero border
481 if (border != 0)
482 {
483 return gl::error(GL_INVALID_VALUE, false);
484 }
485
486 // Validate dimensions based on Context limits and validate the texture
Geoff Langce635692013-09-24 13:56:32 -0400487 if (!ValidMipLevel(context, target, level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488 {
489 return gl::error(GL_INVALID_VALUE, false);
490 }
491
492 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
493
494 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
495 {
496 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
497 }
498
499 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
500 {
501 return gl::error(GL_INVALID_OPERATION, false);
502 }
503
504 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
505 gl::Texture *texture = NULL;
506 GLenum textureFormat = GL_RGBA;
507
508 switch (target)
509 {
510 case GL_TEXTURE_2D:
511 {
512 if (width > (context->getMaximum2DTextureDimension() >> level) ||
513 height > (context->getMaximum2DTextureDimension() >> level))
514 {
515 return gl::error(GL_INVALID_VALUE, false);
516 }
517
518 gl::Texture2D *tex2d = context->getTexture2D();
519 if (tex2d)
520 {
521 if (isSubImage && !validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
522 {
523 return false; // error already registered by validateSubImageParams
524 }
525 texture = tex2d;
526 textureFormat = gl::GetFormat(tex2d->getInternalFormat(level), context->getClientVersion());
527 }
528 }
529 break;
530
531 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
532 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
533 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
534 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
535 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
536 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
537 {
538 if (!isSubImage && width != height)
539 {
540 return gl::error(GL_INVALID_VALUE, false);
541 }
542
543 if (width > (context->getMaximumCubeTextureDimension() >> level) ||
544 height > (context->getMaximumCubeTextureDimension() >> level))
545 {
546 return gl::error(GL_INVALID_VALUE, false);
547 }
548
549 gl::TextureCubeMap *texcube = context->getTextureCubeMap();
550 if (texcube)
551 {
552 if (isSubImage && !validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
553 {
554 return false; // error already registered by validateSubImageParams
555 }
556 texture = texcube;
557 textureFormat = gl::GetFormat(texcube->getInternalFormat(target, level), context->getClientVersion());
558 }
559 }
560 break;
561
562 default:
563 return gl::error(GL_INVALID_ENUM, false);
564 }
565
566 if (!texture)
567 {
568 return gl::error(GL_INVALID_OPERATION, false);
569 }
570
571 if (texture->isImmutable() && !isSubImage)
572 {
573 return gl::error(GL_INVALID_OPERATION, false);
574 }
575
576
577 // [OpenGL ES 2.0.24] table 3.9
578 if (isSubImage)
579 {
580 switch (textureFormat)
581 {
582 case GL_ALPHA:
583 if (colorbufferFormat != GL_ALPHA8_EXT &&
584 colorbufferFormat != GL_RGBA4 &&
585 colorbufferFormat != GL_RGB5_A1 &&
586 colorbufferFormat != GL_RGBA8_OES)
587 {
588 return gl::error(GL_INVALID_OPERATION, false);
589 }
590 break;
591 case GL_LUMINANCE:
Geoff Lang632192d2013-10-04 13:40:46 -0400592 if (colorbufferFormat != GL_R8_EXT &&
593 colorbufferFormat != GL_RG8_EXT &&
594 colorbufferFormat != GL_RGB565 &&
595 colorbufferFormat != GL_RGB8_OES &&
596 colorbufferFormat != GL_RGBA4 &&
597 colorbufferFormat != GL_RGB5_A1 &&
598 colorbufferFormat != GL_RGBA8_OES)
599 {
600 return gl::error(GL_INVALID_OPERATION, false);
601 }
602 break;
603 case GL_RED_EXT:
604 if (colorbufferFormat != GL_R8_EXT &&
605 colorbufferFormat != GL_RG8_EXT &&
606 colorbufferFormat != GL_RGB565 &&
607 colorbufferFormat != GL_RGB8_OES &&
608 colorbufferFormat != GL_RGBA4 &&
609 colorbufferFormat != GL_RGB5_A1 &&
610 colorbufferFormat != GL_RGBA8_OES)
611 {
612 return gl::error(GL_INVALID_OPERATION, false);
613 }
614 break;
615 case GL_RG_EXT:
616 if (colorbufferFormat != GL_RG8_EXT &&
617 colorbufferFormat != GL_RGB565 &&
618 colorbufferFormat != GL_RGB8_OES &&
619 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;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400626 case GL_RGB:
627 if (colorbufferFormat != GL_RGB565 &&
628 colorbufferFormat != GL_RGB8_OES &&
629 colorbufferFormat != GL_RGBA4 &&
630 colorbufferFormat != GL_RGB5_A1 &&
631 colorbufferFormat != GL_RGBA8_OES)
632 {
633 return gl::error(GL_INVALID_OPERATION, false);
634 }
635 break;
636 case GL_LUMINANCE_ALPHA:
637 case GL_RGBA:
638 if (colorbufferFormat != GL_RGBA4 &&
639 colorbufferFormat != GL_RGB5_A1 &&
640 colorbufferFormat != GL_RGBA8_OES)
641 {
642 return gl::error(GL_INVALID_OPERATION, false);
643 }
644 break;
645 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
646 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
647 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
648 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
649 return gl::error(GL_INVALID_OPERATION, false);
650 case GL_DEPTH_COMPONENT:
651 case GL_DEPTH_STENCIL_OES:
652 return gl::error(GL_INVALID_OPERATION, false);
653 default:
654 return gl::error(GL_INVALID_OPERATION, false);
655 }
656 }
657 else
658 {
659 switch (internalformat)
660 {
661 case GL_ALPHA:
662 if (colorbufferFormat != GL_ALPHA8_EXT &&
663 colorbufferFormat != GL_RGBA4 &&
664 colorbufferFormat != GL_RGB5_A1 &&
665 colorbufferFormat != GL_BGRA8_EXT &&
666 colorbufferFormat != GL_RGBA8_OES)
667 {
668 return gl::error(GL_INVALID_OPERATION, false);
669 }
670 break;
671 case GL_LUMINANCE:
Geoff Lang632192d2013-10-04 13:40:46 -0400672 if (colorbufferFormat != GL_R8_EXT &&
673 colorbufferFormat != GL_RG8_EXT &&
674 colorbufferFormat != GL_RGB565 &&
675 colorbufferFormat != GL_RGB8_OES &&
676 colorbufferFormat != GL_RGBA4 &&
677 colorbufferFormat != GL_RGB5_A1 &&
678 colorbufferFormat != GL_BGRA8_EXT &&
679 colorbufferFormat != GL_RGBA8_OES)
680 {
681 return gl::error(GL_INVALID_OPERATION, false);
682 }
683 break;
684 case GL_RED_EXT:
685 if (colorbufferFormat != GL_R8_EXT &&
686 colorbufferFormat != GL_RG8_EXT &&
687 colorbufferFormat != GL_RGB565 &&
688 colorbufferFormat != GL_RGB8_OES &&
689 colorbufferFormat != GL_RGBA4 &&
690 colorbufferFormat != GL_RGB5_A1 &&
691 colorbufferFormat != GL_BGRA8_EXT &&
692 colorbufferFormat != GL_RGBA8_OES)
693 {
694 return gl::error(GL_INVALID_OPERATION, false);
695 }
696 break;
697 case GL_RG_EXT:
698 if (colorbufferFormat != GL_RG8_EXT &&
699 colorbufferFormat != GL_RGB565 &&
700 colorbufferFormat != GL_RGB8_OES &&
701 colorbufferFormat != GL_RGBA4 &&
702 colorbufferFormat != GL_RGB5_A1 &&
703 colorbufferFormat != GL_BGRA8_EXT &&
704 colorbufferFormat != GL_RGBA8_OES)
705 {
706 return gl::error(GL_INVALID_OPERATION, false);
707 }
708 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 case GL_RGB:
710 if (colorbufferFormat != GL_RGB565 &&
711 colorbufferFormat != GL_RGB8_OES &&
712 colorbufferFormat != GL_RGBA4 &&
713 colorbufferFormat != GL_RGB5_A1 &&
714 colorbufferFormat != GL_BGRA8_EXT &&
715 colorbufferFormat != GL_RGBA8_OES)
716 {
717 return gl::error(GL_INVALID_OPERATION, false);
718 }
719 break;
720 case GL_LUMINANCE_ALPHA:
721 case GL_RGBA:
722 if (colorbufferFormat != GL_RGBA4 &&
723 colorbufferFormat != GL_RGB5_A1 &&
724 colorbufferFormat != GL_BGRA8_EXT &&
725 colorbufferFormat != GL_RGBA8_OES)
726 {
727 return gl::error(GL_INVALID_OPERATION, false);
728 }
729 break;
730 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
731 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
732 if (context->supportsDXT1Textures())
733 {
734 return gl::error(GL_INVALID_OPERATION, false);
735 }
736 else
737 {
738 return gl::error(GL_INVALID_ENUM, false);
739 }
740 break;
741 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
742 if (context->supportsDXT3Textures())
743 {
744 return gl::error(GL_INVALID_OPERATION, false);
745 }
746 else
747 {
748 return gl::error(GL_INVALID_ENUM, false);
749 }
750 break;
751 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
752 if (context->supportsDXT5Textures())
753 {
754 return gl::error(GL_INVALID_OPERATION, false);
755 }
756 else
757 {
758 return gl::error(GL_INVALID_ENUM, false);
759 }
760 break;
761 case GL_DEPTH_COMPONENT:
762 case GL_DEPTH_COMPONENT16:
763 case GL_DEPTH_COMPONENT32_OES:
764 case GL_DEPTH_STENCIL_OES:
765 case GL_DEPTH24_STENCIL8_OES:
766 if (context->supportsDepthTextures())
767 {
768 return gl::error(GL_INVALID_OPERATION, false);
769 }
770 else
771 {
772 return gl::error(GL_INVALID_ENUM, false);
773 }
774 default:
775 return gl::error(GL_INVALID_ENUM, false);
776 }
777 }
778
Geoff Lang784a8fd2013-09-24 12:33:16 -0400779 // If width or height is zero, it is a no-op. Return false without setting an error.
780 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781}
782
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400783bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 GLsizei width, GLsizei height)
785{
786 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
787 {
788 return gl::error(GL_INVALID_ENUM, false);
789 }
790
791 if (width < 1 || height < 1 || levels < 1)
792 {
793 return gl::error(GL_INVALID_VALUE, false);
794 }
795
796 if (target == GL_TEXTURE_CUBE_MAP && width != height)
797 {
798 return gl::error(GL_INVALID_VALUE, false);
799 }
800
801 if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
802 {
803 return gl::error(GL_INVALID_OPERATION, false);
804 }
805
806 GLenum format = gl::GetFormat(internalformat, context->getClientVersion());
807 GLenum type = gl::GetType(internalformat, context->getClientVersion());
808
809 if (format == GL_NONE || type == GL_NONE)
810 {
811 return gl::error(GL_INVALID_ENUM, false);
812 }
813
814 switch (target)
815 {
816 case GL_TEXTURE_2D:
817 if (width > context->getMaximum2DTextureDimension() ||
818 height > context->getMaximum2DTextureDimension())
819 {
820 return gl::error(GL_INVALID_VALUE, false);
821 }
822 break;
823 case GL_TEXTURE_CUBE_MAP:
824 if (width > context->getMaximumCubeTextureDimension() ||
825 height > context->getMaximumCubeTextureDimension())
826 {
827 return gl::error(GL_INVALID_VALUE, false);
828 }
829 break;
830 default:
831 return gl::error(GL_INVALID_ENUM, false);
832 }
833
834 if (levels != 1 && !context->supportsNonPower2Texture())
835 {
836 if (!gl::isPow2(width) || !gl::isPow2(height))
837 {
838 return gl::error(GL_INVALID_OPERATION, false);
839 }
840 }
841
842 switch (internalformat)
843 {
844 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
845 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
846 if (!context->supportsDXT1Textures())
847 {
848 return gl::error(GL_INVALID_ENUM, false);
849 }
850 break;
851 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
852 if (!context->supportsDXT3Textures())
853 {
854 return gl::error(GL_INVALID_ENUM, false);
855 }
856 break;
857 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
858 if (!context->supportsDXT5Textures())
859 {
860 return gl::error(GL_INVALID_ENUM, false);
861 }
862 break;
863 case GL_RGBA32F_EXT:
864 case GL_RGB32F_EXT:
865 case GL_ALPHA32F_EXT:
866 case GL_LUMINANCE32F_EXT:
867 case GL_LUMINANCE_ALPHA32F_EXT:
868 if (!context->supportsFloat32Textures())
869 {
870 return gl::error(GL_INVALID_ENUM, false);
871 }
872 break;
873 case GL_RGBA16F_EXT:
874 case GL_RGB16F_EXT:
875 case GL_ALPHA16F_EXT:
876 case GL_LUMINANCE16F_EXT:
877 case GL_LUMINANCE_ALPHA16F_EXT:
878 if (!context->supportsFloat16Textures())
879 {
880 return gl::error(GL_INVALID_ENUM, false);
881 }
882 break;
Geoff Lang632192d2013-10-04 13:40:46 -0400883 case GL_R8_EXT:
884 case GL_RG8_EXT:
885 case GL_R16F_EXT:
886 case GL_RG16F_EXT:
887 case GL_R32F_EXT:
888 case GL_RG32F_EXT:
889 if (!context->supportsRGTextures())
890 {
891 return gl::error(GL_INVALID_ENUM, false);
892 }
893 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 case GL_DEPTH_COMPONENT16:
895 case GL_DEPTH_COMPONENT32_OES:
896 case GL_DEPTH24_STENCIL8_OES:
897 if (!context->supportsDepthTextures())
898 {
899 return gl::error(GL_INVALID_ENUM, false);
900 }
901 if (target != GL_TEXTURE_2D)
902 {
903 return gl::error(GL_INVALID_OPERATION, false);
904 }
905 // ANGLE_depth_texture only supports 1-level textures
906 if (levels != 1)
907 {
908 return gl::error(GL_INVALID_OPERATION, false);
909 }
910 break;
911 default:
912 break;
913 }
914
915 gl::Texture *texture = NULL;
916 switch(target)
917 {
918 case GL_TEXTURE_2D:
919 texture = context->getTexture2D();
920 break;
921 case GL_TEXTURE_CUBE_MAP:
922 texture = context->getTextureCubeMap();
923 break;
924 default:
925 UNREACHABLE();
926 }
927
928 if (!texture || texture->id() == 0)
929 {
930 return gl::error(GL_INVALID_OPERATION, false);
931 }
932
933 if (texture->isImmutable())
934 {
935 return gl::error(GL_INVALID_OPERATION, false);
936 }
937
938 return true;
939}
940
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400941bool ValidateES2FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 GLenum textarget, GLuint texture, GLint level)
943{
944 META_ASSERT(GL_DRAW_FRAMEBUFFER == GL_DRAW_FRAMEBUFFER_ANGLE && GL_READ_FRAMEBUFFER == GL_READ_FRAMEBUFFER_ANGLE);
945
946 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
947 {
948 return gl::error(GL_INVALID_ENUM, false);
949 }
950
951 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
952 {
953 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
954 if (colorAttachment >= context->getMaximumRenderTargets())
955 {
956 return gl::error(GL_INVALID_VALUE, false);
957 }
958 }
959 else
960 {
961 switch (attachment)
962 {
963 case GL_DEPTH_ATTACHMENT:
964 case GL_STENCIL_ATTACHMENT:
965 break;
966 default:
967 return gl::error(GL_INVALID_ENUM, false);
968 }
969 }
970
971 if (texture != 0)
972 {
973 gl::Texture *tex = context->getTexture(texture);
974
975 if (tex == NULL)
976 {
977 return gl::error(GL_INVALID_OPERATION, false);
978 }
979
980 switch (textarget)
981 {
982 case GL_TEXTURE_2D:
983 {
984 if (tex->getTarget() != GL_TEXTURE_2D)
985 {
986 return gl::error(GL_INVALID_OPERATION, false);
987 }
988 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
989 if (tex2d->isCompressed(level))
990 {
991 return gl::error(GL_INVALID_OPERATION, false);
992 }
993 break;
994 }
995
996 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
997 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
998 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
999 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1000 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1001 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1002 {
1003 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1004 {
1005 return gl::error(GL_INVALID_OPERATION, false);
1006 }
1007 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1008 if (texcube->isCompressed(textarget, level))
1009 {
1010 return gl::error(GL_INVALID_OPERATION, false);
1011 }
1012 break;
1013 }
1014
1015 default:
1016 return gl::error(GL_INVALID_ENUM, false);
1017 }
1018
1019 if (level != 0)
1020 {
1021 return gl::error(GL_INVALID_VALUE, false);
1022 }
1023 }
1024
1025 gl::Framebuffer *framebuffer = NULL;
1026 GLuint framebufferHandle = 0;
1027 if (target == GL_READ_FRAMEBUFFER)
1028 {
1029 framebuffer = context->getReadFramebuffer();
1030 framebufferHandle = context->getReadFramebufferHandle();
1031 }
1032 else
1033 {
1034 framebuffer = context->getDrawFramebuffer();
1035 framebufferHandle = context->getDrawFramebufferHandle();
1036 }
1037
1038 if (framebufferHandle == 0 || !framebuffer)
1039 {
1040 return gl::error(GL_INVALID_OPERATION, false);
1041 }
1042
1043 return true;
1044}
1045
1046// check for combinations of format and type that are valid for ReadPixels
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001047bool ValidES2ReadFormatType(gl::Context *context, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001048{
1049 switch (format)
1050 {
1051 case GL_RGBA:
1052 switch (type)
1053 {
1054 case GL_UNSIGNED_BYTE:
1055 break;
1056 default:
1057 return false;
1058 }
1059 break;
1060 case GL_BGRA_EXT:
1061 switch (type)
1062 {
1063 case GL_UNSIGNED_BYTE:
1064 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
1065 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
1066 break;
1067 default:
1068 return false;
1069 }
1070 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001071 case GL_RG_EXT:
1072 case GL_RED_EXT:
1073 if (!context->supportsRGTextures())
1074 {
1075 return false;
1076 }
1077 switch (type)
1078 {
1079 case GL_UNSIGNED_BYTE:
1080 break;
1081 default:
1082 return false;
1083 }
1084 break;
1085
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001086 default:
1087 return false;
1088 }
1089 return true;
1090}
1091
1092}