blob: 0a37894bda32ee1e6632c91acd92361d700dbfb3 [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);
137 textureLevelDepth = texture2darray->getDepth(level);
138 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
275 // TODO: ...the buffer object's data store is currently mapped.
276 }
277
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400278 return true;
279}
280
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400281bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400282 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
283 GLsizei width, GLsizei height, GLint border)
284{
285 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
286 {
287 return gl::error(GL_INVALID_VALUE, false);
288 }
289
290 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
291 {
292 return gl::error(GL_INVALID_VALUE, false);
293 }
294
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400295 if (border != 0)
296 {
297 return gl::error(GL_INVALID_VALUE, false);
298 }
299
Geoff Langce635692013-09-24 13:56:32 -0400300 if (!ValidMipLevel(context, target, level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400301 {
302 return gl::error(GL_INVALID_VALUE, false);
303 }
304
305 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
306
307 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
308 {
309 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
310 }
311
312 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
313 {
314 return gl::error(GL_INVALID_OPERATION, false);
315 }
316
317 gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
318 GLenum colorbufferInternalFormat = source->getInternalFormat();
319 gl::Texture *texture = NULL;
320 GLenum textureInternalFormat = GL_NONE;
321 bool textureCompressed = false;
322 bool textureIsDepth = false;
323 GLint textureLevelWidth = 0;
324 GLint textureLevelHeight = 0;
325 GLint textureLevelDepth = 0;
326 switch (target)
327 {
328 case GL_TEXTURE_2D:
329 {
330 gl::Texture2D *texture2d = context->getTexture2D();
331 if (texture2d)
332 {
333 textureInternalFormat = texture2d->getInternalFormat(level);
334 textureCompressed = texture2d->isCompressed(level);
335 textureIsDepth = texture2d->isDepth(level);
336 textureLevelWidth = texture2d->getWidth(level);
337 textureLevelHeight = texture2d->getHeight(level);
338 textureLevelDepth = 1;
339 texture = texture2d;
340 }
341 }
342 break;
343
344 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
345 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
346 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
347 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
348 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
349 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
350 {
351 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
352 if (textureCube)
353 {
354 textureInternalFormat = textureCube->getInternalFormat(target, level);
355 textureCompressed = textureCube->isCompressed(target, level);
356 textureIsDepth = false;
357 textureLevelWidth = textureCube->getWidth(target, level);
358 textureLevelHeight = textureCube->getHeight(target, level);
359 textureLevelDepth = 1;
360 texture = textureCube;
361 }
362 }
363 break;
364
365 case GL_TEXTURE_2D_ARRAY:
366 {
367 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
368 if (texture2dArray)
369 {
370 textureInternalFormat = texture2dArray->getInternalFormat(level);
371 textureCompressed = texture2dArray->isCompressed(level);
372 textureIsDepth = texture2dArray->isDepth(level);
373 textureLevelWidth = texture2dArray->getWidth(level);
374 textureLevelHeight = texture2dArray->getHeight(level);
375 textureLevelDepth = texture2dArray->getDepth(level);
376 texture = texture2dArray;
377 }
378 }
379 break;
380
381 case GL_TEXTURE_3D:
382 {
383 gl::Texture3D *texture3d = context->getTexture3D();
384 if (texture3d)
385 {
386 textureInternalFormat = texture3d->getInternalFormat(level);
387 textureCompressed = texture3d->isCompressed(level);
388 textureIsDepth = texture3d->isDepth(level);
389 textureLevelWidth = texture3d->getWidth(level);
390 textureLevelHeight = texture3d->getHeight(level);
391 textureLevelDepth = texture3d->getDepth(level);
392 texture = texture3d;
393 }
394 }
395 break;
396
397 default:
398 return gl::error(GL_INVALID_ENUM, false);
399 }
400
401 if (!texture)
402 {
403 return gl::error(GL_INVALID_OPERATION, false);
404 }
405
406 if (texture->isImmutable() && !isSubImage)
407 {
408 return gl::error(GL_INVALID_OPERATION, false);
409 }
410
411 if (textureIsDepth)
412 {
413 return gl::error(GL_INVALID_OPERATION, false);
414 }
415
416 if (textureCompressed)
417 {
418 if ((width % 4 != 0 && width != textureLevelWidth) ||
419 (height % 4 != 0 && height != textureLevelHeight))
420 {
421 return gl::error(GL_INVALID_OPERATION, false);
422 }
423 }
424
425 if (isSubImage)
426 {
427 if (xoffset + width > textureLevelWidth ||
428 yoffset + height > textureLevelHeight ||
429 zoffset >= textureLevelDepth)
430 {
431 return gl::error(GL_INVALID_VALUE, false);
432 }
433
434 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
435 context->getClientVersion()))
436 {
437 return gl::error(GL_INVALID_OPERATION, false);
438 }
439 }
440
Geoff Lang784a8fd2013-09-24 12:33:16 -0400441 // If width or height is zero, it is a no-op. Return false without setting an error.
442 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400443}
444
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400445bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400446 GLsizei width, GLsizei height, GLsizei depth)
447{
448 if (width < 1 || height < 1 || depth < 1 || levels < 1)
449 {
450 return gl::error(GL_INVALID_VALUE, false);
451 }
452
453 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
454 {
455 return gl::error(GL_INVALID_OPERATION, false);
456 }
457
458 gl::Texture *texture = NULL;
459 switch (target)
460 {
461 case GL_TEXTURE_2D:
462 {
463 texture = context->getTexture2D();
464
465 if (width > (context->getMaximum2DTextureDimension()) ||
466 height > (context->getMaximum2DTextureDimension()))
467 {
468 return gl::error(GL_INVALID_VALUE, false);
469 }
470 }
471 break;
472
Geoff Lang01c21d22013-09-24 11:52:16 -0400473 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400474 {
475 texture = context->getTextureCubeMap();
476
477 if (width != height)
478 {
479 return gl::error(GL_INVALID_VALUE, false);
480 }
481
482 if (width > (context->getMaximumCubeTextureDimension()))
483 {
484 return gl::error(GL_INVALID_VALUE, false);
485 }
486 }
487 break;
488
489 case GL_TEXTURE_3D:
490 {
491 texture = context->getTexture3D();
492
493 if (width > (context->getMaximum3DTextureDimension()) ||
494 height > (context->getMaximum3DTextureDimension()) ||
495 depth > (context->getMaximum3DTextureDimension()))
496 {
497 return gl::error(GL_INVALID_VALUE, false);
498 }
499 }
500 break;
501
502 case GL_TEXTURE_2D_ARRAY:
503 {
504 texture = context->getTexture2DArray();
505
506 if (width > (context->getMaximum2DTextureDimension()) ||
507 height > (context->getMaximum2DTextureDimension()) ||
508 depth > (context->getMaximum2DArrayTextureLayers()))
509 {
510 return gl::error(GL_INVALID_VALUE, false);
511 }
512 }
513 break;
514
515 default:
516 return gl::error(GL_INVALID_ENUM, false);
517 }
518
519 if (!texture || texture->id() == 0)
520 {
521 return gl::error(GL_INVALID_OPERATION, false);
522 }
523
524 if (texture->isImmutable())
525 {
526 return gl::error(GL_INVALID_OPERATION, false);
527 }
528
529 if (!gl::IsValidInternalFormat(internalformat, context))
530 {
531 return gl::error(GL_INVALID_ENUM, false);
532 }
533
534 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
535 {
536 return gl::error(GL_INVALID_ENUM, false);
537 }
538
539 return true;
540}
541
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400542bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400543 GLenum textarget, GLuint texture, GLint level, GLint layer,
544 bool layerCall)
545{
546 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
547 {
548 return gl::error(GL_INVALID_ENUM, false);
549 }
550
551 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
552 {
553 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
554 if (colorAttachment >= context->getMaximumRenderTargets())
555 {
556 return gl::error(GL_INVALID_VALUE, false);
557 }
558 }
559 else
560 {
561 switch (attachment)
562 {
563 case GL_DEPTH_ATTACHMENT:
564 case GL_STENCIL_ATTACHMENT:
565 case GL_DEPTH_STENCIL_ATTACHMENT:
566 break;
567 default:
568 return gl::error(GL_INVALID_ENUM, false);
569 }
570 }
571
572 if (texture != 0)
573 {
574 gl::Texture *tex = context->getTexture(texture);
575
576 if (tex == NULL)
577 {
578 return gl::error(GL_INVALID_OPERATION, false);
579 }
580
581 if (level < 0)
582 {
583 return gl::error(GL_INVALID_VALUE, false);
584 }
585
586 if (layer < 0)
587 {
588 return gl::error(GL_INVALID_VALUE, false);
589 }
590
591 if (!layerCall)
592 {
593 switch (textarget)
594 {
595 case GL_TEXTURE_2D:
596 {
597 if (level > gl::log2(context->getMaximum2DTextureDimension()))
598 {
599 return gl::error(GL_INVALID_VALUE, false);
600 }
601 if (tex->getTarget() != GL_TEXTURE_2D)
602 {
603 return gl::error(GL_INVALID_OPERATION, false);
604 }
605 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
606 if (tex2d->isCompressed(level))
607 {
608 return gl::error(GL_INVALID_OPERATION, false);
609 }
610 break;
611 }
612
613 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
614 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
615 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
616 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
617 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
618 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
619 {
620 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
621 {
622 return gl::error(GL_INVALID_VALUE, false);
623 }
624 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
625 {
626 return gl::error(GL_INVALID_OPERATION, false);
627 }
628 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
629 if (texcube->isCompressed(textarget, level))
630 {
631 return gl::error(GL_INVALID_OPERATION, false);
632 }
633 break;
634 }
635
636 default:
637 return gl::error(GL_INVALID_ENUM, false);
638 }
639 }
640 else
641 {
642 switch (tex->getTarget())
643 {
644 case GL_TEXTURE_2D_ARRAY:
645 {
646 if (level > gl::log2(context->getMaximum2DTextureDimension()))
647 {
648 return gl::error(GL_INVALID_VALUE, false);
649 }
650
651 if (layer >= context->getMaximum2DArrayTextureLayers())
652 {
653 return gl::error(GL_INVALID_VALUE, false);
654 }
655
656 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
657 if (texArray->isCompressed(level))
658 {
659 return gl::error(GL_INVALID_OPERATION, false);
660 }
661
662 break;
663 }
664
665 case GL_TEXTURE_3D:
666 {
667 if (level > gl::log2(context->getMaximum3DTextureDimension()))
668 {
669 return gl::error(GL_INVALID_VALUE, false);
670 }
671
672 if (layer >= context->getMaximum3DTextureDimension())
673 {
674 return gl::error(GL_INVALID_VALUE, false);
675 }
676
677 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
678 if (tex3d->isCompressed(level))
679 {
680 return gl::error(GL_INVALID_OPERATION, false);
681 }
682
683 break;
684 }
685
686 default:
687 return gl::error(GL_INVALID_OPERATION, false);
688 }
689 }
690 }
691
692 gl::Framebuffer *framebuffer = NULL;
693 GLuint framebufferHandle = 0;
694 if (target == GL_READ_FRAMEBUFFER)
695 {
696 framebuffer = context->getReadFramebuffer();
697 framebufferHandle = context->getReadFramebufferHandle();
698 }
699 else
700 {
701 framebuffer = context->getDrawFramebuffer();
702 framebufferHandle = context->getDrawFramebufferHandle();
703 }
704
705 if (framebufferHandle == 0 || !framebuffer)
706 {
707 return gl::error(GL_INVALID_OPERATION, false);
708 }
709
710 return true;
711}
712
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400713bool ValidES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714{
715 switch (format)
716 {
717 case GL_RGBA:
718 switch (type)
719 {
720 case GL_UNSIGNED_BYTE:
721 break;
722 case GL_UNSIGNED_INT_2_10_10_10_REV:
723 if (internalFormat != GL_RGB10_A2)
724 {
725 return false;
726 }
727 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400728 case GL_FLOAT:
729 if (gl::GetComponentType(internalFormat, 3) != GL_FLOAT)
730 {
731 return false;
732 }
733 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400734 default:
735 return false;
736 }
737 break;
738 case GL_RGBA_INTEGER:
739 switch (type)
740 {
741 case GL_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400742 if (gl::GetComponentType(internalFormat, 3) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400743 {
744 return false;
745 }
746 break;
747 case GL_UNSIGNED_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400748 if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400749 {
750 return false;
751 }
752 break;
753 default:
754 return false;
755 }
756 break;
757 case GL_BGRA_EXT:
758 switch (type)
759 {
760 case GL_UNSIGNED_BYTE:
761 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
762 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
763 break;
764 default:
765 return false;
766 }
767 break;
768 default:
769 return false;
770 }
771 return true;
772}
773
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400774bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 const GLenum* attachments)
776{
777 bool defaultFramebuffer = false;
778
779 switch (target)
780 {
781 case GL_DRAW_FRAMEBUFFER:
782 case GL_FRAMEBUFFER:
783 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
784 break;
785 case GL_READ_FRAMEBUFFER:
786 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
787 break;
788 default:
789 return gl::error(GL_INVALID_ENUM, false);
790 }
791
792 for (int i = 0; i < numAttachments; ++i)
793 {
794 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
795 {
796 if (defaultFramebuffer)
797 {
798 return gl::error(GL_INVALID_ENUM, false);
799 }
800
801 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
802 {
803 return gl::error(GL_INVALID_OPERATION, false);
804 }
805 }
806 else
807 {
808 switch (attachments[i])
809 {
810 case GL_DEPTH_ATTACHMENT:
811 case GL_STENCIL_ATTACHMENT:
812 case GL_DEPTH_STENCIL_ATTACHMENT:
813 if (defaultFramebuffer)
814 {
815 return gl::error(GL_INVALID_ENUM, false);
816 }
817 break;
818 case GL_COLOR:
819 case GL_DEPTH:
820 case GL_STENCIL:
821 if (!defaultFramebuffer)
822 {
823 return gl::error(GL_INVALID_ENUM, false);
824 }
825 break;
826 default:
827 return gl::error(GL_INVALID_ENUM, false);
828 }
829 }
830 }
831
832 return true;
833}
834
835}