blob: 3c345641bd327791a7a5af3d5a0bd281787fedda [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
114 case GL_RASTERIZER_DISCARD:
115 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500116
117 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
118 case GL_DEBUG_OUTPUT:
119 return context->getExtensions().debug;
120
Geoff Lang0550d032014-01-30 11:29:07 -0500121 default:
122 return false;
123 }
124}
125
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500126bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400127{
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400129 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500130 case GL_TEXTURE_2D:
131 case GL_TEXTURE_CUBE_MAP:
132 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400133
Jamie Madilld7460c72014-01-21 16:38:14 -0500134 case GL_TEXTURE_3D:
135 case GL_TEXTURE_2D_ARRAY:
136 return (context->getClientVersion() >= 3);
137
138 default:
139 return false;
140 }
Jamie Madill35d15012013-10-07 10:46:37 -0400141}
142
Shannon Woods4dfed832014-03-17 20:03:39 -0400143// This function differs from ValidTextureTarget in that the target must be
144// usable as the destination of a 2D operation-- so a cube face is valid, but
145// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400146// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500147bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400148{
149 switch (target)
150 {
151 case GL_TEXTURE_2D:
152 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
153 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
154 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
155 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
156 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
157 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
158 return true;
159 case GL_TEXTURE_2D_ARRAY:
160 case GL_TEXTURE_3D:
161 return (context->getClientVersion() >= 3);
162 default:
163 return false;
164 }
165}
166
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500167bool ValidFramebufferTarget(GLenum target)
168{
Geoff Langd4475812015-03-18 10:53:05 -0400169 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
170 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500171
172 switch (target)
173 {
174 case GL_FRAMEBUFFER: return true;
175 case GL_READ_FRAMEBUFFER: return true;
176 case GL_DRAW_FRAMEBUFFER: return true;
177 default: return false;
178 }
179}
180
Jamie Madill8c96d582014-03-05 15:01:23 -0500181bool ValidBufferTarget(const Context *context, GLenum target)
182{
183 switch (target)
184 {
185 case GL_ARRAY_BUFFER:
186 case GL_ELEMENT_ARRAY_BUFFER:
187 return true;
188
Jamie Madill8c96d582014-03-05 15:01:23 -0500189 case GL_PIXEL_PACK_BUFFER:
190 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400191 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400192
Shannon Woodsb3801742014-03-27 14:59:19 -0400193 case GL_COPY_READ_BUFFER:
194 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500195 case GL_TRANSFORM_FEEDBACK_BUFFER:
196 case GL_UNIFORM_BUFFER:
197 return (context->getClientVersion() >= 3);
198
199 default:
200 return false;
201 }
202}
203
Jamie Madill70656a62014-03-05 15:01:26 -0500204bool ValidBufferParameter(const Context *context, GLenum pname)
205{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400206 const Extensions &extensions = context->getExtensions();
207
Jamie Madill70656a62014-03-05 15:01:26 -0500208 switch (pname)
209 {
210 case GL_BUFFER_USAGE:
211 case GL_BUFFER_SIZE:
212 return true;
213
Geoff Langcc6f55d2015-03-20 13:01:02 -0400214 case GL_BUFFER_ACCESS_OES:
215 return extensions.mapBuffer;
216
217 case GL_BUFFER_MAPPED:
218 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
219 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
220
Jamie Madill70656a62014-03-05 15:01:26 -0500221 // GL_BUFFER_MAP_POINTER is a special case, and may only be
222 // queried with GetBufferPointerv
223 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500224 case GL_BUFFER_MAP_OFFSET:
225 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400226 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500227
228 default:
229 return false;
230 }
231}
232
Jamie Madillc29968b2016-01-20 11:17:23 -0500233bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400234{
Jamie Madillc29968b2016-01-20 11:17:23 -0500235 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400236 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400237 switch (target)
238 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500239 case GL_TEXTURE_2D:
240 maxDimension = caps.max2DTextureSize;
241 break;
Geoff Langce635692013-09-24 13:56:32 -0400242 case GL_TEXTURE_CUBE_MAP:
243 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
244 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
245 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
246 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
247 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500248 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
249 maxDimension = caps.maxCubeMapTextureSize;
250 break;
251 case GL_TEXTURE_3D:
252 maxDimension = caps.max3DTextureSize;
253 break;
254 case GL_TEXTURE_2D_ARRAY:
255 maxDimension = caps.max2DTextureSize;
256 break;
Geoff Langce635692013-09-24 13:56:32 -0400257 default: UNREACHABLE();
258 }
259
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700260 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400261}
262
Austin Kinross08528e12015-10-07 16:24:40 -0700263bool ValidImageSizeParameters(const Context *context,
264 GLenum target,
265 GLint level,
266 GLsizei width,
267 GLsizei height,
268 GLsizei depth,
269 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400270{
271 if (level < 0 || width < 0 || height < 0 || depth < 0)
272 {
273 return false;
274 }
275
Austin Kinross08528e12015-10-07 16:24:40 -0700276 // TexSubImage parameters can be NPOT without textureNPOT extension,
277 // as long as the destination texture is POT.
278 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400279 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400280 {
281 return false;
282 }
283
284 if (!ValidMipLevel(context, target, level))
285 {
286 return false;
287 }
288
289 return true;
290}
291
Geoff Lang0d8b7242015-09-09 14:56:53 -0400292bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
293{
294 // List of compressed format that require that the texture size is smaller than or a multiple of
295 // the compressed block size.
296 switch (internalFormat)
297 {
298 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
299 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
300 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
301 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
302 return true;
303
304 default:
305 return false;
306 }
307}
308
Jamie Madillc29968b2016-01-20 11:17:23 -0500309bool ValidCompressedImageSize(const ValidationContext *context,
310 GLenum internalFormat,
311 GLsizei width,
312 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400313{
Geoff Lang5d601382014-07-22 15:14:06 -0400314 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
315 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400316 {
317 return false;
318 }
319
Geoff Lang0d8b7242015-09-09 14:56:53 -0400320 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400321 {
322 return false;
323 }
324
Geoff Lang0d8b7242015-09-09 14:56:53 -0400325 if (CompressedTextureFormatRequiresExactSize(internalFormat))
326 {
327 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
328 width % formatInfo.compressedBlockWidth != 0) ||
329 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
330 height % formatInfo.compressedBlockHeight != 0))
331 {
332 return false;
333 }
334 }
335
Geoff Langd4f180b2013-09-24 13:57:44 -0400336 return true;
337}
338
Geoff Lang37dde692014-01-31 16:34:54 -0500339bool ValidQueryType(const Context *context, GLenum queryType)
340{
Geoff Langd4475812015-03-18 10:53:05 -0400341 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
342 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 -0500343
344 switch (queryType)
345 {
346 case GL_ANY_SAMPLES_PASSED:
347 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
348 return true;
349 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
350 return (context->getClientVersion() >= 3);
351 default:
352 return false;
353 }
354}
355
Dian Xiang769769a2015-09-09 15:20:08 -0700356Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500357{
358 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
359 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
360 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
361
Dian Xiang769769a2015-09-09 15:20:08 -0700362 Program *validProgram = context->getProgram(id);
363
364 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500365 {
Dian Xiang769769a2015-09-09 15:20:08 -0700366 if (context->getShader(id))
367 {
368 context->recordError(
369 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
370 }
371 else
372 {
373 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
374 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500375 }
Dian Xiang769769a2015-09-09 15:20:08 -0700376
377 return validProgram;
378}
379
380Shader *GetValidShader(Context *context, GLuint id)
381{
382 // See ValidProgram for spec details.
383
384 Shader *validShader = context->getShader(id);
385
386 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500387 {
Dian Xiang769769a2015-09-09 15:20:08 -0700388 if (context->getProgram(id))
389 {
390 context->recordError(
391 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
392 }
393 else
394 {
395 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
396 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500397 }
Dian Xiang769769a2015-09-09 15:20:08 -0700398
399 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500400}
401
Geoff Langb1196682014-07-23 13:47:29 -0400402bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400403{
404 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
405 {
406 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
407
Geoff Langaae65a42014-05-26 12:43:44 -0400408 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400409 {
Geoff Langb1196682014-07-23 13:47:29 -0400410 context->recordError(Error(GL_INVALID_VALUE));
411 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400412 }
413 }
414 else
415 {
416 switch (attachment)
417 {
418 case GL_DEPTH_ATTACHMENT:
419 case GL_STENCIL_ATTACHMENT:
420 break;
421
422 case GL_DEPTH_STENCIL_ATTACHMENT:
423 if (context->getClientVersion() < 3)
424 {
Geoff Langb1196682014-07-23 13:47:29 -0400425 context->recordError(Error(GL_INVALID_ENUM));
426 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400427 }
428 break;
429
430 default:
Geoff Langb1196682014-07-23 13:47:29 -0400431 context->recordError(Error(GL_INVALID_ENUM));
432 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400433 }
434 }
435
436 return true;
437}
438
Corentin Walleze0902642014-11-04 12:32:15 -0800439bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
440 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400441{
442 switch (target)
443 {
444 case GL_RENDERBUFFER:
445 break;
446 default:
Geoff Langb1196682014-07-23 13:47:29 -0400447 context->recordError(Error(GL_INVALID_ENUM));
448 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400449 }
450
451 if (width < 0 || height < 0 || samples < 0)
452 {
Geoff Langb1196682014-07-23 13:47:29 -0400453 context->recordError(Error(GL_INVALID_VALUE));
454 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400455 }
456
Geoff Langd87878e2014-09-19 15:42:59 -0400457 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
458 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400459 {
Geoff Langb1196682014-07-23 13:47:29 -0400460 context->recordError(Error(GL_INVALID_ENUM));
461 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400462 }
463
464 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
465 // 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 -0800466 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400467 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400468 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400469 {
Geoff Langb1196682014-07-23 13:47:29 -0400470 context->recordError(Error(GL_INVALID_ENUM));
471 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400472 }
473
Geoff Langaae65a42014-05-26 12:43:44 -0400474 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400475 {
Geoff Langb1196682014-07-23 13:47:29 -0400476 context->recordError(Error(GL_INVALID_VALUE));
477 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400478 }
479
Shannon Woods53a94a82014-06-24 15:20:36 -0400480 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400481 if (handle == 0)
482 {
Geoff Langb1196682014-07-23 13:47:29 -0400483 context->recordError(Error(GL_INVALID_OPERATION));
484 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400485 }
486
487 return true;
488}
489
Corentin Walleze0902642014-11-04 12:32:15 -0800490bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
491 GLenum internalformat, GLsizei width, GLsizei height)
492{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800493 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800494
495 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400496 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800497 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400498 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800499 {
500 context->recordError(Error(GL_INVALID_VALUE));
501 return false;
502 }
503
504 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
505 // the specified storage. This is different than ES 3.0 in which a sample number higher
506 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800507 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
508 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800509 {
Geoff Langa4903b72015-03-02 16:02:48 -0800510 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
511 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
512 {
513 context->recordError(Error(GL_OUT_OF_MEMORY));
514 return false;
515 }
Corentin Walleze0902642014-11-04 12:32:15 -0800516 }
517
518 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
519}
520
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500521bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
522 GLenum renderbuffertarget, GLuint renderbuffer)
523{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400524 if (!ValidFramebufferTarget(target))
525 {
Geoff Langb1196682014-07-23 13:47:29 -0400526 context->recordError(Error(GL_INVALID_ENUM));
527 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400528 }
529
Shannon Woods53a94a82014-06-24 15:20:36 -0400530 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500531
Jamie Madill84115c92015-04-23 15:00:07 -0400532 ASSERT(framebuffer);
533 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500534 {
Jamie Madill84115c92015-04-23 15:00:07 -0400535 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400536 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500537 }
538
Jamie Madillb4472272014-07-03 10:38:55 -0400539 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500540 {
Jamie Madillb4472272014-07-03 10:38:55 -0400541 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500542 }
543
Jamie Madillab9d82c2014-01-21 16:38:14 -0500544 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
545 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
546 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
547 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
548 if (renderbuffer != 0)
549 {
550 if (!context->getRenderbuffer(renderbuffer))
551 {
Geoff Langb1196682014-07-23 13:47:29 -0400552 context->recordError(Error(GL_INVALID_OPERATION));
553 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500554 }
555 }
556
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500557 return true;
558}
559
Jamie Madillc29968b2016-01-20 11:17:23 -0500560bool ValidateBlitFramebufferParameters(gl::Context *context,
561 GLint srcX0,
562 GLint srcY0,
563 GLint srcX1,
564 GLint srcY1,
565 GLint dstX0,
566 GLint dstY0,
567 GLint dstX1,
568 GLint dstY1,
569 GLbitfield mask,
570 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400571{
572 switch (filter)
573 {
574 case GL_NEAREST:
575 break;
576 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400577 break;
578 default:
Geoff Langb1196682014-07-23 13:47:29 -0400579 context->recordError(Error(GL_INVALID_ENUM));
580 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 }
582
583 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
584 {
Geoff Langb1196682014-07-23 13:47:29 -0400585 context->recordError(Error(GL_INVALID_VALUE));
586 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400587 }
588
589 if (mask == 0)
590 {
591 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
592 // buffers are copied.
593 return false;
594 }
595
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
597 // color buffer, leaving only nearest being unfiltered from above
598 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
599 {
Geoff Langb1196682014-07-23 13:47:29 -0400600 context->recordError(Error(GL_INVALID_OPERATION));
601 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400602 }
603
Shannon Woods53a94a82014-06-24 15:20:36 -0400604 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605 {
Geoff Langb1196682014-07-23 13:47:29 -0400606 context->recordError(Error(GL_INVALID_OPERATION));
607 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400608 }
609
Jamie Madille3ef7152015-04-28 16:55:17 +0000610 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
611 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500612
613 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400614 {
Geoff Langb1196682014-07-23 13:47:29 -0400615 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
616 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400617 }
618
Geoff Lang748f74e2014-12-01 11:25:34 -0500619 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500620 {
621 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
622 return false;
623 }
624
Geoff Lang748f74e2014-12-01 11:25:34 -0500625 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500626 {
627 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
628 return false;
629 }
630
631 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 {
Geoff Langb1196682014-07-23 13:47:29 -0400633 context->recordError(Error(GL_INVALID_OPERATION));
634 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635 }
636
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
638
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 if (mask & GL_COLOR_BUFFER_BIT)
640 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400641 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
642 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500643 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644
645 if (readColorBuffer && drawColorBuffer)
646 {
Geoff Langd8a22582014-12-17 15:28:23 -0500647 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400648 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649
Corentin Wallez37c39792015-08-20 14:19:46 -0400650 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 {
652 if (drawFramebuffer->isEnabledColorAttachment(i))
653 {
Geoff Langd8a22582014-12-17 15:28:23 -0500654 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400655 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656
Geoff Langb2f3d052013-08-13 12:49:27 -0400657 // The GL ES 3.0.2 spec (pg 193) states that:
658 // 1) If the read buffer is fixed point format, the draw buffer must be as well
659 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
660 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500661 // Changes with EXT_color_buffer_float:
662 // Case 1) is changed to fixed point OR floating point
663 GLenum readComponentType = readFormatInfo.componentType;
664 GLenum drawComponentType = drawFormatInfo.componentType;
665 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
666 readComponentType == GL_SIGNED_NORMALIZED);
667 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
668 drawComponentType == GL_SIGNED_NORMALIZED);
669
670 if (extensions.colorBufferFloat)
671 {
672 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
673 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
674
675 if (readFixedOrFloat != drawFixedOrFloat)
676 {
677 context->recordError(Error(GL_INVALID_OPERATION,
678 "If the read buffer contains fixed-point or "
679 "floating-point values, the draw buffer "
680 "must as well."));
681 return false;
682 }
683 }
684 else if (readFixedPoint != drawFixedPoint)
685 {
686 context->recordError(Error(GL_INVALID_OPERATION,
687 "If the read buffer contains fixed-point "
688 "values, the draw buffer must as well."));
689 return false;
690 }
691
692 if (readComponentType == GL_UNSIGNED_INT &&
693 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 {
Geoff Langb1196682014-07-23 13:47:29 -0400695 context->recordError(Error(GL_INVALID_OPERATION));
696 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 }
698
Jamie Madill6163c752015-12-07 16:32:59 -0500699 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700 {
Geoff Langb1196682014-07-23 13:47:29 -0400701 context->recordError(Error(GL_INVALID_OPERATION));
702 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 }
704
Geoff Langb2f3d052013-08-13 12:49:27 -0400705 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706 {
Geoff Langb1196682014-07-23 13:47:29 -0400707 context->recordError(Error(GL_INVALID_OPERATION));
708 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 }
710 }
711 }
712
Geoff Lang5d601382014-07-22 15:14:06 -0400713 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714 {
Geoff Langb1196682014-07-23 13:47:29 -0400715 context->recordError(Error(GL_INVALID_OPERATION));
716 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400717 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400718 }
719 }
720
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200721 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
722 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
723 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400724 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200725 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400726 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400727 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
728 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400729
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200730 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400731 {
Geoff Langd8a22582014-12-17 15:28:23 -0500732 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400733 {
Geoff Langb1196682014-07-23 13:47:29 -0400734 context->recordError(Error(GL_INVALID_OPERATION));
735 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400736 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400737
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200738 if (readBuffer->getSamples() > 0 && !sameBounds)
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 }
745 }
746
747 return true;
748}
749
Geoff Langb1196682014-07-23 13:47:29 -0400750bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751{
752 switch (pname)
753 {
754 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
755 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
756 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
757 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
758 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
759 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
760 case GL_CURRENT_VERTEX_ATTRIB:
761 return true;
762
763 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
764 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
765 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400766 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
767 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 return true;
769
770 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400771 if (context->getClientVersion() < 3)
772 {
773 context->recordError(Error(GL_INVALID_ENUM));
774 return false;
775 }
776 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777
778 default:
Geoff Langb1196682014-07-23 13:47:29 -0400779 context->recordError(Error(GL_INVALID_ENUM));
780 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781 }
782}
783
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400784bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785{
786 switch (pname)
787 {
788 case GL_TEXTURE_WRAP_R:
789 case GL_TEXTURE_SWIZZLE_R:
790 case GL_TEXTURE_SWIZZLE_G:
791 case GL_TEXTURE_SWIZZLE_B:
792 case GL_TEXTURE_SWIZZLE_A:
793 case GL_TEXTURE_BASE_LEVEL:
794 case GL_TEXTURE_MAX_LEVEL:
795 case GL_TEXTURE_COMPARE_MODE:
796 case GL_TEXTURE_COMPARE_FUNC:
797 case GL_TEXTURE_MIN_LOD:
798 case GL_TEXTURE_MAX_LOD:
799 if (context->getClientVersion() < 3)
800 {
Geoff Langb1196682014-07-23 13:47:29 -0400801 context->recordError(Error(GL_INVALID_ENUM));
802 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 }
804 break;
805
806 default: break;
807 }
808
809 switch (pname)
810 {
811 case GL_TEXTURE_WRAP_S:
812 case GL_TEXTURE_WRAP_T:
813 case GL_TEXTURE_WRAP_R:
814 switch (param)
815 {
816 case GL_REPEAT:
817 case GL_CLAMP_TO_EDGE:
818 case GL_MIRRORED_REPEAT:
819 return true;
820 default:
Geoff Langb1196682014-07-23 13:47:29 -0400821 context->recordError(Error(GL_INVALID_ENUM));
822 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400823 }
824
825 case GL_TEXTURE_MIN_FILTER:
826 switch (param)
827 {
828 case GL_NEAREST:
829 case GL_LINEAR:
830 case GL_NEAREST_MIPMAP_NEAREST:
831 case GL_LINEAR_MIPMAP_NEAREST:
832 case GL_NEAREST_MIPMAP_LINEAR:
833 case GL_LINEAR_MIPMAP_LINEAR:
834 return true;
835 default:
Geoff Langb1196682014-07-23 13:47:29 -0400836 context->recordError(Error(GL_INVALID_ENUM));
837 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838 }
839 break;
840
841 case GL_TEXTURE_MAG_FILTER:
842 switch (param)
843 {
844 case GL_NEAREST:
845 case GL_LINEAR:
846 return true;
847 default:
Geoff Langb1196682014-07-23 13:47:29 -0400848 context->recordError(Error(GL_INVALID_ENUM));
849 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400850 }
851 break;
852
853 case GL_TEXTURE_USAGE_ANGLE:
854 switch (param)
855 {
856 case GL_NONE:
857 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
858 return true;
859 default:
Geoff Langb1196682014-07-23 13:47:29 -0400860 context->recordError(Error(GL_INVALID_ENUM));
861 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400862 }
863 break;
864
865 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400866 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867 {
Geoff Langb1196682014-07-23 13:47:29 -0400868 context->recordError(Error(GL_INVALID_ENUM));
869 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400870 }
871
872 // we assume the parameter passed to this validation method is truncated, not rounded
873 if (param < 1)
874 {
Geoff Langb1196682014-07-23 13:47:29 -0400875 context->recordError(Error(GL_INVALID_VALUE));
876 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877 }
878 return true;
879
880 case GL_TEXTURE_MIN_LOD:
881 case GL_TEXTURE_MAX_LOD:
882 // any value is permissible
883 return true;
884
885 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400886 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 switch (param)
888 {
889 case GL_NONE:
890 case GL_COMPARE_REF_TO_TEXTURE:
891 return true;
892 default:
Geoff Langb1196682014-07-23 13:47:29 -0400893 context->recordError(Error(GL_INVALID_ENUM));
894 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 }
896 break;
897
898 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400899 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400900 switch (param)
901 {
902 case GL_LEQUAL:
903 case GL_GEQUAL:
904 case GL_LESS:
905 case GL_GREATER:
906 case GL_EQUAL:
907 case GL_NOTEQUAL:
908 case GL_ALWAYS:
909 case GL_NEVER:
910 return true;
911 default:
Geoff Langb1196682014-07-23 13:47:29 -0400912 context->recordError(Error(GL_INVALID_ENUM));
913 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400914 }
915 break;
916
917 case GL_TEXTURE_SWIZZLE_R:
918 case GL_TEXTURE_SWIZZLE_G:
919 case GL_TEXTURE_SWIZZLE_B:
920 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400921 switch (param)
922 {
923 case GL_RED:
924 case GL_GREEN:
925 case GL_BLUE:
926 case GL_ALPHA:
927 case GL_ZERO:
928 case GL_ONE:
929 return true;
930 default:
Geoff Langb1196682014-07-23 13:47:29 -0400931 context->recordError(Error(GL_INVALID_ENUM));
932 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400933 }
934 break;
935
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400936 case GL_TEXTURE_BASE_LEVEL:
937 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400938 if (param < 0)
939 {
Geoff Langb1196682014-07-23 13:47:29 -0400940 context->recordError(Error(GL_INVALID_VALUE));
941 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400942 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 return true;
944
945 default:
Geoff Langb1196682014-07-23 13:47:29 -0400946 context->recordError(Error(GL_INVALID_ENUM));
947 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400948 }
949}
950
Geoff Langb1196682014-07-23 13:47:29 -0400951bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952{
953 switch (pname)
954 {
955 case GL_TEXTURE_MIN_FILTER:
956 case GL_TEXTURE_MAG_FILTER:
957 case GL_TEXTURE_WRAP_S:
958 case GL_TEXTURE_WRAP_T:
959 case GL_TEXTURE_WRAP_R:
960 case GL_TEXTURE_MIN_LOD:
961 case GL_TEXTURE_MAX_LOD:
962 case GL_TEXTURE_COMPARE_MODE:
963 case GL_TEXTURE_COMPARE_FUNC:
964 return true;
965
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}
971
Jamie Madillc29968b2016-01-20 11:17:23 -0500972bool ValidateReadPixels(Context *context,
973 GLint x,
974 GLint y,
975 GLsizei width,
976 GLsizei height,
977 GLenum format,
978 GLenum type,
979 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -0500980{
Jamie Madillc29968b2016-01-20 11:17:23 -0500981 if (width < 0 || height < 0)
982 {
983 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
984 return false;
985 }
986
987 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400988 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500989
Geoff Lang748f74e2014-12-01 11:25:34 -0500990 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500991 {
Geoff Langb1196682014-07-23 13:47:29 -0400992 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
993 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500994 }
995
Jamie Madill48faf802014-11-06 15:27:22 -0500996 if (context->getState().getReadFramebuffer()->id() != 0 &&
997 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500998 {
Geoff Langb1196682014-07-23 13:47:29 -0400999 context->recordError(Error(GL_INVALID_OPERATION));
1000 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001001 }
1002
Geoff Langbce529e2014-12-01 12:48:41 -05001003 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1004 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001005 {
Geoff Langb1196682014-07-23 13:47:29 -04001006 context->recordError(Error(GL_INVALID_OPERATION));
1007 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001008 }
1009
Geoff Langbce529e2014-12-01 12:48:41 -05001010 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1011 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001012 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001013 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001014
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001015 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1016 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001017
1018 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1019 {
Geoff Langb1196682014-07-23 13:47:29 -04001020 context->recordError(Error(GL_INVALID_OPERATION));
1021 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001022 }
1023
Jamie Madillc29968b2016-01-20 11:17:23 -05001024 return true;
1025}
1026
1027bool ValidateReadnPixelsEXT(Context *context,
1028 GLint x,
1029 GLint y,
1030 GLsizei width,
1031 GLsizei height,
1032 GLenum format,
1033 GLenum type,
1034 GLsizei bufSize,
1035 GLvoid *pixels)
1036{
1037 if (bufSize < 0)
1038 {
1039 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1040 return false;
1041 }
1042
Geoff Lang5d601382014-07-22 15:14:06 -04001043 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1044 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001045
Minmin Gongadff67b2015-10-14 10:34:45 -04001046 GLsizei outputPitch =
1047 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1048 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001049 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001050 int requiredSize = outputPitch * height;
1051 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001052 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001053 context->recordError(Error(GL_INVALID_OPERATION));
1054 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001055 }
1056
Jamie Madillc29968b2016-01-20 11:17:23 -05001057 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001058}
1059
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001060bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1061{
1062 if (!ValidQueryType(context, target))
1063 {
Geoff Langb1196682014-07-23 13:47:29 -04001064 context->recordError(Error(GL_INVALID_ENUM));
1065 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001066 }
1067
1068 if (id == 0)
1069 {
Geoff Langb1196682014-07-23 13:47:29 -04001070 context->recordError(Error(GL_INVALID_OPERATION));
1071 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001072 }
1073
1074 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1075 // of zero, if the active query object name for <target> is non-zero (for the
1076 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1077 // the active query for either target is non-zero), if <id> is the name of an
1078 // existing query object whose type does not match <target>, or if <id> is the
1079 // active query object name for any query type, the error INVALID_OPERATION is
1080 // generated.
1081
1082 // Ensure no other queries are active
1083 // NOTE: If other queries than occlusion are supported, we will need to check
1084 // separately that:
1085 // a) The query ID passed is not the current active query for any target/type
1086 // b) There are no active queries for the requested target (and in the case
1087 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1088 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001089 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001090 {
Geoff Langb1196682014-07-23 13:47:29 -04001091 context->recordError(Error(GL_INVALID_OPERATION));
1092 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001093 }
1094
1095 Query *queryObject = context->getQuery(id, true, target);
1096
1097 // check that name was obtained with glGenQueries
1098 if (!queryObject)
1099 {
Geoff Langb1196682014-07-23 13:47:29 -04001100 context->recordError(Error(GL_INVALID_OPERATION));
1101 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001102 }
1103
1104 // check for type mismatch
1105 if (queryObject->getType() != target)
1106 {
Geoff Langb1196682014-07-23 13:47:29 -04001107 context->recordError(Error(GL_INVALID_OPERATION));
1108 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001109 }
1110
1111 return true;
1112}
1113
Jamie Madill45c785d2014-05-13 14:09:34 -04001114bool ValidateEndQuery(gl::Context *context, GLenum target)
1115{
1116 if (!ValidQueryType(context, target))
1117 {
Geoff Langb1196682014-07-23 13:47:29 -04001118 context->recordError(Error(GL_INVALID_ENUM));
1119 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001120 }
1121
Shannon Woods53a94a82014-06-24 15:20:36 -04001122 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001123
1124 if (queryObject == NULL)
1125 {
Geoff Langb1196682014-07-23 13:47:29 -04001126 context->recordError(Error(GL_INVALID_OPERATION));
1127 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001128 }
1129
Jamie Madill45c785d2014-05-13 14:09:34 -04001130 return true;
1131}
1132
Jamie Madill62d31cb2015-09-11 13:25:51 -04001133static bool ValidateUniformCommonBase(gl::Context *context,
1134 GLenum targetUniformType,
1135 GLint location,
1136 GLsizei count,
1137 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001138{
1139 if (count < 0)
1140 {
Geoff Langb1196682014-07-23 13:47:29 -04001141 context->recordError(Error(GL_INVALID_VALUE));
1142 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001143 }
1144
Geoff Lang7dd2e102014-11-10 15:19:26 -05001145 gl::Program *program = context->getState().getProgram();
1146 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001147 {
Geoff Langb1196682014-07-23 13:47:29 -04001148 context->recordError(Error(GL_INVALID_OPERATION));
1149 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001150 }
1151
1152 if (location == -1)
1153 {
1154 // Silently ignore the uniform command
1155 return false;
1156 }
1157
Geoff Lang7dd2e102014-11-10 15:19:26 -05001158 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001159 {
Geoff Langb1196682014-07-23 13:47:29 -04001160 context->recordError(Error(GL_INVALID_OPERATION));
1161 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001162 }
1163
Jamie Madill62d31cb2015-09-11 13:25:51 -04001164 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001165
1166 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001167 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001168 {
Geoff Langb1196682014-07-23 13:47:29 -04001169 context->recordError(Error(GL_INVALID_OPERATION));
1170 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001171 }
1172
Jamie Madill62d31cb2015-09-11 13:25:51 -04001173 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001174 return true;
1175}
1176
Jamie Madillaa981bd2014-05-20 10:55:55 -04001177bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1178{
1179 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001180 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001181 {
Geoff Langb1196682014-07-23 13:47:29 -04001182 context->recordError(Error(GL_INVALID_OPERATION));
1183 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001184 }
1185
Jamie Madill62d31cb2015-09-11 13:25:51 -04001186 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001187 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1188 {
1189 return false;
1190 }
1191
Jamie Madillf2575982014-06-25 16:04:54 -04001192 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001193 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001194 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1195 {
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
1200 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001201}
1202
1203bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1204 GLboolean transpose)
1205{
1206 // Check for ES3 uniform entry points
1207 int rows = VariableRowCount(matrixType);
1208 int cols = VariableColumnCount(matrixType);
1209 if (rows != cols && context->getClientVersion() < 3)
1210 {
Geoff Langb1196682014-07-23 13:47:29 -04001211 context->recordError(Error(GL_INVALID_OPERATION));
1212 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001213 }
1214
1215 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1216 {
Geoff Langb1196682014-07-23 13:47:29 -04001217 context->recordError(Error(GL_INVALID_VALUE));
1218 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001219 }
1220
Jamie Madill62d31cb2015-09-11 13:25:51 -04001221 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001222 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1223 {
1224 return false;
1225 }
1226
1227 if (uniform->type != matrixType)
1228 {
Geoff Langb1196682014-07-23 13:47:29 -04001229 context->recordError(Error(GL_INVALID_OPERATION));
1230 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001231 }
1232
1233 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001234}
1235
Jamie Madill893ab082014-05-16 16:56:10 -04001236bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1237{
1238 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1239 {
Geoff Langb1196682014-07-23 13:47:29 -04001240 context->recordError(Error(GL_INVALID_ENUM));
1241 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001242 }
1243
Jamie Madill0af26e12015-03-05 19:54:33 -05001244 const Caps &caps = context->getCaps();
1245
Jamie Madill893ab082014-05-16 16:56:10 -04001246 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1247 {
1248 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1249
Jamie Madill0af26e12015-03-05 19:54:33 -05001250 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001251 {
Geoff Langb1196682014-07-23 13:47:29 -04001252 context->recordError(Error(GL_INVALID_OPERATION));
1253 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001254 }
1255 }
1256
1257 switch (pname)
1258 {
1259 case GL_TEXTURE_BINDING_2D:
1260 case GL_TEXTURE_BINDING_CUBE_MAP:
1261 case GL_TEXTURE_BINDING_3D:
1262 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001263 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001264 {
Geoff Langb1196682014-07-23 13:47:29 -04001265 context->recordError(Error(GL_INVALID_OPERATION));
1266 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001267 }
1268 break;
1269
1270 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1271 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1272 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001273 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001274 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001275 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001276 {
Geoff Langb1196682014-07-23 13:47:29 -04001277 context->recordError(Error(GL_INVALID_OPERATION));
1278 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001279 }
1280
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001281 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001282 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001283 {
Geoff Langb1196682014-07-23 13:47:29 -04001284 context->recordError(Error(GL_INVALID_OPERATION));
1285 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001286 }
1287 }
1288 break;
1289
1290 default:
1291 break;
1292 }
1293
1294 // pname is valid, but there are no parameters to return
1295 if (numParams == 0)
1296 {
1297 return false;
1298 }
1299
1300 return true;
1301}
1302
Jamie Madillc29968b2016-01-20 11:17:23 -05001303bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1304 GLenum target,
1305 GLint level,
1306 GLenum internalformat,
1307 bool isSubImage,
1308 GLint xoffset,
1309 GLint yoffset,
1310 GLint zoffset,
1311 GLint x,
1312 GLint y,
1313 GLsizei width,
1314 GLsizei height,
1315 GLint border,
1316 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001317{
1318
1319 if (!ValidTexture2DDestinationTarget(context, target))
1320 {
Geoff Langb1196682014-07-23 13:47:29 -04001321 context->recordError(Error(GL_INVALID_ENUM));
1322 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001323 }
1324
1325 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1326 {
Geoff Langb1196682014-07-23 13:47:29 -04001327 context->recordError(Error(GL_INVALID_VALUE));
1328 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001329 }
1330
1331 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1332 {
Geoff Langb1196682014-07-23 13:47:29 -04001333 context->recordError(Error(GL_INVALID_VALUE));
1334 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001335 }
1336
1337 if (border != 0)
1338 {
Geoff Langb1196682014-07-23 13:47:29 -04001339 context->recordError(Error(GL_INVALID_VALUE));
1340 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001341 }
1342
1343 if (!ValidMipLevel(context, target, level))
1344 {
Geoff Langb1196682014-07-23 13:47:29 -04001345 context->recordError(Error(GL_INVALID_VALUE));
1346 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001347 }
1348
Jamie Madillc29968b2016-01-20 11:17:23 -05001349 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001350 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001351 {
Geoff Langb1196682014-07-23 13:47:29 -04001352 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1353 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001354 }
1355
Jamie Madillc29968b2016-01-20 11:17:23 -05001356 const auto &state = context->getState();
1357 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001358 {
Geoff Langb1196682014-07-23 13:47:29 -04001359 context->recordError(Error(GL_INVALID_OPERATION));
1360 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001361 }
1362
Geoff Langaae65a42014-05-26 12:43:44 -04001363 const gl::Caps &caps = context->getCaps();
1364
Geoff Langaae65a42014-05-26 12:43:44 -04001365 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001366 switch (target)
1367 {
1368 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001369 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 break;
1371
1372 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1373 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1374 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1375 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1376 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1377 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001378 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001379 break;
1380
1381 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001382 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001383 break;
1384
1385 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001386 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001387 break;
1388
1389 default:
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_ENUM));
1391 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001392 }
1393
Jamie Madillc29968b2016-01-20 11:17:23 -05001394 gl::Texture *texture =
1395 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001396 if (!texture)
1397 {
Geoff Langb1196682014-07-23 13:47:29 -04001398 context->recordError(Error(GL_INVALID_OPERATION));
1399 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001400 }
1401
Geoff Lang69cce582015-09-17 13:20:36 -04001402 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001403 {
Geoff Langb1196682014-07-23 13:47:29 -04001404 context->recordError(Error(GL_INVALID_OPERATION));
1405 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001406 }
1407
Geoff Lang5d601382014-07-22 15:14:06 -04001408 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1409
1410 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001411 {
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 Langa9be0dc2014-12-17 12:34:40 -05001416 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001417 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001418 context->recordError(Error(GL_INVALID_OPERATION));
1419 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001420 }
1421
1422 if (isSubImage)
1423 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001424 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1425 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1426 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001427 {
Geoff Langb1196682014-07-23 13:47:29 -04001428 context->recordError(Error(GL_INVALID_VALUE));
1429 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001430 }
1431 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001432 else
1433 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001434 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001435 {
Geoff Langb1196682014-07-23 13:47:29 -04001436 context->recordError(Error(GL_INVALID_VALUE));
1437 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001438 }
1439
Geoff Lang5d601382014-07-22 15:14:06 -04001440 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001441 {
Geoff Langb1196682014-07-23 13:47:29 -04001442 context->recordError(Error(GL_INVALID_ENUM));
1443 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001444 }
1445
1446 int maxLevelDimension = (maxDimension >> level);
1447 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1448 {
Geoff Langb1196682014-07-23 13:47:29 -04001449 context->recordError(Error(GL_INVALID_VALUE));
1450 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001451 }
1452 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001453
Geoff Langa9be0dc2014-12-17 12:34:40 -05001454 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001455 return true;
1456}
1457
Jamie Madillf25855c2015-11-03 11:06:18 -05001458static bool ValidateDrawBase(ValidationContext *context,
1459 GLenum mode,
1460 GLsizei count,
1461 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001462{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001463 switch (mode)
1464 {
1465 case GL_POINTS:
1466 case GL_LINES:
1467 case GL_LINE_LOOP:
1468 case GL_LINE_STRIP:
1469 case GL_TRIANGLES:
1470 case GL_TRIANGLE_STRIP:
1471 case GL_TRIANGLE_FAN:
1472 break;
1473 default:
Geoff Langb1196682014-07-23 13:47:29 -04001474 context->recordError(Error(GL_INVALID_ENUM));
1475 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001476 }
1477
Jamie Madill250d33f2014-06-06 17:09:03 -04001478 if (count < 0)
1479 {
Geoff Langb1196682014-07-23 13:47:29 -04001480 context->recordError(Error(GL_INVALID_VALUE));
1481 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001482 }
1483
Geoff Langb1196682014-07-23 13:47:29 -04001484 const State &state = context->getState();
1485
Jamie Madill250d33f2014-06-06 17:09:03 -04001486 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001487 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001488 {
Geoff Langb1196682014-07-23 13:47:29 -04001489 context->recordError(Error(GL_INVALID_OPERATION));
1490 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001491 }
1492
Geoff Lang3a86ad32015-09-01 11:47:05 -04001493 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001494 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001495 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1496 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1497 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1498 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1499 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1500 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1501 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001502 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001503 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1504 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001505 {
1506 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1507 // Section 6.10 of the WebGL 1.0 spec
1508 ERR(
1509 "This ANGLE implementation does not support separate front/back stencil "
1510 "writemasks, reference values, or stencil mask values.");
1511 context->recordError(Error(GL_INVALID_OPERATION));
1512 return false;
1513 }
Jamie Madillac528012014-06-20 13:21:23 -04001514 }
1515
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001516 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001517 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001518 {
Geoff Langb1196682014-07-23 13:47:29 -04001519 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1520 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001521 }
1522
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523 gl::Program *program = state.getProgram();
1524 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001525 {
Geoff Langb1196682014-07-23 13:47:29 -04001526 context->recordError(Error(GL_INVALID_OPERATION));
1527 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001528 }
1529
Geoff Lang7dd2e102014-11-10 15:19:26 -05001530 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001531 {
Geoff Langb1196682014-07-23 13:47:29 -04001532 context->recordError(Error(GL_INVALID_OPERATION));
1533 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001534 }
1535
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001536 // Uniform buffer validation
1537 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1538 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001539 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001540 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001541 const OffsetBindingPointer<Buffer> &uniformBuffer =
1542 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001543
Geoff Lang5d124a62015-09-15 13:03:27 -04001544 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001545 {
1546 // undefined behaviour
1547 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1548 return false;
1549 }
1550
Geoff Lang5d124a62015-09-15 13:03:27 -04001551 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001552 if (uniformBufferSize == 0)
1553 {
1554 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001555 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001556 }
1557
Jamie Madill62d31cb2015-09-11 13:25:51 -04001558 if (uniformBufferSize < uniformBlock.dataSize)
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 use a uniform buffer that is too small."));
1562 return false;
1563 }
1564 }
1565
Jamie Madill250d33f2014-06-06 17:09:03 -04001566 // No-op if zero count
1567 return (count > 0);
1568}
1569
Geoff Langb1196682014-07-23 13:47:29 -04001570bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001571{
Jamie Madillfd716582014-06-06 17:09:04 -04001572 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001573 {
Geoff Langb1196682014-07-23 13:47:29 -04001574 context->recordError(Error(GL_INVALID_VALUE));
1575 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001576 }
1577
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001578 const State &state = context->getState();
1579 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001580 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1581 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001582 {
1583 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1584 // that does not match the current transform feedback object's draw mode (if transform feedback
1585 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001586 context->recordError(Error(GL_INVALID_OPERATION));
1587 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001588 }
1589
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001590 if (!ValidateDrawBase(context, mode, count, primcount))
1591 {
1592 return false;
1593 }
1594
1595 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001596 {
1597 return false;
1598 }
1599
1600 return true;
1601}
1602
Geoff Langb1196682014-07-23 13:47:29 -04001603bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001604{
1605 if (primcount < 0)
1606 {
Geoff Langb1196682014-07-23 13:47:29 -04001607 context->recordError(Error(GL_INVALID_VALUE));
1608 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001609 }
1610
Jamie Madill2b976812014-08-25 15:47:49 -04001611 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001612 {
1613 return false;
1614 }
1615
1616 // No-op if zero primitive count
1617 return (primcount > 0);
1618}
1619
Geoff Lang87a93302014-09-16 13:29:43 -04001620static bool ValidateDrawInstancedANGLE(Context *context)
1621{
1622 // Verify there is at least one active attribute with a divisor of zero
1623 const gl::State& state = context->getState();
1624
Geoff Lang7dd2e102014-11-10 15:19:26 -05001625 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001626
1627 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001628 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001629 {
1630 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001631 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001632 {
1633 return true;
1634 }
1635 }
1636
1637 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1638 "has a divisor of zero."));
1639 return false;
1640}
1641
1642bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1643{
1644 if (!ValidateDrawInstancedANGLE(context))
1645 {
1646 return false;
1647 }
1648
1649 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1650}
1651
Jamie Madillf25855c2015-11-03 11:06:18 -05001652bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001653 GLenum mode,
1654 GLsizei count,
1655 GLenum type,
1656 const GLvoid *indices,
1657 GLsizei primcount,
1658 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001659{
Jamie Madill250d33f2014-06-06 17:09:03 -04001660 switch (type)
1661 {
1662 case GL_UNSIGNED_BYTE:
1663 case GL_UNSIGNED_SHORT:
1664 break;
1665 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001666 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001667 {
Geoff Langb1196682014-07-23 13:47:29 -04001668 context->recordError(Error(GL_INVALID_ENUM));
1669 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001670 }
1671 break;
1672 default:
Geoff Langb1196682014-07-23 13:47:29 -04001673 context->recordError(Error(GL_INVALID_ENUM));
1674 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001675 }
1676
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001677 const State &state = context->getState();
1678
1679 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001680 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001681 {
1682 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1683 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001684 context->recordError(Error(GL_INVALID_OPERATION));
1685 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001686 }
1687
1688 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001689 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001690 {
Geoff Langb1196682014-07-23 13:47:29 -04001691 context->recordError(Error(GL_INVALID_OPERATION));
1692 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001693 }
1694
Jamie Madill2b976812014-08-25 15:47:49 -04001695 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001696 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001697 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001698 {
Geoff Langb1196682014-07-23 13:47:29 -04001699 context->recordError(Error(GL_INVALID_OPERATION));
1700 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001701 }
1702
Jamie Madillae3000b2014-08-25 15:47:51 -04001703 if (elementArrayBuffer)
1704 {
1705 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1706
1707 GLint64 offset = reinterpret_cast<GLint64>(indices);
1708 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1709
1710 // check for integer overflows
1711 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1712 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1713 {
Geoff Langb1196682014-07-23 13:47:29 -04001714 context->recordError(Error(GL_OUT_OF_MEMORY));
1715 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001716 }
1717
1718 // Check for reading past the end of the bound buffer object
1719 if (byteCount > elementArrayBuffer->getSize())
1720 {
Geoff Langb1196682014-07-23 13:47:29 -04001721 context->recordError(Error(GL_INVALID_OPERATION));
1722 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001723 }
1724 }
1725 else if (!indices)
1726 {
1727 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001728 context->recordError(Error(GL_INVALID_OPERATION));
1729 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001730 }
1731
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001732 if (!ValidateDrawBase(context, mode, count, primcount))
1733 {
1734 return false;
1735 }
1736
Jamie Madill2b976812014-08-25 15:47:49 -04001737 // Use max index to validate if our vertex buffers are large enough for the pull.
1738 // TODO: offer fast path, with disabled index validation.
1739 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1740 if (elementArrayBuffer)
1741 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001742 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001743 Error error =
1744 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1745 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001746 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001747 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001748 context->recordError(error);
1749 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001750 }
1751 }
1752 else
1753 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001754 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001755 }
1756
Jamie Madille79b1e12015-11-04 16:36:37 -05001757 // If we use an index greater than our maximum supported index range, return an error.
1758 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1759 // return an error if possible here.
1760 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1761 {
1762 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1763 return false;
1764 }
1765
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001766 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001767 {
1768 return false;
1769 }
1770
Geoff Lang3edfe032015-09-04 16:38:24 -04001771 // No op if there are no real indices in the index data (all are primitive restart).
1772 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001773}
1774
Geoff Langb1196682014-07-23 13:47:29 -04001775bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001776 GLenum mode,
1777 GLsizei count,
1778 GLenum type,
1779 const GLvoid *indices,
1780 GLsizei primcount,
1781 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001782{
1783 if (primcount < 0)
1784 {
Geoff Langb1196682014-07-23 13:47:29 -04001785 context->recordError(Error(GL_INVALID_VALUE));
1786 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001787 }
1788
Jamie Madill2b976812014-08-25 15:47:49 -04001789 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001790 {
1791 return false;
1792 }
1793
1794 // No-op zero primitive count
1795 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001796}
1797
Geoff Lang3edfe032015-09-04 16:38:24 -04001798bool ValidateDrawElementsInstancedANGLE(Context *context,
1799 GLenum mode,
1800 GLsizei count,
1801 GLenum type,
1802 const GLvoid *indices,
1803 GLsizei primcount,
1804 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001805{
1806 if (!ValidateDrawInstancedANGLE(context))
1807 {
1808 return false;
1809 }
1810
1811 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1812}
1813
Geoff Langb1196682014-07-23 13:47:29 -04001814bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001815 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001816{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001817 if (!ValidFramebufferTarget(target))
1818 {
Geoff Langb1196682014-07-23 13:47:29 -04001819 context->recordError(Error(GL_INVALID_ENUM));
1820 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001821 }
1822
1823 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001824 {
1825 return false;
1826 }
1827
Jamie Madill55ec3b12014-07-03 10:38:57 -04001828 if (texture != 0)
1829 {
1830 gl::Texture *tex = context->getTexture(texture);
1831
1832 if (tex == NULL)
1833 {
Geoff Langb1196682014-07-23 13:47:29 -04001834 context->recordError(Error(GL_INVALID_OPERATION));
1835 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001836 }
1837
1838 if (level < 0)
1839 {
Geoff Langb1196682014-07-23 13:47:29 -04001840 context->recordError(Error(GL_INVALID_VALUE));
1841 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001842 }
1843 }
1844
Shannon Woods53a94a82014-06-24 15:20:36 -04001845 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001846 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001847
Jamie Madill84115c92015-04-23 15:00:07 -04001848 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001849 {
Jamie Madill84115c92015-04-23 15:00:07 -04001850 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001851 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001852 }
1853
1854 return true;
1855}
1856
Geoff Langb1196682014-07-23 13:47:29 -04001857bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001858 GLenum textarget, GLuint texture, GLint level)
1859{
Geoff Lang95663912015-04-02 15:54:45 -04001860 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1861 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001862 {
Geoff Langb1196682014-07-23 13:47:29 -04001863 context->recordError(Error(GL_INVALID_VALUE));
1864 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001865 }
1866
1867 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001868 {
1869 return false;
1870 }
1871
Jamie Madill55ec3b12014-07-03 10:38:57 -04001872 if (texture != 0)
1873 {
1874 gl::Texture *tex = context->getTexture(texture);
1875 ASSERT(tex);
1876
Jamie Madill2a6564e2014-07-11 09:53:19 -04001877 const gl::Caps &caps = context->getCaps();
1878
Jamie Madill55ec3b12014-07-03 10:38:57 -04001879 switch (textarget)
1880 {
1881 case GL_TEXTURE_2D:
1882 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001883 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001884 {
Geoff Langb1196682014-07-23 13:47:29 -04001885 context->recordError(Error(GL_INVALID_VALUE));
1886 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001887 }
1888 if (tex->getTarget() != GL_TEXTURE_2D)
1889 {
Geoff Langb1196682014-07-23 13:47:29 -04001890 context->recordError(Error(GL_INVALID_OPERATION));
1891 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001892 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001893 }
1894 break;
1895
1896 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1897 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1898 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1899 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1900 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1901 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1902 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001903 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001904 {
Geoff Langb1196682014-07-23 13:47:29 -04001905 context->recordError(Error(GL_INVALID_VALUE));
1906 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001907 }
1908 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1909 {
Geoff Langb1196682014-07-23 13:47:29 -04001910 context->recordError(Error(GL_INVALID_OPERATION));
1911 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001912 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001913 }
1914 break;
1915
1916 default:
Geoff Langb1196682014-07-23 13:47:29 -04001917 context->recordError(Error(GL_INVALID_ENUM));
1918 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001919 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001920
1921 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1922 if (internalFormatInfo.compressed)
1923 {
1924 context->recordError(Error(GL_INVALID_OPERATION));
1925 return false;
1926 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001927 }
1928
Jamie Madill570f7c82014-07-03 10:38:54 -04001929 return true;
1930}
1931
Geoff Langb1196682014-07-23 13:47:29 -04001932bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001933{
1934 if (program == 0)
1935 {
Geoff Langb1196682014-07-23 13:47:29 -04001936 context->recordError(Error(GL_INVALID_VALUE));
1937 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001938 }
1939
Dian Xiang769769a2015-09-09 15:20:08 -07001940 gl::Program *programObject = GetValidProgram(context, program);
1941 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001942 {
1943 return false;
1944 }
1945
Jamie Madill0063c512014-08-25 15:47:53 -04001946 if (!programObject || !programObject->isLinked())
1947 {
Geoff Langb1196682014-07-23 13:47:29 -04001948 context->recordError(Error(GL_INVALID_OPERATION));
1949 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001950 }
1951
Geoff Lang7dd2e102014-11-10 15:19:26 -05001952 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001953 {
Geoff Langb1196682014-07-23 13:47:29 -04001954 context->recordError(Error(GL_INVALID_OPERATION));
1955 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001956 }
1957
Jamie Madill0063c512014-08-25 15:47:53 -04001958 return true;
1959}
1960
Geoff Langb1196682014-07-23 13:47:29 -04001961bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001962{
1963 return ValidateGetUniformBase(context, program, location);
1964}
1965
Geoff Langb1196682014-07-23 13:47:29 -04001966bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001967{
Jamie Madill78f41802014-08-25 15:47:55 -04001968 return ValidateGetUniformBase(context, program, location);
1969}
1970
Geoff Langb1196682014-07-23 13:47:29 -04001971static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001972{
1973 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001974 {
Jamie Madill78f41802014-08-25 15:47:55 -04001975 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001976 }
1977
Jamie Madilla502c742014-08-28 17:19:13 -04001978 gl::Program *programObject = context->getProgram(program);
1979 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001980
Jamie Madill78f41802014-08-25 15:47:55 -04001981 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04001982 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
1983 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04001984 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001985 {
Geoff Langb1196682014-07-23 13:47:29 -04001986 context->recordError(Error(GL_INVALID_OPERATION));
1987 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001988 }
1989
1990 return true;
1991}
1992
Geoff Langb1196682014-07-23 13:47:29 -04001993bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001994{
Jamie Madill78f41802014-08-25 15:47:55 -04001995 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001996}
1997
Geoff Langb1196682014-07-23 13:47:29 -04001998bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001999{
Jamie Madill78f41802014-08-25 15:47:55 -04002000 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002001}
2002
Austin Kinross08332632015-05-05 13:35:47 -07002003bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2004 const GLenum *attachments, bool defaultFramebuffer)
2005{
2006 if (numAttachments < 0)
2007 {
2008 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2009 return false;
2010 }
2011
2012 for (GLsizei i = 0; i < numAttachments; ++i)
2013 {
2014 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2015 {
2016 if (defaultFramebuffer)
2017 {
2018 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2019 return false;
2020 }
2021
2022 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2023 {
2024 context->recordError(Error(GL_INVALID_OPERATION,
2025 "Requested color attachment is greater than the maximum supported color attachments"));
2026 return false;
2027 }
2028 }
2029 else
2030 {
2031 switch (attachments[i])
2032 {
2033 case GL_DEPTH_ATTACHMENT:
2034 case GL_STENCIL_ATTACHMENT:
2035 case GL_DEPTH_STENCIL_ATTACHMENT:
2036 if (defaultFramebuffer)
2037 {
2038 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2039 return false;
2040 }
2041 break;
2042 case GL_COLOR:
2043 case GL_DEPTH:
2044 case GL_STENCIL:
2045 if (!defaultFramebuffer)
2046 {
2047 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2048 return false;
2049 }
2050 break;
2051 default:
2052 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2053 return false;
2054 }
2055 }
2056 }
2057
2058 return true;
2059}
2060
Austin Kinross6ee1e782015-05-29 17:05:37 -07002061bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2062{
2063 // Note that debug marker calls must not set error state
2064
2065 if (length < 0)
2066 {
2067 return false;
2068 }
2069
2070 if (marker == nullptr)
2071 {
2072 return false;
2073 }
2074
2075 return true;
2076}
2077
2078bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2079{
2080 // Note that debug marker calls must not set error state
2081
2082 if (length < 0)
2083 {
2084 return false;
2085 }
2086
2087 if (length > 0 && marker == nullptr)
2088 {
2089 return false;
2090 }
2091
2092 return true;
2093}
2094
Geoff Langdcab33b2015-07-21 13:03:16 -04002095bool ValidateEGLImageTargetTexture2DOES(Context *context,
2096 egl::Display *display,
2097 GLenum target,
2098 egl::Image *image)
2099{
Geoff Langa8406172015-07-21 16:53:39 -04002100 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2101 {
2102 context->recordError(Error(GL_INVALID_OPERATION));
2103 return false;
2104 }
2105
2106 switch (target)
2107 {
2108 case GL_TEXTURE_2D:
2109 break;
2110
2111 default:
2112 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2113 return false;
2114 }
2115
2116 if (!display->isValidImage(image))
2117 {
2118 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2119 return false;
2120 }
2121
2122 if (image->getSamples() > 0)
2123 {
2124 context->recordError(Error(GL_INVALID_OPERATION,
2125 "cannot create a 2D texture from a multisampled EGL image."));
2126 return false;
2127 }
2128
2129 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2130 if (!textureCaps.texturable)
2131 {
2132 context->recordError(Error(GL_INVALID_OPERATION,
2133 "EGL image internal format is not supported as a texture."));
2134 return false;
2135 }
2136
Geoff Langdcab33b2015-07-21 13:03:16 -04002137 return true;
2138}
2139
2140bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2141 egl::Display *display,
2142 GLenum target,
2143 egl::Image *image)
2144{
Geoff Langa8406172015-07-21 16:53:39 -04002145 if (!context->getExtensions().eglImage)
2146 {
2147 context->recordError(Error(GL_INVALID_OPERATION));
2148 return false;
2149 }
2150
2151 switch (target)
2152 {
2153 case GL_RENDERBUFFER:
2154 break;
2155
2156 default:
2157 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2158 return false;
2159 }
2160
2161 if (!display->isValidImage(image))
2162 {
2163 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2164 return false;
2165 }
2166
2167 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2168 if (!textureCaps.renderable)
2169 {
2170 context->recordError(Error(
2171 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2172 return false;
2173 }
2174
Geoff Langdcab33b2015-07-21 13:03:16 -04002175 return true;
2176}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002177
2178bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2179{
Geoff Lang36167ab2015-12-07 10:27:14 -05002180 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002181 {
2182 // The default VAO should always exist
2183 ASSERT(array != 0);
2184 context->recordError(Error(GL_INVALID_OPERATION));
2185 return false;
2186 }
2187
2188 return true;
2189}
2190
2191bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2192{
2193 if (n < 0)
2194 {
2195 context->recordError(Error(GL_INVALID_VALUE));
2196 return false;
2197 }
2198
2199 return true;
2200}
2201
2202bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2203{
2204 if (n < 0)
2205 {
2206 context->recordError(Error(GL_INVALID_VALUE));
2207 return false;
2208 }
2209
2210 return true;
2211}
Geoff Langc5629752015-12-07 16:29:04 -05002212
2213bool ValidateProgramBinaryBase(Context *context,
2214 GLuint program,
2215 GLenum binaryFormat,
2216 const void *binary,
2217 GLint length)
2218{
2219 Program *programObject = GetValidProgram(context, program);
2220 if (programObject == nullptr)
2221 {
2222 return false;
2223 }
2224
2225 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2226 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2227 programBinaryFormats.end())
2228 {
2229 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2230 return false;
2231 }
2232
2233 return true;
2234}
2235
2236bool ValidateGetProgramBinaryBase(Context *context,
2237 GLuint program,
2238 GLsizei bufSize,
2239 GLsizei *length,
2240 GLenum *binaryFormat,
2241 void *binary)
2242{
2243 Program *programObject = GetValidProgram(context, program);
2244 if (programObject == nullptr)
2245 {
2246 return false;
2247 }
2248
2249 if (!programObject->isLinked())
2250 {
2251 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2252 return false;
2253 }
2254
2255 return true;
2256}
Jamie Madillc29968b2016-01-20 11:17:23 -05002257
2258bool ValidateCopyTexImage2D(ValidationContext *context,
2259 GLenum target,
2260 GLint level,
2261 GLenum internalformat,
2262 GLint x,
2263 GLint y,
2264 GLsizei width,
2265 GLsizei height,
2266 GLint border)
2267{
2268 if (context->getClientVersion() < 3)
2269 {
2270 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2271 0, x, y, width, height, border);
2272 }
2273
2274 ASSERT(context->getClientVersion() == 3);
2275 return ValidateES3CopyTexImageParameters(context, target, level, internalformat, false, 0, 0, 0,
2276 x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002277}
Jamie Madillc29968b2016-01-20 11:17:23 -05002278
2279bool ValidateFramebufferRenderbuffer(Context *context,
2280 GLenum target,
2281 GLenum attachment,
2282 GLenum renderbuffertarget,
2283 GLuint renderbuffer)
2284{
2285 if (!ValidFramebufferTarget(target) ||
2286 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2287 {
2288 context->recordError(Error(GL_INVALID_ENUM));
2289 return false;
2290 }
2291
2292 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2293 renderbuffertarget, renderbuffer);
2294}
2295
2296bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2297{
2298 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2299 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2300 {
2301 context->recordError(
2302 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2303 return false;
2304 }
2305
2306 ASSERT(context->getState().getDrawFramebuffer());
2307 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2308 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2309
2310 // This should come first before the check for the default frame buffer
2311 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2312 // rather than INVALID_OPERATION
2313 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2314 {
2315 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2316
2317 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
2318 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
2319 bufs[colorAttachment] >= maxColorAttachment))
2320 {
2321 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
2322 // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
2323 // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
2324 context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
2325 return false;
2326 }
2327 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2328 frameBufferId != 0)
2329 {
2330 // INVALID_OPERATION-GL is bound to buffer and ith argument
2331 // is not COLOR_ATTACHMENTi or NONE
2332 context->recordError(
2333 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2334 return false;
2335 }
2336 }
2337
2338 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2339 // and n is not 1 or bufs is bound to value other than BACK and NONE
2340 if (frameBufferId == 0)
2341 {
2342 if (n != 1)
2343 {
2344 context->recordError(Error(GL_INVALID_OPERATION,
2345 "n must be 1 when GL is bound to the default framebuffer"));
2346 return false;
2347 }
2348
2349 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2350 {
2351 context->recordError(Error(
2352 GL_INVALID_OPERATION,
2353 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2354 return false;
2355 }
2356 }
2357
2358 return true;
2359}
2360
2361bool ValidateCopyTexSubImage2D(Context *context,
2362 GLenum target,
2363 GLint level,
2364 GLint xoffset,
2365 GLint yoffset,
2366 GLint x,
2367 GLint y,
2368 GLsizei width,
2369 GLsizei height)
2370{
2371 if (context->getClientVersion() < 3)
2372 {
2373 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2374 yoffset, x, y, width, height, 0);
2375 }
2376
2377 return ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2378 yoffset, 0, x, y, width, height, 0);
2379}
2380
2381} // namespace gl