blob: 547f548ca9e85c669f46df2538486b97af8fe398 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madille79b1e12015-11-04 16:36:37 -050030const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
31
Jamie Madill1ca74672015-07-21 15:14:11 -040032namespace
33{
Jamie Madillf25855c2015-11-03 11:06:18 -050034bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040035{
36 const gl::State &state = context->getState();
37 const gl::Program *program = state.getProgram();
38
39 const VertexArray *vao = state.getVertexArray();
40 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040041 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
42 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
43 {
44 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040045 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040046 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
112 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
113 case GL_RASTERIZER_DISCARD:
114 return (context->getClientVersion() >= 3);
115 default:
116 return false;
117 }
118}
119
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500120bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121{
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400123 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500124 case GL_TEXTURE_2D:
125 case GL_TEXTURE_CUBE_MAP:
126 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400127
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 case GL_TEXTURE_3D:
129 case GL_TEXTURE_2D_ARRAY:
130 return (context->getClientVersion() >= 3);
131
132 default:
133 return false;
134 }
Jamie Madill35d15012013-10-07 10:46:37 -0400135}
136
Shannon Woods4dfed832014-03-17 20:03:39 -0400137// This function differs from ValidTextureTarget in that the target must be
138// usable as the destination of a 2D operation-- so a cube face is valid, but
139// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400140// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400141bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
142{
143 switch (target)
144 {
145 case GL_TEXTURE_2D:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
150 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
151 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
152 return true;
153 case GL_TEXTURE_2D_ARRAY:
154 case GL_TEXTURE_3D:
155 return (context->getClientVersion() >= 3);
156 default:
157 return false;
158 }
159}
160
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500161bool ValidFramebufferTarget(GLenum target)
162{
Geoff Langd4475812015-03-18 10:53:05 -0400163 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
164 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500165
166 switch (target)
167 {
168 case GL_FRAMEBUFFER: return true;
169 case GL_READ_FRAMEBUFFER: return true;
170 case GL_DRAW_FRAMEBUFFER: return true;
171 default: return false;
172 }
173}
174
Jamie Madill8c96d582014-03-05 15:01:23 -0500175bool ValidBufferTarget(const Context *context, GLenum target)
176{
177 switch (target)
178 {
179 case GL_ARRAY_BUFFER:
180 case GL_ELEMENT_ARRAY_BUFFER:
181 return true;
182
Jamie Madill8c96d582014-03-05 15:01:23 -0500183 case GL_PIXEL_PACK_BUFFER:
184 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400185 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400186
Shannon Woodsb3801742014-03-27 14:59:19 -0400187 case GL_COPY_READ_BUFFER:
188 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500189 case GL_TRANSFORM_FEEDBACK_BUFFER:
190 case GL_UNIFORM_BUFFER:
191 return (context->getClientVersion() >= 3);
192
193 default:
194 return false;
195 }
196}
197
Jamie Madill70656a62014-03-05 15:01:26 -0500198bool ValidBufferParameter(const Context *context, GLenum pname)
199{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400200 const Extensions &extensions = context->getExtensions();
201
Jamie Madill70656a62014-03-05 15:01:26 -0500202 switch (pname)
203 {
204 case GL_BUFFER_USAGE:
205 case GL_BUFFER_SIZE:
206 return true;
207
Geoff Langcc6f55d2015-03-20 13:01:02 -0400208 case GL_BUFFER_ACCESS_OES:
209 return extensions.mapBuffer;
210
211 case GL_BUFFER_MAPPED:
212 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
213 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
214
Jamie Madill70656a62014-03-05 15:01:26 -0500215 // GL_BUFFER_MAP_POINTER is a special case, and may only be
216 // queried with GetBufferPointerv
217 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500218 case GL_BUFFER_MAP_OFFSET:
219 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400220 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500221
222 default:
223 return false;
224 }
225}
226
Jamie Madill8c96d582014-03-05 15:01:23 -0500227bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400228{
Geoff Langaae65a42014-05-26 12:43:44 -0400229 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400230 switch (target)
231 {
Geoff Langaae65a42014-05-26 12:43:44 -0400232 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400233 case GL_TEXTURE_CUBE_MAP:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
238 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400239 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
240 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
241 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400242 default: UNREACHABLE();
243 }
244
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700245 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400246}
247
Austin Kinross08528e12015-10-07 16:24:40 -0700248bool ValidImageSizeParameters(const Context *context,
249 GLenum target,
250 GLint level,
251 GLsizei width,
252 GLsizei height,
253 GLsizei depth,
254 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400255{
256 if (level < 0 || width < 0 || height < 0 || depth < 0)
257 {
258 return false;
259 }
260
Austin Kinross08528e12015-10-07 16:24:40 -0700261 // TexSubImage parameters can be NPOT without textureNPOT extension,
262 // as long as the destination texture is POT.
263 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400264 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400265 {
266 return false;
267 }
268
269 if (!ValidMipLevel(context, target, level))
270 {
271 return false;
272 }
273
274 return true;
275}
276
Geoff Lang0d8b7242015-09-09 14:56:53 -0400277bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
278{
279 // List of compressed format that require that the texture size is smaller than or a multiple of
280 // the compressed block size.
281 switch (internalFormat)
282 {
283 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
284 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
285 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
286 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
287 return true;
288
289 default:
290 return false;
291 }
292}
293
Geoff Langb1196682014-07-23 13:47:29 -0400294bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400295{
Geoff Lang5d601382014-07-22 15:14:06 -0400296 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
297 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400298 {
299 return false;
300 }
301
Geoff Lang0d8b7242015-09-09 14:56:53 -0400302 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400303 {
304 return false;
305 }
306
Geoff Lang0d8b7242015-09-09 14:56:53 -0400307 if (CompressedTextureFormatRequiresExactSize(internalFormat))
308 {
309 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
310 width % formatInfo.compressedBlockWidth != 0) ||
311 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
312 height % formatInfo.compressedBlockHeight != 0))
313 {
314 return false;
315 }
316 }
317
Geoff Langd4f180b2013-09-24 13:57:44 -0400318 return true;
319}
320
Geoff Lang37dde692014-01-31 16:34:54 -0500321bool ValidQueryType(const Context *context, GLenum queryType)
322{
Geoff Langd4475812015-03-18 10:53:05 -0400323 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
324 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500325
326 switch (queryType)
327 {
328 case GL_ANY_SAMPLES_PASSED:
329 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
330 return true;
331 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
332 return (context->getClientVersion() >= 3);
333 default:
334 return false;
335 }
336}
337
Dian Xiang769769a2015-09-09 15:20:08 -0700338Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500339{
340 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
341 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
342 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
343
Dian Xiang769769a2015-09-09 15:20:08 -0700344 Program *validProgram = context->getProgram(id);
345
346 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500347 {
Dian Xiang769769a2015-09-09 15:20:08 -0700348 if (context->getShader(id))
349 {
350 context->recordError(
351 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
352 }
353 else
354 {
355 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
356 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500357 }
Dian Xiang769769a2015-09-09 15:20:08 -0700358
359 return validProgram;
360}
361
362Shader *GetValidShader(Context *context, GLuint id)
363{
364 // See ValidProgram for spec details.
365
366 Shader *validShader = context->getShader(id);
367
368 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500369 {
Dian Xiang769769a2015-09-09 15:20:08 -0700370 if (context->getProgram(id))
371 {
372 context->recordError(
373 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
374 }
375 else
376 {
377 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
378 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500379 }
Dian Xiang769769a2015-09-09 15:20:08 -0700380
381 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500382}
383
Geoff Langb1196682014-07-23 13:47:29 -0400384bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400385{
386 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
387 {
388 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
389
Geoff Langaae65a42014-05-26 12:43:44 -0400390 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400391 {
Geoff Langb1196682014-07-23 13:47:29 -0400392 context->recordError(Error(GL_INVALID_VALUE));
393 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400394 }
395 }
396 else
397 {
398 switch (attachment)
399 {
400 case GL_DEPTH_ATTACHMENT:
401 case GL_STENCIL_ATTACHMENT:
402 break;
403
404 case GL_DEPTH_STENCIL_ATTACHMENT:
405 if (context->getClientVersion() < 3)
406 {
Geoff Langb1196682014-07-23 13:47:29 -0400407 context->recordError(Error(GL_INVALID_ENUM));
408 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400409 }
410 break;
411
412 default:
Geoff Langb1196682014-07-23 13:47:29 -0400413 context->recordError(Error(GL_INVALID_ENUM));
414 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400415 }
416 }
417
418 return true;
419}
420
Corentin Walleze0902642014-11-04 12:32:15 -0800421bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
422 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423{
424 switch (target)
425 {
426 case GL_RENDERBUFFER:
427 break;
428 default:
Geoff Langb1196682014-07-23 13:47:29 -0400429 context->recordError(Error(GL_INVALID_ENUM));
430 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400431 }
432
433 if (width < 0 || height < 0 || samples < 0)
434 {
Geoff Langb1196682014-07-23 13:47:29 -0400435 context->recordError(Error(GL_INVALID_VALUE));
436 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400437 }
438
Geoff Langd87878e2014-09-19 15:42:59 -0400439 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
440 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400441 {
Geoff Langb1196682014-07-23 13:47:29 -0400442 context->recordError(Error(GL_INVALID_ENUM));
443 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 }
445
446 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
447 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800448 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400449 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400450 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400451 {
Geoff Langb1196682014-07-23 13:47:29 -0400452 context->recordError(Error(GL_INVALID_ENUM));
453 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400454 }
455
Geoff Langaae65a42014-05-26 12:43:44 -0400456 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 {
Geoff Langb1196682014-07-23 13:47:29 -0400458 context->recordError(Error(GL_INVALID_VALUE));
459 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400460 }
461
Shannon Woods53a94a82014-06-24 15:20:36 -0400462 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 if (handle == 0)
464 {
Geoff Langb1196682014-07-23 13:47:29 -0400465 context->recordError(Error(GL_INVALID_OPERATION));
466 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400467 }
468
469 return true;
470}
471
Corentin Walleze0902642014-11-04 12:32:15 -0800472bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
473 GLenum internalformat, GLsizei width, GLsizei height)
474{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800475 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800476
477 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400478 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800479 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400480 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800481 {
482 context->recordError(Error(GL_INVALID_VALUE));
483 return false;
484 }
485
486 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
487 // the specified storage. This is different than ES 3.0 in which a sample number higher
488 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800489 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
490 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800491 {
Geoff Langa4903b72015-03-02 16:02:48 -0800492 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
493 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
494 {
495 context->recordError(Error(GL_OUT_OF_MEMORY));
496 return false;
497 }
Corentin Walleze0902642014-11-04 12:32:15 -0800498 }
499
500 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
501}
502
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500503bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
504 GLenum renderbuffertarget, GLuint renderbuffer)
505{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400506 if (!ValidFramebufferTarget(target))
507 {
Geoff Langb1196682014-07-23 13:47:29 -0400508 context->recordError(Error(GL_INVALID_ENUM));
509 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400510 }
511
Shannon Woods53a94a82014-06-24 15:20:36 -0400512 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500513
Jamie Madill84115c92015-04-23 15:00:07 -0400514 ASSERT(framebuffer);
515 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500516 {
Jamie Madill84115c92015-04-23 15:00:07 -0400517 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400518 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500519 }
520
Jamie Madillb4472272014-07-03 10:38:55 -0400521 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500522 {
Jamie Madillb4472272014-07-03 10:38:55 -0400523 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500524 }
525
Jamie Madillab9d82c2014-01-21 16:38:14 -0500526 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
527 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
528 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
529 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
530 if (renderbuffer != 0)
531 {
532 if (!context->getRenderbuffer(renderbuffer))
533 {
Geoff Langb1196682014-07-23 13:47:29 -0400534 context->recordError(Error(GL_INVALID_OPERATION));
535 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500536 }
537 }
538
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500539 return true;
540}
541
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400542static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400543 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
544 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
545{
546 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
547 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
548 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
549 {
550 return true;
551 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400552 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400553 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400554 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400555
Shannon Woods53a94a82014-06-24 15:20:36 -0400556 return scissor.x > 0 || scissor.y > 0 ||
557 scissor.width < writeBuffer->getWidth() ||
558 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400559 }
560 else
561 {
562 return false;
563 }
564}
565
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400566bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
568 GLenum filter, bool fromAngleExtension)
569{
570 switch (filter)
571 {
572 case GL_NEAREST:
573 break;
574 case GL_LINEAR:
575 if (fromAngleExtension)
576 {
Geoff Langb1196682014-07-23 13:47:29 -0400577 context->recordError(Error(GL_INVALID_ENUM));
578 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400579 }
580 break;
581 default:
Geoff Langb1196682014-07-23 13:47:29 -0400582 context->recordError(Error(GL_INVALID_ENUM));
583 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400584 }
585
586 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
587 {
Geoff Langb1196682014-07-23 13:47:29 -0400588 context->recordError(Error(GL_INVALID_VALUE));
589 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400590 }
591
592 if (mask == 0)
593 {
594 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
595 // buffers are copied.
596 return false;
597 }
598
599 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
600 {
601 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400602 context->recordError(Error(GL_INVALID_OPERATION));
603 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400604 }
605
606 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
607 // color buffer, leaving only nearest being unfiltered from above
608 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
609 {
Geoff Langb1196682014-07-23 13:47:29 -0400610 context->recordError(Error(GL_INVALID_OPERATION));
611 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 }
613
Shannon Woods53a94a82014-06-24 15:20:36 -0400614 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 {
616 if (fromAngleExtension)
617 {
618 ERR("Blits with the same source and destination framebuffer are not supported by this "
619 "implementation.");
620 }
Geoff Langb1196682014-07-23 13:47:29 -0400621 context->recordError(Error(GL_INVALID_OPERATION));
622 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400623 }
624
Jamie Madille3ef7152015-04-28 16:55:17 +0000625 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
626 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500627
628 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400629 {
Geoff Langb1196682014-07-23 13:47:29 -0400630 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
631 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 }
633
Geoff Lang748f74e2014-12-01 11:25:34 -0500634 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500635 {
636 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
637 return false;
638 }
639
Geoff Lang748f74e2014-12-01 11:25:34 -0500640 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500641 {
642 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
643 return false;
644 }
645
646 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400647 {
Geoff Langb1196682014-07-23 13:47:29 -0400648 context->recordError(Error(GL_INVALID_OPERATION));
649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 }
651
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
653
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654 if (mask & GL_COLOR_BUFFER_BIT)
655 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400656 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
657 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658
659 if (readColorBuffer && drawColorBuffer)
660 {
Geoff Langd8a22582014-12-17 15:28:23 -0500661 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400662 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400663
Corentin Wallez37c39792015-08-20 14:19:46 -0400664 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 {
666 if (drawFramebuffer->isEnabledColorAttachment(i))
667 {
Geoff Langd8a22582014-12-17 15:28:23 -0500668 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400669 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400670
Geoff Langb2f3d052013-08-13 12:49:27 -0400671 // The GL ES 3.0.2 spec (pg 193) states that:
672 // 1) If the read buffer is fixed point format, the draw buffer must be as well
673 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
674 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400675 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
676 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400677 {
Geoff Langb1196682014-07-23 13:47:29 -0400678 context->recordError(Error(GL_INVALID_OPERATION));
679 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680 }
681
Geoff Lang5d601382014-07-22 15:14:06 -0400682 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 {
Geoff Langb1196682014-07-23 13:47:29 -0400684 context->recordError(Error(GL_INVALID_OPERATION));
685 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686 }
687
Geoff Lang5d601382014-07-22 15:14:06 -0400688 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400689 {
Geoff Langb1196682014-07-23 13:47:29 -0400690 context->recordError(Error(GL_INVALID_OPERATION));
691 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400692 }
693
Geoff Langb2f3d052013-08-13 12:49:27 -0400694 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400695 {
Geoff Langb1196682014-07-23 13:47:29 -0400696 context->recordError(Error(GL_INVALID_OPERATION));
697 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400698 }
699 }
700 }
701
Geoff Lang5d601382014-07-22 15:14:06 -0400702 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 {
Geoff Langb1196682014-07-23 13:47:29 -0400704 context->recordError(Error(GL_INVALID_OPERATION));
705 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706 }
707
708 if (fromAngleExtension)
709 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400710 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500711 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400712 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500713 readColorAttachment->type() != GL_RENDERBUFFER &&
714 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400715 {
Geoff Langb1196682014-07-23 13:47:29 -0400716 context->recordError(Error(GL_INVALID_OPERATION));
717 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400718 }
719
Corentin Wallez37c39792015-08-20 14:19:46 -0400720 for (size_t colorAttachment = 0;
721 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722 {
723 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
724 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000725 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400726 ASSERT(attachment);
727
Jamie Madill8cf4a392015-04-02 11:36:04 -0400728 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500729 attachment->type() != GL_RENDERBUFFER &&
730 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400731 {
Geoff Langb1196682014-07-23 13:47:29 -0400732 context->recordError(Error(GL_INVALID_OPERATION));
733 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400734 }
735
Jamie Madillf8f18f02014-10-02 10:44:17 -0400736 // Return an error if the destination formats do not match
737 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 {
Geoff Langb1196682014-07-23 13:47:29 -0400739 context->recordError(Error(GL_INVALID_OPERATION));
740 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 }
742 }
743 }
Jamie Madill48faf802014-11-06 15:27:22 -0500744
745 int readSamples = readFramebuffer->getSamples(context->getData());
746
747 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
748 srcX0, srcY0, srcX1, srcY1,
749 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400750 {
Geoff Langb1196682014-07-23 13:47:29 -0400751 context->recordError(Error(GL_INVALID_OPERATION));
752 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 }
754 }
755 }
756 }
757
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200758 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
759 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
760 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200762 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400763 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400764 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
765 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200767 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400768 {
Geoff Langd8a22582014-12-17 15:28:23 -0500769 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 {
Geoff Langb1196682014-07-23 13:47:29 -0400771 context->recordError(Error(GL_INVALID_OPERATION));
772 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200775 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400776 {
Geoff Langb1196682014-07-23 13:47:29 -0400777 context->recordError(Error(GL_INVALID_OPERATION));
778 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200780
781 if (fromAngleExtension)
782 {
783 if (IsPartialBlit(context, readBuffer, drawBuffer,
784 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
785 {
786 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
787 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
788 return false;
789 }
790
791 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
792 {
793 context->recordError(Error(GL_INVALID_OPERATION));
794 return false;
795 }
796 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400797 }
798 }
799 }
800
801 return true;
802}
803
Geoff Langb1196682014-07-23 13:47:29 -0400804bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805{
806 switch (pname)
807 {
808 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
809 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
810 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
811 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
812 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
813 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
814 case GL_CURRENT_VERTEX_ATTRIB:
815 return true;
816
817 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
818 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
819 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400820 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
821 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400822 return true;
823
824 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400825 if (context->getClientVersion() < 3)
826 {
827 context->recordError(Error(GL_INVALID_ENUM));
828 return false;
829 }
830 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400831
832 default:
Geoff Langb1196682014-07-23 13:47:29 -0400833 context->recordError(Error(GL_INVALID_ENUM));
834 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400835 }
836}
837
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400838bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400839{
840 switch (pname)
841 {
842 case GL_TEXTURE_WRAP_R:
843 case GL_TEXTURE_SWIZZLE_R:
844 case GL_TEXTURE_SWIZZLE_G:
845 case GL_TEXTURE_SWIZZLE_B:
846 case GL_TEXTURE_SWIZZLE_A:
847 case GL_TEXTURE_BASE_LEVEL:
848 case GL_TEXTURE_MAX_LEVEL:
849 case GL_TEXTURE_COMPARE_MODE:
850 case GL_TEXTURE_COMPARE_FUNC:
851 case GL_TEXTURE_MIN_LOD:
852 case GL_TEXTURE_MAX_LOD:
853 if (context->getClientVersion() < 3)
854 {
Geoff Langb1196682014-07-23 13:47:29 -0400855 context->recordError(Error(GL_INVALID_ENUM));
856 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400857 }
858 break;
859
860 default: break;
861 }
862
863 switch (pname)
864 {
865 case GL_TEXTURE_WRAP_S:
866 case GL_TEXTURE_WRAP_T:
867 case GL_TEXTURE_WRAP_R:
868 switch (param)
869 {
870 case GL_REPEAT:
871 case GL_CLAMP_TO_EDGE:
872 case GL_MIRRORED_REPEAT:
873 return true;
874 default:
Geoff Langb1196682014-07-23 13:47:29 -0400875 context->recordError(Error(GL_INVALID_ENUM));
876 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877 }
878
879 case GL_TEXTURE_MIN_FILTER:
880 switch (param)
881 {
882 case GL_NEAREST:
883 case GL_LINEAR:
884 case GL_NEAREST_MIPMAP_NEAREST:
885 case GL_LINEAR_MIPMAP_NEAREST:
886 case GL_NEAREST_MIPMAP_LINEAR:
887 case GL_LINEAR_MIPMAP_LINEAR:
888 return true;
889 default:
Geoff Langb1196682014-07-23 13:47:29 -0400890 context->recordError(Error(GL_INVALID_ENUM));
891 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400892 }
893 break;
894
895 case GL_TEXTURE_MAG_FILTER:
896 switch (param)
897 {
898 case GL_NEAREST:
899 case GL_LINEAR:
900 return true;
901 default:
Geoff Langb1196682014-07-23 13:47:29 -0400902 context->recordError(Error(GL_INVALID_ENUM));
903 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400904 }
905 break;
906
907 case GL_TEXTURE_USAGE_ANGLE:
908 switch (param)
909 {
910 case GL_NONE:
911 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
912 return true;
913 default:
Geoff Langb1196682014-07-23 13:47:29 -0400914 context->recordError(Error(GL_INVALID_ENUM));
915 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400916 }
917 break;
918
919 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400920 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400921 {
Geoff Langb1196682014-07-23 13:47:29 -0400922 context->recordError(Error(GL_INVALID_ENUM));
923 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400924 }
925
926 // we assume the parameter passed to this validation method is truncated, not rounded
927 if (param < 1)
928 {
Geoff Langb1196682014-07-23 13:47:29 -0400929 context->recordError(Error(GL_INVALID_VALUE));
930 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400931 }
932 return true;
933
934 case GL_TEXTURE_MIN_LOD:
935 case GL_TEXTURE_MAX_LOD:
936 // any value is permissible
937 return true;
938
939 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400940 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400941 switch (param)
942 {
943 case GL_NONE:
944 case GL_COMPARE_REF_TO_TEXTURE:
945 return true;
946 default:
Geoff Langb1196682014-07-23 13:47:29 -0400947 context->recordError(Error(GL_INVALID_ENUM));
948 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400949 }
950 break;
951
952 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400953 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400954 switch (param)
955 {
956 case GL_LEQUAL:
957 case GL_GEQUAL:
958 case GL_LESS:
959 case GL_GREATER:
960 case GL_EQUAL:
961 case GL_NOTEQUAL:
962 case GL_ALWAYS:
963 case GL_NEVER:
964 return true;
965 default:
Geoff Langb1196682014-07-23 13:47:29 -0400966 context->recordError(Error(GL_INVALID_ENUM));
967 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400968 }
969 break;
970
971 case GL_TEXTURE_SWIZZLE_R:
972 case GL_TEXTURE_SWIZZLE_G:
973 case GL_TEXTURE_SWIZZLE_B:
974 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400975 switch (param)
976 {
977 case GL_RED:
978 case GL_GREEN:
979 case GL_BLUE:
980 case GL_ALPHA:
981 case GL_ZERO:
982 case GL_ONE:
983 return true;
984 default:
Geoff Langb1196682014-07-23 13:47:29 -0400985 context->recordError(Error(GL_INVALID_ENUM));
986 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400987 }
988 break;
989
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400990 case GL_TEXTURE_BASE_LEVEL:
991 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400992 if (param < 0)
993 {
Geoff Langb1196682014-07-23 13:47:29 -0400994 context->recordError(Error(GL_INVALID_VALUE));
995 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400996 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400997 return true;
998
999 default:
Geoff Langb1196682014-07-23 13:47:29 -04001000 context->recordError(Error(GL_INVALID_ENUM));
1001 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001002 }
1003}
1004
Geoff Langb1196682014-07-23 13:47:29 -04001005bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001006{
1007 switch (pname)
1008 {
1009 case GL_TEXTURE_MIN_FILTER:
1010 case GL_TEXTURE_MAG_FILTER:
1011 case GL_TEXTURE_WRAP_S:
1012 case GL_TEXTURE_WRAP_T:
1013 case GL_TEXTURE_WRAP_R:
1014 case GL_TEXTURE_MIN_LOD:
1015 case GL_TEXTURE_MAX_LOD:
1016 case GL_TEXTURE_COMPARE_MODE:
1017 case GL_TEXTURE_COMPARE_FUNC:
1018 return true;
1019
1020 default:
Geoff Langb1196682014-07-23 13:47:29 -04001021 context->recordError(Error(GL_INVALID_ENUM));
1022 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001023 }
1024}
1025
Jamie Madill26e91952014-03-05 15:01:27 -05001026bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
1027 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
1028{
Shannon Woods53a94a82014-06-24 15:20:36 -04001029 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001030 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001031
Geoff Lang748f74e2014-12-01 11:25:34 -05001032 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001033 {
Geoff Langb1196682014-07-23 13:47:29 -04001034 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1035 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001036 }
1037
Jamie Madill48faf802014-11-06 15:27:22 -05001038 if (context->getState().getReadFramebuffer()->id() != 0 &&
1039 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001040 {
Geoff Langb1196682014-07-23 13:47:29 -04001041 context->recordError(Error(GL_INVALID_OPERATION));
1042 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001043 }
1044
Geoff Langbce529e2014-12-01 12:48:41 -05001045 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1046 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001047 {
Geoff Langb1196682014-07-23 13:47:29 -04001048 context->recordError(Error(GL_INVALID_OPERATION));
1049 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001050 }
1051
Geoff Langbce529e2014-12-01 12:48:41 -05001052 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1053 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001054 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001055 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001056
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001057 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1058 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001059
1060 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1061 {
Geoff Langb1196682014-07-23 13:47:29 -04001062 context->recordError(Error(GL_INVALID_OPERATION));
1063 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001064 }
1065
Geoff Lang5d601382014-07-22 15:14:06 -04001066 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1067 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001068
Minmin Gongadff67b2015-10-14 10:34:45 -04001069 GLsizei outputPitch =
1070 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1071 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001072 // sized query sanity check
1073 if (bufSize)
1074 {
1075 int requiredSize = outputPitch * height;
1076 if (requiredSize > *bufSize)
1077 {
Geoff Langb1196682014-07-23 13:47:29 -04001078 context->recordError(Error(GL_INVALID_OPERATION));
1079 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001080 }
1081 }
1082
1083 return true;
1084}
1085
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001086bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1087{
1088 if (!ValidQueryType(context, target))
1089 {
Geoff Langb1196682014-07-23 13:47:29 -04001090 context->recordError(Error(GL_INVALID_ENUM));
1091 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001092 }
1093
1094 if (id == 0)
1095 {
Geoff Langb1196682014-07-23 13:47:29 -04001096 context->recordError(Error(GL_INVALID_OPERATION));
1097 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001098 }
1099
1100 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1101 // of zero, if the active query object name for <target> is non-zero (for the
1102 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1103 // the active query for either target is non-zero), if <id> is the name of an
1104 // existing query object whose type does not match <target>, or if <id> is the
1105 // active query object name for any query type, the error INVALID_OPERATION is
1106 // generated.
1107
1108 // Ensure no other queries are active
1109 // NOTE: If other queries than occlusion are supported, we will need to check
1110 // separately that:
1111 // a) The query ID passed is not the current active query for any target/type
1112 // b) There are no active queries for the requested target (and in the case
1113 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1114 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001115 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001116 {
Geoff Langb1196682014-07-23 13:47:29 -04001117 context->recordError(Error(GL_INVALID_OPERATION));
1118 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001119 }
1120
1121 Query *queryObject = context->getQuery(id, true, target);
1122
1123 // check that name was obtained with glGenQueries
1124 if (!queryObject)
1125 {
Geoff Langb1196682014-07-23 13:47:29 -04001126 context->recordError(Error(GL_INVALID_OPERATION));
1127 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001128 }
1129
1130 // check for type mismatch
1131 if (queryObject->getType() != target)
1132 {
Geoff Langb1196682014-07-23 13:47:29 -04001133 context->recordError(Error(GL_INVALID_OPERATION));
1134 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001135 }
1136
1137 return true;
1138}
1139
Jamie Madill45c785d2014-05-13 14:09:34 -04001140bool ValidateEndQuery(gl::Context *context, GLenum target)
1141{
1142 if (!ValidQueryType(context, target))
1143 {
Geoff Langb1196682014-07-23 13:47:29 -04001144 context->recordError(Error(GL_INVALID_ENUM));
1145 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001146 }
1147
Shannon Woods53a94a82014-06-24 15:20:36 -04001148 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001149
1150 if (queryObject == NULL)
1151 {
Geoff Langb1196682014-07-23 13:47:29 -04001152 context->recordError(Error(GL_INVALID_OPERATION));
1153 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001154 }
1155
Jamie Madill45c785d2014-05-13 14:09:34 -04001156 return true;
1157}
1158
Jamie Madill62d31cb2015-09-11 13:25:51 -04001159static bool ValidateUniformCommonBase(gl::Context *context,
1160 GLenum targetUniformType,
1161 GLint location,
1162 GLsizei count,
1163 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001164{
1165 if (count < 0)
1166 {
Geoff Langb1196682014-07-23 13:47:29 -04001167 context->recordError(Error(GL_INVALID_VALUE));
1168 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001169 }
1170
Geoff Lang7dd2e102014-11-10 15:19:26 -05001171 gl::Program *program = context->getState().getProgram();
1172 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001173 {
Geoff Langb1196682014-07-23 13:47:29 -04001174 context->recordError(Error(GL_INVALID_OPERATION));
1175 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001176 }
1177
1178 if (location == -1)
1179 {
1180 // Silently ignore the uniform command
1181 return false;
1182 }
1183
Geoff Lang7dd2e102014-11-10 15:19:26 -05001184 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001185 {
Geoff Langb1196682014-07-23 13:47:29 -04001186 context->recordError(Error(GL_INVALID_OPERATION));
1187 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001188 }
1189
Jamie Madill62d31cb2015-09-11 13:25:51 -04001190 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001191
1192 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001193 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001194 {
Geoff Langb1196682014-07-23 13:47:29 -04001195 context->recordError(Error(GL_INVALID_OPERATION));
1196 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001197 }
1198
Jamie Madill62d31cb2015-09-11 13:25:51 -04001199 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001200 return true;
1201}
1202
Jamie Madillaa981bd2014-05-20 10:55:55 -04001203bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1204{
1205 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001206 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001207 {
Geoff Langb1196682014-07-23 13:47:29 -04001208 context->recordError(Error(GL_INVALID_OPERATION));
1209 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001210 }
1211
Jamie Madill62d31cb2015-09-11 13:25:51 -04001212 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001213 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1214 {
1215 return false;
1216 }
1217
Jamie Madillf2575982014-06-25 16:04:54 -04001218 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001219 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001220 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1221 {
Geoff Langb1196682014-07-23 13:47:29 -04001222 context->recordError(Error(GL_INVALID_OPERATION));
1223 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001224 }
1225
1226 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001227}
1228
1229bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1230 GLboolean transpose)
1231{
1232 // Check for ES3 uniform entry points
1233 int rows = VariableRowCount(matrixType);
1234 int cols = VariableColumnCount(matrixType);
1235 if (rows != cols && context->getClientVersion() < 3)
1236 {
Geoff Langb1196682014-07-23 13:47:29 -04001237 context->recordError(Error(GL_INVALID_OPERATION));
1238 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001239 }
1240
1241 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1242 {
Geoff Langb1196682014-07-23 13:47:29 -04001243 context->recordError(Error(GL_INVALID_VALUE));
1244 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001245 }
1246
Jamie Madill62d31cb2015-09-11 13:25:51 -04001247 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001248 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1249 {
1250 return false;
1251 }
1252
1253 if (uniform->type != matrixType)
1254 {
Geoff Langb1196682014-07-23 13:47:29 -04001255 context->recordError(Error(GL_INVALID_OPERATION));
1256 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001257 }
1258
1259 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001260}
1261
Jamie Madill893ab082014-05-16 16:56:10 -04001262bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1263{
1264 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1265 {
Geoff Langb1196682014-07-23 13:47:29 -04001266 context->recordError(Error(GL_INVALID_ENUM));
1267 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001268 }
1269
Jamie Madill0af26e12015-03-05 19:54:33 -05001270 const Caps &caps = context->getCaps();
1271
Jamie Madill893ab082014-05-16 16:56:10 -04001272 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1273 {
1274 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1275
Jamie Madill0af26e12015-03-05 19:54:33 -05001276 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001277 {
Geoff Langb1196682014-07-23 13:47:29 -04001278 context->recordError(Error(GL_INVALID_OPERATION));
1279 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001280 }
1281 }
1282
1283 switch (pname)
1284 {
1285 case GL_TEXTURE_BINDING_2D:
1286 case GL_TEXTURE_BINDING_CUBE_MAP:
1287 case GL_TEXTURE_BINDING_3D:
1288 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001289 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001290 {
Geoff Langb1196682014-07-23 13:47:29 -04001291 context->recordError(Error(GL_INVALID_OPERATION));
1292 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001293 }
1294 break;
1295
1296 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1297 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1298 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001299 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001300 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001301 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001302 {
Geoff Langb1196682014-07-23 13:47:29 -04001303 context->recordError(Error(GL_INVALID_OPERATION));
1304 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001305 }
1306
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001307 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001308 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001309 {
Geoff Langb1196682014-07-23 13:47:29 -04001310 context->recordError(Error(GL_INVALID_OPERATION));
1311 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001312 }
1313 }
1314 break;
1315
1316 default:
1317 break;
1318 }
1319
1320 // pname is valid, but there are no parameters to return
1321 if (numParams == 0)
1322 {
1323 return false;
1324 }
1325
1326 return true;
1327}
1328
Geoff Lang831b1952015-05-05 11:02:27 -04001329bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001330 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1331 GLint border, GLenum *textureFormatOut)
1332{
1333
1334 if (!ValidTexture2DDestinationTarget(context, target))
1335 {
Geoff Langb1196682014-07-23 13:47:29 -04001336 context->recordError(Error(GL_INVALID_ENUM));
1337 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001338 }
1339
1340 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1341 {
Geoff Langb1196682014-07-23 13:47:29 -04001342 context->recordError(Error(GL_INVALID_VALUE));
1343 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001344 }
1345
1346 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1347 {
Geoff Langb1196682014-07-23 13:47:29 -04001348 context->recordError(Error(GL_INVALID_VALUE));
1349 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001350 }
1351
1352 if (border != 0)
1353 {
Geoff Langb1196682014-07-23 13:47:29 -04001354 context->recordError(Error(GL_INVALID_VALUE));
1355 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001356 }
1357
1358 if (!ValidMipLevel(context, target, level))
1359 {
Geoff Langb1196682014-07-23 13:47:29 -04001360 context->recordError(Error(GL_INVALID_VALUE));
1361 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001362 }
1363
Shannon Woods53a94a82014-06-24 15:20:36 -04001364 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001365 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001366 {
Geoff Langb1196682014-07-23 13:47:29 -04001367 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1368 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001369 }
1370
Jamie Madill48faf802014-11-06 15:27:22 -05001371 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001372 {
Geoff Langb1196682014-07-23 13:47:29 -04001373 context->recordError(Error(GL_INVALID_OPERATION));
1374 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001375 }
1376
Geoff Langaae65a42014-05-26 12:43:44 -04001377 const gl::Caps &caps = context->getCaps();
1378
Geoff Langaae65a42014-05-26 12:43:44 -04001379 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001380 switch (target)
1381 {
1382 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001383 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001384 break;
1385
1386 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1387 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1388 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1389 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1390 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1391 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001392 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001393 break;
1394
1395 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001396 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001397 break;
1398
1399 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001400 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001401 break;
1402
1403 default:
Geoff Langb1196682014-07-23 13:47:29 -04001404 context->recordError(Error(GL_INVALID_ENUM));
1405 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001406 }
1407
Geoff Lang691e58c2014-12-19 17:03:25 -05001408 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001409 if (!texture)
1410 {
Geoff Langb1196682014-07-23 13:47:29 -04001411 context->recordError(Error(GL_INVALID_OPERATION));
1412 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001413 }
1414
Geoff Lang69cce582015-09-17 13:20:36 -04001415 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001416 {
Geoff Langb1196682014-07-23 13:47:29 -04001417 context->recordError(Error(GL_INVALID_OPERATION));
1418 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001419 }
1420
Geoff Lang5d601382014-07-22 15:14:06 -04001421 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1422
1423 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001424 {
Geoff Langb1196682014-07-23 13:47:29 -04001425 context->recordError(Error(GL_INVALID_OPERATION));
1426 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001427 }
1428
Geoff Langa9be0dc2014-12-17 12:34:40 -05001429 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001430 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001431 context->recordError(Error(GL_INVALID_OPERATION));
1432 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001433 }
1434
1435 if (isSubImage)
1436 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001437 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1438 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1439 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001440 {
Geoff Langb1196682014-07-23 13:47:29 -04001441 context->recordError(Error(GL_INVALID_VALUE));
1442 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001443 }
1444 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001445 else
1446 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001447 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001448 {
Geoff Langb1196682014-07-23 13:47:29 -04001449 context->recordError(Error(GL_INVALID_VALUE));
1450 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001451 }
1452
Geoff Lang5d601382014-07-22 15:14:06 -04001453 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001454 {
Geoff Langb1196682014-07-23 13:47:29 -04001455 context->recordError(Error(GL_INVALID_ENUM));
1456 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001457 }
1458
1459 int maxLevelDimension = (maxDimension >> level);
1460 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1461 {
Geoff Langb1196682014-07-23 13:47:29 -04001462 context->recordError(Error(GL_INVALID_VALUE));
1463 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001464 }
1465 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001466
Geoff Langa9be0dc2014-12-17 12:34:40 -05001467 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001468 return true;
1469}
1470
Jamie Madillf25855c2015-11-03 11:06:18 -05001471static bool ValidateDrawBase(ValidationContext *context,
1472 GLenum mode,
1473 GLsizei count,
1474 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001475{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001476 switch (mode)
1477 {
1478 case GL_POINTS:
1479 case GL_LINES:
1480 case GL_LINE_LOOP:
1481 case GL_LINE_STRIP:
1482 case GL_TRIANGLES:
1483 case GL_TRIANGLE_STRIP:
1484 case GL_TRIANGLE_FAN:
1485 break;
1486 default:
Geoff Langb1196682014-07-23 13:47:29 -04001487 context->recordError(Error(GL_INVALID_ENUM));
1488 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001489 }
1490
Jamie Madill250d33f2014-06-06 17:09:03 -04001491 if (count < 0)
1492 {
Geoff Langb1196682014-07-23 13:47:29 -04001493 context->recordError(Error(GL_INVALID_VALUE));
1494 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001495 }
1496
Geoff Langb1196682014-07-23 13:47:29 -04001497 const State &state = context->getState();
1498
Jamie Madill250d33f2014-06-06 17:09:03 -04001499 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001500 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001501 {
Geoff Langb1196682014-07-23 13:47:29 -04001502 context->recordError(Error(GL_INVALID_OPERATION));
1503 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001504 }
1505
Geoff Lang3a86ad32015-09-01 11:47:05 -04001506 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001507 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04001508 const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
1509 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
1510 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
1511 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
1512 const DepthStencilState &depthStencilState = state.getDepthStencilState();
1513 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
1514 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04001515 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04001516 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
1517 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04001518 {
1519 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1520 // Section 6.10 of the WebGL 1.0 spec
1521 ERR(
1522 "This ANGLE implementation does not support separate front/back stencil "
1523 "writemasks, reference values, or stencil mask values.");
1524 context->recordError(Error(GL_INVALID_OPERATION));
1525 return false;
1526 }
Jamie Madillac528012014-06-20 13:21:23 -04001527 }
1528
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001529 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001530 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001531 {
Geoff Langb1196682014-07-23 13:47:29 -04001532 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1533 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001534 }
1535
Geoff Lang7dd2e102014-11-10 15:19:26 -05001536 gl::Program *program = state.getProgram();
1537 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001538 {
Geoff Langb1196682014-07-23 13:47:29 -04001539 context->recordError(Error(GL_INVALID_OPERATION));
1540 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001541 }
1542
Geoff Lang7dd2e102014-11-10 15:19:26 -05001543 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001544 {
Geoff Langb1196682014-07-23 13:47:29 -04001545 context->recordError(Error(GL_INVALID_OPERATION));
1546 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001547 }
1548
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001549 // Uniform buffer validation
1550 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1551 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001552 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001553 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001554 const OffsetBindingPointer<Buffer> &uniformBuffer =
1555 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001556
Geoff Lang5d124a62015-09-15 13:03:27 -04001557 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001558 {
1559 // undefined behaviour
1560 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1561 return false;
1562 }
1563
Geoff Lang5d124a62015-09-15 13:03:27 -04001564 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001565 if (uniformBufferSize == 0)
1566 {
1567 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001568 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001569 }
1570
Jamie Madill62d31cb2015-09-11 13:25:51 -04001571 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001572 {
1573 // undefined behaviour
1574 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1575 return false;
1576 }
1577 }
1578
Jamie Madill250d33f2014-06-06 17:09:03 -04001579 // No-op if zero count
1580 return (count > 0);
1581}
1582
Geoff Langb1196682014-07-23 13:47:29 -04001583bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001584{
Jamie Madillfd716582014-06-06 17:09:04 -04001585 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001586 {
Geoff Langb1196682014-07-23 13:47:29 -04001587 context->recordError(Error(GL_INVALID_VALUE));
1588 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001589 }
1590
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001591 const State &state = context->getState();
1592 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001593 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1594 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001595 {
1596 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1597 // that does not match the current transform feedback object's draw mode (if transform feedback
1598 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001599 context->recordError(Error(GL_INVALID_OPERATION));
1600 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001601 }
1602
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001603 if (!ValidateDrawBase(context, mode, count, primcount))
1604 {
1605 return false;
1606 }
1607
1608 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001609 {
1610 return false;
1611 }
1612
1613 return true;
1614}
1615
Geoff Langb1196682014-07-23 13:47:29 -04001616bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001617{
1618 if (primcount < 0)
1619 {
Geoff Langb1196682014-07-23 13:47:29 -04001620 context->recordError(Error(GL_INVALID_VALUE));
1621 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001622 }
1623
Jamie Madill2b976812014-08-25 15:47:49 -04001624 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001625 {
1626 return false;
1627 }
1628
1629 // No-op if zero primitive count
1630 return (primcount > 0);
1631}
1632
Geoff Lang87a93302014-09-16 13:29:43 -04001633static bool ValidateDrawInstancedANGLE(Context *context)
1634{
1635 // Verify there is at least one active attribute with a divisor of zero
1636 const gl::State& state = context->getState();
1637
Geoff Lang7dd2e102014-11-10 15:19:26 -05001638 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001639
1640 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001641 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001642 {
1643 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001644 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001645 {
1646 return true;
1647 }
1648 }
1649
1650 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1651 "has a divisor of zero."));
1652 return false;
1653}
1654
1655bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1656{
1657 if (!ValidateDrawInstancedANGLE(context))
1658 {
1659 return false;
1660 }
1661
1662 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1663}
1664
Jamie Madillf25855c2015-11-03 11:06:18 -05001665bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001666 GLenum mode,
1667 GLsizei count,
1668 GLenum type,
1669 const GLvoid *indices,
1670 GLsizei primcount,
1671 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001672{
Jamie Madill250d33f2014-06-06 17:09:03 -04001673 switch (type)
1674 {
1675 case GL_UNSIGNED_BYTE:
1676 case GL_UNSIGNED_SHORT:
1677 break;
1678 case GL_UNSIGNED_INT:
Jamie Madille79b1e12015-11-04 16:36:37 -05001679 if (context->getClientVersion() < 3 && !context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001680 {
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 break;
1685 default:
Geoff Langb1196682014-07-23 13:47:29 -04001686 context->recordError(Error(GL_INVALID_ENUM));
1687 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001688 }
1689
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001690 const State &state = context->getState();
1691
1692 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001693 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001694 {
1695 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1696 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001697 context->recordError(Error(GL_INVALID_OPERATION));
1698 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001699 }
1700
1701 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001702 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001703 {
Geoff Langb1196682014-07-23 13:47:29 -04001704 context->recordError(Error(GL_INVALID_OPERATION));
1705 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001706 }
1707
Jamie Madill2b976812014-08-25 15:47:49 -04001708 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001709 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001710 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001711 {
Geoff Langb1196682014-07-23 13:47:29 -04001712 context->recordError(Error(GL_INVALID_OPERATION));
1713 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001714 }
1715
Jamie Madillae3000b2014-08-25 15:47:51 -04001716 if (elementArrayBuffer)
1717 {
1718 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1719
1720 GLint64 offset = reinterpret_cast<GLint64>(indices);
1721 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1722
1723 // check for integer overflows
1724 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1725 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1726 {
Geoff Langb1196682014-07-23 13:47:29 -04001727 context->recordError(Error(GL_OUT_OF_MEMORY));
1728 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001729 }
1730
1731 // Check for reading past the end of the bound buffer object
1732 if (byteCount > elementArrayBuffer->getSize())
1733 {
Geoff Langb1196682014-07-23 13:47:29 -04001734 context->recordError(Error(GL_INVALID_OPERATION));
1735 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001736 }
1737 }
1738 else if (!indices)
1739 {
1740 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001741 context->recordError(Error(GL_INVALID_OPERATION));
1742 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001743 }
1744
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001745 if (!ValidateDrawBase(context, mode, count, primcount))
1746 {
1747 return false;
1748 }
1749
Jamie Madill2b976812014-08-25 15:47:49 -04001750 // Use max index to validate if our vertex buffers are large enough for the pull.
1751 // TODO: offer fast path, with disabled index validation.
1752 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1753 if (elementArrayBuffer)
1754 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001755 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001756 Error error =
1757 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1758 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001759 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001760 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001761 context->recordError(error);
1762 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001763 }
1764 }
1765 else
1766 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001767 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001768 }
1769
Jamie Madille79b1e12015-11-04 16:36:37 -05001770 // If we use an index greater than our maximum supported index range, return an error.
1771 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
1772 // return an error if possible here.
1773 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
1774 {
1775 context->recordError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
1776 return false;
1777 }
1778
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001779 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001780 {
1781 return false;
1782 }
1783
Geoff Lang3edfe032015-09-04 16:38:24 -04001784 // No op if there are no real indices in the index data (all are primitive restart).
1785 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001786}
1787
Geoff Langb1196682014-07-23 13:47:29 -04001788bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001789 GLenum mode,
1790 GLsizei count,
1791 GLenum type,
1792 const GLvoid *indices,
1793 GLsizei primcount,
1794 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001795{
1796 if (primcount < 0)
1797 {
Geoff Langb1196682014-07-23 13:47:29 -04001798 context->recordError(Error(GL_INVALID_VALUE));
1799 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001800 }
1801
Jamie Madill2b976812014-08-25 15:47:49 -04001802 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001803 {
1804 return false;
1805 }
1806
1807 // No-op zero primitive count
1808 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001809}
1810
Geoff Lang3edfe032015-09-04 16:38:24 -04001811bool ValidateDrawElementsInstancedANGLE(Context *context,
1812 GLenum mode,
1813 GLsizei count,
1814 GLenum type,
1815 const GLvoid *indices,
1816 GLsizei primcount,
1817 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001818{
1819 if (!ValidateDrawInstancedANGLE(context))
1820 {
1821 return false;
1822 }
1823
1824 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1825}
1826
Geoff Langb1196682014-07-23 13:47:29 -04001827bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001828 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001829{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001830 if (!ValidFramebufferTarget(target))
1831 {
Geoff Langb1196682014-07-23 13:47:29 -04001832 context->recordError(Error(GL_INVALID_ENUM));
1833 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001834 }
1835
1836 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001837 {
1838 return false;
1839 }
1840
Jamie Madill55ec3b12014-07-03 10:38:57 -04001841 if (texture != 0)
1842 {
1843 gl::Texture *tex = context->getTexture(texture);
1844
1845 if (tex == NULL)
1846 {
Geoff Langb1196682014-07-23 13:47:29 -04001847 context->recordError(Error(GL_INVALID_OPERATION));
1848 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001849 }
1850
1851 if (level < 0)
1852 {
Geoff Langb1196682014-07-23 13:47:29 -04001853 context->recordError(Error(GL_INVALID_VALUE));
1854 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001855 }
1856 }
1857
Shannon Woods53a94a82014-06-24 15:20:36 -04001858 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001859 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001860
Jamie Madill84115c92015-04-23 15:00:07 -04001861 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001862 {
Jamie Madill84115c92015-04-23 15:00:07 -04001863 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001864 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001865 }
1866
1867 return true;
1868}
1869
Geoff Langb1196682014-07-23 13:47:29 -04001870bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001871 GLenum textarget, GLuint texture, GLint level)
1872{
Geoff Lang95663912015-04-02 15:54:45 -04001873 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1874 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001875 {
Geoff Langb1196682014-07-23 13:47:29 -04001876 context->recordError(Error(GL_INVALID_VALUE));
1877 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001878 }
1879
1880 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001881 {
1882 return false;
1883 }
1884
Jamie Madill55ec3b12014-07-03 10:38:57 -04001885 if (texture != 0)
1886 {
1887 gl::Texture *tex = context->getTexture(texture);
1888 ASSERT(tex);
1889
Jamie Madill2a6564e2014-07-11 09:53:19 -04001890 const gl::Caps &caps = context->getCaps();
1891
Jamie Madill55ec3b12014-07-03 10:38:57 -04001892 switch (textarget)
1893 {
1894 case GL_TEXTURE_2D:
1895 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001896 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001897 {
Geoff Langb1196682014-07-23 13:47:29 -04001898 context->recordError(Error(GL_INVALID_VALUE));
1899 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001900 }
1901 if (tex->getTarget() != GL_TEXTURE_2D)
1902 {
Geoff Langb1196682014-07-23 13:47:29 -04001903 context->recordError(Error(GL_INVALID_OPERATION));
1904 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001905 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001906 }
1907 break;
1908
1909 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1910 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1911 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1912 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1913 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1914 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1915 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001916 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001917 {
Geoff Langb1196682014-07-23 13:47:29 -04001918 context->recordError(Error(GL_INVALID_VALUE));
1919 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001920 }
1921 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1922 {
Geoff Langb1196682014-07-23 13:47:29 -04001923 context->recordError(Error(GL_INVALID_OPERATION));
1924 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001925 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001926 }
1927 break;
1928
1929 default:
Geoff Langb1196682014-07-23 13:47:29 -04001930 context->recordError(Error(GL_INVALID_ENUM));
1931 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001932 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001933
1934 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1935 if (internalFormatInfo.compressed)
1936 {
1937 context->recordError(Error(GL_INVALID_OPERATION));
1938 return false;
1939 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001940 }
1941
Jamie Madill570f7c82014-07-03 10:38:54 -04001942 return true;
1943}
1944
Geoff Langb1196682014-07-23 13:47:29 -04001945bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001946{
1947 if (program == 0)
1948 {
Geoff Langb1196682014-07-23 13:47:29 -04001949 context->recordError(Error(GL_INVALID_VALUE));
1950 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001951 }
1952
Dian Xiang769769a2015-09-09 15:20:08 -07001953 gl::Program *programObject = GetValidProgram(context, program);
1954 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001955 {
1956 return false;
1957 }
1958
Jamie Madill0063c512014-08-25 15:47:53 -04001959 if (!programObject || !programObject->isLinked())
1960 {
Geoff Langb1196682014-07-23 13:47:29 -04001961 context->recordError(Error(GL_INVALID_OPERATION));
1962 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001963 }
1964
Geoff Lang7dd2e102014-11-10 15:19:26 -05001965 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001966 {
Geoff Langb1196682014-07-23 13:47:29 -04001967 context->recordError(Error(GL_INVALID_OPERATION));
1968 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001969 }
1970
Jamie Madill0063c512014-08-25 15:47:53 -04001971 return true;
1972}
1973
Geoff Langb1196682014-07-23 13:47:29 -04001974bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001975{
1976 return ValidateGetUniformBase(context, program, location);
1977}
1978
Geoff Langb1196682014-07-23 13:47:29 -04001979bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001980{
Jamie Madill78f41802014-08-25 15:47:55 -04001981 return ValidateGetUniformBase(context, program, location);
1982}
1983
Geoff Langb1196682014-07-23 13:47:29 -04001984static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001985{
1986 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001987 {
Jamie Madill78f41802014-08-25 15:47:55 -04001988 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001989 }
1990
Jamie Madilla502c742014-08-28 17:19:13 -04001991 gl::Program *programObject = context->getProgram(program);
1992 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001993
Jamie Madill78f41802014-08-25 15:47:55 -04001994 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04001995 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
1996 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04001997 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001998 {
Geoff Langb1196682014-07-23 13:47:29 -04001999 context->recordError(Error(GL_INVALID_OPERATION));
2000 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002001 }
2002
2003 return true;
2004}
2005
Geoff Langb1196682014-07-23 13:47:29 -04002006bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002007{
Jamie Madill78f41802014-08-25 15:47:55 -04002008 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002009}
2010
Geoff Langb1196682014-07-23 13:47:29 -04002011bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002012{
Jamie Madill78f41802014-08-25 15:47:55 -04002013 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04002014}
2015
Austin Kinross08332632015-05-05 13:35:47 -07002016bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2017 const GLenum *attachments, bool defaultFramebuffer)
2018{
2019 if (numAttachments < 0)
2020 {
2021 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
2022 return false;
2023 }
2024
2025 for (GLsizei i = 0; i < numAttachments; ++i)
2026 {
2027 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2028 {
2029 if (defaultFramebuffer)
2030 {
2031 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2032 return false;
2033 }
2034
2035 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2036 {
2037 context->recordError(Error(GL_INVALID_OPERATION,
2038 "Requested color attachment is greater than the maximum supported color attachments"));
2039 return false;
2040 }
2041 }
2042 else
2043 {
2044 switch (attachments[i])
2045 {
2046 case GL_DEPTH_ATTACHMENT:
2047 case GL_STENCIL_ATTACHMENT:
2048 case GL_DEPTH_STENCIL_ATTACHMENT:
2049 if (defaultFramebuffer)
2050 {
2051 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2052 return false;
2053 }
2054 break;
2055 case GL_COLOR:
2056 case GL_DEPTH:
2057 case GL_STENCIL:
2058 if (!defaultFramebuffer)
2059 {
2060 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2061 return false;
2062 }
2063 break;
2064 default:
2065 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2066 return false;
2067 }
2068 }
2069 }
2070
2071 return true;
2072}
2073
Austin Kinross6ee1e782015-05-29 17:05:37 -07002074bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2075{
2076 // Note that debug marker calls must not set error state
2077
2078 if (length < 0)
2079 {
2080 return false;
2081 }
2082
2083 if (marker == nullptr)
2084 {
2085 return false;
2086 }
2087
2088 return true;
2089}
2090
2091bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2092{
2093 // Note that debug marker calls must not set error state
2094
2095 if (length < 0)
2096 {
2097 return false;
2098 }
2099
2100 if (length > 0 && marker == nullptr)
2101 {
2102 return false;
2103 }
2104
2105 return true;
2106}
2107
Geoff Langdcab33b2015-07-21 13:03:16 -04002108bool ValidateEGLImageTargetTexture2DOES(Context *context,
2109 egl::Display *display,
2110 GLenum target,
2111 egl::Image *image)
2112{
Geoff Langa8406172015-07-21 16:53:39 -04002113 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2114 {
2115 context->recordError(Error(GL_INVALID_OPERATION));
2116 return false;
2117 }
2118
2119 switch (target)
2120 {
2121 case GL_TEXTURE_2D:
2122 break;
2123
2124 default:
2125 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2126 return false;
2127 }
2128
2129 if (!display->isValidImage(image))
2130 {
2131 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2132 return false;
2133 }
2134
2135 if (image->getSamples() > 0)
2136 {
2137 context->recordError(Error(GL_INVALID_OPERATION,
2138 "cannot create a 2D texture from a multisampled EGL image."));
2139 return false;
2140 }
2141
2142 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2143 if (!textureCaps.texturable)
2144 {
2145 context->recordError(Error(GL_INVALID_OPERATION,
2146 "EGL image internal format is not supported as a texture."));
2147 return false;
2148 }
2149
Geoff Langdcab33b2015-07-21 13:03:16 -04002150 return true;
2151}
2152
2153bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2154 egl::Display *display,
2155 GLenum target,
2156 egl::Image *image)
2157{
Geoff Langa8406172015-07-21 16:53:39 -04002158 if (!context->getExtensions().eglImage)
2159 {
2160 context->recordError(Error(GL_INVALID_OPERATION));
2161 return false;
2162 }
2163
2164 switch (target)
2165 {
2166 case GL_RENDERBUFFER:
2167 break;
2168
2169 default:
2170 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2171 return false;
2172 }
2173
2174 if (!display->isValidImage(image))
2175 {
2176 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2177 return false;
2178 }
2179
2180 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2181 if (!textureCaps.renderable)
2182 {
2183 context->recordError(Error(
2184 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2185 return false;
2186 }
2187
Geoff Langdcab33b2015-07-21 13:03:16 -04002188 return true;
2189}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002190
2191bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2192{
2193 VertexArray *vao = context->getVertexArray(array);
2194
2195 if (!vao)
2196 {
2197 // The default VAO should always exist
2198 ASSERT(array != 0);
2199 context->recordError(Error(GL_INVALID_OPERATION));
2200 return false;
2201 }
2202
2203 return true;
2204}
2205
2206bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n)
2207{
2208 if (n < 0)
2209 {
2210 context->recordError(Error(GL_INVALID_VALUE));
2211 return false;
2212 }
2213
2214 return true;
2215}
2216
2217bool ValidateGenVertexArraysBase(Context *context, GLsizei n)
2218{
2219 if (n < 0)
2220 {
2221 context->recordError(Error(GL_INVALID_VALUE));
2222 return false;
2223 }
2224
2225 return true;
2226}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002227}