blob: fc90330dbeecb9dbf764f51246fd4de6fbf0d87e [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 Madill1ca74672015-07-21 15:14:11 -040030namespace
31{
32bool ValidateDrawAttribs(gl::Context *context, GLint primcount, GLint maxVertex)
33{
34 const gl::State &state = context->getState();
35 const gl::Program *program = state.getProgram();
36
37 const VertexArray *vao = state.getVertexArray();
38 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040039 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
40 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
41 {
42 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040043 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040044 {
45 gl::Buffer *buffer = attrib.buffer.get();
46
47 if (buffer)
48 {
49 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
50 GLint64 maxVertexElement = 0;
51
52 if (attrib.divisor > 0)
53 {
54 maxVertexElement =
55 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
56 }
57 else
58 {
59 maxVertexElement = static_cast<GLint64>(maxVertex);
60 }
61
62 // If we're drawing zero vertices, we have enough data.
63 if (maxVertexElement > 0)
64 {
65 // Note: Last vertex element does not take the full stride!
66 GLint64 attribSize =
67 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
68 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
69
70 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
71 // We can return INVALID_OPERATION if our vertex attribute does not have
72 // enough backing data.
73 if (attribDataSize > buffer->getSize())
74 {
75 context->recordError(Error(GL_INVALID_OPERATION));
76 return false;
77 }
78 }
79 }
80 else if (attrib.pointer == NULL)
81 {
82 // This is an application error that would normally result in a crash,
83 // but we catch it and return an error
84 context->recordError(Error(
85 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
86 return false;
87 }
88 }
89 }
90
91 return true;
92}
93
94} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040095
Geoff Lang0550d032014-01-30 11:29:07 -050096bool ValidCap(const Context *context, GLenum cap)
97{
98 switch (cap)
99 {
100 case GL_CULL_FACE:
101 case GL_POLYGON_OFFSET_FILL:
102 case GL_SAMPLE_ALPHA_TO_COVERAGE:
103 case GL_SAMPLE_COVERAGE:
104 case GL_SCISSOR_TEST:
105 case GL_STENCIL_TEST:
106 case GL_DEPTH_TEST:
107 case GL_BLEND:
108 case GL_DITHER:
109 return true;
110 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
111 case GL_RASTERIZER_DISCARD:
112 return (context->getClientVersion() >= 3);
113 default:
114 return false;
115 }
116}
117
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500118bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400119{
Jamie Madilld7460c72014-01-21 16:38:14 -0500120 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 case GL_TEXTURE_2D:
123 case GL_TEXTURE_CUBE_MAP:
124 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400125
Jamie Madilld7460c72014-01-21 16:38:14 -0500126 case GL_TEXTURE_3D:
127 case GL_TEXTURE_2D_ARRAY:
128 return (context->getClientVersion() >= 3);
129
130 default:
131 return false;
132 }
Jamie Madill35d15012013-10-07 10:46:37 -0400133}
134
Shannon Woods4dfed832014-03-17 20:03:39 -0400135// This function differs from ValidTextureTarget in that the target must be
136// usable as the destination of a 2D operation-- so a cube face is valid, but
137// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400138// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400139bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
140{
141 switch (target)
142 {
143 case GL_TEXTURE_2D:
144 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
145 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
150 return true;
151 case GL_TEXTURE_2D_ARRAY:
152 case GL_TEXTURE_3D:
153 return (context->getClientVersion() >= 3);
154 default:
155 return false;
156 }
157}
158
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500159bool ValidFramebufferTarget(GLenum target)
160{
Geoff Langd4475812015-03-18 10:53:05 -0400161 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
162 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500163
164 switch (target)
165 {
166 case GL_FRAMEBUFFER: return true;
167 case GL_READ_FRAMEBUFFER: return true;
168 case GL_DRAW_FRAMEBUFFER: return true;
169 default: return false;
170 }
171}
172
Jamie Madill8c96d582014-03-05 15:01:23 -0500173bool ValidBufferTarget(const Context *context, GLenum target)
174{
175 switch (target)
176 {
177 case GL_ARRAY_BUFFER:
178 case GL_ELEMENT_ARRAY_BUFFER:
179 return true;
180
Jamie Madill8c96d582014-03-05 15:01:23 -0500181 case GL_PIXEL_PACK_BUFFER:
182 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400183 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400184
Shannon Woodsb3801742014-03-27 14:59:19 -0400185 case GL_COPY_READ_BUFFER:
186 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500187 case GL_TRANSFORM_FEEDBACK_BUFFER:
188 case GL_UNIFORM_BUFFER:
189 return (context->getClientVersion() >= 3);
190
191 default:
192 return false;
193 }
194}
195
Jamie Madill70656a62014-03-05 15:01:26 -0500196bool ValidBufferParameter(const Context *context, GLenum pname)
197{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400198 const Extensions &extensions = context->getExtensions();
199
Jamie Madill70656a62014-03-05 15:01:26 -0500200 switch (pname)
201 {
202 case GL_BUFFER_USAGE:
203 case GL_BUFFER_SIZE:
204 return true;
205
Geoff Langcc6f55d2015-03-20 13:01:02 -0400206 case GL_BUFFER_ACCESS_OES:
207 return extensions.mapBuffer;
208
209 case GL_BUFFER_MAPPED:
210 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
211 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
212
Jamie Madill70656a62014-03-05 15:01:26 -0500213 // GL_BUFFER_MAP_POINTER is a special case, and may only be
214 // queried with GetBufferPointerv
215 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500216 case GL_BUFFER_MAP_OFFSET:
217 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400218 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500219
220 default:
221 return false;
222 }
223}
224
Jamie Madill8c96d582014-03-05 15:01:23 -0500225bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400226{
Geoff Langaae65a42014-05-26 12:43:44 -0400227 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400228 switch (target)
229 {
Geoff Langaae65a42014-05-26 12:43:44 -0400230 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400231 case GL_TEXTURE_CUBE_MAP:
232 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
233 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
238 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
239 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400240 default: UNREACHABLE();
241 }
242
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700243 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400244}
245
Austin Kinross08528e12015-10-07 16:24:40 -0700246bool ValidImageSizeParameters(const Context *context,
247 GLenum target,
248 GLint level,
249 GLsizei width,
250 GLsizei height,
251 GLsizei depth,
252 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400253{
254 if (level < 0 || width < 0 || height < 0 || depth < 0)
255 {
256 return false;
257 }
258
Austin Kinross08528e12015-10-07 16:24:40 -0700259 // TexSubImage parameters can be NPOT without textureNPOT extension,
260 // as long as the destination texture is POT.
261 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400262 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400263 {
264 return false;
265 }
266
267 if (!ValidMipLevel(context, target, level))
268 {
269 return false;
270 }
271
272 return true;
273}
274
Geoff Lang0d8b7242015-09-09 14:56:53 -0400275bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
276{
277 // List of compressed format that require that the texture size is smaller than or a multiple of
278 // the compressed block size.
279 switch (internalFormat)
280 {
281 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
282 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
283 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
284 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
285 return true;
286
287 default:
288 return false;
289 }
290}
291
Geoff Langb1196682014-07-23 13:47:29 -0400292bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400293{
Geoff Lang5d601382014-07-22 15:14:06 -0400294 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
295 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400296 {
297 return false;
298 }
299
Geoff Lang0d8b7242015-09-09 14:56:53 -0400300 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400301 {
302 return false;
303 }
304
Geoff Lang0d8b7242015-09-09 14:56:53 -0400305 if (CompressedTextureFormatRequiresExactSize(internalFormat))
306 {
307 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
308 width % formatInfo.compressedBlockWidth != 0) ||
309 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
310 height % formatInfo.compressedBlockHeight != 0))
311 {
312 return false;
313 }
314 }
315
Geoff Langd4f180b2013-09-24 13:57:44 -0400316 return true;
317}
318
Geoff Lang37dde692014-01-31 16:34:54 -0500319bool ValidQueryType(const Context *context, GLenum queryType)
320{
Geoff Langd4475812015-03-18 10:53:05 -0400321 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
322 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 -0500323
324 switch (queryType)
325 {
326 case GL_ANY_SAMPLES_PASSED:
327 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
328 return true;
329 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
330 return (context->getClientVersion() >= 3);
331 default:
332 return false;
333 }
334}
335
Dian Xiang769769a2015-09-09 15:20:08 -0700336Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500337{
338 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
339 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
340 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
341
Dian Xiang769769a2015-09-09 15:20:08 -0700342 Program *validProgram = context->getProgram(id);
343
344 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500345 {
Dian Xiang769769a2015-09-09 15:20:08 -0700346 if (context->getShader(id))
347 {
348 context->recordError(
349 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
350 }
351 else
352 {
353 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
354 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500355 }
Dian Xiang769769a2015-09-09 15:20:08 -0700356
357 return validProgram;
358}
359
360Shader *GetValidShader(Context *context, GLuint id)
361{
362 // See ValidProgram for spec details.
363
364 Shader *validShader = context->getShader(id);
365
366 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500367 {
Dian Xiang769769a2015-09-09 15:20:08 -0700368 if (context->getProgram(id))
369 {
370 context->recordError(
371 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
372 }
373 else
374 {
375 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
376 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500377 }
Dian Xiang769769a2015-09-09 15:20:08 -0700378
379 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500380}
381
Geoff Langb1196682014-07-23 13:47:29 -0400382bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400383{
384 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
385 {
386 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
387
Geoff Langaae65a42014-05-26 12:43:44 -0400388 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400389 {
Geoff Langb1196682014-07-23 13:47:29 -0400390 context->recordError(Error(GL_INVALID_VALUE));
391 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400392 }
393 }
394 else
395 {
396 switch (attachment)
397 {
398 case GL_DEPTH_ATTACHMENT:
399 case GL_STENCIL_ATTACHMENT:
400 break;
401
402 case GL_DEPTH_STENCIL_ATTACHMENT:
403 if (context->getClientVersion() < 3)
404 {
Geoff Langb1196682014-07-23 13:47:29 -0400405 context->recordError(Error(GL_INVALID_ENUM));
406 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400407 }
408 break;
409
410 default:
Geoff Langb1196682014-07-23 13:47:29 -0400411 context->recordError(Error(GL_INVALID_ENUM));
412 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400413 }
414 }
415
416 return true;
417}
418
Corentin Walleze0902642014-11-04 12:32:15 -0800419bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
420 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400421{
422 switch (target)
423 {
424 case GL_RENDERBUFFER:
425 break;
426 default:
Geoff Langb1196682014-07-23 13:47:29 -0400427 context->recordError(Error(GL_INVALID_ENUM));
428 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400429 }
430
431 if (width < 0 || height < 0 || samples < 0)
432 {
Geoff Langb1196682014-07-23 13:47:29 -0400433 context->recordError(Error(GL_INVALID_VALUE));
434 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400435 }
436
Geoff Langd87878e2014-09-19 15:42:59 -0400437 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
438 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400439 {
Geoff Langb1196682014-07-23 13:47:29 -0400440 context->recordError(Error(GL_INVALID_ENUM));
441 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 }
443
444 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
445 // 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 -0800446 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400447 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400448 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400449 {
Geoff Langb1196682014-07-23 13:47:29 -0400450 context->recordError(Error(GL_INVALID_ENUM));
451 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400452 }
453
Geoff Langaae65a42014-05-26 12:43:44 -0400454 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400455 {
Geoff Langb1196682014-07-23 13:47:29 -0400456 context->recordError(Error(GL_INVALID_VALUE));
457 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400458 }
459
Shannon Woods53a94a82014-06-24 15:20:36 -0400460 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400461 if (handle == 0)
462 {
Geoff Langb1196682014-07-23 13:47:29 -0400463 context->recordError(Error(GL_INVALID_OPERATION));
464 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400465 }
466
467 return true;
468}
469
Corentin Walleze0902642014-11-04 12:32:15 -0800470bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
471 GLenum internalformat, GLsizei width, GLsizei height)
472{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800473 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800474
475 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400476 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800477 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400478 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800479 {
480 context->recordError(Error(GL_INVALID_VALUE));
481 return false;
482 }
483
484 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
485 // the specified storage. This is different than ES 3.0 in which a sample number higher
486 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800487 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
488 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800489 {
Geoff Langa4903b72015-03-02 16:02:48 -0800490 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
491 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
492 {
493 context->recordError(Error(GL_OUT_OF_MEMORY));
494 return false;
495 }
Corentin Walleze0902642014-11-04 12:32:15 -0800496 }
497
498 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
499}
500
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500501bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
502 GLenum renderbuffertarget, GLuint renderbuffer)
503{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400504 if (!ValidFramebufferTarget(target))
505 {
Geoff Langb1196682014-07-23 13:47:29 -0400506 context->recordError(Error(GL_INVALID_ENUM));
507 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400508 }
509
Shannon Woods53a94a82014-06-24 15:20:36 -0400510 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500511
Jamie Madill84115c92015-04-23 15:00:07 -0400512 ASSERT(framebuffer);
513 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500514 {
Jamie Madill84115c92015-04-23 15:00:07 -0400515 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400516 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500517 }
518
Jamie Madillb4472272014-07-03 10:38:55 -0400519 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500520 {
Jamie Madillb4472272014-07-03 10:38:55 -0400521 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500522 }
523
Jamie Madillab9d82c2014-01-21 16:38:14 -0500524 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
525 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
526 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
527 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
528 if (renderbuffer != 0)
529 {
530 if (!context->getRenderbuffer(renderbuffer))
531 {
Geoff Langb1196682014-07-23 13:47:29 -0400532 context->recordError(Error(GL_INVALID_OPERATION));
533 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500534 }
535 }
536
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500537 return true;
538}
539
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400540static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400541 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
542 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
543{
544 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
545 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
546 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
547 {
548 return true;
549 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400550 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400551 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400552 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400553
Shannon Woods53a94a82014-06-24 15:20:36 -0400554 return scissor.x > 0 || scissor.y > 0 ||
555 scissor.width < writeBuffer->getWidth() ||
556 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400557 }
558 else
559 {
560 return false;
561 }
562}
563
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400564bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400565 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
566 GLenum filter, bool fromAngleExtension)
567{
568 switch (filter)
569 {
570 case GL_NEAREST:
571 break;
572 case GL_LINEAR:
573 if (fromAngleExtension)
574 {
Geoff Langb1196682014-07-23 13:47:29 -0400575 context->recordError(Error(GL_INVALID_ENUM));
576 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400577 }
578 break;
579 default:
Geoff Langb1196682014-07-23 13:47:29 -0400580 context->recordError(Error(GL_INVALID_ENUM));
581 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400582 }
583
584 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
585 {
Geoff Langb1196682014-07-23 13:47:29 -0400586 context->recordError(Error(GL_INVALID_VALUE));
587 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400588 }
589
590 if (mask == 0)
591 {
592 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
593 // buffers are copied.
594 return false;
595 }
596
597 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
598 {
599 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400600 context->recordError(Error(GL_INVALID_OPERATION));
601 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400602 }
603
604 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
605 // color buffer, leaving only nearest being unfiltered from above
606 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
607 {
Geoff Langb1196682014-07-23 13:47:29 -0400608 context->recordError(Error(GL_INVALID_OPERATION));
609 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400610 }
611
Shannon Woods53a94a82014-06-24 15:20:36 -0400612 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613 {
614 if (fromAngleExtension)
615 {
616 ERR("Blits with the same source and destination framebuffer are not supported by this "
617 "implementation.");
618 }
Geoff Langb1196682014-07-23 13:47:29 -0400619 context->recordError(Error(GL_INVALID_OPERATION));
620 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400621 }
622
Jamie Madille3ef7152015-04-28 16:55:17 +0000623 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
624 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500625
626 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627 {
Geoff Langb1196682014-07-23 13:47:29 -0400628 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
629 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 }
631
Geoff Lang748f74e2014-12-01 11:25:34 -0500632 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500633 {
634 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
635 return false;
636 }
637
Geoff Lang748f74e2014-12-01 11:25:34 -0500638 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500639 {
640 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
641 return false;
642 }
643
644 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 {
Geoff Langb1196682014-07-23 13:47:29 -0400646 context->recordError(Error(GL_INVALID_OPERATION));
647 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400648 }
649
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
651
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 if (mask & GL_COLOR_BUFFER_BIT)
653 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400654 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
655 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656
657 if (readColorBuffer && drawColorBuffer)
658 {
Geoff Langd8a22582014-12-17 15:28:23 -0500659 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400660 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661
Corentin Wallez37c39792015-08-20 14:19:46 -0400662 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400663 {
664 if (drawFramebuffer->isEnabledColorAttachment(i))
665 {
Geoff Langd8a22582014-12-17 15:28:23 -0500666 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400667 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668
Geoff Langb2f3d052013-08-13 12:49:27 -0400669 // The GL ES 3.0.2 spec (pg 193) states that:
670 // 1) If the read buffer is fixed point format, the draw buffer must be as well
671 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
672 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400673 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
674 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 {
Geoff Langb1196682014-07-23 13:47:29 -0400676 context->recordError(Error(GL_INVALID_OPERATION));
677 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678 }
679
Geoff Lang5d601382014-07-22 15:14:06 -0400680 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400681 {
Geoff Langb1196682014-07-23 13:47:29 -0400682 context->recordError(Error(GL_INVALID_OPERATION));
683 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684 }
685
Geoff Lang5d601382014-07-22 15:14:06 -0400686 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 {
Geoff Langb1196682014-07-23 13:47:29 -0400688 context->recordError(Error(GL_INVALID_OPERATION));
689 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690 }
691
Geoff Langb2f3d052013-08-13 12:49:27 -0400692 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 {
Geoff Langb1196682014-07-23 13:47:29 -0400694 context->recordError(Error(GL_INVALID_OPERATION));
695 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 }
697 }
698 }
699
Geoff Lang5d601382014-07-22 15:14:06 -0400700 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400701 {
Geoff Langb1196682014-07-23 13:47:29 -0400702 context->recordError(Error(GL_INVALID_OPERATION));
703 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400704 }
705
706 if (fromAngleExtension)
707 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400708 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500709 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400710 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500711 readColorAttachment->type() != GL_RENDERBUFFER &&
712 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713 {
Geoff Langb1196682014-07-23 13:47:29 -0400714 context->recordError(Error(GL_INVALID_OPERATION));
715 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716 }
717
Corentin Wallez37c39792015-08-20 14:19:46 -0400718 for (size_t colorAttachment = 0;
719 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720 {
721 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
722 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000723 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400724 ASSERT(attachment);
725
Jamie Madill8cf4a392015-04-02 11:36:04 -0400726 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500727 attachment->type() != GL_RENDERBUFFER &&
728 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400729 {
Geoff Langb1196682014-07-23 13:47:29 -0400730 context->recordError(Error(GL_INVALID_OPERATION));
731 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 }
733
Jamie Madillf8f18f02014-10-02 10:44:17 -0400734 // Return an error if the destination formats do not match
735 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
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 }
Jamie Madill48faf802014-11-06 15:27:22 -0500742
743 int readSamples = readFramebuffer->getSamples(context->getData());
744
745 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
746 srcX0, srcY0, srcX1, srcY1,
747 dstX0, dstY0, dstX1, dstY1))
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 }
753 }
754 }
755
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200756 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
757 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
758 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200760 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400762 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
763 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200765 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 {
Geoff Langd8a22582014-12-17 15:28:23 -0500767 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Geoff Langb1196682014-07-23 13:47:29 -0400769 context->recordError(Error(GL_INVALID_OPERATION));
770 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400771 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200773 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 {
Geoff Langb1196682014-07-23 13:47:29 -0400775 context->recordError(Error(GL_INVALID_OPERATION));
776 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200778
779 if (fromAngleExtension)
780 {
781 if (IsPartialBlit(context, readBuffer, drawBuffer,
782 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
783 {
784 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
785 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
786 return false;
787 }
788
789 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
790 {
791 context->recordError(Error(GL_INVALID_OPERATION));
792 return false;
793 }
794 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 }
796 }
797 }
798
799 return true;
800}
801
Geoff Langb1196682014-07-23 13:47:29 -0400802bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400803{
804 switch (pname)
805 {
806 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
807 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
808 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
809 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
810 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
811 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
812 case GL_CURRENT_VERTEX_ATTRIB:
813 return true;
814
815 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
816 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
817 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400818 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
819 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400820 return true;
821
822 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400823 if (context->getClientVersion() < 3)
824 {
825 context->recordError(Error(GL_INVALID_ENUM));
826 return false;
827 }
828 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829
830 default:
Geoff Langb1196682014-07-23 13:47:29 -0400831 context->recordError(Error(GL_INVALID_ENUM));
832 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833 }
834}
835
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400836bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837{
838 switch (pname)
839 {
840 case GL_TEXTURE_WRAP_R:
841 case GL_TEXTURE_SWIZZLE_R:
842 case GL_TEXTURE_SWIZZLE_G:
843 case GL_TEXTURE_SWIZZLE_B:
844 case GL_TEXTURE_SWIZZLE_A:
845 case GL_TEXTURE_BASE_LEVEL:
846 case GL_TEXTURE_MAX_LEVEL:
847 case GL_TEXTURE_COMPARE_MODE:
848 case GL_TEXTURE_COMPARE_FUNC:
849 case GL_TEXTURE_MIN_LOD:
850 case GL_TEXTURE_MAX_LOD:
851 if (context->getClientVersion() < 3)
852 {
Geoff Langb1196682014-07-23 13:47:29 -0400853 context->recordError(Error(GL_INVALID_ENUM));
854 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400855 }
856 break;
857
858 default: break;
859 }
860
861 switch (pname)
862 {
863 case GL_TEXTURE_WRAP_S:
864 case GL_TEXTURE_WRAP_T:
865 case GL_TEXTURE_WRAP_R:
866 switch (param)
867 {
868 case GL_REPEAT:
869 case GL_CLAMP_TO_EDGE:
870 case GL_MIRRORED_REPEAT:
871 return true;
872 default:
Geoff Langb1196682014-07-23 13:47:29 -0400873 context->recordError(Error(GL_INVALID_ENUM));
874 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400875 }
876
877 case GL_TEXTURE_MIN_FILTER:
878 switch (param)
879 {
880 case GL_NEAREST:
881 case GL_LINEAR:
882 case GL_NEAREST_MIPMAP_NEAREST:
883 case GL_LINEAR_MIPMAP_NEAREST:
884 case GL_NEAREST_MIPMAP_LINEAR:
885 case GL_LINEAR_MIPMAP_LINEAR:
886 return true;
887 default:
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 case GL_TEXTURE_MAG_FILTER:
894 switch (param)
895 {
896 case GL_NEAREST:
897 case GL_LINEAR:
898 return true;
899 default:
Geoff Langb1196682014-07-23 13:47:29 -0400900 context->recordError(Error(GL_INVALID_ENUM));
901 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902 }
903 break;
904
905 case GL_TEXTURE_USAGE_ANGLE:
906 switch (param)
907 {
908 case GL_NONE:
909 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
910 return true;
911 default:
Geoff Langb1196682014-07-23 13:47:29 -0400912 context->recordError(Error(GL_INVALID_ENUM));
913 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400914 }
915 break;
916
917 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400918 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400919 {
Geoff Langb1196682014-07-23 13:47:29 -0400920 context->recordError(Error(GL_INVALID_ENUM));
921 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400922 }
923
924 // we assume the parameter passed to this validation method is truncated, not rounded
925 if (param < 1)
926 {
Geoff Langb1196682014-07-23 13:47:29 -0400927 context->recordError(Error(GL_INVALID_VALUE));
928 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400929 }
930 return true;
931
932 case GL_TEXTURE_MIN_LOD:
933 case GL_TEXTURE_MAX_LOD:
934 // any value is permissible
935 return true;
936
937 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400938 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 switch (param)
940 {
941 case GL_NONE:
942 case GL_COMPARE_REF_TO_TEXTURE:
943 return true;
944 default:
Geoff Langb1196682014-07-23 13:47:29 -0400945 context->recordError(Error(GL_INVALID_ENUM));
946 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400947 }
948 break;
949
950 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400951 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400952 switch (param)
953 {
954 case GL_LEQUAL:
955 case GL_GEQUAL:
956 case GL_LESS:
957 case GL_GREATER:
958 case GL_EQUAL:
959 case GL_NOTEQUAL:
960 case GL_ALWAYS:
961 case GL_NEVER:
962 return true;
963 default:
Geoff Langb1196682014-07-23 13:47:29 -0400964 context->recordError(Error(GL_INVALID_ENUM));
965 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400966 }
967 break;
968
969 case GL_TEXTURE_SWIZZLE_R:
970 case GL_TEXTURE_SWIZZLE_G:
971 case GL_TEXTURE_SWIZZLE_B:
972 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400973 switch (param)
974 {
975 case GL_RED:
976 case GL_GREEN:
977 case GL_BLUE:
978 case GL_ALPHA:
979 case GL_ZERO:
980 case GL_ONE:
981 return true;
982 default:
Geoff Langb1196682014-07-23 13:47:29 -0400983 context->recordError(Error(GL_INVALID_ENUM));
984 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400985 }
986 break;
987
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400988 case GL_TEXTURE_BASE_LEVEL:
989 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400990 if (param < 0)
991 {
Geoff Langb1196682014-07-23 13:47:29 -0400992 context->recordError(Error(GL_INVALID_VALUE));
993 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400994 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400995 return true;
996
997 default:
Geoff Langb1196682014-07-23 13:47:29 -0400998 context->recordError(Error(GL_INVALID_ENUM));
999 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001000 }
1001}
1002
Geoff Langb1196682014-07-23 13:47:29 -04001003bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001004{
1005 switch (pname)
1006 {
1007 case GL_TEXTURE_MIN_FILTER:
1008 case GL_TEXTURE_MAG_FILTER:
1009 case GL_TEXTURE_WRAP_S:
1010 case GL_TEXTURE_WRAP_T:
1011 case GL_TEXTURE_WRAP_R:
1012 case GL_TEXTURE_MIN_LOD:
1013 case GL_TEXTURE_MAX_LOD:
1014 case GL_TEXTURE_COMPARE_MODE:
1015 case GL_TEXTURE_COMPARE_FUNC:
1016 return true;
1017
1018 default:
Geoff Langb1196682014-07-23 13:47:29 -04001019 context->recordError(Error(GL_INVALID_ENUM));
1020 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001021 }
1022}
1023
Jamie Madill26e91952014-03-05 15:01:27 -05001024bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
1025 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
1026{
Shannon Woods53a94a82014-06-24 15:20:36 -04001027 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001028 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001029
Geoff Lang748f74e2014-12-01 11:25:34 -05001030 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001031 {
Geoff Langb1196682014-07-23 13:47:29 -04001032 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1033 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001034 }
1035
Jamie Madill48faf802014-11-06 15:27:22 -05001036 if (context->getState().getReadFramebuffer()->id() != 0 &&
1037 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001038 {
Geoff Langb1196682014-07-23 13:47:29 -04001039 context->recordError(Error(GL_INVALID_OPERATION));
1040 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001041 }
1042
Geoff Langbce529e2014-12-01 12:48:41 -05001043 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1044 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001045 {
Geoff Langb1196682014-07-23 13:47:29 -04001046 context->recordError(Error(GL_INVALID_OPERATION));
1047 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001048 }
1049
Geoff Langbce529e2014-12-01 12:48:41 -05001050 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1051 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001052 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001053 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001054
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001055 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1056 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001057
1058 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1059 {
Geoff Langb1196682014-07-23 13:47:29 -04001060 context->recordError(Error(GL_INVALID_OPERATION));
1061 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001062 }
1063
Geoff Lang5d601382014-07-22 15:14:06 -04001064 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1065 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001066
Minmin Gongadff67b2015-10-14 10:34:45 -04001067 GLsizei outputPitch =
1068 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1069 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001070 // sized query sanity check
1071 if (bufSize)
1072 {
1073 int requiredSize = outputPitch * height;
1074 if (requiredSize > *bufSize)
1075 {
Geoff Langb1196682014-07-23 13:47:29 -04001076 context->recordError(Error(GL_INVALID_OPERATION));
1077 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001078 }
1079 }
1080
1081 return true;
1082}
1083
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001084bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1085{
1086 if (!ValidQueryType(context, target))
1087 {
Geoff Langb1196682014-07-23 13:47:29 -04001088 context->recordError(Error(GL_INVALID_ENUM));
1089 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001090 }
1091
1092 if (id == 0)
1093 {
Geoff Langb1196682014-07-23 13:47:29 -04001094 context->recordError(Error(GL_INVALID_OPERATION));
1095 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001096 }
1097
1098 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1099 // of zero, if the active query object name for <target> is non-zero (for the
1100 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1101 // the active query for either target is non-zero), if <id> is the name of an
1102 // existing query object whose type does not match <target>, or if <id> is the
1103 // active query object name for any query type, the error INVALID_OPERATION is
1104 // generated.
1105
1106 // Ensure no other queries are active
1107 // NOTE: If other queries than occlusion are supported, we will need to check
1108 // separately that:
1109 // a) The query ID passed is not the current active query for any target/type
1110 // b) There are no active queries for the requested target (and in the case
1111 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1112 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001113 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001114 {
Geoff Langb1196682014-07-23 13:47:29 -04001115 context->recordError(Error(GL_INVALID_OPERATION));
1116 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001117 }
1118
1119 Query *queryObject = context->getQuery(id, true, target);
1120
1121 // check that name was obtained with glGenQueries
1122 if (!queryObject)
1123 {
Geoff Langb1196682014-07-23 13:47:29 -04001124 context->recordError(Error(GL_INVALID_OPERATION));
1125 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001126 }
1127
1128 // check for type mismatch
1129 if (queryObject->getType() != target)
1130 {
Geoff Langb1196682014-07-23 13:47:29 -04001131 context->recordError(Error(GL_INVALID_OPERATION));
1132 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001133 }
1134
1135 return true;
1136}
1137
Jamie Madill45c785d2014-05-13 14:09:34 -04001138bool ValidateEndQuery(gl::Context *context, GLenum target)
1139{
1140 if (!ValidQueryType(context, target))
1141 {
Geoff Langb1196682014-07-23 13:47:29 -04001142 context->recordError(Error(GL_INVALID_ENUM));
1143 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001144 }
1145
Shannon Woods53a94a82014-06-24 15:20:36 -04001146 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001147
1148 if (queryObject == NULL)
1149 {
Geoff Langb1196682014-07-23 13:47:29 -04001150 context->recordError(Error(GL_INVALID_OPERATION));
1151 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001152 }
1153
Jamie Madill45c785d2014-05-13 14:09:34 -04001154 return true;
1155}
1156
Jamie Madill62d31cb2015-09-11 13:25:51 -04001157static bool ValidateUniformCommonBase(gl::Context *context,
1158 GLenum targetUniformType,
1159 GLint location,
1160 GLsizei count,
1161 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001162{
1163 if (count < 0)
1164 {
Geoff Langb1196682014-07-23 13:47:29 -04001165 context->recordError(Error(GL_INVALID_VALUE));
1166 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001167 }
1168
Geoff Lang7dd2e102014-11-10 15:19:26 -05001169 gl::Program *program = context->getState().getProgram();
1170 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001171 {
Geoff Langb1196682014-07-23 13:47:29 -04001172 context->recordError(Error(GL_INVALID_OPERATION));
1173 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001174 }
1175
1176 if (location == -1)
1177 {
1178 // Silently ignore the uniform command
1179 return false;
1180 }
1181
Geoff Lang7dd2e102014-11-10 15:19:26 -05001182 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001183 {
Geoff Langb1196682014-07-23 13:47:29 -04001184 context->recordError(Error(GL_INVALID_OPERATION));
1185 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001186 }
1187
Jamie Madill62d31cb2015-09-11 13:25:51 -04001188 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001189
1190 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001191 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001192 {
Geoff Langb1196682014-07-23 13:47:29 -04001193 context->recordError(Error(GL_INVALID_OPERATION));
1194 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001195 }
1196
Jamie Madill62d31cb2015-09-11 13:25:51 -04001197 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001198 return true;
1199}
1200
Jamie Madillaa981bd2014-05-20 10:55:55 -04001201bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1202{
1203 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001204 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001205 {
Geoff Langb1196682014-07-23 13:47:29 -04001206 context->recordError(Error(GL_INVALID_OPERATION));
1207 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001208 }
1209
Jamie Madill62d31cb2015-09-11 13:25:51 -04001210 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001211 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1212 {
1213 return false;
1214 }
1215
Jamie Madillf2575982014-06-25 16:04:54 -04001216 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001217 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001218 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1219 {
Geoff Langb1196682014-07-23 13:47:29 -04001220 context->recordError(Error(GL_INVALID_OPERATION));
1221 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001222 }
1223
1224 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001225}
1226
1227bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1228 GLboolean transpose)
1229{
1230 // Check for ES3 uniform entry points
1231 int rows = VariableRowCount(matrixType);
1232 int cols = VariableColumnCount(matrixType);
1233 if (rows != cols && context->getClientVersion() < 3)
1234 {
Geoff Langb1196682014-07-23 13:47:29 -04001235 context->recordError(Error(GL_INVALID_OPERATION));
1236 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001237 }
1238
1239 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1240 {
Geoff Langb1196682014-07-23 13:47:29 -04001241 context->recordError(Error(GL_INVALID_VALUE));
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, matrixType, location, count, &uniform))
1247 {
1248 return false;
1249 }
1250
1251 if (uniform->type != matrixType)
1252 {
Geoff Langb1196682014-07-23 13:47:29 -04001253 context->recordError(Error(GL_INVALID_OPERATION));
1254 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001255 }
1256
1257 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001258}
1259
Jamie Madill893ab082014-05-16 16:56:10 -04001260bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1261{
1262 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1263 {
Geoff Langb1196682014-07-23 13:47:29 -04001264 context->recordError(Error(GL_INVALID_ENUM));
1265 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001266 }
1267
Jamie Madill0af26e12015-03-05 19:54:33 -05001268 const Caps &caps = context->getCaps();
1269
Jamie Madill893ab082014-05-16 16:56:10 -04001270 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1271 {
1272 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1273
Jamie Madill0af26e12015-03-05 19:54:33 -05001274 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001275 {
Geoff Langb1196682014-07-23 13:47:29 -04001276 context->recordError(Error(GL_INVALID_OPERATION));
1277 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001278 }
1279 }
1280
1281 switch (pname)
1282 {
1283 case GL_TEXTURE_BINDING_2D:
1284 case GL_TEXTURE_BINDING_CUBE_MAP:
1285 case GL_TEXTURE_BINDING_3D:
1286 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001287 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001288 {
Geoff Langb1196682014-07-23 13:47:29 -04001289 context->recordError(Error(GL_INVALID_OPERATION));
1290 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001291 }
1292 break;
1293
1294 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1295 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1296 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001297 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001298 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001299 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001300 {
Geoff Langb1196682014-07-23 13:47:29 -04001301 context->recordError(Error(GL_INVALID_OPERATION));
1302 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001303 }
1304
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001305 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001306 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001307 {
Geoff Langb1196682014-07-23 13:47:29 -04001308 context->recordError(Error(GL_INVALID_OPERATION));
1309 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001310 }
1311 }
1312 break;
1313
1314 default:
1315 break;
1316 }
1317
1318 // pname is valid, but there are no parameters to return
1319 if (numParams == 0)
1320 {
1321 return false;
1322 }
1323
1324 return true;
1325}
1326
Geoff Lang831b1952015-05-05 11:02:27 -04001327bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001328 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1329 GLint border, GLenum *textureFormatOut)
1330{
1331
1332 if (!ValidTexture2DDestinationTarget(context, target))
1333 {
Geoff Langb1196682014-07-23 13:47:29 -04001334 context->recordError(Error(GL_INVALID_ENUM));
1335 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001336 }
1337
1338 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1339 {
Geoff Langb1196682014-07-23 13:47:29 -04001340 context->recordError(Error(GL_INVALID_VALUE));
1341 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001342 }
1343
1344 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1345 {
Geoff Langb1196682014-07-23 13:47:29 -04001346 context->recordError(Error(GL_INVALID_VALUE));
1347 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001348 }
1349
1350 if (border != 0)
1351 {
Geoff Langb1196682014-07-23 13:47:29 -04001352 context->recordError(Error(GL_INVALID_VALUE));
1353 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001354 }
1355
1356 if (!ValidMipLevel(context, target, level))
1357 {
Geoff Langb1196682014-07-23 13:47:29 -04001358 context->recordError(Error(GL_INVALID_VALUE));
1359 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001360 }
1361
Shannon Woods53a94a82014-06-24 15:20:36 -04001362 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001363 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001364 {
Geoff Langb1196682014-07-23 13:47:29 -04001365 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1366 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001367 }
1368
Jamie Madill48faf802014-11-06 15:27:22 -05001369 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 {
Geoff Langb1196682014-07-23 13:47:29 -04001371 context->recordError(Error(GL_INVALID_OPERATION));
1372 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001373 }
1374
Geoff Langaae65a42014-05-26 12:43:44 -04001375 const gl::Caps &caps = context->getCaps();
1376
Geoff Langaae65a42014-05-26 12:43:44 -04001377 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001378 switch (target)
1379 {
1380 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001381 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001382 break;
1383
1384 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1385 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1386 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1387 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1388 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1389 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001390 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001391 break;
1392
1393 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001394 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001395 break;
1396
1397 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001398 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001399 break;
1400
1401 default:
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_ENUM));
1403 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001404 }
1405
Geoff Lang691e58c2014-12-19 17:03:25 -05001406 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001407 if (!texture)
1408 {
Geoff Langb1196682014-07-23 13:47:29 -04001409 context->recordError(Error(GL_INVALID_OPERATION));
1410 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001411 }
1412
Geoff Lang69cce582015-09-17 13:20:36 -04001413 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001414 {
Geoff Langb1196682014-07-23 13:47:29 -04001415 context->recordError(Error(GL_INVALID_OPERATION));
1416 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001417 }
1418
Geoff Lang5d601382014-07-22 15:14:06 -04001419 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1420
1421 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001422 {
Geoff Langb1196682014-07-23 13:47:29 -04001423 context->recordError(Error(GL_INVALID_OPERATION));
1424 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001425 }
1426
Geoff Langa9be0dc2014-12-17 12:34:40 -05001427 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001428 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001429 context->recordError(Error(GL_INVALID_OPERATION));
1430 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001431 }
1432
1433 if (isSubImage)
1434 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001435 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1436 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1437 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001438 {
Geoff Langb1196682014-07-23 13:47:29 -04001439 context->recordError(Error(GL_INVALID_VALUE));
1440 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001441 }
1442 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001443 else
1444 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001445 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001446 {
Geoff Langb1196682014-07-23 13:47:29 -04001447 context->recordError(Error(GL_INVALID_VALUE));
1448 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001449 }
1450
Geoff Lang5d601382014-07-22 15:14:06 -04001451 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001452 {
Geoff Langb1196682014-07-23 13:47:29 -04001453 context->recordError(Error(GL_INVALID_ENUM));
1454 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001455 }
1456
1457 int maxLevelDimension = (maxDimension >> level);
1458 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1459 {
Geoff Langb1196682014-07-23 13:47:29 -04001460 context->recordError(Error(GL_INVALID_VALUE));
1461 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001462 }
1463 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001464
Geoff Langa9be0dc2014-12-17 12:34:40 -05001465 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001466 return true;
1467}
1468
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001469static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001470{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001471 switch (mode)
1472 {
1473 case GL_POINTS:
1474 case GL_LINES:
1475 case GL_LINE_LOOP:
1476 case GL_LINE_STRIP:
1477 case GL_TRIANGLES:
1478 case GL_TRIANGLE_STRIP:
1479 case GL_TRIANGLE_FAN:
1480 break;
1481 default:
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_ENUM));
1483 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001484 }
1485
Jamie Madill250d33f2014-06-06 17:09:03 -04001486 if (count < 0)
1487 {
Geoff Langb1196682014-07-23 13:47:29 -04001488 context->recordError(Error(GL_INVALID_VALUE));
1489 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001490 }
1491
Geoff Langb1196682014-07-23 13:47:29 -04001492 const State &state = context->getState();
1493
Jamie Madill250d33f2014-06-06 17:09:03 -04001494 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001495 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001496 {
Geoff Langb1196682014-07-23 13:47:29 -04001497 context->recordError(Error(GL_INVALID_OPERATION));
1498 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001499 }
1500
Geoff Lang3a86ad32015-09-01 11:47:05 -04001501 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001502 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001503 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1504 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1505 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1506 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1507 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1508 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1509 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001510 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001511 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1512 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001513 {
1514 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1515 // Section 6.10 of the WebGL 1.0 spec
1516 ERR(
1517 "This ANGLE implementation does not support separate front/back stencil "
1518 "writemasks, reference values, or stencil mask values.");
1519 context->recordError(Error(GL_INVALID_OPERATION));
1520 return false;
1521 }
Jamie Madillac528012014-06-20 13:21:23 -04001522 }
1523
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001524 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001525 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001526 {
Geoff Langb1196682014-07-23 13:47:29 -04001527 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1528 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001529 }
1530
Geoff Lang7dd2e102014-11-10 15:19:26 -05001531 gl::Program *program = state.getProgram();
1532 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001533 {
Geoff Langb1196682014-07-23 13:47:29 -04001534 context->recordError(Error(GL_INVALID_OPERATION));
1535 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001536 }
1537
Geoff Lang7dd2e102014-11-10 15:19:26 -05001538 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001539 {
Geoff Langb1196682014-07-23 13:47:29 -04001540 context->recordError(Error(GL_INVALID_OPERATION));
1541 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001542 }
1543
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001544 // Uniform buffer validation
1545 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1546 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001547 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001548 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001549 const OffsetBindingPointer<Buffer> &uniformBuffer =
1550 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001551
Geoff Lang5d124a62015-09-15 13:03:27 -04001552 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001553 {
1554 // undefined behaviour
1555 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1556 return false;
1557 }
1558
Geoff Lang5d124a62015-09-15 13:03:27 -04001559 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001560 if (uniformBufferSize == 0)
1561 {
1562 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001563 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001564 }
1565
Jamie Madill62d31cb2015-09-11 13:25:51 -04001566 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001567 {
1568 // undefined behaviour
1569 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1570 return false;
1571 }
1572 }
1573
Jamie Madill250d33f2014-06-06 17:09:03 -04001574 // No-op if zero count
1575 return (count > 0);
1576}
1577
Geoff Langb1196682014-07-23 13:47:29 -04001578bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001579{
Jamie Madillfd716582014-06-06 17:09:04 -04001580 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001581 {
Geoff Langb1196682014-07-23 13:47:29 -04001582 context->recordError(Error(GL_INVALID_VALUE));
1583 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001584 }
1585
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001586 const State &state = context->getState();
1587 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001588 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1589 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001590 {
1591 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1592 // that does not match the current transform feedback object's draw mode (if transform feedback
1593 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001594 context->recordError(Error(GL_INVALID_OPERATION));
1595 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001596 }
1597
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001598 if (!ValidateDrawBase(context, mode, count, primcount))
1599 {
1600 return false;
1601 }
1602
1603 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001604 {
1605 return false;
1606 }
1607
1608 return true;
1609}
1610
Geoff Langb1196682014-07-23 13:47:29 -04001611bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001612{
1613 if (primcount < 0)
1614 {
Geoff Langb1196682014-07-23 13:47:29 -04001615 context->recordError(Error(GL_INVALID_VALUE));
1616 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001617 }
1618
Jamie Madill2b976812014-08-25 15:47:49 -04001619 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001620 {
1621 return false;
1622 }
1623
1624 // No-op if zero primitive count
1625 return (primcount > 0);
1626}
1627
Geoff Lang87a93302014-09-16 13:29:43 -04001628static bool ValidateDrawInstancedANGLE(Context *context)
1629{
1630 // Verify there is at least one active attribute with a divisor of zero
1631 const gl::State& state = context->getState();
1632
Geoff Lang7dd2e102014-11-10 15:19:26 -05001633 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001634
1635 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001636 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001637 {
1638 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001639 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001640 {
1641 return true;
1642 }
1643 }
1644
1645 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1646 "has a divisor of zero."));
1647 return false;
1648}
1649
1650bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1651{
1652 if (!ValidateDrawInstancedANGLE(context))
1653 {
1654 return false;
1655 }
1656
1657 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1658}
1659
Geoff Lang3edfe032015-09-04 16:38:24 -04001660bool ValidateDrawElements(Context *context,
1661 GLenum mode,
1662 GLsizei count,
1663 GLenum type,
1664 const GLvoid *indices,
1665 GLsizei primcount,
1666 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001667{
Jamie Madill250d33f2014-06-06 17:09:03 -04001668 switch (type)
1669 {
1670 case GL_UNSIGNED_BYTE:
1671 case GL_UNSIGNED_SHORT:
1672 break;
1673 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001674 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001675 {
Geoff Langb1196682014-07-23 13:47:29 -04001676 context->recordError(Error(GL_INVALID_ENUM));
1677 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001678 }
1679 break;
1680 default:
Geoff Langb1196682014-07-23 13:47:29 -04001681 context->recordError(Error(GL_INVALID_ENUM));
1682 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001683 }
1684
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001685 const State &state = context->getState();
1686
1687 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001688 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001689 {
1690 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1691 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001692 context->recordError(Error(GL_INVALID_OPERATION));
1693 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001694 }
1695
1696 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001697 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001698 {
Geoff Langb1196682014-07-23 13:47:29 -04001699 context->recordError(Error(GL_INVALID_OPERATION));
1700 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001701 }
1702
Jamie Madill2b976812014-08-25 15:47:49 -04001703 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001704 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001705 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001706 {
Geoff Langb1196682014-07-23 13:47:29 -04001707 context->recordError(Error(GL_INVALID_OPERATION));
1708 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001709 }
1710
Jamie Madillae3000b2014-08-25 15:47:51 -04001711 if (elementArrayBuffer)
1712 {
1713 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1714
1715 GLint64 offset = reinterpret_cast<GLint64>(indices);
1716 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1717
1718 // check for integer overflows
1719 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1720 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1721 {
Geoff Langb1196682014-07-23 13:47:29 -04001722 context->recordError(Error(GL_OUT_OF_MEMORY));
1723 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001724 }
1725
1726 // Check for reading past the end of the bound buffer object
1727 if (byteCount > elementArrayBuffer->getSize())
1728 {
Geoff Langb1196682014-07-23 13:47:29 -04001729 context->recordError(Error(GL_INVALID_OPERATION));
1730 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001731 }
1732 }
1733 else if (!indices)
1734 {
1735 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001736 context->recordError(Error(GL_INVALID_OPERATION));
1737 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001738 }
1739
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001740 if (!ValidateDrawBase(context, mode, count, primcount))
1741 {
1742 return false;
1743 }
1744
Jamie Madill2b976812014-08-25 15:47:49 -04001745 // Use max index to validate if our vertex buffers are large enough for the pull.
1746 // TODO: offer fast path, with disabled index validation.
1747 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1748 if (elementArrayBuffer)
1749 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001750 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001751 Error error =
1752 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1753 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001754 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001755 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001756 context->recordError(error);
1757 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001758 }
1759 }
1760 else
1761 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001762 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001763 }
1764
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001765 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001766 {
1767 return false;
1768 }
1769
Geoff Lang3edfe032015-09-04 16:38:24 -04001770 // No op if there are no real indices in the index data (all are primitive restart).
1771 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001772}
1773
Geoff Langb1196682014-07-23 13:47:29 -04001774bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001775 GLenum mode,
1776 GLsizei count,
1777 GLenum type,
1778 const GLvoid *indices,
1779 GLsizei primcount,
1780 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001781{
1782 if (primcount < 0)
1783 {
Geoff Langb1196682014-07-23 13:47:29 -04001784 context->recordError(Error(GL_INVALID_VALUE));
1785 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001786 }
1787
Jamie Madill2b976812014-08-25 15:47:49 -04001788 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001789 {
1790 return false;
1791 }
1792
1793 // No-op zero primitive count
1794 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001795}
1796
Geoff Lang3edfe032015-09-04 16:38:24 -04001797bool ValidateDrawElementsInstancedANGLE(Context *context,
1798 GLenum mode,
1799 GLsizei count,
1800 GLenum type,
1801 const GLvoid *indices,
1802 GLsizei primcount,
1803 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001804{
1805 if (!ValidateDrawInstancedANGLE(context))
1806 {
1807 return false;
1808 }
1809
1810 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1811}
1812
Geoff Langb1196682014-07-23 13:47:29 -04001813bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001814 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001815{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001816 if (!ValidFramebufferTarget(target))
1817 {
Geoff Langb1196682014-07-23 13:47:29 -04001818 context->recordError(Error(GL_INVALID_ENUM));
1819 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001820 }
1821
1822 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001823 {
1824 return false;
1825 }
1826
Jamie Madill55ec3b12014-07-03 10:38:57 -04001827 if (texture != 0)
1828 {
1829 gl::Texture *tex = context->getTexture(texture);
1830
1831 if (tex == NULL)
1832 {
Geoff Langb1196682014-07-23 13:47:29 -04001833 context->recordError(Error(GL_INVALID_OPERATION));
1834 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001835 }
1836
1837 if (level < 0)
1838 {
Geoff Langb1196682014-07-23 13:47:29 -04001839 context->recordError(Error(GL_INVALID_VALUE));
1840 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001841 }
1842 }
1843
Shannon Woods53a94a82014-06-24 15:20:36 -04001844 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001845 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001846
Jamie Madill84115c92015-04-23 15:00:07 -04001847 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001848 {
Jamie Madill84115c92015-04-23 15:00:07 -04001849 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001850 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001851 }
1852
1853 return true;
1854}
1855
Geoff Langb1196682014-07-23 13:47:29 -04001856bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001857 GLenum textarget, GLuint texture, GLint level)
1858{
Geoff Lang95663912015-04-02 15:54:45 -04001859 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1860 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001861 {
Geoff Langb1196682014-07-23 13:47:29 -04001862 context->recordError(Error(GL_INVALID_VALUE));
1863 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001864 }
1865
1866 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001867 {
1868 return false;
1869 }
1870
Jamie Madill55ec3b12014-07-03 10:38:57 -04001871 if (texture != 0)
1872 {
1873 gl::Texture *tex = context->getTexture(texture);
1874 ASSERT(tex);
1875
Jamie Madill2a6564e2014-07-11 09:53:19 -04001876 const gl::Caps &caps = context->getCaps();
1877
Jamie Madill55ec3b12014-07-03 10:38:57 -04001878 switch (textarget)
1879 {
1880 case GL_TEXTURE_2D:
1881 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001882 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001883 {
Geoff Langb1196682014-07-23 13:47:29 -04001884 context->recordError(Error(GL_INVALID_VALUE));
1885 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001886 }
1887 if (tex->getTarget() != GL_TEXTURE_2D)
1888 {
Geoff Langb1196682014-07-23 13:47:29 -04001889 context->recordError(Error(GL_INVALID_OPERATION));
1890 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001891 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001892 }
1893 break;
1894
1895 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1896 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1897 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1898 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1899 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1900 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1901 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001902 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001903 {
Geoff Langb1196682014-07-23 13:47:29 -04001904 context->recordError(Error(GL_INVALID_VALUE));
1905 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001906 }
1907 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1908 {
Geoff Langb1196682014-07-23 13:47:29 -04001909 context->recordError(Error(GL_INVALID_OPERATION));
1910 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001911 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001912 }
1913 break;
1914
1915 default:
Geoff Langb1196682014-07-23 13:47:29 -04001916 context->recordError(Error(GL_INVALID_ENUM));
1917 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001918 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001919
1920 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1921 if (internalFormatInfo.compressed)
1922 {
1923 context->recordError(Error(GL_INVALID_OPERATION));
1924 return false;
1925 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001926 }
1927
Jamie Madill570f7c82014-07-03 10:38:54 -04001928 return true;
1929}
1930
Geoff Langb1196682014-07-23 13:47:29 -04001931bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001932{
1933 if (program == 0)
1934 {
Geoff Langb1196682014-07-23 13:47:29 -04001935 context->recordError(Error(GL_INVALID_VALUE));
1936 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001937 }
1938
Dian Xiang769769a2015-09-09 15:20:08 -07001939 gl::Program *programObject = GetValidProgram(context, program);
1940 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001941 {
1942 return false;
1943 }
1944
Jamie Madill0063c512014-08-25 15:47:53 -04001945 if (!programObject || !programObject->isLinked())
1946 {
Geoff Langb1196682014-07-23 13:47:29 -04001947 context->recordError(Error(GL_INVALID_OPERATION));
1948 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001949 }
1950
Geoff Lang7dd2e102014-11-10 15:19:26 -05001951 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001952 {
Geoff Langb1196682014-07-23 13:47:29 -04001953 context->recordError(Error(GL_INVALID_OPERATION));
1954 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001955 }
1956
Jamie Madill0063c512014-08-25 15:47:53 -04001957 return true;
1958}
1959
Geoff Langb1196682014-07-23 13:47:29 -04001960bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001961{
1962 return ValidateGetUniformBase(context, program, location);
1963}
1964
Geoff Langb1196682014-07-23 13:47:29 -04001965bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001966{
Jamie Madill78f41802014-08-25 15:47:55 -04001967 return ValidateGetUniformBase(context, program, location);
1968}
1969
Geoff Langb1196682014-07-23 13:47:29 -04001970static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001971{
1972 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001973 {
Jamie Madill78f41802014-08-25 15:47:55 -04001974 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001975 }
1976
Jamie Madilla502c742014-08-28 17:19:13 -04001977 gl::Program *programObject = context->getProgram(program);
1978 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001979
Jamie Madill78f41802014-08-25 15:47:55 -04001980 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04001981 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
1982 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04001983 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001984 {
Geoff Langb1196682014-07-23 13:47:29 -04001985 context->recordError(Error(GL_INVALID_OPERATION));
1986 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001987 }
1988
1989 return true;
1990}
1991
Geoff Langb1196682014-07-23 13:47:29 -04001992bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001993{
Jamie Madill78f41802014-08-25 15:47:55 -04001994 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001995}
1996
Geoff Langb1196682014-07-23 13:47:29 -04001997bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001998{
Jamie Madill78f41802014-08-25 15:47:55 -04001999 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002000}
2001
Austin Kinross08332632015-05-05 13:35:47 -07002002bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2003 const GLenum *attachments, bool defaultFramebuffer)
2004{
2005 if (numAttachments < 0)
2006 {
2007 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2008 return false;
2009 }
2010
2011 for (GLsizei i = 0; i < numAttachments; ++i)
2012 {
2013 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2014 {
2015 if (defaultFramebuffer)
2016 {
2017 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2018 return false;
2019 }
2020
2021 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2022 {
2023 context->recordError(Error(GL_INVALID_OPERATION,
2024 "Requested color attachment is greater than the maximum supported color attachments"));
2025 return false;
2026 }
2027 }
2028 else
2029 {
2030 switch (attachments[i])
2031 {
2032 case GL_DEPTH_ATTACHMENT:
2033 case GL_STENCIL_ATTACHMENT:
2034 case GL_DEPTH_STENCIL_ATTACHMENT:
2035 if (defaultFramebuffer)
2036 {
2037 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2038 return false;
2039 }
2040 break;
2041 case GL_COLOR:
2042 case GL_DEPTH:
2043 case GL_STENCIL:
2044 if (!defaultFramebuffer)
2045 {
2046 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2047 return false;
2048 }
2049 break;
2050 default:
2051 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2052 return false;
2053 }
2054 }
2055 }
2056
2057 return true;
2058}
2059
Austin Kinross6ee1e782015-05-29 17:05:37 -07002060bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2061{
2062 // Note that debug marker calls must not set error state
2063
2064 if (length < 0)
2065 {
2066 return false;
2067 }
2068
2069 if (marker == nullptr)
2070 {
2071 return false;
2072 }
2073
2074 return true;
2075}
2076
2077bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2078{
2079 // Note that debug marker calls must not set error state
2080
2081 if (length < 0)
2082 {
2083 return false;
2084 }
2085
2086 if (length > 0 && marker == nullptr)
2087 {
2088 return false;
2089 }
2090
2091 return true;
2092}
2093
Geoff Langdcab33b2015-07-21 13:03:16 -04002094bool ValidateEGLImageTargetTexture2DOES(Context *context,
2095 egl::Display *display,
2096 GLenum target,
2097 egl::Image *image)
2098{
Geoff Langa8406172015-07-21 16:53:39 -04002099 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2100 {
2101 context->recordError(Error(GL_INVALID_OPERATION));
2102 return false;
2103 }
2104
2105 switch (target)
2106 {
2107 case GL_TEXTURE_2D:
2108 break;
2109
2110 default:
2111 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2112 return false;
2113 }
2114
2115 if (!display->isValidImage(image))
2116 {
2117 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2118 return false;
2119 }
2120
2121 if (image->getSamples() > 0)
2122 {
2123 context->recordError(Error(GL_INVALID_OPERATION,
2124 "cannot create a 2D texture from a multisampled EGL image."));
2125 return false;
2126 }
2127
2128 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2129 if (!textureCaps.texturable)
2130 {
2131 context->recordError(Error(GL_INVALID_OPERATION,
2132 "EGL image internal format is not supported as a texture."));
2133 return false;
2134 }
2135
Geoff Langdcab33b2015-07-21 13:03:16 -04002136 return true;
2137}
2138
2139bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2140 egl::Display *display,
2141 GLenum target,
2142 egl::Image *image)
2143{
Geoff Langa8406172015-07-21 16:53:39 -04002144 if (!context->getExtensions().eglImage)
2145 {
2146 context->recordError(Error(GL_INVALID_OPERATION));
2147 return false;
2148 }
2149
2150 switch (target)
2151 {
2152 case GL_RENDERBUFFER:
2153 break;
2154
2155 default:
2156 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2157 return false;
2158 }
2159
2160 if (!display->isValidImage(image))
2161 {
2162 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2163 return false;
2164 }
2165
2166 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2167 if (!textureCaps.renderable)
2168 {
2169 context->recordError(Error(
2170 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2171 return false;
2172 }
2173
Geoff Langdcab33b2015-07-21 13:03:16 -04002174 return true;
2175}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002176
2177bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2178{
2179 VertexArray *vao = context->getVertexArray(array);
2180
2181 if (!vao)
2182 {
2183 // The default VAO should always exist
2184 ASSERT(array != 0);
2185 context->recordError(Error(GL_INVALID_OPERATION));
2186 return false;
2187 }
2188
2189 return true;
2190}
2191
2192bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2193{
2194 if (n < 0)
2195 {
2196 context->recordError(Error(GL_INVALID_VALUE));
2197 return false;
2198 }
2199
2200 return true;
2201}
2202
2203bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2204{
2205 if (n < 0)
2206 {
2207 context->recordError(Error(GL_INVALID_VALUE));
2208 return false;
2209 }
2210
2211 return true;
2212}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002213}