blob: e9cd516520e259d51fd3777002b8072143408281 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
112 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
113 case GL_RASTERIZER_DISCARD:
114 return (context->getClientVersion() >= 3);
115 default:
116 return false;
117 }
118}
119
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500120bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121{
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400123 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500124 case GL_TEXTURE_2D:
125 case GL_TEXTURE_CUBE_MAP:
126 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400127
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 case GL_TEXTURE_3D:
129 case GL_TEXTURE_2D_ARRAY:
130 return (context->getClientVersion() >= 3);
131
132 default:
133 return false;
134 }
Jamie Madill35d15012013-10-07 10:46:37 -0400135}
136
Shannon Woods4dfed832014-03-17 20:03:39 -0400137// This function differs from ValidTextureTarget in that the target must be
138// usable as the destination of a 2D operation-- so a cube face is valid, but
139// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400140// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400141bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
142{
143 switch (target)
144 {
145 case GL_TEXTURE_2D:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
150 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
151 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
152 return true;
153 case GL_TEXTURE_2D_ARRAY:
154 case GL_TEXTURE_3D:
155 return (context->getClientVersion() >= 3);
156 default:
157 return false;
158 }
159}
160
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500161bool ValidFramebufferTarget(GLenum target)
162{
Geoff Langd4475812015-03-18 10:53:05 -0400163 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
164 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500165
166 switch (target)
167 {
168 case GL_FRAMEBUFFER: return true;
169 case GL_READ_FRAMEBUFFER: return true;
170 case GL_DRAW_FRAMEBUFFER: return true;
171 default: return false;
172 }
173}
174
Jamie Madill8c96d582014-03-05 15:01:23 -0500175bool ValidBufferTarget(const Context *context, GLenum target)
176{
177 switch (target)
178 {
179 case GL_ARRAY_BUFFER:
180 case GL_ELEMENT_ARRAY_BUFFER:
181 return true;
182
Jamie Madill8c96d582014-03-05 15:01:23 -0500183 case GL_PIXEL_PACK_BUFFER:
184 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400185 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400186
Shannon Woodsb3801742014-03-27 14:59:19 -0400187 case GL_COPY_READ_BUFFER:
188 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500189 case GL_TRANSFORM_FEEDBACK_BUFFER:
190 case GL_UNIFORM_BUFFER:
191 return (context->getClientVersion() >= 3);
192
193 default:
194 return false;
195 }
196}
197
Jamie Madill70656a62014-03-05 15:01:26 -0500198bool ValidBufferParameter(const Context *context, GLenum pname)
199{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400200 const Extensions &extensions = context->getExtensions();
201
Jamie Madill70656a62014-03-05 15:01:26 -0500202 switch (pname)
203 {
204 case GL_BUFFER_USAGE:
205 case GL_BUFFER_SIZE:
206 return true;
207
Geoff Langcc6f55d2015-03-20 13:01:02 -0400208 case GL_BUFFER_ACCESS_OES:
209 return extensions.mapBuffer;
210
211 case GL_BUFFER_MAPPED:
212 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
213 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
214
Jamie Madill70656a62014-03-05 15:01:26 -0500215 // GL_BUFFER_MAP_POINTER is a special case, and may only be
216 // queried with GetBufferPointerv
217 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500218 case GL_BUFFER_MAP_OFFSET:
219 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400220 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500221
222 default:
223 return false;
224 }
225}
226
Jamie Madill8c96d582014-03-05 15:01:23 -0500227bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400228{
Geoff Langaae65a42014-05-26 12:43:44 -0400229 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400230 switch (target)
231 {
Geoff Langaae65a42014-05-26 12:43:44 -0400232 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400233 case GL_TEXTURE_CUBE_MAP:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
238 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400239 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
240 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
241 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400242 default: UNREACHABLE();
243 }
244
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700245 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400246}
247
Austin Kinross08528e12015-10-07 16:24:40 -0700248bool ValidImageSizeParameters(const Context *context,
249 GLenum target,
250 GLint level,
251 GLsizei width,
252 GLsizei height,
253 GLsizei depth,
254 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400255{
256 if (level < 0 || width < 0 || height < 0 || depth < 0)
257 {
258 return false;
259 }
260
Austin Kinross08528e12015-10-07 16:24:40 -0700261 // TexSubImage parameters can be NPOT without textureNPOT extension,
262 // as long as the destination texture is POT.
263 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400264 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400265 {
266 return false;
267 }
268
269 if (!ValidMipLevel(context, target, level))
270 {
271 return false;
272 }
273
274 return true;
275}
276
Geoff Lang0d8b7242015-09-09 14:56:53 -0400277bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
278{
279 // List of compressed format that require that the texture size is smaller than or a multiple of
280 // the compressed block size.
281 switch (internalFormat)
282 {
283 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
284 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
285 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
286 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
287 return true;
288
289 default:
290 return false;
291 }
292}
293
Geoff Langb1196682014-07-23 13:47:29 -0400294bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400295{
Geoff Lang5d601382014-07-22 15:14:06 -0400296 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
297 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400298 {
299 return false;
300 }
301
Geoff Lang0d8b7242015-09-09 14:56:53 -0400302 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400303 {
304 return false;
305 }
306
Geoff Lang0d8b7242015-09-09 14:56:53 -0400307 if (CompressedTextureFormatRequiresExactSize(internalFormat))
308 {
309 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
310 width % formatInfo.compressedBlockWidth != 0) ||
311 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
312 height % formatInfo.compressedBlockHeight != 0))
313 {
314 return false;
315 }
316 }
317
Geoff Langd4f180b2013-09-24 13:57:44 -0400318 return true;
319}
320
Geoff Lang37dde692014-01-31 16:34:54 -0500321bool ValidQueryType(const Context *context, GLenum queryType)
322{
Geoff Langd4475812015-03-18 10:53:05 -0400323 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
324 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500325
326 switch (queryType)
327 {
328 case GL_ANY_SAMPLES_PASSED:
329 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
330 return true;
331 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
332 return (context->getClientVersion() >= 3);
333 default:
334 return false;
335 }
336}
337
Dian Xiang769769a2015-09-09 15:20:08 -0700338Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500339{
340 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
341 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
342 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
343
Dian Xiang769769a2015-09-09 15:20:08 -0700344 Program *validProgram = context->getProgram(id);
345
346 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500347 {
Dian Xiang769769a2015-09-09 15:20:08 -0700348 if (context->getShader(id))
349 {
350 context->recordError(
351 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
352 }
353 else
354 {
355 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
356 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500357 }
Dian Xiang769769a2015-09-09 15:20:08 -0700358
359 return validProgram;
360}
361
362Shader *GetValidShader(Context *context, GLuint id)
363{
364 // See ValidProgram for spec details.
365
366 Shader *validShader = context->getShader(id);
367
368 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500369 {
Dian Xiang769769a2015-09-09 15:20:08 -0700370 if (context->getProgram(id))
371 {
372 context->recordError(
373 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
374 }
375 else
376 {
377 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
378 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500379 }
Dian Xiang769769a2015-09-09 15:20:08 -0700380
381 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500382}
383
Geoff Langb1196682014-07-23 13:47:29 -0400384bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400385{
386 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
387 {
388 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
389
Geoff Langaae65a42014-05-26 12:43:44 -0400390 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400391 {
Geoff Langb1196682014-07-23 13:47:29 -0400392 context->recordError(Error(GL_INVALID_VALUE));
393 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400394 }
395 }
396 else
397 {
398 switch (attachment)
399 {
400 case GL_DEPTH_ATTACHMENT:
401 case GL_STENCIL_ATTACHMENT:
402 break;
403
404 case GL_DEPTH_STENCIL_ATTACHMENT:
405 if (context->getClientVersion() < 3)
406 {
Geoff Langb1196682014-07-23 13:47:29 -0400407 context->recordError(Error(GL_INVALID_ENUM));
408 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400409 }
410 break;
411
412 default:
Geoff Langb1196682014-07-23 13:47:29 -0400413 context->recordError(Error(GL_INVALID_ENUM));
414 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400415 }
416 }
417
418 return true;
419}
420
Corentin Walleze0902642014-11-04 12:32:15 -0800421bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
422 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423{
424 switch (target)
425 {
426 case GL_RENDERBUFFER:
427 break;
428 default:
Geoff Langb1196682014-07-23 13:47:29 -0400429 context->recordError(Error(GL_INVALID_ENUM));
430 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400431 }
432
433 if (width < 0 || height < 0 || samples < 0)
434 {
Geoff Langb1196682014-07-23 13:47:29 -0400435 context->recordError(Error(GL_INVALID_VALUE));
436 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400437 }
438
Geoff Langd87878e2014-09-19 15:42:59 -0400439 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
440 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400441 {
Geoff Langb1196682014-07-23 13:47:29 -0400442 context->recordError(Error(GL_INVALID_ENUM));
443 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 }
445
446 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
447 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800448 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400449 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400450 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400451 {
Geoff Langb1196682014-07-23 13:47:29 -0400452 context->recordError(Error(GL_INVALID_ENUM));
453 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400454 }
455
Geoff Langaae65a42014-05-26 12:43:44 -0400456 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 {
Geoff Langb1196682014-07-23 13:47:29 -0400458 context->recordError(Error(GL_INVALID_VALUE));
459 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400460 }
461
Shannon Woods53a94a82014-06-24 15:20:36 -0400462 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 if (handle == 0)
464 {
Geoff Langb1196682014-07-23 13:47:29 -0400465 context->recordError(Error(GL_INVALID_OPERATION));
466 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400467 }
468
469 return true;
470}
471
Corentin Walleze0902642014-11-04 12:32:15 -0800472bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
473 GLenum internalformat, GLsizei width, GLsizei height)
474{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800475 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800476
477 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400478 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800479 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400480 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800481 {
482 context->recordError(Error(GL_INVALID_VALUE));
483 return false;
484 }
485
486 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
487 // the specified storage. This is different than ES 3.0 in which a sample number higher
488 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800489 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
490 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800491 {
Geoff Langa4903b72015-03-02 16:02:48 -0800492 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
493 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
494 {
495 context->recordError(Error(GL_OUT_OF_MEMORY));
496 return false;
497 }
Corentin Walleze0902642014-11-04 12:32:15 -0800498 }
499
500 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
501}
502
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500503bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
504 GLenum renderbuffertarget, GLuint renderbuffer)
505{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400506 if (!ValidFramebufferTarget(target))
507 {
Geoff Langb1196682014-07-23 13:47:29 -0400508 context->recordError(Error(GL_INVALID_ENUM));
509 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400510 }
511
Shannon Woods53a94a82014-06-24 15:20:36 -0400512 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500513
Jamie Madill84115c92015-04-23 15:00:07 -0400514 ASSERT(framebuffer);
515 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500516 {
Jamie Madill84115c92015-04-23 15:00:07 -0400517 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400518 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500519 }
520
Jamie Madillb4472272014-07-03 10:38:55 -0400521 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500522 {
Jamie Madillb4472272014-07-03 10:38:55 -0400523 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500524 }
525
Jamie Madillab9d82c2014-01-21 16:38:14 -0500526 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
527 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
528 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
529 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
530 if (renderbuffer != 0)
531 {
532 if (!context->getRenderbuffer(renderbuffer))
533 {
Geoff Langb1196682014-07-23 13:47:29 -0400534 context->recordError(Error(GL_INVALID_OPERATION));
535 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500536 }
537 }
538
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500539 return true;
540}
541
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400542static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400543 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
544 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
545{
Jamie Madill6b120b92015-11-24 13:00:07 -0500546 const Extents &writeSize = writeBuffer->getSize();
547 const Extents &readSize = readBuffer->getSize();
548
549 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width ||
550 dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height)
Geoff Lang125deab2013-08-09 13:34:16 -0400551 {
552 return true;
553 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400554 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400555 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400556 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400557
Jamie Madill6b120b92015-11-24 13:00:07 -0500558 return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
559 scissor.height < writeSize.height;
Geoff Lang125deab2013-08-09 13:34:16 -0400560 }
561 else
562 {
563 return false;
564 }
565}
566
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400567bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400568 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
569 GLenum filter, bool fromAngleExtension)
570{
571 switch (filter)
572 {
573 case GL_NEAREST:
574 break;
575 case GL_LINEAR:
576 if (fromAngleExtension)
577 {
Geoff Langb1196682014-07-23 13:47:29 -0400578 context->recordError(Error(GL_INVALID_ENUM));
579 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400580 }
581 break;
582 default:
Geoff Langb1196682014-07-23 13:47:29 -0400583 context->recordError(Error(GL_INVALID_ENUM));
584 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400585 }
586
587 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
588 {
Geoff Langb1196682014-07-23 13:47:29 -0400589 context->recordError(Error(GL_INVALID_VALUE));
590 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400591 }
592
593 if (mask == 0)
594 {
595 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
596 // buffers are copied.
597 return false;
598 }
599
600 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
601 {
602 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400603 context->recordError(Error(GL_INVALID_OPERATION));
604 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605 }
606
607 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
608 // color buffer, leaving only nearest being unfiltered from above
609 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
610 {
Geoff Langb1196682014-07-23 13:47:29 -0400611 context->recordError(Error(GL_INVALID_OPERATION));
612 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613 }
614
Shannon Woods53a94a82014-06-24 15:20:36 -0400615 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 {
617 if (fromAngleExtension)
618 {
619 ERR("Blits with the same source and destination framebuffer are not supported by this "
620 "implementation.");
621 }
Geoff Langb1196682014-07-23 13:47:29 -0400622 context->recordError(Error(GL_INVALID_OPERATION));
623 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 }
625
Jamie Madille3ef7152015-04-28 16:55:17 +0000626 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
627 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500628
629 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 {
Geoff Langb1196682014-07-23 13:47:29 -0400631 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
632 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 }
634
Geoff Lang748f74e2014-12-01 11:25:34 -0500635 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500636 {
637 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
638 return false;
639 }
640
Geoff Lang748f74e2014-12-01 11:25:34 -0500641 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500642 {
643 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
644 return false;
645 }
646
647 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400648 {
Geoff Langb1196682014-07-23 13:47:29 -0400649 context->recordError(Error(GL_INVALID_OPERATION));
650 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 }
652
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
654
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 if (mask & GL_COLOR_BUFFER_BIT)
656 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400657 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
658 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500659 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400660
661 if (readColorBuffer && drawColorBuffer)
662 {
Geoff Langd8a22582014-12-17 15:28:23 -0500663 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400664 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665
Corentin Wallez37c39792015-08-20 14:19:46 -0400666 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 {
668 if (drawFramebuffer->isEnabledColorAttachment(i))
669 {
Geoff Langd8a22582014-12-17 15:28:23 -0500670 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400671 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672
Geoff Langb2f3d052013-08-13 12:49:27 -0400673 // The GL ES 3.0.2 spec (pg 193) states that:
674 // 1) If the read buffer is fixed point format, the draw buffer must be as well
675 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
676 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500677 // Changes with EXT_color_buffer_float:
678 // Case 1) is changed to fixed point OR floating point
679 GLenum readComponentType = readFormatInfo.componentType;
680 GLenum drawComponentType = drawFormatInfo.componentType;
681 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
682 readComponentType == GL_SIGNED_NORMALIZED);
683 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
684 drawComponentType == GL_SIGNED_NORMALIZED);
685
686 if (extensions.colorBufferFloat)
687 {
688 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
689 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
690
691 if (readFixedOrFloat != drawFixedOrFloat)
692 {
693 context->recordError(Error(GL_INVALID_OPERATION,
694 "If the read buffer contains fixed-point or "
695 "floating-point values, the draw buffer "
696 "must as well."));
697 return false;
698 }
699 }
700 else if (readFixedPoint != drawFixedPoint)
701 {
702 context->recordError(Error(GL_INVALID_OPERATION,
703 "If the read buffer contains fixed-point "
704 "values, the draw buffer must as well."));
705 return false;
706 }
707
708 if (readComponentType == GL_UNSIGNED_INT &&
709 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710 {
Geoff Langb1196682014-07-23 13:47:29 -0400711 context->recordError(Error(GL_INVALID_OPERATION));
712 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713 }
714
Jamie Madill6163c752015-12-07 16:32:59 -0500715 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716 {
Geoff Langb1196682014-07-23 13:47:29 -0400717 context->recordError(Error(GL_INVALID_OPERATION));
718 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 }
720
Geoff Langb2f3d052013-08-13 12:49:27 -0400721 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722 {
Geoff Langb1196682014-07-23 13:47:29 -0400723 context->recordError(Error(GL_INVALID_OPERATION));
724 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400725 }
726 }
727 }
728
Geoff Lang5d601382014-07-22 15:14:06 -0400729 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400730 {
Geoff Langb1196682014-07-23 13:47:29 -0400731 context->recordError(Error(GL_INVALID_OPERATION));
732 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400733 }
734
735 if (fromAngleExtension)
736 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400737 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500738 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400739 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500740 readColorAttachment->type() != GL_RENDERBUFFER &&
741 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400742 {
Geoff Langb1196682014-07-23 13:47:29 -0400743 context->recordError(Error(GL_INVALID_OPERATION));
744 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400745 }
746
Corentin Wallez37c39792015-08-20 14:19:46 -0400747 for (size_t colorAttachment = 0;
748 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400749 {
750 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
751 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000752 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400753 ASSERT(attachment);
754
Jamie Madill8cf4a392015-04-02 11:36:04 -0400755 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500756 attachment->type() != GL_RENDERBUFFER &&
757 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400758 {
Geoff Langb1196682014-07-23 13:47:29 -0400759 context->recordError(Error(GL_INVALID_OPERATION));
760 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 }
762
Jamie Madillf8f18f02014-10-02 10:44:17 -0400763 // Return an error if the destination formats do not match
764 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 {
Geoff Langb1196682014-07-23 13:47:29 -0400766 context->recordError(Error(GL_INVALID_OPERATION));
767 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 }
769 }
770 }
Jamie Madill48faf802014-11-06 15:27:22 -0500771
772 int readSamples = readFramebuffer->getSamples(context->getData());
773
774 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
775 srcX0, srcY0, srcX1, srcY1,
776 dstX0, dstY0, dstX1, dstY1))
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
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200785 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
786 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
787 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400788 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200789 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400791 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
792 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400793
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200794 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 {
Geoff Langd8a22582014-12-17 15:28:23 -0500796 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 {
Geoff Langb1196682014-07-23 13:47:29 -0400798 context->recordError(Error(GL_INVALID_OPERATION));
799 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200802 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803 {
Geoff Langb1196682014-07-23 13:47:29 -0400804 context->recordError(Error(GL_INVALID_OPERATION));
805 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200807
808 if (fromAngleExtension)
809 {
810 if (IsPartialBlit(context, readBuffer, drawBuffer,
811 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
812 {
813 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
814 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
815 return false;
816 }
817
818 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
819 {
820 context->recordError(Error(GL_INVALID_OPERATION));
821 return false;
822 }
823 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400824 }
825 }
826 }
827
828 return true;
829}
830
Geoff Langb1196682014-07-23 13:47:29 -0400831bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400832{
833 switch (pname)
834 {
835 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
836 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
837 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
838 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
839 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
840 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
841 case GL_CURRENT_VERTEX_ATTRIB:
842 return true;
843
844 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
845 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
846 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400847 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
848 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400849 return true;
850
851 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400852 if (context->getClientVersion() < 3)
853 {
854 context->recordError(Error(GL_INVALID_ENUM));
855 return false;
856 }
857 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400858
859 default:
Geoff Langb1196682014-07-23 13:47:29 -0400860 context->recordError(Error(GL_INVALID_ENUM));
861 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400862 }
863}
864
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400865bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400866{
867 switch (pname)
868 {
869 case GL_TEXTURE_WRAP_R:
870 case GL_TEXTURE_SWIZZLE_R:
871 case GL_TEXTURE_SWIZZLE_G:
872 case GL_TEXTURE_SWIZZLE_B:
873 case GL_TEXTURE_SWIZZLE_A:
874 case GL_TEXTURE_BASE_LEVEL:
875 case GL_TEXTURE_MAX_LEVEL:
876 case GL_TEXTURE_COMPARE_MODE:
877 case GL_TEXTURE_COMPARE_FUNC:
878 case GL_TEXTURE_MIN_LOD:
879 case GL_TEXTURE_MAX_LOD:
880 if (context->getClientVersion() < 3)
881 {
Geoff Langb1196682014-07-23 13:47:29 -0400882 context->recordError(Error(GL_INVALID_ENUM));
883 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400884 }
885 break;
886
887 default: break;
888 }
889
890 switch (pname)
891 {
892 case GL_TEXTURE_WRAP_S:
893 case GL_TEXTURE_WRAP_T:
894 case GL_TEXTURE_WRAP_R:
895 switch (param)
896 {
897 case GL_REPEAT:
898 case GL_CLAMP_TO_EDGE:
899 case GL_MIRRORED_REPEAT:
900 return true;
901 default:
Geoff Langb1196682014-07-23 13:47:29 -0400902 context->recordError(Error(GL_INVALID_ENUM));
903 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400904 }
905
906 case GL_TEXTURE_MIN_FILTER:
907 switch (param)
908 {
909 case GL_NEAREST:
910 case GL_LINEAR:
911 case GL_NEAREST_MIPMAP_NEAREST:
912 case GL_LINEAR_MIPMAP_NEAREST:
913 case GL_NEAREST_MIPMAP_LINEAR:
914 case GL_LINEAR_MIPMAP_LINEAR:
915 return true;
916 default:
Geoff Langb1196682014-07-23 13:47:29 -0400917 context->recordError(Error(GL_INVALID_ENUM));
918 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400919 }
920 break;
921
922 case GL_TEXTURE_MAG_FILTER:
923 switch (param)
924 {
925 case GL_NEAREST:
926 case GL_LINEAR:
927 return true;
928 default:
Geoff Langb1196682014-07-23 13:47:29 -0400929 context->recordError(Error(GL_INVALID_ENUM));
930 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400931 }
932 break;
933
934 case GL_TEXTURE_USAGE_ANGLE:
935 switch (param)
936 {
937 case GL_NONE:
938 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
939 return true;
940 default:
Geoff Langb1196682014-07-23 13:47:29 -0400941 context->recordError(Error(GL_INVALID_ENUM));
942 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 }
944 break;
945
946 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400947 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400948 {
Geoff Langb1196682014-07-23 13:47:29 -0400949 context->recordError(Error(GL_INVALID_ENUM));
950 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400951 }
952
953 // we assume the parameter passed to this validation method is truncated, not rounded
954 if (param < 1)
955 {
Geoff Langb1196682014-07-23 13:47:29 -0400956 context->recordError(Error(GL_INVALID_VALUE));
957 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400958 }
959 return true;
960
961 case GL_TEXTURE_MIN_LOD:
962 case GL_TEXTURE_MAX_LOD:
963 // any value is permissible
964 return true;
965
966 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400967 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400968 switch (param)
969 {
970 case GL_NONE:
971 case GL_COMPARE_REF_TO_TEXTURE:
972 return true;
973 default:
Geoff Langb1196682014-07-23 13:47:29 -0400974 context->recordError(Error(GL_INVALID_ENUM));
975 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400976 }
977 break;
978
979 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400980 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400981 switch (param)
982 {
983 case GL_LEQUAL:
984 case GL_GEQUAL:
985 case GL_LESS:
986 case GL_GREATER:
987 case GL_EQUAL:
988 case GL_NOTEQUAL:
989 case GL_ALWAYS:
990 case GL_NEVER:
991 return true;
992 default:
Geoff Langb1196682014-07-23 13:47:29 -0400993 context->recordError(Error(GL_INVALID_ENUM));
994 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400995 }
996 break;
997
998 case GL_TEXTURE_SWIZZLE_R:
999 case GL_TEXTURE_SWIZZLE_G:
1000 case GL_TEXTURE_SWIZZLE_B:
1001 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001002 switch (param)
1003 {
1004 case GL_RED:
1005 case GL_GREEN:
1006 case GL_BLUE:
1007 case GL_ALPHA:
1008 case GL_ZERO:
1009 case GL_ONE:
1010 return true;
1011 default:
Geoff Langb1196682014-07-23 13:47:29 -04001012 context->recordError(Error(GL_INVALID_ENUM));
1013 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001014 }
1015 break;
1016
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001017 case GL_TEXTURE_BASE_LEVEL:
1018 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -04001019 if (param < 0)
1020 {
Geoff Langb1196682014-07-23 13:47:29 -04001021 context->recordError(Error(GL_INVALID_VALUE));
1022 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -04001023 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001024 return true;
1025
1026 default:
Geoff Langb1196682014-07-23 13:47:29 -04001027 context->recordError(Error(GL_INVALID_ENUM));
1028 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001029 }
1030}
1031
Geoff Langb1196682014-07-23 13:47:29 -04001032bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001033{
1034 switch (pname)
1035 {
1036 case GL_TEXTURE_MIN_FILTER:
1037 case GL_TEXTURE_MAG_FILTER:
1038 case GL_TEXTURE_WRAP_S:
1039 case GL_TEXTURE_WRAP_T:
1040 case GL_TEXTURE_WRAP_R:
1041 case GL_TEXTURE_MIN_LOD:
1042 case GL_TEXTURE_MAX_LOD:
1043 case GL_TEXTURE_COMPARE_MODE:
1044 case GL_TEXTURE_COMPARE_FUNC:
1045 return true;
1046
1047 default:
Geoff Langb1196682014-07-23 13:47:29 -04001048 context->recordError(Error(GL_INVALID_ENUM));
1049 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001050 }
1051}
1052
Jamie Madill26e91952014-03-05 15:01:27 -05001053bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
1054 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
1055{
Shannon Woods53a94a82014-06-24 15:20:36 -04001056 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001057 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001058
Geoff Lang748f74e2014-12-01 11:25:34 -05001059 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001060 {
Geoff Langb1196682014-07-23 13:47:29 -04001061 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1062 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001063 }
1064
Jamie Madill48faf802014-11-06 15:27:22 -05001065 if (context->getState().getReadFramebuffer()->id() != 0 &&
1066 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001067 {
Geoff Langb1196682014-07-23 13:47:29 -04001068 context->recordError(Error(GL_INVALID_OPERATION));
1069 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001070 }
1071
Geoff Langbce529e2014-12-01 12:48:41 -05001072 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1073 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001074 {
Geoff Langb1196682014-07-23 13:47:29 -04001075 context->recordError(Error(GL_INVALID_OPERATION));
1076 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001077 }
1078
Geoff Langbce529e2014-12-01 12:48:41 -05001079 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1080 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001081 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001082 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001083
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001084 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1085 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001086
1087 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1088 {
Geoff Langb1196682014-07-23 13:47:29 -04001089 context->recordError(Error(GL_INVALID_OPERATION));
1090 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001091 }
1092
Geoff Lang5d601382014-07-22 15:14:06 -04001093 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1094 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001095
Minmin Gongadff67b2015-10-14 10:34:45 -04001096 GLsizei outputPitch =
1097 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1098 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001099 // sized query sanity check
1100 if (bufSize)
1101 {
1102 int requiredSize = outputPitch * height;
1103 if (requiredSize > *bufSize)
1104 {
Geoff Langb1196682014-07-23 13:47:29 -04001105 context->recordError(Error(GL_INVALID_OPERATION));
1106 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001107 }
1108 }
1109
1110 return true;
1111}
1112
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001113bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1114{
1115 if (!ValidQueryType(context, target))
1116 {
Geoff Langb1196682014-07-23 13:47:29 -04001117 context->recordError(Error(GL_INVALID_ENUM));
1118 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001119 }
1120
1121 if (id == 0)
1122 {
Geoff Langb1196682014-07-23 13:47:29 -04001123 context->recordError(Error(GL_INVALID_OPERATION));
1124 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001125 }
1126
1127 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1128 // of zero, if the active query object name for <target> is non-zero (for the
1129 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1130 // the active query for either target is non-zero), if <id> is the name of an
1131 // existing query object whose type does not match <target>, or if <id> is the
1132 // active query object name for any query type, the error INVALID_OPERATION is
1133 // generated.
1134
1135 // Ensure no other queries are active
1136 // NOTE: If other queries than occlusion are supported, we will need to check
1137 // separately that:
1138 // a) The query ID passed is not the current active query for any target/type
1139 // b) There are no active queries for the requested target (and in the case
1140 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1141 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001142 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001143 {
Geoff Langb1196682014-07-23 13:47:29 -04001144 context->recordError(Error(GL_INVALID_OPERATION));
1145 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001146 }
1147
1148 Query *queryObject = context->getQuery(id, true, target);
1149
1150 // check that name was obtained with glGenQueries
1151 if (!queryObject)
1152 {
Geoff Langb1196682014-07-23 13:47:29 -04001153 context->recordError(Error(GL_INVALID_OPERATION));
1154 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001155 }
1156
1157 // check for type mismatch
1158 if (queryObject->getType() != target)
1159 {
Geoff Langb1196682014-07-23 13:47:29 -04001160 context->recordError(Error(GL_INVALID_OPERATION));
1161 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001162 }
1163
1164 return true;
1165}
1166
Jamie Madill45c785d2014-05-13 14:09:34 -04001167bool ValidateEndQuery(gl::Context *context, GLenum target)
1168{
1169 if (!ValidQueryType(context, target))
1170 {
Geoff Langb1196682014-07-23 13:47:29 -04001171 context->recordError(Error(GL_INVALID_ENUM));
1172 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001173 }
1174
Shannon Woods53a94a82014-06-24 15:20:36 -04001175 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001176
1177 if (queryObject == NULL)
1178 {
Geoff Langb1196682014-07-23 13:47:29 -04001179 context->recordError(Error(GL_INVALID_OPERATION));
1180 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001181 }
1182
Jamie Madill45c785d2014-05-13 14:09:34 -04001183 return true;
1184}
1185
Jamie Madill62d31cb2015-09-11 13:25:51 -04001186static bool ValidateUniformCommonBase(gl::Context *context,
1187 GLenum targetUniformType,
1188 GLint location,
1189 GLsizei count,
1190 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001191{
1192 if (count < 0)
1193 {
Geoff Langb1196682014-07-23 13:47:29 -04001194 context->recordError(Error(GL_INVALID_VALUE));
1195 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001196 }
1197
Geoff Lang7dd2e102014-11-10 15:19:26 -05001198 gl::Program *program = context->getState().getProgram();
1199 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001200 {
Geoff Langb1196682014-07-23 13:47:29 -04001201 context->recordError(Error(GL_INVALID_OPERATION));
1202 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001203 }
1204
1205 if (location == -1)
1206 {
1207 // Silently ignore the uniform command
1208 return false;
1209 }
1210
Geoff Lang7dd2e102014-11-10 15:19:26 -05001211 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001212 {
Geoff Langb1196682014-07-23 13:47:29 -04001213 context->recordError(Error(GL_INVALID_OPERATION));
1214 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001215 }
1216
Jamie Madill62d31cb2015-09-11 13:25:51 -04001217 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001218
1219 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001220 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001221 {
Geoff Langb1196682014-07-23 13:47:29 -04001222 context->recordError(Error(GL_INVALID_OPERATION));
1223 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001224 }
1225
Jamie Madill62d31cb2015-09-11 13:25:51 -04001226 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001227 return true;
1228}
1229
Jamie Madillaa981bd2014-05-20 10:55:55 -04001230bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1231{
1232 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001233 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001234 {
Geoff Langb1196682014-07-23 13:47:29 -04001235 context->recordError(Error(GL_INVALID_OPERATION));
1236 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001237 }
1238
Jamie Madill62d31cb2015-09-11 13:25:51 -04001239 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001240 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1241 {
1242 return false;
1243 }
1244
Jamie Madillf2575982014-06-25 16:04:54 -04001245 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001246 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001247 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1248 {
Geoff Langb1196682014-07-23 13:47:29 -04001249 context->recordError(Error(GL_INVALID_OPERATION));
1250 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001251 }
1252
1253 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001254}
1255
1256bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1257 GLboolean transpose)
1258{
1259 // Check for ES3 uniform entry points
1260 int rows = VariableRowCount(matrixType);
1261 int cols = VariableColumnCount(matrixType);
1262 if (rows != cols && context->getClientVersion() < 3)
1263 {
Geoff Langb1196682014-07-23 13:47:29 -04001264 context->recordError(Error(GL_INVALID_OPERATION));
1265 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001266 }
1267
1268 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1269 {
Geoff Langb1196682014-07-23 13:47:29 -04001270 context->recordError(Error(GL_INVALID_VALUE));
1271 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001272 }
1273
Jamie Madill62d31cb2015-09-11 13:25:51 -04001274 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001275 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1276 {
1277 return false;
1278 }
1279
1280 if (uniform->type != matrixType)
1281 {
Geoff Langb1196682014-07-23 13:47:29 -04001282 context->recordError(Error(GL_INVALID_OPERATION));
1283 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001284 }
1285
1286 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001287}
1288
Jamie Madill893ab082014-05-16 16:56:10 -04001289bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1290{
1291 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1292 {
Geoff Langb1196682014-07-23 13:47:29 -04001293 context->recordError(Error(GL_INVALID_ENUM));
1294 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001295 }
1296
Jamie Madill0af26e12015-03-05 19:54:33 -05001297 const Caps &caps = context->getCaps();
1298
Jamie Madill893ab082014-05-16 16:56:10 -04001299 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1300 {
1301 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1302
Jamie Madill0af26e12015-03-05 19:54:33 -05001303 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001304 {
Geoff Langb1196682014-07-23 13:47:29 -04001305 context->recordError(Error(GL_INVALID_OPERATION));
1306 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001307 }
1308 }
1309
1310 switch (pname)
1311 {
1312 case GL_TEXTURE_BINDING_2D:
1313 case GL_TEXTURE_BINDING_CUBE_MAP:
1314 case GL_TEXTURE_BINDING_3D:
1315 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001316 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001317 {
Geoff Langb1196682014-07-23 13:47:29 -04001318 context->recordError(Error(GL_INVALID_OPERATION));
1319 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001320 }
1321 break;
1322
1323 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1324 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1325 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001326 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001327 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001328 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001329 {
Geoff Langb1196682014-07-23 13:47:29 -04001330 context->recordError(Error(GL_INVALID_OPERATION));
1331 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001332 }
1333
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001334 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001335 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001336 {
Geoff Langb1196682014-07-23 13:47:29 -04001337 context->recordError(Error(GL_INVALID_OPERATION));
1338 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001339 }
1340 }
1341 break;
1342
1343 default:
1344 break;
1345 }
1346
1347 // pname is valid, but there are no parameters to return
1348 if (numParams == 0)
1349 {
1350 return false;
1351 }
1352
1353 return true;
1354}
1355
Geoff Lang831b1952015-05-05 11:02:27 -04001356bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1358 GLint border, GLenum *textureFormatOut)
1359{
1360
1361 if (!ValidTexture2DDestinationTarget(context, target))
1362 {
Geoff Langb1196682014-07-23 13:47:29 -04001363 context->recordError(Error(GL_INVALID_ENUM));
1364 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001365 }
1366
1367 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1368 {
Geoff Langb1196682014-07-23 13:47:29 -04001369 context->recordError(Error(GL_INVALID_VALUE));
1370 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001371 }
1372
1373 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1374 {
Geoff Langb1196682014-07-23 13:47:29 -04001375 context->recordError(Error(GL_INVALID_VALUE));
1376 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001377 }
1378
1379 if (border != 0)
1380 {
Geoff Langb1196682014-07-23 13:47:29 -04001381 context->recordError(Error(GL_INVALID_VALUE));
1382 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001383 }
1384
1385 if (!ValidMipLevel(context, target, level))
1386 {
Geoff Langb1196682014-07-23 13:47:29 -04001387 context->recordError(Error(GL_INVALID_VALUE));
1388 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001389 }
1390
Shannon Woods53a94a82014-06-24 15:20:36 -04001391 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001392 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001393 {
Geoff Langb1196682014-07-23 13:47:29 -04001394 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1395 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001396 }
1397
Jamie Madill48faf802014-11-06 15:27:22 -05001398 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001399 {
Geoff Langb1196682014-07-23 13:47:29 -04001400 context->recordError(Error(GL_INVALID_OPERATION));
1401 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001402 }
1403
Geoff Langaae65a42014-05-26 12:43:44 -04001404 const gl::Caps &caps = context->getCaps();
1405
Geoff Langaae65a42014-05-26 12:43:44 -04001406 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001407 switch (target)
1408 {
1409 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001410 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001411 break;
1412
1413 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1414 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1415 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1416 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1417 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1418 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001419 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001420 break;
1421
1422 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001423 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001424 break;
1425
1426 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001427 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001428 break;
1429
1430 default:
Geoff Langb1196682014-07-23 13:47:29 -04001431 context->recordError(Error(GL_INVALID_ENUM));
1432 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001433 }
1434
Geoff Lang691e58c2014-12-19 17:03:25 -05001435 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001436 if (!texture)
1437 {
Geoff Langb1196682014-07-23 13:47:29 -04001438 context->recordError(Error(GL_INVALID_OPERATION));
1439 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001440 }
1441
Geoff Lang69cce582015-09-17 13:20:36 -04001442 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001443 {
Geoff Langb1196682014-07-23 13:47:29 -04001444 context->recordError(Error(GL_INVALID_OPERATION));
1445 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001446 }
1447
Geoff Lang5d601382014-07-22 15:14:06 -04001448 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1449
1450 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001451 {
Geoff Langb1196682014-07-23 13:47:29 -04001452 context->recordError(Error(GL_INVALID_OPERATION));
1453 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001454 }
1455
Geoff Langa9be0dc2014-12-17 12:34:40 -05001456 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001457 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001458 context->recordError(Error(GL_INVALID_OPERATION));
1459 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001460 }
1461
1462 if (isSubImage)
1463 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001464 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1465 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1466 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001467 {
Geoff Langb1196682014-07-23 13:47:29 -04001468 context->recordError(Error(GL_INVALID_VALUE));
1469 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001470 }
1471 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001472 else
1473 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001474 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001475 {
Geoff Langb1196682014-07-23 13:47:29 -04001476 context->recordError(Error(GL_INVALID_VALUE));
1477 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001478 }
1479
Geoff Lang5d601382014-07-22 15:14:06 -04001480 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001481 {
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_ENUM));
1483 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001484 }
1485
1486 int maxLevelDimension = (maxDimension >> level);
1487 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1488 {
Geoff Langb1196682014-07-23 13:47:29 -04001489 context->recordError(Error(GL_INVALID_VALUE));
1490 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001491 }
1492 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001493
Geoff Langa9be0dc2014-12-17 12:34:40 -05001494 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001495 return true;
1496}
1497
Jamie Madillf25855c2015-11-03 11:06:18 -05001498static bool ValidateDrawBase(ValidationContext *context,
1499 GLenum mode,
1500 GLsizei count,
1501 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001502{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001503 switch (mode)
1504 {
1505 case GL_POINTS:
1506 case GL_LINES:
1507 case GL_LINE_LOOP:
1508 case GL_LINE_STRIP:
1509 case GL_TRIANGLES:
1510 case GL_TRIANGLE_STRIP:
1511 case GL_TRIANGLE_FAN:
1512 break;
1513 default:
Geoff Langb1196682014-07-23 13:47:29 -04001514 context->recordError(Error(GL_INVALID_ENUM));
1515 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001516 }
1517
Jamie Madill250d33f2014-06-06 17:09:03 -04001518 if (count < 0)
1519 {
Geoff Langb1196682014-07-23 13:47:29 -04001520 context->recordError(Error(GL_INVALID_VALUE));
1521 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001522 }
1523
Geoff Langb1196682014-07-23 13:47:29 -04001524 const State &state = context->getState();
1525
Jamie Madill250d33f2014-06-06 17:09:03 -04001526 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001527 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001528 {
Geoff Langb1196682014-07-23 13:47:29 -04001529 context->recordError(Error(GL_INVALID_OPERATION));
1530 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001531 }
1532
Geoff Lang3a86ad32015-09-01 11:47:05 -04001533 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001534 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001535 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1536 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1537 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1538 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1539 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1540 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1541 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001542 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001543 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1544 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001545 {
1546 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1547 // Section 6.10 of the WebGL 1.0 spec
1548 ERR(
1549 "This ANGLE implementation does not support separate front/back stencil "
1550 "writemasks, reference values, or stencil mask values.");
1551 context->recordError(Error(GL_INVALID_OPERATION));
1552 return false;
1553 }
Jamie Madillac528012014-06-20 13:21:23 -04001554 }
1555
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001556 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001557 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001558 {
Geoff Langb1196682014-07-23 13:47:29 -04001559 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1560 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001561 }
1562
Geoff Lang7dd2e102014-11-10 15:19:26 -05001563 gl::Program *program = state.getProgram();
1564 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001565 {
Geoff Langb1196682014-07-23 13:47:29 -04001566 context->recordError(Error(GL_INVALID_OPERATION));
1567 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001568 }
1569
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001571 {
Geoff Langb1196682014-07-23 13:47:29 -04001572 context->recordError(Error(GL_INVALID_OPERATION));
1573 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001574 }
1575
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001576 // Uniform buffer validation
1577 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1578 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001579 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001580 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001581 const OffsetBindingPointer<Buffer> &uniformBuffer =
1582 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001583
Geoff Lang5d124a62015-09-15 13:03:27 -04001584 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001585 {
1586 // undefined behaviour
1587 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1588 return false;
1589 }
1590
Geoff Lang5d124a62015-09-15 13:03:27 -04001591 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001592 if (uniformBufferSize == 0)
1593 {
1594 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001595 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001596 }
1597
Jamie Madill62d31cb2015-09-11 13:25:51 -04001598 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001599 {
1600 // undefined behaviour
1601 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1602 return false;
1603 }
1604 }
1605
Jamie Madill250d33f2014-06-06 17:09:03 -04001606 // No-op if zero count
1607 return (count > 0);
1608}
1609
Geoff Langb1196682014-07-23 13:47:29 -04001610bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001611{
Jamie Madillfd716582014-06-06 17:09:04 -04001612 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001613 {
Geoff Langb1196682014-07-23 13:47:29 -04001614 context->recordError(Error(GL_INVALID_VALUE));
1615 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001616 }
1617
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001618 const State &state = context->getState();
1619 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001620 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1621 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001622 {
1623 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1624 // that does not match the current transform feedback object's draw mode (if transform feedback
1625 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001626 context->recordError(Error(GL_INVALID_OPERATION));
1627 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001628 }
1629
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001630 if (!ValidateDrawBase(context, mode, count, primcount))
1631 {
1632 return false;
1633 }
1634
1635 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001636 {
1637 return false;
1638 }
1639
1640 return true;
1641}
1642
Geoff Langb1196682014-07-23 13:47:29 -04001643bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001644{
1645 if (primcount < 0)
1646 {
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_INVALID_VALUE));
1648 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001649 }
1650
Jamie Madill2b976812014-08-25 15:47:49 -04001651 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001652 {
1653 return false;
1654 }
1655
1656 // No-op if zero primitive count
1657 return (primcount > 0);
1658}
1659
Geoff Lang87a93302014-09-16 13:29:43 -04001660static bool ValidateDrawInstancedANGLE(Context *context)
1661{
1662 // Verify there is at least one active attribute with a divisor of zero
1663 const gl::State& state = context->getState();
1664
Geoff Lang7dd2e102014-11-10 15:19:26 -05001665 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001666
1667 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001668 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001669 {
1670 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001671 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001672 {
1673 return true;
1674 }
1675 }
1676
1677 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1678 "has a divisor of zero."));
1679 return false;
1680}
1681
1682bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1683{
1684 if (!ValidateDrawInstancedANGLE(context))
1685 {
1686 return false;
1687 }
1688
1689 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1690}
1691
Jamie Madillf25855c2015-11-03 11:06:18 -05001692bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001693 GLenum mode,
1694 GLsizei count,
1695 GLenum type,
1696 const GLvoid *indices,
1697 GLsizei primcount,
1698 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001699{
Jamie Madill250d33f2014-06-06 17:09:03 -04001700 switch (type)
1701 {
1702 case GL_UNSIGNED_BYTE:
1703 case GL_UNSIGNED_SHORT:
1704 break;
1705 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001706 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001707 {
Geoff Langb1196682014-07-23 13:47:29 -04001708 context->recordError(Error(GL_INVALID_ENUM));
1709 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001710 }
1711 break;
1712 default:
Geoff Langb1196682014-07-23 13:47:29 -04001713 context->recordError(Error(GL_INVALID_ENUM));
1714 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001715 }
1716
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001717 const State &state = context->getState();
1718
1719 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001720 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001721 {
1722 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1723 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001724 context->recordError(Error(GL_INVALID_OPERATION));
1725 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001726 }
1727
1728 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001729 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001730 {
Geoff Langb1196682014-07-23 13:47:29 -04001731 context->recordError(Error(GL_INVALID_OPERATION));
1732 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001733 }
1734
Jamie Madill2b976812014-08-25 15:47:49 -04001735 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001736 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001737 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001738 {
Geoff Langb1196682014-07-23 13:47:29 -04001739 context->recordError(Error(GL_INVALID_OPERATION));
1740 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001741 }
1742
Jamie Madillae3000b2014-08-25 15:47:51 -04001743 if (elementArrayBuffer)
1744 {
1745 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1746
1747 GLint64 offset = reinterpret_cast<GLint64>(indices);
1748 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1749
1750 // check for integer overflows
1751 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1752 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1753 {
Geoff Langb1196682014-07-23 13:47:29 -04001754 context->recordError(Error(GL_OUT_OF_MEMORY));
1755 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001756 }
1757
1758 // Check for reading past the end of the bound buffer object
1759 if (byteCount > elementArrayBuffer->getSize())
1760 {
Geoff Langb1196682014-07-23 13:47:29 -04001761 context->recordError(Error(GL_INVALID_OPERATION));
1762 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001763 }
1764 }
1765 else if (!indices)
1766 {
1767 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001768 context->recordError(Error(GL_INVALID_OPERATION));
1769 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001770 }
1771
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001772 if (!ValidateDrawBase(context, mode, count, primcount))
1773 {
1774 return false;
1775 }
1776
Jamie Madill2b976812014-08-25 15:47:49 -04001777 // Use max index to validate if our vertex buffers are large enough for the pull.
1778 // TODO: offer fast path, with disabled index validation.
1779 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1780 if (elementArrayBuffer)
1781 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001782 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001783 Error error =
1784 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1785 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001786 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001787 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001788 context->recordError(error);
1789 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001790 }
1791 }
1792 else
1793 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001794 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001795 }
1796
Jamie Madille79b1e12015-11-04 16:36:37 -05001797 // If we use an index greater than our maximum supported index range, return an error.
1798 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1799 // return an error if possible here.
1800 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1801 {
1802 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1803 return false;
1804 }
1805
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001806 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001807 {
1808 return false;
1809 }
1810
Geoff Lang3edfe032015-09-04 16:38:24 -04001811 // No op if there are no real indices in the index data (all are primitive restart).
1812 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001813}
1814
Geoff Langb1196682014-07-23 13:47:29 -04001815bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001816 GLenum mode,
1817 GLsizei count,
1818 GLenum type,
1819 const GLvoid *indices,
1820 GLsizei primcount,
1821 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001822{
1823 if (primcount < 0)
1824 {
Geoff Langb1196682014-07-23 13:47:29 -04001825 context->recordError(Error(GL_INVALID_VALUE));
1826 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001827 }
1828
Jamie Madill2b976812014-08-25 15:47:49 -04001829 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001830 {
1831 return false;
1832 }
1833
1834 // No-op zero primitive count
1835 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001836}
1837
Geoff Lang3edfe032015-09-04 16:38:24 -04001838bool ValidateDrawElementsInstancedANGLE(Context *context,
1839 GLenum mode,
1840 GLsizei count,
1841 GLenum type,
1842 const GLvoid *indices,
1843 GLsizei primcount,
1844 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001845{
1846 if (!ValidateDrawInstancedANGLE(context))
1847 {
1848 return false;
1849 }
1850
1851 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1852}
1853
Geoff Langb1196682014-07-23 13:47:29 -04001854bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001855 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001856{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001857 if (!ValidFramebufferTarget(target))
1858 {
Geoff Langb1196682014-07-23 13:47:29 -04001859 context->recordError(Error(GL_INVALID_ENUM));
1860 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001861 }
1862
1863 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001864 {
1865 return false;
1866 }
1867
Jamie Madill55ec3b12014-07-03 10:38:57 -04001868 if (texture != 0)
1869 {
1870 gl::Texture *tex = context->getTexture(texture);
1871
1872 if (tex == NULL)
1873 {
Geoff Langb1196682014-07-23 13:47:29 -04001874 context->recordError(Error(GL_INVALID_OPERATION));
1875 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001876 }
1877
1878 if (level < 0)
1879 {
Geoff Langb1196682014-07-23 13:47:29 -04001880 context->recordError(Error(GL_INVALID_VALUE));
1881 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001882 }
1883 }
1884
Shannon Woods53a94a82014-06-24 15:20:36 -04001885 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001886 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001887
Jamie Madill84115c92015-04-23 15:00:07 -04001888 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001889 {
Jamie Madill84115c92015-04-23 15:00:07 -04001890 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001891 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001892 }
1893
1894 return true;
1895}
1896
Geoff Langb1196682014-07-23 13:47:29 -04001897bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001898 GLenum textarget, GLuint texture, GLint level)
1899{
Geoff Lang95663912015-04-02 15:54:45 -04001900 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1901 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001902 {
Geoff Langb1196682014-07-23 13:47:29 -04001903 context->recordError(Error(GL_INVALID_VALUE));
1904 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001905 }
1906
1907 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001908 {
1909 return false;
1910 }
1911
Jamie Madill55ec3b12014-07-03 10:38:57 -04001912 if (texture != 0)
1913 {
1914 gl::Texture *tex = context->getTexture(texture);
1915 ASSERT(tex);
1916
Jamie Madill2a6564e2014-07-11 09:53:19 -04001917 const gl::Caps &caps = context->getCaps();
1918
Jamie Madill55ec3b12014-07-03 10:38:57 -04001919 switch (textarget)
1920 {
1921 case GL_TEXTURE_2D:
1922 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001923 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001924 {
Geoff Langb1196682014-07-23 13:47:29 -04001925 context->recordError(Error(GL_INVALID_VALUE));
1926 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001927 }
1928 if (tex->getTarget() != GL_TEXTURE_2D)
1929 {
Geoff Langb1196682014-07-23 13:47:29 -04001930 context->recordError(Error(GL_INVALID_OPERATION));
1931 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001932 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001933 }
1934 break;
1935
1936 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1937 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1938 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1939 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1940 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1941 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1942 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001943 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001944 {
Geoff Langb1196682014-07-23 13:47:29 -04001945 context->recordError(Error(GL_INVALID_VALUE));
1946 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001947 }
1948 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1949 {
Geoff Langb1196682014-07-23 13:47:29 -04001950 context->recordError(Error(GL_INVALID_OPERATION));
1951 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001952 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001953 }
1954 break;
1955
1956 default:
Geoff Langb1196682014-07-23 13:47:29 -04001957 context->recordError(Error(GL_INVALID_ENUM));
1958 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001959 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001960
1961 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1962 if (internalFormatInfo.compressed)
1963 {
1964 context->recordError(Error(GL_INVALID_OPERATION));
1965 return false;
1966 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001967 }
1968
Jamie Madill570f7c82014-07-03 10:38:54 -04001969 return true;
1970}
1971
Geoff Langb1196682014-07-23 13:47:29 -04001972bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001973{
1974 if (program == 0)
1975 {
Geoff Langb1196682014-07-23 13:47:29 -04001976 context->recordError(Error(GL_INVALID_VALUE));
1977 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001978 }
1979
Dian Xiang769769a2015-09-09 15:20:08 -07001980 gl::Program *programObject = GetValidProgram(context, program);
1981 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001982 {
1983 return false;
1984 }
1985
Jamie Madill0063c512014-08-25 15:47:53 -04001986 if (!programObject || !programObject->isLinked())
1987 {
Geoff Langb1196682014-07-23 13:47:29 -04001988 context->recordError(Error(GL_INVALID_OPERATION));
1989 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001990 }
1991
Geoff Lang7dd2e102014-11-10 15:19:26 -05001992 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001993 {
Geoff Langb1196682014-07-23 13:47:29 -04001994 context->recordError(Error(GL_INVALID_OPERATION));
1995 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001996 }
1997
Jamie Madill0063c512014-08-25 15:47:53 -04001998 return true;
1999}
2000
Geoff Langb1196682014-07-23 13:47:29 -04002001bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002002{
2003 return ValidateGetUniformBase(context, program, location);
2004}
2005
Geoff Langb1196682014-07-23 13:47:29 -04002006bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002007{
Jamie Madill78f41802014-08-25 15:47:55 -04002008 return ValidateGetUniformBase(context, program, location);
2009}
2010
Geoff Langb1196682014-07-23 13:47:29 -04002011static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002012{
2013 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002014 {
Jamie Madill78f41802014-08-25 15:47:55 -04002015 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002016 }
2017
Jamie Madilla502c742014-08-28 17:19:13 -04002018 gl::Program *programObject = context->getProgram(program);
2019 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002020
Jamie Madill78f41802014-08-25 15:47:55 -04002021 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002022 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2023 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002024 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002025 {
Geoff Langb1196682014-07-23 13:47:29 -04002026 context->recordError(Error(GL_INVALID_OPERATION));
2027 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002028 }
2029
2030 return true;
2031}
2032
Geoff Langb1196682014-07-23 13:47:29 -04002033bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002034{
Jamie Madill78f41802014-08-25 15:47:55 -04002035 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002036}
2037
Geoff Langb1196682014-07-23 13:47:29 -04002038bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002039{
Jamie Madill78f41802014-08-25 15:47:55 -04002040 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002041}
2042
Austin Kinross08332632015-05-05 13:35:47 -07002043bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2044 const GLenum *attachments, bool defaultFramebuffer)
2045{
2046 if (numAttachments < 0)
2047 {
2048 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2049 return false;
2050 }
2051
2052 for (GLsizei i = 0; i < numAttachments; ++i)
2053 {
2054 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2055 {
2056 if (defaultFramebuffer)
2057 {
2058 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2059 return false;
2060 }
2061
2062 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2063 {
2064 context->recordError(Error(GL_INVALID_OPERATION,
2065 "Requested color attachment is greater than the maximum supported color attachments"));
2066 return false;
2067 }
2068 }
2069 else
2070 {
2071 switch (attachments[i])
2072 {
2073 case GL_DEPTH_ATTACHMENT:
2074 case GL_STENCIL_ATTACHMENT:
2075 case GL_DEPTH_STENCIL_ATTACHMENT:
2076 if (defaultFramebuffer)
2077 {
2078 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2079 return false;
2080 }
2081 break;
2082 case GL_COLOR:
2083 case GL_DEPTH:
2084 case GL_STENCIL:
2085 if (!defaultFramebuffer)
2086 {
2087 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2088 return false;
2089 }
2090 break;
2091 default:
2092 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2093 return false;
2094 }
2095 }
2096 }
2097
2098 return true;
2099}
2100
Austin Kinross6ee1e782015-05-29 17:05:37 -07002101bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2102{
2103 // Note that debug marker calls must not set error state
2104
2105 if (length < 0)
2106 {
2107 return false;
2108 }
2109
2110 if (marker == nullptr)
2111 {
2112 return false;
2113 }
2114
2115 return true;
2116}
2117
2118bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2119{
2120 // Note that debug marker calls must not set error state
2121
2122 if (length < 0)
2123 {
2124 return false;
2125 }
2126
2127 if (length > 0 && marker == nullptr)
2128 {
2129 return false;
2130 }
2131
2132 return true;
2133}
2134
Geoff Langdcab33b2015-07-21 13:03:16 -04002135bool ValidateEGLImageTargetTexture2DOES(Context *context,
2136 egl::Display *display,
2137 GLenum target,
2138 egl::Image *image)
2139{
Geoff Langa8406172015-07-21 16:53:39 -04002140 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2141 {
2142 context->recordError(Error(GL_INVALID_OPERATION));
2143 return false;
2144 }
2145
2146 switch (target)
2147 {
2148 case GL_TEXTURE_2D:
2149 break;
2150
2151 default:
2152 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2153 return false;
2154 }
2155
2156 if (!display->isValidImage(image))
2157 {
2158 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2159 return false;
2160 }
2161
2162 if (image->getSamples() > 0)
2163 {
2164 context->recordError(Error(GL_INVALID_OPERATION,
2165 "cannot create a 2D texture from a multisampled EGL image."));
2166 return false;
2167 }
2168
2169 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2170 if (!textureCaps.texturable)
2171 {
2172 context->recordError(Error(GL_INVALID_OPERATION,
2173 "EGL image internal format is not supported as a texture."));
2174 return false;
2175 }
2176
Geoff Langdcab33b2015-07-21 13:03:16 -04002177 return true;
2178}
2179
2180bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2181 egl::Display *display,
2182 GLenum target,
2183 egl::Image *image)
2184{
Geoff Langa8406172015-07-21 16:53:39 -04002185 if (!context->getExtensions().eglImage)
2186 {
2187 context->recordError(Error(GL_INVALID_OPERATION));
2188 return false;
2189 }
2190
2191 switch (target)
2192 {
2193 case GL_RENDERBUFFER:
2194 break;
2195
2196 default:
2197 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2198 return false;
2199 }
2200
2201 if (!display->isValidImage(image))
2202 {
2203 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2204 return false;
2205 }
2206
2207 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2208 if (!textureCaps.renderable)
2209 {
2210 context->recordError(Error(
2211 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2212 return false;
2213 }
2214
Geoff Langdcab33b2015-07-21 13:03:16 -04002215 return true;
2216}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002217
2218bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2219{
Geoff Lang36167ab2015-12-07 10:27:14 -05002220 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002221 {
2222 // The default VAO should always exist
2223 ASSERT(array != 0);
2224 context->recordError(Error(GL_INVALID_OPERATION));
2225 return false;
2226 }
2227
2228 return true;
2229}
2230
2231bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2232{
2233 if (n < 0)
2234 {
2235 context->recordError(Error(GL_INVALID_VALUE));
2236 return false;
2237 }
2238
2239 return true;
2240}
2241
2242bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2243{
2244 if (n < 0)
2245 {
2246 context->recordError(Error(GL_INVALID_VALUE));
2247 return false;
2248 }
2249
2250 return true;
2251}
Geoff Langc5629752015-12-07 16:29:04 -05002252
2253bool ValidateProgramBinaryBase(Context *context,
2254 GLuint program,
2255 GLenum binaryFormat,
2256 const void *binary,
2257 GLint length)
2258{
2259 Program *programObject = GetValidProgram(context, program);
2260 if (programObject == nullptr)
2261 {
2262 return false;
2263 }
2264
2265 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2266 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2267 programBinaryFormats.end())
2268 {
2269 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2270 return false;
2271 }
2272
2273 return true;
2274}
2275
2276bool ValidateGetProgramBinaryBase(Context *context,
2277 GLuint program,
2278 GLsizei bufSize,
2279 GLsizei *length,
2280 GLenum *binaryFormat,
2281 void *binary)
2282{
2283 Program *programObject = GetValidProgram(context, program);
2284 if (programObject == nullptr)
2285 {
2286 return false;
2287 }
2288
2289 if (!programObject->isLinked())
2290 {
2291 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2292 return false;
2293 }
2294
2295 return true;
2296}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002297}