blob: 1784bbabd04fc9fef4f1a3c26447734b930406e4 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500112
Geoff Lang0550d032014-01-30 11:29:07 -0500113 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
114 case GL_RASTERIZER_DISCARD:
115 return (context->getClientVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500116
117 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
118 case GL_DEBUG_OUTPUT:
119 return context->getExtensions().debug;
120
Geoff Lang0550d032014-01-30 11:29:07 -0500121 default:
122 return false;
123 }
124}
125
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500126bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400127{
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400129 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500130 case GL_TEXTURE_2D:
131 case GL_TEXTURE_CUBE_MAP:
132 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400133
Jamie Madilld7460c72014-01-21 16:38:14 -0500134 case GL_TEXTURE_3D:
135 case GL_TEXTURE_2D_ARRAY:
136 return (context->getClientVersion() >= 3);
137
138 default:
139 return false;
140 }
Jamie Madill35d15012013-10-07 10:46:37 -0400141}
142
Shannon Woods4dfed832014-03-17 20:03:39 -0400143// This function differs from ValidTextureTarget in that the target must be
144// usable as the destination of a 2D operation-- so a cube face is valid, but
145// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400146// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400147bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
148{
149 switch (target)
150 {
151 case GL_TEXTURE_2D:
152 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
153 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
154 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
155 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
156 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
157 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
158 return true;
159 case GL_TEXTURE_2D_ARRAY:
160 case GL_TEXTURE_3D:
161 return (context->getClientVersion() >= 3);
162 default:
163 return false;
164 }
165}
166
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500167bool ValidFramebufferTarget(GLenum target)
168{
Geoff Langd4475812015-03-18 10:53:05 -0400169 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
170 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500171
172 switch (target)
173 {
174 case GL_FRAMEBUFFER: return true;
175 case GL_READ_FRAMEBUFFER: return true;
176 case GL_DRAW_FRAMEBUFFER: return true;
177 default: return false;
178 }
179}
180
Jamie Madill8c96d582014-03-05 15:01:23 -0500181bool ValidBufferTarget(const Context *context, GLenum target)
182{
183 switch (target)
184 {
185 case GL_ARRAY_BUFFER:
186 case GL_ELEMENT_ARRAY_BUFFER:
187 return true;
188
Jamie Madill8c96d582014-03-05 15:01:23 -0500189 case GL_PIXEL_PACK_BUFFER:
190 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400191 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400192
Shannon Woodsb3801742014-03-27 14:59:19 -0400193 case GL_COPY_READ_BUFFER:
194 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500195 case GL_TRANSFORM_FEEDBACK_BUFFER:
196 case GL_UNIFORM_BUFFER:
197 return (context->getClientVersion() >= 3);
198
199 default:
200 return false;
201 }
202}
203
Jamie Madill70656a62014-03-05 15:01:26 -0500204bool ValidBufferParameter(const Context *context, GLenum pname)
205{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400206 const Extensions &extensions = context->getExtensions();
207
Jamie Madill70656a62014-03-05 15:01:26 -0500208 switch (pname)
209 {
210 case GL_BUFFER_USAGE:
211 case GL_BUFFER_SIZE:
212 return true;
213
Geoff Langcc6f55d2015-03-20 13:01:02 -0400214 case GL_BUFFER_ACCESS_OES:
215 return extensions.mapBuffer;
216
217 case GL_BUFFER_MAPPED:
218 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
219 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
220
Jamie Madill70656a62014-03-05 15:01:26 -0500221 // GL_BUFFER_MAP_POINTER is a special case, and may only be
222 // queried with GetBufferPointerv
223 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500224 case GL_BUFFER_MAP_OFFSET:
225 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400226 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500227
228 default:
229 return false;
230 }
231}
232
Jamie Madill8c96d582014-03-05 15:01:23 -0500233bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400234{
Geoff Langaae65a42014-05-26 12:43:44 -0400235 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400236 switch (target)
237 {
Geoff Langaae65a42014-05-26 12:43:44 -0400238 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400239 case GL_TEXTURE_CUBE_MAP:
240 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
242 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
243 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
244 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400245 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
246 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
247 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400248 default: UNREACHABLE();
249 }
250
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700251 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400252}
253
Austin Kinross08528e12015-10-07 16:24:40 -0700254bool ValidImageSizeParameters(const Context *context,
255 GLenum target,
256 GLint level,
257 GLsizei width,
258 GLsizei height,
259 GLsizei depth,
260 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400261{
262 if (level < 0 || width < 0 || height < 0 || depth < 0)
263 {
264 return false;
265 }
266
Austin Kinross08528e12015-10-07 16:24:40 -0700267 // TexSubImage parameters can be NPOT without textureNPOT extension,
268 // as long as the destination texture is POT.
269 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400270 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400271 {
272 return false;
273 }
274
275 if (!ValidMipLevel(context, target, level))
276 {
277 return false;
278 }
279
280 return true;
281}
282
Geoff Lang0d8b7242015-09-09 14:56:53 -0400283bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
284{
285 // List of compressed format that require that the texture size is smaller than or a multiple of
286 // the compressed block size.
287 switch (internalFormat)
288 {
289 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
290 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
291 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
292 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
293 return true;
294
295 default:
296 return false;
297 }
298}
299
Geoff Langb1196682014-07-23 13:47:29 -0400300bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400301{
Geoff Lang5d601382014-07-22 15:14:06 -0400302 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
303 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400304 {
305 return false;
306 }
307
Geoff Lang0d8b7242015-09-09 14:56:53 -0400308 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400309 {
310 return false;
311 }
312
Geoff Lang0d8b7242015-09-09 14:56:53 -0400313 if (CompressedTextureFormatRequiresExactSize(internalFormat))
314 {
315 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
316 width % formatInfo.compressedBlockWidth != 0) ||
317 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
318 height % formatInfo.compressedBlockHeight != 0))
319 {
320 return false;
321 }
322 }
323
Geoff Langd4f180b2013-09-24 13:57:44 -0400324 return true;
325}
326
Geoff Lang37dde692014-01-31 16:34:54 -0500327bool ValidQueryType(const Context *context, GLenum queryType)
328{
Geoff Langd4475812015-03-18 10:53:05 -0400329 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
330 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 -0500331
332 switch (queryType)
333 {
334 case GL_ANY_SAMPLES_PASSED:
335 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
336 return true;
337 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
338 return (context->getClientVersion() >= 3);
339 default:
340 return false;
341 }
342}
343
Dian Xiang769769a2015-09-09 15:20:08 -0700344Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500345{
346 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
347 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
348 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
349
Dian Xiang769769a2015-09-09 15:20:08 -0700350 Program *validProgram = context->getProgram(id);
351
352 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500353 {
Dian Xiang769769a2015-09-09 15:20:08 -0700354 if (context->getShader(id))
355 {
356 context->recordError(
357 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
358 }
359 else
360 {
361 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
362 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500363 }
Dian Xiang769769a2015-09-09 15:20:08 -0700364
365 return validProgram;
366}
367
368Shader *GetValidShader(Context *context, GLuint id)
369{
370 // See ValidProgram for spec details.
371
372 Shader *validShader = context->getShader(id);
373
374 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500375 {
Dian Xiang769769a2015-09-09 15:20:08 -0700376 if (context->getProgram(id))
377 {
378 context->recordError(
379 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
380 }
381 else
382 {
383 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
384 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500385 }
Dian Xiang769769a2015-09-09 15:20:08 -0700386
387 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500388}
389
Geoff Langb1196682014-07-23 13:47:29 -0400390bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400391{
392 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
393 {
394 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
395
Geoff Langaae65a42014-05-26 12:43:44 -0400396 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400397 {
Geoff Langb1196682014-07-23 13:47:29 -0400398 context->recordError(Error(GL_INVALID_VALUE));
399 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400400 }
401 }
402 else
403 {
404 switch (attachment)
405 {
406 case GL_DEPTH_ATTACHMENT:
407 case GL_STENCIL_ATTACHMENT:
408 break;
409
410 case GL_DEPTH_STENCIL_ATTACHMENT:
411 if (context->getClientVersion() < 3)
412 {
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 break;
417
418 default:
Geoff Langb1196682014-07-23 13:47:29 -0400419 context->recordError(Error(GL_INVALID_ENUM));
420 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400421 }
422 }
423
424 return true;
425}
426
Corentin Walleze0902642014-11-04 12:32:15 -0800427bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
428 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400429{
430 switch (target)
431 {
432 case GL_RENDERBUFFER:
433 break;
434 default:
Geoff Langb1196682014-07-23 13:47:29 -0400435 context->recordError(Error(GL_INVALID_ENUM));
436 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400437 }
438
439 if (width < 0 || height < 0 || samples < 0)
440 {
Geoff Langb1196682014-07-23 13:47:29 -0400441 context->recordError(Error(GL_INVALID_VALUE));
442 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400443 }
444
Geoff Langd87878e2014-09-19 15:42:59 -0400445 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
446 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400447 {
Geoff Langb1196682014-07-23 13:47:29 -0400448 context->recordError(Error(GL_INVALID_ENUM));
449 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400450 }
451
452 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
453 // 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 -0800454 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400455 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400456 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 {
Geoff Langb1196682014-07-23 13:47:29 -0400458 context->recordError(Error(GL_INVALID_ENUM));
459 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400460 }
461
Geoff Langaae65a42014-05-26 12:43:44 -0400462 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 {
Geoff Langb1196682014-07-23 13:47:29 -0400464 context->recordError(Error(GL_INVALID_VALUE));
465 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400466 }
467
Shannon Woods53a94a82014-06-24 15:20:36 -0400468 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400469 if (handle == 0)
470 {
Geoff Langb1196682014-07-23 13:47:29 -0400471 context->recordError(Error(GL_INVALID_OPERATION));
472 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400473 }
474
475 return true;
476}
477
Corentin Walleze0902642014-11-04 12:32:15 -0800478bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
479 GLenum internalformat, GLsizei width, GLsizei height)
480{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800481 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800482
483 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400484 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800485 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400486 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800487 {
488 context->recordError(Error(GL_INVALID_VALUE));
489 return false;
490 }
491
492 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
493 // the specified storage. This is different than ES 3.0 in which a sample number higher
494 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800495 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
496 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800497 {
Geoff Langa4903b72015-03-02 16:02:48 -0800498 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
499 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
500 {
501 context->recordError(Error(GL_OUT_OF_MEMORY));
502 return false;
503 }
Corentin Walleze0902642014-11-04 12:32:15 -0800504 }
505
506 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
507}
508
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500509bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
510 GLenum renderbuffertarget, GLuint renderbuffer)
511{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400512 if (!ValidFramebufferTarget(target))
513 {
Geoff Langb1196682014-07-23 13:47:29 -0400514 context->recordError(Error(GL_INVALID_ENUM));
515 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400516 }
517
Shannon Woods53a94a82014-06-24 15:20:36 -0400518 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500519
Jamie Madill84115c92015-04-23 15:00:07 -0400520 ASSERT(framebuffer);
521 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500522 {
Jamie Madill84115c92015-04-23 15:00:07 -0400523 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400524 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500525 }
526
Jamie Madillb4472272014-07-03 10:38:55 -0400527 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500528 {
Jamie Madillb4472272014-07-03 10:38:55 -0400529 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500530 }
531
Jamie Madillab9d82c2014-01-21 16:38:14 -0500532 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
533 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
534 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
535 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
536 if (renderbuffer != 0)
537 {
538 if (!context->getRenderbuffer(renderbuffer))
539 {
Geoff Langb1196682014-07-23 13:47:29 -0400540 context->recordError(Error(GL_INVALID_OPERATION));
541 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500542 }
543 }
544
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500545 return true;
546}
547
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400548static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400549 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
550 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
551{
Jamie Madill6b120b92015-11-24 13:00:07 -0500552 const Extents &writeSize = writeBuffer->getSize();
553 const Extents &readSize = readBuffer->getSize();
554
555 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || dstX1 != writeSize.width ||
556 dstY1 != writeSize.height || srcX1 != readSize.width || srcY1 != readSize.height)
Geoff Lang125deab2013-08-09 13:34:16 -0400557 {
558 return true;
559 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400560 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400561 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400562 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400563
Jamie Madill6b120b92015-11-24 13:00:07 -0500564 return scissor.x > 0 || scissor.y > 0 || scissor.width < writeSize.width ||
565 scissor.height < writeSize.height;
Geoff Lang125deab2013-08-09 13:34:16 -0400566 }
567 else
568 {
569 return false;
570 }
571}
572
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400573bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400574 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
575 GLenum filter, bool fromAngleExtension)
576{
577 switch (filter)
578 {
579 case GL_NEAREST:
580 break;
581 case GL_LINEAR:
582 if (fromAngleExtension)
583 {
Geoff Langb1196682014-07-23 13:47:29 -0400584 context->recordError(Error(GL_INVALID_ENUM));
585 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400586 }
587 break;
588 default:
Geoff Langb1196682014-07-23 13:47:29 -0400589 context->recordError(Error(GL_INVALID_ENUM));
590 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400591 }
592
593 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
594 {
Geoff Langb1196682014-07-23 13:47:29 -0400595 context->recordError(Error(GL_INVALID_VALUE));
596 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400597 }
598
599 if (mask == 0)
600 {
601 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
602 // buffers are copied.
603 return false;
604 }
605
606 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
607 {
608 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400609 context->recordError(Error(GL_INVALID_OPERATION));
610 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400611 }
612
613 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
614 // color buffer, leaving only nearest being unfiltered from above
615 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
616 {
Geoff Langb1196682014-07-23 13:47:29 -0400617 context->recordError(Error(GL_INVALID_OPERATION));
618 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400619 }
620
Shannon Woods53a94a82014-06-24 15:20:36 -0400621 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622 {
623 if (fromAngleExtension)
624 {
625 ERR("Blits with the same source and destination framebuffer are not supported by this "
626 "implementation.");
627 }
Geoff Langb1196682014-07-23 13:47:29 -0400628 context->recordError(Error(GL_INVALID_OPERATION));
629 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 }
631
Jamie Madille3ef7152015-04-28 16:55:17 +0000632 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
633 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500634
635 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636 {
Geoff Langb1196682014-07-23 13:47:29 -0400637 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
638 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 }
640
Geoff Lang748f74e2014-12-01 11:25:34 -0500641 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500642 {
643 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
644 return false;
645 }
646
Geoff Lang748f74e2014-12-01 11:25:34 -0500647 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500648 {
649 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
650 return false;
651 }
652
653 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654 {
Geoff Langb1196682014-07-23 13:47:29 -0400655 context->recordError(Error(GL_INVALID_OPERATION));
656 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400657 }
658
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
660
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661 if (mask & GL_COLOR_BUFFER_BIT)
662 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400663 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
664 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -0500665 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400666
667 if (readColorBuffer && drawColorBuffer)
668 {
Geoff Langd8a22582014-12-17 15:28:23 -0500669 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400670 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400671
Corentin Wallez37c39792015-08-20 14:19:46 -0400672 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 {
674 if (drawFramebuffer->isEnabledColorAttachment(i))
675 {
Geoff Langd8a22582014-12-17 15:28:23 -0500676 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400677 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678
Geoff Langb2f3d052013-08-13 12:49:27 -0400679 // The GL ES 3.0.2 spec (pg 193) states that:
680 // 1) If the read buffer is fixed point format, the draw buffer must be as well
681 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
682 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -0500683 // Changes with EXT_color_buffer_float:
684 // Case 1) is changed to fixed point OR floating point
685 GLenum readComponentType = readFormatInfo.componentType;
686 GLenum drawComponentType = drawFormatInfo.componentType;
687 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
688 readComponentType == GL_SIGNED_NORMALIZED);
689 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
690 drawComponentType == GL_SIGNED_NORMALIZED);
691
692 if (extensions.colorBufferFloat)
693 {
694 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
695 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
696
697 if (readFixedOrFloat != drawFixedOrFloat)
698 {
699 context->recordError(Error(GL_INVALID_OPERATION,
700 "If the read buffer contains fixed-point or "
701 "floating-point values, the draw buffer "
702 "must as well."));
703 return false;
704 }
705 }
706 else if (readFixedPoint != drawFixedPoint)
707 {
708 context->recordError(Error(GL_INVALID_OPERATION,
709 "If the read buffer contains fixed-point "
710 "values, the draw buffer must as well."));
711 return false;
712 }
713
714 if (readComponentType == GL_UNSIGNED_INT &&
715 drawComponentType != GL_UNSIGNED_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
Jamie Madill6163c752015-12-07 16:32:59 -0500721 if (readComponentType == GL_INT && drawComponentType != GL_INT)
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
Geoff Langb2f3d052013-08-13 12:49:27 -0400727 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400728 {
Geoff Langb1196682014-07-23 13:47:29 -0400729 context->recordError(Error(GL_INVALID_OPERATION));
730 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400731 }
732 }
733 }
734
Geoff Lang5d601382014-07-22 15:14:06 -0400735 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400736 {
Geoff Langb1196682014-07-23 13:47:29 -0400737 context->recordError(Error(GL_INVALID_OPERATION));
738 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400739 }
740
741 if (fromAngleExtension)
742 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400743 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500744 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400745 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500746 readColorAttachment->type() != GL_RENDERBUFFER &&
747 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 {
Geoff Langb1196682014-07-23 13:47:29 -0400749 context->recordError(Error(GL_INVALID_OPERATION));
750 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751 }
752
Corentin Wallez37c39792015-08-20 14:19:46 -0400753 for (size_t colorAttachment = 0;
754 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400755 {
756 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
757 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000758 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400759 ASSERT(attachment);
760
Jamie Madill8cf4a392015-04-02 11:36:04 -0400761 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500762 attachment->type() != GL_RENDERBUFFER &&
763 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 {
Geoff Langb1196682014-07-23 13:47:29 -0400765 context->recordError(Error(GL_INVALID_OPERATION));
766 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 }
768
Jamie Madillf8f18f02014-10-02 10:44:17 -0400769 // Return an error if the destination formats do not match
770 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 {
Geoff Langb1196682014-07-23 13:47:29 -0400772 context->recordError(Error(GL_INVALID_OPERATION));
773 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 }
775 }
776 }
Jamie Madill48faf802014-11-06 15:27:22 -0500777
778 int readSamples = readFramebuffer->getSamples(context->getData());
779
780 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
781 srcX0, srcY0, srcX1, srcY1,
782 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400783 {
Geoff Langb1196682014-07-23 13:47:29 -0400784 context->recordError(Error(GL_INVALID_OPERATION));
785 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400786 }
787 }
788 }
789 }
790
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200791 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
792 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
793 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200795 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400797 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
798 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200800 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801 {
Geoff Langd8a22582014-12-17 15:28:23 -0500802 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
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 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400807
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200808 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400809 {
Geoff Langb1196682014-07-23 13:47:29 -0400810 context->recordError(Error(GL_INVALID_OPERATION));
811 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200813
814 if (fromAngleExtension)
815 {
816 if (IsPartialBlit(context, readBuffer, drawBuffer,
817 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
818 {
819 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
820 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
821 return false;
822 }
823
824 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
825 {
826 context->recordError(Error(GL_INVALID_OPERATION));
827 return false;
828 }
829 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400830 }
831 }
832 }
833
834 return true;
835}
836
Geoff Langb1196682014-07-23 13:47:29 -0400837bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838{
839 switch (pname)
840 {
841 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
842 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
843 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
844 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
845 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
846 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
847 case GL_CURRENT_VERTEX_ATTRIB:
848 return true;
849
850 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
851 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
852 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400853 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
854 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400855 return true;
856
857 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400858 if (context->getClientVersion() < 3)
859 {
860 context->recordError(Error(GL_INVALID_ENUM));
861 return false;
862 }
863 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864
865 default:
Geoff Langb1196682014-07-23 13:47:29 -0400866 context->recordError(Error(GL_INVALID_ENUM));
867 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400868 }
869}
870
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400871bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400872{
873 switch (pname)
874 {
875 case GL_TEXTURE_WRAP_R:
876 case GL_TEXTURE_SWIZZLE_R:
877 case GL_TEXTURE_SWIZZLE_G:
878 case GL_TEXTURE_SWIZZLE_B:
879 case GL_TEXTURE_SWIZZLE_A:
880 case GL_TEXTURE_BASE_LEVEL:
881 case GL_TEXTURE_MAX_LEVEL:
882 case GL_TEXTURE_COMPARE_MODE:
883 case GL_TEXTURE_COMPARE_FUNC:
884 case GL_TEXTURE_MIN_LOD:
885 case GL_TEXTURE_MAX_LOD:
886 if (context->getClientVersion() < 3)
887 {
Geoff Langb1196682014-07-23 13:47:29 -0400888 context->recordError(Error(GL_INVALID_ENUM));
889 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 }
891 break;
892
893 default: break;
894 }
895
896 switch (pname)
897 {
898 case GL_TEXTURE_WRAP_S:
899 case GL_TEXTURE_WRAP_T:
900 case GL_TEXTURE_WRAP_R:
901 switch (param)
902 {
903 case GL_REPEAT:
904 case GL_CLAMP_TO_EDGE:
905 case GL_MIRRORED_REPEAT:
906 return true;
907 default:
Geoff Langb1196682014-07-23 13:47:29 -0400908 context->recordError(Error(GL_INVALID_ENUM));
909 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 }
911
912 case GL_TEXTURE_MIN_FILTER:
913 switch (param)
914 {
915 case GL_NEAREST:
916 case GL_LINEAR:
917 case GL_NEAREST_MIPMAP_NEAREST:
918 case GL_LINEAR_MIPMAP_NEAREST:
919 case GL_NEAREST_MIPMAP_LINEAR:
920 case GL_LINEAR_MIPMAP_LINEAR:
921 return true;
922 default:
Geoff Langb1196682014-07-23 13:47:29 -0400923 context->recordError(Error(GL_INVALID_ENUM));
924 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400925 }
926 break;
927
928 case GL_TEXTURE_MAG_FILTER:
929 switch (param)
930 {
931 case GL_NEAREST:
932 case GL_LINEAR:
933 return true;
934 default:
Geoff Langb1196682014-07-23 13:47:29 -0400935 context->recordError(Error(GL_INVALID_ENUM));
936 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400937 }
938 break;
939
940 case GL_TEXTURE_USAGE_ANGLE:
941 switch (param)
942 {
943 case GL_NONE:
944 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
945 return true;
946 default:
Geoff Langb1196682014-07-23 13:47:29 -0400947 context->recordError(Error(GL_INVALID_ENUM));
948 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400949 }
950 break;
951
952 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400953 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400954 {
Geoff Langb1196682014-07-23 13:47:29 -0400955 context->recordError(Error(GL_INVALID_ENUM));
956 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400957 }
958
959 // we assume the parameter passed to this validation method is truncated, not rounded
960 if (param < 1)
961 {
Geoff Langb1196682014-07-23 13:47:29 -0400962 context->recordError(Error(GL_INVALID_VALUE));
963 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400964 }
965 return true;
966
967 case GL_TEXTURE_MIN_LOD:
968 case GL_TEXTURE_MAX_LOD:
969 // any value is permissible
970 return true;
971
972 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400973 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400974 switch (param)
975 {
976 case GL_NONE:
977 case GL_COMPARE_REF_TO_TEXTURE:
978 return true;
979 default:
Geoff Langb1196682014-07-23 13:47:29 -0400980 context->recordError(Error(GL_INVALID_ENUM));
981 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400982 }
983 break;
984
985 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400986 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400987 switch (param)
988 {
989 case GL_LEQUAL:
990 case GL_GEQUAL:
991 case GL_LESS:
992 case GL_GREATER:
993 case GL_EQUAL:
994 case GL_NOTEQUAL:
995 case GL_ALWAYS:
996 case GL_NEVER:
997 return true;
998 default:
Geoff Langb1196682014-07-23 13:47:29 -0400999 context->recordError(Error(GL_INVALID_ENUM));
1000 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001001 }
1002 break;
1003
1004 case GL_TEXTURE_SWIZZLE_R:
1005 case GL_TEXTURE_SWIZZLE_G:
1006 case GL_TEXTURE_SWIZZLE_B:
1007 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001008 switch (param)
1009 {
1010 case GL_RED:
1011 case GL_GREEN:
1012 case GL_BLUE:
1013 case GL_ALPHA:
1014 case GL_ZERO:
1015 case GL_ONE:
1016 return true;
1017 default:
Geoff Langb1196682014-07-23 13:47:29 -04001018 context->recordError(Error(GL_INVALID_ENUM));
1019 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001020 }
1021 break;
1022
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001023 case GL_TEXTURE_BASE_LEVEL:
1024 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -04001025 if (param < 0)
1026 {
Geoff Langb1196682014-07-23 13:47:29 -04001027 context->recordError(Error(GL_INVALID_VALUE));
1028 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -04001029 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001030 return true;
1031
1032 default:
Geoff Langb1196682014-07-23 13:47:29 -04001033 context->recordError(Error(GL_INVALID_ENUM));
1034 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001035 }
1036}
1037
Geoff Langb1196682014-07-23 13:47:29 -04001038bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001039{
1040 switch (pname)
1041 {
1042 case GL_TEXTURE_MIN_FILTER:
1043 case GL_TEXTURE_MAG_FILTER:
1044 case GL_TEXTURE_WRAP_S:
1045 case GL_TEXTURE_WRAP_T:
1046 case GL_TEXTURE_WRAP_R:
1047 case GL_TEXTURE_MIN_LOD:
1048 case GL_TEXTURE_MAX_LOD:
1049 case GL_TEXTURE_COMPARE_MODE:
1050 case GL_TEXTURE_COMPARE_FUNC:
1051 return true;
1052
1053 default:
Geoff Langb1196682014-07-23 13:47:29 -04001054 context->recordError(Error(GL_INVALID_ENUM));
1055 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001056 }
1057}
1058
Jamie Madill26e91952014-03-05 15:01:27 -05001059bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
1060 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
1061{
Shannon Woods53a94a82014-06-24 15:20:36 -04001062 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001063 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001064
Geoff Lang748f74e2014-12-01 11:25:34 -05001065 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001066 {
Geoff Langb1196682014-07-23 13:47:29 -04001067 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1068 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001069 }
1070
Jamie Madill48faf802014-11-06 15:27:22 -05001071 if (context->getState().getReadFramebuffer()->id() != 0 &&
1072 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001073 {
Geoff Langb1196682014-07-23 13:47:29 -04001074 context->recordError(Error(GL_INVALID_OPERATION));
1075 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001076 }
1077
Geoff Langbce529e2014-12-01 12:48:41 -05001078 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1079 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001080 {
Geoff Langb1196682014-07-23 13:47:29 -04001081 context->recordError(Error(GL_INVALID_OPERATION));
1082 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001083 }
1084
Geoff Langbce529e2014-12-01 12:48:41 -05001085 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1086 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001087 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001088 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001089
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001090 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1091 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001092
1093 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1094 {
Geoff Langb1196682014-07-23 13:47:29 -04001095 context->recordError(Error(GL_INVALID_OPERATION));
1096 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001097 }
1098
Geoff Lang5d601382014-07-22 15:14:06 -04001099 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1100 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001101
Minmin Gongadff67b2015-10-14 10:34:45 -04001102 GLsizei outputPitch =
1103 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1104 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001105 // sized query sanity check
1106 if (bufSize)
1107 {
1108 int requiredSize = outputPitch * height;
1109 if (requiredSize > *bufSize)
1110 {
Geoff Langb1196682014-07-23 13:47:29 -04001111 context->recordError(Error(GL_INVALID_OPERATION));
1112 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001113 }
1114 }
1115
1116 return true;
1117}
1118
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001119bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1120{
1121 if (!ValidQueryType(context, target))
1122 {
Geoff Langb1196682014-07-23 13:47:29 -04001123 context->recordError(Error(GL_INVALID_ENUM));
1124 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001125 }
1126
1127 if (id == 0)
1128 {
Geoff Langb1196682014-07-23 13:47:29 -04001129 context->recordError(Error(GL_INVALID_OPERATION));
1130 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001131 }
1132
1133 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1134 // of zero, if the active query object name for <target> is non-zero (for the
1135 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1136 // the active query for either target is non-zero), if <id> is the name of an
1137 // existing query object whose type does not match <target>, or if <id> is the
1138 // active query object name for any query type, the error INVALID_OPERATION is
1139 // generated.
1140
1141 // Ensure no other queries are active
1142 // NOTE: If other queries than occlusion are supported, we will need to check
1143 // separately that:
1144 // a) The query ID passed is not the current active query for any target/type
1145 // b) There are no active queries for the requested target (and in the case
1146 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1147 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001148 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001149 {
Geoff Langb1196682014-07-23 13:47:29 -04001150 context->recordError(Error(GL_INVALID_OPERATION));
1151 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001152 }
1153
1154 Query *queryObject = context->getQuery(id, true, target);
1155
1156 // check that name was obtained with glGenQueries
1157 if (!queryObject)
1158 {
Geoff Langb1196682014-07-23 13:47:29 -04001159 context->recordError(Error(GL_INVALID_OPERATION));
1160 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001161 }
1162
1163 // check for type mismatch
1164 if (queryObject->getType() != target)
1165 {
Geoff Langb1196682014-07-23 13:47:29 -04001166 context->recordError(Error(GL_INVALID_OPERATION));
1167 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001168 }
1169
1170 return true;
1171}
1172
Jamie Madill45c785d2014-05-13 14:09:34 -04001173bool ValidateEndQuery(gl::Context *context, GLenum target)
1174{
1175 if (!ValidQueryType(context, target))
1176 {
Geoff Langb1196682014-07-23 13:47:29 -04001177 context->recordError(Error(GL_INVALID_ENUM));
1178 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001179 }
1180
Shannon Woods53a94a82014-06-24 15:20:36 -04001181 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001182
1183 if (queryObject == NULL)
1184 {
Geoff Langb1196682014-07-23 13:47:29 -04001185 context->recordError(Error(GL_INVALID_OPERATION));
1186 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001187 }
1188
Jamie Madill45c785d2014-05-13 14:09:34 -04001189 return true;
1190}
1191
Jamie Madill62d31cb2015-09-11 13:25:51 -04001192static bool ValidateUniformCommonBase(gl::Context *context,
1193 GLenum targetUniformType,
1194 GLint location,
1195 GLsizei count,
1196 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001197{
1198 if (count < 0)
1199 {
Geoff Langb1196682014-07-23 13:47:29 -04001200 context->recordError(Error(GL_INVALID_VALUE));
1201 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001202 }
1203
Geoff Lang7dd2e102014-11-10 15:19:26 -05001204 gl::Program *program = context->getState().getProgram();
1205 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001206 {
Geoff Langb1196682014-07-23 13:47:29 -04001207 context->recordError(Error(GL_INVALID_OPERATION));
1208 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001209 }
1210
1211 if (location == -1)
1212 {
1213 // Silently ignore the uniform command
1214 return false;
1215 }
1216
Geoff Lang7dd2e102014-11-10 15:19:26 -05001217 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001218 {
Geoff Langb1196682014-07-23 13:47:29 -04001219 context->recordError(Error(GL_INVALID_OPERATION));
1220 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001221 }
1222
Jamie Madill62d31cb2015-09-11 13:25:51 -04001223 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001224
1225 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001226 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001227 {
Geoff Langb1196682014-07-23 13:47:29 -04001228 context->recordError(Error(GL_INVALID_OPERATION));
1229 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001230 }
1231
Jamie Madill62d31cb2015-09-11 13:25:51 -04001232 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001233 return true;
1234}
1235
Jamie Madillaa981bd2014-05-20 10:55:55 -04001236bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1237{
1238 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001239 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001240 {
Geoff Langb1196682014-07-23 13:47:29 -04001241 context->recordError(Error(GL_INVALID_OPERATION));
1242 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001243 }
1244
Jamie Madill62d31cb2015-09-11 13:25:51 -04001245 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001246 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1247 {
1248 return false;
1249 }
1250
Jamie Madillf2575982014-06-25 16:04:54 -04001251 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001252 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001253 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1254 {
Geoff Langb1196682014-07-23 13:47:29 -04001255 context->recordError(Error(GL_INVALID_OPERATION));
1256 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001257 }
1258
1259 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001260}
1261
1262bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1263 GLboolean transpose)
1264{
1265 // Check for ES3 uniform entry points
1266 int rows = VariableRowCount(matrixType);
1267 int cols = VariableColumnCount(matrixType);
1268 if (rows != cols && context->getClientVersion() < 3)
1269 {
Geoff Langb1196682014-07-23 13:47:29 -04001270 context->recordError(Error(GL_INVALID_OPERATION));
1271 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001272 }
1273
1274 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1275 {
Geoff Langb1196682014-07-23 13:47:29 -04001276 context->recordError(Error(GL_INVALID_VALUE));
1277 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001278 }
1279
Jamie Madill62d31cb2015-09-11 13:25:51 -04001280 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001281 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1282 {
1283 return false;
1284 }
1285
1286 if (uniform->type != matrixType)
1287 {
Geoff Langb1196682014-07-23 13:47:29 -04001288 context->recordError(Error(GL_INVALID_OPERATION));
1289 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001290 }
1291
1292 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001293}
1294
Jamie Madill893ab082014-05-16 16:56:10 -04001295bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1296{
1297 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1298 {
Geoff Langb1196682014-07-23 13:47:29 -04001299 context->recordError(Error(GL_INVALID_ENUM));
1300 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001301 }
1302
Jamie Madill0af26e12015-03-05 19:54:33 -05001303 const Caps &caps = context->getCaps();
1304
Jamie Madill893ab082014-05-16 16:56:10 -04001305 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1306 {
1307 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1308
Jamie Madill0af26e12015-03-05 19:54:33 -05001309 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001310 {
Geoff Langb1196682014-07-23 13:47:29 -04001311 context->recordError(Error(GL_INVALID_OPERATION));
1312 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001313 }
1314 }
1315
1316 switch (pname)
1317 {
1318 case GL_TEXTURE_BINDING_2D:
1319 case GL_TEXTURE_BINDING_CUBE_MAP:
1320 case GL_TEXTURE_BINDING_3D:
1321 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001322 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001323 {
Geoff Langb1196682014-07-23 13:47:29 -04001324 context->recordError(Error(GL_INVALID_OPERATION));
1325 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001326 }
1327 break;
1328
1329 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1330 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1331 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001332 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001333 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001334 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001335 {
Geoff Langb1196682014-07-23 13:47:29 -04001336 context->recordError(Error(GL_INVALID_OPERATION));
1337 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001338 }
1339
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001340 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001341 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001342 {
Geoff Langb1196682014-07-23 13:47:29 -04001343 context->recordError(Error(GL_INVALID_OPERATION));
1344 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001345 }
1346 }
1347 break;
1348
1349 default:
1350 break;
1351 }
1352
1353 // pname is valid, but there are no parameters to return
1354 if (numParams == 0)
1355 {
1356 return false;
1357 }
1358
1359 return true;
1360}
1361
Geoff Lang831b1952015-05-05 11:02:27 -04001362bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001363 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1364 GLint border, GLenum *textureFormatOut)
1365{
1366
1367 if (!ValidTexture2DDestinationTarget(context, target))
1368 {
Geoff Langb1196682014-07-23 13:47:29 -04001369 context->recordError(Error(GL_INVALID_ENUM));
1370 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001371 }
1372
1373 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
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 (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
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 (border != 0)
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
1391 if (!ValidMipLevel(context, target, level))
1392 {
Geoff Langb1196682014-07-23 13:47:29 -04001393 context->recordError(Error(GL_INVALID_VALUE));
1394 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001395 }
1396
Shannon Woods53a94a82014-06-24 15:20:36 -04001397 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001398 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001399 {
Geoff Langb1196682014-07-23 13:47:29 -04001400 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1401 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001402 }
1403
Jamie Madill48faf802014-11-06 15:27:22 -05001404 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001405 {
Geoff Langb1196682014-07-23 13:47:29 -04001406 context->recordError(Error(GL_INVALID_OPERATION));
1407 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001408 }
1409
Geoff Langaae65a42014-05-26 12:43:44 -04001410 const gl::Caps &caps = context->getCaps();
1411
Geoff Langaae65a42014-05-26 12:43:44 -04001412 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001413 switch (target)
1414 {
1415 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001416 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001417 break;
1418
1419 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1420 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1421 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1422 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1423 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1424 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001425 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001426 break;
1427
1428 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001429 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001430 break;
1431
1432 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001433 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001434 break;
1435
1436 default:
Geoff Langb1196682014-07-23 13:47:29 -04001437 context->recordError(Error(GL_INVALID_ENUM));
1438 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001439 }
1440
Geoff Lang691e58c2014-12-19 17:03:25 -05001441 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001442 if (!texture)
1443 {
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 Lang69cce582015-09-17 13:20:36 -04001448 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001449 {
Geoff Langb1196682014-07-23 13:47:29 -04001450 context->recordError(Error(GL_INVALID_OPERATION));
1451 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001452 }
1453
Geoff Lang5d601382014-07-22 15:14:06 -04001454 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1455
1456 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001457 {
Geoff Langb1196682014-07-23 13:47:29 -04001458 context->recordError(Error(GL_INVALID_OPERATION));
1459 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001460 }
1461
Geoff Langa9be0dc2014-12-17 12:34:40 -05001462 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001463 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001464 context->recordError(Error(GL_INVALID_OPERATION));
1465 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001466 }
1467
1468 if (isSubImage)
1469 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001470 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1471 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1472 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001473 {
Geoff Langb1196682014-07-23 13:47:29 -04001474 context->recordError(Error(GL_INVALID_VALUE));
1475 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001476 }
1477 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001478 else
1479 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001480 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001481 {
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_VALUE));
1483 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001484 }
1485
Geoff Lang5d601382014-07-22 15:14:06 -04001486 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001487 {
Geoff Langb1196682014-07-23 13:47:29 -04001488 context->recordError(Error(GL_INVALID_ENUM));
1489 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001490 }
1491
1492 int maxLevelDimension = (maxDimension >> level);
1493 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1494 {
Geoff Langb1196682014-07-23 13:47:29 -04001495 context->recordError(Error(GL_INVALID_VALUE));
1496 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001497 }
1498 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001499
Geoff Langa9be0dc2014-12-17 12:34:40 -05001500 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001501 return true;
1502}
1503
Jamie Madillf25855c2015-11-03 11:06:18 -05001504static bool ValidateDrawBase(ValidationContext *context,
1505 GLenum mode,
1506 GLsizei count,
1507 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001508{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001509 switch (mode)
1510 {
1511 case GL_POINTS:
1512 case GL_LINES:
1513 case GL_LINE_LOOP:
1514 case GL_LINE_STRIP:
1515 case GL_TRIANGLES:
1516 case GL_TRIANGLE_STRIP:
1517 case GL_TRIANGLE_FAN:
1518 break;
1519 default:
Geoff Langb1196682014-07-23 13:47:29 -04001520 context->recordError(Error(GL_INVALID_ENUM));
1521 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001522 }
1523
Jamie Madill250d33f2014-06-06 17:09:03 -04001524 if (count < 0)
1525 {
Geoff Langb1196682014-07-23 13:47:29 -04001526 context->recordError(Error(GL_INVALID_VALUE));
1527 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001528 }
1529
Geoff Langb1196682014-07-23 13:47:29 -04001530 const State &state = context->getState();
1531
Jamie Madill250d33f2014-06-06 17:09:03 -04001532 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001533 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001534 {
Geoff Langb1196682014-07-23 13:47:29 -04001535 context->recordError(Error(GL_INVALID_OPERATION));
1536 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001537 }
1538
Geoff Lang3a86ad32015-09-01 11:47:05 -04001539 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001540 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001541 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1542 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1543 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1544 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1545 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1546 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1547 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001548 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001549 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1550 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001551 {
1552 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1553 // Section 6.10 of the WebGL 1.0 spec
1554 ERR(
1555 "This ANGLE implementation does not support separate front/back stencil "
1556 "writemasks, reference values, or stencil mask values.");
1557 context->recordError(Error(GL_INVALID_OPERATION));
1558 return false;
1559 }
Jamie Madillac528012014-06-20 13:21:23 -04001560 }
1561
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001562 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001563 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001564 {
Geoff Langb1196682014-07-23 13:47:29 -04001565 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1566 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001567 }
1568
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569 gl::Program *program = state.getProgram();
1570 if (!program)
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
Geoff Lang7dd2e102014-11-10 15:19:26 -05001576 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001577 {
Geoff Langb1196682014-07-23 13:47:29 -04001578 context->recordError(Error(GL_INVALID_OPERATION));
1579 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001580 }
1581
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001582 // Uniform buffer validation
1583 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1584 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001585 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001586 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001587 const OffsetBindingPointer<Buffer> &uniformBuffer =
1588 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001589
Geoff Lang5d124a62015-09-15 13:03:27 -04001590 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001591 {
1592 // undefined behaviour
1593 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1594 return false;
1595 }
1596
Geoff Lang5d124a62015-09-15 13:03:27 -04001597 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001598 if (uniformBufferSize == 0)
1599 {
1600 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001601 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001602 }
1603
Jamie Madill62d31cb2015-09-11 13:25:51 -04001604 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001605 {
1606 // undefined behaviour
1607 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1608 return false;
1609 }
1610 }
1611
Jamie Madill250d33f2014-06-06 17:09:03 -04001612 // No-op if zero count
1613 return (count > 0);
1614}
1615
Geoff Langb1196682014-07-23 13:47:29 -04001616bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001617{
Jamie Madillfd716582014-06-06 17:09:04 -04001618 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001619 {
Geoff Langb1196682014-07-23 13:47:29 -04001620 context->recordError(Error(GL_INVALID_VALUE));
1621 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001622 }
1623
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001624 const State &state = context->getState();
1625 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001626 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1627 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001628 {
1629 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1630 // that does not match the current transform feedback object's draw mode (if transform feedback
1631 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001632 context->recordError(Error(GL_INVALID_OPERATION));
1633 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001634 }
1635
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001636 if (!ValidateDrawBase(context, mode, count, primcount))
1637 {
1638 return false;
1639 }
1640
1641 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001642 {
1643 return false;
1644 }
1645
1646 return true;
1647}
1648
Geoff Langb1196682014-07-23 13:47:29 -04001649bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001650{
1651 if (primcount < 0)
1652 {
Geoff Langb1196682014-07-23 13:47:29 -04001653 context->recordError(Error(GL_INVALID_VALUE));
1654 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001655 }
1656
Jamie Madill2b976812014-08-25 15:47:49 -04001657 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001658 {
1659 return false;
1660 }
1661
1662 // No-op if zero primitive count
1663 return (primcount > 0);
1664}
1665
Geoff Lang87a93302014-09-16 13:29:43 -04001666static bool ValidateDrawInstancedANGLE(Context *context)
1667{
1668 // Verify there is at least one active attribute with a divisor of zero
1669 const gl::State& state = context->getState();
1670
Geoff Lang7dd2e102014-11-10 15:19:26 -05001671 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001672
1673 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001674 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001675 {
1676 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001677 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001678 {
1679 return true;
1680 }
1681 }
1682
1683 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1684 "has a divisor of zero."));
1685 return false;
1686}
1687
1688bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1689{
1690 if (!ValidateDrawInstancedANGLE(context))
1691 {
1692 return false;
1693 }
1694
1695 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1696}
1697
Jamie Madillf25855c2015-11-03 11:06:18 -05001698bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001699 GLenum mode,
1700 GLsizei count,
1701 GLenum type,
1702 const GLvoid *indices,
1703 GLsizei primcount,
1704 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001705{
Jamie Madill250d33f2014-06-06 17:09:03 -04001706 switch (type)
1707 {
1708 case GL_UNSIGNED_BYTE:
1709 case GL_UNSIGNED_SHORT:
1710 break;
1711 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001712 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001713 {
Geoff Langb1196682014-07-23 13:47:29 -04001714 context->recordError(Error(GL_INVALID_ENUM));
1715 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001716 }
1717 break;
1718 default:
Geoff Langb1196682014-07-23 13:47:29 -04001719 context->recordError(Error(GL_INVALID_ENUM));
1720 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001721 }
1722
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001723 const State &state = context->getState();
1724
1725 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001726 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001727 {
1728 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1729 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001730 context->recordError(Error(GL_INVALID_OPERATION));
1731 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001732 }
1733
1734 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001735 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001736 {
Geoff Langb1196682014-07-23 13:47:29 -04001737 context->recordError(Error(GL_INVALID_OPERATION));
1738 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001739 }
1740
Jamie Madill2b976812014-08-25 15:47:49 -04001741 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001742 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001743 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001744 {
Geoff Langb1196682014-07-23 13:47:29 -04001745 context->recordError(Error(GL_INVALID_OPERATION));
1746 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001747 }
1748
Jamie Madillae3000b2014-08-25 15:47:51 -04001749 if (elementArrayBuffer)
1750 {
1751 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1752
1753 GLint64 offset = reinterpret_cast<GLint64>(indices);
1754 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1755
1756 // check for integer overflows
1757 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1758 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1759 {
Geoff Langb1196682014-07-23 13:47:29 -04001760 context->recordError(Error(GL_OUT_OF_MEMORY));
1761 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001762 }
1763
1764 // Check for reading past the end of the bound buffer object
1765 if (byteCount > elementArrayBuffer->getSize())
1766 {
Geoff Langb1196682014-07-23 13:47:29 -04001767 context->recordError(Error(GL_INVALID_OPERATION));
1768 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001769 }
1770 }
1771 else if (!indices)
1772 {
1773 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001774 context->recordError(Error(GL_INVALID_OPERATION));
1775 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001776 }
1777
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001778 if (!ValidateDrawBase(context, mode, count, primcount))
1779 {
1780 return false;
1781 }
1782
Jamie Madill2b976812014-08-25 15:47:49 -04001783 // Use max index to validate if our vertex buffers are large enough for the pull.
1784 // TODO: offer fast path, with disabled index validation.
1785 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1786 if (elementArrayBuffer)
1787 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001788 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001789 Error error =
1790 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1791 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001792 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001793 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001794 context->recordError(error);
1795 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001796 }
1797 }
1798 else
1799 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001800 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001801 }
1802
Jamie Madille79b1e12015-11-04 16:36:37 -05001803 // If we use an index greater than our maximum supported index range, return an error.
1804 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1805 // return an error if possible here.
1806 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1807 {
1808 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1809 return false;
1810 }
1811
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001812 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001813 {
1814 return false;
1815 }
1816
Geoff Lang3edfe032015-09-04 16:38:24 -04001817 // No op if there are no real indices in the index data (all are primitive restart).
1818 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001819}
1820
Geoff Langb1196682014-07-23 13:47:29 -04001821bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001822 GLenum mode,
1823 GLsizei count,
1824 GLenum type,
1825 const GLvoid *indices,
1826 GLsizei primcount,
1827 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001828{
1829 if (primcount < 0)
1830 {
Geoff Langb1196682014-07-23 13:47:29 -04001831 context->recordError(Error(GL_INVALID_VALUE));
1832 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001833 }
1834
Jamie Madill2b976812014-08-25 15:47:49 -04001835 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001836 {
1837 return false;
1838 }
1839
1840 // No-op zero primitive count
1841 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001842}
1843
Geoff Lang3edfe032015-09-04 16:38:24 -04001844bool ValidateDrawElementsInstancedANGLE(Context *context,
1845 GLenum mode,
1846 GLsizei count,
1847 GLenum type,
1848 const GLvoid *indices,
1849 GLsizei primcount,
1850 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001851{
1852 if (!ValidateDrawInstancedANGLE(context))
1853 {
1854 return false;
1855 }
1856
1857 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1858}
1859
Geoff Langb1196682014-07-23 13:47:29 -04001860bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001861 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001862{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001863 if (!ValidFramebufferTarget(target))
1864 {
Geoff Langb1196682014-07-23 13:47:29 -04001865 context->recordError(Error(GL_INVALID_ENUM));
1866 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001867 }
1868
1869 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001870 {
1871 return false;
1872 }
1873
Jamie Madill55ec3b12014-07-03 10:38:57 -04001874 if (texture != 0)
1875 {
1876 gl::Texture *tex = context->getTexture(texture);
1877
1878 if (tex == NULL)
1879 {
Geoff Langb1196682014-07-23 13:47:29 -04001880 context->recordError(Error(GL_INVALID_OPERATION));
1881 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001882 }
1883
1884 if (level < 0)
1885 {
Geoff Langb1196682014-07-23 13:47:29 -04001886 context->recordError(Error(GL_INVALID_VALUE));
1887 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001888 }
1889 }
1890
Shannon Woods53a94a82014-06-24 15:20:36 -04001891 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001892 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001893
Jamie Madill84115c92015-04-23 15:00:07 -04001894 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001895 {
Jamie Madill84115c92015-04-23 15:00:07 -04001896 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001897 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001898 }
1899
1900 return true;
1901}
1902
Geoff Langb1196682014-07-23 13:47:29 -04001903bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001904 GLenum textarget, GLuint texture, GLint level)
1905{
Geoff Lang95663912015-04-02 15:54:45 -04001906 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1907 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001908 {
Geoff Langb1196682014-07-23 13:47:29 -04001909 context->recordError(Error(GL_INVALID_VALUE));
1910 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001911 }
1912
1913 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001914 {
1915 return false;
1916 }
1917
Jamie Madill55ec3b12014-07-03 10:38:57 -04001918 if (texture != 0)
1919 {
1920 gl::Texture *tex = context->getTexture(texture);
1921 ASSERT(tex);
1922
Jamie Madill2a6564e2014-07-11 09:53:19 -04001923 const gl::Caps &caps = context->getCaps();
1924
Jamie Madill55ec3b12014-07-03 10:38:57 -04001925 switch (textarget)
1926 {
1927 case GL_TEXTURE_2D:
1928 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001929 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001930 {
Geoff Langb1196682014-07-23 13:47:29 -04001931 context->recordError(Error(GL_INVALID_VALUE));
1932 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001933 }
1934 if (tex->getTarget() != GL_TEXTURE_2D)
1935 {
Geoff Langb1196682014-07-23 13:47:29 -04001936 context->recordError(Error(GL_INVALID_OPERATION));
1937 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001938 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001939 }
1940 break;
1941
1942 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1943 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1944 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1945 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1946 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1947 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1948 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001949 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001950 {
Geoff Langb1196682014-07-23 13:47:29 -04001951 context->recordError(Error(GL_INVALID_VALUE));
1952 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001953 }
1954 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1955 {
Geoff Langb1196682014-07-23 13:47:29 -04001956 context->recordError(Error(GL_INVALID_OPERATION));
1957 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001958 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001959 }
1960 break;
1961
1962 default:
Geoff Langb1196682014-07-23 13:47:29 -04001963 context->recordError(Error(GL_INVALID_ENUM));
1964 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001965 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001966
1967 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1968 if (internalFormatInfo.compressed)
1969 {
1970 context->recordError(Error(GL_INVALID_OPERATION));
1971 return false;
1972 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001973 }
1974
Jamie Madill570f7c82014-07-03 10:38:54 -04001975 return true;
1976}
1977
Geoff Langb1196682014-07-23 13:47:29 -04001978bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001979{
1980 if (program == 0)
1981 {
Geoff Langb1196682014-07-23 13:47:29 -04001982 context->recordError(Error(GL_INVALID_VALUE));
1983 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001984 }
1985
Dian Xiang769769a2015-09-09 15:20:08 -07001986 gl::Program *programObject = GetValidProgram(context, program);
1987 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001988 {
1989 return false;
1990 }
1991
Jamie Madill0063c512014-08-25 15:47:53 -04001992 if (!programObject || !programObject->isLinked())
1993 {
Geoff Langb1196682014-07-23 13:47:29 -04001994 context->recordError(Error(GL_INVALID_OPERATION));
1995 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001996 }
1997
Geoff Lang7dd2e102014-11-10 15:19:26 -05001998 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001999 {
Geoff Langb1196682014-07-23 13:47:29 -04002000 context->recordError(Error(GL_INVALID_OPERATION));
2001 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002002 }
2003
Jamie Madill0063c512014-08-25 15:47:53 -04002004 return true;
2005}
2006
Geoff Langb1196682014-07-23 13:47:29 -04002007bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002008{
2009 return ValidateGetUniformBase(context, program, location);
2010}
2011
Geoff Langb1196682014-07-23 13:47:29 -04002012bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002013{
Jamie Madill78f41802014-08-25 15:47:55 -04002014 return ValidateGetUniformBase(context, program, location);
2015}
2016
Geoff Langb1196682014-07-23 13:47:29 -04002017static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04002018{
2019 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002020 {
Jamie Madill78f41802014-08-25 15:47:55 -04002021 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002022 }
2023
Jamie Madilla502c742014-08-28 17:19:13 -04002024 gl::Program *programObject = context->getProgram(program);
2025 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002026
Jamie Madill78f41802014-08-25 15:47:55 -04002027 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002028 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2029 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002030 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002031 {
Geoff Langb1196682014-07-23 13:47:29 -04002032 context->recordError(Error(GL_INVALID_OPERATION));
2033 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002034 }
2035
2036 return true;
2037}
2038
Geoff Langb1196682014-07-23 13:47:29 -04002039bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002040{
Jamie Madill78f41802014-08-25 15:47:55 -04002041 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002042}
2043
Geoff Langb1196682014-07-23 13:47:29 -04002044bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002045{
Jamie Madill78f41802014-08-25 15:47:55 -04002046 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002047}
2048
Austin Kinross08332632015-05-05 13:35:47 -07002049bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2050 const GLenum *attachments, bool defaultFramebuffer)
2051{
2052 if (numAttachments < 0)
2053 {
2054 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2055 return false;
2056 }
2057
2058 for (GLsizei i = 0; i < numAttachments; ++i)
2059 {
2060 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2061 {
2062 if (defaultFramebuffer)
2063 {
2064 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2065 return false;
2066 }
2067
2068 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2069 {
2070 context->recordError(Error(GL_INVALID_OPERATION,
2071 "Requested color attachment is greater than the maximum supported color attachments"));
2072 return false;
2073 }
2074 }
2075 else
2076 {
2077 switch (attachments[i])
2078 {
2079 case GL_DEPTH_ATTACHMENT:
2080 case GL_STENCIL_ATTACHMENT:
2081 case GL_DEPTH_STENCIL_ATTACHMENT:
2082 if (defaultFramebuffer)
2083 {
2084 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2085 return false;
2086 }
2087 break;
2088 case GL_COLOR:
2089 case GL_DEPTH:
2090 case GL_STENCIL:
2091 if (!defaultFramebuffer)
2092 {
2093 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2094 return false;
2095 }
2096 break;
2097 default:
2098 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2099 return false;
2100 }
2101 }
2102 }
2103
2104 return true;
2105}
2106
Austin Kinross6ee1e782015-05-29 17:05:37 -07002107bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2108{
2109 // Note that debug marker calls must not set error state
2110
2111 if (length < 0)
2112 {
2113 return false;
2114 }
2115
2116 if (marker == nullptr)
2117 {
2118 return false;
2119 }
2120
2121 return true;
2122}
2123
2124bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2125{
2126 // Note that debug marker calls must not set error state
2127
2128 if (length < 0)
2129 {
2130 return false;
2131 }
2132
2133 if (length > 0 && marker == nullptr)
2134 {
2135 return false;
2136 }
2137
2138 return true;
2139}
2140
Geoff Langdcab33b2015-07-21 13:03:16 -04002141bool ValidateEGLImageTargetTexture2DOES(Context *context,
2142 egl::Display *display,
2143 GLenum target,
2144 egl::Image *image)
2145{
Geoff Langa8406172015-07-21 16:53:39 -04002146 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2147 {
2148 context->recordError(Error(GL_INVALID_OPERATION));
2149 return false;
2150 }
2151
2152 switch (target)
2153 {
2154 case GL_TEXTURE_2D:
2155 break;
2156
2157 default:
2158 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2159 return false;
2160 }
2161
2162 if (!display->isValidImage(image))
2163 {
2164 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2165 return false;
2166 }
2167
2168 if (image->getSamples() > 0)
2169 {
2170 context->recordError(Error(GL_INVALID_OPERATION,
2171 "cannot create a 2D texture from a multisampled EGL image."));
2172 return false;
2173 }
2174
2175 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2176 if (!textureCaps.texturable)
2177 {
2178 context->recordError(Error(GL_INVALID_OPERATION,
2179 "EGL image internal format is not supported as a texture."));
2180 return false;
2181 }
2182
Geoff Langdcab33b2015-07-21 13:03:16 -04002183 return true;
2184}
2185
2186bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2187 egl::Display *display,
2188 GLenum target,
2189 egl::Image *image)
2190{
Geoff Langa8406172015-07-21 16:53:39 -04002191 if (!context->getExtensions().eglImage)
2192 {
2193 context->recordError(Error(GL_INVALID_OPERATION));
2194 return false;
2195 }
2196
2197 switch (target)
2198 {
2199 case GL_RENDERBUFFER:
2200 break;
2201
2202 default:
2203 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2204 return false;
2205 }
2206
2207 if (!display->isValidImage(image))
2208 {
2209 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2210 return false;
2211 }
2212
2213 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2214 if (!textureCaps.renderable)
2215 {
2216 context->recordError(Error(
2217 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2218 return false;
2219 }
2220
Geoff Langdcab33b2015-07-21 13:03:16 -04002221 return true;
2222}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002223
2224bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2225{
Geoff Lang36167ab2015-12-07 10:27:14 -05002226 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002227 {
2228 // The default VAO should always exist
2229 ASSERT(array != 0);
2230 context->recordError(Error(GL_INVALID_OPERATION));
2231 return false;
2232 }
2233
2234 return true;
2235}
2236
2237bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2238{
2239 if (n < 0)
2240 {
2241 context->recordError(Error(GL_INVALID_VALUE));
2242 return false;
2243 }
2244
2245 return true;
2246}
2247
2248bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2249{
2250 if (n < 0)
2251 {
2252 context->recordError(Error(GL_INVALID_VALUE));
2253 return false;
2254 }
2255
2256 return true;
2257}
Geoff Langc5629752015-12-07 16:29:04 -05002258
2259bool ValidateProgramBinaryBase(Context *context,
2260 GLuint program,
2261 GLenum binaryFormat,
2262 const void *binary,
2263 GLint length)
2264{
2265 Program *programObject = GetValidProgram(context, program);
2266 if (programObject == nullptr)
2267 {
2268 return false;
2269 }
2270
2271 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
2272 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
2273 programBinaryFormats.end())
2274 {
2275 context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
2276 return false;
2277 }
2278
2279 return true;
2280}
2281
2282bool ValidateGetProgramBinaryBase(Context *context,
2283 GLuint program,
2284 GLsizei bufSize,
2285 GLsizei *length,
2286 GLenum *binaryFormat,
2287 void *binary)
2288{
2289 Program *programObject = GetValidProgram(context, program);
2290 if (programObject == nullptr)
2291 {
2292 return false;
2293 }
2294
2295 if (!programObject->isLinked())
2296 {
2297 context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
2298 return false;
2299 }
2300
2301 return true;
2302}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002303}