blob: a11ca9c5962eb790f2296668b3b15e125d2eb918 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#include "precompiled.h"
2//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004// 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"
Jamie Madille261b442014-06-25 12:42:21 -040018#include "libGLESv2/FramebufferAttachment.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040019
20#include "common/mathutil.h"
21#include "common/utilities.h"
22
23namespace gl
24{
25
Geoff Lange8ebe7f2013-08-05 15:03:13 -040026static bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height,
27 GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type,
28 gl::Texture2D *texture)
29{
30 if (!texture)
31 {
32 return gl::error(GL_INVALID_OPERATION, false);
33 }
34
35 if (compressed != texture->isCompressed(level))
36 {
37 return gl::error(GL_INVALID_OPERATION, false);
38 }
39
40 if (format != GL_NONE)
41 {
Geoff Lange4a492b2014-06-19 14:14:41 -040042 GLenum internalformat = gl::GetSizedInternalFormat(format, type);
Geoff Lange8ebe7f2013-08-05 15:03:13 -040043 if (internalformat != texture->getInternalFormat(level))
44 {
45 return gl::error(GL_INVALID_OPERATION, false);
46 }
47 }
48
49 if (compressed)
50 {
Geoff Langa836e482014-04-28 10:08:27 -040051 if ((width % 4 != 0 && width != texture->getWidth(level)) ||
52 (height % 4 != 0 && height != texture->getHeight(level)))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040053 {
54 return gl::error(GL_INVALID_OPERATION, false);
55 }
56 }
57
58 if (xoffset + width > texture->getWidth(level) ||
59 yoffset + height > texture->getHeight(level))
60 {
61 return gl::error(GL_INVALID_VALUE, false);
62 }
63
64 return true;
65}
66
67static bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height,
68 GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type,
69 gl::TextureCubeMap *texture)
70{
71 if (!texture)
72 {
73 return gl::error(GL_INVALID_OPERATION, false);
74 }
75
76 if (compressed != texture->isCompressed(target, level))
77 {
78 return gl::error(GL_INVALID_OPERATION, false);
79 }
80
81 if (format != GL_NONE)
82 {
Geoff Lange4a492b2014-06-19 14:14:41 -040083 GLenum internalformat = gl::GetSizedInternalFormat(format, type);
Geoff Lange8ebe7f2013-08-05 15:03:13 -040084 if (internalformat != texture->getInternalFormat(target, level))
85 {
86 return gl::error(GL_INVALID_OPERATION, false);
87 }
88 }
89
90 if (compressed)
91 {
92 if ((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
93 (height % 4 != 0 && height != texture->getHeight(target, 0)))
94 {
95 return gl::error(GL_INVALID_OPERATION, false);
96 }
97 }
98
99 if (xoffset + width > texture->getWidth(target, level) ||
100 yoffset + height > texture->getHeight(target, level))
101 {
102 return gl::error(GL_INVALID_VALUE, false);
103 }
104
105 return true;
106}
107
Geoff Lang005df412013-10-16 14:12:50 -0400108bool ValidateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400109 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
110 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
111{
Jamie Madill6f38f822014-06-06 17:12:20 -0400112 if (!ValidTexture2DDestinationTarget(context, target))
113 {
114 return gl::error(GL_INVALID_ENUM, false);
115 }
116
Geoff Langce635692013-09-24 13:56:32 -0400117 if (!ValidImageSize(context, target, level, width, height, 1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400118 {
119 return gl::error(GL_INVALID_VALUE, false);
120 }
121
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400122 if (level < 0 || xoffset < 0 ||
123 std::numeric_limits<GLsizei>::max() - xoffset < width ||
124 std::numeric_limits<GLsizei>::max() - yoffset < height)
125 {
126 return gl::error(GL_INVALID_VALUE, false);
127 }
128
Geoff Lang005df412013-10-16 14:12:50 -0400129 if (!isSubImage && !isCompressed && internalformat != format)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400130 {
131 return gl::error(GL_INVALID_OPERATION, false);
132 }
133
134 gl::Texture *texture = NULL;
135 bool textureCompressed = false;
136 GLenum textureInternalFormat = GL_NONE;
137 GLint textureLevelWidth = 0;
138 GLint textureLevelHeight = 0;
139 switch (target)
140 {
141 case GL_TEXTURE_2D:
142 {
143 if (width > (context->getMaximum2DTextureDimension() >> level) ||
144 height > (context->getMaximum2DTextureDimension() >> level))
145 {
146 return gl::error(GL_INVALID_VALUE, false);
147 }
148
149 gl::Texture2D *tex2d = context->getTexture2D();
150 if (tex2d)
151 {
152 textureCompressed = tex2d->isCompressed(level);
153 textureInternalFormat = tex2d->getInternalFormat(level);
154 textureLevelWidth = tex2d->getWidth(level);
155 textureLevelHeight = tex2d->getHeight(level);
156 texture = tex2d;
157 }
158
159 if (isSubImage && !validateSubImageParams2D(isCompressed, width, height, xoffset, yoffset,
160 level, format, type, tex2d))
161 {
162 return false;
163 }
164
165 texture = tex2d;
166 }
167 break;
168
169 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
170 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
171 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
172 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
173 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
174 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
175 {
176 if (!isSubImage && width != height)
177 {
178 return gl::error(GL_INVALID_VALUE, false);
179 }
180
181 if (width > (context->getMaximumCubeTextureDimension() >> level) ||
182 height > (context->getMaximumCubeTextureDimension() >> level))
183 {
184 return gl::error(GL_INVALID_VALUE, false);
185 }
186
187 gl::TextureCubeMap *texCube = context->getTextureCubeMap();
188 if (texCube)
189 {
190 textureCompressed = texCube->isCompressed(target, level);
191 textureInternalFormat = texCube->getInternalFormat(target, level);
192 textureLevelWidth = texCube->getWidth(target, level);
193 textureLevelHeight = texCube->getHeight(target, level);
194 texture = texCube;
195 }
196
197 if (isSubImage && !validateSubImageParamsCube(isCompressed, width, height, xoffset, yoffset,
198 target, level, format, type, texCube))
199 {
200 return false;
201 }
202 }
203 break;
204
205 default:
206 return gl::error(GL_INVALID_ENUM, false);
207 }
208
209 if (!texture)
210 {
211 return gl::error(GL_INVALID_OPERATION, false);
212 }
213
214 if (!isSubImage && texture->isImmutable())
215 {
216 return gl::error(GL_INVALID_OPERATION, false);
217 }
218
219 // Verify zero border
220 if (border != 0)
221 {
222 return gl::error(GL_INVALID_VALUE, false);
223 }
224
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400225 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
226 if (isCompressed)
227 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400228 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
229 {
230 return gl::error(GL_INVALID_OPERATION, false);
231 }
232
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400233 switch (actualInternalFormat)
234 {
235 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
236 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400237 if (!context->getCaps().extensions.textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400238 {
239 return gl::error(GL_INVALID_ENUM, false);
240 }
241 break;
242 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400243 if (!context->getCaps().extensions.textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400244 {
245 return gl::error(GL_INVALID_ENUM, false);
246 }
247 break;
248 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400249 if (!context->getCaps().extensions.textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400250 {
251 return gl::error(GL_INVALID_ENUM, false);
252 }
253 break;
254 default:
255 return gl::error(GL_INVALID_ENUM, false);
256 }
257 }
258 else
259 {
260 // validate <type> by itself (used as secondary key below)
261 switch (type)
262 {
263 case GL_UNSIGNED_BYTE:
264 case GL_UNSIGNED_SHORT_5_6_5:
265 case GL_UNSIGNED_SHORT_4_4_4_4:
266 case GL_UNSIGNED_SHORT_5_5_5_1:
267 case GL_UNSIGNED_SHORT:
268 case GL_UNSIGNED_INT:
269 case GL_UNSIGNED_INT_24_8_OES:
270 case GL_HALF_FLOAT_OES:
271 case GL_FLOAT:
272 break;
273 default:
274 return gl::error(GL_INVALID_ENUM, false);
275 }
276
277 // validate <format> + <type> combinations
278 // - invalid <format> -> sets INVALID_ENUM
279 // - invalid <format>+<type> combination -> sets INVALID_OPERATION
280 switch (format)
281 {
282 case GL_ALPHA:
283 case GL_LUMINANCE:
284 case GL_LUMINANCE_ALPHA:
285 switch (type)
286 {
287 case GL_UNSIGNED_BYTE:
288 case GL_FLOAT:
289 case GL_HALF_FLOAT_OES:
290 break;
291 default:
292 return gl::error(GL_INVALID_OPERATION, false);
293 }
294 break;
Geoff Lang632192d2013-10-04 13:40:46 -0400295 case GL_RED:
Geoff Langcec35902014-04-16 10:52:36 -0400296 case GL_RG:
297 if (!context->getCaps().extensions.textureRG)
Geoff Lang632192d2013-10-04 13:40:46 -0400298 {
299 return gl::error(GL_INVALID_ENUM, false);
300 }
301 switch (type)
302 {
303 case GL_UNSIGNED_BYTE:
304 case GL_FLOAT:
305 case GL_HALF_FLOAT_OES:
306 break;
307 default:
308 return gl::error(GL_INVALID_OPERATION, false);
309 }
310 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400311 case GL_RGB:
312 switch (type)
313 {
314 case GL_UNSIGNED_BYTE:
315 case GL_UNSIGNED_SHORT_5_6_5:
316 case GL_FLOAT:
317 case GL_HALF_FLOAT_OES:
318 break;
319 default:
320 return gl::error(GL_INVALID_OPERATION, false);
321 }
322 break;
323 case GL_RGBA:
324 switch (type)
325 {
326 case GL_UNSIGNED_BYTE:
327 case GL_UNSIGNED_SHORT_4_4_4_4:
328 case GL_UNSIGNED_SHORT_5_5_5_1:
329 case GL_FLOAT:
330 case GL_HALF_FLOAT_OES:
331 break;
332 default:
333 return gl::error(GL_INVALID_OPERATION, false);
334 }
335 break;
336 case GL_BGRA_EXT:
337 switch (type)
338 {
339 case GL_UNSIGNED_BYTE:
340 break;
341 default:
342 return gl::error(GL_INVALID_OPERATION, false);
343 }
344 break;
Geoff Lang05b05022014-06-11 15:31:45 -0400345 case GL_SRGB_EXT:
346 case GL_SRGB_ALPHA_EXT:
347 if (!context->getCaps().extensions.sRGB)
348 {
349 return gl::error(GL_INVALID_ENUM, false);
350 }
351 switch (type)
352 {
353 case GL_UNSIGNED_BYTE:
354 break;
355 default:
356 return gl::error(GL_INVALID_OPERATION, false);
357 }
358 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400359 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below
360 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
361 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
362 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
363 break;
364 case GL_DEPTH_COMPONENT:
365 switch (type)
366 {
367 case GL_UNSIGNED_SHORT:
368 case GL_UNSIGNED_INT:
369 break;
370 default:
371 return gl::error(GL_INVALID_OPERATION, false);
372 }
373 break;
374 case GL_DEPTH_STENCIL_OES:
375 switch (type)
376 {
377 case GL_UNSIGNED_INT_24_8_OES:
378 break;
379 default:
380 return gl::error(GL_INVALID_OPERATION, false);
381 }
382 break;
383 default:
384 return gl::error(GL_INVALID_ENUM, false);
385 }
386
387 switch (format)
388 {
389 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
390 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400391 if (context->getCaps().extensions.textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400392 {
393 return gl::error(GL_INVALID_OPERATION, false);
394 }
395 else
396 {
397 return gl::error(GL_INVALID_ENUM, false);
398 }
399 break;
400 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400401 if (context->getCaps().extensions.textureCompressionDXT3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400402 {
403 return gl::error(GL_INVALID_OPERATION, false);
404 }
405 else
406 {
407 return gl::error(GL_INVALID_ENUM, false);
408 }
409 break;
410 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400411 if (context->getCaps().extensions.textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400412 {
413 return gl::error(GL_INVALID_OPERATION, false);
414 }
415 else
416 {
417 return gl::error(GL_INVALID_ENUM, false);
418 }
419 break;
420 case GL_DEPTH_COMPONENT:
421 case GL_DEPTH_STENCIL_OES:
Geoff Langcec35902014-04-16 10:52:36 -0400422 if (!context->getCaps().extensions.depthTextures)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423 {
424 return gl::error(GL_INVALID_VALUE, false);
425 }
426 if (target != GL_TEXTURE_2D)
427 {
428 return gl::error(GL_INVALID_OPERATION, false);
429 }
430 // OES_depth_texture supports loading depth data and multiple levels,
431 // but ANGLE_depth_texture does not
432 if (pixels != NULL || level != 0)
433 {
434 return gl::error(GL_INVALID_OPERATION, false);
435 }
436 break;
437 default:
438 break;
439 }
440
441 if (type == GL_FLOAT)
442 {
Geoff Langcec35902014-04-16 10:52:36 -0400443 if (!context->getCaps().extensions.textureFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 {
445 return gl::error(GL_INVALID_ENUM, false);
446 }
447 }
448 else if (type == GL_HALF_FLOAT_OES)
449 {
Geoff Langcec35902014-04-16 10:52:36 -0400450 if (!context->getCaps().extensions.textureHalfFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400451 {
452 return gl::error(GL_INVALID_ENUM, false);
453 }
454 }
455 }
456
457 return true;
458}
459
460
461
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400462bool ValidateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
464 GLint border)
465{
Jamie Madill560a8d82014-05-21 13:06:20 -0400466 GLenum textureInternalFormat = GL_NONE;
Shannon Woods4dfed832014-03-17 20:03:39 -0400467
Jamie Madill560a8d82014-05-21 13:06:20 -0400468 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
469 xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400470 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400471 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400472 }
473
474 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400475 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400476 GLenum textureFormat = gl::GetFormat(textureInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400477
478 // [OpenGL ES 2.0.24] table 3.9
479 if (isSubImage)
480 {
481 switch (textureFormat)
482 {
483 case GL_ALPHA:
484 if (colorbufferFormat != GL_ALPHA8_EXT &&
485 colorbufferFormat != GL_RGBA4 &&
486 colorbufferFormat != GL_RGB5_A1 &&
487 colorbufferFormat != GL_RGBA8_OES)
488 {
489 return gl::error(GL_INVALID_OPERATION, false);
490 }
491 break;
492 case GL_LUMINANCE:
Geoff Lang632192d2013-10-04 13:40:46 -0400493 if (colorbufferFormat != GL_R8_EXT &&
494 colorbufferFormat != GL_RG8_EXT &&
495 colorbufferFormat != GL_RGB565 &&
496 colorbufferFormat != GL_RGB8_OES &&
497 colorbufferFormat != GL_RGBA4 &&
498 colorbufferFormat != GL_RGB5_A1 &&
499 colorbufferFormat != GL_RGBA8_OES)
500 {
501 return gl::error(GL_INVALID_OPERATION, false);
502 }
503 break;
504 case GL_RED_EXT:
505 if (colorbufferFormat != GL_R8_EXT &&
506 colorbufferFormat != GL_RG8_EXT &&
507 colorbufferFormat != GL_RGB565 &&
508 colorbufferFormat != GL_RGB8_OES &&
509 colorbufferFormat != GL_RGBA4 &&
510 colorbufferFormat != GL_RGB5_A1 &&
511 colorbufferFormat != GL_RGBA8_OES)
512 {
513 return gl::error(GL_INVALID_OPERATION, false);
514 }
515 break;
516 case GL_RG_EXT:
517 if (colorbufferFormat != GL_RG8_EXT &&
518 colorbufferFormat != GL_RGB565 &&
519 colorbufferFormat != GL_RGB8_OES &&
520 colorbufferFormat != GL_RGBA4 &&
521 colorbufferFormat != GL_RGB5_A1 &&
522 colorbufferFormat != GL_RGBA8_OES)
523 {
524 return gl::error(GL_INVALID_OPERATION, false);
525 }
526 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400527 case GL_RGB:
528 if (colorbufferFormat != GL_RGB565 &&
529 colorbufferFormat != GL_RGB8_OES &&
530 colorbufferFormat != GL_RGBA4 &&
531 colorbufferFormat != GL_RGB5_A1 &&
532 colorbufferFormat != GL_RGBA8_OES)
533 {
534 return gl::error(GL_INVALID_OPERATION, false);
535 }
536 break;
537 case GL_LUMINANCE_ALPHA:
538 case GL_RGBA:
539 if (colorbufferFormat != GL_RGBA4 &&
540 colorbufferFormat != GL_RGB5_A1 &&
541 colorbufferFormat != GL_RGBA8_OES)
542 {
543 return gl::error(GL_INVALID_OPERATION, false);
544 }
545 break;
546 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
547 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
548 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
549 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
550 return gl::error(GL_INVALID_OPERATION, false);
551 case GL_DEPTH_COMPONENT:
552 case GL_DEPTH_STENCIL_OES:
553 return gl::error(GL_INVALID_OPERATION, false);
554 default:
555 return gl::error(GL_INVALID_OPERATION, false);
556 }
557 }
558 else
559 {
560 switch (internalformat)
561 {
562 case GL_ALPHA:
563 if (colorbufferFormat != GL_ALPHA8_EXT &&
564 colorbufferFormat != GL_RGBA4 &&
565 colorbufferFormat != GL_RGB5_A1 &&
566 colorbufferFormat != GL_BGRA8_EXT &&
567 colorbufferFormat != GL_RGBA8_OES)
568 {
569 return gl::error(GL_INVALID_OPERATION, false);
570 }
571 break;
572 case GL_LUMINANCE:
Geoff Lang632192d2013-10-04 13:40:46 -0400573 if (colorbufferFormat != GL_R8_EXT &&
574 colorbufferFormat != GL_RG8_EXT &&
575 colorbufferFormat != GL_RGB565 &&
576 colorbufferFormat != GL_RGB8_OES &&
577 colorbufferFormat != GL_RGBA4 &&
578 colorbufferFormat != GL_RGB5_A1 &&
579 colorbufferFormat != GL_BGRA8_EXT &&
580 colorbufferFormat != GL_RGBA8_OES)
581 {
582 return gl::error(GL_INVALID_OPERATION, false);
583 }
584 break;
585 case GL_RED_EXT:
586 if (colorbufferFormat != GL_R8_EXT &&
587 colorbufferFormat != GL_RG8_EXT &&
588 colorbufferFormat != GL_RGB565 &&
589 colorbufferFormat != GL_RGB8_OES &&
590 colorbufferFormat != GL_RGBA4 &&
591 colorbufferFormat != GL_RGB5_A1 &&
592 colorbufferFormat != GL_BGRA8_EXT &&
593 colorbufferFormat != GL_RGBA8_OES)
594 {
595 return gl::error(GL_INVALID_OPERATION, false);
596 }
597 break;
598 case GL_RG_EXT:
599 if (colorbufferFormat != GL_RG8_EXT &&
600 colorbufferFormat != GL_RGB565 &&
601 colorbufferFormat != GL_RGB8_OES &&
602 colorbufferFormat != GL_RGBA4 &&
603 colorbufferFormat != GL_RGB5_A1 &&
604 colorbufferFormat != GL_BGRA8_EXT &&
605 colorbufferFormat != GL_RGBA8_OES)
606 {
607 return gl::error(GL_INVALID_OPERATION, false);
608 }
609 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400610 case GL_RGB:
611 if (colorbufferFormat != GL_RGB565 &&
612 colorbufferFormat != GL_RGB8_OES &&
613 colorbufferFormat != GL_RGBA4 &&
614 colorbufferFormat != GL_RGB5_A1 &&
615 colorbufferFormat != GL_BGRA8_EXT &&
616 colorbufferFormat != GL_RGBA8_OES)
617 {
618 return gl::error(GL_INVALID_OPERATION, false);
619 }
620 break;
621 case GL_LUMINANCE_ALPHA:
622 case GL_RGBA:
623 if (colorbufferFormat != GL_RGBA4 &&
624 colorbufferFormat != GL_RGB5_A1 &&
625 colorbufferFormat != GL_BGRA8_EXT &&
626 colorbufferFormat != GL_RGBA8_OES)
627 {
628 return gl::error(GL_INVALID_OPERATION, false);
629 }
630 break;
631 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
632 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400633 if (context->getCaps().extensions.textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 {
635 return gl::error(GL_INVALID_OPERATION, false);
636 }
637 else
638 {
639 return gl::error(GL_INVALID_ENUM, false);
640 }
641 break;
642 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400643 if (context->getCaps().extensions.textureCompressionDXT3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644 {
645 return gl::error(GL_INVALID_OPERATION, false);
646 }
647 else
648 {
649 return gl::error(GL_INVALID_ENUM, false);
650 }
651 break;
652 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400653 if (context->getCaps().extensions.textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654 {
655 return gl::error(GL_INVALID_OPERATION, false);
656 }
657 else
658 {
659 return gl::error(GL_INVALID_ENUM, false);
660 }
661 break;
662 case GL_DEPTH_COMPONENT:
663 case GL_DEPTH_COMPONENT16:
664 case GL_DEPTH_COMPONENT32_OES:
665 case GL_DEPTH_STENCIL_OES:
666 case GL_DEPTH24_STENCIL8_OES:
Geoff Langcec35902014-04-16 10:52:36 -0400667 if (context->getCaps().extensions.depthTextures)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668 {
669 return gl::error(GL_INVALID_OPERATION, false);
670 }
671 else
672 {
673 return gl::error(GL_INVALID_ENUM, false);
674 }
675 default:
676 return gl::error(GL_INVALID_ENUM, false);
677 }
678 }
679
Geoff Lang784a8fd2013-09-24 12:33:16 -0400680 // If width or height is zero, it is a no-op. Return false without setting an error.
681 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400682}
683
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400684bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400685 GLsizei width, GLsizei height)
686{
687 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
688 {
689 return gl::error(GL_INVALID_ENUM, false);
690 }
691
692 if (width < 1 || height < 1 || levels < 1)
693 {
694 return gl::error(GL_INVALID_VALUE, false);
695 }
696
697 if (target == GL_TEXTURE_CUBE_MAP && width != height)
698 {
699 return gl::error(GL_INVALID_VALUE, false);
700 }
701
702 if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
703 {
704 return gl::error(GL_INVALID_OPERATION, false);
705 }
706
Geoff Lange4a492b2014-06-19 14:14:41 -0400707 GLenum format = gl::GetFormat(internalformat);
708 GLenum type = gl::GetType(internalformat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709
710 if (format == GL_NONE || type == GL_NONE)
711 {
712 return gl::error(GL_INVALID_ENUM, false);
713 }
714
715 switch (target)
716 {
717 case GL_TEXTURE_2D:
718 if (width > context->getMaximum2DTextureDimension() ||
719 height > context->getMaximum2DTextureDimension())
720 {
721 return gl::error(GL_INVALID_VALUE, false);
722 }
723 break;
724 case GL_TEXTURE_CUBE_MAP:
725 if (width > context->getMaximumCubeTextureDimension() ||
726 height > context->getMaximumCubeTextureDimension())
727 {
728 return gl::error(GL_INVALID_VALUE, false);
729 }
730 break;
731 default:
732 return gl::error(GL_INVALID_ENUM, false);
733 }
734
Geoff Langcec35902014-04-16 10:52:36 -0400735 if (levels != 1 && !context->getCaps().extensions.textureNPOT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400736 {
737 if (!gl::isPow2(width) || !gl::isPow2(height))
738 {
739 return gl::error(GL_INVALID_OPERATION, false);
740 }
741 }
742
743 switch (internalformat)
744 {
745 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
746 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400747 if (!context->getCaps().extensions.textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 {
749 return gl::error(GL_INVALID_ENUM, false);
750 }
751 break;
752 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400753 if (!context->getCaps().extensions.textureCompressionDXT3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 {
755 return gl::error(GL_INVALID_ENUM, false);
756 }
757 break;
758 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langcec35902014-04-16 10:52:36 -0400759 if (!context->getCaps().extensions.textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400760 {
761 return gl::error(GL_INVALID_ENUM, false);
762 }
763 break;
764 case GL_RGBA32F_EXT:
765 case GL_RGB32F_EXT:
766 case GL_ALPHA32F_EXT:
767 case GL_LUMINANCE32F_EXT:
768 case GL_LUMINANCE_ALPHA32F_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400769 if (!context->getCaps().extensions.textureFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 {
771 return gl::error(GL_INVALID_ENUM, false);
772 }
773 break;
774 case GL_RGBA16F_EXT:
775 case GL_RGB16F_EXT:
776 case GL_ALPHA16F_EXT:
777 case GL_LUMINANCE16F_EXT:
778 case GL_LUMINANCE_ALPHA16F_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400779 if (!context->getCaps().extensions.textureHalfFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 {
781 return gl::error(GL_INVALID_ENUM, false);
782 }
783 break;
Geoff Lang632192d2013-10-04 13:40:46 -0400784 case GL_R8_EXT:
785 case GL_RG8_EXT:
786 case GL_R16F_EXT:
787 case GL_RG16F_EXT:
788 case GL_R32F_EXT:
789 case GL_RG32F_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400790 if (!context->getCaps().extensions.textureRG)
Geoff Lang632192d2013-10-04 13:40:46 -0400791 {
792 return gl::error(GL_INVALID_ENUM, false);
793 }
794 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 case GL_DEPTH_COMPONENT16:
796 case GL_DEPTH_COMPONENT32_OES:
797 case GL_DEPTH24_STENCIL8_OES:
Geoff Langcec35902014-04-16 10:52:36 -0400798 if (!context->getCaps().extensions.depthTextures)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 {
800 return gl::error(GL_INVALID_ENUM, false);
801 }
802 if (target != GL_TEXTURE_2D)
803 {
804 return gl::error(GL_INVALID_OPERATION, false);
805 }
806 // ANGLE_depth_texture only supports 1-level textures
807 if (levels != 1)
808 {
809 return gl::error(GL_INVALID_OPERATION, false);
810 }
811 break;
812 default:
813 break;
814 }
815
816 gl::Texture *texture = NULL;
817 switch(target)
818 {
819 case GL_TEXTURE_2D:
820 texture = context->getTexture2D();
821 break;
822 case GL_TEXTURE_CUBE_MAP:
823 texture = context->getTextureCubeMap();
824 break;
825 default:
826 UNREACHABLE();
827 }
828
829 if (!texture || texture->id() == 0)
830 {
831 return gl::error(GL_INVALID_OPERATION, false);
832 }
833
834 if (texture->isImmutable())
835 {
836 return gl::error(GL_INVALID_OPERATION, false);
837 }
838
839 return true;
840}
841
Jamie Madill570f7c82014-07-03 10:38:54 -0400842bool ValidateES2FramebufferTextureParameters(const gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400843 GLenum textarget, GLuint texture, GLint level)
844{
845 META_ASSERT(GL_DRAW_FRAMEBUFFER == GL_DRAW_FRAMEBUFFER_ANGLE && GL_READ_FRAMEBUFFER == GL_READ_FRAMEBUFFER_ANGLE);
846
847 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
848 {
849 return gl::error(GL_INVALID_ENUM, false);
850 }
851
Jamie Madillb4472272014-07-03 10:38:55 -0400852 if (!ValidateAttachmentTarget(context, attachment))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400853 {
Jamie Madillb4472272014-07-03 10:38:55 -0400854 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400855 }
856
857 if (texture != 0)
858 {
859 gl::Texture *tex = context->getTexture(texture);
860
861 if (tex == NULL)
862 {
863 return gl::error(GL_INVALID_OPERATION, false);
864 }
865
866 switch (textarget)
867 {
868 case GL_TEXTURE_2D:
869 {
870 if (tex->getTarget() != GL_TEXTURE_2D)
871 {
872 return gl::error(GL_INVALID_OPERATION, false);
873 }
874 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
875 if (tex2d->isCompressed(level))
876 {
877 return gl::error(GL_INVALID_OPERATION, false);
878 }
879 break;
880 }
881
882 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
883 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
884 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
885 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
886 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
887 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
888 {
889 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
890 {
891 return gl::error(GL_INVALID_OPERATION, false);
892 }
893 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
894 if (texcube->isCompressed(textarget, level))
895 {
896 return gl::error(GL_INVALID_OPERATION, false);
897 }
898 break;
899 }
900
901 default:
902 return gl::error(GL_INVALID_ENUM, false);
903 }
904
905 if (level != 0)
906 {
907 return gl::error(GL_INVALID_VALUE, false);
908 }
909 }
910
Jamie Madill570f7c82014-07-03 10:38:54 -0400911 const gl::Framebuffer *framebuffer = NULL;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400912 GLuint framebufferHandle = 0;
913 if (target == GL_READ_FRAMEBUFFER)
914 {
915 framebuffer = context->getReadFramebuffer();
916 framebufferHandle = context->getReadFramebufferHandle();
917 }
918 else
919 {
920 framebuffer = context->getDrawFramebuffer();
921 framebufferHandle = context->getDrawFramebufferHandle();
922 }
923
924 if (framebufferHandle == 0 || !framebuffer)
925 {
926 return gl::error(GL_INVALID_OPERATION, false);
927 }
928
929 return true;
930}
931
932// check for combinations of format and type that are valid for ReadPixels
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400933bool ValidES2ReadFormatType(gl::Context *context, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400934{
935 switch (format)
936 {
937 case GL_RGBA:
938 switch (type)
939 {
940 case GL_UNSIGNED_BYTE:
941 break;
942 default:
943 return false;
944 }
945 break;
946 case GL_BGRA_EXT:
947 switch (type)
948 {
949 case GL_UNSIGNED_BYTE:
950 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
951 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
952 break;
953 default:
954 return false;
955 }
956 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400957 case GL_RG_EXT:
958 case GL_RED_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400959 if (!context->getCaps().extensions.textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400960 {
961 return false;
962 }
963 switch (type)
964 {
965 case GL_UNSIGNED_BYTE:
966 break;
967 default:
968 return false;
969 }
970 break;
971
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400972 default:
973 return false;
974 }
975 return true;
976}
977
978}