blob: ee096ce171fa6724bbb83c54226a0f104f19db96 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madill1ca74672015-07-21 15:14:11 -040030namespace
31{
32bool ValidateDrawAttribs(gl::Context *context, GLint primcount, GLint maxVertex)
33{
34 const gl::State &state = context->getState();
35 const gl::Program *program = state.getProgram();
36
37 const VertexArray *vao = state.getVertexArray();
38 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040039 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
40 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
41 {
42 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040043 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040044 {
45 gl::Buffer *buffer = attrib.buffer.get();
46
47 if (buffer)
48 {
49 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
50 GLint64 maxVertexElement = 0;
51
52 if (attrib.divisor > 0)
53 {
54 maxVertexElement =
55 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
56 }
57 else
58 {
59 maxVertexElement = static_cast<GLint64>(maxVertex);
60 }
61
62 // If we're drawing zero vertices, we have enough data.
63 if (maxVertexElement > 0)
64 {
65 // Note: Last vertex element does not take the full stride!
66 GLint64 attribSize =
67 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
68 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
69
70 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
71 // We can return INVALID_OPERATION if our vertex attribute does not have
72 // enough backing data.
73 if (attribDataSize > buffer->getSize())
74 {
75 context->recordError(Error(GL_INVALID_OPERATION));
76 return false;
77 }
78 }
79 }
80 else if (attrib.pointer == NULL)
81 {
82 // This is an application error that would normally result in a crash,
83 // but we catch it and return an error
84 context->recordError(Error(
85 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
86 return false;
87 }
88 }
89 }
90
91 return true;
92}
93
94} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040095
Geoff Lang0550d032014-01-30 11:29:07 -050096bool ValidCap(const Context *context, GLenum cap)
97{
98 switch (cap)
99 {
100 case GL_CULL_FACE:
101 case GL_POLYGON_OFFSET_FILL:
102 case GL_SAMPLE_ALPHA_TO_COVERAGE:
103 case GL_SAMPLE_COVERAGE:
104 case GL_SCISSOR_TEST:
105 case GL_STENCIL_TEST:
106 case GL_DEPTH_TEST:
107 case GL_BLEND:
108 case GL_DITHER:
109 return true;
110 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
111 case GL_RASTERIZER_DISCARD:
112 return (context->getClientVersion() >= 3);
113 default:
114 return false;
115 }
116}
117
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500118bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400119{
Jamie Madilld7460c72014-01-21 16:38:14 -0500120 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 case GL_TEXTURE_2D:
123 case GL_TEXTURE_CUBE_MAP:
124 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400125
Jamie Madilld7460c72014-01-21 16:38:14 -0500126 case GL_TEXTURE_3D:
127 case GL_TEXTURE_2D_ARRAY:
128 return (context->getClientVersion() >= 3);
129
130 default:
131 return false;
132 }
Jamie Madill35d15012013-10-07 10:46:37 -0400133}
134
Shannon Woods4dfed832014-03-17 20:03:39 -0400135// This function differs from ValidTextureTarget in that the target must be
136// usable as the destination of a 2D operation-- so a cube face is valid, but
137// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400138// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400139bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
140{
141 switch (target)
142 {
143 case GL_TEXTURE_2D:
144 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
145 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
150 return true;
151 case GL_TEXTURE_2D_ARRAY:
152 case GL_TEXTURE_3D:
153 return (context->getClientVersion() >= 3);
154 default:
155 return false;
156 }
157}
158
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500159bool ValidFramebufferTarget(GLenum target)
160{
Geoff Langd4475812015-03-18 10:53:05 -0400161 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
162 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500163
164 switch (target)
165 {
166 case GL_FRAMEBUFFER: return true;
167 case GL_READ_FRAMEBUFFER: return true;
168 case GL_DRAW_FRAMEBUFFER: return true;
169 default: return false;
170 }
171}
172
Jamie Madill8c96d582014-03-05 15:01:23 -0500173bool ValidBufferTarget(const Context *context, GLenum target)
174{
175 switch (target)
176 {
177 case GL_ARRAY_BUFFER:
178 case GL_ELEMENT_ARRAY_BUFFER:
179 return true;
180
Jamie Madill8c96d582014-03-05 15:01:23 -0500181 case GL_PIXEL_PACK_BUFFER:
182 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400183 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400184
Shannon Woodsb3801742014-03-27 14:59:19 -0400185 case GL_COPY_READ_BUFFER:
186 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500187 case GL_TRANSFORM_FEEDBACK_BUFFER:
188 case GL_UNIFORM_BUFFER:
189 return (context->getClientVersion() >= 3);
190
191 default:
192 return false;
193 }
194}
195
Jamie Madill70656a62014-03-05 15:01:26 -0500196bool ValidBufferParameter(const Context *context, GLenum pname)
197{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400198 const Extensions &extensions = context->getExtensions();
199
Jamie Madill70656a62014-03-05 15:01:26 -0500200 switch (pname)
201 {
202 case GL_BUFFER_USAGE:
203 case GL_BUFFER_SIZE:
204 return true;
205
Geoff Langcc6f55d2015-03-20 13:01:02 -0400206 case GL_BUFFER_ACCESS_OES:
207 return extensions.mapBuffer;
208
209 case GL_BUFFER_MAPPED:
210 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
211 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
212
Jamie Madill70656a62014-03-05 15:01:26 -0500213 // GL_BUFFER_MAP_POINTER is a special case, and may only be
214 // queried with GetBufferPointerv
215 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500216 case GL_BUFFER_MAP_OFFSET:
217 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400218 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500219
220 default:
221 return false;
222 }
223}
224
Jamie Madill8c96d582014-03-05 15:01:23 -0500225bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400226{
Geoff Langaae65a42014-05-26 12:43:44 -0400227 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400228 switch (target)
229 {
Geoff Langaae65a42014-05-26 12:43:44 -0400230 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400231 case GL_TEXTURE_CUBE_MAP:
232 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
233 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
238 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
239 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400240 default: UNREACHABLE();
241 }
242
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700243 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400244}
245
Geoff Langb1196682014-07-23 13:47:29 -0400246bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400247 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400248{
249 if (level < 0 || width < 0 || height < 0 || depth < 0)
250 {
251 return false;
252 }
253
Geoff Langc0b9ef42014-07-02 10:02:37 -0400254 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400255 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400256 {
257 return false;
258 }
259
260 if (!ValidMipLevel(context, target, level))
261 {
262 return false;
263 }
264
265 return true;
266}
267
Geoff Lang0d8b7242015-09-09 14:56:53 -0400268bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
269{
270 // List of compressed format that require that the texture size is smaller than or a multiple of
271 // the compressed block size.
272 switch (internalFormat)
273 {
274 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
275 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
276 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
277 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
278 return true;
279
280 default:
281 return false;
282 }
283}
284
Geoff Langb1196682014-07-23 13:47:29 -0400285bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400286{
Geoff Lang5d601382014-07-22 15:14:06 -0400287 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
288 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400289 {
290 return false;
291 }
292
Geoff Lang0d8b7242015-09-09 14:56:53 -0400293 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400294 {
295 return false;
296 }
297
Geoff Lang0d8b7242015-09-09 14:56:53 -0400298 if (CompressedTextureFormatRequiresExactSize(internalFormat))
299 {
300 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
301 width % formatInfo.compressedBlockWidth != 0) ||
302 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
303 height % formatInfo.compressedBlockHeight != 0))
304 {
305 return false;
306 }
307 }
308
Geoff Langd4f180b2013-09-24 13:57:44 -0400309 return true;
310}
311
Geoff Lang37dde692014-01-31 16:34:54 -0500312bool ValidQueryType(const Context *context, GLenum queryType)
313{
Geoff Langd4475812015-03-18 10:53:05 -0400314 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
315 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 -0500316
317 switch (queryType)
318 {
319 case GL_ANY_SAMPLES_PASSED:
320 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
321 return true;
322 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
323 return (context->getClientVersion() >= 3);
324 default:
325 return false;
326 }
327}
328
Dian Xiang769769a2015-09-09 15:20:08 -0700329Program *GetValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500330{
331 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
332 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
333 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
334
Dian Xiang769769a2015-09-09 15:20:08 -0700335 Program *validProgram = context->getProgram(id);
336
337 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500338 {
Dian Xiang769769a2015-09-09 15:20:08 -0700339 if (context->getShader(id))
340 {
341 context->recordError(
342 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
343 }
344 else
345 {
346 context->recordError(Error(GL_INVALID_VALUE, "Program name is not valid"));
347 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500348 }
Dian Xiang769769a2015-09-09 15:20:08 -0700349
350 return validProgram;
351}
352
353Shader *GetValidShader(Context *context, GLuint id)
354{
355 // See ValidProgram for spec details.
356
357 Shader *validShader = context->getShader(id);
358
359 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500360 {
Dian Xiang769769a2015-09-09 15:20:08 -0700361 if (context->getProgram(id))
362 {
363 context->recordError(
364 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
365 }
366 else
367 {
368 context->recordError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
369 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500370 }
Dian Xiang769769a2015-09-09 15:20:08 -0700371
372 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500373}
374
Geoff Langb1196682014-07-23 13:47:29 -0400375bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400376{
377 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
378 {
379 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
380
Geoff Langaae65a42014-05-26 12:43:44 -0400381 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400382 {
Geoff Langb1196682014-07-23 13:47:29 -0400383 context->recordError(Error(GL_INVALID_VALUE));
384 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400385 }
386 }
387 else
388 {
389 switch (attachment)
390 {
391 case GL_DEPTH_ATTACHMENT:
392 case GL_STENCIL_ATTACHMENT:
393 break;
394
395 case GL_DEPTH_STENCIL_ATTACHMENT:
396 if (context->getClientVersion() < 3)
397 {
Geoff Langb1196682014-07-23 13:47:29 -0400398 context->recordError(Error(GL_INVALID_ENUM));
399 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400400 }
401 break;
402
403 default:
Geoff Langb1196682014-07-23 13:47:29 -0400404 context->recordError(Error(GL_INVALID_ENUM));
405 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400406 }
407 }
408
409 return true;
410}
411
Corentin Walleze0902642014-11-04 12:32:15 -0800412bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
413 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400414{
415 switch (target)
416 {
417 case GL_RENDERBUFFER:
418 break;
419 default:
Geoff Langb1196682014-07-23 13:47:29 -0400420 context->recordError(Error(GL_INVALID_ENUM));
421 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400422 }
423
424 if (width < 0 || height < 0 || samples < 0)
425 {
Geoff Langb1196682014-07-23 13:47:29 -0400426 context->recordError(Error(GL_INVALID_VALUE));
427 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400428 }
429
Geoff Langd87878e2014-09-19 15:42:59 -0400430 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
431 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400432 {
Geoff Langb1196682014-07-23 13:47:29 -0400433 context->recordError(Error(GL_INVALID_ENUM));
434 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400435 }
436
437 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
438 // 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 -0800439 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400440 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400441 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 {
Geoff Langb1196682014-07-23 13:47:29 -0400443 context->recordError(Error(GL_INVALID_ENUM));
444 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400445 }
446
Geoff Langaae65a42014-05-26 12:43:44 -0400447 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400448 {
Geoff Langb1196682014-07-23 13:47:29 -0400449 context->recordError(Error(GL_INVALID_VALUE));
450 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400451 }
452
Shannon Woods53a94a82014-06-24 15:20:36 -0400453 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400454 if (handle == 0)
455 {
Geoff Langb1196682014-07-23 13:47:29 -0400456 context->recordError(Error(GL_INVALID_OPERATION));
457 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400458 }
459
460 return true;
461}
462
Corentin Walleze0902642014-11-04 12:32:15 -0800463bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
464 GLenum internalformat, GLsizei width, GLsizei height)
465{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800466 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800467
468 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400469 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800470 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400471 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800472 {
473 context->recordError(Error(GL_INVALID_VALUE));
474 return false;
475 }
476
477 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
478 // the specified storage. This is different than ES 3.0 in which a sample number higher
479 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800480 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
481 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800482 {
Geoff Langa4903b72015-03-02 16:02:48 -0800483 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
484 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
485 {
486 context->recordError(Error(GL_OUT_OF_MEMORY));
487 return false;
488 }
Corentin Walleze0902642014-11-04 12:32:15 -0800489 }
490
491 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
492}
493
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500494bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
495 GLenum renderbuffertarget, GLuint renderbuffer)
496{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400497 if (!ValidFramebufferTarget(target))
498 {
Geoff Langb1196682014-07-23 13:47:29 -0400499 context->recordError(Error(GL_INVALID_ENUM));
500 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400501 }
502
Shannon Woods53a94a82014-06-24 15:20:36 -0400503 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500504
Jamie Madill84115c92015-04-23 15:00:07 -0400505 ASSERT(framebuffer);
506 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500507 {
Jamie Madill84115c92015-04-23 15:00:07 -0400508 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400509 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500510 }
511
Jamie Madillb4472272014-07-03 10:38:55 -0400512 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500513 {
Jamie Madillb4472272014-07-03 10:38:55 -0400514 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500515 }
516
Jamie Madillab9d82c2014-01-21 16:38:14 -0500517 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
518 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
519 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
520 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
521 if (renderbuffer != 0)
522 {
523 if (!context->getRenderbuffer(renderbuffer))
524 {
Geoff Langb1196682014-07-23 13:47:29 -0400525 context->recordError(Error(GL_INVALID_OPERATION));
526 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500527 }
528 }
529
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500530 return true;
531}
532
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400533static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400534 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
535 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
536{
537 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
538 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
539 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
540 {
541 return true;
542 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400543 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400544 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400545 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400546
Shannon Woods53a94a82014-06-24 15:20:36 -0400547 return scissor.x > 0 || scissor.y > 0 ||
548 scissor.width < writeBuffer->getWidth() ||
549 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400550 }
551 else
552 {
553 return false;
554 }
555}
556
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400557bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400558 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
559 GLenum filter, bool fromAngleExtension)
560{
561 switch (filter)
562 {
563 case GL_NEAREST:
564 break;
565 case GL_LINEAR:
566 if (fromAngleExtension)
567 {
Geoff Langb1196682014-07-23 13:47:29 -0400568 context->recordError(Error(GL_INVALID_ENUM));
569 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400570 }
571 break;
572 default:
Geoff Langb1196682014-07-23 13:47:29 -0400573 context->recordError(Error(GL_INVALID_ENUM));
574 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400575 }
576
577 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
578 {
Geoff Langb1196682014-07-23 13:47:29 -0400579 context->recordError(Error(GL_INVALID_VALUE));
580 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 }
582
583 if (mask == 0)
584 {
585 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
586 // buffers are copied.
587 return false;
588 }
589
590 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
591 {
592 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400593 context->recordError(Error(GL_INVALID_OPERATION));
594 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400595 }
596
597 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
598 // color buffer, leaving only nearest being unfiltered from above
599 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
600 {
Geoff Langb1196682014-07-23 13:47:29 -0400601 context->recordError(Error(GL_INVALID_OPERATION));
602 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400603 }
604
Shannon Woods53a94a82014-06-24 15:20:36 -0400605 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606 {
607 if (fromAngleExtension)
608 {
609 ERR("Blits with the same source and destination framebuffer are not supported by this "
610 "implementation.");
611 }
Geoff Langb1196682014-07-23 13:47:29 -0400612 context->recordError(Error(GL_INVALID_OPERATION));
613 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400614 }
615
Jamie Madille3ef7152015-04-28 16:55:17 +0000616 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
617 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500618
619 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400620 {
Geoff Langb1196682014-07-23 13:47:29 -0400621 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
622 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400623 }
624
Geoff Lang748f74e2014-12-01 11:25:34 -0500625 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500626 {
627 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
628 return false;
629 }
630
Geoff Lang748f74e2014-12-01 11:25:34 -0500631 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500632 {
633 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
634 return false;
635 }
636
637 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400638 {
Geoff Langb1196682014-07-23 13:47:29 -0400639 context->recordError(Error(GL_INVALID_OPERATION));
640 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400641 }
642
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
644
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 if (mask & GL_COLOR_BUFFER_BIT)
646 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400647 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
648 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649
650 if (readColorBuffer && drawColorBuffer)
651 {
Geoff Langd8a22582014-12-17 15:28:23 -0500652 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400653 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654
Corentin Wallez37c39792015-08-20 14:19:46 -0400655 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656 {
657 if (drawFramebuffer->isEnabledColorAttachment(i))
658 {
Geoff Langd8a22582014-12-17 15:28:23 -0500659 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400660 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661
Geoff Langb2f3d052013-08-13 12:49:27 -0400662 // The GL ES 3.0.2 spec (pg 193) states that:
663 // 1) If the read buffer is fixed point format, the draw buffer must be as well
664 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
665 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400666 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
667 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668 {
Geoff Langb1196682014-07-23 13:47:29 -0400669 context->recordError(Error(GL_INVALID_OPERATION));
670 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400671 }
672
Geoff Lang5d601382014-07-22 15:14:06 -0400673 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400674 {
Geoff Langb1196682014-07-23 13:47:29 -0400675 context->recordError(Error(GL_INVALID_OPERATION));
676 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400677 }
678
Geoff Lang5d601382014-07-22 15:14:06 -0400679 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680 {
Geoff Langb1196682014-07-23 13:47:29 -0400681 context->recordError(Error(GL_INVALID_OPERATION));
682 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 }
684
Geoff Langb2f3d052013-08-13 12:49:27 -0400685 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400686 {
Geoff Langb1196682014-07-23 13:47:29 -0400687 context->recordError(Error(GL_INVALID_OPERATION));
688 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400689 }
690 }
691 }
692
Geoff Lang5d601382014-07-22 15:14:06 -0400693 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 {
Geoff Langb1196682014-07-23 13:47:29 -0400695 context->recordError(Error(GL_INVALID_OPERATION));
696 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 }
698
699 if (fromAngleExtension)
700 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400701 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500702 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400703 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500704 readColorAttachment->type() != GL_RENDERBUFFER &&
705 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706 {
Geoff Langb1196682014-07-23 13:47:29 -0400707 context->recordError(Error(GL_INVALID_OPERATION));
708 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 }
710
Corentin Wallez37c39792015-08-20 14:19:46 -0400711 for (size_t colorAttachment = 0;
712 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713 {
714 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
715 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000716 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400717 ASSERT(attachment);
718
Jamie Madill8cf4a392015-04-02 11:36:04 -0400719 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500720 attachment->type() != GL_RENDERBUFFER &&
721 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722 {
Geoff Langb1196682014-07-23 13:47:29 -0400723 context->recordError(Error(GL_INVALID_OPERATION));
724 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400725 }
726
Jamie Madillf8f18f02014-10-02 10:44:17 -0400727 // Return an error if the destination formats do not match
728 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400729 {
Geoff Langb1196682014-07-23 13:47:29 -0400730 context->recordError(Error(GL_INVALID_OPERATION));
731 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 }
733 }
734 }
Jamie Madill48faf802014-11-06 15:27:22 -0500735
736 int readSamples = readFramebuffer->getSamples(context->getData());
737
738 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
739 srcX0, srcY0, srcX1, srcY1,
740 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 {
Geoff Langb1196682014-07-23 13:47:29 -0400742 context->recordError(Error(GL_INVALID_OPERATION));
743 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400744 }
745 }
746 }
747 }
748
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200749 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
750 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
751 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400752 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200753 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400755 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
756 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400757
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200758 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400759 {
Geoff Langd8a22582014-12-17 15:28:23 -0500760 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 {
Geoff Langb1196682014-07-23 13:47:29 -0400762 context->recordError(Error(GL_INVALID_OPERATION));
763 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200766 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 {
Geoff Langb1196682014-07-23 13:47:29 -0400768 context->recordError(Error(GL_INVALID_OPERATION));
769 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400770 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200771
772 if (fromAngleExtension)
773 {
774 if (IsPartialBlit(context, readBuffer, drawBuffer,
775 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
776 {
777 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
778 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
779 return false;
780 }
781
782 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
783 {
784 context->recordError(Error(GL_INVALID_OPERATION));
785 return false;
786 }
787 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400788 }
789 }
790 }
791
792 return true;
793}
794
Geoff Langb1196682014-07-23 13:47:29 -0400795bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796{
797 switch (pname)
798 {
799 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
800 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
801 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
802 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
803 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
804 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
805 case GL_CURRENT_VERTEX_ATTRIB:
806 return true;
807
808 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
809 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
810 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400811 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
812 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400813 return true;
814
815 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400816 if (context->getClientVersion() < 3)
817 {
818 context->recordError(Error(GL_INVALID_ENUM));
819 return false;
820 }
821 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400822
823 default:
Geoff Langb1196682014-07-23 13:47:29 -0400824 context->recordError(Error(GL_INVALID_ENUM));
825 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400826 }
827}
828
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400829bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400830{
831 switch (pname)
832 {
833 case GL_TEXTURE_WRAP_R:
834 case GL_TEXTURE_SWIZZLE_R:
835 case GL_TEXTURE_SWIZZLE_G:
836 case GL_TEXTURE_SWIZZLE_B:
837 case GL_TEXTURE_SWIZZLE_A:
838 case GL_TEXTURE_BASE_LEVEL:
839 case GL_TEXTURE_MAX_LEVEL:
840 case GL_TEXTURE_COMPARE_MODE:
841 case GL_TEXTURE_COMPARE_FUNC:
842 case GL_TEXTURE_MIN_LOD:
843 case GL_TEXTURE_MAX_LOD:
844 if (context->getClientVersion() < 3)
845 {
Geoff Langb1196682014-07-23 13:47:29 -0400846 context->recordError(Error(GL_INVALID_ENUM));
847 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400848 }
849 break;
850
851 default: break;
852 }
853
854 switch (pname)
855 {
856 case GL_TEXTURE_WRAP_S:
857 case GL_TEXTURE_WRAP_T:
858 case GL_TEXTURE_WRAP_R:
859 switch (param)
860 {
861 case GL_REPEAT:
862 case GL_CLAMP_TO_EDGE:
863 case GL_MIRRORED_REPEAT:
864 return true;
865 default:
Geoff Langb1196682014-07-23 13:47:29 -0400866 context->recordError(Error(GL_INVALID_ENUM));
867 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400868 }
869
870 case GL_TEXTURE_MIN_FILTER:
871 switch (param)
872 {
873 case GL_NEAREST:
874 case GL_LINEAR:
875 case GL_NEAREST_MIPMAP_NEAREST:
876 case GL_LINEAR_MIPMAP_NEAREST:
877 case GL_NEAREST_MIPMAP_LINEAR:
878 case GL_LINEAR_MIPMAP_LINEAR:
879 return true;
880 default:
Geoff Langb1196682014-07-23 13:47:29 -0400881 context->recordError(Error(GL_INVALID_ENUM));
882 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400883 }
884 break;
885
886 case GL_TEXTURE_MAG_FILTER:
887 switch (param)
888 {
889 case GL_NEAREST:
890 case GL_LINEAR:
891 return true;
892 default:
Geoff Langb1196682014-07-23 13:47:29 -0400893 context->recordError(Error(GL_INVALID_ENUM));
894 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 }
896 break;
897
898 case GL_TEXTURE_USAGE_ANGLE:
899 switch (param)
900 {
901 case GL_NONE:
902 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
903 return true;
904 default:
Geoff Langb1196682014-07-23 13:47:29 -0400905 context->recordError(Error(GL_INVALID_ENUM));
906 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400907 }
908 break;
909
910 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400911 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400912 {
Geoff Langb1196682014-07-23 13:47:29 -0400913 context->recordError(Error(GL_INVALID_ENUM));
914 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400915 }
916
917 // we assume the parameter passed to this validation method is truncated, not rounded
918 if (param < 1)
919 {
Geoff Langb1196682014-07-23 13:47:29 -0400920 context->recordError(Error(GL_INVALID_VALUE));
921 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400922 }
923 return true;
924
925 case GL_TEXTURE_MIN_LOD:
926 case GL_TEXTURE_MAX_LOD:
927 // any value is permissible
928 return true;
929
930 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400931 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400932 switch (param)
933 {
934 case GL_NONE:
935 case GL_COMPARE_REF_TO_TEXTURE:
936 return true;
937 default:
Geoff Langb1196682014-07-23 13:47:29 -0400938 context->recordError(Error(GL_INVALID_ENUM));
939 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400940 }
941 break;
942
943 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400944 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400945 switch (param)
946 {
947 case GL_LEQUAL:
948 case GL_GEQUAL:
949 case GL_LESS:
950 case GL_GREATER:
951 case GL_EQUAL:
952 case GL_NOTEQUAL:
953 case GL_ALWAYS:
954 case GL_NEVER:
955 return true;
956 default:
Geoff Langb1196682014-07-23 13:47:29 -0400957 context->recordError(Error(GL_INVALID_ENUM));
958 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400959 }
960 break;
961
962 case GL_TEXTURE_SWIZZLE_R:
963 case GL_TEXTURE_SWIZZLE_G:
964 case GL_TEXTURE_SWIZZLE_B:
965 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400966 switch (param)
967 {
968 case GL_RED:
969 case GL_GREEN:
970 case GL_BLUE:
971 case GL_ALPHA:
972 case GL_ZERO:
973 case GL_ONE:
974 return true;
975 default:
Geoff Langb1196682014-07-23 13:47:29 -0400976 context->recordError(Error(GL_INVALID_ENUM));
977 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400978 }
979 break;
980
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400981 case GL_TEXTURE_BASE_LEVEL:
982 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400983 if (param < 0)
984 {
Geoff Langb1196682014-07-23 13:47:29 -0400985 context->recordError(Error(GL_INVALID_VALUE));
986 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400987 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400988 return true;
989
990 default:
Geoff Langb1196682014-07-23 13:47:29 -0400991 context->recordError(Error(GL_INVALID_ENUM));
992 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400993 }
994}
995
Geoff Langb1196682014-07-23 13:47:29 -0400996bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400997{
998 switch (pname)
999 {
1000 case GL_TEXTURE_MIN_FILTER:
1001 case GL_TEXTURE_MAG_FILTER:
1002 case GL_TEXTURE_WRAP_S:
1003 case GL_TEXTURE_WRAP_T:
1004 case GL_TEXTURE_WRAP_R:
1005 case GL_TEXTURE_MIN_LOD:
1006 case GL_TEXTURE_MAX_LOD:
1007 case GL_TEXTURE_COMPARE_MODE:
1008 case GL_TEXTURE_COMPARE_FUNC:
1009 return true;
1010
1011 default:
Geoff Langb1196682014-07-23 13:47:29 -04001012 context->recordError(Error(GL_INVALID_ENUM));
1013 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001014 }
1015}
1016
Jamie Madill26e91952014-03-05 15:01:27 -05001017bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
1018 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
1019{
Shannon Woods53a94a82014-06-24 15:20:36 -04001020 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001021 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001022
Geoff Lang748f74e2014-12-01 11:25:34 -05001023 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001024 {
Geoff Langb1196682014-07-23 13:47:29 -04001025 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1026 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001027 }
1028
Jamie Madill48faf802014-11-06 15:27:22 -05001029 if (context->getState().getReadFramebuffer()->id() != 0 &&
1030 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001031 {
Geoff Langb1196682014-07-23 13:47:29 -04001032 context->recordError(Error(GL_INVALID_OPERATION));
1033 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001034 }
1035
Geoff Langbce529e2014-12-01 12:48:41 -05001036 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1037 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001038 {
Geoff Langb1196682014-07-23 13:47:29 -04001039 context->recordError(Error(GL_INVALID_OPERATION));
1040 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001041 }
1042
Geoff Langbce529e2014-12-01 12:48:41 -05001043 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1044 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001045 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001046 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001047
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001048 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1049 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001050
1051 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1052 {
Geoff Langb1196682014-07-23 13:47:29 -04001053 context->recordError(Error(GL_INVALID_OPERATION));
1054 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001055 }
1056
Geoff Lang5d601382014-07-22 15:14:06 -04001057 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1058 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001059
Minmin Gongf1bb3f02015-10-01 17:19:45 -07001060 GLsizei outputPitch =
1061 sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(),
1062 context->getState().getPackRowLength());
Jamie Madill26e91952014-03-05 15:01:27 -05001063 // sized query sanity check
1064 if (bufSize)
1065 {
1066 int requiredSize = outputPitch * height;
1067 if (requiredSize > *bufSize)
1068 {
Geoff Langb1196682014-07-23 13:47:29 -04001069 context->recordError(Error(GL_INVALID_OPERATION));
1070 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001071 }
1072 }
1073
1074 return true;
1075}
1076
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001077bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1078{
1079 if (!ValidQueryType(context, target))
1080 {
Geoff Langb1196682014-07-23 13:47:29 -04001081 context->recordError(Error(GL_INVALID_ENUM));
1082 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001083 }
1084
1085 if (id == 0)
1086 {
Geoff Langb1196682014-07-23 13:47:29 -04001087 context->recordError(Error(GL_INVALID_OPERATION));
1088 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001089 }
1090
1091 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1092 // of zero, if the active query object name for <target> is non-zero (for the
1093 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1094 // the active query for either target is non-zero), if <id> is the name of an
1095 // existing query object whose type does not match <target>, or if <id> is the
1096 // active query object name for any query type, the error INVALID_OPERATION is
1097 // generated.
1098
1099 // Ensure no other queries are active
1100 // NOTE: If other queries than occlusion are supported, we will need to check
1101 // separately that:
1102 // a) The query ID passed is not the current active query for any target/type
1103 // b) There are no active queries for the requested target (and in the case
1104 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1105 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001106 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001107 {
Geoff Langb1196682014-07-23 13:47:29 -04001108 context->recordError(Error(GL_INVALID_OPERATION));
1109 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001110 }
1111
1112 Query *queryObject = context->getQuery(id, true, target);
1113
1114 // check that name was obtained with glGenQueries
1115 if (!queryObject)
1116 {
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 // check for type mismatch
1122 if (queryObject->getType() != target)
1123 {
Geoff Langb1196682014-07-23 13:47:29 -04001124 context->recordError(Error(GL_INVALID_OPERATION));
1125 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001126 }
1127
1128 return true;
1129}
1130
Jamie Madill45c785d2014-05-13 14:09:34 -04001131bool ValidateEndQuery(gl::Context *context, GLenum target)
1132{
1133 if (!ValidQueryType(context, target))
1134 {
Geoff Langb1196682014-07-23 13:47:29 -04001135 context->recordError(Error(GL_INVALID_ENUM));
1136 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001137 }
1138
Shannon Woods53a94a82014-06-24 15:20:36 -04001139 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001140
1141 if (queryObject == NULL)
1142 {
Geoff Langb1196682014-07-23 13:47:29 -04001143 context->recordError(Error(GL_INVALID_OPERATION));
1144 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001145 }
1146
Jamie Madill45c785d2014-05-13 14:09:34 -04001147 return true;
1148}
1149
Jamie Madill62d31cb2015-09-11 13:25:51 -04001150static bool ValidateUniformCommonBase(gl::Context *context,
1151 GLenum targetUniformType,
1152 GLint location,
1153 GLsizei count,
1154 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001155{
1156 if (count < 0)
1157 {
Geoff Langb1196682014-07-23 13:47:29 -04001158 context->recordError(Error(GL_INVALID_VALUE));
1159 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001160 }
1161
Geoff Lang7dd2e102014-11-10 15:19:26 -05001162 gl::Program *program = context->getState().getProgram();
1163 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001164 {
Geoff Langb1196682014-07-23 13:47:29 -04001165 context->recordError(Error(GL_INVALID_OPERATION));
1166 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001167 }
1168
1169 if (location == -1)
1170 {
1171 // Silently ignore the uniform command
1172 return false;
1173 }
1174
Geoff Lang7dd2e102014-11-10 15:19:26 -05001175 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001176 {
Geoff Langb1196682014-07-23 13:47:29 -04001177 context->recordError(Error(GL_INVALID_OPERATION));
1178 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001179 }
1180
Jamie Madill62d31cb2015-09-11 13:25:51 -04001181 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001182
1183 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001184 if (!uniform.isArray() && count > 1)
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 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001191 return true;
1192}
1193
Jamie Madillaa981bd2014-05-20 10:55:55 -04001194bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1195{
1196 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001197 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001198 {
Geoff Langb1196682014-07-23 13:47:29 -04001199 context->recordError(Error(GL_INVALID_OPERATION));
1200 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001201 }
1202
Jamie Madill62d31cb2015-09-11 13:25:51 -04001203 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001204 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1205 {
1206 return false;
1207 }
1208
Jamie Madillf2575982014-06-25 16:04:54 -04001209 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001210 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001211 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1212 {
Geoff Langb1196682014-07-23 13:47:29 -04001213 context->recordError(Error(GL_INVALID_OPERATION));
1214 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001215 }
1216
1217 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001218}
1219
1220bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1221 GLboolean transpose)
1222{
1223 // Check for ES3 uniform entry points
1224 int rows = VariableRowCount(matrixType);
1225 int cols = VariableColumnCount(matrixType);
1226 if (rows != cols && context->getClientVersion() < 3)
1227 {
Geoff Langb1196682014-07-23 13:47:29 -04001228 context->recordError(Error(GL_INVALID_OPERATION));
1229 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001230 }
1231
1232 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1233 {
Geoff Langb1196682014-07-23 13:47:29 -04001234 context->recordError(Error(GL_INVALID_VALUE));
1235 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001236 }
1237
Jamie Madill62d31cb2015-09-11 13:25:51 -04001238 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001239 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1240 {
1241 return false;
1242 }
1243
1244 if (uniform->type != matrixType)
1245 {
Geoff Langb1196682014-07-23 13:47:29 -04001246 context->recordError(Error(GL_INVALID_OPERATION));
1247 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001248 }
1249
1250 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001251}
1252
Jamie Madill893ab082014-05-16 16:56:10 -04001253bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1254{
1255 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1256 {
Geoff Langb1196682014-07-23 13:47:29 -04001257 context->recordError(Error(GL_INVALID_ENUM));
1258 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001259 }
1260
Jamie Madill0af26e12015-03-05 19:54:33 -05001261 const Caps &caps = context->getCaps();
1262
Jamie Madill893ab082014-05-16 16:56:10 -04001263 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1264 {
1265 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1266
Jamie Madill0af26e12015-03-05 19:54:33 -05001267 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001268 {
Geoff Langb1196682014-07-23 13:47:29 -04001269 context->recordError(Error(GL_INVALID_OPERATION));
1270 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001271 }
1272 }
1273
1274 switch (pname)
1275 {
1276 case GL_TEXTURE_BINDING_2D:
1277 case GL_TEXTURE_BINDING_CUBE_MAP:
1278 case GL_TEXTURE_BINDING_3D:
1279 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001280 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001281 {
Geoff Langb1196682014-07-23 13:47:29 -04001282 context->recordError(Error(GL_INVALID_OPERATION));
1283 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001284 }
1285 break;
1286
1287 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1288 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1289 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001290 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001291 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001292 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001293 {
Geoff Langb1196682014-07-23 13:47:29 -04001294 context->recordError(Error(GL_INVALID_OPERATION));
1295 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001296 }
1297
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001298 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001299 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001300 {
Geoff Langb1196682014-07-23 13:47:29 -04001301 context->recordError(Error(GL_INVALID_OPERATION));
1302 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001303 }
1304 }
1305 break;
1306
1307 default:
1308 break;
1309 }
1310
1311 // pname is valid, but there are no parameters to return
1312 if (numParams == 0)
1313 {
1314 return false;
1315 }
1316
1317 return true;
1318}
1319
Geoff Lang831b1952015-05-05 11:02:27 -04001320bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001321 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1322 GLint border, GLenum *textureFormatOut)
1323{
1324
1325 if (!ValidTexture2DDestinationTarget(context, target))
1326 {
Geoff Langb1196682014-07-23 13:47:29 -04001327 context->recordError(Error(GL_INVALID_ENUM));
1328 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001329 }
1330
1331 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1332 {
Geoff Langb1196682014-07-23 13:47:29 -04001333 context->recordError(Error(GL_INVALID_VALUE));
1334 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001335 }
1336
1337 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1338 {
Geoff Langb1196682014-07-23 13:47:29 -04001339 context->recordError(Error(GL_INVALID_VALUE));
1340 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001341 }
1342
1343 if (border != 0)
1344 {
Geoff Langb1196682014-07-23 13:47:29 -04001345 context->recordError(Error(GL_INVALID_VALUE));
1346 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001347 }
1348
1349 if (!ValidMipLevel(context, target, level))
1350 {
Geoff Langb1196682014-07-23 13:47:29 -04001351 context->recordError(Error(GL_INVALID_VALUE));
1352 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001353 }
1354
Shannon Woods53a94a82014-06-24 15:20:36 -04001355 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001356 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 {
Geoff Langb1196682014-07-23 13:47:29 -04001358 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1359 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001360 }
1361
Jamie Madill48faf802014-11-06 15:27:22 -05001362 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001363 {
Geoff Langb1196682014-07-23 13:47:29 -04001364 context->recordError(Error(GL_INVALID_OPERATION));
1365 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001366 }
1367
Geoff Langaae65a42014-05-26 12:43:44 -04001368 const gl::Caps &caps = context->getCaps();
1369
Geoff Langaae65a42014-05-26 12:43:44 -04001370 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001371 switch (target)
1372 {
1373 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001374 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001375 break;
1376
1377 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1378 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1379 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1380 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1381 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1382 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001383 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001384 break;
1385
1386 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001387 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001388 break;
1389
1390 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001391 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001392 break;
1393
1394 default:
Geoff Langb1196682014-07-23 13:47:29 -04001395 context->recordError(Error(GL_INVALID_ENUM));
1396 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001397 }
1398
Geoff Lang691e58c2014-12-19 17:03:25 -05001399 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001400 if (!texture)
1401 {
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_OPERATION));
1403 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001404 }
1405
Geoff Lang69cce582015-09-17 13:20:36 -04001406 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04001407 {
Geoff Langb1196682014-07-23 13:47:29 -04001408 context->recordError(Error(GL_INVALID_OPERATION));
1409 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001410 }
1411
Geoff Lang5d601382014-07-22 15:14:06 -04001412 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1413
1414 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001415 {
Geoff Langb1196682014-07-23 13:47:29 -04001416 context->recordError(Error(GL_INVALID_OPERATION));
1417 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001418 }
1419
Geoff Langa9be0dc2014-12-17 12:34:40 -05001420 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001421 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001422 context->recordError(Error(GL_INVALID_OPERATION));
1423 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001424 }
1425
1426 if (isSubImage)
1427 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001428 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1429 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1430 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001431 {
Geoff Langb1196682014-07-23 13:47:29 -04001432 context->recordError(Error(GL_INVALID_VALUE));
1433 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001434 }
1435 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001436 else
1437 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001438 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001439 {
Geoff Langb1196682014-07-23 13:47:29 -04001440 context->recordError(Error(GL_INVALID_VALUE));
1441 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001442 }
1443
Geoff Lang5d601382014-07-22 15:14:06 -04001444 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001445 {
Geoff Langb1196682014-07-23 13:47:29 -04001446 context->recordError(Error(GL_INVALID_ENUM));
1447 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001448 }
1449
1450 int maxLevelDimension = (maxDimension >> level);
1451 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1452 {
Geoff Langb1196682014-07-23 13:47:29 -04001453 context->recordError(Error(GL_INVALID_VALUE));
1454 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001455 }
1456 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001457
Geoff Langa9be0dc2014-12-17 12:34:40 -05001458 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001459 return true;
1460}
1461
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001462static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001463{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001464 switch (mode)
1465 {
1466 case GL_POINTS:
1467 case GL_LINES:
1468 case GL_LINE_LOOP:
1469 case GL_LINE_STRIP:
1470 case GL_TRIANGLES:
1471 case GL_TRIANGLE_STRIP:
1472 case GL_TRIANGLE_FAN:
1473 break;
1474 default:
Geoff Langb1196682014-07-23 13:47:29 -04001475 context->recordError(Error(GL_INVALID_ENUM));
1476 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001477 }
1478
Jamie Madill250d33f2014-06-06 17:09:03 -04001479 if (count < 0)
1480 {
Geoff Langb1196682014-07-23 13:47:29 -04001481 context->recordError(Error(GL_INVALID_VALUE));
1482 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001483 }
1484
Geoff Langb1196682014-07-23 13:47:29 -04001485 const State &state = context->getState();
1486
Jamie Madill250d33f2014-06-06 17:09:03 -04001487 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001488 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001489 {
Geoff Langb1196682014-07-23 13:47:29 -04001490 context->recordError(Error(GL_INVALID_OPERATION));
1491 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001492 }
1493
Geoff Lang3a86ad32015-09-01 11:47:05 -04001494 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001495 {
Geoff Lang3a86ad32015-09-01 11:47:05 -04001496 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
1497 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1498 state.getStencilRef() != state.getStencilBackRef() ||
1499 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1500 {
1501 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1502 // Section 6.10 of the WebGL 1.0 spec
1503 ERR(
1504 "This ANGLE implementation does not support separate front/back stencil "
1505 "writemasks, reference values, or stencil mask values.");
1506 context->recordError(Error(GL_INVALID_OPERATION));
1507 return false;
1508 }
Jamie Madillac528012014-06-20 13:21:23 -04001509 }
1510
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001511 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001512 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001513 {
Geoff Langb1196682014-07-23 13:47:29 -04001514 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1515 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001516 }
1517
Geoff Lang7dd2e102014-11-10 15:19:26 -05001518 gl::Program *program = state.getProgram();
1519 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001520 {
Geoff Langb1196682014-07-23 13:47:29 -04001521 context->recordError(Error(GL_INVALID_OPERATION));
1522 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001523 }
1524
Geoff Lang7dd2e102014-11-10 15:19:26 -05001525 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001526 {
Geoff Langb1196682014-07-23 13:47:29 -04001527 context->recordError(Error(GL_INVALID_OPERATION));
1528 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001529 }
1530
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001531 // Uniform buffer validation
1532 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1533 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04001534 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001535 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04001536 const OffsetBindingPointer<Buffer> &uniformBuffer =
1537 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001538
Geoff Lang5d124a62015-09-15 13:03:27 -04001539 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001540 {
1541 // undefined behaviour
1542 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1543 return false;
1544 }
1545
Geoff Lang5d124a62015-09-15 13:03:27 -04001546 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001547 if (uniformBufferSize == 0)
1548 {
1549 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001550 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001551 }
1552
Jamie Madill62d31cb2015-09-11 13:25:51 -04001553 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001554 {
1555 // undefined behaviour
1556 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1557 return false;
1558 }
1559 }
1560
Jamie Madill250d33f2014-06-06 17:09:03 -04001561 // No-op if zero count
1562 return (count > 0);
1563}
1564
Geoff Langb1196682014-07-23 13:47:29 -04001565bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001566{
Jamie Madillfd716582014-06-06 17:09:04 -04001567 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001568 {
Geoff Langb1196682014-07-23 13:47:29 -04001569 context->recordError(Error(GL_INVALID_VALUE));
1570 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001571 }
1572
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001573 const State &state = context->getState();
1574 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001575 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1576 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001577 {
1578 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1579 // that does not match the current transform feedback object's draw mode (if transform feedback
1580 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001581 context->recordError(Error(GL_INVALID_OPERATION));
1582 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001583 }
1584
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001585 if (!ValidateDrawBase(context, mode, count, primcount))
1586 {
1587 return false;
1588 }
1589
1590 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001591 {
1592 return false;
1593 }
1594
1595 return true;
1596}
1597
Geoff Langb1196682014-07-23 13:47:29 -04001598bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001599{
1600 if (primcount < 0)
1601 {
Geoff Langb1196682014-07-23 13:47:29 -04001602 context->recordError(Error(GL_INVALID_VALUE));
1603 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001604 }
1605
Jamie Madill2b976812014-08-25 15:47:49 -04001606 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001607 {
1608 return false;
1609 }
1610
1611 // No-op if zero primitive count
1612 return (primcount > 0);
1613}
1614
Geoff Lang87a93302014-09-16 13:29:43 -04001615static bool ValidateDrawInstancedANGLE(Context *context)
1616{
1617 // Verify there is at least one active attribute with a divisor of zero
1618 const gl::State& state = context->getState();
1619
Geoff Lang7dd2e102014-11-10 15:19:26 -05001620 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001621
1622 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001623 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001624 {
1625 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001626 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001627 {
1628 return true;
1629 }
1630 }
1631
1632 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1633 "has a divisor of zero."));
1634 return false;
1635}
1636
1637bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1638{
1639 if (!ValidateDrawInstancedANGLE(context))
1640 {
1641 return false;
1642 }
1643
1644 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1645}
1646
Geoff Lang3edfe032015-09-04 16:38:24 -04001647bool ValidateDrawElements(Context *context,
1648 GLenum mode,
1649 GLsizei count,
1650 GLenum type,
1651 const GLvoid *indices,
1652 GLsizei primcount,
1653 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001654{
Jamie Madill250d33f2014-06-06 17:09:03 -04001655 switch (type)
1656 {
1657 case GL_UNSIGNED_BYTE:
1658 case GL_UNSIGNED_SHORT:
1659 break;
1660 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001661 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001662 {
Geoff Langb1196682014-07-23 13:47:29 -04001663 context->recordError(Error(GL_INVALID_ENUM));
1664 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001665 }
1666 break;
1667 default:
Geoff Langb1196682014-07-23 13:47:29 -04001668 context->recordError(Error(GL_INVALID_ENUM));
1669 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001670 }
1671
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001672 const State &state = context->getState();
1673
1674 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001675 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001676 {
1677 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1678 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001679 context->recordError(Error(GL_INVALID_OPERATION));
1680 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001681 }
1682
1683 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001684 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001685 {
Geoff Langb1196682014-07-23 13:47:29 -04001686 context->recordError(Error(GL_INVALID_OPERATION));
1687 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001688 }
1689
Jamie Madill2b976812014-08-25 15:47:49 -04001690 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001691 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001692 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001693 {
Geoff Langb1196682014-07-23 13:47:29 -04001694 context->recordError(Error(GL_INVALID_OPERATION));
1695 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001696 }
1697
Jamie Madillae3000b2014-08-25 15:47:51 -04001698 if (elementArrayBuffer)
1699 {
1700 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1701
1702 GLint64 offset = reinterpret_cast<GLint64>(indices);
1703 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1704
1705 // check for integer overflows
1706 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1707 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1708 {
Geoff Langb1196682014-07-23 13:47:29 -04001709 context->recordError(Error(GL_OUT_OF_MEMORY));
1710 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001711 }
1712
1713 // Check for reading past the end of the bound buffer object
1714 if (byteCount > elementArrayBuffer->getSize())
1715 {
Geoff Langb1196682014-07-23 13:47:29 -04001716 context->recordError(Error(GL_INVALID_OPERATION));
1717 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001718 }
1719 }
1720 else if (!indices)
1721 {
1722 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001723 context->recordError(Error(GL_INVALID_OPERATION));
1724 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001725 }
1726
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001727 if (!ValidateDrawBase(context, mode, count, primcount))
1728 {
1729 return false;
1730 }
1731
Jamie Madill2b976812014-08-25 15:47:49 -04001732 // Use max index to validate if our vertex buffers are large enough for the pull.
1733 // TODO: offer fast path, with disabled index validation.
1734 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1735 if (elementArrayBuffer)
1736 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001737 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04001738 Error error =
1739 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
1740 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001741 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001742 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001743 context->recordError(error);
1744 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001745 }
1746 }
1747 else
1748 {
Geoff Lang3edfe032015-09-04 16:38:24 -04001749 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04001750 }
1751
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001752 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001753 {
1754 return false;
1755 }
1756
Geoff Lang3edfe032015-09-04 16:38:24 -04001757 // No op if there are no real indices in the index data (all are primitive restart).
1758 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04001759}
1760
Geoff Langb1196682014-07-23 13:47:29 -04001761bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04001762 GLenum mode,
1763 GLsizei count,
1764 GLenum type,
1765 const GLvoid *indices,
1766 GLsizei primcount,
1767 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001768{
1769 if (primcount < 0)
1770 {
Geoff Langb1196682014-07-23 13:47:29 -04001771 context->recordError(Error(GL_INVALID_VALUE));
1772 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001773 }
1774
Jamie Madill2b976812014-08-25 15:47:49 -04001775 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001776 {
1777 return false;
1778 }
1779
1780 // No-op zero primitive count
1781 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001782}
1783
Geoff Lang3edfe032015-09-04 16:38:24 -04001784bool ValidateDrawElementsInstancedANGLE(Context *context,
1785 GLenum mode,
1786 GLsizei count,
1787 GLenum type,
1788 const GLvoid *indices,
1789 GLsizei primcount,
1790 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001791{
1792 if (!ValidateDrawInstancedANGLE(context))
1793 {
1794 return false;
1795 }
1796
1797 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1798}
1799
Geoff Langb1196682014-07-23 13:47:29 -04001800bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001801 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001802{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001803 if (!ValidFramebufferTarget(target))
1804 {
Geoff Langb1196682014-07-23 13:47:29 -04001805 context->recordError(Error(GL_INVALID_ENUM));
1806 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001807 }
1808
1809 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001810 {
1811 return false;
1812 }
1813
Jamie Madill55ec3b12014-07-03 10:38:57 -04001814 if (texture != 0)
1815 {
1816 gl::Texture *tex = context->getTexture(texture);
1817
1818 if (tex == NULL)
1819 {
Geoff Langb1196682014-07-23 13:47:29 -04001820 context->recordError(Error(GL_INVALID_OPERATION));
1821 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001822 }
1823
1824 if (level < 0)
1825 {
Geoff Langb1196682014-07-23 13:47:29 -04001826 context->recordError(Error(GL_INVALID_VALUE));
1827 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001828 }
1829 }
1830
Shannon Woods53a94a82014-06-24 15:20:36 -04001831 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001832 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001833
Jamie Madill84115c92015-04-23 15:00:07 -04001834 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001835 {
Jamie Madill84115c92015-04-23 15:00:07 -04001836 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001837 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001838 }
1839
1840 return true;
1841}
1842
Geoff Langb1196682014-07-23 13:47:29 -04001843bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001844 GLenum textarget, GLuint texture, GLint level)
1845{
Geoff Lang95663912015-04-02 15:54:45 -04001846 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1847 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001848 {
Geoff Langb1196682014-07-23 13:47:29 -04001849 context->recordError(Error(GL_INVALID_VALUE));
1850 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001851 }
1852
1853 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001854 {
1855 return false;
1856 }
1857
Jamie Madill55ec3b12014-07-03 10:38:57 -04001858 if (texture != 0)
1859 {
1860 gl::Texture *tex = context->getTexture(texture);
1861 ASSERT(tex);
1862
Jamie Madill2a6564e2014-07-11 09:53:19 -04001863 const gl::Caps &caps = context->getCaps();
1864
Jamie Madill55ec3b12014-07-03 10:38:57 -04001865 switch (textarget)
1866 {
1867 case GL_TEXTURE_2D:
1868 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001869 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001870 {
Geoff Langb1196682014-07-23 13:47:29 -04001871 context->recordError(Error(GL_INVALID_VALUE));
1872 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001873 }
1874 if (tex->getTarget() != GL_TEXTURE_2D)
1875 {
Geoff Langb1196682014-07-23 13:47:29 -04001876 context->recordError(Error(GL_INVALID_OPERATION));
1877 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001878 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001879 }
1880 break;
1881
1882 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1883 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1884 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1885 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1886 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1887 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1888 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001889 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001890 {
Geoff Langb1196682014-07-23 13:47:29 -04001891 context->recordError(Error(GL_INVALID_VALUE));
1892 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001893 }
1894 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1895 {
Geoff Langb1196682014-07-23 13:47:29 -04001896 context->recordError(Error(GL_INVALID_OPERATION));
1897 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001898 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001899 }
1900 break;
1901
1902 default:
Geoff Langb1196682014-07-23 13:47:29 -04001903 context->recordError(Error(GL_INVALID_ENUM));
1904 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001905 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001906
1907 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1908 if (internalFormatInfo.compressed)
1909 {
1910 context->recordError(Error(GL_INVALID_OPERATION));
1911 return false;
1912 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001913 }
1914
Jamie Madill570f7c82014-07-03 10:38:54 -04001915 return true;
1916}
1917
Geoff Langb1196682014-07-23 13:47:29 -04001918bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001919{
1920 if (program == 0)
1921 {
Geoff Langb1196682014-07-23 13:47:29 -04001922 context->recordError(Error(GL_INVALID_VALUE));
1923 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001924 }
1925
Dian Xiang769769a2015-09-09 15:20:08 -07001926 gl::Program *programObject = GetValidProgram(context, program);
1927 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05001928 {
1929 return false;
1930 }
1931
Jamie Madill0063c512014-08-25 15:47:53 -04001932 if (!programObject || !programObject->isLinked())
1933 {
Geoff Langb1196682014-07-23 13:47:29 -04001934 context->recordError(Error(GL_INVALID_OPERATION));
1935 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001936 }
1937
Geoff Lang7dd2e102014-11-10 15:19:26 -05001938 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001939 {
Geoff Langb1196682014-07-23 13:47:29 -04001940 context->recordError(Error(GL_INVALID_OPERATION));
1941 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001942 }
1943
Jamie Madill0063c512014-08-25 15:47:53 -04001944 return true;
1945}
1946
Geoff Langb1196682014-07-23 13:47:29 -04001947bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001948{
1949 return ValidateGetUniformBase(context, program, location);
1950}
1951
Geoff Langb1196682014-07-23 13:47:29 -04001952bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001953{
Jamie Madill78f41802014-08-25 15:47:55 -04001954 return ValidateGetUniformBase(context, program, location);
1955}
1956
Geoff Langb1196682014-07-23 13:47:29 -04001957static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001958{
1959 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001960 {
Jamie Madill78f41802014-08-25 15:47:55 -04001961 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001962 }
1963
Jamie Madilla502c742014-08-28 17:19:13 -04001964 gl::Program *programObject = context->getProgram(program);
1965 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001966
Jamie Madill78f41802014-08-25 15:47:55 -04001967 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04001968 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
1969 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04001970 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001971 {
Geoff Langb1196682014-07-23 13:47:29 -04001972 context->recordError(Error(GL_INVALID_OPERATION));
1973 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001974 }
1975
1976 return true;
1977}
1978
Geoff Langb1196682014-07-23 13:47:29 -04001979bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001980{
Jamie Madill78f41802014-08-25 15:47:55 -04001981 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001982}
1983
Geoff Langb1196682014-07-23 13:47:29 -04001984bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001985{
Jamie Madill78f41802014-08-25 15:47:55 -04001986 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001987}
1988
Austin Kinross08332632015-05-05 13:35:47 -07001989bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
1990 const GLenum *attachments, bool defaultFramebuffer)
1991{
1992 if (numAttachments < 0)
1993 {
1994 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
1995 return false;
1996 }
1997
1998 for (GLsizei i = 0; i < numAttachments; ++i)
1999 {
2000 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
2001 {
2002 if (defaultFramebuffer)
2003 {
2004 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2005 return false;
2006 }
2007
2008 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2009 {
2010 context->recordError(Error(GL_INVALID_OPERATION,
2011 "Requested color attachment is greater than the maximum supported color attachments"));
2012 return false;
2013 }
2014 }
2015 else
2016 {
2017 switch (attachments[i])
2018 {
2019 case GL_DEPTH_ATTACHMENT:
2020 case GL_STENCIL_ATTACHMENT:
2021 case GL_DEPTH_STENCIL_ATTACHMENT:
2022 if (defaultFramebuffer)
2023 {
2024 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
2025 return false;
2026 }
2027 break;
2028 case GL_COLOR:
2029 case GL_DEPTH:
2030 case GL_STENCIL:
2031 if (!defaultFramebuffer)
2032 {
2033 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
2034 return false;
2035 }
2036 break;
2037 default:
2038 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
2039 return false;
2040 }
2041 }
2042 }
2043
2044 return true;
2045}
2046
Austin Kinross6ee1e782015-05-29 17:05:37 -07002047bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2048{
2049 // Note that debug marker calls must not set error state
2050
2051 if (length < 0)
2052 {
2053 return false;
2054 }
2055
2056 if (marker == nullptr)
2057 {
2058 return false;
2059 }
2060
2061 return true;
2062}
2063
2064bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2065{
2066 // Note that debug marker calls must not set error state
2067
2068 if (length < 0)
2069 {
2070 return false;
2071 }
2072
2073 if (length > 0 && marker == nullptr)
2074 {
2075 return false;
2076 }
2077
2078 return true;
2079}
2080
Geoff Langdcab33b2015-07-21 13:03:16 -04002081bool ValidateEGLImageTargetTexture2DOES(Context *context,
2082 egl::Display *display,
2083 GLenum target,
2084 egl::Image *image)
2085{
Geoff Langa8406172015-07-21 16:53:39 -04002086 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2087 {
2088 context->recordError(Error(GL_INVALID_OPERATION));
2089 return false;
2090 }
2091
2092 switch (target)
2093 {
2094 case GL_TEXTURE_2D:
2095 break;
2096
2097 default:
2098 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2099 return false;
2100 }
2101
2102 if (!display->isValidImage(image))
2103 {
2104 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2105 return false;
2106 }
2107
2108 if (image->getSamples() > 0)
2109 {
2110 context->recordError(Error(GL_INVALID_OPERATION,
2111 "cannot create a 2D texture from a multisampled EGL image."));
2112 return false;
2113 }
2114
2115 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2116 if (!textureCaps.texturable)
2117 {
2118 context->recordError(Error(GL_INVALID_OPERATION,
2119 "EGL image internal format is not supported as a texture."));
2120 return false;
2121 }
2122
Geoff Langdcab33b2015-07-21 13:03:16 -04002123 return true;
2124}
2125
2126bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2127 egl::Display *display,
2128 GLenum target,
2129 egl::Image *image)
2130{
Geoff Langa8406172015-07-21 16:53:39 -04002131 if (!context->getExtensions().eglImage)
2132 {
2133 context->recordError(Error(GL_INVALID_OPERATION));
2134 return false;
2135 }
2136
2137 switch (target)
2138 {
2139 case GL_RENDERBUFFER:
2140 break;
2141
2142 default:
2143 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2144 return false;
2145 }
2146
2147 if (!display->isValidImage(image))
2148 {
2149 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2150 return false;
2151 }
2152
2153 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2154 if (!textureCaps.renderable)
2155 {
2156 context->recordError(Error(
2157 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2158 return false;
2159 }
2160
Geoff Langdcab33b2015-07-21 13:03:16 -04002161 return true;
2162}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002163}