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