blob: 745f342b8a2e45dee1744a3012f0b71976bc3fdc [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
114 case GL_RASTERIZER_DISCARD:
115 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500116
117 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
118 case GL_DEBUG_OUTPUT:
119 return context->getExtensions().debug;
120
Geoff Lang0550d032014-01-30 11:29:07 -0500121 default:
122 return false;
123 }
124}
125
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500126bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400127{
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400129 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500130 case GL_TEXTURE_2D:
131 case GL_TEXTURE_CUBE_MAP:
132 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400133
Jamie Madilld7460c72014-01-21 16:38:14 -0500134 case GL_TEXTURE_3D:
135 case GL_TEXTURE_2D_ARRAY:
136 return (context->getClientVersion() >= 3);
137
138 default:
139 return false;
140 }
Jamie Madill35d15012013-10-07 10:46:37 -0400141}
142
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500143bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
144{
145 switch (target)
146 {
147 case GL_TEXTURE_2D:
148 case GL_TEXTURE_CUBE_MAP:
149 return true;
150
151 default:
152 return false;
153 }
154}
155
156bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
157{
158 switch (target)
159 {
160 case GL_TEXTURE_3D:
161 case GL_TEXTURE_2D_ARRAY:
162 return (context->getClientVersion() >= 3);
163
164 default:
165 return false;
166 }
167}
168
Shannon Woods4dfed832014-03-17 20:03:39 -0400169// This function differs from ValidTextureTarget in that the target must be
170// usable as the destination of a 2D operation-- so a cube face is valid, but
171// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400172// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500173bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400174{
175 switch (target)
176 {
177 case GL_TEXTURE_2D:
178 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
179 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
180 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
181 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
182 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
183 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
184 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500185 default:
186 return false;
187 }
188}
189
190bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
191{
192 switch (target)
193 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400194 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500195 case GL_TEXTURE_2D_ARRAY:
196 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400197 default:
198 return false;
199 }
200}
201
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500202bool ValidFramebufferTarget(GLenum target)
203{
Geoff Langd4475812015-03-18 10:53:05 -0400204 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
205 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500206
207 switch (target)
208 {
209 case GL_FRAMEBUFFER: return true;
210 case GL_READ_FRAMEBUFFER: return true;
211 case GL_DRAW_FRAMEBUFFER: return true;
212 default: return false;
213 }
214}
215
Jamie Madill8c96d582014-03-05 15:01:23 -0500216bool ValidBufferTarget(const Context *context, GLenum target)
217{
218 switch (target)
219 {
220 case GL_ARRAY_BUFFER:
221 case GL_ELEMENT_ARRAY_BUFFER:
222 return true;
223
Jamie Madill8c96d582014-03-05 15:01:23 -0500224 case GL_PIXEL_PACK_BUFFER:
225 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400226 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400227
Shannon Woodsb3801742014-03-27 14:59:19 -0400228 case GL_COPY_READ_BUFFER:
229 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500230 case GL_TRANSFORM_FEEDBACK_BUFFER:
231 case GL_UNIFORM_BUFFER:
232 return (context->getClientVersion() >= 3);
233
234 default:
235 return false;
236 }
237}
238
Jamie Madill70656a62014-03-05 15:01:26 -0500239bool ValidBufferParameter(const Context *context, GLenum pname)
240{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400241 const Extensions &extensions = context->getExtensions();
242
Jamie Madill70656a62014-03-05 15:01:26 -0500243 switch (pname)
244 {
245 case GL_BUFFER_USAGE:
246 case GL_BUFFER_SIZE:
247 return true;
248
Geoff Langcc6f55d2015-03-20 13:01:02 -0400249 case GL_BUFFER_ACCESS_OES:
250 return extensions.mapBuffer;
251
252 case GL_BUFFER_MAPPED:
253 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
254 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
255
Jamie Madill70656a62014-03-05 15:01:26 -0500256 // GL_BUFFER_MAP_POINTER is a special case, and may only be
257 // queried with GetBufferPointerv
258 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500259 case GL_BUFFER_MAP_OFFSET:
260 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400261 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500262
263 default:
264 return false;
265 }
266}
267
Jamie Madillc29968b2016-01-20 11:17:23 -0500268bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400269{
Jamie Madillc29968b2016-01-20 11:17:23 -0500270 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400271 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400272 switch (target)
273 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500274 case GL_TEXTURE_2D:
275 maxDimension = caps.max2DTextureSize;
276 break;
Geoff Langce635692013-09-24 13:56:32 -0400277 case GL_TEXTURE_CUBE_MAP:
278 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
279 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
280 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
281 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
282 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500283 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
284 maxDimension = caps.maxCubeMapTextureSize;
285 break;
286 case GL_TEXTURE_3D:
287 maxDimension = caps.max3DTextureSize;
288 break;
289 case GL_TEXTURE_2D_ARRAY:
290 maxDimension = caps.max2DTextureSize;
291 break;
Geoff Langce635692013-09-24 13:56:32 -0400292 default: UNREACHABLE();
293 }
294
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700295 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400296}
297
Austin Kinross08528e12015-10-07 16:24:40 -0700298bool ValidImageSizeParameters(const Context *context,
299 GLenum target,
300 GLint level,
301 GLsizei width,
302 GLsizei height,
303 GLsizei depth,
304 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400305{
306 if (level < 0 || width < 0 || height < 0 || depth < 0)
307 {
308 return false;
309 }
310
Austin Kinross08528e12015-10-07 16:24:40 -0700311 // TexSubImage parameters can be NPOT without textureNPOT extension,
312 // as long as the destination texture is POT.
313 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400314 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400315 {
316 return false;
317 }
318
319 if (!ValidMipLevel(context, target, level))
320 {
321 return false;
322 }
323
324 return true;
325}
326
Geoff Lang0d8b7242015-09-09 14:56:53 -0400327bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
328{
329 // List of compressed format that require that the texture size is smaller than or a multiple of
330 // the compressed block size.
331 switch (internalFormat)
332 {
333 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
334 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
335 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
336 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
337 return true;
338
339 default:
340 return false;
341 }
342}
343
Jamie Madillc29968b2016-01-20 11:17:23 -0500344bool ValidCompressedImageSize(const ValidationContext *context,
345 GLenum internalFormat,
346 GLsizei width,
347 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400348{
Geoff Lang5d601382014-07-22 15:14:06 -0400349 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
350 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400351 {
352 return false;
353 }
354
Geoff Lang0d8b7242015-09-09 14:56:53 -0400355 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400356 {
357 return false;
358 }
359
Geoff Lang0d8b7242015-09-09 14:56:53 -0400360 if (CompressedTextureFormatRequiresExactSize(internalFormat))
361 {
362 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
363 width % formatInfo.compressedBlockWidth != 0) ||
364 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
365 height % formatInfo.compressedBlockHeight != 0))
366 {
367 return false;
368 }
369 }
370
Geoff Langd4f180b2013-09-24 13:57:44 -0400371 return true;
372}
373
Geoff Lang37dde692014-01-31 16:34:54 -0500374bool ValidQueryType(const Context *context, GLenum queryType)
375{
Geoff Langd4475812015-03-18 10:53:05 -0400376 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
377 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500378
379 switch (queryType)
380 {
381 case GL_ANY_SAMPLES_PASSED:
382 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
383 return true;
384 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
385 return (context->getClientVersion() >= 3);
386 default:
387 return false;
388 }
389}
390
Dian Xiang769769a2015-09-09 15:20:08 -0700391Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500392{
393 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
394 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
395 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
396
Dian Xiang769769a2015-09-09 15:20:08 -0700397 Program *validProgram = context->getProgram(id);
398
399 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500400 {
Dian Xiang769769a2015-09-09 15:20:08 -0700401 if (context->getShader(id))
402 {
403 context->recordError(
404 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
405 }
406 else
407 {
408 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
409 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500410 }
Dian Xiang769769a2015-09-09 15:20:08 -0700411
412 return validProgram;
413}
414
415Shader *GetValidShader(Context *context, GLuint id)
416{
417 // See ValidProgram for spec details.
418
419 Shader *validShader = context->getShader(id);
420
421 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500422 {
Dian Xiang769769a2015-09-09 15:20:08 -0700423 if (context->getProgram(id))
424 {
425 context->recordError(
426 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
427 }
428 else
429 {
430 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
431 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500432 }
Dian Xiang769769a2015-09-09 15:20:08 -0700433
434 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500435}
436
Geoff Langb1196682014-07-23 13:47:29 -0400437bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400438{
439 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
440 {
441 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
442
Geoff Langaae65a42014-05-26 12:43:44 -0400443 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400444 {
Geoff Langb1196682014-07-23 13:47:29 -0400445 context->recordError(Error(GL_INVALID_VALUE));
446 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400447 }
448 }
449 else
450 {
451 switch (attachment)
452 {
453 case GL_DEPTH_ATTACHMENT:
454 case GL_STENCIL_ATTACHMENT:
455 break;
456
457 case GL_DEPTH_STENCIL_ATTACHMENT:
458 if (context->getClientVersion() < 3)
459 {
Geoff Langb1196682014-07-23 13:47:29 -0400460 context->recordError(Error(GL_INVALID_ENUM));
461 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400462 }
463 break;
464
465 default:
Geoff Langb1196682014-07-23 13:47:29 -0400466 context->recordError(Error(GL_INVALID_ENUM));
467 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400468 }
469 }
470
471 return true;
472}
473
Corentin Walleze0902642014-11-04 12:32:15 -0800474bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
475 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400476{
477 switch (target)
478 {
479 case GL_RENDERBUFFER:
480 break;
481 default:
Geoff Langb1196682014-07-23 13:47:29 -0400482 context->recordError(Error(GL_INVALID_ENUM));
483 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400484 }
485
486 if (width < 0 || height < 0 || samples < 0)
487 {
Geoff Langb1196682014-07-23 13:47:29 -0400488 context->recordError(Error(GL_INVALID_VALUE));
489 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400490 }
491
Geoff Langd87878e2014-09-19 15:42:59 -0400492 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
493 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400494 {
Geoff Langb1196682014-07-23 13:47:29 -0400495 context->recordError(Error(GL_INVALID_ENUM));
496 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400497 }
498
499 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
500 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800501 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400502 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400503 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400504 {
Geoff Langb1196682014-07-23 13:47:29 -0400505 context->recordError(Error(GL_INVALID_ENUM));
506 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400507 }
508
Geoff Langaae65a42014-05-26 12:43:44 -0400509 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
Geoff Langb1196682014-07-23 13:47:29 -0400511 context->recordError(Error(GL_INVALID_VALUE));
512 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 }
514
Shannon Woods53a94a82014-06-24 15:20:36 -0400515 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 if (handle == 0)
517 {
Geoff Langb1196682014-07-23 13:47:29 -0400518 context->recordError(Error(GL_INVALID_OPERATION));
519 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400520 }
521
522 return true;
523}
524
Corentin Walleze0902642014-11-04 12:32:15 -0800525bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
526 GLenum internalformat, GLsizei width, GLsizei height)
527{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800528 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800529
530 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400531 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800532 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400533 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800534 {
535 context->recordError(Error(GL_INVALID_VALUE));
536 return false;
537 }
538
539 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
540 // the specified storage. This is different than ES 3.0 in which a sample number higher
541 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800542 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
543 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800544 {
Geoff Langa4903b72015-03-02 16:02:48 -0800545 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
546 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
547 {
548 context->recordError(Error(GL_OUT_OF_MEMORY));
549 return false;
550 }
Corentin Walleze0902642014-11-04 12:32:15 -0800551 }
552
553 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
554}
555
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500556bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
557 GLenum renderbuffertarget, GLuint renderbuffer)
558{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400559 if (!ValidFramebufferTarget(target))
560 {
Geoff Langb1196682014-07-23 13:47:29 -0400561 context->recordError(Error(GL_INVALID_ENUM));
562 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400563 }
564
Shannon Woods53a94a82014-06-24 15:20:36 -0400565 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500566
Jamie Madill84115c92015-04-23 15:00:07 -0400567 ASSERT(framebuffer);
568 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500569 {
Jamie Madill84115c92015-04-23 15:00:07 -0400570 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400571 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500572 }
573
Jamie Madillb4472272014-07-03 10:38:55 -0400574 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500575 {
Jamie Madillb4472272014-07-03 10:38:55 -0400576 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500577 }
578
Jamie Madillab9d82c2014-01-21 16:38:14 -0500579 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
580 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
581 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
582 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
583 if (renderbuffer != 0)
584 {
585 if (!context->getRenderbuffer(renderbuffer))
586 {
Geoff Langb1196682014-07-23 13:47:29 -0400587 context->recordError(Error(GL_INVALID_OPERATION));
588 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500589 }
590 }
591
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500592 return true;
593}
594
Jamie Madillc29968b2016-01-20 11:17:23 -0500595bool ValidateBlitFramebufferParameters(gl::Context *context,
596 GLint srcX0,
597 GLint srcY0,
598 GLint srcX1,
599 GLint srcY1,
600 GLint dstX0,
601 GLint dstY0,
602 GLint dstX1,
603 GLint dstY1,
604 GLbitfield mask,
605 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606{
607 switch (filter)
608 {
609 case GL_NEAREST:
610 break;
611 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 break;
613 default:
Geoff Langb1196682014-07-23 13:47:29 -0400614 context->recordError(Error(GL_INVALID_ENUM));
615 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 }
617
618 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
619 {
Geoff Langb1196682014-07-23 13:47:29 -0400620 context->recordError(Error(GL_INVALID_VALUE));
621 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622 }
623
624 if (mask == 0)
625 {
626 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
627 // buffers are copied.
628 return false;
629 }
630
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400631 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
632 // color buffer, leaving only nearest being unfiltered from above
633 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
634 {
Geoff Langb1196682014-07-23 13:47:29 -0400635 context->recordError(Error(GL_INVALID_OPERATION));
636 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 }
638
Shannon Woods53a94a82014-06-24 15:20:36 -0400639 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 {
Geoff Langb1196682014-07-23 13:47:29 -0400641 context->recordError(Error(GL_INVALID_OPERATION));
642 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 }
644
Jamie Madille3ef7152015-04-28 16:55:17 +0000645 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
646 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500647
648 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 {
Geoff Langb1196682014-07-23 13:47:29 -0400650 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
651 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 }
653
Geoff Lang748f74e2014-12-01 11:25:34 -0500654 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500655 {
656 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
657 return false;
658 }
659
Geoff Lang748f74e2014-12-01 11:25:34 -0500660 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500661 {
662 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
663 return false;
664 }
665
666 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 {
Geoff Langb1196682014-07-23 13:47:29 -0400668 context->recordError(Error(GL_INVALID_OPERATION));
669 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670 }
671
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
673
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400674 if (mask & GL_COLOR_BUFFER_BIT)
675 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400676 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
677 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500678 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400679
680 if (readColorBuffer && drawColorBuffer)
681 {
Geoff Langd8a22582014-12-17 15:28:23 -0500682 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400683 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684
Geoff Langa15472a2015-08-11 11:48:03 -0400685 for (size_t drawbufferIdx = 0;
686 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 {
Geoff Langa15472a2015-08-11 11:48:03 -0400688 const FramebufferAttachment *attachment =
689 drawFramebuffer->getDrawBuffer(drawbufferIdx);
690 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400691 {
Geoff Langa15472a2015-08-11 11:48:03 -0400692 GLenum drawInternalFormat = attachment->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400693 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694
Geoff Langb2f3d052013-08-13 12:49:27 -0400695 // The GL ES 3.0.2 spec (pg 193) states that:
696 // 1) If the read buffer is fixed point format, the draw buffer must be as well
697 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
698 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500699 // Changes with EXT_color_buffer_float:
700 // Case 1) is changed to fixed point OR floating point
701 GLenum readComponentType = readFormatInfo.componentType;
702 GLenum drawComponentType = drawFormatInfo.componentType;
703 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
704 readComponentType == GL_SIGNED_NORMALIZED);
705 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
706 drawComponentType == GL_SIGNED_NORMALIZED);
707
708 if (extensions.colorBufferFloat)
709 {
710 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
711 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
712
713 if (readFixedOrFloat != drawFixedOrFloat)
714 {
715 context->recordError(Error(GL_INVALID_OPERATION,
716 "If the read buffer contains fixed-point or "
717 "floating-point values, the draw buffer "
718 "must as well."));
719 return false;
720 }
721 }
722 else if (readFixedPoint != drawFixedPoint)
723 {
724 context->recordError(Error(GL_INVALID_OPERATION,
725 "If the read buffer contains fixed-point "
726 "values, the draw buffer must as well."));
727 return false;
728 }
729
730 if (readComponentType == GL_UNSIGNED_INT &&
731 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 {
Geoff Langb1196682014-07-23 13:47:29 -0400733 context->recordError(Error(GL_INVALID_OPERATION));
734 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735 }
736
Jamie Madill6163c752015-12-07 16:32:59 -0500737 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 {
Geoff Langb1196682014-07-23 13:47:29 -0400739 context->recordError(Error(GL_INVALID_OPERATION));
740 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 }
742
Geoff Langb2f3d052013-08-13 12:49:27 -0400743 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744 {
Geoff Langb1196682014-07-23 13:47:29 -0400745 context->recordError(Error(GL_INVALID_OPERATION));
746 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747 }
748 }
749 }
750
Geoff Lang5d601382014-07-22 15:14:06 -0400751 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400752 {
Geoff Langb1196682014-07-23 13:47:29 -0400753 context->recordError(Error(GL_INVALID_OPERATION));
754 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400755 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400756 }
757 }
758
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200759 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
760 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
761 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400762 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200763 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400765 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
766 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200768 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400769 {
Geoff Langd8a22582014-12-17 15:28:23 -0500770 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 {
Geoff Langb1196682014-07-23 13:47:29 -0400772 context->recordError(Error(GL_INVALID_OPERATION));
773 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200776 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 {
Geoff Langb1196682014-07-23 13:47:29 -0400778 context->recordError(Error(GL_INVALID_OPERATION));
779 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780 }
781 }
782 }
783 }
784
785 return true;
786}
787
Geoff Langb1196682014-07-23 13:47:29 -0400788bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400789{
790 switch (pname)
791 {
792 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
793 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
794 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
795 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
796 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
797 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
798 case GL_CURRENT_VERTEX_ATTRIB:
799 return true;
800
801 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
802 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
803 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400804 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
805 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 return true;
807
808 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400809 if (context->getClientVersion() < 3)
810 {
811 context->recordError(Error(GL_INVALID_ENUM));
812 return false;
813 }
814 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815
816 default:
Geoff Langb1196682014-07-23 13:47:29 -0400817 context->recordError(Error(GL_INVALID_ENUM));
818 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400819 }
820}
821
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400822bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400823{
824 switch (pname)
825 {
826 case GL_TEXTURE_WRAP_R:
827 case GL_TEXTURE_SWIZZLE_R:
828 case GL_TEXTURE_SWIZZLE_G:
829 case GL_TEXTURE_SWIZZLE_B:
830 case GL_TEXTURE_SWIZZLE_A:
831 case GL_TEXTURE_BASE_LEVEL:
832 case GL_TEXTURE_MAX_LEVEL:
833 case GL_TEXTURE_COMPARE_MODE:
834 case GL_TEXTURE_COMPARE_FUNC:
835 case GL_TEXTURE_MIN_LOD:
836 case GL_TEXTURE_MAX_LOD:
837 if (context->getClientVersion() < 3)
838 {
Geoff Langb1196682014-07-23 13:47:29 -0400839 context->recordError(Error(GL_INVALID_ENUM));
840 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400841 }
842 break;
843
844 default: break;
845 }
846
847 switch (pname)
848 {
849 case GL_TEXTURE_WRAP_S:
850 case GL_TEXTURE_WRAP_T:
851 case GL_TEXTURE_WRAP_R:
852 switch (param)
853 {
854 case GL_REPEAT:
855 case GL_CLAMP_TO_EDGE:
856 case GL_MIRRORED_REPEAT:
857 return true;
858 default:
Geoff Langb1196682014-07-23 13:47:29 -0400859 context->recordError(Error(GL_INVALID_ENUM));
860 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400861 }
862
863 case GL_TEXTURE_MIN_FILTER:
864 switch (param)
865 {
866 case GL_NEAREST:
867 case GL_LINEAR:
868 case GL_NEAREST_MIPMAP_NEAREST:
869 case GL_LINEAR_MIPMAP_NEAREST:
870 case GL_NEAREST_MIPMAP_LINEAR:
871 case GL_LINEAR_MIPMAP_LINEAR:
872 return true;
873 default:
Geoff Langb1196682014-07-23 13:47:29 -0400874 context->recordError(Error(GL_INVALID_ENUM));
875 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400876 }
877 break;
878
879 case GL_TEXTURE_MAG_FILTER:
880 switch (param)
881 {
882 case GL_NEAREST:
883 case GL_LINEAR:
884 return true;
885 default:
Geoff Langb1196682014-07-23 13:47:29 -0400886 context->recordError(Error(GL_INVALID_ENUM));
887 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400888 }
889 break;
890
891 case GL_TEXTURE_USAGE_ANGLE:
892 switch (param)
893 {
894 case GL_NONE:
895 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
896 return true;
897 default:
Geoff Langb1196682014-07-23 13:47:29 -0400898 context->recordError(Error(GL_INVALID_ENUM));
899 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400900 }
901 break;
902
903 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400904 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400905 {
Geoff Langb1196682014-07-23 13:47:29 -0400906 context->recordError(Error(GL_INVALID_ENUM));
907 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400908 }
909
910 // we assume the parameter passed to this validation method is truncated, not rounded
911 if (param < 1)
912 {
Geoff Langb1196682014-07-23 13:47:29 -0400913 context->recordError(Error(GL_INVALID_VALUE));
914 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400915 }
916 return true;
917
918 case GL_TEXTURE_MIN_LOD:
919 case GL_TEXTURE_MAX_LOD:
920 // any value is permissible
921 return true;
922
923 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400924 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400925 switch (param)
926 {
927 case GL_NONE:
928 case GL_COMPARE_REF_TO_TEXTURE:
929 return true;
930 default:
Geoff Langb1196682014-07-23 13:47:29 -0400931 context->recordError(Error(GL_INVALID_ENUM));
932 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400933 }
934 break;
935
936 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400937 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400938 switch (param)
939 {
940 case GL_LEQUAL:
941 case GL_GEQUAL:
942 case GL_LESS:
943 case GL_GREATER:
944 case GL_EQUAL:
945 case GL_NOTEQUAL:
946 case GL_ALWAYS:
947 case GL_NEVER:
948 return true;
949 default:
Geoff Langb1196682014-07-23 13:47:29 -0400950 context->recordError(Error(GL_INVALID_ENUM));
951 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952 }
953 break;
954
955 case GL_TEXTURE_SWIZZLE_R:
956 case GL_TEXTURE_SWIZZLE_G:
957 case GL_TEXTURE_SWIZZLE_B:
958 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400959 switch (param)
960 {
961 case GL_RED:
962 case GL_GREEN:
963 case GL_BLUE:
964 case GL_ALPHA:
965 case GL_ZERO:
966 case GL_ONE:
967 return true;
968 default:
Geoff Langb1196682014-07-23 13:47:29 -0400969 context->recordError(Error(GL_INVALID_ENUM));
970 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400971 }
972 break;
973
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400974 case GL_TEXTURE_BASE_LEVEL:
975 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400976 if (param < 0)
977 {
Geoff Langb1196682014-07-23 13:47:29 -0400978 context->recordError(Error(GL_INVALID_VALUE));
979 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400980 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400981 return true;
982
983 default:
Geoff Langb1196682014-07-23 13:47:29 -0400984 context->recordError(Error(GL_INVALID_ENUM));
985 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400986 }
987}
988
Geoff Langb1196682014-07-23 13:47:29 -0400989bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400990{
991 switch (pname)
992 {
993 case GL_TEXTURE_MIN_FILTER:
994 case GL_TEXTURE_MAG_FILTER:
995 case GL_TEXTURE_WRAP_S:
996 case GL_TEXTURE_WRAP_T:
997 case GL_TEXTURE_WRAP_R:
998 case GL_TEXTURE_MIN_LOD:
999 case GL_TEXTURE_MAX_LOD:
1000 case GL_TEXTURE_COMPARE_MODE:
1001 case GL_TEXTURE_COMPARE_FUNC:
1002 return true;
1003
1004 default:
Geoff Langb1196682014-07-23 13:47:29 -04001005 context->recordError(Error(GL_INVALID_ENUM));
1006 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001007 }
1008}
1009
Jamie Madillc29968b2016-01-20 11:17:23 -05001010bool ValidateReadPixels(Context *context,
1011 GLint x,
1012 GLint y,
1013 GLsizei width,
1014 GLsizei height,
1015 GLenum format,
1016 GLenum type,
1017 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001018{
Jamie Madillc29968b2016-01-20 11:17:23 -05001019 if (width < 0 || height < 0)
1020 {
1021 context->recordError(Error(GL_INVALID_VALUE, "width and height must be positive"));
1022 return false;
1023 }
1024
1025 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001026 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001027
Geoff Lang748f74e2014-12-01 11:25:34 -05001028 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001029 {
Geoff Langb1196682014-07-23 13:47:29 -04001030 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1031 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001032 }
1033
Jamie Madill48faf802014-11-06 15:27:22 -05001034 if (context->getState().getReadFramebuffer()->id() != 0 &&
1035 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001036 {
Geoff Langb1196682014-07-23 13:47:29 -04001037 context->recordError(Error(GL_INVALID_OPERATION));
1038 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001039 }
1040
Geoff Langbce529e2014-12-01 12:48:41 -05001041 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1042 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001043 {
Geoff Langb1196682014-07-23 13:47:29 -04001044 context->recordError(Error(GL_INVALID_OPERATION));
1045 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001046 }
1047
Geoff Langbce529e2014-12-01 12:48:41 -05001048 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1049 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001050 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001051 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001052
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001053 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1054 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001055
1056 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1057 {
Geoff Langb1196682014-07-23 13:47:29 -04001058 context->recordError(Error(GL_INVALID_OPERATION));
1059 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001060 }
1061
Jamie Madillc29968b2016-01-20 11:17:23 -05001062 return true;
1063}
1064
1065bool ValidateReadnPixelsEXT(Context *context,
1066 GLint x,
1067 GLint y,
1068 GLsizei width,
1069 GLsizei height,
1070 GLenum format,
1071 GLenum type,
1072 GLsizei bufSize,
1073 GLvoid *pixels)
1074{
1075 if (bufSize < 0)
1076 {
1077 context->recordError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
1078 return false;
1079 }
1080
Geoff Lang5d601382014-07-22 15:14:06 -04001081 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1082 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001083
Minmin Gongadff67b2015-10-14 10:34:45 -04001084 GLsizei outputPitch =
1085 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1086 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001087 // sized query sanity check
Jamie Madillc29968b2016-01-20 11:17:23 -05001088 int requiredSize = outputPitch * height;
1089 if (requiredSize > bufSize)
Jamie Madill26e91952014-03-05 15:01:27 -05001090 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001091 context->recordError(Error(GL_INVALID_OPERATION));
1092 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001093 }
1094
Jamie Madillc29968b2016-01-20 11:17:23 -05001095 return ValidateReadPixels(context, x, y, width, height, format, type, pixels);
Jamie Madill26e91952014-03-05 15:01:27 -05001096}
1097
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001098bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1099{
1100 if (!ValidQueryType(context, target))
1101 {
Geoff Langb1196682014-07-23 13:47:29 -04001102 context->recordError(Error(GL_INVALID_ENUM));
1103 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001104 }
1105
1106 if (id == 0)
1107 {
Geoff Langb1196682014-07-23 13:47:29 -04001108 context->recordError(Error(GL_INVALID_OPERATION));
1109 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001110 }
1111
1112 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1113 // of zero, if the active query object name for <target> is non-zero (for the
1114 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1115 // the active query for either target is non-zero), if <id> is the name of an
1116 // existing query object whose type does not match <target>, or if <id> is the
1117 // active query object name for any query type, the error INVALID_OPERATION is
1118 // generated.
1119
1120 // Ensure no other queries are active
1121 // NOTE: If other queries than occlusion are supported, we will need to check
1122 // separately that:
1123 // a) The query ID passed is not the current active query for any target/type
1124 // b) There are no active queries for the requested target (and in the case
1125 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1126 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001127 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001128 {
Geoff Langb1196682014-07-23 13:47:29 -04001129 context->recordError(Error(GL_INVALID_OPERATION));
1130 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001131 }
1132
1133 Query *queryObject = context->getQuery(id, true, target);
1134
1135 // check that name was obtained with glGenQueries
1136 if (!queryObject)
1137 {
Geoff Langb1196682014-07-23 13:47:29 -04001138 context->recordError(Error(GL_INVALID_OPERATION));
1139 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001140 }
1141
1142 // check for type mismatch
1143 if (queryObject->getType() != target)
1144 {
Geoff Langb1196682014-07-23 13:47:29 -04001145 context->recordError(Error(GL_INVALID_OPERATION));
1146 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001147 }
1148
1149 return true;
1150}
1151
Jamie Madill45c785d2014-05-13 14:09:34 -04001152bool ValidateEndQuery(gl::Context *context, GLenum target)
1153{
1154 if (!ValidQueryType(context, target))
1155 {
Geoff Langb1196682014-07-23 13:47:29 -04001156 context->recordError(Error(GL_INVALID_ENUM));
1157 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001158 }
1159
Shannon Woods53a94a82014-06-24 15:20:36 -04001160 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001161
1162 if (queryObject == NULL)
1163 {
Geoff Langb1196682014-07-23 13:47:29 -04001164 context->recordError(Error(GL_INVALID_OPERATION));
1165 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001166 }
1167
Jamie Madill45c785d2014-05-13 14:09:34 -04001168 return true;
1169}
1170
Jamie Madill62d31cb2015-09-11 13:25:51 -04001171static bool ValidateUniformCommonBase(gl::Context *context,
1172 GLenum targetUniformType,
1173 GLint location,
1174 GLsizei count,
1175 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001176{
1177 if (count < 0)
1178 {
Geoff Langb1196682014-07-23 13:47:29 -04001179 context->recordError(Error(GL_INVALID_VALUE));
1180 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001181 }
1182
Geoff Lang7dd2e102014-11-10 15:19:26 -05001183 gl::Program *program = context->getState().getProgram();
1184 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001185 {
Geoff Langb1196682014-07-23 13:47:29 -04001186 context->recordError(Error(GL_INVALID_OPERATION));
1187 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001188 }
1189
1190 if (location == -1)
1191 {
1192 // Silently ignore the uniform command
1193 return false;
1194 }
1195
Geoff Lang7dd2e102014-11-10 15:19:26 -05001196 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001197 {
Geoff Langb1196682014-07-23 13:47:29 -04001198 context->recordError(Error(GL_INVALID_OPERATION));
1199 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001200 }
1201
Jamie Madill62d31cb2015-09-11 13:25:51 -04001202 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001203
1204 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001205 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001206 {
Geoff Langb1196682014-07-23 13:47:29 -04001207 context->recordError(Error(GL_INVALID_OPERATION));
1208 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001209 }
1210
Jamie Madill62d31cb2015-09-11 13:25:51 -04001211 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001212 return true;
1213}
1214
Jamie Madillaa981bd2014-05-20 10:55:55 -04001215bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1216{
1217 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001218 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001219 {
Geoff Langb1196682014-07-23 13:47:29 -04001220 context->recordError(Error(GL_INVALID_OPERATION));
1221 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001222 }
1223
Jamie Madill62d31cb2015-09-11 13:25:51 -04001224 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001225 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1226 {
1227 return false;
1228 }
1229
Jamie Madillf2575982014-06-25 16:04:54 -04001230 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001231 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001232 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1233 {
Geoff Langb1196682014-07-23 13:47:29 -04001234 context->recordError(Error(GL_INVALID_OPERATION));
1235 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001236 }
1237
1238 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001239}
1240
1241bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1242 GLboolean transpose)
1243{
1244 // Check for ES3 uniform entry points
1245 int rows = VariableRowCount(matrixType);
1246 int cols = VariableColumnCount(matrixType);
1247 if (rows != cols && context->getClientVersion() < 3)
1248 {
Geoff Langb1196682014-07-23 13:47:29 -04001249 context->recordError(Error(GL_INVALID_OPERATION));
1250 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001251 }
1252
1253 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1254 {
Geoff Langb1196682014-07-23 13:47:29 -04001255 context->recordError(Error(GL_INVALID_VALUE));
1256 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001257 }
1258
Jamie Madill62d31cb2015-09-11 13:25:51 -04001259 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001260 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1261 {
1262 return false;
1263 }
1264
1265 if (uniform->type != matrixType)
1266 {
Geoff Langb1196682014-07-23 13:47:29 -04001267 context->recordError(Error(GL_INVALID_OPERATION));
1268 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001269 }
1270
1271 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001272}
1273
Jamie Madill893ab082014-05-16 16:56:10 -04001274bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1275{
1276 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1277 {
Geoff Langb1196682014-07-23 13:47:29 -04001278 context->recordError(Error(GL_INVALID_ENUM));
1279 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001280 }
1281
Jamie Madill0af26e12015-03-05 19:54:33 -05001282 const Caps &caps = context->getCaps();
1283
Jamie Madill893ab082014-05-16 16:56:10 -04001284 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1285 {
1286 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1287
Jamie Madill0af26e12015-03-05 19:54:33 -05001288 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001289 {
Geoff Langb1196682014-07-23 13:47:29 -04001290 context->recordError(Error(GL_INVALID_OPERATION));
1291 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001292 }
1293 }
1294
1295 switch (pname)
1296 {
1297 case GL_TEXTURE_BINDING_2D:
1298 case GL_TEXTURE_BINDING_CUBE_MAP:
1299 case GL_TEXTURE_BINDING_3D:
1300 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001301 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001302 {
Geoff Langb1196682014-07-23 13:47:29 -04001303 context->recordError(Error(GL_INVALID_OPERATION));
1304 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001305 }
1306 break;
1307
1308 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1309 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1310 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001311 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001312 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001313 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001314 {
Geoff Langb1196682014-07-23 13:47:29 -04001315 context->recordError(Error(GL_INVALID_OPERATION));
1316 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001317 }
1318
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001319 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001320 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001321 {
Geoff Langb1196682014-07-23 13:47:29 -04001322 context->recordError(Error(GL_INVALID_OPERATION));
1323 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001324 }
1325 }
1326 break;
1327
1328 default:
1329 break;
1330 }
1331
1332 // pname is valid, but there are no parameters to return
1333 if (numParams == 0)
1334 {
1335 return false;
1336 }
1337
1338 return true;
1339}
1340
Jamie Madillc29968b2016-01-20 11:17:23 -05001341bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1342 GLenum target,
1343 GLint level,
1344 GLenum internalformat,
1345 bool isSubImage,
1346 GLint xoffset,
1347 GLint yoffset,
1348 GLint zoffset,
1349 GLint x,
1350 GLint y,
1351 GLsizei width,
1352 GLsizei height,
1353 GLint border,
1354 GLenum *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04001355{
Jamie Madill560a8d82014-05-21 13:06:20 -04001356 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1357 {
Geoff Langb1196682014-07-23 13:47:29 -04001358 context->recordError(Error(GL_INVALID_VALUE));
1359 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001360 }
1361
1362 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1363 {
Geoff Langb1196682014-07-23 13:47:29 -04001364 context->recordError(Error(GL_INVALID_VALUE));
1365 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001366 }
1367
1368 if (border != 0)
1369 {
Geoff Langb1196682014-07-23 13:47:29 -04001370 context->recordError(Error(GL_INVALID_VALUE));
1371 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001372 }
1373
1374 if (!ValidMipLevel(context, target, level))
1375 {
Geoff Langb1196682014-07-23 13:47:29 -04001376 context->recordError(Error(GL_INVALID_VALUE));
1377 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001378 }
1379
Jamie Madillc29968b2016-01-20 11:17:23 -05001380 const gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001381 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001382 {
Geoff Langb1196682014-07-23 13:47:29 -04001383 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1384 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001385 }
1386
Jamie Madillc29968b2016-01-20 11:17:23 -05001387 const auto &state = context->getState();
1388 if (state.getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001389 {
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_OPERATION));
1391 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001392 }
1393
Geoff Langaae65a42014-05-26 12:43:44 -04001394 const gl::Caps &caps = context->getCaps();
1395
Geoff Langaae65a42014-05-26 12:43:44 -04001396 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001397 switch (target)
1398 {
1399 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001400 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001401 break;
1402
1403 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1404 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1405 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1406 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1407 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1408 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001409 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001410 break;
1411
1412 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001413 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001414 break;
1415
1416 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001417 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001418 break;
1419
1420 default:
Geoff Langb1196682014-07-23 13:47:29 -04001421 context->recordError(Error(GL_INVALID_ENUM));
1422 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001423 }
1424
Jamie Madillc29968b2016-01-20 11:17:23 -05001425 gl::Texture *texture =
1426 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001427 if (!texture)
1428 {
Geoff Langb1196682014-07-23 13:47:29 -04001429 context->recordError(Error(GL_INVALID_OPERATION));
1430 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001431 }
1432
Geoff Lang69cce582015-09-17 13:20:36 -04001433 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001434 {
Geoff Langb1196682014-07-23 13:47:29 -04001435 context->recordError(Error(GL_INVALID_OPERATION));
1436 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001437 }
1438
Geoff Lang5d601382014-07-22 15:14:06 -04001439 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1440
1441 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001442 {
Geoff Langb1196682014-07-23 13:47:29 -04001443 context->recordError(Error(GL_INVALID_OPERATION));
1444 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001445 }
1446
Geoff Langa9be0dc2014-12-17 12:34:40 -05001447 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001448 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001449 context->recordError(Error(GL_INVALID_OPERATION));
1450 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001451 }
1452
1453 if (isSubImage)
1454 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001455 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1456 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1457 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001458 {
Geoff Langb1196682014-07-23 13:47:29 -04001459 context->recordError(Error(GL_INVALID_VALUE));
1460 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001461 }
1462 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001463 else
1464 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001465 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001466 {
Geoff Langb1196682014-07-23 13:47:29 -04001467 context->recordError(Error(GL_INVALID_VALUE));
1468 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001469 }
1470
Geoff Lang5d601382014-07-22 15:14:06 -04001471 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001472 {
Geoff Langb1196682014-07-23 13:47:29 -04001473 context->recordError(Error(GL_INVALID_ENUM));
1474 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001475 }
1476
1477 int maxLevelDimension = (maxDimension >> level);
1478 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1479 {
Geoff Langb1196682014-07-23 13:47:29 -04001480 context->recordError(Error(GL_INVALID_VALUE));
1481 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001482 }
1483 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001484
Geoff Langa9be0dc2014-12-17 12:34:40 -05001485 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001486 return true;
1487}
1488
Jamie Madillf25855c2015-11-03 11:06:18 -05001489static bool ValidateDrawBase(ValidationContext *context,
1490 GLenum mode,
1491 GLsizei count,
1492 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001493{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001494 switch (mode)
1495 {
1496 case GL_POINTS:
1497 case GL_LINES:
1498 case GL_LINE_LOOP:
1499 case GL_LINE_STRIP:
1500 case GL_TRIANGLES:
1501 case GL_TRIANGLE_STRIP:
1502 case GL_TRIANGLE_FAN:
1503 break;
1504 default:
Geoff Langb1196682014-07-23 13:47:29 -04001505 context->recordError(Error(GL_INVALID_ENUM));
1506 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001507 }
1508
Jamie Madill250d33f2014-06-06 17:09:03 -04001509 if (count < 0)
1510 {
Geoff Langb1196682014-07-23 13:47:29 -04001511 context->recordError(Error(GL_INVALID_VALUE));
1512 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001513 }
1514
Geoff Langb1196682014-07-23 13:47:29 -04001515 const State &state = context->getState();
1516
Jamie Madill250d33f2014-06-06 17:09:03 -04001517 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001518 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001519 {
Geoff Langb1196682014-07-23 13:47:29 -04001520 context->recordError(Error(GL_INVALID_OPERATION));
1521 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001522 }
1523
Geoff Lang3a86ad32015-09-01 11:47:05 -04001524 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001525 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001526 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1527 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1528 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1529 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1530 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1531 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1532 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001533 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001534 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1535 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001536 {
1537 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1538 // Section 6.10 of the WebGL 1.0 spec
1539 ERR(
1540 "This ANGLE implementation does not support separate front/back stencil "
1541 "writemasks, reference values, or stencil mask values.");
1542 context->recordError(Error(GL_INVALID_OPERATION));
1543 return false;
1544 }
Jamie Madillac528012014-06-20 13:21:23 -04001545 }
1546
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001547 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001548 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001549 {
Geoff Langb1196682014-07-23 13:47:29 -04001550 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1551 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001552 }
1553
Geoff Lang7dd2e102014-11-10 15:19:26 -05001554 gl::Program *program = state.getProgram();
1555 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001556 {
Geoff Langb1196682014-07-23 13:47:29 -04001557 context->recordError(Error(GL_INVALID_OPERATION));
1558 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001559 }
1560
Geoff Lang7dd2e102014-11-10 15:19:26 -05001561 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001562 {
Geoff Langb1196682014-07-23 13:47:29 -04001563 context->recordError(Error(GL_INVALID_OPERATION));
1564 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001565 }
1566
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001567 // Uniform buffer validation
1568 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1569 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001570 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001571 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001572 const OffsetBindingPointer<Buffer> &uniformBuffer =
1573 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001574
Geoff Lang5d124a62015-09-15 13:03:27 -04001575 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001576 {
1577 // undefined behaviour
1578 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1579 return false;
1580 }
1581
Geoff Lang5d124a62015-09-15 13:03:27 -04001582 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001583 if (uniformBufferSize == 0)
1584 {
1585 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001586 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001587 }
1588
Jamie Madill62d31cb2015-09-11 13:25:51 -04001589 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001590 {
1591 // undefined behaviour
1592 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1593 return false;
1594 }
1595 }
1596
Jamie Madill250d33f2014-06-06 17:09:03 -04001597 // No-op if zero count
1598 return (count > 0);
1599}
1600
Geoff Langb1196682014-07-23 13:47:29 -04001601bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001602{
Jamie Madillfd716582014-06-06 17:09:04 -04001603 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001604 {
Geoff Langb1196682014-07-23 13:47:29 -04001605 context->recordError(Error(GL_INVALID_VALUE));
1606 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001607 }
1608
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001609 const State &state = context->getState();
1610 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001611 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1612 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001613 {
1614 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1615 // that does not match the current transform feedback object's draw mode (if transform feedback
1616 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001617 context->recordError(Error(GL_INVALID_OPERATION));
1618 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001619 }
1620
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001621 if (!ValidateDrawBase(context, mode, count, primcount))
1622 {
1623 return false;
1624 }
1625
1626 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001627 {
1628 return false;
1629 }
1630
1631 return true;
1632}
1633
Geoff Langb1196682014-07-23 13:47:29 -04001634bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001635{
1636 if (primcount < 0)
1637 {
Geoff Langb1196682014-07-23 13:47:29 -04001638 context->recordError(Error(GL_INVALID_VALUE));
1639 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001640 }
1641
Jamie Madill2b976812014-08-25 15:47:49 -04001642 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001643 {
1644 return false;
1645 }
1646
1647 // No-op if zero primitive count
1648 return (primcount > 0);
1649}
1650
Geoff Lang87a93302014-09-16 13:29:43 -04001651static bool ValidateDrawInstancedANGLE(Context *context)
1652{
1653 // Verify there is at least one active attribute with a divisor of zero
1654 const gl::State& state = context->getState();
1655
Geoff Lang7dd2e102014-11-10 15:19:26 -05001656 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001657
1658 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001659 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001660 {
1661 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001662 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001663 {
1664 return true;
1665 }
1666 }
1667
1668 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1669 "has a divisor of zero."));
1670 return false;
1671}
1672
1673bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1674{
1675 if (!ValidateDrawInstancedANGLE(context))
1676 {
1677 return false;
1678 }
1679
1680 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1681}
1682
Jamie Madillf25855c2015-11-03 11:06:18 -05001683bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001684 GLenum mode,
1685 GLsizei count,
1686 GLenum type,
1687 const GLvoid *indices,
1688 GLsizei primcount,
1689 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001690{
Jamie Madill250d33f2014-06-06 17:09:03 -04001691 switch (type)
1692 {
1693 case GL_UNSIGNED_BYTE:
1694 case GL_UNSIGNED_SHORT:
1695 break;
1696 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001697 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001698 {
Geoff Langb1196682014-07-23 13:47:29 -04001699 context->recordError(Error(GL_INVALID_ENUM));
1700 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001701 }
1702 break;
1703 default:
Geoff Langb1196682014-07-23 13:47:29 -04001704 context->recordError(Error(GL_INVALID_ENUM));
1705 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001706 }
1707
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001708 const State &state = context->getState();
1709
1710 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001711 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001712 {
1713 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1714 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001715 context->recordError(Error(GL_INVALID_OPERATION));
1716 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001717 }
1718
1719 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001720 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001721 {
Geoff Langb1196682014-07-23 13:47:29 -04001722 context->recordError(Error(GL_INVALID_OPERATION));
1723 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001724 }
1725
Jamie Madill2b976812014-08-25 15:47:49 -04001726 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001727 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001728 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001729 {
Geoff Langb1196682014-07-23 13:47:29 -04001730 context->recordError(Error(GL_INVALID_OPERATION));
1731 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001732 }
1733
Jamie Madillae3000b2014-08-25 15:47:51 -04001734 if (elementArrayBuffer)
1735 {
1736 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1737
1738 GLint64 offset = reinterpret_cast<GLint64>(indices);
1739 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1740
1741 // check for integer overflows
1742 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1743 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1744 {
Geoff Langb1196682014-07-23 13:47:29 -04001745 context->recordError(Error(GL_OUT_OF_MEMORY));
1746 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001747 }
1748
1749 // Check for reading past the end of the bound buffer object
1750 if (byteCount > elementArrayBuffer->getSize())
1751 {
Geoff Langb1196682014-07-23 13:47:29 -04001752 context->recordError(Error(GL_INVALID_OPERATION));
1753 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001754 }
1755 }
1756 else if (!indices)
1757 {
1758 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001759 context->recordError(Error(GL_INVALID_OPERATION));
1760 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001761 }
1762
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001763 if (!ValidateDrawBase(context, mode, count, primcount))
1764 {
1765 return false;
1766 }
1767
Jamie Madill2b976812014-08-25 15:47:49 -04001768 // Use max index to validate if our vertex buffers are large enough for the pull.
1769 // TODO: offer fast path, with disabled index validation.
1770 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1771 if (elementArrayBuffer)
1772 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001773 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001774 Error error =
1775 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1776 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001777 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001778 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001779 context->recordError(error);
1780 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001781 }
1782 }
1783 else
1784 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001785 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001786 }
1787
Jamie Madille79b1e12015-11-04 16:36:37 -05001788 // If we use an index greater than our maximum supported index range, return an error.
1789 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1790 // return an error if possible here.
1791 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1792 {
1793 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1794 return false;
1795 }
1796
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001797 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001798 {
1799 return false;
1800 }
1801
Geoff Lang3edfe032015-09-04 16:38:24 -04001802 // No op if there are no real indices in the index data (all are primitive restart).
1803 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001804}
1805
Geoff Langb1196682014-07-23 13:47:29 -04001806bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001807 GLenum mode,
1808 GLsizei count,
1809 GLenum type,
1810 const GLvoid *indices,
1811 GLsizei primcount,
1812 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001813{
1814 if (primcount < 0)
1815 {
Geoff Langb1196682014-07-23 13:47:29 -04001816 context->recordError(Error(GL_INVALID_VALUE));
1817 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001818 }
1819
Jamie Madill2b976812014-08-25 15:47:49 -04001820 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001821 {
1822 return false;
1823 }
1824
1825 // No-op zero primitive count
1826 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001827}
1828
Geoff Lang3edfe032015-09-04 16:38:24 -04001829bool ValidateDrawElementsInstancedANGLE(Context *context,
1830 GLenum mode,
1831 GLsizei count,
1832 GLenum type,
1833 const GLvoid *indices,
1834 GLsizei primcount,
1835 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001836{
1837 if (!ValidateDrawInstancedANGLE(context))
1838 {
1839 return false;
1840 }
1841
1842 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1843}
1844
Geoff Langb1196682014-07-23 13:47:29 -04001845bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001846 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001847{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001848 if (!ValidFramebufferTarget(target))
1849 {
Geoff Langb1196682014-07-23 13:47:29 -04001850 context->recordError(Error(GL_INVALID_ENUM));
1851 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001852 }
1853
1854 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001855 {
1856 return false;
1857 }
1858
Jamie Madill55ec3b12014-07-03 10:38:57 -04001859 if (texture != 0)
1860 {
1861 gl::Texture *tex = context->getTexture(texture);
1862
1863 if (tex == NULL)
1864 {
Geoff Langb1196682014-07-23 13:47:29 -04001865 context->recordError(Error(GL_INVALID_OPERATION));
1866 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001867 }
1868
1869 if (level < 0)
1870 {
Geoff Langb1196682014-07-23 13:47:29 -04001871 context->recordError(Error(GL_INVALID_VALUE));
1872 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001873 }
1874 }
1875
Shannon Woods53a94a82014-06-24 15:20:36 -04001876 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001877 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001878
Jamie Madill84115c92015-04-23 15:00:07 -04001879 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001880 {
Jamie Madill84115c92015-04-23 15:00:07 -04001881 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001882 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001883 }
1884
1885 return true;
1886}
1887
Geoff Langb1196682014-07-23 13:47:29 -04001888bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001889 GLenum textarget, GLuint texture, GLint level)
1890{
Geoff Lang95663912015-04-02 15:54:45 -04001891 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1892 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001893 {
Geoff Langb1196682014-07-23 13:47:29 -04001894 context->recordError(Error(GL_INVALID_VALUE));
1895 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001896 }
1897
1898 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001899 {
1900 return false;
1901 }
1902
Jamie Madill55ec3b12014-07-03 10:38:57 -04001903 if (texture != 0)
1904 {
1905 gl::Texture *tex = context->getTexture(texture);
1906 ASSERT(tex);
1907
Jamie Madill2a6564e2014-07-11 09:53:19 -04001908 const gl::Caps &caps = context->getCaps();
1909
Jamie Madill55ec3b12014-07-03 10:38:57 -04001910 switch (textarget)
1911 {
1912 case GL_TEXTURE_2D:
1913 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001914 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001915 {
Geoff Langb1196682014-07-23 13:47:29 -04001916 context->recordError(Error(GL_INVALID_VALUE));
1917 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001918 }
1919 if (tex->getTarget() != GL_TEXTURE_2D)
1920 {
Geoff Langb1196682014-07-23 13:47:29 -04001921 context->recordError(Error(GL_INVALID_OPERATION));
1922 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001923 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001924 }
1925 break;
1926
1927 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1928 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1929 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1930 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1931 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1932 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1933 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001934 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001935 {
Geoff Langb1196682014-07-23 13:47:29 -04001936 context->recordError(Error(GL_INVALID_VALUE));
1937 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001938 }
1939 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1940 {
Geoff Langb1196682014-07-23 13:47:29 -04001941 context->recordError(Error(GL_INVALID_OPERATION));
1942 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001943 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001944 }
1945 break;
1946
1947 default:
Geoff Langb1196682014-07-23 13:47:29 -04001948 context->recordError(Error(GL_INVALID_ENUM));
1949 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001950 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001951
1952 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1953 if (internalFormatInfo.compressed)
1954 {
1955 context->recordError(Error(GL_INVALID_OPERATION));
1956 return false;
1957 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001958 }
1959
Jamie Madill570f7c82014-07-03 10:38:54 -04001960 return true;
1961}
1962
Geoff Langb1196682014-07-23 13:47:29 -04001963bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001964{
1965 if (program == 0)
1966 {
Geoff Langb1196682014-07-23 13:47:29 -04001967 context->recordError(Error(GL_INVALID_VALUE));
1968 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001969 }
1970
Dian Xiang769769a2015-09-09 15:20:08 -07001971 gl::Program *programObject = GetValidProgram(context, program);
1972 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001973 {
1974 return false;
1975 }
1976
Jamie Madill0063c512014-08-25 15:47:53 -04001977 if (!programObject || !programObject->isLinked())
1978 {
Geoff Langb1196682014-07-23 13:47:29 -04001979 context->recordError(Error(GL_INVALID_OPERATION));
1980 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001981 }
1982
Geoff Lang7dd2e102014-11-10 15:19:26 -05001983 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001984 {
Geoff Langb1196682014-07-23 13:47:29 -04001985 context->recordError(Error(GL_INVALID_OPERATION));
1986 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001987 }
1988
Jamie Madill0063c512014-08-25 15:47:53 -04001989 return true;
1990}
1991
Geoff Langb1196682014-07-23 13:47:29 -04001992bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001993{
1994 return ValidateGetUniformBase(context, program, location);
1995}
1996
Geoff Langb1196682014-07-23 13:47:29 -04001997bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001998{
Jamie Madill78f41802014-08-25 15:47:55 -04001999 return ValidateGetUniformBase(context, program, location);
2000}
2001
Geoff Langb1196682014-07-23 13:47:29 -04002002static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002003{
2004 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002005 {
Jamie Madill78f41802014-08-25 15:47:55 -04002006 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002007 }
2008
Jamie Madilla502c742014-08-28 17:19:13 -04002009 gl::Program *programObject = context->getProgram(program);
2010 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002011
Jamie Madill78f41802014-08-25 15:47:55 -04002012 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002013 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2014 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002015 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002016 {
Geoff Langb1196682014-07-23 13:47:29 -04002017 context->recordError(Error(GL_INVALID_OPERATION));
2018 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002019 }
2020
2021 return true;
2022}
2023
Geoff Langb1196682014-07-23 13:47:29 -04002024bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002025{
Jamie Madill78f41802014-08-25 15:47:55 -04002026 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002027}
2028
Geoff Langb1196682014-07-23 13:47:29 -04002029bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002030{
Jamie Madill78f41802014-08-25 15:47:55 -04002031 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002032}
2033
Austin Kinross08332632015-05-05 13:35:47 -07002034bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2035 const GLenum *attachments, bool defaultFramebuffer)
2036{
2037 if (numAttachments < 0)
2038 {
2039 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2040 return false;
2041 }
2042
2043 for (GLsizei i = 0; i < numAttachments; ++i)
2044 {
2045 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2046 {
2047 if (defaultFramebuffer)
2048 {
2049 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2050 return false;
2051 }
2052
2053 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2054 {
2055 context->recordError(Error(GL_INVALID_OPERATION,
2056 "Requested color attachment is greater than the maximum supported color attachments"));
2057 return false;
2058 }
2059 }
2060 else
2061 {
2062 switch (attachments[i])
2063 {
2064 case GL_DEPTH_ATTACHMENT:
2065 case GL_STENCIL_ATTACHMENT:
2066 case GL_DEPTH_STENCIL_ATTACHMENT:
2067 if (defaultFramebuffer)
2068 {
2069 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2070 return false;
2071 }
2072 break;
2073 case GL_COLOR:
2074 case GL_DEPTH:
2075 case GL_STENCIL:
2076 if (!defaultFramebuffer)
2077 {
2078 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2079 return false;
2080 }
2081 break;
2082 default:
2083 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2084 return false;
2085 }
2086 }
2087 }
2088
2089 return true;
2090}
2091
Austin Kinross6ee1e782015-05-29 17:05:37 -07002092bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2093{
2094 // Note that debug marker calls must not set error state
2095
2096 if (length < 0)
2097 {
2098 return false;
2099 }
2100
2101 if (marker == nullptr)
2102 {
2103 return false;
2104 }
2105
2106 return true;
2107}
2108
2109bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2110{
2111 // Note that debug marker calls must not set error state
2112
2113 if (length < 0)
2114 {
2115 return false;
2116 }
2117
2118 if (length > 0 && marker == nullptr)
2119 {
2120 return false;
2121 }
2122
2123 return true;
2124}
2125
Geoff Langdcab33b2015-07-21 13:03:16 -04002126bool ValidateEGLImageTargetTexture2DOES(Context *context,
2127 egl::Display *display,
2128 GLenum target,
2129 egl::Image *image)
2130{
Geoff Langa8406172015-07-21 16:53:39 -04002131 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2132 {
2133 context->recordError(Error(GL_INVALID_OPERATION));
2134 return false;
2135 }
2136
2137 switch (target)
2138 {
2139 case GL_TEXTURE_2D:
2140 break;
2141
2142 default:
2143 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2144 return false;
2145 }
2146
2147 if (!display->isValidImage(image))
2148 {
2149 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2150 return false;
2151 }
2152
2153 if (image->getSamples() > 0)
2154 {
2155 context->recordError(Error(GL_INVALID_OPERATION,
2156 "cannot create a 2D texture from a multisampled EGL image."));
2157 return false;
2158 }
2159
2160 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2161 if (!textureCaps.texturable)
2162 {
2163 context->recordError(Error(GL_INVALID_OPERATION,
2164 "EGL image internal format is not supported as a texture."));
2165 return false;
2166 }
2167
Geoff Langdcab33b2015-07-21 13:03:16 -04002168 return true;
2169}
2170
2171bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2172 egl::Display *display,
2173 GLenum target,
2174 egl::Image *image)
2175{
Geoff Langa8406172015-07-21 16:53:39 -04002176 if (!context->getExtensions().eglImage)
2177 {
2178 context->recordError(Error(GL_INVALID_OPERATION));
2179 return false;
2180 }
2181
2182 switch (target)
2183 {
2184 case GL_RENDERBUFFER:
2185 break;
2186
2187 default:
2188 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2189 return false;
2190 }
2191
2192 if (!display->isValidImage(image))
2193 {
2194 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2195 return false;
2196 }
2197
2198 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2199 if (!textureCaps.renderable)
2200 {
2201 context->recordError(Error(
2202 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2203 return false;
2204 }
2205
Geoff Langdcab33b2015-07-21 13:03:16 -04002206 return true;
2207}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002208
2209bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2210{
Geoff Lang36167ab2015-12-07 10:27:14 -05002211 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002212 {
2213 // The default VAO should always exist
2214 ASSERT(array != 0);
2215 context->recordError(Error(GL_INVALID_OPERATION));
2216 return false;
2217 }
2218
2219 return true;
2220}
2221
2222bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2223{
2224 if (n < 0)
2225 {
2226 context->recordError(Error(GL_INVALID_VALUE));
2227 return false;
2228 }
2229
2230 return true;
2231}
2232
2233bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2234{
2235 if (n < 0)
2236 {
2237 context->recordError(Error(GL_INVALID_VALUE));
2238 return false;
2239 }
2240
2241 return true;
2242}
Geoff Langc5629752015-12-07 16:29:04 -05002243
2244bool ValidateProgramBinaryBase(Context *context,
2245 GLuint program,
2246 GLenum binaryFormat,
2247 const void *binary,
2248 GLint length)
2249{
2250 Program *programObject = GetValidProgram(context, program);
2251 if (programObject == nullptr)
2252 {
2253 return false;
2254 }
2255
2256 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2257 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2258 programBinaryFormats.end())
2259 {
2260 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2261 return false;
2262 }
2263
2264 return true;
2265}
2266
2267bool ValidateGetProgramBinaryBase(Context *context,
2268 GLuint program,
2269 GLsizei bufSize,
2270 GLsizei *length,
2271 GLenum *binaryFormat,
2272 void *binary)
2273{
2274 Program *programObject = GetValidProgram(context, program);
2275 if (programObject == nullptr)
2276 {
2277 return false;
2278 }
2279
2280 if (!programObject->isLinked())
2281 {
2282 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2283 return false;
2284 }
2285
2286 return true;
2287}
Jamie Madillc29968b2016-01-20 11:17:23 -05002288
2289bool ValidateCopyTexImage2D(ValidationContext *context,
2290 GLenum target,
2291 GLint level,
2292 GLenum internalformat,
2293 GLint x,
2294 GLint y,
2295 GLsizei width,
2296 GLsizei height,
2297 GLint border)
2298{
2299 if (context->getClientVersion() < 3)
2300 {
2301 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
2302 0, x, y, width, height, border);
2303 }
2304
2305 ASSERT(context->getClientVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002306 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
2307 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002308}
Jamie Madillc29968b2016-01-20 11:17:23 -05002309
2310bool ValidateFramebufferRenderbuffer(Context *context,
2311 GLenum target,
2312 GLenum attachment,
2313 GLenum renderbuffertarget,
2314 GLuint renderbuffer)
2315{
2316 if (!ValidFramebufferTarget(target) ||
2317 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
2318 {
2319 context->recordError(Error(GL_INVALID_ENUM));
2320 return false;
2321 }
2322
2323 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
2324 renderbuffertarget, renderbuffer);
2325}
2326
2327bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
2328{
2329 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
2330 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
2331 {
2332 context->recordError(
2333 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
2334 return false;
2335 }
2336
2337 ASSERT(context->getState().getDrawFramebuffer());
2338 GLuint frameBufferId = context->getState().getDrawFramebuffer()->id();
2339 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
2340
2341 // This should come first before the check for the default frame buffer
2342 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
2343 // rather than INVALID_OPERATION
2344 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
2345 {
2346 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
2347
2348 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
2349 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0_EXT ||
2350 bufs[colorAttachment] >= maxColorAttachment))
2351 {
2352 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
2353 // In the 3.0 specs, the error should return GL_INVALID_OPERATION.
2354 // When we move to 3.1 specs, we should change the error to be GL_INVALID_ENUM
2355 context->recordError(Error(GL_INVALID_OPERATION, "Invalid buffer value"));
2356 return false;
2357 }
2358 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
2359 frameBufferId != 0)
2360 {
2361 // INVALID_OPERATION-GL is bound to buffer and ith argument
2362 // is not COLOR_ATTACHMENTi or NONE
2363 context->recordError(
2364 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
2365 return false;
2366 }
2367 }
2368
2369 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
2370 // and n is not 1 or bufs is bound to value other than BACK and NONE
2371 if (frameBufferId == 0)
2372 {
2373 if (n != 1)
2374 {
2375 context->recordError(Error(GL_INVALID_OPERATION,
2376 "n must be 1 when GL is bound to the default framebuffer"));
2377 return false;
2378 }
2379
2380 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
2381 {
2382 context->recordError(Error(
2383 GL_INVALID_OPERATION,
2384 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
2385 return false;
2386 }
2387 }
2388
2389 return true;
2390}
2391
2392bool ValidateCopyTexSubImage2D(Context *context,
2393 GLenum target,
2394 GLint level,
2395 GLint xoffset,
2396 GLint yoffset,
2397 GLint x,
2398 GLint y,
2399 GLsizei width,
2400 GLsizei height)
2401{
2402 if (context->getClientVersion() < 3)
2403 {
2404 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
2405 yoffset, x, y, width, height, 0);
2406 }
2407
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05002408 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
2409 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05002410}
2411
2412} // namespace gl