blob: 59067f56c0dd3899253c5ae24fcc0d1bb798a533 [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 Lang5d601382014-07-22 15:14:06 -040042 if (gl::GetFormatTypeInfo(format, type).internalFormat != texture->getInternalFormat(level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040043 {
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 {
Geoff Lang5d601382014-07-22 15:14:06 -040082 if (gl::GetFormatTypeInfo(format, type).internalFormat != texture->getInternalFormat(target, level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040083 {
84 return gl::error(GL_INVALID_OPERATION, false);
85 }
86 }
87
88 if (compressed)
89 {
90 if ((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
91 (height % 4 != 0 && height != texture->getHeight(target, 0)))
92 {
93 return gl::error(GL_INVALID_OPERATION, false);
94 }
95 }
96
97 if (xoffset + width > texture->getWidth(target, level) ||
98 yoffset + height > texture->getHeight(target, level))
99 {
100 return gl::error(GL_INVALID_VALUE, false);
101 }
102
103 return true;
104}
105
Geoff Lang005df412013-10-16 14:12:50 -0400106bool ValidateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400107 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
108 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
109{
Jamie Madill6f38f822014-06-06 17:12:20 -0400110 if (!ValidTexture2DDestinationTarget(context, target))
111 {
112 return gl::error(GL_INVALID_ENUM, false);
113 }
114
Geoff Langce635692013-09-24 13:56:32 -0400115 if (!ValidImageSize(context, target, level, width, height, 1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400116 {
117 return gl::error(GL_INVALID_VALUE, false);
118 }
119
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400120 if (level < 0 || xoffset < 0 ||
121 std::numeric_limits<GLsizei>::max() - xoffset < width ||
122 std::numeric_limits<GLsizei>::max() - yoffset < height)
123 {
124 return gl::error(GL_INVALID_VALUE, false);
125 }
126
Geoff Lang005df412013-10-16 14:12:50 -0400127 if (!isSubImage && !isCompressed && internalformat != format)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400128 {
129 return gl::error(GL_INVALID_OPERATION, false);
130 }
131
Geoff Langaae65a42014-05-26 12:43:44 -0400132 const gl::Caps &caps = context->getCaps();
133
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400134 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 {
Geoff Langaae65a42014-05-26 12:43:44 -0400143 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
144 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400145 {
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
Geoff Langaae65a42014-05-26 12:43:44 -0400181 if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level) ||
182 static_cast<GLuint>(height) > (caps.maxCubeMapTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400183 {
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 Langc0b9ef42014-07-02 10:02:37 -0400237 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400243 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400249 if (!context->getExtensions().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:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400297 if (!context->getExtensions().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:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400347 if (!context->getExtensions().sRGB)
Geoff Lang05b05022014-06-11 15:31:45 -0400348 {
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 Langc0b9ef42014-07-02 10:02:37 -0400391 if (context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400401 if (context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400411 if (context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400422 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400443 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400450 if (!context->getExtensions().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
Shannon Woods53a94a82014-06-24 15:20:36 -0400474 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400475 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400476 GLenum textureFormat = gl::GetInternalFormatInfo(textureInternalFormat).format;
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 Langc0b9ef42014-07-02 10:02:37 -0400633 if (context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400643 if (context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400653 if (context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400667 if (context->getExtensions().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 Lang5d601382014-07-22 15:14:06 -0400707 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
708 if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 {
710 return gl::error(GL_INVALID_ENUM, false);
711 }
712
Geoff Langaae65a42014-05-26 12:43:44 -0400713 const gl::Caps &caps = context->getCaps();
714
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400715 switch (target)
716 {
717 case GL_TEXTURE_2D:
Geoff Langaae65a42014-05-26 12:43:44 -0400718 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
719 static_cast<GLuint>(height) > caps.max2DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720 {
721 return gl::error(GL_INVALID_VALUE, false);
722 }
723 break;
724 case GL_TEXTURE_CUBE_MAP:
Geoff Langaae65a42014-05-26 12:43:44 -0400725 if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize ||
726 static_cast<GLuint>(height) > caps.maxCubeMapTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400727 {
728 return gl::error(GL_INVALID_VALUE, false);
729 }
730 break;
731 default:
732 return gl::error(GL_INVALID_ENUM, false);
733 }
734
Geoff Langc0b9ef42014-07-02 10:02:37 -0400735 if (levels != 1 && !context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400747 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400753 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400759 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400769 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400779 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400790 if (!context->getExtensions().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 Langc0b9ef42014-07-02 10:02:37 -0400798 if (!context->getExtensions().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
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400842// check for combinations of format and type that are valid for ReadPixels
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400843bool ValidES2ReadFormatType(gl::Context *context, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400844{
845 switch (format)
846 {
847 case GL_RGBA:
848 switch (type)
849 {
850 case GL_UNSIGNED_BYTE:
851 break;
852 default:
853 return false;
854 }
855 break;
856 case GL_BGRA_EXT:
857 switch (type)
858 {
859 case GL_UNSIGNED_BYTE:
860 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
861 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
862 break;
863 default:
864 return false;
865 }
866 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400867 case GL_RG_EXT:
868 case GL_RED_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400869 if (!context->getExtensions().textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400870 {
871 return false;
872 }
873 switch (type)
874 {
875 case GL_UNSIGNED_BYTE:
876 break;
877 default:
878 return false;
879 }
880 break;
881
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 default:
883 return false;
884 }
885 return true;
886}
887
888}