blob: e865fbac9358f7a7680c74f5d1b3feff7a04a275 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#include "precompiled.h"
2//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// 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"
Jamie Madille261b442014-06-25 12:42:21 -040018#include "libGLESv2/FramebufferAttachment.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040019
20#include "common/mathutil.h"
21
22namespace gl
23{
24
Geoff Lang005df412013-10-16 14:12:50 -040025bool ValidateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
Geoff Lange8ebe7f2013-08-05 15:03:13 -040026 GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillefb2a6f2013-09-24 10:22:42 -040027 GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Geoff Lange8ebe7f2013-08-05 15:03:13 -040028{
Jamie Madill6f38f822014-06-06 17:12:20 -040029 if (!ValidTexture2DDestinationTarget(context, target))
30 {
31 return gl::error(GL_INVALID_ENUM, false);
32 }
33
Geoff Lange8ebe7f2013-08-05 15:03:13 -040034 // Validate image size
Geoff Langce635692013-09-24 13:56:32 -040035 if (!ValidImageSize(context, target, level, width, height, depth))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040036 {
37 return gl::error(GL_INVALID_VALUE, false);
38 }
39
Geoff Lange8ebe7f2013-08-05 15:03:13 -040040 // Verify zero border
41 if (border != 0)
42 {
43 return gl::error(GL_INVALID_VALUE, false);
44 }
45
Jamie Madill6f38f822014-06-06 17:12:20 -040046 if (xoffset < 0 || yoffset < 0 || zoffset < 0 ||
47 std::numeric_limits<GLsizei>::max() - xoffset < width ||
48 std::numeric_limits<GLsizei>::max() - yoffset < height ||
49 std::numeric_limits<GLsizei>::max() - zoffset < depth)
50 {
51 return gl::error(GL_INVALID_VALUE, false);
52 }
53
Geoff Lange8ebe7f2013-08-05 15:03:13 -040054 gl::Texture *texture = NULL;
55 bool textureCompressed = false;
56 GLenum textureInternalFormat = GL_NONE;
57 GLint textureLevelWidth = 0;
58 GLint textureLevelHeight = 0;
59 GLint textureLevelDepth = 0;
60 switch (target)
61 {
62 case GL_TEXTURE_2D:
63 {
64 if (width > (context->getMaximum2DTextureDimension() >> level) ||
65 height > (context->getMaximum2DTextureDimension() >> level))
66 {
67 return gl::error(GL_INVALID_VALUE, false);
68 }
69
70 gl::Texture2D *texture2d = context->getTexture2D();
71 if (texture2d)
72 {
73 textureCompressed = texture2d->isCompressed(level);
74 textureInternalFormat = texture2d->getInternalFormat(level);
75 textureLevelWidth = texture2d->getWidth(level);
76 textureLevelHeight = texture2d->getHeight(level);
77 textureLevelDepth = 1;
78 texture = texture2d;
79 }
80 }
81 break;
82
83 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
84 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
85 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
86 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
87 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
88 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
89 {
90 if (!isSubImage && width != height)
91 {
92 return gl::error(GL_INVALID_VALUE, false);
93 }
94
95 if (width > (context->getMaximumCubeTextureDimension() >> level))
96 {
97 return gl::error(GL_INVALID_VALUE, false);
98 }
99
100 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
101 if (textureCube)
102 {
103 textureCompressed = textureCube->isCompressed(target, level);
104 textureInternalFormat = textureCube->getInternalFormat(target, level);
105 textureLevelWidth = textureCube->getWidth(target, level);
106 textureLevelHeight = textureCube->getHeight(target, level);
107 textureLevelDepth = 1;
108 texture = textureCube;
109 }
110 }
111 break;
112
113 case GL_TEXTURE_3D:
114 {
115 if (width > (context->getMaximum3DTextureDimension() >> level) ||
116 height > (context->getMaximum3DTextureDimension() >> level) ||
117 depth > (context->getMaximum3DTextureDimension() >> level))
118 {
119 return gl::error(GL_INVALID_VALUE, false);
120 }
121
122 gl::Texture3D *texture3d = context->getTexture3D();
123 if (texture3d)
124 {
125 textureCompressed = texture3d->isCompressed(level);
126 textureInternalFormat = texture3d->getInternalFormat(level);
127 textureLevelWidth = texture3d->getWidth(level);
128 textureLevelHeight = texture3d->getHeight(level);
129 textureLevelDepth = texture3d->getDepth(level);
130 texture = texture3d;
131 }
132 }
133 break;
134
135 case GL_TEXTURE_2D_ARRAY:
136 {
137 if (width > (context->getMaximum2DTextureDimension() >> level) ||
138 height > (context->getMaximum2DTextureDimension() >> level) ||
139 depth > (context->getMaximum2DArrayTextureLayers() >> level))
140 {
141 return gl::error(GL_INVALID_VALUE, false);
142 }
143
144 gl::Texture2DArray *texture2darray = context->getTexture2DArray();
145 if (texture2darray)
146 {
147 textureCompressed = texture2darray->isCompressed(level);
148 textureInternalFormat = texture2darray->getInternalFormat(level);
149 textureLevelWidth = texture2darray->getWidth(level);
150 textureLevelHeight = texture2darray->getHeight(level);
Jamie Madillb8f8b892014-01-07 10:12:50 -0500151 textureLevelDepth = texture2darray->getLayers(level);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400152 texture = texture2darray;
153 }
154 }
155 break;
156
157 default:
158 return gl::error(GL_INVALID_ENUM, false);
159 }
160
161 if (!texture)
162 {
163 return gl::error(GL_INVALID_OPERATION, false);
164 }
165
166 if (texture->isImmutable() && !isSubImage)
167 {
168 return gl::error(GL_INVALID_OPERATION, false);
169 }
170
171 // Validate texture formats
172 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
Jamie Madill6f38f822014-06-06 17:12:20 -0400173 int clientVersion = context->getClientVersion();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400174 if (isCompressed)
175 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400176 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
177 {
178 return gl::error(GL_INVALID_OPERATION, false);
179 }
180
Jamie Madill6f38f822014-06-06 17:12:20 -0400181 if (!gl::IsFormatCompressed(actualInternalFormat, clientVersion))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400182 {
183 return gl::error(GL_INVALID_ENUM, false);
184 }
185
186 if (target == GL_TEXTURE_3D)
187 {
188 return gl::error(GL_INVALID_OPERATION, false);
189 }
190 }
191 else
192 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400193 // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
194 // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
Geoff Langcec35902014-04-16 10:52:36 -0400195 if (!gl::IsValidInternalFormat(actualInternalFormat, context->getCaps().extensions, context->getClientVersion()) ||
196 !gl::IsValidFormat(format, context->getClientVersion()) ||
197 !gl::IsValidType(type, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400198 {
199 return gl::error(GL_INVALID_ENUM, false);
200 }
201
Jamie Madill6f38f822014-06-06 17:12:20 -0400202 if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, clientVersion))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400203 {
204 return gl::error(GL_INVALID_OPERATION, false);
205 }
206
207 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
208 {
209 return gl::error(GL_INVALID_OPERATION, false);
210 }
211 }
212
213 // Validate sub image parameters
214 if (isSubImage)
215 {
216 if (isCompressed != textureCompressed)
217 {
218 return gl::error(GL_INVALID_OPERATION, false);
219 }
220
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400221 if (isCompressed)
222 {
223 if ((width % 4 != 0 && width != textureLevelWidth) ||
224 (height % 4 != 0 && height != textureLevelHeight))
225 {
226 return gl::error(GL_INVALID_OPERATION, false);
227 }
228 }
229
230 if (width == 0 || height == 0 || depth == 0)
231 {
232 return false;
233 }
234
235 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
236 {
237 return gl::error(GL_INVALID_VALUE, false);
238 }
239
240 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
241 std::numeric_limits<GLsizei>::max() - yoffset < height ||
242 std::numeric_limits<GLsizei>::max() - zoffset < depth)
243 {
244 return gl::error(GL_INVALID_VALUE, false);
245 }
246
247 if (xoffset + width > textureLevelWidth ||
248 yoffset + height > textureLevelHeight ||
249 zoffset + depth > textureLevelDepth)
250 {
251 return gl::error(GL_INVALID_VALUE, false);
252 }
253 }
254
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400255 // Check for pixel unpack buffer related API errors
256 gl::Buffer *pixelUnpackBuffer = context->getPixelUnpackBuffer();
257 if (pixelUnpackBuffer != NULL)
258 {
259 // ...the data would be unpacked from the buffer object such that the memory reads required
260 // would exceed the data store size.
261 size_t widthSize = static_cast<size_t>(width);
262 size_t heightSize = static_cast<size_t>(height);
263 size_t depthSize = static_cast<size_t>(depth);
Jamie Madill6f38f822014-06-06 17:12:20 -0400264 GLenum sizedFormat = gl::IsSizedInternalFormat(actualInternalFormat, clientVersion) ?
265 actualInternalFormat :
266 gl::GetSizedInternalFormat(actualInternalFormat, type, clientVersion);
267
268 size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(sizedFormat, clientVersion));
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400269
270 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
271 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
272 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
273 {
274 // Overflow past the end of the buffer
275 return gl::error(GL_INVALID_OPERATION, false);
276 }
277
278 size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes;
279 size_t offset = reinterpret_cast<size_t>(pixels);
280
Jamie Madill6f38f822014-06-06 17:12:20 -0400281 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
282 ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->size())))
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400283 {
284 // Overflow past the end of the buffer
285 return gl::error(GL_INVALID_OPERATION, false);
286 }
287
288 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
289 // indicated by type.
290 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type));
291
292 if ((offset % dataBytesPerPixel) != 0)
293 {
294 return gl::error(GL_INVALID_OPERATION, false);
295 }
296
Jamie Madill7a5f7382014-03-05 15:01:24 -0500297 // ...the buffer object's data store is currently mapped.
298 if (pixelUnpackBuffer->mapped())
299 {
300 return gl::error(GL_INVALID_OPERATION, false);
301 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400302 }
303
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400304 return true;
305}
306
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400307bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
Jamie Madill6f38f822014-06-06 17:12:20 -0400308 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
309 GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400310{
Jamie Madill560a8d82014-05-21 13:06:20 -0400311 GLenum textureInternalFormat;
312 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
Jamie Madill6f38f822014-06-06 17:12:20 -0400313 xoffset, yoffset, zoffset, x, y, width, height,
314 border, &textureInternalFormat))
Shannon Woods4dfed832014-03-17 20:03:39 -0400315 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400316 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400317 }
318
319 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -0400320
321 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
322 {
323 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
324 }
325
326 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
327 {
328 return gl::error(GL_INVALID_OPERATION, false);
329 }
330
331 gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400332 GLenum colorbufferInternalFormat = source->getInternalFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400333
334 if (isSubImage)
335 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400336 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
337 context->getReadFramebufferHandle(),
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400338 context->getClientVersion()))
339 {
340 return gl::error(GL_INVALID_OPERATION, false);
341 }
342 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400343 else
344 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400345 if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat,
346 context->getReadFramebufferHandle(),
Shannon Woods4d161ba2014-03-17 18:13:30 -0400347 context->getClientVersion()))
348 {
349 return gl::error(GL_INVALID_OPERATION, false);
350 }
351 }
352
Geoff Lang784a8fd2013-09-24 12:33:16 -0400353 // If width or height is zero, it is a no-op. Return false without setting an error.
354 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400355}
356
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400357bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400358 GLsizei width, GLsizei height, GLsizei depth)
359{
360 if (width < 1 || height < 1 || depth < 1 || levels < 1)
361 {
362 return gl::error(GL_INVALID_VALUE, false);
363 }
364
365 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
366 {
367 return gl::error(GL_INVALID_OPERATION, false);
368 }
369
370 gl::Texture *texture = NULL;
371 switch (target)
372 {
373 case GL_TEXTURE_2D:
374 {
375 texture = context->getTexture2D();
376
377 if (width > (context->getMaximum2DTextureDimension()) ||
378 height > (context->getMaximum2DTextureDimension()))
379 {
380 return gl::error(GL_INVALID_VALUE, false);
381 }
382 }
383 break;
384
Geoff Lang01c21d22013-09-24 11:52:16 -0400385 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400386 {
387 texture = context->getTextureCubeMap();
388
389 if (width != height)
390 {
391 return gl::error(GL_INVALID_VALUE, false);
392 }
393
394 if (width > (context->getMaximumCubeTextureDimension()))
395 {
396 return gl::error(GL_INVALID_VALUE, false);
397 }
398 }
399 break;
400
401 case GL_TEXTURE_3D:
402 {
403 texture = context->getTexture3D();
404
405 if (width > (context->getMaximum3DTextureDimension()) ||
406 height > (context->getMaximum3DTextureDimension()) ||
407 depth > (context->getMaximum3DTextureDimension()))
408 {
409 return gl::error(GL_INVALID_VALUE, false);
410 }
411 }
412 break;
413
414 case GL_TEXTURE_2D_ARRAY:
415 {
416 texture = context->getTexture2DArray();
417
418 if (width > (context->getMaximum2DTextureDimension()) ||
419 height > (context->getMaximum2DTextureDimension()) ||
420 depth > (context->getMaximum2DArrayTextureLayers()))
421 {
422 return gl::error(GL_INVALID_VALUE, false);
423 }
424 }
425 break;
426
427 default:
428 return gl::error(GL_INVALID_ENUM, false);
429 }
430
431 if (!texture || texture->id() == 0)
432 {
433 return gl::error(GL_INVALID_OPERATION, false);
434 }
435
436 if (texture->isImmutable())
437 {
438 return gl::error(GL_INVALID_OPERATION, false);
439 }
440
Geoff Langcec35902014-04-16 10:52:36 -0400441 if (!gl::IsValidInternalFormat(internalformat, context->getCaps().extensions, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 {
443 return gl::error(GL_INVALID_ENUM, false);
444 }
445
446 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
447 {
448 return gl::error(GL_INVALID_ENUM, false);
449 }
450
451 return true;
452}
453
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400454bool ValidateES3FramebufferTextureParameters(gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400455 GLenum textarget, GLuint texture, GLint level, GLint layer,
456 bool layerCall)
457{
458 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
459 {
460 return gl::error(GL_INVALID_ENUM, false);
461 }
462
463 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
464 {
465 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
466 if (colorAttachment >= context->getMaximumRenderTargets())
467 {
468 return gl::error(GL_INVALID_VALUE, false);
469 }
470 }
471 else
472 {
473 switch (attachment)
474 {
475 case GL_DEPTH_ATTACHMENT:
476 case GL_STENCIL_ATTACHMENT:
477 case GL_DEPTH_STENCIL_ATTACHMENT:
478 break;
479 default:
480 return gl::error(GL_INVALID_ENUM, false);
481 }
482 }
483
484 if (texture != 0)
485 {
486 gl::Texture *tex = context->getTexture(texture);
487
488 if (tex == NULL)
489 {
490 return gl::error(GL_INVALID_OPERATION, false);
491 }
492
493 if (level < 0)
494 {
495 return gl::error(GL_INVALID_VALUE, false);
496 }
497
498 if (layer < 0)
499 {
500 return gl::error(GL_INVALID_VALUE, false);
501 }
502
503 if (!layerCall)
504 {
505 switch (textarget)
506 {
507 case GL_TEXTURE_2D:
508 {
509 if (level > gl::log2(context->getMaximum2DTextureDimension()))
510 {
511 return gl::error(GL_INVALID_VALUE, false);
512 }
513 if (tex->getTarget() != GL_TEXTURE_2D)
514 {
515 return gl::error(GL_INVALID_OPERATION, false);
516 }
517 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
518 if (tex2d->isCompressed(level))
519 {
520 return gl::error(GL_INVALID_OPERATION, false);
521 }
522 break;
523 }
524
525 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
526 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
527 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
528 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
529 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
530 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
531 {
532 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
533 {
534 return gl::error(GL_INVALID_VALUE, false);
535 }
536 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
537 {
538 return gl::error(GL_INVALID_OPERATION, false);
539 }
540 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
541 if (texcube->isCompressed(textarget, level))
542 {
543 return gl::error(GL_INVALID_OPERATION, false);
544 }
545 break;
546 }
547
548 default:
549 return gl::error(GL_INVALID_ENUM, false);
550 }
551 }
552 else
553 {
554 switch (tex->getTarget())
555 {
556 case GL_TEXTURE_2D_ARRAY:
557 {
558 if (level > gl::log2(context->getMaximum2DTextureDimension()))
559 {
560 return gl::error(GL_INVALID_VALUE, false);
561 }
562
563 if (layer >= context->getMaximum2DArrayTextureLayers())
564 {
565 return gl::error(GL_INVALID_VALUE, false);
566 }
567
568 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
569 if (texArray->isCompressed(level))
570 {
571 return gl::error(GL_INVALID_OPERATION, false);
572 }
573
574 break;
575 }
576
577 case GL_TEXTURE_3D:
578 {
579 if (level > gl::log2(context->getMaximum3DTextureDimension()))
580 {
581 return gl::error(GL_INVALID_VALUE, false);
582 }
583
584 if (layer >= context->getMaximum3DTextureDimension())
585 {
586 return gl::error(GL_INVALID_VALUE, false);
587 }
588
589 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
590 if (tex3d->isCompressed(level))
591 {
592 return gl::error(GL_INVALID_OPERATION, false);
593 }
594
595 break;
596 }
597
598 default:
599 return gl::error(GL_INVALID_OPERATION, false);
600 }
601 }
602 }
603
604 gl::Framebuffer *framebuffer = NULL;
605 GLuint framebufferHandle = 0;
606 if (target == GL_READ_FRAMEBUFFER)
607 {
608 framebuffer = context->getReadFramebuffer();
609 framebufferHandle = context->getReadFramebufferHandle();
610 }
611 else
612 {
613 framebuffer = context->getDrawFramebuffer();
614 framebufferHandle = context->getDrawFramebufferHandle();
615 }
616
617 if (framebufferHandle == 0 || !framebuffer)
618 {
619 return gl::error(GL_INVALID_OPERATION, false);
620 }
621
622 return true;
623}
624
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400625bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400626{
627 switch (format)
628 {
629 case GL_RGBA:
630 switch (type)
631 {
632 case GL_UNSIGNED_BYTE:
633 break;
634 case GL_UNSIGNED_INT_2_10_10_10_REV:
635 if (internalFormat != GL_RGB10_A2)
636 {
637 return false;
638 }
639 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400640 case GL_FLOAT:
641 if (gl::GetComponentType(internalFormat, 3) != GL_FLOAT)
642 {
643 return false;
644 }
645 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 default:
647 return false;
648 }
649 break;
650 case GL_RGBA_INTEGER:
651 switch (type)
652 {
653 case GL_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400654 if (gl::GetComponentType(internalFormat, 3) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 {
656 return false;
657 }
658 break;
659 case GL_UNSIGNED_INT:
Geoff Langb2f3d052013-08-13 12:49:27 -0400660 if (gl::GetComponentType(internalFormat, 3) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661 {
662 return false;
663 }
664 break;
665 default:
666 return false;
667 }
668 break;
669 case GL_BGRA_EXT:
670 switch (type)
671 {
672 case GL_UNSIGNED_BYTE:
673 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
674 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
675 break;
676 default:
677 return false;
678 }
679 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400680 case GL_RG_EXT:
681 case GL_RED_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400682 if (!context->getCaps().extensions.textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400683 {
684 return false;
685 }
686 switch (type)
687 {
688 case GL_UNSIGNED_BYTE:
689 break;
690 default:
691 return false;
692 }
693 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 default:
695 return false;
696 }
697 return true;
698}
699
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400700bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400701 const GLenum* attachments)
702{
703 bool defaultFramebuffer = false;
704
705 switch (target)
706 {
707 case GL_DRAW_FRAMEBUFFER:
708 case GL_FRAMEBUFFER:
709 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
710 break;
711 case GL_READ_FRAMEBUFFER:
712 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
713 break;
714 default:
715 return gl::error(GL_INVALID_ENUM, false);
716 }
717
718 for (int i = 0; i < numAttachments; ++i)
719 {
720 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
721 {
722 if (defaultFramebuffer)
723 {
724 return gl::error(GL_INVALID_ENUM, false);
725 }
726
727 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
728 {
729 return gl::error(GL_INVALID_OPERATION, false);
730 }
731 }
732 else
733 {
734 switch (attachments[i])
735 {
736 case GL_DEPTH_ATTACHMENT:
737 case GL_STENCIL_ATTACHMENT:
738 case GL_DEPTH_STENCIL_ATTACHMENT:
739 if (defaultFramebuffer)
740 {
741 return gl::error(GL_INVALID_ENUM, false);
742 }
743 break;
744 case GL_COLOR:
745 case GL_DEPTH:
746 case GL_STENCIL:
747 if (!defaultFramebuffer)
748 {
749 return gl::error(GL_INVALID_ENUM, false);
750 }
751 break;
752 default:
753 return gl::error(GL_INVALID_ENUM, false);
754 }
755 }
756 }
757
758 return true;
759}
760
Jamie Madill13f7d7d2014-06-20 13:21:27 -0400761bool ValidateClearBuffer(const gl::Context *context)
762{
763 if (context->getClientVersion() < 3)
764 {
765 return gl::error(GL_INVALID_OPERATION, false);
766 }
767
768 const gl::Framebuffer *fbo = context->getDrawFramebuffer();
769 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
770 {
771 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
772 }
773
774 return true;
775}
776
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777}