blob: dfb0356b707ddfef96fcf3ccb0d6128b29dee2ee [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 Langcec35902014-04-16 10:52:36 -0400196 if (!gl::IsValidInternalFormat(actualInternalFormat, context->getCaps().extensions, context->getClientVersion()) ||
Geoff Lange4a492b2014-06-19 14:14:41 -0400197 !gl::IsValidFormat(format, context->getCaps().extensions, context->getClientVersion()) ||
198 !gl::IsValidType(type, context->getCaps().extensions, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400199 {
200 return gl::error(GL_INVALID_ENUM, false);
201 }
202
Geoff Lange4a492b2014-06-19 14:14:41 -0400203 if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getCaps().extensions, 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
257 gl::Buffer *pixelUnpackBuffer = context->getPixelUnpackBuffer();
258 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
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
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 Langcec35902014-04-16 10:52:36 -0400443 if (!gl::IsValidInternalFormat(internalformat, context->getCaps().extensions, 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 ValidateES3FramebufferTextureParameters(const gl::Context *context, GLenum target, GLenum attachment,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 GLenum textarget, GLuint texture, GLint level, GLint layer,
458 bool layerCall)
459{
460 if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
461 {
462 return gl::error(GL_INVALID_ENUM, false);
463 }
464
Jamie Madillb4472272014-07-03 10:38:55 -0400465 if (!ValidateAttachmentTarget(context, attachment))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400466 {
Jamie Madillb4472272014-07-03 10:38:55 -0400467 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400468 }
469
Geoff Langaae65a42014-05-26 12:43:44 -0400470 const gl::Caps &caps = context->getCaps();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400471 if (texture != 0)
472 {
473 gl::Texture *tex = context->getTexture(texture);
474
475 if (tex == NULL)
476 {
477 return gl::error(GL_INVALID_OPERATION, false);
478 }
479
480 if (level < 0)
481 {
482 return gl::error(GL_INVALID_VALUE, false);
483 }
484
485 if (layer < 0)
486 {
487 return gl::error(GL_INVALID_VALUE, false);
488 }
489
490 if (!layerCall)
491 {
492 switch (textarget)
493 {
494 case GL_TEXTURE_2D:
495 {
Geoff Langaae65a42014-05-26 12:43:44 -0400496 if (level > gl::log2(caps.max2DTextureSize))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400497 {
498 return gl::error(GL_INVALID_VALUE, false);
499 }
500 if (tex->getTarget() != GL_TEXTURE_2D)
501 {
502 return gl::error(GL_INVALID_OPERATION, false);
503 }
504 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
505 if (tex2d->isCompressed(level))
506 {
507 return gl::error(GL_INVALID_OPERATION, false);
508 }
509 break;
510 }
511
512 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
513 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
514 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
515 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
516 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
517 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
518 {
Geoff Langaae65a42014-05-26 12:43:44 -0400519 if (level > gl::log2(caps.maxCubeMapTextureSize))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400520 {
521 return gl::error(GL_INVALID_VALUE, false);
522 }
523 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
524 {
525 return gl::error(GL_INVALID_OPERATION, false);
526 }
527 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
528 if (texcube->isCompressed(textarget, level))
529 {
530 return gl::error(GL_INVALID_OPERATION, false);
531 }
532 break;
533 }
534
535 default:
536 return gl::error(GL_INVALID_ENUM, false);
537 }
538 }
539 else
540 {
541 switch (tex->getTarget())
542 {
543 case GL_TEXTURE_2D_ARRAY:
544 {
Geoff Langaae65a42014-05-26 12:43:44 -0400545 if (level > gl::log2(caps.max2DTextureSize))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400546 {
547 return gl::error(GL_INVALID_VALUE, false);
548 }
549
Geoff Langaae65a42014-05-26 12:43:44 -0400550 if (static_cast<GLuint>(layer) >= caps.maxArrayTextureLayers)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400551 {
552 return gl::error(GL_INVALID_VALUE, false);
553 }
554
555 gl::Texture2DArray *texArray = static_cast<gl::Texture2DArray *>(tex);
556 if (texArray->isCompressed(level))
557 {
558 return gl::error(GL_INVALID_OPERATION, false);
559 }
560
561 break;
562 }
563
564 case GL_TEXTURE_3D:
565 {
Geoff Langaae65a42014-05-26 12:43:44 -0400566 if (level > gl::log2(caps.max3DTextureSize))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 {
568 return gl::error(GL_INVALID_VALUE, false);
569 }
570
Geoff Langaae65a42014-05-26 12:43:44 -0400571 if (static_cast<GLuint>(layer) >= caps.max3DTextureSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400572 {
573 return gl::error(GL_INVALID_VALUE, false);
574 }
575
576 gl::Texture3D *tex3d = static_cast<gl::Texture3D *>(tex);
577 if (tex3d->isCompressed(level))
578 {
579 return gl::error(GL_INVALID_OPERATION, false);
580 }
581
582 break;
583 }
584
585 default:
586 return gl::error(GL_INVALID_OPERATION, false);
587 }
588 }
589 }
590
Jamie Madill570f7c82014-07-03 10:38:54 -0400591 const gl::Framebuffer *framebuffer = NULL;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400592 GLuint framebufferHandle = 0;
593 if (target == GL_READ_FRAMEBUFFER)
594 {
595 framebuffer = context->getReadFramebuffer();
596 framebufferHandle = context->getReadFramebufferHandle();
597 }
598 else
599 {
600 framebuffer = context->getDrawFramebuffer();
601 framebufferHandle = context->getDrawFramebufferHandle();
602 }
603
604 if (framebufferHandle == 0 || !framebuffer)
605 {
606 return gl::error(GL_INVALID_OPERATION, false);
607 }
608
609 return true;
610}
611
Jamie Madill570f7c82014-07-03 10:38:54 -0400612bool ValidateFramebufferTextureLayer(const gl::Context *context, GLenum target, GLenum attachment,
613 GLuint texture, GLint level, GLint layer)
614{
615 if (context->getClientVersion() < 3)
616 {
617 return gl::error(GL_INVALID_OPERATION, false);
618 }
619
620 return ValidateES3FramebufferTextureParameters(context, target, attachment, GL_NONE, texture, level, layer, true);
621}
622
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400623bool ValidES3ReadFormatType(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624{
625 switch (format)
626 {
627 case GL_RGBA:
628 switch (type)
629 {
630 case GL_UNSIGNED_BYTE:
631 break;
632 case GL_UNSIGNED_INT_2_10_10_10_REV:
633 if (internalFormat != GL_RGB10_A2)
634 {
635 return false;
636 }
637 break;
Geoff Lang1ec57f82013-10-16 11:43:23 -0400638 case GL_FLOAT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400639 if (gl::GetComponentType(internalFormat) != GL_FLOAT)
Geoff Lang1ec57f82013-10-16 11:43:23 -0400640 {
641 return false;
642 }
643 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644 default:
645 return false;
646 }
647 break;
648 case GL_RGBA_INTEGER:
649 switch (type)
650 {
651 case GL_INT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400652 if (gl::GetComponentType(internalFormat) != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 {
654 return false;
655 }
656 break;
657 case GL_UNSIGNED_INT:
Geoff Lange4a492b2014-06-19 14:14:41 -0400658 if (gl::GetComponentType(internalFormat) != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 {
660 return false;
661 }
662 break;
663 default:
664 return false;
665 }
666 break;
667 case GL_BGRA_EXT:
668 switch (type)
669 {
670 case GL_UNSIGNED_BYTE:
671 case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
672 case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
673 break;
674 default:
675 return false;
676 }
677 break;
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400678 case GL_RG_EXT:
679 case GL_RED_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400680 if (!context->getCaps().extensions.textureRG)
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400681 {
682 return false;
683 }
684 switch (type)
685 {
686 case GL_UNSIGNED_BYTE:
687 break;
688 default:
689 return false;
690 }
691 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400692 default:
693 return false;
694 }
695 return true;
696}
697
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400698bool ValidateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400699 const GLenum* attachments)
700{
701 bool defaultFramebuffer = false;
702
703 switch (target)
704 {
705 case GL_DRAW_FRAMEBUFFER:
706 case GL_FRAMEBUFFER:
707 defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
708 break;
709 case GL_READ_FRAMEBUFFER:
710 defaultFramebuffer = context->getReadFramebufferHandle() == 0;
711 break;
712 default:
713 return gl::error(GL_INVALID_ENUM, false);
714 }
715
716 for (int i = 0; i < numAttachments; ++i)
717 {
718 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
719 {
720 if (defaultFramebuffer)
721 {
722 return gl::error(GL_INVALID_ENUM, false);
723 }
724
Geoff Langaae65a42014-05-26 12:43:44 -0400725 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400726 {
727 return gl::error(GL_INVALID_OPERATION, false);
728 }
729 }
730 else
731 {
732 switch (attachments[i])
733 {
734 case GL_DEPTH_ATTACHMENT:
735 case GL_STENCIL_ATTACHMENT:
736 case GL_DEPTH_STENCIL_ATTACHMENT:
737 if (defaultFramebuffer)
738 {
739 return gl::error(GL_INVALID_ENUM, false);
740 }
741 break;
742 case GL_COLOR:
743 case GL_DEPTH:
744 case GL_STENCIL:
745 if (!defaultFramebuffer)
746 {
747 return gl::error(GL_INVALID_ENUM, false);
748 }
749 break;
750 default:
751 return gl::error(GL_INVALID_ENUM, false);
752 }
753 }
754 }
755
756 return true;
757}
758
Jamie Madill13f7d7d2014-06-20 13:21:27 -0400759bool ValidateClearBuffer(const gl::Context *context)
760{
761 if (context->getClientVersion() < 3)
762 {
763 return gl::error(GL_INVALID_OPERATION, false);
764 }
765
766 const gl::Framebuffer *fbo = context->getDrawFramebuffer();
767 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
768 {
769 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
770 }
771
772 return true;
773}
774
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775}