blob: 4af2ac0e8ee6f892973b503b949341a0aae67227 [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;
112 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
113 case GL_RASTERIZER_DISCARD:
114 return (context->getClientVersion() >= 3);
115 default:
116 return false;
117 }
118}
119
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500120bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121{
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400123 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500124 case GL_TEXTURE_2D:
125 case GL_TEXTURE_CUBE_MAP:
126 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400127
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 case GL_TEXTURE_3D:
129 case GL_TEXTURE_2D_ARRAY:
130 return (context->getClientVersion() >= 3);
131
132 default:
133 return false;
134 }
Jamie Madill35d15012013-10-07 10:46:37 -0400135}
136
Shannon Woods4dfed832014-03-17 20:03:39 -0400137// This function differs from ValidTextureTarget in that the target must be
138// usable as the destination of a 2D operation-- so a cube face is valid, but
139// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400140// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400141bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
142{
143 switch (target)
144 {
145 case GL_TEXTURE_2D:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
150 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
151 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
152 return true;
153 case GL_TEXTURE_2D_ARRAY:
154 case GL_TEXTURE_3D:
155 return (context->getClientVersion() >= 3);
156 default:
157 return false;
158 }
159}
160
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500161bool ValidFramebufferTarget(GLenum target)
162{
Geoff Langd4475812015-03-18 10:53:05 -0400163 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
164 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500165
166 switch (target)
167 {
168 case GL_FRAMEBUFFER: return true;
169 case GL_READ_FRAMEBUFFER: return true;
170 case GL_DRAW_FRAMEBUFFER: return true;
171 default: return false;
172 }
173}
174
Jamie Madill8c96d582014-03-05 15:01:23 -0500175bool ValidBufferTarget(const Context *context, GLenum target)
176{
177 switch (target)
178 {
179 case GL_ARRAY_BUFFER:
180 case GL_ELEMENT_ARRAY_BUFFER:
181 return true;
182
Jamie Madill8c96d582014-03-05 15:01:23 -0500183 case GL_PIXEL_PACK_BUFFER:
184 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400185 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400186
Shannon Woodsb3801742014-03-27 14:59:19 -0400187 case GL_COPY_READ_BUFFER:
188 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500189 case GL_TRANSFORM_FEEDBACK_BUFFER:
190 case GL_UNIFORM_BUFFER:
191 return (context->getClientVersion() >= 3);
192
193 default:
194 return false;
195 }
196}
197
Jamie Madill70656a62014-03-05 15:01:26 -0500198bool ValidBufferParameter(const Context *context, GLenum pname)
199{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400200 const Extensions &extensions = context->getExtensions();
201
Jamie Madill70656a62014-03-05 15:01:26 -0500202 switch (pname)
203 {
204 case GL_BUFFER_USAGE:
205 case GL_BUFFER_SIZE:
206 return true;
207
Geoff Langcc6f55d2015-03-20 13:01:02 -0400208 case GL_BUFFER_ACCESS_OES:
209 return extensions.mapBuffer;
210
211 case GL_BUFFER_MAPPED:
212 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
213 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
214
Jamie Madill70656a62014-03-05 15:01:26 -0500215 // GL_BUFFER_MAP_POINTER is a special case, and may only be
216 // queried with GetBufferPointerv
217 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500218 case GL_BUFFER_MAP_OFFSET:
219 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400220 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500221
222 default:
223 return false;
224 }
225}
226
Jamie Madill8c96d582014-03-05 15:01:23 -0500227bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400228{
Geoff Langaae65a42014-05-26 12:43:44 -0400229 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400230 switch (target)
231 {
Geoff Langaae65a42014-05-26 12:43:44 -0400232 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400233 case GL_TEXTURE_CUBE_MAP:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
238 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400239 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
240 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
241 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400242 default: UNREACHABLE();
243 }
244
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700245 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400246}
247
Austin Kinross08528e12015-10-07 16:24:40 -0700248bool ValidImageSizeParameters(const Context *context,
249 GLenum target,
250 GLint level,
251 GLsizei width,
252 GLsizei height,
253 GLsizei depth,
254 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400255{
256 if (level < 0 || width < 0 || height < 0 || depth < 0)
257 {
258 return false;
259 }
260
Austin Kinross08528e12015-10-07 16:24:40 -0700261 // TexSubImage parameters can be NPOT without textureNPOT extension,
262 // as long as the destination texture is POT.
263 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400264 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400265 {
266 return false;
267 }
268
269 if (!ValidMipLevel(context, target, level))
270 {
271 return false;
272 }
273
274 return true;
275}
276
Geoff Lang0d8b7242015-09-09 14:56:53 -0400277bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
278{
279 // List of compressed format that require that the texture size is smaller than or a multiple of
280 // the compressed block size.
281 switch (internalFormat)
282 {
283 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
284 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
285 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
286 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
287 return true;
288
289 default:
290 return false;
291 }
292}
293
Geoff Langb1196682014-07-23 13:47:29 -0400294bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400295{
Geoff Lang5d601382014-07-22 15:14:06 -0400296 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
297 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400298 {
299 return false;
300 }
301
Geoff Lang0d8b7242015-09-09 14:56:53 -0400302 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400303 {
304 return false;
305 }
306
Geoff Lang0d8b7242015-09-09 14:56:53 -0400307 if (CompressedTextureFormatRequiresExactSize(internalFormat))
308 {
309 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
310 width % formatInfo.compressedBlockWidth != 0) ||
311 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
312 height % formatInfo.compressedBlockHeight != 0))
313 {
314 return false;
315 }
316 }
317
Geoff Langd4f180b2013-09-24 13:57:44 -0400318 return true;
319}
320
Geoff Lang37dde692014-01-31 16:34:54 -0500321bool ValidQueryType(const Context *context, GLenum queryType)
322{
Geoff Langd4475812015-03-18 10:53:05 -0400323 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
324 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 -0500325
326 switch (queryType)
327 {
328 case GL_ANY_SAMPLES_PASSED:
329 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
330 return true;
331 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
332 return (context->getClientVersion() >= 3);
333 default:
334 return false;
335 }
336}
337
Dian Xiang769769a2015-09-09 15:20:08 -0700338Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500339{
340 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
341 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
342 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
343
Dian Xiang769769a2015-09-09 15:20:08 -0700344 Program *validProgram = context->getProgram(id);
345
346 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500347 {
Dian Xiang769769a2015-09-09 15:20:08 -0700348 if (context->getShader(id))
349 {
350 context->recordError(
351 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
352 }
353 else
354 {
355 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
356 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500357 }
Dian Xiang769769a2015-09-09 15:20:08 -0700358
359 return validProgram;
360}
361
362Shader *GetValidShader(Context *context, GLuint id)
363{
364 // See ValidProgram for spec details.
365
366 Shader *validShader = context->getShader(id);
367
368 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500369 {
Dian Xiang769769a2015-09-09 15:20:08 -0700370 if (context->getProgram(id))
371 {
372 context->recordError(
373 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
374 }
375 else
376 {
377 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
378 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500379 }
Dian Xiang769769a2015-09-09 15:20:08 -0700380
381 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500382}
383
Geoff Langb1196682014-07-23 13:47:29 -0400384bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400385{
386 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
387 {
388 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
389
Geoff Langaae65a42014-05-26 12:43:44 -0400390 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400391 {
Geoff Langb1196682014-07-23 13:47:29 -0400392 context->recordError(Error(GL_INVALID_VALUE));
393 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400394 }
395 }
396 else
397 {
398 switch (attachment)
399 {
400 case GL_DEPTH_ATTACHMENT:
401 case GL_STENCIL_ATTACHMENT:
402 break;
403
404 case GL_DEPTH_STENCIL_ATTACHMENT:
405 if (context->getClientVersion() < 3)
406 {
Geoff Langb1196682014-07-23 13:47:29 -0400407 context->recordError(Error(GL_INVALID_ENUM));
408 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400409 }
410 break;
411
412 default:
Geoff Langb1196682014-07-23 13:47:29 -0400413 context->recordError(Error(GL_INVALID_ENUM));
414 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400415 }
416 }
417
418 return true;
419}
420
Corentin Walleze0902642014-11-04 12:32:15 -0800421bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
422 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423{
424 switch (target)
425 {
426 case GL_RENDERBUFFER:
427 break;
428 default:
Geoff Langb1196682014-07-23 13:47:29 -0400429 context->recordError(Error(GL_INVALID_ENUM));
430 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400431 }
432
433 if (width < 0 || height < 0 || samples < 0)
434 {
Geoff Langb1196682014-07-23 13:47:29 -0400435 context->recordError(Error(GL_INVALID_VALUE));
436 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400437 }
438
Geoff Langd87878e2014-09-19 15:42:59 -0400439 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
440 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400441 {
Geoff Langb1196682014-07-23 13:47:29 -0400442 context->recordError(Error(GL_INVALID_ENUM));
443 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 }
445
446 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
447 // 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 -0800448 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400449 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400450 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400451 {
Geoff Langb1196682014-07-23 13:47:29 -0400452 context->recordError(Error(GL_INVALID_ENUM));
453 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400454 }
455
Geoff Langaae65a42014-05-26 12:43:44 -0400456 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 {
Geoff Langb1196682014-07-23 13:47:29 -0400458 context->recordError(Error(GL_INVALID_VALUE));
459 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400460 }
461
Shannon Woods53a94a82014-06-24 15:20:36 -0400462 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 if (handle == 0)
464 {
Geoff Langb1196682014-07-23 13:47:29 -0400465 context->recordError(Error(GL_INVALID_OPERATION));
466 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400467 }
468
469 return true;
470}
471
Corentin Walleze0902642014-11-04 12:32:15 -0800472bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
473 GLenum internalformat, GLsizei width, GLsizei height)
474{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800475 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800476
477 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400478 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800479 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400480 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800481 {
482 context->recordError(Error(GL_INVALID_VALUE));
483 return false;
484 }
485
486 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
487 // the specified storage. This is different than ES 3.0 in which a sample number higher
488 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800489 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
490 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800491 {
Geoff Langa4903b72015-03-02 16:02:48 -0800492 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
493 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
494 {
495 context->recordError(Error(GL_OUT_OF_MEMORY));
496 return false;
497 }
Corentin Walleze0902642014-11-04 12:32:15 -0800498 }
499
500 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
501}
502
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500503bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
504 GLenum renderbuffertarget, GLuint renderbuffer)
505{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400506 if (!ValidFramebufferTarget(target))
507 {
Geoff Langb1196682014-07-23 13:47:29 -0400508 context->recordError(Error(GL_INVALID_ENUM));
509 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400510 }
511
Shannon Woods53a94a82014-06-24 15:20:36 -0400512 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500513
Jamie Madill84115c92015-04-23 15:00:07 -0400514 ASSERT(framebuffer);
515 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500516 {
Jamie Madill84115c92015-04-23 15:00:07 -0400517 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400518 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500519 }
520
Jamie Madillb4472272014-07-03 10:38:55 -0400521 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500522 {
Jamie Madillb4472272014-07-03 10:38:55 -0400523 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500524 }
525
Jamie Madillab9d82c2014-01-21 16:38:14 -0500526 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
527 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
528 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
529 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
530 if (renderbuffer != 0)
531 {
532 if (!context->getRenderbuffer(renderbuffer))
533 {
Geoff Langb1196682014-07-23 13:47:29 -0400534 context->recordError(Error(GL_INVALID_OPERATION));
535 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500536 }
537 }
538
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500539 return true;
540}
541
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400542static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400543 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
544 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
545{
Jamie Madill6b120b92015-11-24 13:00:07 -0500546 const Extents &writeSize = writeBuffer->getSize();
547 const Extents &readSize = readBuffer->getSize();
548
549 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width ||
550 dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height)
Geoff Lang125deab2013-08-09 13:34:16 -0400551 {
552 return true;
553 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400554 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400555 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400556 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400557
Jamie Madill6b120b92015-11-24 13:00:07 -0500558 return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
559 scissor.height < writeSize.height;
Geoff Lang125deab2013-08-09 13:34:16 -0400560 }
561 else
562 {
563 return false;
564 }
565}
566
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400567bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400568 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
569 GLenum filter, bool fromAngleExtension)
570{
571 switch (filter)
572 {
573 case GL_NEAREST:
574 break;
575 case GL_LINEAR:
576 if (fromAngleExtension)
577 {
Geoff Langb1196682014-07-23 13:47:29 -0400578 context->recordError(Error(GL_INVALID_ENUM));
579 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400580 }
581 break;
582 default:
Geoff Langb1196682014-07-23 13:47:29 -0400583 context->recordError(Error(GL_INVALID_ENUM));
584 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400585 }
586
587 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
588 {
Geoff Langb1196682014-07-23 13:47:29 -0400589 context->recordError(Error(GL_INVALID_VALUE));
590 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400591 }
592
593 if (mask == 0)
594 {
595 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
596 // buffers are copied.
597 return false;
598 }
599
600 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
601 {
602 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400603 context->recordError(Error(GL_INVALID_OPERATION));
604 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605 }
606
607 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
608 // color buffer, leaving only nearest being unfiltered from above
609 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
610 {
Geoff Langb1196682014-07-23 13:47:29 -0400611 context->recordError(Error(GL_INVALID_OPERATION));
612 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613 }
614
Shannon Woods53a94a82014-06-24 15:20:36 -0400615 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 {
617 if (fromAngleExtension)
618 {
619 ERR("Blits with the same source and destination framebuffer are not supported by this "
620 "implementation.");
621 }
Geoff Langb1196682014-07-23 13:47:29 -0400622 context->recordError(Error(GL_INVALID_OPERATION));
623 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 }
625
Jamie Madille3ef7152015-04-28 16:55:17 +0000626 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
627 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500628
629 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 {
Geoff Langb1196682014-07-23 13:47:29 -0400631 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
632 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 }
634
Geoff Lang748f74e2014-12-01 11:25:34 -0500635 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500636 {
637 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
638 return false;
639 }
640
Geoff Lang748f74e2014-12-01 11:25:34 -0500641 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500642 {
643 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
644 return false;
645 }
646
647 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400648 {
Geoff Langb1196682014-07-23 13:47:29 -0400649 context->recordError(Error(GL_INVALID_OPERATION));
650 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 }
652
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
654
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 if (mask & GL_COLOR_BUFFER_BIT)
656 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400657 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
658 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659
660 if (readColorBuffer && drawColorBuffer)
661 {
Geoff Langd8a22582014-12-17 15:28:23 -0500662 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400663 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664
Corentin Wallez37c39792015-08-20 14:19:46 -0400665 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400666 {
667 if (drawFramebuffer->isEnabledColorAttachment(i))
668 {
Geoff Langd8a22582014-12-17 15:28:23 -0500669 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400670 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400671
Geoff Langb2f3d052013-08-13 12:49:27 -0400672 // The GL ES 3.0.2 spec (pg 193) states that:
673 // 1) If the read buffer is fixed point format, the draw buffer must be as well
674 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
675 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400676 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
677 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678 {
Geoff Langb1196682014-07-23 13:47:29 -0400679 context->recordError(Error(GL_INVALID_OPERATION));
680 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400681 }
682
Geoff Lang5d601382014-07-22 15:14:06 -0400683 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684 {
Geoff Langb1196682014-07-23 13:47:29 -0400685 context->recordError(Error(GL_INVALID_OPERATION));
686 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 }
688
Geoff Lang5d601382014-07-22 15:14:06 -0400689 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 {
Geoff Langb1196682014-07-23 13:47:29 -0400691 context->recordError(Error(GL_INVALID_OPERATION));
692 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 }
694
Geoff Langb2f3d052013-08-13 12:49:27 -0400695 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 {
Geoff Langb1196682014-07-23 13:47:29 -0400697 context->recordError(Error(GL_INVALID_OPERATION));
698 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400699 }
700 }
701 }
702
Geoff Lang5d601382014-07-22 15:14:06 -0400703 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400704 {
Geoff Langb1196682014-07-23 13:47:29 -0400705 context->recordError(Error(GL_INVALID_OPERATION));
706 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400707 }
708
709 if (fromAngleExtension)
710 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400711 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500712 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400713 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500714 readColorAttachment->type() != GL_RENDERBUFFER &&
715 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716 {
Geoff Langb1196682014-07-23 13:47:29 -0400717 context->recordError(Error(GL_INVALID_OPERATION));
718 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 }
720
Corentin Wallez37c39792015-08-20 14:19:46 -0400721 for (size_t colorAttachment = 0;
722 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723 {
724 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
725 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000726 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400727 ASSERT(attachment);
728
Jamie Madill8cf4a392015-04-02 11:36:04 -0400729 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500730 attachment->type() != GL_RENDERBUFFER &&
731 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 {
Geoff Langb1196682014-07-23 13:47:29 -0400733 context->recordError(Error(GL_INVALID_OPERATION));
734 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735 }
736
Jamie Madillf8f18f02014-10-02 10:44:17 -0400737 // Return an error if the destination formats do not match
738 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400739 {
Geoff Langb1196682014-07-23 13:47:29 -0400740 context->recordError(Error(GL_INVALID_OPERATION));
741 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400742 }
743 }
744 }
Jamie Madill48faf802014-11-06 15:27:22 -0500745
746 int readSamples = readFramebuffer->getSamples(context->getData());
747
748 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
749 srcX0, srcY0, srcX1, srcY1,
750 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751 {
Geoff Langb1196682014-07-23 13:47:29 -0400752 context->recordError(Error(GL_INVALID_OPERATION));
753 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 }
755 }
756 }
757 }
758
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200759 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
760 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
761 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200763 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400765 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
766 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200768 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400769 {
Geoff Langd8a22582014-12-17 15:28:23 -0500770 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 {
Geoff Langb1196682014-07-23 13:47:29 -0400772 context->recordError(Error(GL_INVALID_OPERATION));
773 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200776 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 {
Geoff Langb1196682014-07-23 13:47:29 -0400778 context->recordError(Error(GL_INVALID_OPERATION));
779 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200781
782 if (fromAngleExtension)
783 {
784 if (IsPartialBlit(context, readBuffer, drawBuffer,
785 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
786 {
787 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
788 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
789 return false;
790 }
791
792 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
793 {
794 context->recordError(Error(GL_INVALID_OPERATION));
795 return false;
796 }
797 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 }
799 }
800 }
801
802 return true;
803}
804
Geoff Langb1196682014-07-23 13:47:29 -0400805bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806{
807 switch (pname)
808 {
809 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
810 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
811 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
812 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
813 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
814 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
815 case GL_CURRENT_VERTEX_ATTRIB:
816 return true;
817
818 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
819 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
820 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400821 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
822 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400823 return true;
824
825 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400826 if (context->getClientVersion() < 3)
827 {
828 context->recordError(Error(GL_INVALID_ENUM));
829 return false;
830 }
831 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400832
833 default:
Geoff Langb1196682014-07-23 13:47:29 -0400834 context->recordError(Error(GL_INVALID_ENUM));
835 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400836 }
837}
838
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400839bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400840{
841 switch (pname)
842 {
843 case GL_TEXTURE_WRAP_R:
844 case GL_TEXTURE_SWIZZLE_R:
845 case GL_TEXTURE_SWIZZLE_G:
846 case GL_TEXTURE_SWIZZLE_B:
847 case GL_TEXTURE_SWIZZLE_A:
848 case GL_TEXTURE_BASE_LEVEL:
849 case GL_TEXTURE_MAX_LEVEL:
850 case GL_TEXTURE_COMPARE_MODE:
851 case GL_TEXTURE_COMPARE_FUNC:
852 case GL_TEXTURE_MIN_LOD:
853 case GL_TEXTURE_MAX_LOD:
854 if (context->getClientVersion() < 3)
855 {
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 break;
860
861 default: break;
862 }
863
864 switch (pname)
865 {
866 case GL_TEXTURE_WRAP_S:
867 case GL_TEXTURE_WRAP_T:
868 case GL_TEXTURE_WRAP_R:
869 switch (param)
870 {
871 case GL_REPEAT:
872 case GL_CLAMP_TO_EDGE:
873 case GL_MIRRORED_REPEAT:
874 return true;
875 default:
Geoff Langb1196682014-07-23 13:47:29 -0400876 context->recordError(Error(GL_INVALID_ENUM));
877 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400878 }
879
880 case GL_TEXTURE_MIN_FILTER:
881 switch (param)
882 {
883 case GL_NEAREST:
884 case GL_LINEAR:
885 case GL_NEAREST_MIPMAP_NEAREST:
886 case GL_LINEAR_MIPMAP_NEAREST:
887 case GL_NEAREST_MIPMAP_LINEAR:
888 case GL_LINEAR_MIPMAP_LINEAR:
889 return true;
890 default:
Geoff Langb1196682014-07-23 13:47:29 -0400891 context->recordError(Error(GL_INVALID_ENUM));
892 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400893 }
894 break;
895
896 case GL_TEXTURE_MAG_FILTER:
897 switch (param)
898 {
899 case GL_NEAREST:
900 case GL_LINEAR:
901 return true;
902 default:
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 break;
907
908 case GL_TEXTURE_USAGE_ANGLE:
909 switch (param)
910 {
911 case GL_NONE:
912 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
913 return true;
914 default:
Geoff Langb1196682014-07-23 13:47:29 -0400915 context->recordError(Error(GL_INVALID_ENUM));
916 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400917 }
918 break;
919
920 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400921 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400922 {
Geoff Langb1196682014-07-23 13:47:29 -0400923 context->recordError(Error(GL_INVALID_ENUM));
924 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400925 }
926
927 // we assume the parameter passed to this validation method is truncated, not rounded
928 if (param < 1)
929 {
Geoff Langb1196682014-07-23 13:47:29 -0400930 context->recordError(Error(GL_INVALID_VALUE));
931 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400932 }
933 return true;
934
935 case GL_TEXTURE_MIN_LOD:
936 case GL_TEXTURE_MAX_LOD:
937 // any value is permissible
938 return true;
939
940 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400941 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400942 switch (param)
943 {
944 case GL_NONE:
945 case GL_COMPARE_REF_TO_TEXTURE:
946 return true;
947 default:
Geoff Langb1196682014-07-23 13:47:29 -0400948 context->recordError(Error(GL_INVALID_ENUM));
949 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400950 }
951 break;
952
953 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400954 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400955 switch (param)
956 {
957 case GL_LEQUAL:
958 case GL_GEQUAL:
959 case GL_LESS:
960 case GL_GREATER:
961 case GL_EQUAL:
962 case GL_NOTEQUAL:
963 case GL_ALWAYS:
964 case GL_NEVER:
965 return true;
966 default:
Geoff Langb1196682014-07-23 13:47:29 -0400967 context->recordError(Error(GL_INVALID_ENUM));
968 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400969 }
970 break;
971
972 case GL_TEXTURE_SWIZZLE_R:
973 case GL_TEXTURE_SWIZZLE_G:
974 case GL_TEXTURE_SWIZZLE_B:
975 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400976 switch (param)
977 {
978 case GL_RED:
979 case GL_GREEN:
980 case GL_BLUE:
981 case GL_ALPHA:
982 case GL_ZERO:
983 case GL_ONE:
984 return true;
985 default:
Geoff Langb1196682014-07-23 13:47:29 -0400986 context->recordError(Error(GL_INVALID_ENUM));
987 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400988 }
989 break;
990
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400991 case GL_TEXTURE_BASE_LEVEL:
992 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400993 if (param < 0)
994 {
Geoff Langb1196682014-07-23 13:47:29 -0400995 context->recordError(Error(GL_INVALID_VALUE));
996 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400997 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400998 return true;
999
1000 default:
Geoff Langb1196682014-07-23 13:47:29 -04001001 context->recordError(Error(GL_INVALID_ENUM));
1002 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001003 }
1004}
1005
Geoff Langb1196682014-07-23 13:47:29 -04001006bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001007{
1008 switch (pname)
1009 {
1010 case GL_TEXTURE_MIN_FILTER:
1011 case GL_TEXTURE_MAG_FILTER:
1012 case GL_TEXTURE_WRAP_S:
1013 case GL_TEXTURE_WRAP_T:
1014 case GL_TEXTURE_WRAP_R:
1015 case GL_TEXTURE_MIN_LOD:
1016 case GL_TEXTURE_MAX_LOD:
1017 case GL_TEXTURE_COMPARE_MODE:
1018 case GL_TEXTURE_COMPARE_FUNC:
1019 return true;
1020
1021 default:
Geoff Langb1196682014-07-23 13:47:29 -04001022 context->recordError(Error(GL_INVALID_ENUM));
1023 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001024 }
1025}
1026
Jamie Madill26e91952014-03-05 15:01:27 -05001027bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
1028 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
1029{
Shannon Woods53a94a82014-06-24 15:20:36 -04001030 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001031 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001032
Geoff Lang748f74e2014-12-01 11:25:34 -05001033 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001034 {
Geoff Langb1196682014-07-23 13:47:29 -04001035 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1036 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001037 }
1038
Jamie Madill48faf802014-11-06 15:27:22 -05001039 if (context->getState().getReadFramebuffer()->id() != 0 &&
1040 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001041 {
Geoff Langb1196682014-07-23 13:47:29 -04001042 context->recordError(Error(GL_INVALID_OPERATION));
1043 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001044 }
1045
Geoff Langbce529e2014-12-01 12:48:41 -05001046 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1047 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001048 {
Geoff Langb1196682014-07-23 13:47:29 -04001049 context->recordError(Error(GL_INVALID_OPERATION));
1050 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001051 }
1052
Geoff Langbce529e2014-12-01 12:48:41 -05001053 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1054 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001055 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001056 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001057
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001058 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1059 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001060
1061 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1062 {
Geoff Langb1196682014-07-23 13:47:29 -04001063 context->recordError(Error(GL_INVALID_OPERATION));
1064 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001065 }
1066
Geoff Lang5d601382014-07-22 15:14:06 -04001067 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1068 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001069
Minmin Gongadff67b2015-10-14 10:34:45 -04001070 GLsizei outputPitch =
1071 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1072 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001073 // sized query sanity check
1074 if (bufSize)
1075 {
1076 int requiredSize = outputPitch * height;
1077 if (requiredSize > *bufSize)
1078 {
Geoff Langb1196682014-07-23 13:47:29 -04001079 context->recordError(Error(GL_INVALID_OPERATION));
1080 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001081 }
1082 }
1083
1084 return true;
1085}
1086
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001087bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1088{
1089 if (!ValidQueryType(context, target))
1090 {
Geoff Langb1196682014-07-23 13:47:29 -04001091 context->recordError(Error(GL_INVALID_ENUM));
1092 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001093 }
1094
1095 if (id == 0)
1096 {
Geoff Langb1196682014-07-23 13:47:29 -04001097 context->recordError(Error(GL_INVALID_OPERATION));
1098 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001099 }
1100
1101 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1102 // of zero, if the active query object name for <target> is non-zero (for the
1103 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1104 // the active query for either target is non-zero), if <id> is the name of an
1105 // existing query object whose type does not match <target>, or if <id> is the
1106 // active query object name for any query type, the error INVALID_OPERATION is
1107 // generated.
1108
1109 // Ensure no other queries are active
1110 // NOTE: If other queries than occlusion are supported, we will need to check
1111 // separately that:
1112 // a) The query ID passed is not the current active query for any target/type
1113 // b) There are no active queries for the requested target (and in the case
1114 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1115 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001116 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001117 {
Geoff Langb1196682014-07-23 13:47:29 -04001118 context->recordError(Error(GL_INVALID_OPERATION));
1119 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001120 }
1121
1122 Query *queryObject = context->getQuery(id, true, target);
1123
1124 // check that name was obtained with glGenQueries
1125 if (!queryObject)
1126 {
Geoff Langb1196682014-07-23 13:47:29 -04001127 context->recordError(Error(GL_INVALID_OPERATION));
1128 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001129 }
1130
1131 // check for type mismatch
1132 if (queryObject->getType() != target)
1133 {
Geoff Langb1196682014-07-23 13:47:29 -04001134 context->recordError(Error(GL_INVALID_OPERATION));
1135 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001136 }
1137
1138 return true;
1139}
1140
Jamie Madill45c785d2014-05-13 14:09:34 -04001141bool ValidateEndQuery(gl::Context *context, GLenum target)
1142{
1143 if (!ValidQueryType(context, target))
1144 {
Geoff Langb1196682014-07-23 13:47:29 -04001145 context->recordError(Error(GL_INVALID_ENUM));
1146 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001147 }
1148
Shannon Woods53a94a82014-06-24 15:20:36 -04001149 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001150
1151 if (queryObject == NULL)
1152 {
Geoff Langb1196682014-07-23 13:47:29 -04001153 context->recordError(Error(GL_INVALID_OPERATION));
1154 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001155 }
1156
Jamie Madill45c785d2014-05-13 14:09:34 -04001157 return true;
1158}
1159
Jamie Madill62d31cb2015-09-11 13:25:51 -04001160static bool ValidateUniformCommonBase(gl::Context *context,
1161 GLenum targetUniformType,
1162 GLint location,
1163 GLsizei count,
1164 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001165{
1166 if (count < 0)
1167 {
Geoff Langb1196682014-07-23 13:47:29 -04001168 context->recordError(Error(GL_INVALID_VALUE));
1169 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001170 }
1171
Geoff Lang7dd2e102014-11-10 15:19:26 -05001172 gl::Program *program = context->getState().getProgram();
1173 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001174 {
Geoff Langb1196682014-07-23 13:47:29 -04001175 context->recordError(Error(GL_INVALID_OPERATION));
1176 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001177 }
1178
1179 if (location == -1)
1180 {
1181 // Silently ignore the uniform command
1182 return false;
1183 }
1184
Geoff Lang7dd2e102014-11-10 15:19:26 -05001185 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001186 {
Geoff Langb1196682014-07-23 13:47:29 -04001187 context->recordError(Error(GL_INVALID_OPERATION));
1188 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001189 }
1190
Jamie Madill62d31cb2015-09-11 13:25:51 -04001191 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001192
1193 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001194 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001195 {
Geoff Langb1196682014-07-23 13:47:29 -04001196 context->recordError(Error(GL_INVALID_OPERATION));
1197 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001198 }
1199
Jamie Madill62d31cb2015-09-11 13:25:51 -04001200 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001201 return true;
1202}
1203
Jamie Madillaa981bd2014-05-20 10:55:55 -04001204bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1205{
1206 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001207 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001208 {
Geoff Langb1196682014-07-23 13:47:29 -04001209 context->recordError(Error(GL_INVALID_OPERATION));
1210 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001211 }
1212
Jamie Madill62d31cb2015-09-11 13:25:51 -04001213 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001214 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1215 {
1216 return false;
1217 }
1218
Jamie Madillf2575982014-06-25 16:04:54 -04001219 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001220 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001221 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1222 {
Geoff Langb1196682014-07-23 13:47:29 -04001223 context->recordError(Error(GL_INVALID_OPERATION));
1224 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001225 }
1226
1227 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001228}
1229
1230bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1231 GLboolean transpose)
1232{
1233 // Check for ES3 uniform entry points
1234 int rows = VariableRowCount(matrixType);
1235 int cols = VariableColumnCount(matrixType);
1236 if (rows != cols && context->getClientVersion() < 3)
1237 {
Geoff Langb1196682014-07-23 13:47:29 -04001238 context->recordError(Error(GL_INVALID_OPERATION));
1239 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001240 }
1241
1242 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1243 {
Geoff Langb1196682014-07-23 13:47:29 -04001244 context->recordError(Error(GL_INVALID_VALUE));
1245 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001246 }
1247
Jamie Madill62d31cb2015-09-11 13:25:51 -04001248 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001249 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1250 {
1251 return false;
1252 }
1253
1254 if (uniform->type != matrixType)
1255 {
Geoff Langb1196682014-07-23 13:47:29 -04001256 context->recordError(Error(GL_INVALID_OPERATION));
1257 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001258 }
1259
1260 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001261}
1262
Jamie Madill893ab082014-05-16 16:56:10 -04001263bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1264{
1265 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1266 {
Geoff Langb1196682014-07-23 13:47:29 -04001267 context->recordError(Error(GL_INVALID_ENUM));
1268 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001269 }
1270
Jamie Madill0af26e12015-03-05 19:54:33 -05001271 const Caps &caps = context->getCaps();
1272
Jamie Madill893ab082014-05-16 16:56:10 -04001273 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1274 {
1275 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1276
Jamie Madill0af26e12015-03-05 19:54:33 -05001277 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001278 {
Geoff Langb1196682014-07-23 13:47:29 -04001279 context->recordError(Error(GL_INVALID_OPERATION));
1280 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001281 }
1282 }
1283
1284 switch (pname)
1285 {
1286 case GL_TEXTURE_BINDING_2D:
1287 case GL_TEXTURE_BINDING_CUBE_MAP:
1288 case GL_TEXTURE_BINDING_3D:
1289 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001290 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001291 {
Geoff Langb1196682014-07-23 13:47:29 -04001292 context->recordError(Error(GL_INVALID_OPERATION));
1293 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001294 }
1295 break;
1296
1297 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1298 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1299 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001300 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001301 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001302 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001303 {
Geoff Langb1196682014-07-23 13:47:29 -04001304 context->recordError(Error(GL_INVALID_OPERATION));
1305 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001306 }
1307
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001308 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001309 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001310 {
Geoff Langb1196682014-07-23 13:47:29 -04001311 context->recordError(Error(GL_INVALID_OPERATION));
1312 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001313 }
1314 }
1315 break;
1316
1317 default:
1318 break;
1319 }
1320
1321 // pname is valid, but there are no parameters to return
1322 if (numParams == 0)
1323 {
1324 return false;
1325 }
1326
1327 return true;
1328}
1329
Geoff Lang831b1952015-05-05 11:02:27 -04001330bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001331 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1332 GLint border, GLenum *textureFormatOut)
1333{
1334
1335 if (!ValidTexture2DDestinationTarget(context, target))
1336 {
Geoff Langb1196682014-07-23 13:47:29 -04001337 context->recordError(Error(GL_INVALID_ENUM));
1338 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001339 }
1340
1341 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1342 {
Geoff Langb1196682014-07-23 13:47:29 -04001343 context->recordError(Error(GL_INVALID_VALUE));
1344 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001345 }
1346
1347 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1348 {
Geoff Langb1196682014-07-23 13:47:29 -04001349 context->recordError(Error(GL_INVALID_VALUE));
1350 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001351 }
1352
1353 if (border != 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 (!ValidMipLevel(context, target, level))
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
Shannon Woods53a94a82014-06-24 15:20:36 -04001365 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001366 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001367 {
Geoff Langb1196682014-07-23 13:47:29 -04001368 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1369 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 }
1371
Jamie Madill48faf802014-11-06 15:27:22 -05001372 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001373 {
Geoff Langb1196682014-07-23 13:47:29 -04001374 context->recordError(Error(GL_INVALID_OPERATION));
1375 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001376 }
1377
Geoff Langaae65a42014-05-26 12:43:44 -04001378 const gl::Caps &caps = context->getCaps();
1379
Geoff Langaae65a42014-05-26 12:43:44 -04001380 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001381 switch (target)
1382 {
1383 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001384 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001385 break;
1386
1387 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1388 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1389 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1390 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1391 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1392 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001393 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001394 break;
1395
1396 case GL_TEXTURE_2D_ARRAY:
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_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001401 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001402 break;
1403
1404 default:
Geoff Langb1196682014-07-23 13:47:29 -04001405 context->recordError(Error(GL_INVALID_ENUM));
1406 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001407 }
1408
Geoff Lang691e58c2014-12-19 17:03:25 -05001409 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001410 if (!texture)
1411 {
Geoff Langb1196682014-07-23 13:47:29 -04001412 context->recordError(Error(GL_INVALID_OPERATION));
1413 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001414 }
1415
Geoff Lang69cce582015-09-17 13:20:36 -04001416 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001417 {
Geoff Langb1196682014-07-23 13:47:29 -04001418 context->recordError(Error(GL_INVALID_OPERATION));
1419 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001420 }
1421
Geoff Lang5d601382014-07-22 15:14:06 -04001422 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1423
1424 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001425 {
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 Langa9be0dc2014-12-17 12:34:40 -05001430 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001431 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001432 context->recordError(Error(GL_INVALID_OPERATION));
1433 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001434 }
1435
1436 if (isSubImage)
1437 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001438 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1439 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1440 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001441 {
Geoff Langb1196682014-07-23 13:47:29 -04001442 context->recordError(Error(GL_INVALID_VALUE));
1443 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001444 }
1445 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001446 else
1447 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001448 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001449 {
Geoff Langb1196682014-07-23 13:47:29 -04001450 context->recordError(Error(GL_INVALID_VALUE));
1451 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001452 }
1453
Geoff Lang5d601382014-07-22 15:14:06 -04001454 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001455 {
Geoff Langb1196682014-07-23 13:47:29 -04001456 context->recordError(Error(GL_INVALID_ENUM));
1457 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001458 }
1459
1460 int maxLevelDimension = (maxDimension >> level);
1461 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1462 {
Geoff Langb1196682014-07-23 13:47:29 -04001463 context->recordError(Error(GL_INVALID_VALUE));
1464 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001465 }
1466 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001467
Geoff Langa9be0dc2014-12-17 12:34:40 -05001468 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001469 return true;
1470}
1471
Jamie Madillf25855c2015-11-03 11:06:18 -05001472static bool ValidateDrawBase(ValidationContext *context,
1473 GLenum mode,
1474 GLsizei count,
1475 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001476{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001477 switch (mode)
1478 {
1479 case GL_POINTS:
1480 case GL_LINES:
1481 case GL_LINE_LOOP:
1482 case GL_LINE_STRIP:
1483 case GL_TRIANGLES:
1484 case GL_TRIANGLE_STRIP:
1485 case GL_TRIANGLE_FAN:
1486 break;
1487 default:
Geoff Langb1196682014-07-23 13:47:29 -04001488 context->recordError(Error(GL_INVALID_ENUM));
1489 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001490 }
1491
Jamie Madill250d33f2014-06-06 17:09:03 -04001492 if (count < 0)
1493 {
Geoff Langb1196682014-07-23 13:47:29 -04001494 context->recordError(Error(GL_INVALID_VALUE));
1495 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001496 }
1497
Geoff Langb1196682014-07-23 13:47:29 -04001498 const State &state = context->getState();
1499
Jamie Madill250d33f2014-06-06 17:09:03 -04001500 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001501 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001502 {
Geoff Langb1196682014-07-23 13:47:29 -04001503 context->recordError(Error(GL_INVALID_OPERATION));
1504 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001505 }
1506
Geoff Lang3a86ad32015-09-01 11:47:05 -04001507 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001508 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001509 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1510 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1511 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1512 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1513 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1514 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1515 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001516 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001517 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1518 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001519 {
1520 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1521 // Section 6.10 of the WebGL 1.0 spec
1522 ERR(
1523 "This ANGLE implementation does not support separate front/back stencil "
1524 "writemasks, reference values, or stencil mask values.");
1525 context->recordError(Error(GL_INVALID_OPERATION));
1526 return false;
1527 }
Jamie Madillac528012014-06-20 13:21:23 -04001528 }
1529
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001530 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001531 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001532 {
Geoff Langb1196682014-07-23 13:47:29 -04001533 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1534 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001535 }
1536
Geoff Lang7dd2e102014-11-10 15:19:26 -05001537 gl::Program *program = state.getProgram();
1538 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001539 {
Geoff Langb1196682014-07-23 13:47:29 -04001540 context->recordError(Error(GL_INVALID_OPERATION));
1541 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001542 }
1543
Geoff Lang7dd2e102014-11-10 15:19:26 -05001544 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001545 {
Geoff Langb1196682014-07-23 13:47:29 -04001546 context->recordError(Error(GL_INVALID_OPERATION));
1547 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001548 }
1549
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001550 // Uniform buffer validation
1551 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1552 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001553 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001554 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001555 const OffsetBindingPointer<Buffer> &uniformBuffer =
1556 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001557
Geoff Lang5d124a62015-09-15 13:03:27 -04001558 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001559 {
1560 // undefined behaviour
1561 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1562 return false;
1563 }
1564
Geoff Lang5d124a62015-09-15 13:03:27 -04001565 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001566 if (uniformBufferSize == 0)
1567 {
1568 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001569 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001570 }
1571
Jamie Madill62d31cb2015-09-11 13:25:51 -04001572 if (uniformBufferSize < uniformBlock.dataSize)
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 use a uniform buffer that is too small."));
1576 return false;
1577 }
1578 }
1579
Jamie Madill250d33f2014-06-06 17:09:03 -04001580 // No-op if zero count
1581 return (count > 0);
1582}
1583
Geoff Langb1196682014-07-23 13:47:29 -04001584bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001585{
Jamie Madillfd716582014-06-06 17:09:04 -04001586 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001587 {
Geoff Langb1196682014-07-23 13:47:29 -04001588 context->recordError(Error(GL_INVALID_VALUE));
1589 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001590 }
1591
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001592 const State &state = context->getState();
1593 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001594 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1595 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001596 {
1597 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1598 // that does not match the current transform feedback object's draw mode (if transform feedback
1599 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001600 context->recordError(Error(GL_INVALID_OPERATION));
1601 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001602 }
1603
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001604 if (!ValidateDrawBase(context, mode, count, primcount))
1605 {
1606 return false;
1607 }
1608
1609 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001610 {
1611 return false;
1612 }
1613
1614 return true;
1615}
1616
Geoff Langb1196682014-07-23 13:47:29 -04001617bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001618{
1619 if (primcount < 0)
1620 {
Geoff Langb1196682014-07-23 13:47:29 -04001621 context->recordError(Error(GL_INVALID_VALUE));
1622 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001623 }
1624
Jamie Madill2b976812014-08-25 15:47:49 -04001625 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001626 {
1627 return false;
1628 }
1629
1630 // No-op if zero primitive count
1631 return (primcount > 0);
1632}
1633
Geoff Lang87a93302014-09-16 13:29:43 -04001634static bool ValidateDrawInstancedANGLE(Context *context)
1635{
1636 // Verify there is at least one active attribute with a divisor of zero
1637 const gl::State& state = context->getState();
1638
Geoff Lang7dd2e102014-11-10 15:19:26 -05001639 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001640
1641 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001642 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001643 {
1644 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001645 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001646 {
1647 return true;
1648 }
1649 }
1650
1651 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1652 "has a divisor of zero."));
1653 return false;
1654}
1655
1656bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1657{
1658 if (!ValidateDrawInstancedANGLE(context))
1659 {
1660 return false;
1661 }
1662
1663 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1664}
1665
Jamie Madillf25855c2015-11-03 11:06:18 -05001666bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001667 GLenum mode,
1668 GLsizei count,
1669 GLenum type,
1670 const GLvoid *indices,
1671 GLsizei primcount,
1672 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001673{
Jamie Madill250d33f2014-06-06 17:09:03 -04001674 switch (type)
1675 {
1676 case GL_UNSIGNED_BYTE:
1677 case GL_UNSIGNED_SHORT:
1678 break;
1679 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001680 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001681 {
Geoff Langb1196682014-07-23 13:47:29 -04001682 context->recordError(Error(GL_INVALID_ENUM));
1683 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001684 }
1685 break;
1686 default:
Geoff Langb1196682014-07-23 13:47:29 -04001687 context->recordError(Error(GL_INVALID_ENUM));
1688 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001689 }
1690
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001691 const State &state = context->getState();
1692
1693 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001694 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001695 {
1696 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1697 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001698 context->recordError(Error(GL_INVALID_OPERATION));
1699 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001700 }
1701
1702 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001703 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001704 {
Geoff Langb1196682014-07-23 13:47:29 -04001705 context->recordError(Error(GL_INVALID_OPERATION));
1706 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001707 }
1708
Jamie Madill2b976812014-08-25 15:47:49 -04001709 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001710 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001711 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001712 {
Geoff Langb1196682014-07-23 13:47:29 -04001713 context->recordError(Error(GL_INVALID_OPERATION));
1714 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001715 }
1716
Jamie Madillae3000b2014-08-25 15:47:51 -04001717 if (elementArrayBuffer)
1718 {
1719 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1720
1721 GLint64 offset = reinterpret_cast<GLint64>(indices);
1722 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1723
1724 // check for integer overflows
1725 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1726 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1727 {
Geoff Langb1196682014-07-23 13:47:29 -04001728 context->recordError(Error(GL_OUT_OF_MEMORY));
1729 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001730 }
1731
1732 // Check for reading past the end of the bound buffer object
1733 if (byteCount > elementArrayBuffer->getSize())
1734 {
Geoff Langb1196682014-07-23 13:47:29 -04001735 context->recordError(Error(GL_INVALID_OPERATION));
1736 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001737 }
1738 }
1739 else if (!indices)
1740 {
1741 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001742 context->recordError(Error(GL_INVALID_OPERATION));
1743 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001744 }
1745
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001746 if (!ValidateDrawBase(context, mode, count, primcount))
1747 {
1748 return false;
1749 }
1750
Jamie Madill2b976812014-08-25 15:47:49 -04001751 // Use max index to validate if our vertex buffers are large enough for the pull.
1752 // TODO: offer fast path, with disabled index validation.
1753 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1754 if (elementArrayBuffer)
1755 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001756 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001757 Error error =
1758 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1759 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001760 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001761 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001762 context->recordError(error);
1763 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001764 }
1765 }
1766 else
1767 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001768 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001769 }
1770
Jamie Madille79b1e12015-11-04 16:36:37 -05001771 // If we use an index greater than our maximum supported index range, return an error.
1772 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1773 // return an error if possible here.
1774 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1775 {
1776 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1777 return false;
1778 }
1779
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001780 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001781 {
1782 return false;
1783 }
1784
Geoff Lang3edfe032015-09-04 16:38:24 -04001785 // No op if there are no real indices in the index data (all are primitive restart).
1786 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001787}
1788
Geoff Langb1196682014-07-23 13:47:29 -04001789bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001790 GLenum mode,
1791 GLsizei count,
1792 GLenum type,
1793 const GLvoid *indices,
1794 GLsizei primcount,
1795 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001796{
1797 if (primcount < 0)
1798 {
Geoff Langb1196682014-07-23 13:47:29 -04001799 context->recordError(Error(GL_INVALID_VALUE));
1800 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001801 }
1802
Jamie Madill2b976812014-08-25 15:47:49 -04001803 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001804 {
1805 return false;
1806 }
1807
1808 // No-op zero primitive count
1809 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001810}
1811
Geoff Lang3edfe032015-09-04 16:38:24 -04001812bool ValidateDrawElementsInstancedANGLE(Context *context,
1813 GLenum mode,
1814 GLsizei count,
1815 GLenum type,
1816 const GLvoid *indices,
1817 GLsizei primcount,
1818 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001819{
1820 if (!ValidateDrawInstancedANGLE(context))
1821 {
1822 return false;
1823 }
1824
1825 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1826}
1827
Geoff Langb1196682014-07-23 13:47:29 -04001828bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001829 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001830{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001831 if (!ValidFramebufferTarget(target))
1832 {
Geoff Langb1196682014-07-23 13:47:29 -04001833 context->recordError(Error(GL_INVALID_ENUM));
1834 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001835 }
1836
1837 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001838 {
1839 return false;
1840 }
1841
Jamie Madill55ec3b12014-07-03 10:38:57 -04001842 if (texture != 0)
1843 {
1844 gl::Texture *tex = context->getTexture(texture);
1845
1846 if (tex == NULL)
1847 {
Geoff Langb1196682014-07-23 13:47:29 -04001848 context->recordError(Error(GL_INVALID_OPERATION));
1849 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001850 }
1851
1852 if (level < 0)
1853 {
Geoff Langb1196682014-07-23 13:47:29 -04001854 context->recordError(Error(GL_INVALID_VALUE));
1855 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001856 }
1857 }
1858
Shannon Woods53a94a82014-06-24 15:20:36 -04001859 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001860 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001861
Jamie Madill84115c92015-04-23 15:00:07 -04001862 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001863 {
Jamie Madill84115c92015-04-23 15:00:07 -04001864 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001865 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001866 }
1867
1868 return true;
1869}
1870
Geoff Langb1196682014-07-23 13:47:29 -04001871bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001872 GLenum textarget, GLuint texture, GLint level)
1873{
Geoff Lang95663912015-04-02 15:54:45 -04001874 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1875 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001876 {
Geoff Langb1196682014-07-23 13:47:29 -04001877 context->recordError(Error(GL_INVALID_VALUE));
1878 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001879 }
1880
1881 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001882 {
1883 return false;
1884 }
1885
Jamie Madill55ec3b12014-07-03 10:38:57 -04001886 if (texture != 0)
1887 {
1888 gl::Texture *tex = context->getTexture(texture);
1889 ASSERT(tex);
1890
Jamie Madill2a6564e2014-07-11 09:53:19 -04001891 const gl::Caps &caps = context->getCaps();
1892
Jamie Madill55ec3b12014-07-03 10:38:57 -04001893 switch (textarget)
1894 {
1895 case GL_TEXTURE_2D:
1896 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001897 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001898 {
Geoff Langb1196682014-07-23 13:47:29 -04001899 context->recordError(Error(GL_INVALID_VALUE));
1900 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001901 }
1902 if (tex->getTarget() != GL_TEXTURE_2D)
1903 {
Geoff Langb1196682014-07-23 13:47:29 -04001904 context->recordError(Error(GL_INVALID_OPERATION));
1905 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001906 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001907 }
1908 break;
1909
1910 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1911 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1912 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1913 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1914 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1915 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1916 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001917 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001918 {
Geoff Langb1196682014-07-23 13:47:29 -04001919 context->recordError(Error(GL_INVALID_VALUE));
1920 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001921 }
1922 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1923 {
Geoff Langb1196682014-07-23 13:47:29 -04001924 context->recordError(Error(GL_INVALID_OPERATION));
1925 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001926 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001927 }
1928 break;
1929
1930 default:
Geoff Langb1196682014-07-23 13:47:29 -04001931 context->recordError(Error(GL_INVALID_ENUM));
1932 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001933 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001934
1935 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1936 if (internalFormatInfo.compressed)
1937 {
1938 context->recordError(Error(GL_INVALID_OPERATION));
1939 return false;
1940 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001941 }
1942
Jamie Madill570f7c82014-07-03 10:38:54 -04001943 return true;
1944}
1945
Geoff Langb1196682014-07-23 13:47:29 -04001946bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001947{
1948 if (program == 0)
1949 {
Geoff Langb1196682014-07-23 13:47:29 -04001950 context->recordError(Error(GL_INVALID_VALUE));
1951 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001952 }
1953
Dian Xiang769769a2015-09-09 15:20:08 -07001954 gl::Program *programObject = GetValidProgram(context, program);
1955 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001956 {
1957 return false;
1958 }
1959
Jamie Madill0063c512014-08-25 15:47:53 -04001960 if (!programObject || !programObject->isLinked())
1961 {
Geoff Langb1196682014-07-23 13:47:29 -04001962 context->recordError(Error(GL_INVALID_OPERATION));
1963 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001964 }
1965
Geoff Lang7dd2e102014-11-10 15:19:26 -05001966 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001967 {
Geoff Langb1196682014-07-23 13:47:29 -04001968 context->recordError(Error(GL_INVALID_OPERATION));
1969 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001970 }
1971
Jamie Madill0063c512014-08-25 15:47:53 -04001972 return true;
1973}
1974
Geoff Langb1196682014-07-23 13:47:29 -04001975bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001976{
1977 return ValidateGetUniformBase(context, program, location);
1978}
1979
Geoff Langb1196682014-07-23 13:47:29 -04001980bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001981{
Jamie Madill78f41802014-08-25 15:47:55 -04001982 return ValidateGetUniformBase(context, program, location);
1983}
1984
Geoff Langb1196682014-07-23 13:47:29 -04001985static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001986{
1987 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001988 {
Jamie Madill78f41802014-08-25 15:47:55 -04001989 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001990 }
1991
Jamie Madilla502c742014-08-28 17:19:13 -04001992 gl::Program *programObject = context->getProgram(program);
1993 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001994
Jamie Madill78f41802014-08-25 15:47:55 -04001995 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04001996 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
1997 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04001998 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001999 {
Geoff Langb1196682014-07-23 13:47:29 -04002000 context->recordError(Error(GL_INVALID_OPERATION));
2001 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002002 }
2003
2004 return true;
2005}
2006
Geoff Langb1196682014-07-23 13:47:29 -04002007bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002008{
Jamie Madill78f41802014-08-25 15:47:55 -04002009 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002010}
2011
Geoff Langb1196682014-07-23 13:47:29 -04002012bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002013{
Jamie Madill78f41802014-08-25 15:47:55 -04002014 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002015}
2016
Austin Kinross08332632015-05-05 13:35:47 -07002017bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2018 const GLenum *attachments, bool defaultFramebuffer)
2019{
2020 if (numAttachments < 0)
2021 {
2022 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2023 return false;
2024 }
2025
2026 for (GLsizei i = 0; i < numAttachments; ++i)
2027 {
2028 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2029 {
2030 if (defaultFramebuffer)
2031 {
2032 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2033 return false;
2034 }
2035
2036 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2037 {
2038 context->recordError(Error(GL_INVALID_OPERATION,
2039 "Requested color attachment is greater than the maximum supported color attachments"));
2040 return false;
2041 }
2042 }
2043 else
2044 {
2045 switch (attachments[i])
2046 {
2047 case GL_DEPTH_ATTACHMENT:
2048 case GL_STENCIL_ATTACHMENT:
2049 case GL_DEPTH_STENCIL_ATTACHMENT:
2050 if (defaultFramebuffer)
2051 {
2052 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2053 return false;
2054 }
2055 break;
2056 case GL_COLOR:
2057 case GL_DEPTH:
2058 case GL_STENCIL:
2059 if (!defaultFramebuffer)
2060 {
2061 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2062 return false;
2063 }
2064 break;
2065 default:
2066 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2067 return false;
2068 }
2069 }
2070 }
2071
2072 return true;
2073}
2074
Austin Kinross6ee1e782015-05-29 17:05:37 -07002075bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2076{
2077 // Note that debug marker calls must not set error state
2078
2079 if (length < 0)
2080 {
2081 return false;
2082 }
2083
2084 if (marker == nullptr)
2085 {
2086 return false;
2087 }
2088
2089 return true;
2090}
2091
2092bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2093{
2094 // Note that debug marker calls must not set error state
2095
2096 if (length < 0)
2097 {
2098 return false;
2099 }
2100
2101 if (length > 0 && marker == nullptr)
2102 {
2103 return false;
2104 }
2105
2106 return true;
2107}
2108
Geoff Langdcab33b2015-07-21 13:03:16 -04002109bool ValidateEGLImageTargetTexture2DOES(Context *context,
2110 egl::Display *display,
2111 GLenum target,
2112 egl::Image *image)
2113{
Geoff Langa8406172015-07-21 16:53:39 -04002114 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2115 {
2116 context->recordError(Error(GL_INVALID_OPERATION));
2117 return false;
2118 }
2119
2120 switch (target)
2121 {
2122 case GL_TEXTURE_2D:
2123 break;
2124
2125 default:
2126 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2127 return false;
2128 }
2129
2130 if (!display->isValidImage(image))
2131 {
2132 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2133 return false;
2134 }
2135
2136 if (image->getSamples() > 0)
2137 {
2138 context->recordError(Error(GL_INVALID_OPERATION,
2139 "cannot create a 2D texture from a multisampled EGL image."));
2140 return false;
2141 }
2142
2143 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2144 if (!textureCaps.texturable)
2145 {
2146 context->recordError(Error(GL_INVALID_OPERATION,
2147 "EGL image internal format is not supported as a texture."));
2148 return false;
2149 }
2150
Geoff Langdcab33b2015-07-21 13:03:16 -04002151 return true;
2152}
2153
2154bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2155 egl::Display *display,
2156 GLenum target,
2157 egl::Image *image)
2158{
Geoff Langa8406172015-07-21 16:53:39 -04002159 if (!context->getExtensions().eglImage)
2160 {
2161 context->recordError(Error(GL_INVALID_OPERATION));
2162 return false;
2163 }
2164
2165 switch (target)
2166 {
2167 case GL_RENDERBUFFER:
2168 break;
2169
2170 default:
2171 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2172 return false;
2173 }
2174
2175 if (!display->isValidImage(image))
2176 {
2177 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2178 return false;
2179 }
2180
2181 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2182 if (!textureCaps.renderable)
2183 {
2184 context->recordError(Error(
2185 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2186 return false;
2187 }
2188
Geoff Langdcab33b2015-07-21 13:03:16 -04002189 return true;
2190}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002191
2192bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2193{
Geoff Lang50b3fe82015-12-08 14:49:12 +00002194 VertexArray *vao = context->getVertexArray(array);
2195
2196 if (!vao)
Austin Kinrossbc781f32015-10-26 09:27:38 -07002197 {
2198 // The default VAO should always exist
2199 ASSERT(array != 0);
2200 context->recordError(Error(GL_INVALID_OPERATION));
2201 return false;
2202 }
2203
2204 return true;
2205}
2206
2207bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2208{
2209 if (n < 0)
2210 {
2211 context->recordError(Error(GL_INVALID_VALUE));
2212 return false;
2213 }
2214
2215 return true;
2216}
2217
2218bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2219{
2220 if (n < 0)
2221 {
2222 context->recordError(Error(GL_INVALID_VALUE));
2223 return false;
2224 }
2225
2226 return true;
2227}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002228}