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