blob: 1a0940032218a425661266337ede4d1d4396bdbb [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
Geoff Langaae65a42014-05-26 12:43:44 -0400134 const gl::Caps &caps = context->getCaps();
135
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400136 gl::Texture *texture = NULL;
137 bool textureCompressed = false;
138 GLenum textureInternalFormat = GL_NONE;
139 GLint textureLevelWidth = 0;
140 GLint textureLevelHeight = 0;
141 switch (target)
142 {
143 case GL_TEXTURE_2D:
144 {
Geoff Langaae65a42014-05-26 12:43:44 -0400145 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
146 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400147 {
148 return gl::error(GL_INVALID_VALUE, false);
149 }
150
151 gl::Texture2D *tex2d = context->getTexture2D();
152 if (tex2d)
153 {
154 textureCompressed = tex2d->isCompressed(level);
155 textureInternalFormat = tex2d->getInternalFormat(level);
156 textureLevelWidth = tex2d->getWidth(level);
157 textureLevelHeight = tex2d->getHeight(level);
158 texture = tex2d;
159 }
160
161 if (isSubImage && !validateSubImageParams2D(isCompressed, width, height, xoffset, yoffset,
162 level, format, type, tex2d))
163 {
164 return false;
165 }
166
167 texture = tex2d;
168 }
169 break;
170
171 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
172 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
173 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
174 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
175 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
176 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
177 {
178 if (!isSubImage && width != height)
179 {
180 return gl::error(GL_INVALID_VALUE, false);
181 }
182
Geoff Langaae65a42014-05-26 12:43:44 -0400183 if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level) ||
184 static_cast<GLuint>(height) > (caps.maxCubeMapTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400185 {
186 return gl::error(GL_INVALID_VALUE, false);
187 }
188
189 gl::TextureCubeMap *texCube = context->getTextureCubeMap();
190 if (texCube)
191 {
192 textureCompressed = texCube->isCompressed(target, level);
193 textureInternalFormat = texCube->getInternalFormat(target, level);
194 textureLevelWidth = texCube->getWidth(target, level);
195 textureLevelHeight = texCube->getHeight(target, level);
196 texture = texCube;
197 }
198
199 if (isSubImage && !validateSubImageParamsCube(isCompressed, width, height, xoffset, yoffset,
200 target, level, format, type, texCube))
201 {
202 return false;
203 }
204 }
205 break;
206
207 default:
208 return gl::error(GL_INVALID_ENUM, false);
209 }
210
211 if (!texture)
212 {
213 return gl::error(GL_INVALID_OPERATION, false);
214 }
215
216 if (!isSubImage && texture->isImmutable())
217 {
218 return gl::error(GL_INVALID_OPERATION, false);
219 }
220
221 // Verify zero border
222 if (border != 0)
223 {
224 return gl::error(GL_INVALID_VALUE, false);
225 }
226
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400227 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
228 if (isCompressed)
229 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400230 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
231 {
232 return gl::error(GL_INVALID_OPERATION, false);
233 }
234
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400235 switch (actualInternalFormat)
236 {
237 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
238 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400239 if (!context->getExtensions().textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400240 {
241 return gl::error(GL_INVALID_ENUM, false);
242 }
243 break;
244 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400245 if (!context->getExtensions().textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400246 {
247 return gl::error(GL_INVALID_ENUM, false);
248 }
249 break;
250 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400251 if (!context->getExtensions().textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400252 {
253 return gl::error(GL_INVALID_ENUM, false);
254 }
255 break;
256 default:
257 return gl::error(GL_INVALID_ENUM, false);
258 }
259 }
260 else
261 {
262 // validate <type> by itself (used as secondary key below)
263 switch (type)
264 {
265 case GL_UNSIGNED_BYTE:
266 case GL_UNSIGNED_SHORT_5_6_5:
267 case GL_UNSIGNED_SHORT_4_4_4_4:
268 case GL_UNSIGNED_SHORT_5_5_5_1:
269 case GL_UNSIGNED_SHORT:
270 case GL_UNSIGNED_INT:
271 case GL_UNSIGNED_INT_24_8_OES:
272 case GL_HALF_FLOAT_OES:
273 case GL_FLOAT:
274 break;
275 default:
276 return gl::error(GL_INVALID_ENUM, false);
277 }
278
279 // validate <format> + <type> combinations
280 // - invalid <format> -> sets INVALID_ENUM
281 // - invalid <format>+<type> combination -> sets INVALID_OPERATION
282 switch (format)
283 {
284 case GL_ALPHA:
285 case GL_LUMINANCE:
286 case GL_LUMINANCE_ALPHA:
287 switch (type)
288 {
289 case GL_UNSIGNED_BYTE:
290 case GL_FLOAT:
291 case GL_HALF_FLOAT_OES:
292 break;
293 default:
294 return gl::error(GL_INVALID_OPERATION, false);
295 }
296 break;
Geoff Lang632192d2013-10-04 13:40:46 -0400297 case GL_RED:
Geoff Langcec35902014-04-16 10:52:36 -0400298 case GL_RG:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400299 if (!context->getExtensions().textureRG)
Geoff Lang632192d2013-10-04 13:40:46 -0400300 {
301 return gl::error(GL_INVALID_ENUM, false);
302 }
303 switch (type)
304 {
305 case GL_UNSIGNED_BYTE:
306 case GL_FLOAT:
307 case GL_HALF_FLOAT_OES:
308 break;
309 default:
310 return gl::error(GL_INVALID_OPERATION, false);
311 }
312 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400313 case GL_RGB:
314 switch (type)
315 {
316 case GL_UNSIGNED_BYTE:
317 case GL_UNSIGNED_SHORT_5_6_5:
318 case GL_FLOAT:
319 case GL_HALF_FLOAT_OES:
320 break;
321 default:
322 return gl::error(GL_INVALID_OPERATION, false);
323 }
324 break;
325 case GL_RGBA:
326 switch (type)
327 {
328 case GL_UNSIGNED_BYTE:
329 case GL_UNSIGNED_SHORT_4_4_4_4:
330 case GL_UNSIGNED_SHORT_5_5_5_1:
331 case GL_FLOAT:
332 case GL_HALF_FLOAT_OES:
333 break;
334 default:
335 return gl::error(GL_INVALID_OPERATION, false);
336 }
337 break;
338 case GL_BGRA_EXT:
339 switch (type)
340 {
341 case GL_UNSIGNED_BYTE:
342 break;
343 default:
344 return gl::error(GL_INVALID_OPERATION, false);
345 }
346 break;
Geoff Lang05b05022014-06-11 15:31:45 -0400347 case GL_SRGB_EXT:
348 case GL_SRGB_ALPHA_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400349 if (!context->getExtensions().sRGB)
Geoff Lang05b05022014-06-11 15:31:45 -0400350 {
351 return gl::error(GL_INVALID_ENUM, false);
352 }
353 switch (type)
354 {
355 case GL_UNSIGNED_BYTE:
356 break;
357 default:
358 return gl::error(GL_INVALID_OPERATION, false);
359 }
360 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400361 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below
362 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
363 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
364 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
365 break;
366 case GL_DEPTH_COMPONENT:
367 switch (type)
368 {
369 case GL_UNSIGNED_SHORT:
370 case GL_UNSIGNED_INT:
371 break;
372 default:
373 return gl::error(GL_INVALID_OPERATION, false);
374 }
375 break;
376 case GL_DEPTH_STENCIL_OES:
377 switch (type)
378 {
379 case GL_UNSIGNED_INT_24_8_OES:
380 break;
381 default:
382 return gl::error(GL_INVALID_OPERATION, false);
383 }
384 break;
385 default:
386 return gl::error(GL_INVALID_ENUM, false);
387 }
388
389 switch (format)
390 {
391 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
392 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400393 if (context->getExtensions().textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400394 {
395 return gl::error(GL_INVALID_OPERATION, false);
396 }
397 else
398 {
399 return gl::error(GL_INVALID_ENUM, false);
400 }
401 break;
402 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400403 if (context->getExtensions().textureCompressionDXT3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400404 {
405 return gl::error(GL_INVALID_OPERATION, false);
406 }
407 else
408 {
409 return gl::error(GL_INVALID_ENUM, false);
410 }
411 break;
412 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400413 if (context->getExtensions().textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400414 {
415 return gl::error(GL_INVALID_OPERATION, false);
416 }
417 else
418 {
419 return gl::error(GL_INVALID_ENUM, false);
420 }
421 break;
422 case GL_DEPTH_COMPONENT:
423 case GL_DEPTH_STENCIL_OES:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400424 if (!context->getExtensions().depthTextures)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400425 {
426 return gl::error(GL_INVALID_VALUE, false);
427 }
428 if (target != GL_TEXTURE_2D)
429 {
430 return gl::error(GL_INVALID_OPERATION, false);
431 }
432 // OES_depth_texture supports loading depth data and multiple levels,
433 // but ANGLE_depth_texture does not
434 if (pixels != NULL || level != 0)
435 {
436 return gl::error(GL_INVALID_OPERATION, false);
437 }
438 break;
439 default:
440 break;
441 }
442
443 if (type == GL_FLOAT)
444 {
Geoff Langc0b9ef42014-07-02 10:02:37 -0400445 if (!context->getExtensions().textureFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400446 {
447 return gl::error(GL_INVALID_ENUM, false);
448 }
449 }
450 else if (type == GL_HALF_FLOAT_OES)
451 {
Geoff Langc0b9ef42014-07-02 10:02:37 -0400452 if (!context->getExtensions().textureHalfFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400453 {
454 return gl::error(GL_INVALID_ENUM, false);
455 }
456 }
457 }
458
459 return true;
460}
461
462
463
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400464bool ValidateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400465 GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
466 GLint border)
467{
Jamie Madill560a8d82014-05-21 13:06:20 -0400468 GLenum textureInternalFormat = GL_NONE;
Shannon Woods4dfed832014-03-17 20:03:39 -0400469
Jamie Madill560a8d82014-05-21 13:06:20 -0400470 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
471 xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400472 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400473 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400474 }
475
Shannon Woods53a94a82014-06-24 15:20:36 -0400476 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400477 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400478 GLenum textureFormat = gl::GetFormat(textureInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400479
480 // [OpenGL ES 2.0.24] table 3.9
481 if (isSubImage)
482 {
483 switch (textureFormat)
484 {
485 case GL_ALPHA:
486 if (colorbufferFormat != GL_ALPHA8_EXT &&
487 colorbufferFormat != GL_RGBA4 &&
488 colorbufferFormat != GL_RGB5_A1 &&
489 colorbufferFormat != GL_RGBA8_OES)
490 {
491 return gl::error(GL_INVALID_OPERATION, false);
492 }
493 break;
494 case GL_LUMINANCE:
Geoff Lang632192d2013-10-04 13:40:46 -0400495 if (colorbufferFormat != GL_R8_EXT &&
496 colorbufferFormat != GL_RG8_EXT &&
497 colorbufferFormat != GL_RGB565 &&
498 colorbufferFormat != GL_RGB8_OES &&
499 colorbufferFormat != GL_RGBA4 &&
500 colorbufferFormat != GL_RGB5_A1 &&
501 colorbufferFormat != GL_RGBA8_OES)
502 {
503 return gl::error(GL_INVALID_OPERATION, false);
504 }
505 break;
506 case GL_RED_EXT:
507 if (colorbufferFormat != GL_R8_EXT &&
508 colorbufferFormat != GL_RG8_EXT &&
509 colorbufferFormat != GL_RGB565 &&
510 colorbufferFormat != GL_RGB8_OES &&
511 colorbufferFormat != GL_RGBA4 &&
512 colorbufferFormat != GL_RGB5_A1 &&
513 colorbufferFormat != GL_RGBA8_OES)
514 {
515 return gl::error(GL_INVALID_OPERATION, false);
516 }
517 break;
518 case GL_RG_EXT:
519 if (colorbufferFormat != GL_RG8_EXT &&
520 colorbufferFormat != GL_RGB565 &&
521 colorbufferFormat != GL_RGB8_OES &&
522 colorbufferFormat != GL_RGBA4 &&
523 colorbufferFormat != GL_RGB5_A1 &&
524 colorbufferFormat != GL_RGBA8_OES)
525 {
526 return gl::error(GL_INVALID_OPERATION, false);
527 }
528 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400529 case GL_RGB:
530 if (colorbufferFormat != GL_RGB565 &&
531 colorbufferFormat != GL_RGB8_OES &&
532 colorbufferFormat != GL_RGBA4 &&
533 colorbufferFormat != GL_RGB5_A1 &&
534 colorbufferFormat != GL_RGBA8_OES)
535 {
536 return gl::error(GL_INVALID_OPERATION, false);
537 }
538 break;
539 case GL_LUMINANCE_ALPHA:
540 case GL_RGBA:
541 if (colorbufferFormat != GL_RGBA4 &&
542 colorbufferFormat != GL_RGB5_A1 &&
543 colorbufferFormat != GL_RGBA8_OES)
544 {
545 return gl::error(GL_INVALID_OPERATION, false);
546 }
547 break;
548 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
549 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
550 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
551 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
552 return gl::error(GL_INVALID_OPERATION, false);
553 case GL_DEPTH_COMPONENT:
554 case GL_DEPTH_STENCIL_OES:
555 return gl::error(GL_INVALID_OPERATION, false);
556 default:
557 return gl::error(GL_INVALID_OPERATION, false);
558 }
559 }
560 else
561 {
562 switch (internalformat)
563 {
564 case GL_ALPHA:
565 if (colorbufferFormat != GL_ALPHA8_EXT &&
566 colorbufferFormat != GL_RGBA4 &&
567 colorbufferFormat != GL_RGB5_A1 &&
568 colorbufferFormat != GL_BGRA8_EXT &&
569 colorbufferFormat != GL_RGBA8_OES)
570 {
571 return gl::error(GL_INVALID_OPERATION, false);
572 }
573 break;
574 case GL_LUMINANCE:
Geoff Lang632192d2013-10-04 13:40:46 -0400575 if (colorbufferFormat != GL_R8_EXT &&
576 colorbufferFormat != GL_RG8_EXT &&
577 colorbufferFormat != GL_RGB565 &&
578 colorbufferFormat != GL_RGB8_OES &&
579 colorbufferFormat != GL_RGBA4 &&
580 colorbufferFormat != GL_RGB5_A1 &&
581 colorbufferFormat != GL_BGRA8_EXT &&
582 colorbufferFormat != GL_RGBA8_OES)
583 {
584 return gl::error(GL_INVALID_OPERATION, false);
585 }
586 break;
587 case GL_RED_EXT:
588 if (colorbufferFormat != GL_R8_EXT &&
589 colorbufferFormat != GL_RG8_EXT &&
590 colorbufferFormat != GL_RGB565 &&
591 colorbufferFormat != GL_RGB8_OES &&
592 colorbufferFormat != GL_RGBA4 &&
593 colorbufferFormat != GL_RGB5_A1 &&
594 colorbufferFormat != GL_BGRA8_EXT &&
595 colorbufferFormat != GL_RGBA8_OES)
596 {
597 return gl::error(GL_INVALID_OPERATION, false);
598 }
599 break;
600 case GL_RG_EXT:
601 if (colorbufferFormat != GL_RG8_EXT &&
602 colorbufferFormat != GL_RGB565 &&
603 colorbufferFormat != GL_RGB8_OES &&
604 colorbufferFormat != GL_RGBA4 &&
605 colorbufferFormat != GL_RGB5_A1 &&
606 colorbufferFormat != GL_BGRA8_EXT &&
607 colorbufferFormat != GL_RGBA8_OES)
608 {
609 return gl::error(GL_INVALID_OPERATION, false);
610 }
611 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 case GL_RGB:
613 if (colorbufferFormat != GL_RGB565 &&
614 colorbufferFormat != GL_RGB8_OES &&
615 colorbufferFormat != GL_RGBA4 &&
616 colorbufferFormat != GL_RGB5_A1 &&
617 colorbufferFormat != GL_BGRA8_EXT &&
618 colorbufferFormat != GL_RGBA8_OES)
619 {
620 return gl::error(GL_INVALID_OPERATION, false);
621 }
622 break;
623 case GL_LUMINANCE_ALPHA:
624 case GL_RGBA:
625 if (colorbufferFormat != GL_RGBA4 &&
626 colorbufferFormat != GL_RGB5_A1 &&
627 colorbufferFormat != GL_BGRA8_EXT &&
628 colorbufferFormat != GL_RGBA8_OES)
629 {
630 return gl::error(GL_INVALID_OPERATION, false);
631 }
632 break;
633 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
634 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400635 if (context->getExtensions().textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636 {
637 return gl::error(GL_INVALID_OPERATION, false);
638 }
639 else
640 {
641 return gl::error(GL_INVALID_ENUM, false);
642 }
643 break;
644 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400645 if (context->getExtensions().textureCompressionDXT3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 {
647 return gl::error(GL_INVALID_OPERATION, false);
648 }
649 else
650 {
651 return gl::error(GL_INVALID_ENUM, false);
652 }
653 break;
654 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400655 if (context->getExtensions().textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656 {
657 return gl::error(GL_INVALID_OPERATION, false);
658 }
659 else
660 {
661 return gl::error(GL_INVALID_ENUM, false);
662 }
663 break;
664 case GL_DEPTH_COMPONENT:
665 case GL_DEPTH_COMPONENT16:
666 case GL_DEPTH_COMPONENT32_OES:
667 case GL_DEPTH_STENCIL_OES:
668 case GL_DEPTH24_STENCIL8_OES:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400669 if (context->getExtensions().depthTextures)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 {
671 return gl::error(GL_INVALID_OPERATION, false);
672 }
673 else
674 {
675 return gl::error(GL_INVALID_ENUM, false);
676 }
677 default:
678 return gl::error(GL_INVALID_ENUM, false);
679 }
680 }
681
Geoff Lang784a8fd2013-09-24 12:33:16 -0400682 // If width or height is zero, it is a no-op. Return false without setting an error.
683 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684}
685
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400686bool ValidateES2TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 GLsizei width, GLsizei height)
688{
689 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
690 {
691 return gl::error(GL_INVALID_ENUM, false);
692 }
693
694 if (width < 1 || height < 1 || levels < 1)
695 {
696 return gl::error(GL_INVALID_VALUE, false);
697 }
698
699 if (target == GL_TEXTURE_CUBE_MAP && width != height)
700 {
701 return gl::error(GL_INVALID_VALUE, false);
702 }
703
704 if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
705 {
706 return gl::error(GL_INVALID_OPERATION, false);
707 }
708
Geoff Lange4a492b2014-06-19 14:14:41 -0400709 GLenum format = gl::GetFormat(internalformat);
710 GLenum type = gl::GetType(internalformat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400711
712 if (format == GL_NONE || type == GL_NONE)
713 {
714 return gl::error(GL_INVALID_ENUM, false);
715 }
716
Geoff Langaae65a42014-05-26 12:43:44 -0400717 const gl::Caps &caps = context->getCaps();
718
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 switch (target)
720 {
721 case GL_TEXTURE_2D:
Geoff Langaae65a42014-05-26 12:43:44 -0400722 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
723 static_cast<GLuint>(height) > caps.max2DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400724 {
725 return gl::error(GL_INVALID_VALUE, false);
726 }
727 break;
728 case GL_TEXTURE_CUBE_MAP:
Geoff Langaae65a42014-05-26 12:43:44 -0400729 if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize ||
730 static_cast<GLuint>(height) > caps.maxCubeMapTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400731 {
732 return gl::error(GL_INVALID_VALUE, false);
733 }
734 break;
735 default:
736 return gl::error(GL_INVALID_ENUM, false);
737 }
738
Geoff Langc0b9ef42014-07-02 10:02:37 -0400739 if (levels != 1 && !context->getExtensions().textureNPOT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400740 {
741 if (!gl::isPow2(width) || !gl::isPow2(height))
742 {
743 return gl::error(GL_INVALID_OPERATION, false);
744 }
745 }
746
747 switch (internalformat)
748 {
749 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
750 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400751 if (!context->getExtensions().textureCompressionDXT1)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400752 {
753 return gl::error(GL_INVALID_ENUM, false);
754 }
755 break;
756 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400757 if (!context->getExtensions().textureCompressionDXT3)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 {
759 return gl::error(GL_INVALID_ENUM, false);
760 }
761 break;
762 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400763 if (!context->getExtensions().textureCompressionDXT5)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 {
765 return gl::error(GL_INVALID_ENUM, false);
766 }
767 break;
768 case GL_RGBA32F_EXT:
769 case GL_RGB32F_EXT:
770 case GL_ALPHA32F_EXT:
771 case GL_LUMINANCE32F_EXT:
772 case GL_LUMINANCE_ALPHA32F_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400773 if (!context->getExtensions().textureFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 {
775 return gl::error(GL_INVALID_ENUM, false);
776 }
777 break;
778 case GL_RGBA16F_EXT:
779 case GL_RGB16F_EXT:
780 case GL_ALPHA16F_EXT:
781 case GL_LUMINANCE16F_EXT:
782 case GL_LUMINANCE_ALPHA16F_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400783 if (!context->getExtensions().textureHalfFloat)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 {
785 return gl::error(GL_INVALID_ENUM, false);
786 }
787 break;
Geoff Lang632192d2013-10-04 13:40:46 -0400788 case GL_R8_EXT:
789 case GL_RG8_EXT:
790 case GL_R16F_EXT:
791 case GL_RG16F_EXT:
792 case GL_R32F_EXT:
793 case GL_RG32F_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400794 if (!context->getExtensions().textureRG)
Geoff Lang632192d2013-10-04 13:40:46 -0400795 {
796 return gl::error(GL_INVALID_ENUM, false);
797 }
798 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 case GL_DEPTH_COMPONENT16:
800 case GL_DEPTH_COMPONENT32_OES:
801 case GL_DEPTH24_STENCIL8_OES:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400802 if (!context->getExtensions().depthTextures)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 {
804 return gl::error(GL_INVALID_ENUM, false);
805 }
806 if (target != GL_TEXTURE_2D)
807 {
808 return gl::error(GL_INVALID_OPERATION, false);
809 }
810 // ANGLE_depth_texture only supports 1-level textures
811 if (levels != 1)
812 {
813 return gl::error(GL_INVALID_OPERATION, false);
814 }
815 break;
816 default:
817 break;
818 }
819
820 gl::Texture *texture = NULL;
821 switch(target)
822 {
823 case GL_TEXTURE_2D:
824 texture = context->getTexture2D();
825 break;
826 case GL_TEXTURE_CUBE_MAP:
827 texture = context->getTextureCubeMap();
828 break;
829 default:
830 UNREACHABLE();
831 }
832
833 if (!texture || texture->id() == 0)
834 {
835 return gl::error(GL_INVALID_OPERATION, false);
836 }
837
838 if (texture->isImmutable())
839 {
840 return gl::error(GL_INVALID_OPERATION, false);
841 }
842
843 return true;
844}
845
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846// check for combinations of format and type that are valid for ReadPixels
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400847bool ValidES2ReadFormatType(gl::Context *context, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400848{
849 switch (format)
850 {
851 case GL_RGBA:
852 switch (type)
853 {
854 case GL_UNSIGNED_BYTE:
855 break;
856 default:
857 return false;
858 }
859 break;
860 case GL_BGRA_EXT:
861 switch (type)
862 {
863 case GL_UNSIGNED_BYTE:
864 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
865 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
866 break;
867 default:
868 return false;
869 }
870 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400871 case GL_RG_EXT:
872 case GL_RED_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400873 if (!context->getExtensions().textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400874 {
875 return false;
876 }
877 switch (type)
878 {
879 case GL_UNSIGNED_BYTE:
880 break;
881 default:
882 return false;
883 }
884 break;
885
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400886 default:
887 return false;
888 }
889 return true;
890}
891
892}