blob: a584a7127b222724a3cf3f9fea49652d9004ad9d [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 Langaae65a42014-05-26 12:43:44 -040054 const gl::Caps &caps = context->getCaps();
55
Geoff Lange8ebe7f2013-08-05 15:03:13 -040056 gl::Texture *texture = NULL;
57 bool textureCompressed = false;
58 GLenum textureInternalFormat = GL_NONE;
59 GLint textureLevelWidth = 0;
60 GLint textureLevelHeight = 0;
61 GLint textureLevelDepth = 0;
62 switch (target)
63 {
64 case GL_TEXTURE_2D:
65 {
Geoff Langaae65a42014-05-26 12:43:44 -040066 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
67 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040068 {
69 return gl::error(GL_INVALID_VALUE, false);
70 }
71
72 gl::Texture2D *texture2d = context->getTexture2D();
73 if (texture2d)
74 {
75 textureCompressed = texture2d->isCompressed(level);
76 textureInternalFormat = texture2d->getInternalFormat(level);
77 textureLevelWidth = texture2d->getWidth(level);
78 textureLevelHeight = texture2d->getHeight(level);
79 textureLevelDepth = 1;
80 texture = texture2d;
81 }
82 }
83 break;
84
85 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
86 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
87 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
88 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
89 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
90 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
91 {
92 if (!isSubImage && width != height)
93 {
94 return gl::error(GL_INVALID_VALUE, false);
95 }
96
Geoff Langaae65a42014-05-26 12:43:44 -040097 if (static_cast<GLuint>(width) > (caps.maxCubeMapTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -040098 {
99 return gl::error(GL_INVALID_VALUE, false);
100 }
101
102 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
103 if (textureCube)
104 {
105 textureCompressed = textureCube->isCompressed(target, level);
106 textureInternalFormat = textureCube->getInternalFormat(target, level);
107 textureLevelWidth = textureCube->getWidth(target, level);
108 textureLevelHeight = textureCube->getHeight(target, level);
109 textureLevelDepth = 1;
110 texture = textureCube;
111 }
112 }
113 break;
114
115 case GL_TEXTURE_3D:
116 {
Geoff Langaae65a42014-05-26 12:43:44 -0400117 if (static_cast<GLuint>(width) > (caps.max3DTextureSize >> level) ||
118 static_cast<GLuint>(height) > (caps.max3DTextureSize >> level) ||
119 static_cast<GLuint>(depth) > (caps.max3DTextureSize >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400120 {
121 return gl::error(GL_INVALID_VALUE, false);
122 }
123
124 gl::Texture3D *texture3d = context->getTexture3D();
125 if (texture3d)
126 {
127 textureCompressed = texture3d->isCompressed(level);
128 textureInternalFormat = texture3d->getInternalFormat(level);
129 textureLevelWidth = texture3d->getWidth(level);
130 textureLevelHeight = texture3d->getHeight(level);
131 textureLevelDepth = texture3d->getDepth(level);
132 texture = texture3d;
133 }
134 }
135 break;
136
137 case GL_TEXTURE_2D_ARRAY:
138 {
Geoff Langaae65a42014-05-26 12:43:44 -0400139 if (static_cast<GLuint>(width) > (caps.max2DTextureSize >> level) ||
140 static_cast<GLuint>(height) > (caps.max2DTextureSize >> level) ||
141 static_cast<GLuint>(depth) > (caps.maxArrayTextureLayers >> level))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400142 {
143 return gl::error(GL_INVALID_VALUE, false);
144 }
145
146 gl::Texture2DArray *texture2darray = context->getTexture2DArray();
147 if (texture2darray)
148 {
149 textureCompressed = texture2darray->isCompressed(level);
150 textureInternalFormat = texture2darray->getInternalFormat(level);
151 textureLevelWidth = texture2darray->getWidth(level);
152 textureLevelHeight = texture2darray->getHeight(level);
Jamie Madillb8f8b892014-01-07 10:12:50 -0500153 textureLevelDepth = texture2darray->getLayers(level);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400154 texture = texture2darray;
155 }
156 }
157 break;
158
159 default:
160 return gl::error(GL_INVALID_ENUM, false);
161 }
162
163 if (!texture)
164 {
165 return gl::error(GL_INVALID_OPERATION, false);
166 }
167
168 if (texture->isImmutable() && !isSubImage)
169 {
170 return gl::error(GL_INVALID_OPERATION, false);
171 }
172
173 // Validate texture formats
174 GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
175 if (isCompressed)
176 {
Geoff Langd4f180b2013-09-24 13:57:44 -0400177 if (!ValidCompressedImageSize(context, actualInternalFormat, width, height))
178 {
179 return gl::error(GL_INVALID_OPERATION, false);
180 }
181
Geoff Lange4a492b2014-06-19 14:14:41 -0400182 if (!gl::IsFormatCompressed(actualInternalFormat))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400183 {
184 return gl::error(GL_INVALID_ENUM, false);
185 }
186
187 if (target == GL_TEXTURE_3D)
188 {
189 return gl::error(GL_INVALID_OPERATION, false);
190 }
191 }
192 else
193 {
Jamie Madill6f38f822014-06-06 17:12:20 -0400194 // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid
195 // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d)
Geoff Langc0b9ef42014-07-02 10:02:37 -0400196 if (!gl::IsValidInternalFormat(actualInternalFormat, context->getExtensions(), context->getClientVersion()) ||
197 !gl::IsValidFormat(format, context->getExtensions(), context->getClientVersion()) ||
198 !gl::IsValidType(type, context->getExtensions(), context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400199 {
200 return gl::error(GL_INVALID_ENUM, false);
201 }
202
Geoff Langc0b9ef42014-07-02 10:02:37 -0400203 if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getExtensions(), context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400204 {
205 return gl::error(GL_INVALID_OPERATION, false);
206 }
207
208 if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
209 {
210 return gl::error(GL_INVALID_OPERATION, false);
211 }
212 }
213
214 // Validate sub image parameters
215 if (isSubImage)
216 {
217 if (isCompressed != textureCompressed)
218 {
219 return gl::error(GL_INVALID_OPERATION, false);
220 }
221
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400222 if (isCompressed)
223 {
224 if ((width % 4 != 0 && width != textureLevelWidth) ||
225 (height % 4 != 0 && height != textureLevelHeight))
226 {
227 return gl::error(GL_INVALID_OPERATION, false);
228 }
229 }
230
231 if (width == 0 || height == 0 || depth == 0)
232 {
233 return false;
234 }
235
236 if (xoffset < 0 || yoffset < 0 || zoffset < 0)
237 {
238 return gl::error(GL_INVALID_VALUE, false);
239 }
240
241 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
242 std::numeric_limits<GLsizei>::max() - yoffset < height ||
243 std::numeric_limits<GLsizei>::max() - zoffset < depth)
244 {
245 return gl::error(GL_INVALID_VALUE, false);
246 }
247
248 if (xoffset + width > textureLevelWidth ||
249 yoffset + height > textureLevelHeight ||
250 zoffset + depth > textureLevelDepth)
251 {
252 return gl::error(GL_INVALID_VALUE, false);
253 }
254 }
255
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400256 // Check for pixel unpack buffer related API errors
Shannon Woods53a94a82014-06-24 15:20:36 -0400257 gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
Jamie Madillefb2a6f2013-09-24 10:22:42 -0400258 if (pixelUnpackBuffer != NULL)
259 {
260 // ...the data would be unpacked from the buffer object such that the memory reads required
261 // would exceed the data store size.
262 size_t widthSize = static_cast<size_t>(width);
263 size_t heightSize = static_cast<size_t>(height);
264 size_t depthSize = static_cast<size_t>(depth);
Geoff Lange4a492b2014-06-19 14:14:41 -0400265 GLenum sizedFormat = gl::IsSizedInternalFormat(actualInternalFormat) ? actualInternalFormat
266 : gl::GetSizedInternalFormat(actualInternalFormat, type);
Jamie Madill6f38f822014-06-06 17:12:20 -0400267
Geoff Lange4a492b2014-06-19 14:14:41 -0400268 size_t pixelBytes = static_cast<size_t>(gl::GetPixelBytes(sizedFormat));
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) ||
Brandon Jonesd38f9262014-06-18 16:26:45 -0700282 ((offset + copyBytes) > static_cast<size_t>(pixelUnpackBuffer->getSize())))
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.
Brandon Jonesd38f9262014-06-18 16:26:45 -0700298 if (pixelUnpackBuffer->isMapped())
Jamie Madill7a5f7382014-03-05 15:01:24 -0500299 {
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
Shannon Woods53a94a82014-06-24 15:20:36 -0400319 gl::Framebuffer *framebuffer = context->getState().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
Shannon Woods53a94a82014-06-24 15:20:36 -0400326 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
Jamie Madill3c7fa222014-06-05 13:08:51 -0400327 {
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,
Shannon Woods53a94a82014-06-24 15:20:36 -0400337 context->getState().getReadFramebuffer()->id(),
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,
Shannon Woods53a94a82014-06-24 15:20:36 -0400346 context->getState().getReadFramebuffer()->id(),
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
Geoff Langaae65a42014-05-26 12:43:44 -0400370 const gl::Caps &caps = context->getCaps();
371
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400372 gl::Texture *texture = NULL;
373 switch (target)
374 {
375 case GL_TEXTURE_2D:
376 {
377 texture = context->getTexture2D();
378
Geoff Langaae65a42014-05-26 12:43:44 -0400379 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
380 static_cast<GLuint>(height) > caps.max2DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400381 {
382 return gl::error(GL_INVALID_VALUE, false);
383 }
384 }
385 break;
386
Geoff Lang01c21d22013-09-24 11:52:16 -0400387 case GL_TEXTURE_CUBE_MAP:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400388 {
389 texture = context->getTextureCubeMap();
390
391 if (width != height)
392 {
393 return gl::error(GL_INVALID_VALUE, false);
394 }
395
Geoff Langaae65a42014-05-26 12:43:44 -0400396 if (static_cast<GLuint>(width) > caps.maxCubeMapTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400397 {
398 return gl::error(GL_INVALID_VALUE, false);
399 }
400 }
401 break;
402
403 case GL_TEXTURE_3D:
404 {
405 texture = context->getTexture3D();
406
Geoff Langaae65a42014-05-26 12:43:44 -0400407 if (static_cast<GLuint>(width) > caps.max3DTextureSize ||
408 static_cast<GLuint>(height) > caps.max3DTextureSize ||
409 static_cast<GLuint>(depth) > caps.max3DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400410 {
411 return gl::error(GL_INVALID_VALUE, false);
412 }
413 }
414 break;
415
416 case GL_TEXTURE_2D_ARRAY:
417 {
418 texture = context->getTexture2DArray();
419
Geoff Langaae65a42014-05-26 12:43:44 -0400420 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
421 static_cast<GLuint>(height) > caps.max2DTextureSize ||
422 static_cast<GLuint>(depth) > caps.maxArrayTextureLayers)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423 {
424 return gl::error(GL_INVALID_VALUE, false);
425 }
426 }
427 break;
428
429 default:
430 return gl::error(GL_INVALID_ENUM, false);
431 }
432
433 if (!texture || texture->id() == 0)
434 {
435 return gl::error(GL_INVALID_OPERATION, false);
436 }
437
438 if (texture->isImmutable())
439 {
440 return gl::error(GL_INVALID_OPERATION, false);
441 }
442
Geoff Langc0b9ef42014-07-02 10:02:37 -0400443 if (!gl::IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 {
445 return gl::error(GL_INVALID_ENUM, false);
446 }
447
Geoff Lange4a492b2014-06-19 14:14:41 -0400448 if (!gl::IsSizedInternalFormat(internalformat))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400449 {
450 return gl::error(GL_INVALID_ENUM, false);
451 }
452
453 return true;
454}
455
Jamie Madill570f7c82014-07-03 10:38:54 -0400456bool ValidateFramebufferTextureLayer(const gl::Context *context, GLenum target, GLenum attachment,
457 GLuint texture, GLint level, GLint layer)
458{
459 if (context->getClientVersion() < 3)
460 {
461 return gl::error(GL_INVALID_OPERATION, false);
462 }
463
Jamie Madill55ec3b12014-07-03 10:38:57 -0400464 if (layer < 0)
465 {
466 return gl::error(GL_INVALID_VALUE, false);
467 }
468
469 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
470 {
471 return false;
472 }
473
474 const gl::Caps &caps = context->getCaps();
475 if (texture != 0)
476 {
477 gl::Texture *tex = context->getTexture(texture);
478 ASSERT(tex);
479
480 switch (tex->getTarget())
481 {
482 case GL_TEXTURE_2D_ARRAY:
483 {
484 if (level > gl::log2(caps.max2DTextureSize))
485 {
486 return gl::error(GL_INVALID_VALUE, false);
487 }
488
489 if (static_cast<GLuint>(layer) >= caps.maxArrayTextureLayers)
490 {
491 return gl::error(GL_INVALID_VALUE, false);
492 }
493
494 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
495 if (texArray->isCompressed(level))
496 {
497 return gl::error(GL_INVALID_OPERATION, false);
498 }
499 }
500 break;
501
502 case GL_TEXTURE_3D:
503 {
504 if (level > gl::log2(caps.max3DTextureSize))
505 {
506 return gl::error(GL_INVALID_VALUE, false);
507 }
508
509 if (static_cast<GLuint>(layer) >= caps.max3DTextureSize)
510 {
511 return gl::error(GL_INVALID_VALUE, false);
512 }
513
514 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
515 if (tex3d->isCompressed(level))
516 {
517 return gl::error(GL_INVALID_OPERATION, false);
518 }
519 }
520 break;
521
522 default:
523 return gl::error(GL_INVALID_OPERATION, false);
524 }
525 }
526
527 return true;
Jamie Madill570f7c82014-07-03 10:38:54 -0400528}
529
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400530bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531{
532 switch (format)
533 {
534 case GL_RGBA:
535 switch (type)
536 {
537 case GL_UNSIGNED_BYTE:
538 break;
539 case GL_UNSIGNED_INT_2_10_10_10_REV:
540 if (internalFormat != GL_RGB10_A2)
541 {
542 return false;
543 }
544 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400545 case GL_FLOAT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400546 if (gl::GetComponentType(internalFormat) != GL_FLOAT)
Geoff Lang1ec57f82013-10-16 11:43:23 -0400547 {
548 return false;
549 }
550 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400551 default:
552 return false;
553 }
554 break;
555 case GL_RGBA_INTEGER:
556 switch (type)
557 {
558 case GL_INT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400559 if (gl::GetComponentType(internalFormat) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400560 {
561 return false;
562 }
563 break;
564 case GL_UNSIGNED_INT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400565 if (gl::GetComponentType(internalFormat) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400566 {
567 return false;
568 }
569 break;
570 default:
571 return false;
572 }
573 break;
574 case GL_BGRA_EXT:
575 switch (type)
576 {
577 case GL_UNSIGNED_BYTE:
578 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
579 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
580 break;
581 default:
582 return false;
583 }
584 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400585 case GL_RG_EXT:
586 case GL_RED_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400587 if (!context->getExtensions().textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400588 {
589 return false;
590 }
591 switch (type)
592 {
593 case GL_UNSIGNED_BYTE:
594 break;
595 default:
596 return false;
597 }
598 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400599 default:
600 return false;
601 }
602 return true;
603}
604
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400605bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606 const GLenum* attachments)
607{
608 bool defaultFramebuffer = false;
609
610 switch (target)
611 {
612 case GL_DRAW_FRAMEBUFFER:
613 case GL_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -0400614 defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 break;
616 case GL_READ_FRAMEBUFFER:
Shannon Woods53a94a82014-06-24 15:20:36 -0400617 defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400618 break;
619 default:
620 return gl::error(GL_INVALID_ENUM, false);
621 }
622
623 for (int i = 0; i < numAttachments; ++i)
624 {
625 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
626 {
627 if (defaultFramebuffer)
628 {
629 return gl::error(GL_INVALID_ENUM, false);
630 }
631
Geoff Langaae65a42014-05-26 12:43:44 -0400632 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 {
634 return gl::error(GL_INVALID_OPERATION, false);
635 }
636 }
637 else
638 {
639 switch (attachments[i])
640 {
641 case GL_DEPTH_ATTACHMENT:
642 case GL_STENCIL_ATTACHMENT:
643 case GL_DEPTH_STENCIL_ATTACHMENT:
644 if (defaultFramebuffer)
645 {
646 return gl::error(GL_INVALID_ENUM, false);
647 }
648 break;
649 case GL_COLOR:
650 case GL_DEPTH:
651 case GL_STENCIL:
652 if (!defaultFramebuffer)
653 {
654 return gl::error(GL_INVALID_ENUM, false);
655 }
656 break;
657 default:
658 return gl::error(GL_INVALID_ENUM, false);
659 }
660 }
661 }
662
663 return true;
664}
665
Jamie Madill13f7d7d2014-06-20 13:21:27 -0400666bool ValidateClearBuffer(const gl::Context *context)
667{
668 if (context->getClientVersion() < 3)
669 {
670 return gl::error(GL_INVALID_OPERATION, false);
671 }
672
Shannon Woods53a94a82014-06-24 15:20:36 -0400673 const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer();
Jamie Madill13f7d7d2014-06-20 13:21:27 -0400674 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
675 {
676 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
677 }
678
679 return true;
680}
681
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400682}