blob: 621d8da39700eb82e390525b5d4844b6b5b600c0 [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;
173 if (isCompressed)
174 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400175 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
176 {
177 return gl::error(GL_INVALID_OPERATION, false);
178 }
179
Geoff Lange4a492b2014-06-19 14:14:41 -0400180 if (!gl::IsFormatCompressed(actualInternalFormat))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400181 {
182 return gl::error(GL_INVALID_ENUM, false);
183 }
184
185 if (target == GL_TEXTURE_3D)
186 {
187 return gl::error(GL_INVALID_OPERATION, false);
188 }
189 }
190 else
191 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400192 // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
193 // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
Geoff Langcec35902014-04-16 10:52:36 -0400194 if (!gl::IsValidInternalFormat(actualInternalFormat, context->getCaps().extensions, context->getClientVersion()) ||
Geoff Lange4a492b2014-06-19 14:14:41 -0400195 !gl::IsValidFormat(format, context->getCaps().extensions, context->getClientVersion()) ||
196 !gl::IsValidType(type, context->getCaps().extensions, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400197 {
198 return gl::error(GL_INVALID_ENUM, false);
199 }
200
Geoff Lange4a492b2014-06-19 14:14:41 -0400201 if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getCaps().extensions, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400202 {
203 return gl::error(GL_INVALID_OPERATION, false);
204 }
205
206 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
207 {
208 return gl::error(GL_INVALID_OPERATION, false);
209 }
210 }
211
212 // Validate sub image parameters
213 if (isSubImage)
214 {
215 if (isCompressed != textureCompressed)
216 {
217 return gl::error(GL_INVALID_OPERATION, false);
218 }
219
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400220 if (isCompressed)
221 {
222 if ((width % 4 != 0 && width != textureLevelWidth) ||
223 (height % 4 != 0 && height != textureLevelHeight))
224 {
225 return gl::error(GL_INVALID_OPERATION, false);
226 }
227 }
228
229 if (width == 0 || height == 0 || depth == 0)
230 {
231 return false;
232 }
233
234 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
235 {
236 return gl::error(GL_INVALID_VALUE, false);
237 }
238
239 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
240 std::numeric_limits<GLsizei>::max() - yoffset < height ||
241 std::numeric_limits<GLsizei>::max() - zoffset < depth)
242 {
243 return gl::error(GL_INVALID_VALUE, false);
244 }
245
246 if (xoffset + width > textureLevelWidth ||
247 yoffset + height > textureLevelHeight ||
248 zoffset + depth > textureLevelDepth)
249 {
250 return gl::error(GL_INVALID_VALUE, false);
251 }
252 }
253
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400254 // Check for pixel unpack buffer related API errors
255 gl::Buffer *pixelUnpackBuffer = context->getPixelUnpackBuffer();
256 if (pixelUnpackBuffer != NULL)
257 {
258 // ...the data would be unpacked from the buffer object such that the memory reads required
259 // would exceed the data store size.
260 size_t widthSize = static_cast<size_t>(width);
261 size_t heightSize = static_cast<size_t>(height);
262 size_t depthSize = static_cast<size_t>(depth);
Geoff Lange4a492b2014-06-19 14:14:41 -0400263 GLenum sizedFormat = gl::IsSizedInternalFormat(actualInternalFormat) ? actualInternalFormat
264 : gl::GetSizedInternalFormat(actualInternalFormat, type);
Jamie Madill6f38f822014-06-06 17:12:20 -0400265
Geoff Lange4a492b2014-06-19 14:14:41 -0400266 size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(sizedFormat));
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400267
268 if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) ||
269 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) ||
270 !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes))
271 {
272 // Overflow past the end of the buffer
273 return gl::error(GL_INVALID_OPERATION, false);
274 }
275
276 size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes;
277 size_t offset = reinterpret_cast<size_t>(pixels);
278
Jamie Madill6f38f822014-06-06 17:12:20 -0400279 if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) ||
Brandon Jonesd38f9262014-06-18 16:26:45 -0700280 ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize())))
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400281 {
282 // Overflow past the end of the buffer
283 return gl::error(GL_INVALID_OPERATION, false);
284 }
285
286 // ...data is not evenly divisible into the number of bytes needed to store in memory a datum
287 // indicated by type.
288 size_t dataBytesPerPixel = static_cast<size_t>(gl::GetTypeBytes(type));
289
290 if ((offset % dataBytesPerPixel) != 0)
291 {
292 return gl::error(GL_INVALID_OPERATION, false);
293 }
294
Jamie Madill7a5f7382014-03-05 15:01:24 -0500295 // ...the buffer object's data store is currently mapped.
Brandon Jonesd38f9262014-06-18 16:26:45 -0700296 if (pixelUnpackBuffer->isMapped())
Jamie Madill7a5f7382014-03-05 15:01:24 -0500297 {
298 return gl::error(GL_INVALID_OPERATION, false);
299 }
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400300 }
301
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400302 return true;
303}
304
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400305bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat,
Jamie Madill6f38f822014-06-06 17:12:20 -0400306 bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset,
307 GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400308{
Jamie Madill560a8d82014-05-21 13:06:20 -0400309 GLenum textureInternalFormat;
310 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
Jamie Madill6f38f822014-06-06 17:12:20 -0400311 xoffset, yoffset, zoffset, x, y, width, height,
312 border, &textureInternalFormat))
Shannon Woods4dfed832014-03-17 20:03:39 -0400313 {
Jamie Madill560a8d82014-05-21 13:06:20 -0400314 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400315 }
316
317 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -0400318
319 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
320 {
321 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
322 }
323
324 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
325 {
326 return gl::error(GL_INVALID_OPERATION, false);
327 }
328
329 gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400330 GLenum colorbufferInternalFormat = source->getInternalFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400331
332 if (isSubImage)
333 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400334 if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat,
335 context->getReadFramebufferHandle(),
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400336 context->getClientVersion()))
337 {
338 return gl::error(GL_INVALID_OPERATION, false);
339 }
340 }
Shannon Woods4d161ba2014-03-17 18:13:30 -0400341 else
342 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400343 if (!gl::IsValidCopyTexImageCombination(internalformat, colorbufferInternalFormat,
344 context->getReadFramebufferHandle(),
Shannon Woods4d161ba2014-03-17 18:13:30 -0400345 context->getClientVersion()))
346 {
347 return gl::error(GL_INVALID_OPERATION, false);
348 }
349 }
350
Geoff Lang784a8fd2013-09-24 12:33:16 -0400351 // If width or height is zero, it is a no-op. Return false without setting an error.
352 return (width > 0 && height > 0);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400353}
354
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400355bool ValidateES3TexStorageParameters(gl::Context *context, GLenum target, GLsizei levels, GLenum internalformat,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400356 GLsizei width, GLsizei height, GLsizei depth)
357{
358 if (width < 1 || height < 1 || depth < 1 || levels < 1)
359 {
360 return gl::error(GL_INVALID_VALUE, false);
361 }
362
363 if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1)
364 {
365 return gl::error(GL_INVALID_OPERATION, false);
366 }
367
368 gl::Texture *texture = NULL;
369 switch (target)
370 {
371 case GL_TEXTURE_2D:
372 {
373 texture = context->getTexture2D();
374
375 if (width > (context->getMaximum2DTextureDimension()) ||
376 height > (context->getMaximum2DTextureDimension()))
377 {
378 return gl::error(GL_INVALID_VALUE, false);
379 }
380 }
381 break;
382
Geoff Lang01c21d22013-09-24 11:52:16 -0400383 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400384 {
385 texture = context->getTextureCubeMap();
386
387 if (width != height)
388 {
389 return gl::error(GL_INVALID_VALUE, false);
390 }
391
392 if (width > (context->getMaximumCubeTextureDimension()))
393 {
394 return gl::error(GL_INVALID_VALUE, false);
395 }
396 }
397 break;
398
399 case GL_TEXTURE_3D:
400 {
401 texture = context->getTexture3D();
402
403 if (width > (context->getMaximum3DTextureDimension()) ||
404 height > (context->getMaximum3DTextureDimension()) ||
405 depth > (context->getMaximum3DTextureDimension()))
406 {
407 return gl::error(GL_INVALID_VALUE, false);
408 }
409 }
410 break;
411
412 case GL_TEXTURE_2D_ARRAY:
413 {
414 texture = context->getTexture2DArray();
415
416 if (width > (context->getMaximum2DTextureDimension()) ||
417 height > (context->getMaximum2DTextureDimension()) ||
418 depth > (context->getMaximum2DArrayTextureLayers()))
419 {
420 return gl::error(GL_INVALID_VALUE, false);
421 }
422 }
423 break;
424
425 default:
426 return gl::error(GL_INVALID_ENUM, false);
427 }
428
429 if (!texture || texture->id() == 0)
430 {
431 return gl::error(GL_INVALID_OPERATION, false);
432 }
433
434 if (texture->isImmutable())
435 {
436 return gl::error(GL_INVALID_OPERATION, false);
437 }
438
Geoff Langcec35902014-04-16 10:52:36 -0400439 if (!gl::IsValidInternalFormat(internalformat, context->getCaps().extensions, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400440 {
441 return gl::error(GL_INVALID_ENUM, false);
442 }
443
Geoff Lange4a492b2014-06-19 14:14:41 -0400444 if (!gl::IsSizedInternalFormat(internalformat))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400445 {
446 return gl::error(GL_INVALID_ENUM, false);
447 }
448
449 return true;
450}
451
Jamie Madill570f7c82014-07-03 10:38:54 -0400452bool ValidateES3FramebufferTextureParameters(const gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400453 GLenum textarget, GLuint texture, GLint level, GLint layer,
454 bool layerCall)
455{
456 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
457 {
458 return gl::error(GL_INVALID_ENUM, false);
459 }
460
461 if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15)
462 {
463 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0);
464 if (colorAttachment >= context->getMaximumRenderTargets())
465 {
466 return gl::error(GL_INVALID_VALUE, false);
467 }
468 }
469 else
470 {
471 switch (attachment)
472 {
473 case GL_DEPTH_ATTACHMENT:
474 case GL_STENCIL_ATTACHMENT:
475 case GL_DEPTH_STENCIL_ATTACHMENT:
476 break;
477 default:
478 return gl::error(GL_INVALID_ENUM, false);
479 }
480 }
481
482 if (texture != 0)
483 {
484 gl::Texture *tex = context->getTexture(texture);
485
486 if (tex == NULL)
487 {
488 return gl::error(GL_INVALID_OPERATION, false);
489 }
490
491 if (level < 0)
492 {
493 return gl::error(GL_INVALID_VALUE, false);
494 }
495
496 if (layer < 0)
497 {
498 return gl::error(GL_INVALID_VALUE, false);
499 }
500
501 if (!layerCall)
502 {
503 switch (textarget)
504 {
505 case GL_TEXTURE_2D:
506 {
507 if (level > gl::log2(context->getMaximum2DTextureDimension()))
508 {
509 return gl::error(GL_INVALID_VALUE, false);
510 }
511 if (tex->getTarget() != GL_TEXTURE_2D)
512 {
513 return gl::error(GL_INVALID_OPERATION, false);
514 }
515 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
516 if (tex2d->isCompressed(level))
517 {
518 return gl::error(GL_INVALID_OPERATION, false);
519 }
520 break;
521 }
522
523 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
524 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
525 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
526 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
527 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
528 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
529 {
530 if (level > gl::log2(context->getMaximumCubeTextureDimension()))
531 {
532 return gl::error(GL_INVALID_VALUE, false);
533 }
534 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
535 {
536 return gl::error(GL_INVALID_OPERATION, false);
537 }
538 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
539 if (texcube->isCompressed(textarget, level))
540 {
541 return gl::error(GL_INVALID_OPERATION, false);
542 }
543 break;
544 }
545
546 default:
547 return gl::error(GL_INVALID_ENUM, false);
548 }
549 }
550 else
551 {
552 switch (tex->getTarget())
553 {
554 case GL_TEXTURE_2D_ARRAY:
555 {
556 if (level > gl::log2(context->getMaximum2DTextureDimension()))
557 {
558 return gl::error(GL_INVALID_VALUE, false);
559 }
560
561 if (layer >= context->getMaximum2DArrayTextureLayers())
562 {
563 return gl::error(GL_INVALID_VALUE, false);
564 }
565
566 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
567 if (texArray->isCompressed(level))
568 {
569 return gl::error(GL_INVALID_OPERATION, false);
570 }
571
572 break;
573 }
574
575 case GL_TEXTURE_3D:
576 {
577 if (level > gl::log2(context->getMaximum3DTextureDimension()))
578 {
579 return gl::error(GL_INVALID_VALUE, false);
580 }
581
582 if (layer >= context->getMaximum3DTextureDimension())
583 {
584 return gl::error(GL_INVALID_VALUE, false);
585 }
586
587 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
588 if (tex3d->isCompressed(level))
589 {
590 return gl::error(GL_INVALID_OPERATION, false);
591 }
592
593 break;
594 }
595
596 default:
597 return gl::error(GL_INVALID_OPERATION, false);
598 }
599 }
600 }
601
Jamie Madill570f7c82014-07-03 10:38:54 -0400602 const gl::Framebuffer *framebuffer = NULL;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400603 GLuint framebufferHandle = 0;
604 if (target == GL_READ_FRAMEBUFFER)
605 {
606 framebuffer = context->getReadFramebuffer();
607 framebufferHandle = context->getReadFramebufferHandle();
608 }
609 else
610 {
611 framebuffer = context->getDrawFramebuffer();
612 framebufferHandle = context->getDrawFramebufferHandle();
613 }
614
615 if (framebufferHandle == 0 || !framebuffer)
616 {
617 return gl::error(GL_INVALID_OPERATION, false);
618 }
619
620 return true;
621}
622
Jamie Madill570f7c82014-07-03 10:38:54 -0400623bool ValidateFramebufferTextureLayer(const gl::Context *context, GLenum target, GLenum attachment,
624 GLuint texture, GLint level, GLint layer)
625{
626 if (context->getClientVersion() < 3)
627 {
628 return gl::error(GL_INVALID_OPERATION, false);
629 }
630
631 return ValidateES3FramebufferTextureParameters(context, target, attachment, GL_NONE, texture, level, layer, true);
632}
633
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400634bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635{
636 switch (format)
637 {
638 case GL_RGBA:
639 switch (type)
640 {
641 case GL_UNSIGNED_BYTE:
642 break;
643 case GL_UNSIGNED_INT_2_10_10_10_REV:
644 if (internalFormat != GL_RGB10_A2)
645 {
646 return false;
647 }
648 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400649 case GL_FLOAT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400650 if (gl::GetComponentType(internalFormat) != GL_FLOAT)
Geoff Lang1ec57f82013-10-16 11:43:23 -0400651 {
652 return false;
653 }
654 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 default:
656 return false;
657 }
658 break;
659 case GL_RGBA_INTEGER:
660 switch (type)
661 {
662 case GL_INT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400663 if (gl::GetComponentType(internalFormat) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664 {
665 return false;
666 }
667 break;
668 case GL_UNSIGNED_INT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400669 if (gl::GetComponentType(internalFormat) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 {
671 return false;
672 }
673 break;
674 default:
675 return false;
676 }
677 break;
678 case GL_BGRA_EXT:
679 switch (type)
680 {
681 case GL_UNSIGNED_BYTE:
682 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
683 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
684 break;
685 default:
686 return false;
687 }
688 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400689 case GL_RG_EXT:
690 case GL_RED_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400691 if (!context->getCaps().extensions.textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400692 {
693 return false;
694 }
695 switch (type)
696 {
697 case GL_UNSIGNED_BYTE:
698 break;
699 default:
700 return false;
701 }
702 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 default:
704 return false;
705 }
706 return true;
707}
708
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400709bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710 const GLenum* attachments)
711{
712 bool defaultFramebuffer = false;
713
714 switch (target)
715 {
716 case GL_DRAW_FRAMEBUFFER:
717 case GL_FRAMEBUFFER:
718 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
719 break;
720 case GL_READ_FRAMEBUFFER:
721 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
722 break;
723 default:
724 return gl::error(GL_INVALID_ENUM, false);
725 }
726
727 for (int i = 0; i < numAttachments; ++i)
728 {
729 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
730 {
731 if (defaultFramebuffer)
732 {
733 return gl::error(GL_INVALID_ENUM, false);
734 }
735
736 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
737 {
738 return gl::error(GL_INVALID_OPERATION, false);
739 }
740 }
741 else
742 {
743 switch (attachments[i])
744 {
745 case GL_DEPTH_ATTACHMENT:
746 case GL_STENCIL_ATTACHMENT:
747 case GL_DEPTH_STENCIL_ATTACHMENT:
748 if (defaultFramebuffer)
749 {
750 return gl::error(GL_INVALID_ENUM, false);
751 }
752 break;
753 case GL_COLOR:
754 case GL_DEPTH:
755 case GL_STENCIL:
756 if (!defaultFramebuffer)
757 {
758 return gl::error(GL_INVALID_ENUM, false);
759 }
760 break;
761 default:
762 return gl::error(GL_INVALID_ENUM, false);
763 }
764 }
765 }
766
767 return true;
768}
769
Jamie Madill13f7d7d2014-06-20 13:21:27 -0400770bool ValidateClearBuffer(const gl::Context *context)
771{
772 if (context->getClientVersion() < 3)
773 {
774 return gl::error(GL_INVALID_OPERATION, false);
775 }
776
777 const gl::Framebuffer *fbo = context->getDrawFramebuffer();
778 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
779 {
780 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
781 }
782
783 return true;
784}
785
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786}