blob: 326e5aa06ca91c9af2e36110e933565b7ec151cf [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// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters
9
10#include "libGLESv2/validationES3.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
21namespace gl
22{
23
Geoff Lang005df412013-10-16 14:12:50 -040024bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillefb2a6f2013-09-24 10:22:42 -040026 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Geoff Lange8ebe7f2013-08-05 15:03:13 -040027{
28 // Validate image size
Geoff Langce635692013-09-24 13:56:32 -040029 if (!ValidImageSize(context, target, level, width, height, depth))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040030 {
31 return gl::error(GL_INVALID_VALUE, false);
32 }
33
Geoff Lange8ebe7f2013-08-05 15:03:13 -040034 // Verify zero border
35 if (border != 0)
36 {
37 return gl::error(GL_INVALID_VALUE, false);
38 }
39
Geoff Lange8ebe7f2013-08-05 15:03:13 -040040 gl::Texture *texture = NULL;
41 bool textureCompressed = false;
42 GLenum textureInternalFormat = GL_NONE;
43 GLint textureLevelWidth = 0;
44 GLint textureLevelHeight = 0;
45 GLint textureLevelDepth = 0;
46 switch (target)
47 {
48 case GL_TEXTURE_2D:
49 {
50 if (width > (context->getMaximum2DTextureDimension() >> level) ||
51 height > (context->getMaximum2DTextureDimension() >> level))
52 {
53 return gl::error(GL_INVALID_VALUE, false);
54 }
55
56 gl::Texture2D *texture2d = context->getTexture2D();
57 if (texture2d)
58 {
59 textureCompressed = texture2d->isCompressed(level);
60 textureInternalFormat = texture2d->getInternalFormat(level);
61 textureLevelWidth = texture2d->getWidth(level);
62 textureLevelHeight = texture2d->getHeight(level);
63 textureLevelDepth = 1;
64 texture = texture2d;
65 }
66 }
67 break;
68
69 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
70 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
71 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
72 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
73 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
74 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
75 {
76 if (!isSubImage && width != height)
77 {
78 return gl::error(GL_INVALID_VALUE, false);
79 }
80
81 if (width > (context->getMaximumCubeTextureDimension() >> level))
82 {
83 return gl::error(GL_INVALID_VALUE, false);
84 }
85
86 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
87 if (textureCube)
88 {
89 textureCompressed = textureCube->isCompressed(target, level);
90 textureInternalFormat = textureCube->getInternalFormat(target, level);
91 textureLevelWidth = textureCube->getWidth(target, level);
92 textureLevelHeight = textureCube->getHeight(target, level);
93 textureLevelDepth = 1;
94 texture = textureCube;
95 }
96 }
97 break;
98
99 case GL_TEXTURE_3D:
100 {
101 if (width > (context->getMaximum3DTextureDimension() >> level) ||
102 height > (context->getMaximum3DTextureDimension() >> level) ||
103 depth > (context->getMaximum3DTextureDimension() >> level))
104 {
105 return gl::error(GL_INVALID_VALUE, false);
106 }
107
108 gl::Texture3D *texture3d = context->getTexture3D();
109 if (texture3d)
110 {
111 textureCompressed = texture3d->isCompressed(level);
112 textureInternalFormat = texture3d->getInternalFormat(level);
113 textureLevelWidth = texture3d->getWidth(level);
114 textureLevelHeight = texture3d->getHeight(level);
115 textureLevelDepth = texture3d->getDepth(level);
116 texture = texture3d;
117 }
118 }
119 break;
120
121 case GL_TEXTURE_2D_ARRAY:
122 {
123 if (width > (context->getMaximum2DTextureDimension() >> level) ||
124 height > (context->getMaximum2DTextureDimension() >> level) ||
125 depth > (context->getMaximum2DArrayTextureLayers() >> level))
126 {
127 return gl::error(GL_INVALID_VALUE, false);
128 }
129
130 gl::Texture2DArray *texture2darray = context->getTexture2DArray();
131 if (texture2darray)
132 {
133 textureCompressed = texture2darray->isCompressed(level);
134 textureInternalFormat = texture2darray->getInternalFormat(level);
135 textureLevelWidth = texture2darray->getWidth(level);
136 textureLevelHeight = texture2darray->getHeight(level);
Jamie Madillb8f8b892014-01-07 10:12:50 -0500137 textureLevelDepth = texture2darray->getLayers(level);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400138 texture = texture2darray;
139 }
140 }
141 break;
142
143 default:
144 return gl::error(GL_INVALID_ENUM, false);
145 }
146
147 if (!texture)
148 {
149 return gl::error(GL_INVALID_OPERATION, false);
150 }
151
152 if (texture->isImmutable() && !isSubImage)
153 {
154 return gl::error(GL_INVALID_OPERATION, false);
155 }
156
157 // Validate texture formats
158 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
159 if (isCompressed)
160 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400161 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
162 {
163 return gl::error(GL_INVALID_OPERATION, false);
164 }
165
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400166 if (!gl::IsFormatCompressed(actualInternalFormat, context->getClientVersion()))
167 {
168 return gl::error(GL_INVALID_ENUM, false);
169 }
170
171 if (target == GL_TEXTURE_3D)
172 {
173 return gl::error(GL_INVALID_OPERATION, false);
174 }
175 }
176 else
177 {
178 if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
179 !gl::IsValidFormat(format, context->getClientVersion()) ||
180 !gl::IsValidType(type, context->getClientVersion()))
181 {
182 return gl::error(GL_INVALID_ENUM, false);
183 }
184
185 if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion()))
186 {
187 return gl::error(GL_INVALID_OPERATION, false);
188 }
189
190 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
191 {
192 return gl::error(GL_INVALID_OPERATION, false);
193 }
194 }
195
196 // Validate sub image parameters
197 if (isSubImage)
198 {
199 if (isCompressed != textureCompressed)
200 {
201 return gl::error(GL_INVALID_OPERATION, false);
202 }
203
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400204 if (isCompressed)
205 {
206 if ((width % 4 != 0 && width != textureLevelWidth) ||
207 (height % 4 != 0 && height != textureLevelHeight))
208 {
209 return gl::error(GL_INVALID_OPERATION, false);
210 }
211 }
212
213 if (width == 0 || height == 0 || depth == 0)
214 {
215 return false;
216 }
217
218 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
219 {
220 return gl::error(GL_INVALID_VALUE, false);
221 }
222
223 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
224 std::numeric_limits<GLsizei>::max() - yoffset < height ||
225 std::numeric_limits<GLsizei>::max() - zoffset < depth)
226 {
227 return gl::error(GL_INVALID_VALUE, false);
228 }
229
230 if (xoffset + width > textureLevelWidth ||
231 yoffset + height > textureLevelHeight ||
232 zoffset + depth > textureLevelDepth)
233 {
234 return gl::error(GL_INVALID_VALUE, false);
235 }
236 }
237
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400238 // Check for pixel unpack buffer related API errors
239 gl::Buffer *pixelUnpackBuffer = context->getPixelUnpackBuffer();
240 if (pixelUnpackBuffer != NULL)
241 {
242 // ...the data would be unpacked from the buffer object such that the memory reads required
243 // would exceed the data store size.
244 size_t widthSize = static_cast<size_t>(width);
245 size_t heightSize = static_cast<size_t>(height);
246 size_t depthSize = static_cast<size_t>(depth);
247 size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(actualInternalFormat, context->getClientVersion()));
248
249 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
250 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
251 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
252 {
253 // Overflow past the end of the buffer
254 return gl::error(GL_INVALID_OPERATION, false);
255 }
256
257 size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes;
258 size_t offset = reinterpret_cast<size_t>(pixels);
259
260 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->size())))
261 {
262 // Overflow past the end of the buffer
263 return gl::error(GL_INVALID_OPERATION, false);
264 }
265
266 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
267 // indicated by type.
268 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type));
269
270 if ((offset % dataBytesPerPixel) != 0)
271 {
272 return gl::error(GL_INVALID_OPERATION, false);
273 }
274
Jamie Madill7a5f7382014-03-05 15:01:24 -0500275 // ...the buffer object's data store is currently mapped.
276 if (pixelUnpackBuffer->mapped())
277 {
278 return gl::error(GL_INVALID_OPERATION, false);
279 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400280 }
281
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400282 return true;
283}
284
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400285bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400286 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
287 GLsizei width, GLsizei height, GLint border)
288{
Shannon Woods4dfed832014-03-17 20:03:39 -0400289 if (!ValidTexture2DDestinationTarget(context, target))
290 {
291 return gl::error(GL_INVALID_ENUM, false);
292 }
293
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400294 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
295 {
296 return gl::error(GL_INVALID_VALUE, false);
297 }
298
299 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
300 {
301 return gl::error(GL_INVALID_VALUE, false);
302 }
303
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400304 if (border != 0)
305 {
306 return gl::error(GL_INVALID_VALUE, false);
307 }
308
Geoff Langce635692013-09-24 13:56:32 -0400309 if (!ValidMipLevel(context, target, level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400310 {
311 return gl::error(GL_INVALID_VALUE, false);
312 }
313
314 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
315
316 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
317 {
318 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
319 }
320
321 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
322 {
323 return gl::error(GL_INVALID_OPERATION, false);
324 }
325
326 gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
327 GLenum colorbufferInternalFormat = source->getInternalFormat();
328 gl::Texture *texture = NULL;
329 GLenum textureInternalFormat = GL_NONE;
330 bool textureCompressed = false;
331 bool textureIsDepth = false;
332 GLint textureLevelWidth = 0;
333 GLint textureLevelHeight = 0;
334 GLint textureLevelDepth = 0;
335 switch (target)
336 {
337 case GL_TEXTURE_2D:
338 {
339 gl::Texture2D *texture2d = context->getTexture2D();
340 if (texture2d)
341 {
342 textureInternalFormat = texture2d->getInternalFormat(level);
343 textureCompressed = texture2d->isCompressed(level);
344 textureIsDepth = texture2d->isDepth(level);
345 textureLevelWidth = texture2d->getWidth(level);
346 textureLevelHeight = texture2d->getHeight(level);
347 textureLevelDepth = 1;
348 texture = texture2d;
349 }
350 }
351 break;
352
353 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
354 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
355 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
356 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
357 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
358 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
359 {
360 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
361 if (textureCube)
362 {
363 textureInternalFormat = textureCube->getInternalFormat(target, level);
364 textureCompressed = textureCube->isCompressed(target, level);
365 textureIsDepth = false;
366 textureLevelWidth = textureCube->getWidth(target, level);
367 textureLevelHeight = textureCube->getHeight(target, level);
368 textureLevelDepth = 1;
369 texture = textureCube;
370 }
371 }
372 break;
373
374 case GL_TEXTURE_2D_ARRAY:
375 {
376 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
377 if (texture2dArray)
378 {
379 textureInternalFormat = texture2dArray->getInternalFormat(level);
380 textureCompressed = texture2dArray->isCompressed(level);
381 textureIsDepth = texture2dArray->isDepth(level);
382 textureLevelWidth = texture2dArray->getWidth(level);
383 textureLevelHeight = texture2dArray->getHeight(level);
Jamie Madillb8f8b892014-01-07 10:12:50 -0500384 textureLevelDepth = texture2dArray->getLayers(level);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400385 texture = texture2dArray;
386 }
387 }
388 break;
389
390 case GL_TEXTURE_3D:
391 {
392 gl::Texture3D *texture3d = context->getTexture3D();
393 if (texture3d)
394 {
395 textureInternalFormat = texture3d->getInternalFormat(level);
396 textureCompressed = texture3d->isCompressed(level);
397 textureIsDepth = texture3d->isDepth(level);
398 textureLevelWidth = texture3d->getWidth(level);
399 textureLevelHeight = texture3d->getHeight(level);
400 textureLevelDepth = texture3d->getDepth(level);
401 texture = texture3d;
402 }
403 }
404 break;
405
406 default:
407 return gl::error(GL_INVALID_ENUM, false);
408 }
409
410 if (!texture)
411 {
412 return gl::error(GL_INVALID_OPERATION, false);
413 }
414
415 if (texture->isImmutable() && !isSubImage)
416 {
417 return gl::error(GL_INVALID_OPERATION, false);
418 }
419
420 if (textureIsDepth)
421 {
422 return gl::error(GL_INVALID_OPERATION, false);
423 }
424
425 if (textureCompressed)
426 {
427 if ((width % 4 != 0 && width != textureLevelWidth) ||
428 (height % 4 != 0 && height != textureLevelHeight))
429 {
430 return gl::error(GL_INVALID_OPERATION, false);
431 }
432 }
433
434 if (isSubImage)
435 {
436 if (xoffset + width > textureLevelWidth ||
437 yoffset + height > textureLevelHeight ||
438 zoffset >= textureLevelDepth)
439 {
440 return gl::error(GL_INVALID_VALUE, false);
441 }
442
Shannon Woods4d161ba2014-03-17 18:13:30 -0400443 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, context->getReadFramebufferHandle(),
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 context->getClientVersion()))
445 {
446 return gl::error(GL_INVALID_OPERATION, false);
447 }
448 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400449 else
450 {
451 if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat, context->getReadFramebufferHandle(),
452 context->getClientVersion()))
453 {
454 return gl::error(GL_INVALID_OPERATION, false);
455 }
456 }
457
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400458
Shannon Woods4dfed832014-03-17 20:03:39 -0400459
Geoff Lang784a8fd2013-09-24 12:33:16 -0400460 // If width or height is zero, it is a no-op. Return false without setting an error.
461 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400462}
463
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400464bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400465 GLsizei width, GLsizei height, GLsizei depth)
466{
467 if (width < 1 || height < 1 || depth < 1 || levels < 1)
468 {
469 return gl::error(GL_INVALID_VALUE, false);
470 }
471
472 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
473 {
474 return gl::error(GL_INVALID_OPERATION, false);
475 }
476
477 gl::Texture *texture = NULL;
478 switch (target)
479 {
480 case GL_TEXTURE_2D:
481 {
482 texture = context->getTexture2D();
483
484 if (width > (context->getMaximum2DTextureDimension()) ||
485 height > (context->getMaximum2DTextureDimension()))
486 {
487 return gl::error(GL_INVALID_VALUE, false);
488 }
489 }
490 break;
491
Geoff Lang01c21d22013-09-24 11:52:16 -0400492 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400493 {
494 texture = context->getTextureCubeMap();
495
496 if (width != height)
497 {
498 return gl::error(GL_INVALID_VALUE, false);
499 }
500
501 if (width > (context->getMaximumCubeTextureDimension()))
502 {
503 return gl::error(GL_INVALID_VALUE, false);
504 }
505 }
506 break;
507
508 case GL_TEXTURE_3D:
509 {
510 texture = context->getTexture3D();
511
512 if (width > (context->getMaximum3DTextureDimension()) ||
513 height > (context->getMaximum3DTextureDimension()) ||
514 depth > (context->getMaximum3DTextureDimension()))
515 {
516 return gl::error(GL_INVALID_VALUE, false);
517 }
518 }
519 break;
520
521 case GL_TEXTURE_2D_ARRAY:
522 {
523 texture = context->getTexture2DArray();
524
525 if (width > (context->getMaximum2DTextureDimension()) ||
526 height > (context->getMaximum2DTextureDimension()) ||
527 depth > (context->getMaximum2DArrayTextureLayers()))
528 {
529 return gl::error(GL_INVALID_VALUE, false);
530 }
531 }
532 break;
533
534 default:
535 return gl::error(GL_INVALID_ENUM, false);
536 }
537
538 if (!texture || texture->id() == 0)
539 {
540 return gl::error(GL_INVALID_OPERATION, false);
541 }
542
543 if (texture->isImmutable())
544 {
545 return gl::error(GL_INVALID_OPERATION, false);
546 }
547
548 if (!gl::IsValidInternalFormat(internalformat, context))
549 {
550 return gl::error(GL_INVALID_ENUM, false);
551 }
552
553 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
554 {
555 return gl::error(GL_INVALID_ENUM, false);
556 }
557
558 return true;
559}
560
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400561bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400562 GLenum textarget, GLuint texture, GLint level, GLint layer,
563 bool layerCall)
564{
565 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
566 {
567 return gl::error(GL_INVALID_ENUM, false);
568 }
569
570 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
571 {
572 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
573 if (colorAttachment >= context->getMaximumRenderTargets())
574 {
575 return gl::error(GL_INVALID_VALUE, false);
576 }
577 }
578 else
579 {
580 switch (attachment)
581 {
582 case GL_DEPTH_ATTACHMENT:
583 case GL_STENCIL_ATTACHMENT:
584 case GL_DEPTH_STENCIL_ATTACHMENT:
585 break;
586 default:
587 return gl::error(GL_INVALID_ENUM, false);
588 }
589 }
590
591 if (texture != 0)
592 {
593 gl::Texture *tex = context->getTexture(texture);
594
595 if (tex == NULL)
596 {
597 return gl::error(GL_INVALID_OPERATION, false);
598 }
599
600 if (level < 0)
601 {
602 return gl::error(GL_INVALID_VALUE, false);
603 }
604
605 if (layer < 0)
606 {
607 return gl::error(GL_INVALID_VALUE, false);
608 }
609
610 if (!layerCall)
611 {
612 switch (textarget)
613 {
614 case GL_TEXTURE_2D:
615 {
616 if (level > gl::log2(context->getMaximum2DTextureDimension()))
617 {
618 return gl::error(GL_INVALID_VALUE, false);
619 }
620 if (tex->getTarget() != GL_TEXTURE_2D)
621 {
622 return gl::error(GL_INVALID_OPERATION, false);
623 }
624 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
625 if (tex2d->isCompressed(level))
626 {
627 return gl::error(GL_INVALID_OPERATION, false);
628 }
629 break;
630 }
631
632 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
633 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
634 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
635 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
636 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
637 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
638 {
639 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
640 {
641 return gl::error(GL_INVALID_VALUE, false);
642 }
643 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
644 {
645 return gl::error(GL_INVALID_OPERATION, false);
646 }
647 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
648 if (texcube->isCompressed(textarget, level))
649 {
650 return gl::error(GL_INVALID_OPERATION, false);
651 }
652 break;
653 }
654
655 default:
656 return gl::error(GL_INVALID_ENUM, false);
657 }
658 }
659 else
660 {
661 switch (tex->getTarget())
662 {
663 case GL_TEXTURE_2D_ARRAY:
664 {
665 if (level > gl::log2(context->getMaximum2DTextureDimension()))
666 {
667 return gl::error(GL_INVALID_VALUE, false);
668 }
669
670 if (layer >= context->getMaximum2DArrayTextureLayers())
671 {
672 return gl::error(GL_INVALID_VALUE, false);
673 }
674
675 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
676 if (texArray->isCompressed(level))
677 {
678 return gl::error(GL_INVALID_OPERATION, false);
679 }
680
681 break;
682 }
683
684 case GL_TEXTURE_3D:
685 {
686 if (level > gl::log2(context->getMaximum3DTextureDimension()))
687 {
688 return gl::error(GL_INVALID_VALUE, false);
689 }
690
691 if (layer >= context->getMaximum3DTextureDimension())
692 {
693 return gl::error(GL_INVALID_VALUE, false);
694 }
695
696 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
697 if (tex3d->isCompressed(level))
698 {
699 return gl::error(GL_INVALID_OPERATION, false);
700 }
701
702 break;
703 }
704
705 default:
706 return gl::error(GL_INVALID_OPERATION, false);
707 }
708 }
709 }
710
711 gl::Framebuffer *framebuffer = NULL;
712 GLuint framebufferHandle = 0;
713 if (target == GL_READ_FRAMEBUFFER)
714 {
715 framebuffer = context->getReadFramebuffer();
716 framebufferHandle = context->getReadFramebufferHandle();
717 }
718 else
719 {
720 framebuffer = context->getDrawFramebuffer();
721 framebufferHandle = context->getDrawFramebufferHandle();
722 }
723
724 if (framebufferHandle == 0 || !framebuffer)
725 {
726 return gl::error(GL_INVALID_OPERATION, false);
727 }
728
729 return true;
730}
731
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400732bool ValidES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400733{
734 switch (format)
735 {
736 case GL_RGBA:
737 switch (type)
738 {
739 case GL_UNSIGNED_BYTE:
740 break;
741 case GL_UNSIGNED_INT_2_10_10_10_REV:
742 if (internalFormat != GL_RGB10_A2)
743 {
744 return false;
745 }
746 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400747 case GL_FLOAT:
748 if (gl::GetComponentType(internalFormat, 3) != GL_FLOAT)
749 {
750 return false;
751 }
752 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 default:
754 return false;
755 }
756 break;
757 case GL_RGBA_INTEGER:
758 switch (type)
759 {
760 case GL_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400761 if (gl::GetComponentType(internalFormat, 3) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 {
763 return false;
764 }
765 break;
766 case GL_UNSIGNED_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400767 if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
769 return false;
770 }
771 break;
772 default:
773 return false;
774 }
775 break;
776 case GL_BGRA_EXT:
777 switch (type)
778 {
779 case GL_UNSIGNED_BYTE:
780 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
781 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
782 break;
783 default:
784 return false;
785 }
786 break;
787 default:
788 return false;
789 }
790 return true;
791}
792
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400793bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794 const GLenum* attachments)
795{
796 bool defaultFramebuffer = false;
797
798 switch (target)
799 {
800 case GL_DRAW_FRAMEBUFFER:
801 case GL_FRAMEBUFFER:
802 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
803 break;
804 case GL_READ_FRAMEBUFFER:
805 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
806 break;
807 default:
808 return gl::error(GL_INVALID_ENUM, false);
809 }
810
811 for (int i = 0; i < numAttachments; ++i)
812 {
813 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
814 {
815 if (defaultFramebuffer)
816 {
817 return gl::error(GL_INVALID_ENUM, false);
818 }
819
820 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
821 {
822 return gl::error(GL_INVALID_OPERATION, false);
823 }
824 }
825 else
826 {
827 switch (attachments[i])
828 {
829 case GL_DEPTH_ATTACHMENT:
830 case GL_STENCIL_ATTACHMENT:
831 case GL_DEPTH_STENCIL_ATTACHMENT:
832 if (defaultFramebuffer)
833 {
834 return gl::error(GL_INVALID_ENUM, false);
835 }
836 break;
837 case GL_COLOR:
838 case GL_DEPTH:
839 case GL_STENCIL:
840 if (!defaultFramebuffer)
841 {
842 return gl::error(GL_INVALID_ENUM, false);
843 }
844 break;
845 default:
846 return gl::error(GL_INVALID_ENUM, false);
847 }
848 }
849 }
850
851 return true;
852}
853
854}