blob: 4b2bd455fe0272045d9779871a37543ff2fe042e [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
Shannon Woods4d161ba2014-03-17 18:13:30 -0400438 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, context->getReadFramebufferHandle(),
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400439 context->getClientVersion()))
440 {
441 return gl::error(GL_INVALID_OPERATION, false);
442 }
443 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400444 else
445 {
446 if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat, context->getReadFramebufferHandle(),
447 context->getClientVersion()))
448 {
449 return gl::error(GL_INVALID_OPERATION, false);
450 }
451 }
452
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400453
Geoff Lang784a8fd2013-09-24 12:33:16 -0400454 // If width or height is zero, it is a no-op. Return false without setting an error.
455 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400456}
457
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400458bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400459 GLsizei width, GLsizei height, GLsizei depth)
460{
461 if (width < 1 || height < 1 || depth < 1 || levels < 1)
462 {
463 return gl::error(GL_INVALID_VALUE, false);
464 }
465
466 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
467 {
468 return gl::error(GL_INVALID_OPERATION, false);
469 }
470
471 gl::Texture *texture = NULL;
472 switch (target)
473 {
474 case GL_TEXTURE_2D:
475 {
476 texture = context->getTexture2D();
477
478 if (width > (context->getMaximum2DTextureDimension()) ||
479 height > (context->getMaximum2DTextureDimension()))
480 {
481 return gl::error(GL_INVALID_VALUE, false);
482 }
483 }
484 break;
485
Geoff Lang01c21d22013-09-24 11:52:16 -0400486 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400487 {
488 texture = context->getTextureCubeMap();
489
490 if (width != height)
491 {
492 return gl::error(GL_INVALID_VALUE, false);
493 }
494
495 if (width > (context->getMaximumCubeTextureDimension()))
496 {
497 return gl::error(GL_INVALID_VALUE, false);
498 }
499 }
500 break;
501
502 case GL_TEXTURE_3D:
503 {
504 texture = context->getTexture3D();
505
506 if (width > (context->getMaximum3DTextureDimension()) ||
507 height > (context->getMaximum3DTextureDimension()) ||
508 depth > (context->getMaximum3DTextureDimension()))
509 {
510 return gl::error(GL_INVALID_VALUE, false);
511 }
512 }
513 break;
514
515 case GL_TEXTURE_2D_ARRAY:
516 {
517 texture = context->getTexture2DArray();
518
519 if (width > (context->getMaximum2DTextureDimension()) ||
520 height > (context->getMaximum2DTextureDimension()) ||
521 depth > (context->getMaximum2DArrayTextureLayers()))
522 {
523 return gl::error(GL_INVALID_VALUE, false);
524 }
525 }
526 break;
527
528 default:
529 return gl::error(GL_INVALID_ENUM, false);
530 }
531
532 if (!texture || texture->id() == 0)
533 {
534 return gl::error(GL_INVALID_OPERATION, false);
535 }
536
537 if (texture->isImmutable())
538 {
539 return gl::error(GL_INVALID_OPERATION, false);
540 }
541
542 if (!gl::IsValidInternalFormat(internalformat, context))
543 {
544 return gl::error(GL_INVALID_ENUM, false);
545 }
546
547 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
548 {
549 return gl::error(GL_INVALID_ENUM, false);
550 }
551
552 return true;
553}
554
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400555bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400556 GLenum textarget, GLuint texture, GLint level, GLint layer,
557 bool layerCall)
558{
559 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
560 {
561 return gl::error(GL_INVALID_ENUM, false);
562 }
563
564 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
565 {
566 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
567 if (colorAttachment >= context->getMaximumRenderTargets())
568 {
569 return gl::error(GL_INVALID_VALUE, false);
570 }
571 }
572 else
573 {
574 switch (attachment)
575 {
576 case GL_DEPTH_ATTACHMENT:
577 case GL_STENCIL_ATTACHMENT:
578 case GL_DEPTH_STENCIL_ATTACHMENT:
579 break;
580 default:
581 return gl::error(GL_INVALID_ENUM, false);
582 }
583 }
584
585 if (texture != 0)
586 {
587 gl::Texture *tex = context->getTexture(texture);
588
589 if (tex == NULL)
590 {
591 return gl::error(GL_INVALID_OPERATION, false);
592 }
593
594 if (level < 0)
595 {
596 return gl::error(GL_INVALID_VALUE, false);
597 }
598
599 if (layer < 0)
600 {
601 return gl::error(GL_INVALID_VALUE, false);
602 }
603
604 if (!layerCall)
605 {
606 switch (textarget)
607 {
608 case GL_TEXTURE_2D:
609 {
610 if (level > gl::log2(context->getMaximum2DTextureDimension()))
611 {
612 return gl::error(GL_INVALID_VALUE, false);
613 }
614 if (tex->getTarget() != GL_TEXTURE_2D)
615 {
616 return gl::error(GL_INVALID_OPERATION, false);
617 }
618 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
619 if (tex2d->isCompressed(level))
620 {
621 return gl::error(GL_INVALID_OPERATION, false);
622 }
623 break;
624 }
625
626 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
627 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
628 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
629 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
630 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
631 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
632 {
633 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
634 {
635 return gl::error(GL_INVALID_VALUE, false);
636 }
637 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
638 {
639 return gl::error(GL_INVALID_OPERATION, false);
640 }
641 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
642 if (texcube->isCompressed(textarget, level))
643 {
644 return gl::error(GL_INVALID_OPERATION, false);
645 }
646 break;
647 }
648
649 default:
650 return gl::error(GL_INVALID_ENUM, false);
651 }
652 }
653 else
654 {
655 switch (tex->getTarget())
656 {
657 case GL_TEXTURE_2D_ARRAY:
658 {
659 if (level > gl::log2(context->getMaximum2DTextureDimension()))
660 {
661 return gl::error(GL_INVALID_VALUE, false);
662 }
663
664 if (layer >= context->getMaximum2DArrayTextureLayers())
665 {
666 return gl::error(GL_INVALID_VALUE, false);
667 }
668
669 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
670 if (texArray->isCompressed(level))
671 {
672 return gl::error(GL_INVALID_OPERATION, false);
673 }
674
675 break;
676 }
677
678 case GL_TEXTURE_3D:
679 {
680 if (level > gl::log2(context->getMaximum3DTextureDimension()))
681 {
682 return gl::error(GL_INVALID_VALUE, false);
683 }
684
685 if (layer >= context->getMaximum3DTextureDimension())
686 {
687 return gl::error(GL_INVALID_VALUE, false);
688 }
689
690 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
691 if (tex3d->isCompressed(level))
692 {
693 return gl::error(GL_INVALID_OPERATION, false);
694 }
695
696 break;
697 }
698
699 default:
700 return gl::error(GL_INVALID_OPERATION, false);
701 }
702 }
703 }
704
705 gl::Framebuffer *framebuffer = NULL;
706 GLuint framebufferHandle = 0;
707 if (target == GL_READ_FRAMEBUFFER)
708 {
709 framebuffer = context->getReadFramebuffer();
710 framebufferHandle = context->getReadFramebufferHandle();
711 }
712 else
713 {
714 framebuffer = context->getDrawFramebuffer();
715 framebufferHandle = context->getDrawFramebufferHandle();
716 }
717
718 if (framebufferHandle == 0 || !framebuffer)
719 {
720 return gl::error(GL_INVALID_OPERATION, false);
721 }
722
723 return true;
724}
725
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400726bool ValidES3ReadFormatType(GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400727{
728 switch (format)
729 {
730 case GL_RGBA:
731 switch (type)
732 {
733 case GL_UNSIGNED_BYTE:
734 break;
735 case GL_UNSIGNED_INT_2_10_10_10_REV:
736 if (internalFormat != GL_RGB10_A2)
737 {
738 return false;
739 }
740 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400741 case GL_FLOAT:
742 if (gl::GetComponentType(internalFormat, 3) != GL_FLOAT)
743 {
744 return false;
745 }
746 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 default:
748 return false;
749 }
750 break;
751 case GL_RGBA_INTEGER:
752 switch (type)
753 {
754 case GL_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400755 if (gl::GetComponentType(internalFormat, 3) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400756 {
757 return false;
758 }
759 break;
760 case GL_UNSIGNED_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400761 if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 {
763 return false;
764 }
765 break;
766 default:
767 return false;
768 }
769 break;
770 case GL_BGRA_EXT:
771 switch (type)
772 {
773 case GL_UNSIGNED_BYTE:
774 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
775 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
776 break;
777 default:
778 return false;
779 }
780 break;
781 default:
782 return false;
783 }
784 return true;
785}
786
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400787bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400788 const GLenum* attachments)
789{
790 bool defaultFramebuffer = false;
791
792 switch (target)
793 {
794 case GL_DRAW_FRAMEBUFFER:
795 case GL_FRAMEBUFFER:
796 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
797 break;
798 case GL_READ_FRAMEBUFFER:
799 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
800 break;
801 default:
802 return gl::error(GL_INVALID_ENUM, false);
803 }
804
805 for (int i = 0; i < numAttachments; ++i)
806 {
807 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
808 {
809 if (defaultFramebuffer)
810 {
811 return gl::error(GL_INVALID_ENUM, false);
812 }
813
814 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
815 {
816 return gl::error(GL_INVALID_OPERATION, false);
817 }
818 }
819 else
820 {
821 switch (attachments[i])
822 {
823 case GL_DEPTH_ATTACHMENT:
824 case GL_STENCIL_ATTACHMENT:
825 case GL_DEPTH_STENCIL_ATTACHMENT:
826 if (defaultFramebuffer)
827 {
828 return gl::error(GL_INVALID_ENUM, false);
829 }
830 break;
831 case GL_COLOR:
832 case GL_DEPTH:
833 case GL_STENCIL:
834 if (!defaultFramebuffer)
835 {
836 return gl::error(GL_INVALID_ENUM, false);
837 }
838 break;
839 default:
840 return gl::error(GL_INVALID_ENUM, false);
841 }
842 }
843 }
844
845 return true;
846}
847
848}