blob: 66b988ad023c6e5e12da55852f7f7c9023d4c415 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
114 case GL_RASTERIZER_DISCARD:
115 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500116
117 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
118 case GL_DEBUG_OUTPUT:
119 return context->getExtensions().debug;
120
Geoff Lang0550d032014-01-30 11:29:07 -0500121 default:
122 return false;
123 }
124}
125
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500126bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400127{
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400129 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500130 case GL_TEXTURE_2D:
131 case GL_TEXTURE_CUBE_MAP:
132 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400133
Jamie Madilld7460c72014-01-21 16:38:14 -0500134 case GL_TEXTURE_3D:
135 case GL_TEXTURE_2D_ARRAY:
136 return (context->getClientVersion() >= 3);
137
138 default:
139 return false;
140 }
Jamie Madill35d15012013-10-07 10:46:37 -0400141}
142
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500143bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
144{
145 switch (target)
146 {
147 case GL_TEXTURE_2D:
148 case GL_TEXTURE_CUBE_MAP:
149 return true;
150
151 default:
152 return false;
153 }
154}
155
156bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
157{
158 switch (target)
159 {
160 case GL_TEXTURE_3D:
161 case GL_TEXTURE_2D_ARRAY:
162 return (context->getClientVersion() >= 3);
163
164 default:
165 return false;
166 }
167}
168
Shannon Woods4dfed832014-03-17 20:03:39 -0400169// This function differs from ValidTextureTarget in that the target must be
170// usable as the destination of a 2D operation-- so a cube face is valid, but
171// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400172// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500173bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400174{
175 switch (target)
176 {
177 case GL_TEXTURE_2D:
178 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
179 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
180 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
181 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
182 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
183 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
184 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500185 default:
186 return false;
187 }
188}
189
190bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
191{
192 switch (target)
193 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400194 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500195 case GL_TEXTURE_2D_ARRAY:
196 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400197 default:
198 return false;
199 }
200}
201
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500202bool ValidFramebufferTarget(GLenum target)
203{
Geoff Langd4475812015-03-18 10:53:05 -0400204 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
205 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500206
207 switch (target)
208 {
209 case GL_FRAMEBUFFER: return true;
210 case GL_READ_FRAMEBUFFER: return true;
211 case GL_DRAW_FRAMEBUFFER: return true;
212 default: return false;
213 }
214}
215
Jamie Madill8c96d582014-03-05 15:01:23 -0500216bool ValidBufferTarget(const Context *context, GLenum target)
217{
218 switch (target)
219 {
220 case GL_ARRAY_BUFFER:
221 case GL_ELEMENT_ARRAY_BUFFER:
222 return true;
223
Jamie Madill8c96d582014-03-05 15:01:23 -0500224 case GL_PIXEL_PACK_BUFFER:
225 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400226 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400227
Shannon Woodsb3801742014-03-27 14:59:19 -0400228 case GL_COPY_READ_BUFFER:
229 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500230 case GL_TRANSFORM_FEEDBACK_BUFFER:
231 case GL_UNIFORM_BUFFER:
232 return (context->getClientVersion() >= 3);
233
234 default:
235 return false;
236 }
237}
238
Jamie Madill70656a62014-03-05 15:01:26 -0500239bool ValidBufferParameter(const Context *context, GLenum pname)
240{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400241 const Extensions &extensions = context->getExtensions();
242
Jamie Madill70656a62014-03-05 15:01:26 -0500243 switch (pname)
244 {
245 case GL_BUFFER_USAGE:
246 case GL_BUFFER_SIZE:
247 return true;
248
Geoff Langcc6f55d2015-03-20 13:01:02 -0400249 case GL_BUFFER_ACCESS_OES:
250 return extensions.mapBuffer;
251
252 case GL_BUFFER_MAPPED:
253 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
254 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
255
Jamie Madill70656a62014-03-05 15:01:26 -0500256 // GL_BUFFER_MAP_POINTER is a special case, and may only be
257 // queried with GetBufferPointerv
258 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500259 case GL_BUFFER_MAP_OFFSET:
260 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400261 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500262
263 default:
264 return false;
265 }
266}
267
Jamie Madillc29968b2016-01-20 11:17:23 -0500268bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400269{
Jamie Madillc29968b2016-01-20 11:17:23 -0500270 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400271 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400272 switch (target)
273 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500274 case GL_TEXTURE_2D:
275 maxDimension = caps.max2DTextureSize;
276 break;
Geoff Langce635692013-09-24 13:56:32 -0400277 case GL_TEXTURE_CUBE_MAP:
278 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
279 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
280 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
281 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
282 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500283 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
284 maxDimension = caps.maxCubeMapTextureSize;
285 break;
286 case GL_TEXTURE_3D:
287 maxDimension = caps.max3DTextureSize;
288 break;
289 case GL_TEXTURE_2D_ARRAY:
290 maxDimension = caps.max2DTextureSize;
291 break;
Geoff Langce635692013-09-24 13:56:32 -0400292 default: UNREACHABLE();
293 }
294
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700295 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400296}
297
Austin Kinross08528e12015-10-07 16:24:40 -0700298bool ValidImageSizeParameters(const Context *context,
299 GLenum target,
300 GLint level,
301 GLsizei width,
302 GLsizei height,
303 GLsizei depth,
304 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400305{
306 if (level < 0 || width < 0 || height < 0 || depth < 0)
307 {
308 return false;
309 }
310
Austin Kinross08528e12015-10-07 16:24:40 -0700311 // TexSubImage parameters can be NPOT without textureNPOT extension,
312 // as long as the destination texture is POT.
313 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400314 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400315 {
316 return false;
317 }
318
319 if (!ValidMipLevel(context, target, level))
320 {
321 return false;
322 }
323
324 return true;
325}
326
Geoff Lang0d8b7242015-09-09 14:56:53 -0400327bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
328{
329 // List of compressed format that require that the texture size is smaller than or a multiple of
330 // the compressed block size.
331 switch (internalFormat)
332 {
333 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
334 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
335 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
336 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
337 return true;
338
339 default:
340 return false;
341 }
342}
343
Jamie Madillc29968b2016-01-20 11:17:23 -0500344bool ValidCompressedImageSize(const ValidationContext *context,
345 GLenum internalFormat,
346 GLsizei width,
347 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400348{
Geoff Lang5d601382014-07-22 15:14:06 -0400349 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
350 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400351 {
352 return false;
353 }
354
Geoff Lang0d8b7242015-09-09 14:56:53 -0400355 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400356 {
357 return false;
358 }
359
Geoff Lang0d8b7242015-09-09 14:56:53 -0400360 if (CompressedTextureFormatRequiresExactSize(internalFormat))
361 {
362 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
363 width % formatInfo.compressedBlockWidth != 0) ||
364 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
365 height % formatInfo.compressedBlockHeight != 0))
366 {
367 return false;
368 }
369 }
370
Geoff Langd4f180b2013-09-24 13:57:44 -0400371 return true;
372}
373
Geoff Lang37dde692014-01-31 16:34:54 -0500374bool ValidQueryType(const Context *context, GLenum queryType)
375{
Geoff Langd4475812015-03-18 10:53:05 -0400376 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
377 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500378
379 switch (queryType)
380 {
381 case GL_ANY_SAMPLES_PASSED:
382 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
383 return true;
384 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
385 return (context->getClientVersion() >= 3);
386 default:
387 return false;
388 }
389}
390
Dian Xiang769769a2015-09-09 15:20:08 -0700391Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500392{
393 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
394 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
395 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
396
Dian Xiang769769a2015-09-09 15:20:08 -0700397 Program *validProgram = context->getProgram(id);
398
399 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500400 {
Dian Xiang769769a2015-09-09 15:20:08 -0700401 if (context->getShader(id))
402 {
403 context->recordError(
404 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
405 }
406 else
407 {
408 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
409 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500410 }
Dian Xiang769769a2015-09-09 15:20:08 -0700411
412 return validProgram;
413}
414
415Shader *GetValidShader(Context *context, GLuint id)
416{
417 // See ValidProgram for spec details.
418
419 Shader *validShader = context->getShader(id);
420
421 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500422 {
Dian Xiang769769a2015-09-09 15:20:08 -0700423 if (context->getProgram(id))
424 {
425 context->recordError(
426 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
427 }
428 else
429 {
430 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
431 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500432 }
Dian Xiang769769a2015-09-09 15:20:08 -0700433
434 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500435}
436
Geoff Langb1196682014-07-23 13:47:29 -0400437bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400438{
439 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
440 {
441 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
442
Geoff Langaae65a42014-05-26 12:43:44 -0400443 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400444 {
Geoff Langb1196682014-07-23 13:47:29 -0400445 context->recordError(Error(GL_INVALID_VALUE));
446 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400447 }
448 }
449 else
450 {
451 switch (attachment)
452 {
453 case GL_DEPTH_ATTACHMENT:
454 case GL_STENCIL_ATTACHMENT:
455 break;
456
457 case GL_DEPTH_STENCIL_ATTACHMENT:
458 if (context->getClientVersion() < 3)
459 {
Geoff Langb1196682014-07-23 13:47:29 -0400460 context->recordError(Error(GL_INVALID_ENUM));
461 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400462 }
463 break;
464
465 default:
Geoff Langb1196682014-07-23 13:47:29 -0400466 context->recordError(Error(GL_INVALID_ENUM));
467 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400468 }
469 }
470
471 return true;
472}
473
Corentin Walleze0902642014-11-04 12:32:15 -0800474bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
475 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400476{
477 switch (target)
478 {
479 case GL_RENDERBUFFER:
480 break;
481 default:
Geoff Langb1196682014-07-23 13:47:29 -0400482 context->recordError(Error(GL_INVALID_ENUM));
483 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400484 }
485
486 if (width < 0 || height < 0 || samples < 0)
487 {
Geoff Langb1196682014-07-23 13:47:29 -0400488 context->recordError(Error(GL_INVALID_VALUE));
489 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400490 }
491
Geoff Langd87878e2014-09-19 15:42:59 -0400492 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
493 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400494 {
Geoff Langb1196682014-07-23 13:47:29 -0400495 context->recordError(Error(GL_INVALID_ENUM));
496 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400497 }
498
499 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
500 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800501 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400502 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400503 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400504 {
Geoff Langb1196682014-07-23 13:47:29 -0400505 context->recordError(Error(GL_INVALID_ENUM));
506 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400507 }
508
Geoff Langaae65a42014-05-26 12:43:44 -0400509 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
Geoff Langb1196682014-07-23 13:47:29 -0400511 context->recordError(Error(GL_INVALID_VALUE));
512 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 }
514
Shannon Woods53a94a82014-06-24 15:20:36 -0400515 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 if (handle == 0)
517 {
Geoff Langb1196682014-07-23 13:47:29 -0400518 context->recordError(Error(GL_INVALID_OPERATION));
519 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400520 }
521
522 return true;
523}
524
Corentin Walleze0902642014-11-04 12:32:15 -0800525bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
526 GLenum internalformat, GLsizei width, GLsizei height)
527{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800528 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800529
530 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400531 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800532 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400533 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800534 {
535 context->recordError(Error(GL_INVALID_VALUE));
536 return false;
537 }
538
539 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
540 // the specified storage. This is different than ES 3.0 in which a sample number higher
541 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800542 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
543 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800544 {
Geoff Langa4903b72015-03-02 16:02:48 -0800545 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
546 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
547 {
548 context->recordError(Error(GL_OUT_OF_MEMORY));
549 return false;
550 }
Corentin Walleze0902642014-11-04 12:32:15 -0800551 }
552
553 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
554}
555
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500556bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
557 GLenum renderbuffertarget, GLuint renderbuffer)
558{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400559 if (!ValidFramebufferTarget(target))
560 {
Geoff Langb1196682014-07-23 13:47:29 -0400561 context->recordError(Error(GL_INVALID_ENUM));
562 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400563 }
564
Shannon Woods53a94a82014-06-24 15:20:36 -0400565 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500566
Jamie Madill84115c92015-04-23 15:00:07 -0400567 ASSERT(framebuffer);
568 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500569 {
Jamie Madill84115c92015-04-23 15:00:07 -0400570 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400571 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500572 }
573
Jamie Madillb4472272014-07-03 10:38:55 -0400574 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500575 {
Jamie Madillb4472272014-07-03 10:38:55 -0400576 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500577 }
578
Jamie Madillab9d82c2014-01-21 16:38:14 -0500579 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
580 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
581 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
582 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
583 if (renderbuffer != 0)
584 {
585 if (!context->getRenderbuffer(renderbuffer))
586 {
Geoff Langb1196682014-07-23 13:47:29 -0400587 context->recordError(Error(GL_INVALID_OPERATION));
588 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500589 }
590 }
591
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500592 return true;
593}
594
Jamie Madillc29968b2016-01-20 11:17:23 -0500595bool ValidateBlitFramebufferParameters(gl::Context *context,
596 GLint srcX0,
597 GLint srcY0,
598 GLint srcX1,
599 GLint srcY1,
600 GLint dstX0,
601 GLint dstY0,
602 GLint dstX1,
603 GLint dstY1,
604 GLbitfield mask,
605 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606{
607 switch (filter)
608 {
609 case GL_NEAREST:
610 break;
611 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 break;
613 default:
Geoff Langb1196682014-07-23 13:47:29 -0400614 context->recordError(Error(GL_INVALID_ENUM));
615 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 }
617
618 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
619 {
Geoff Langb1196682014-07-23 13:47:29 -0400620 context->recordError(Error(GL_INVALID_VALUE));
621 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622 }
623
624 if (mask == 0)
625 {
626 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
627 // buffers are copied.
628 return false;
629 }
630
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400631 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
632 // color buffer, leaving only nearest being unfiltered from above
633 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
634 {
Geoff Langb1196682014-07-23 13:47:29 -0400635 context->recordError(Error(GL_INVALID_OPERATION));
636 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 }
638
Shannon Woods53a94a82014-06-24 15:20:36 -0400639 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 {
Geoff Langb1196682014-07-23 13:47:29 -0400641 context->recordError(Error(GL_INVALID_OPERATION));
642 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 }
644
Jamie Madille3ef7152015-04-28 16:55:17 +0000645 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
646 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500647
648 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 {
Geoff Langb1196682014-07-23 13:47:29 -0400650 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
651 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 }
653
Geoff Lang748f74e2014-12-01 11:25:34 -0500654 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500655 {
656 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
657 return false;
658 }
659
Geoff Lang748f74e2014-12-01 11:25:34 -0500660 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500661 {
662 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
663 return false;
664 }
665
666 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 {
Geoff Langb1196682014-07-23 13:47:29 -0400668 context->recordError(Error(GL_INVALID_OPERATION));
669 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 }
671
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
673
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400674 if (mask & GL_COLOR_BUFFER_BIT)
675 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400676 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
677 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500678 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400679
680 if (readColorBuffer && drawColorBuffer)
681 {
Geoff Langd8a22582014-12-17 15:28:23 -0500682 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400683 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684
Corentin Wallez37c39792015-08-20 14:19:46 -0400685 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686 {
687 if (drawFramebuffer->isEnabledColorAttachment(i))
688 {
Geoff Langd8a22582014-12-17 15:28:23 -0500689 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400690 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400691
Geoff Langb2f3d052013-08-13 12:49:27 -0400692 // The GL ES 3.0.2 spec (pg 193) states that:
693 // 1) If the read buffer is fixed point format, the draw buffer must be as well
694 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
695 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500696 // Changes with EXT_color_buffer_float:
697 // Case 1) is changed to fixed point OR floating point
698 GLenum readComponentType = readFormatInfo.componentType;
699 GLenum drawComponentType = drawFormatInfo.componentType;
700 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
701 readComponentType == GL_SIGNED_NORMALIZED);
702 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
703 drawComponentType == GL_SIGNED_NORMALIZED);
704
705 if (extensions.colorBufferFloat)
706 {
707 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
708 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
709
710 if (readFixedOrFloat != drawFixedOrFloat)
711 {
712 context->recordError(Error(GL_INVALID_OPERATION,
713 "If the read buffer contains fixed-point or "
714 "floating-point values, the draw buffer "
715 "must as well."));
716 return false;
717 }
718 }
719 else if (readFixedPoint != drawFixedPoint)
720 {
721 context->recordError(Error(GL_INVALID_OPERATION,
722 "If the read buffer contains fixed-point "
723 "values, the draw buffer must as well."));
724 return false;
725 }
726
727 if (readComponentType == GL_UNSIGNED_INT &&
728 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400729 {
Geoff Langb1196682014-07-23 13:47:29 -0400730 context->recordError(Error(GL_INVALID_OPERATION));
731 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 }
733
Jamie Madill6163c752015-12-07 16:32:59 -0500734 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735 {
Geoff Langb1196682014-07-23 13:47:29 -0400736 context->recordError(Error(GL_INVALID_OPERATION));
737 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 }
739
Geoff Langb2f3d052013-08-13 12:49:27 -0400740 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 {
Geoff Langb1196682014-07-23 13:47:29 -0400742 context->recordError(Error(GL_INVALID_OPERATION));
743 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744 }
745 }
746 }
747
Geoff Lang5d601382014-07-22 15:14:06 -0400748 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400749 {
Geoff Langb1196682014-07-23 13:47:29 -0400750 context->recordError(Error(GL_INVALID_OPERATION));
751 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400752 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 }
754 }
755
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200756 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
757 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
758 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200760 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400762 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
763 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200765 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 {
Geoff Langd8a22582014-12-17 15:28:23 -0500767 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Geoff Langb1196682014-07-23 13:47:29 -0400769 context->recordError(Error(GL_INVALID_OPERATION));
770 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200773 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 {
Geoff Langb1196682014-07-23 13:47:29 -0400775 context->recordError(Error(GL_INVALID_OPERATION));
776 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 }
778 }
779 }
780 }
781
782 return true;
783}
784
Geoff Langb1196682014-07-23 13:47:29 -0400785bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786{
787 switch (pname)
788 {
789 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
790 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
791 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
792 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
793 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
794 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
795 case GL_CURRENT_VERTEX_ATTRIB:
796 return true;
797
798 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
799 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
800 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400801 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
802 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 return true;
804
805 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400806 if (context->getClientVersion() < 3)
807 {
808 context->recordError(Error(GL_INVALID_ENUM));
809 return false;
810 }
811 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812
813 default:
Geoff Langb1196682014-07-23 13:47:29 -0400814 context->recordError(Error(GL_INVALID_ENUM));
815 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400816 }
817}
818
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400819bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400820{
821 switch (pname)
822 {
823 case GL_TEXTURE_WRAP_R:
824 case GL_TEXTURE_SWIZZLE_R:
825 case GL_TEXTURE_SWIZZLE_G:
826 case GL_TEXTURE_SWIZZLE_B:
827 case GL_TEXTURE_SWIZZLE_A:
828 case GL_TEXTURE_BASE_LEVEL:
829 case GL_TEXTURE_MAX_LEVEL:
830 case GL_TEXTURE_COMPARE_MODE:
831 case GL_TEXTURE_COMPARE_FUNC:
832 case GL_TEXTURE_MIN_LOD:
833 case GL_TEXTURE_MAX_LOD:
834 if (context->getClientVersion() < 3)
835 {
Geoff Langb1196682014-07-23 13:47:29 -0400836 context->recordError(Error(GL_INVALID_ENUM));
837 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838 }
839 break;
840
841 default: break;
842 }
843
844 switch (pname)
845 {
846 case GL_TEXTURE_WRAP_S:
847 case GL_TEXTURE_WRAP_T:
848 case GL_TEXTURE_WRAP_R:
849 switch (param)
850 {
851 case GL_REPEAT:
852 case GL_CLAMP_TO_EDGE:
853 case GL_MIRRORED_REPEAT:
854 return true;
855 default:
Geoff Langb1196682014-07-23 13:47:29 -0400856 context->recordError(Error(GL_INVALID_ENUM));
857 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400858 }
859
860 case GL_TEXTURE_MIN_FILTER:
861 switch (param)
862 {
863 case GL_NEAREST:
864 case GL_LINEAR:
865 case GL_NEAREST_MIPMAP_NEAREST:
866 case GL_LINEAR_MIPMAP_NEAREST:
867 case GL_NEAREST_MIPMAP_LINEAR:
868 case GL_LINEAR_MIPMAP_LINEAR:
869 return true;
870 default:
Geoff Langb1196682014-07-23 13:47:29 -0400871 context->recordError(Error(GL_INVALID_ENUM));
872 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400873 }
874 break;
875
876 case GL_TEXTURE_MAG_FILTER:
877 switch (param)
878 {
879 case GL_NEAREST:
880 case GL_LINEAR:
881 return true;
882 default:
Geoff Langb1196682014-07-23 13:47:29 -0400883 context->recordError(Error(GL_INVALID_ENUM));
884 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400885 }
886 break;
887
888 case GL_TEXTURE_USAGE_ANGLE:
889 switch (param)
890 {
891 case GL_NONE:
892 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
893 return true;
894 default:
Geoff Langb1196682014-07-23 13:47:29 -0400895 context->recordError(Error(GL_INVALID_ENUM));
896 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400897 }
898 break;
899
900 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400901 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 {
Geoff Langb1196682014-07-23 13:47:29 -0400903 context->recordError(Error(GL_INVALID_ENUM));
904 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400905 }
906
907 // we assume the parameter passed to this validation method is truncated, not rounded
908 if (param < 1)
909 {
Geoff Langb1196682014-07-23 13:47:29 -0400910 context->recordError(Error(GL_INVALID_VALUE));
911 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400912 }
913 return true;
914
915 case GL_TEXTURE_MIN_LOD:
916 case GL_TEXTURE_MAX_LOD:
917 // any value is permissible
918 return true;
919
920 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400921 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400922 switch (param)
923 {
924 case GL_NONE:
925 case GL_COMPARE_REF_TO_TEXTURE:
926 return true;
927 default:
Geoff Langb1196682014-07-23 13:47:29 -0400928 context->recordError(Error(GL_INVALID_ENUM));
929 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400930 }
931 break;
932
933 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400934 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400935 switch (param)
936 {
937 case GL_LEQUAL:
938 case GL_GEQUAL:
939 case GL_LESS:
940 case GL_GREATER:
941 case GL_EQUAL:
942 case GL_NOTEQUAL:
943 case GL_ALWAYS:
944 case GL_NEVER:
945 return true;
946 default:
Geoff Langb1196682014-07-23 13:47:29 -0400947 context->recordError(Error(GL_INVALID_ENUM));
948 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400949 }
950 break;
951
952 case GL_TEXTURE_SWIZZLE_R:
953 case GL_TEXTURE_SWIZZLE_G:
954 case GL_TEXTURE_SWIZZLE_B:
955 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400956 switch (param)
957 {
958 case GL_RED:
959 case GL_GREEN:
960 case GL_BLUE:
961 case GL_ALPHA:
962 case GL_ZERO:
963 case GL_ONE:
964 return true;
965 default:
Geoff Langb1196682014-07-23 13:47:29 -0400966 context->recordError(Error(GL_INVALID_ENUM));
967 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400968 }
969 break;
970
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400971 case GL_TEXTURE_BASE_LEVEL:
972 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400973 if (param < 0)
974 {
Geoff Langb1196682014-07-23 13:47:29 -0400975 context->recordError(Error(GL_INVALID_VALUE));
976 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400977 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400978 return true;
979
980 default:
Geoff Langb1196682014-07-23 13:47:29 -0400981 context->recordError(Error(GL_INVALID_ENUM));
982 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400983 }
984}
985
Geoff Langb1196682014-07-23 13:47:29 -0400986bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987{
988 switch (pname)
989 {
990 case GL_TEXTURE_MIN_FILTER:
991 case GL_TEXTURE_MAG_FILTER:
992 case GL_TEXTURE_WRAP_S:
993 case GL_TEXTURE_WRAP_T:
994 case GL_TEXTURE_WRAP_R:
995 case GL_TEXTURE_MIN_LOD:
996 case GL_TEXTURE_MAX_LOD:
997 case GL_TEXTURE_COMPARE_MODE:
998 case GL_TEXTURE_COMPARE_FUNC:
999 return true;
1000
1001 default:
Geoff Langb1196682014-07-23 13:47:29 -04001002 context->recordError(Error(GL_INVALID_ENUM));
1003 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001004 }
1005}
1006
Jamie Madillc29968b2016-01-20 11:17:23 -05001007bool ValidateReadPixels(Context *context,
1008 GLint x,
1009 GLint y,
1010 GLsizei width,
1011 GLsizei height,
1012 GLenum format,
1013 GLenum type,
1014 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001015{
Jamie Madillc29968b2016-01-20 11:17:23 -05001016 if (width < 0 || height < 0)
1017 {
1018 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1019 return false;
1020 }
1021
1022 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001023 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001024
Geoff Lang748f74e2014-12-01 11:25:34 -05001025 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001026 {
Geoff Langb1196682014-07-23 13:47:29 -04001027 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1028 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001029 }
1030
Jamie Madill48faf802014-11-06 15:27:22 -05001031 if (context->getState().getReadFramebuffer()->id() != 0 &&
1032 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001033 {
Geoff Langb1196682014-07-23 13:47:29 -04001034 context->recordError(Error(GL_INVALID_OPERATION));
1035 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001036 }
1037
Geoff Langbce529e2014-12-01 12:48:41 -05001038 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1039 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001040 {
Geoff Langb1196682014-07-23 13:47:29 -04001041 context->recordError(Error(GL_INVALID_OPERATION));
1042 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001043 }
1044
Geoff Langbce529e2014-12-01 12:48:41 -05001045 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1046 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001047 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001048 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001049
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001050 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1051 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001052
1053 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1054 {
Geoff Langb1196682014-07-23 13:47:29 -04001055 context->recordError(Error(GL_INVALID_OPERATION));
1056 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001057 }
1058
Jamie Madillc29968b2016-01-20 11:17:23 -05001059 return true;
1060}
1061
1062bool ValidateReadnPixelsEXT(Context *context,
1063 GLint x,
1064 GLint y,
1065 GLsizei width,
1066 GLsizei height,
1067 GLenum format,
1068 GLenum type,
1069 GLsizei bufSize,
1070 GLvoid *pixels)
1071{
1072 if (bufSize < 0)
1073 {
1074 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1075 return false;
1076 }
1077
Geoff Lang5d601382014-07-22 15:14:06 -04001078 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1079 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001080
Minmin Gongadff67b2015-10-14 10:34:45 -04001081 GLsizei outputPitch =
1082 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1083 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001084 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001085 int requiredSize = outputPitch * height;
1086 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001087 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001088 context->recordError(Error(GL_INVALID_OPERATION));
1089 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001090 }
1091
Jamie Madillc29968b2016-01-20 11:17:23 -05001092 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001093}
1094
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001095bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1096{
1097 if (!ValidQueryType(context, target))
1098 {
Geoff Langb1196682014-07-23 13:47:29 -04001099 context->recordError(Error(GL_INVALID_ENUM));
1100 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001101 }
1102
1103 if (id == 0)
1104 {
Geoff Langb1196682014-07-23 13:47:29 -04001105 context->recordError(Error(GL_INVALID_OPERATION));
1106 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001107 }
1108
1109 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1110 // of zero, if the active query object name for <target> is non-zero (for the
1111 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1112 // the active query for either target is non-zero), if <id> is the name of an
1113 // existing query object whose type does not match <target>, or if <id> is the
1114 // active query object name for any query type, the error INVALID_OPERATION is
1115 // generated.
1116
1117 // Ensure no other queries are active
1118 // NOTE: If other queries than occlusion are supported, we will need to check
1119 // separately that:
1120 // a) The query ID passed is not the current active query for any target/type
1121 // b) There are no active queries for the requested target (and in the case
1122 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1123 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001124 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001125 {
Geoff Langb1196682014-07-23 13:47:29 -04001126 context->recordError(Error(GL_INVALID_OPERATION));
1127 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001128 }
1129
1130 Query *queryObject = context->getQuery(id, true, target);
1131
1132 // check that name was obtained with glGenQueries
1133 if (!queryObject)
1134 {
Geoff Langb1196682014-07-23 13:47:29 -04001135 context->recordError(Error(GL_INVALID_OPERATION));
1136 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001137 }
1138
1139 // check for type mismatch
1140 if (queryObject->getType() != target)
1141 {
Geoff Langb1196682014-07-23 13:47:29 -04001142 context->recordError(Error(GL_INVALID_OPERATION));
1143 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001144 }
1145
1146 return true;
1147}
1148
Jamie Madill45c785d2014-05-13 14:09:34 -04001149bool ValidateEndQuery(gl::Context *context, GLenum target)
1150{
1151 if (!ValidQueryType(context, target))
1152 {
Geoff Langb1196682014-07-23 13:47:29 -04001153 context->recordError(Error(GL_INVALID_ENUM));
1154 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001155 }
1156
Shannon Woods53a94a82014-06-24 15:20:36 -04001157 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001158
1159 if (queryObject == NULL)
1160 {
Geoff Langb1196682014-07-23 13:47:29 -04001161 context->recordError(Error(GL_INVALID_OPERATION));
1162 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001163 }
1164
Jamie Madill45c785d2014-05-13 14:09:34 -04001165 return true;
1166}
1167
Jamie Madill62d31cb2015-09-11 13:25:51 -04001168static bool ValidateUniformCommonBase(gl::Context *context,
1169 GLenum targetUniformType,
1170 GLint location,
1171 GLsizei count,
1172 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001173{
1174 if (count < 0)
1175 {
Geoff Langb1196682014-07-23 13:47:29 -04001176 context->recordError(Error(GL_INVALID_VALUE));
1177 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001178 }
1179
Geoff Lang7dd2e102014-11-10 15:19:26 -05001180 gl::Program *program = context->getState().getProgram();
1181 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001182 {
Geoff Langb1196682014-07-23 13:47:29 -04001183 context->recordError(Error(GL_INVALID_OPERATION));
1184 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001185 }
1186
1187 if (location == -1)
1188 {
1189 // Silently ignore the uniform command
1190 return false;
1191 }
1192
Geoff Lang7dd2e102014-11-10 15:19:26 -05001193 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001194 {
Geoff Langb1196682014-07-23 13:47:29 -04001195 context->recordError(Error(GL_INVALID_OPERATION));
1196 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001197 }
1198
Jamie Madill62d31cb2015-09-11 13:25:51 -04001199 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001200
1201 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001202 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001203 {
Geoff Langb1196682014-07-23 13:47:29 -04001204 context->recordError(Error(GL_INVALID_OPERATION));
1205 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001206 }
1207
Jamie Madill62d31cb2015-09-11 13:25:51 -04001208 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001209 return true;
1210}
1211
Jamie Madillaa981bd2014-05-20 10:55:55 -04001212bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1213{
1214 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001215 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001216 {
Geoff Langb1196682014-07-23 13:47:29 -04001217 context->recordError(Error(GL_INVALID_OPERATION));
1218 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001219 }
1220
Jamie Madill62d31cb2015-09-11 13:25:51 -04001221 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001222 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1223 {
1224 return false;
1225 }
1226
Jamie Madillf2575982014-06-25 16:04:54 -04001227 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001228 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001229 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1230 {
Geoff Langb1196682014-07-23 13:47:29 -04001231 context->recordError(Error(GL_INVALID_OPERATION));
1232 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001233 }
1234
1235 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001236}
1237
1238bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1239 GLboolean transpose)
1240{
1241 // Check for ES3 uniform entry points
1242 int rows = VariableRowCount(matrixType);
1243 int cols = VariableColumnCount(matrixType);
1244 if (rows != cols && context->getClientVersion() < 3)
1245 {
Geoff Langb1196682014-07-23 13:47:29 -04001246 context->recordError(Error(GL_INVALID_OPERATION));
1247 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001248 }
1249
1250 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1251 {
Geoff Langb1196682014-07-23 13:47:29 -04001252 context->recordError(Error(GL_INVALID_VALUE));
1253 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001254 }
1255
Jamie Madill62d31cb2015-09-11 13:25:51 -04001256 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001257 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1258 {
1259 return false;
1260 }
1261
1262 if (uniform->type != matrixType)
1263 {
Geoff Langb1196682014-07-23 13:47:29 -04001264 context->recordError(Error(GL_INVALID_OPERATION));
1265 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001266 }
1267
1268 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001269}
1270
Jamie Madill893ab082014-05-16 16:56:10 -04001271bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1272{
1273 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1274 {
Geoff Langb1196682014-07-23 13:47:29 -04001275 context->recordError(Error(GL_INVALID_ENUM));
1276 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001277 }
1278
Jamie Madill0af26e12015-03-05 19:54:33 -05001279 const Caps &caps = context->getCaps();
1280
Jamie Madill893ab082014-05-16 16:56:10 -04001281 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1282 {
1283 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1284
Jamie Madill0af26e12015-03-05 19:54:33 -05001285 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001286 {
Geoff Langb1196682014-07-23 13:47:29 -04001287 context->recordError(Error(GL_INVALID_OPERATION));
1288 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001289 }
1290 }
1291
1292 switch (pname)
1293 {
1294 case GL_TEXTURE_BINDING_2D:
1295 case GL_TEXTURE_BINDING_CUBE_MAP:
1296 case GL_TEXTURE_BINDING_3D:
1297 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001298 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001299 {
Geoff Langb1196682014-07-23 13:47:29 -04001300 context->recordError(Error(GL_INVALID_OPERATION));
1301 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001302 }
1303 break;
1304
1305 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1306 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1307 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001308 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001309 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001310 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001311 {
Geoff Langb1196682014-07-23 13:47:29 -04001312 context->recordError(Error(GL_INVALID_OPERATION));
1313 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001314 }
1315
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001316 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001317 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001318 {
Geoff Langb1196682014-07-23 13:47:29 -04001319 context->recordError(Error(GL_INVALID_OPERATION));
1320 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001321 }
1322 }
1323 break;
1324
1325 default:
1326 break;
1327 }
1328
1329 // pname is valid, but there are no parameters to return
1330 if (numParams == 0)
1331 {
1332 return false;
1333 }
1334
1335 return true;
1336}
1337
Jamie Madillc29968b2016-01-20 11:17:23 -05001338bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1339 GLenum target,
1340 GLint level,
1341 GLenum internalformat,
1342 bool isSubImage,
1343 GLint xoffset,
1344 GLint yoffset,
1345 GLint zoffset,
1346 GLint x,
1347 GLint y,
1348 GLsizei width,
1349 GLsizei height,
1350 GLint border,
1351 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001352{
Jamie Madill560a8d82014-05-21 13:06:20 -04001353 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1354 {
Geoff Langb1196682014-07-23 13:47:29 -04001355 context->recordError(Error(GL_INVALID_VALUE));
1356 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 }
1358
1359 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1360 {
Geoff Langb1196682014-07-23 13:47:29 -04001361 context->recordError(Error(GL_INVALID_VALUE));
1362 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001363 }
1364
1365 if (border != 0)
1366 {
Geoff Langb1196682014-07-23 13:47:29 -04001367 context->recordError(Error(GL_INVALID_VALUE));
1368 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001369 }
1370
1371 if (!ValidMipLevel(context, target, level))
1372 {
Geoff Langb1196682014-07-23 13:47:29 -04001373 context->recordError(Error(GL_INVALID_VALUE));
1374 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001375 }
1376
Jamie Madillc29968b2016-01-20 11:17:23 -05001377 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001378 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001379 {
Geoff Langb1196682014-07-23 13:47:29 -04001380 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1381 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001382 }
1383
Jamie Madillc29968b2016-01-20 11:17:23 -05001384 const auto &state = context->getState();
1385 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001386 {
Geoff Langb1196682014-07-23 13:47:29 -04001387 context->recordError(Error(GL_INVALID_OPERATION));
1388 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001389 }
1390
Geoff Langaae65a42014-05-26 12:43:44 -04001391 const gl::Caps &caps = context->getCaps();
1392
Geoff Langaae65a42014-05-26 12:43:44 -04001393 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001394 switch (target)
1395 {
1396 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001397 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001398 break;
1399
1400 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1401 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1402 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1403 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1404 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1405 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001406 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001407 break;
1408
1409 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001410 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001411 break;
1412
1413 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001414 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001415 break;
1416
1417 default:
Geoff Langb1196682014-07-23 13:47:29 -04001418 context->recordError(Error(GL_INVALID_ENUM));
1419 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001420 }
1421
Jamie Madillc29968b2016-01-20 11:17:23 -05001422 gl::Texture *texture =
1423 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001424 if (!texture)
1425 {
Geoff Langb1196682014-07-23 13:47:29 -04001426 context->recordError(Error(GL_INVALID_OPERATION));
1427 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001428 }
1429
Geoff Lang69cce582015-09-17 13:20:36 -04001430 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001431 {
Geoff Langb1196682014-07-23 13:47:29 -04001432 context->recordError(Error(GL_INVALID_OPERATION));
1433 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001434 }
1435
Geoff Lang5d601382014-07-22 15:14:06 -04001436 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1437
1438 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001439 {
Geoff Langb1196682014-07-23 13:47:29 -04001440 context->recordError(Error(GL_INVALID_OPERATION));
1441 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001442 }
1443
Geoff Langa9be0dc2014-12-17 12:34:40 -05001444 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001445 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001446 context->recordError(Error(GL_INVALID_OPERATION));
1447 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001448 }
1449
1450 if (isSubImage)
1451 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001452 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1453 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1454 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001455 {
Geoff Langb1196682014-07-23 13:47:29 -04001456 context->recordError(Error(GL_INVALID_VALUE));
1457 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001458 }
1459 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001460 else
1461 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001462 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001463 {
Geoff Langb1196682014-07-23 13:47:29 -04001464 context->recordError(Error(GL_INVALID_VALUE));
1465 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001466 }
1467
Geoff Lang5d601382014-07-22 15:14:06 -04001468 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001469 {
Geoff Langb1196682014-07-23 13:47:29 -04001470 context->recordError(Error(GL_INVALID_ENUM));
1471 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001472 }
1473
1474 int maxLevelDimension = (maxDimension >> level);
1475 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1476 {
Geoff Langb1196682014-07-23 13:47:29 -04001477 context->recordError(Error(GL_INVALID_VALUE));
1478 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001479 }
1480 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001481
Geoff Langa9be0dc2014-12-17 12:34:40 -05001482 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001483 return true;
1484}
1485
Jamie Madillf25855c2015-11-03 11:06:18 -05001486static bool ValidateDrawBase(ValidationContext *context,
1487 GLenum mode,
1488 GLsizei count,
1489 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001490{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001491 switch (mode)
1492 {
1493 case GL_POINTS:
1494 case GL_LINES:
1495 case GL_LINE_LOOP:
1496 case GL_LINE_STRIP:
1497 case GL_TRIANGLES:
1498 case GL_TRIANGLE_STRIP:
1499 case GL_TRIANGLE_FAN:
1500 break;
1501 default:
Geoff Langb1196682014-07-23 13:47:29 -04001502 context->recordError(Error(GL_INVALID_ENUM));
1503 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001504 }
1505
Jamie Madill250d33f2014-06-06 17:09:03 -04001506 if (count < 0)
1507 {
Geoff Langb1196682014-07-23 13:47:29 -04001508 context->recordError(Error(GL_INVALID_VALUE));
1509 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001510 }
1511
Geoff Langb1196682014-07-23 13:47:29 -04001512 const State &state = context->getState();
1513
Jamie Madill250d33f2014-06-06 17:09:03 -04001514 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001515 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001516 {
Geoff Langb1196682014-07-23 13:47:29 -04001517 context->recordError(Error(GL_INVALID_OPERATION));
1518 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001519 }
1520
Geoff Lang3a86ad32015-09-01 11:47:05 -04001521 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001522 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001523 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1524 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1525 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1526 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1527 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1528 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1529 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001530 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001531 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1532 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001533 {
1534 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1535 // Section 6.10 of the WebGL 1.0 spec
1536 ERR(
1537 "This ANGLE implementation does not support separate front/back stencil "
1538 "writemasks, reference values, or stencil mask values.");
1539 context->recordError(Error(GL_INVALID_OPERATION));
1540 return false;
1541 }
Jamie Madillac528012014-06-20 13:21:23 -04001542 }
1543
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001544 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001545 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001546 {
Geoff Langb1196682014-07-23 13:47:29 -04001547 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1548 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001549 }
1550
Geoff Lang7dd2e102014-11-10 15:19:26 -05001551 gl::Program *program = state.getProgram();
1552 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001553 {
Geoff Langb1196682014-07-23 13:47:29 -04001554 context->recordError(Error(GL_INVALID_OPERATION));
1555 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001556 }
1557
Geoff Lang7dd2e102014-11-10 15:19:26 -05001558 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001559 {
Geoff Langb1196682014-07-23 13:47:29 -04001560 context->recordError(Error(GL_INVALID_OPERATION));
1561 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001562 }
1563
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001564 // Uniform buffer validation
1565 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1566 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001567 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001568 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001569 const OffsetBindingPointer<Buffer> &uniformBuffer =
1570 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001571
Geoff Lang5d124a62015-09-15 13:03:27 -04001572 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001573 {
1574 // undefined behaviour
1575 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1576 return false;
1577 }
1578
Geoff Lang5d124a62015-09-15 13:03:27 -04001579 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001580 if (uniformBufferSize == 0)
1581 {
1582 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001583 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001584 }
1585
Jamie Madill62d31cb2015-09-11 13:25:51 -04001586 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001587 {
1588 // undefined behaviour
1589 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1590 return false;
1591 }
1592 }
1593
Jamie Madill250d33f2014-06-06 17:09:03 -04001594 // No-op if zero count
1595 return (count > 0);
1596}
1597
Geoff Langb1196682014-07-23 13:47:29 -04001598bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001599{
Jamie Madillfd716582014-06-06 17:09:04 -04001600 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001601 {
Geoff Langb1196682014-07-23 13:47:29 -04001602 context->recordError(Error(GL_INVALID_VALUE));
1603 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001604 }
1605
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001606 const State &state = context->getState();
1607 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001608 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1609 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001610 {
1611 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1612 // that does not match the current transform feedback object's draw mode (if transform feedback
1613 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001614 context->recordError(Error(GL_INVALID_OPERATION));
1615 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001616 }
1617
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001618 if (!ValidateDrawBase(context, mode, count, primcount))
1619 {
1620 return false;
1621 }
1622
1623 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001624 {
1625 return false;
1626 }
1627
1628 return true;
1629}
1630
Geoff Langb1196682014-07-23 13:47:29 -04001631bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001632{
1633 if (primcount < 0)
1634 {
Geoff Langb1196682014-07-23 13:47:29 -04001635 context->recordError(Error(GL_INVALID_VALUE));
1636 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001637 }
1638
Jamie Madill2b976812014-08-25 15:47:49 -04001639 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001640 {
1641 return false;
1642 }
1643
1644 // No-op if zero primitive count
1645 return (primcount > 0);
1646}
1647
Geoff Lang87a93302014-09-16 13:29:43 -04001648static bool ValidateDrawInstancedANGLE(Context *context)
1649{
1650 // Verify there is at least one active attribute with a divisor of zero
1651 const gl::State& state = context->getState();
1652
Geoff Lang7dd2e102014-11-10 15:19:26 -05001653 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001654
1655 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001656 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001657 {
1658 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001659 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001660 {
1661 return true;
1662 }
1663 }
1664
1665 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1666 "has a divisor of zero."));
1667 return false;
1668}
1669
1670bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1671{
1672 if (!ValidateDrawInstancedANGLE(context))
1673 {
1674 return false;
1675 }
1676
1677 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1678}
1679
Jamie Madillf25855c2015-11-03 11:06:18 -05001680bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001681 GLenum mode,
1682 GLsizei count,
1683 GLenum type,
1684 const GLvoid *indices,
1685 GLsizei primcount,
1686 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001687{
Jamie Madill250d33f2014-06-06 17:09:03 -04001688 switch (type)
1689 {
1690 case GL_UNSIGNED_BYTE:
1691 case GL_UNSIGNED_SHORT:
1692 break;
1693 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001694 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001695 {
Geoff Langb1196682014-07-23 13:47:29 -04001696 context->recordError(Error(GL_INVALID_ENUM));
1697 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001698 }
1699 break;
1700 default:
Geoff Langb1196682014-07-23 13:47:29 -04001701 context->recordError(Error(GL_INVALID_ENUM));
1702 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001703 }
1704
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001705 const State &state = context->getState();
1706
1707 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001708 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001709 {
1710 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1711 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001712 context->recordError(Error(GL_INVALID_OPERATION));
1713 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001714 }
1715
1716 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001717 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001718 {
Geoff Langb1196682014-07-23 13:47:29 -04001719 context->recordError(Error(GL_INVALID_OPERATION));
1720 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001721 }
1722
Jamie Madill2b976812014-08-25 15:47:49 -04001723 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001724 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001725 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001726 {
Geoff Langb1196682014-07-23 13:47:29 -04001727 context->recordError(Error(GL_INVALID_OPERATION));
1728 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001729 }
1730
Jamie Madillae3000b2014-08-25 15:47:51 -04001731 if (elementArrayBuffer)
1732 {
1733 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1734
1735 GLint64 offset = reinterpret_cast<GLint64>(indices);
1736 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1737
1738 // check for integer overflows
1739 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1740 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1741 {
Geoff Langb1196682014-07-23 13:47:29 -04001742 context->recordError(Error(GL_OUT_OF_MEMORY));
1743 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001744 }
1745
1746 // Check for reading past the end of the bound buffer object
1747 if (byteCount > elementArrayBuffer->getSize())
1748 {
Geoff Langb1196682014-07-23 13:47:29 -04001749 context->recordError(Error(GL_INVALID_OPERATION));
1750 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001751 }
1752 }
1753 else if (!indices)
1754 {
1755 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001756 context->recordError(Error(GL_INVALID_OPERATION));
1757 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001758 }
1759
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001760 if (!ValidateDrawBase(context, mode, count, primcount))
1761 {
1762 return false;
1763 }
1764
Jamie Madill2b976812014-08-25 15:47:49 -04001765 // Use max index to validate if our vertex buffers are large enough for the pull.
1766 // TODO: offer fast path, with disabled index validation.
1767 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1768 if (elementArrayBuffer)
1769 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001770 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001771 Error error =
1772 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1773 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001774 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001775 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001776 context->recordError(error);
1777 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001778 }
1779 }
1780 else
1781 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001782 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001783 }
1784
Jamie Madille79b1e12015-11-04 16:36:37 -05001785 // If we use an index greater than our maximum supported index range, return an error.
1786 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1787 // return an error if possible here.
1788 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1789 {
1790 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1791 return false;
1792 }
1793
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001794 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001795 {
1796 return false;
1797 }
1798
Geoff Lang3edfe032015-09-04 16:38:24 -04001799 // No op if there are no real indices in the index data (all are primitive restart).
1800 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001801}
1802
Geoff Langb1196682014-07-23 13:47:29 -04001803bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001804 GLenum mode,
1805 GLsizei count,
1806 GLenum type,
1807 const GLvoid *indices,
1808 GLsizei primcount,
1809 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001810{
1811 if (primcount < 0)
1812 {
Geoff Langb1196682014-07-23 13:47:29 -04001813 context->recordError(Error(GL_INVALID_VALUE));
1814 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001815 }
1816
Jamie Madill2b976812014-08-25 15:47:49 -04001817 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001818 {
1819 return false;
1820 }
1821
1822 // No-op zero primitive count
1823 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001824}
1825
Geoff Lang3edfe032015-09-04 16:38:24 -04001826bool ValidateDrawElementsInstancedANGLE(Context *context,
1827 GLenum mode,
1828 GLsizei count,
1829 GLenum type,
1830 const GLvoid *indices,
1831 GLsizei primcount,
1832 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001833{
1834 if (!ValidateDrawInstancedANGLE(context))
1835 {
1836 return false;
1837 }
1838
1839 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1840}
1841
Geoff Langb1196682014-07-23 13:47:29 -04001842bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001843 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001844{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001845 if (!ValidFramebufferTarget(target))
1846 {
Geoff Langb1196682014-07-23 13:47:29 -04001847 context->recordError(Error(GL_INVALID_ENUM));
1848 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001849 }
1850
1851 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001852 {
1853 return false;
1854 }
1855
Jamie Madill55ec3b12014-07-03 10:38:57 -04001856 if (texture != 0)
1857 {
1858 gl::Texture *tex = context->getTexture(texture);
1859
1860 if (tex == NULL)
1861 {
Geoff Langb1196682014-07-23 13:47:29 -04001862 context->recordError(Error(GL_INVALID_OPERATION));
1863 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001864 }
1865
1866 if (level < 0)
1867 {
Geoff Langb1196682014-07-23 13:47:29 -04001868 context->recordError(Error(GL_INVALID_VALUE));
1869 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001870 }
1871 }
1872
Shannon Woods53a94a82014-06-24 15:20:36 -04001873 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001874 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001875
Jamie Madill84115c92015-04-23 15:00:07 -04001876 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001877 {
Jamie Madill84115c92015-04-23 15:00:07 -04001878 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001879 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001880 }
1881
1882 return true;
1883}
1884
Geoff Langb1196682014-07-23 13:47:29 -04001885bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001886 GLenum textarget, GLuint texture, GLint level)
1887{
Geoff Lang95663912015-04-02 15:54:45 -04001888 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1889 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001890 {
Geoff Langb1196682014-07-23 13:47:29 -04001891 context->recordError(Error(GL_INVALID_VALUE));
1892 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001893 }
1894
1895 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001896 {
1897 return false;
1898 }
1899
Jamie Madill55ec3b12014-07-03 10:38:57 -04001900 if (texture != 0)
1901 {
1902 gl::Texture *tex = context->getTexture(texture);
1903 ASSERT(tex);
1904
Jamie Madill2a6564e2014-07-11 09:53:19 -04001905 const gl::Caps &caps = context->getCaps();
1906
Jamie Madill55ec3b12014-07-03 10:38:57 -04001907 switch (textarget)
1908 {
1909 case GL_TEXTURE_2D:
1910 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001911 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001912 {
Geoff Langb1196682014-07-23 13:47:29 -04001913 context->recordError(Error(GL_INVALID_VALUE));
1914 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001915 }
1916 if (tex->getTarget() != GL_TEXTURE_2D)
1917 {
Geoff Langb1196682014-07-23 13:47:29 -04001918 context->recordError(Error(GL_INVALID_OPERATION));
1919 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001920 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001921 }
1922 break;
1923
1924 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1925 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1926 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1927 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1928 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1929 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1930 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001931 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001932 {
Geoff Langb1196682014-07-23 13:47:29 -04001933 context->recordError(Error(GL_INVALID_VALUE));
1934 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001935 }
1936 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1937 {
Geoff Langb1196682014-07-23 13:47:29 -04001938 context->recordError(Error(GL_INVALID_OPERATION));
1939 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001940 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001941 }
1942 break;
1943
1944 default:
Geoff Langb1196682014-07-23 13:47:29 -04001945 context->recordError(Error(GL_INVALID_ENUM));
1946 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001947 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001948
1949 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1950 if (internalFormatInfo.compressed)
1951 {
1952 context->recordError(Error(GL_INVALID_OPERATION));
1953 return false;
1954 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001955 }
1956
Jamie Madill570f7c82014-07-03 10:38:54 -04001957 return true;
1958}
1959
Geoff Langb1196682014-07-23 13:47:29 -04001960bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001961{
1962 if (program == 0)
1963 {
Geoff Langb1196682014-07-23 13:47:29 -04001964 context->recordError(Error(GL_INVALID_VALUE));
1965 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001966 }
1967
Dian Xiang769769a2015-09-09 15:20:08 -07001968 gl::Program *programObject = GetValidProgram(context, program);
1969 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001970 {
1971 return false;
1972 }
1973
Jamie Madill0063c512014-08-25 15:47:53 -04001974 if (!programObject || !programObject->isLinked())
1975 {
Geoff Langb1196682014-07-23 13:47:29 -04001976 context->recordError(Error(GL_INVALID_OPERATION));
1977 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001978 }
1979
Geoff Lang7dd2e102014-11-10 15:19:26 -05001980 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001981 {
Geoff Langb1196682014-07-23 13:47:29 -04001982 context->recordError(Error(GL_INVALID_OPERATION));
1983 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001984 }
1985
Jamie Madill0063c512014-08-25 15:47:53 -04001986 return true;
1987}
1988
Geoff Langb1196682014-07-23 13:47:29 -04001989bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001990{
1991 return ValidateGetUniformBase(context, program, location);
1992}
1993
Geoff Langb1196682014-07-23 13:47:29 -04001994bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001995{
Jamie Madill78f41802014-08-25 15:47:55 -04001996 return ValidateGetUniformBase(context, program, location);
1997}
1998
Geoff Langb1196682014-07-23 13:47:29 -04001999static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002000{
2001 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002002 {
Jamie Madill78f41802014-08-25 15:47:55 -04002003 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002004 }
2005
Jamie Madilla502c742014-08-28 17:19:13 -04002006 gl::Program *programObject = context->getProgram(program);
2007 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002008
Jamie Madill78f41802014-08-25 15:47:55 -04002009 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002010 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2011 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002012 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002013 {
Geoff Langb1196682014-07-23 13:47:29 -04002014 context->recordError(Error(GL_INVALID_OPERATION));
2015 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002016 }
2017
2018 return true;
2019}
2020
Geoff Langb1196682014-07-23 13:47:29 -04002021bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002022{
Jamie Madill78f41802014-08-25 15:47:55 -04002023 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002024}
2025
Geoff Langb1196682014-07-23 13:47:29 -04002026bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002027{
Jamie Madill78f41802014-08-25 15:47:55 -04002028 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002029}
2030
Austin Kinross08332632015-05-05 13:35:47 -07002031bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2032 const GLenum *attachments, bool defaultFramebuffer)
2033{
2034 if (numAttachments < 0)
2035 {
2036 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2037 return false;
2038 }
2039
2040 for (GLsizei i = 0; i < numAttachments; ++i)
2041 {
2042 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2043 {
2044 if (defaultFramebuffer)
2045 {
2046 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2047 return false;
2048 }
2049
2050 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2051 {
2052 context->recordError(Error(GL_INVALID_OPERATION,
2053 "Requested color attachment is greater than the maximum supported color attachments"));
2054 return false;
2055 }
2056 }
2057 else
2058 {
2059 switch (attachments[i])
2060 {
2061 case GL_DEPTH_ATTACHMENT:
2062 case GL_STENCIL_ATTACHMENT:
2063 case GL_DEPTH_STENCIL_ATTACHMENT:
2064 if (defaultFramebuffer)
2065 {
2066 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2067 return false;
2068 }
2069 break;
2070 case GL_COLOR:
2071 case GL_DEPTH:
2072 case GL_STENCIL:
2073 if (!defaultFramebuffer)
2074 {
2075 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2076 return false;
2077 }
2078 break;
2079 default:
2080 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2081 return false;
2082 }
2083 }
2084 }
2085
2086 return true;
2087}
2088
Austin Kinross6ee1e782015-05-29 17:05:37 -07002089bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2090{
2091 // Note that debug marker calls must not set error state
2092
2093 if (length < 0)
2094 {
2095 return false;
2096 }
2097
2098 if (marker == nullptr)
2099 {
2100 return false;
2101 }
2102
2103 return true;
2104}
2105
2106bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2107{
2108 // Note that debug marker calls must not set error state
2109
2110 if (length < 0)
2111 {
2112 return false;
2113 }
2114
2115 if (length > 0 && marker == nullptr)
2116 {
2117 return false;
2118 }
2119
2120 return true;
2121}
2122
Geoff Langdcab33b2015-07-21 13:03:16 -04002123bool ValidateEGLImageTargetTexture2DOES(Context *context,
2124 egl::Display *display,
2125 GLenum target,
2126 egl::Image *image)
2127{
Geoff Langa8406172015-07-21 16:53:39 -04002128 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2129 {
2130 context->recordError(Error(GL_INVALID_OPERATION));
2131 return false;
2132 }
2133
2134 switch (target)
2135 {
2136 case GL_TEXTURE_2D:
2137 break;
2138
2139 default:
2140 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2141 return false;
2142 }
2143
2144 if (!display->isValidImage(image))
2145 {
2146 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2147 return false;
2148 }
2149
2150 if (image->getSamples() > 0)
2151 {
2152 context->recordError(Error(GL_INVALID_OPERATION,
2153 "cannot create a 2D texture from a multisampled EGL image."));
2154 return false;
2155 }
2156
2157 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2158 if (!textureCaps.texturable)
2159 {
2160 context->recordError(Error(GL_INVALID_OPERATION,
2161 "EGL image internal format is not supported as a texture."));
2162 return false;
2163 }
2164
Geoff Langdcab33b2015-07-21 13:03:16 -04002165 return true;
2166}
2167
2168bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2169 egl::Display *display,
2170 GLenum target,
2171 egl::Image *image)
2172{
Geoff Langa8406172015-07-21 16:53:39 -04002173 if (!context->getExtensions().eglImage)
2174 {
2175 context->recordError(Error(GL_INVALID_OPERATION));
2176 return false;
2177 }
2178
2179 switch (target)
2180 {
2181 case GL_RENDERBUFFER:
2182 break;
2183
2184 default:
2185 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2186 return false;
2187 }
2188
2189 if (!display->isValidImage(image))
2190 {
2191 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2192 return false;
2193 }
2194
2195 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2196 if (!textureCaps.renderable)
2197 {
2198 context->recordError(Error(
2199 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2200 return false;
2201 }
2202
Geoff Langdcab33b2015-07-21 13:03:16 -04002203 return true;
2204}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002205
2206bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2207{
Geoff Lang36167ab2015-12-07 10:27:14 -05002208 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002209 {
2210 // The default VAO should always exist
2211 ASSERT(array != 0);
2212 context->recordError(Error(GL_INVALID_OPERATION));
2213 return false;
2214 }
2215
2216 return true;
2217}
2218
2219bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2220{
2221 if (n < 0)
2222 {
2223 context->recordError(Error(GL_INVALID_VALUE));
2224 return false;
2225 }
2226
2227 return true;
2228}
2229
2230bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2231{
2232 if (n < 0)
2233 {
2234 context->recordError(Error(GL_INVALID_VALUE));
2235 return false;
2236 }
2237
2238 return true;
2239}
Geoff Langc5629752015-12-07 16:29:04 -05002240
2241bool ValidateProgramBinaryBase(Context *context,
2242 GLuint program,
2243 GLenum binaryFormat,
2244 const void *binary,
2245 GLint length)
2246{
2247 Program *programObject = GetValidProgram(context, program);
2248 if (programObject == nullptr)
2249 {
2250 return false;
2251 }
2252
2253 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2254 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2255 programBinaryFormats.end())
2256 {
2257 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2258 return false;
2259 }
2260
2261 return true;
2262}
2263
2264bool ValidateGetProgramBinaryBase(Context *context,
2265 GLuint program,
2266 GLsizei bufSize,
2267 GLsizei *length,
2268 GLenum *binaryFormat,
2269 void *binary)
2270{
2271 Program *programObject = GetValidProgram(context, program);
2272 if (programObject == nullptr)
2273 {
2274 return false;
2275 }
2276
2277 if (!programObject->isLinked())
2278 {
2279 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2280 return false;
2281 }
2282
2283 return true;
2284}
Jamie Madillc29968b2016-01-20 11:17:23 -05002285
2286bool ValidateCopyTexImage2D(ValidationContext *context,
2287 GLenum target,
2288 GLint level,
2289 GLenum internalformat,
2290 GLint x,
2291 GLint y,
2292 GLsizei width,
2293 GLsizei height,
2294 GLint border)
2295{
2296 if (context->getClientVersion() < 3)
2297 {
2298 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2299 0, x, y, width, height, border);
2300 }
2301
2302 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002303 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2304 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002305}
Jamie Madillc29968b2016-01-20 11:17:23 -05002306
2307bool ValidateFramebufferRenderbuffer(Context *context,
2308 GLenum target,
2309 GLenum attachment,
2310 GLenum renderbuffertarget,
2311 GLuint renderbuffer)
2312{
2313 if (!ValidFramebufferTarget(target) ||
2314 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2315 {
2316 context->recordError(Error(GL_INVALID_ENUM));
2317 return false;
2318 }
2319
2320 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2321 renderbuffertarget, renderbuffer);
2322}
2323
2324bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2325{
2326 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2327 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2328 {
2329 context->recordError(
2330 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2331 return false;
2332 }
2333
2334 ASSERT(context->getState().getDrawFramebuffer());
2335 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2336 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2337
2338 // This should come first before the check for the default frame buffer
2339 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2340 // rather than INVALID_OPERATION
2341 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2342 {
2343 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2344
2345 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
2346 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
2347 bufs[colorAttachment] >= maxColorAttachment))
2348 {
2349 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
2350 // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
2351 // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
2352 context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
2353 return false;
2354 }
2355 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2356 frameBufferId != 0)
2357 {
2358 // INVALID_OPERATION-GL is bound to buffer and ith argument
2359 // is not COLOR_ATTACHMENTi or NONE
2360 context->recordError(
2361 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2362 return false;
2363 }
2364 }
2365
2366 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2367 // and n is not 1 or bufs is bound to value other than BACK and NONE
2368 if (frameBufferId == 0)
2369 {
2370 if (n != 1)
2371 {
2372 context->recordError(Error(GL_INVALID_OPERATION,
2373 "n must be 1 when GL is bound to the default framebuffer"));
2374 return false;
2375 }
2376
2377 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2378 {
2379 context->recordError(Error(
2380 GL_INVALID_OPERATION,
2381 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2382 return false;
2383 }
2384 }
2385
2386 return true;
2387}
2388
2389bool ValidateCopyTexSubImage2D(Context *context,
2390 GLenum target,
2391 GLint level,
2392 GLint xoffset,
2393 GLint yoffset,
2394 GLint x,
2395 GLint y,
2396 GLsizei width,
2397 GLsizei height)
2398{
2399 if (context->getClientVersion() < 3)
2400 {
2401 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2402 yoffset, x, y, width, height, 0);
2403 }
2404
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002405 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2406 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002407}
2408
2409} // namespace gl