blob: b858d6f4226d1d193317219d019c08bd9492b604 [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 Langb1196682014-07-23 13:47:29 -0400268bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400269{
Geoff Lang5d601382014-07-22 15:14:06 -0400270 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
271 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400272 {
273 return false;
274 }
275
Geoff Lang5d601382014-07-22 15:14:06 -0400276 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
277 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400278 {
279 return false;
280 }
281
282 return true;
283}
284
Geoff Lang37dde692014-01-31 16:34:54 -0500285bool ValidQueryType(const Context *context, GLenum queryType)
286{
Geoff Langd4475812015-03-18 10:53:05 -0400287 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
288 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 -0500289
290 switch (queryType)
291 {
292 case GL_ANY_SAMPLES_PASSED:
293 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
294 return true;
295 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
296 return (context->getClientVersion() >= 3);
297 default:
298 return false;
299 }
300}
301
Geoff Langb1196682014-07-23 13:47:29 -0400302bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500303{
304 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
305 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
306 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
307
308 if (context->getProgram(id) != NULL)
309 {
310 return true;
311 }
312 else if (context->getShader(id) != NULL)
313 {
314 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400315 context->recordError(Error(GL_INVALID_OPERATION));
316 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500317 }
318 else
319 {
320 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400321 context->recordError(Error(GL_INVALID_VALUE));
322 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500323 }
324}
325
Geoff Langb1196682014-07-23 13:47:29 -0400326bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400327{
328 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
329 {
330 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
331
Geoff Langaae65a42014-05-26 12:43:44 -0400332 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400333 {
Geoff Langb1196682014-07-23 13:47:29 -0400334 context->recordError(Error(GL_INVALID_VALUE));
335 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400336 }
337 }
338 else
339 {
340 switch (attachment)
341 {
342 case GL_DEPTH_ATTACHMENT:
343 case GL_STENCIL_ATTACHMENT:
344 break;
345
346 case GL_DEPTH_STENCIL_ATTACHMENT:
347 if (context->getClientVersion() < 3)
348 {
Geoff Langb1196682014-07-23 13:47:29 -0400349 context->recordError(Error(GL_INVALID_ENUM));
350 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400351 }
352 break;
353
354 default:
Geoff Langb1196682014-07-23 13:47:29 -0400355 context->recordError(Error(GL_INVALID_ENUM));
356 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400357 }
358 }
359
360 return true;
361}
362
Corentin Walleze0902642014-11-04 12:32:15 -0800363bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
364 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400365{
366 switch (target)
367 {
368 case GL_RENDERBUFFER:
369 break;
370 default:
Geoff Langb1196682014-07-23 13:47:29 -0400371 context->recordError(Error(GL_INVALID_ENUM));
372 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400373 }
374
375 if (width < 0 || height < 0 || samples < 0)
376 {
Geoff Langb1196682014-07-23 13:47:29 -0400377 context->recordError(Error(GL_INVALID_VALUE));
378 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400379 }
380
Geoff Langd87878e2014-09-19 15:42:59 -0400381 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
382 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400383 {
Geoff Langb1196682014-07-23 13:47:29 -0400384 context->recordError(Error(GL_INVALID_ENUM));
385 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400386 }
387
388 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
389 // 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 -0800390 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400391 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400392 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400393 {
Geoff Langb1196682014-07-23 13:47:29 -0400394 context->recordError(Error(GL_INVALID_ENUM));
395 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400396 }
397
Geoff Langaae65a42014-05-26 12:43:44 -0400398 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400399 {
Geoff Langb1196682014-07-23 13:47:29 -0400400 context->recordError(Error(GL_INVALID_VALUE));
401 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400402 }
403
Shannon Woods53a94a82014-06-24 15:20:36 -0400404 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400405 if (handle == 0)
406 {
Geoff Langb1196682014-07-23 13:47:29 -0400407 context->recordError(Error(GL_INVALID_OPERATION));
408 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400409 }
410
411 return true;
412}
413
Corentin Walleze0902642014-11-04 12:32:15 -0800414bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
415 GLenum internalformat, GLsizei width, GLsizei height)
416{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800417 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800418
419 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400420 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800421 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400422 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800423 {
424 context->recordError(Error(GL_INVALID_VALUE));
425 return false;
426 }
427
428 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
429 // the specified storage. This is different than ES 3.0 in which a sample number higher
430 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800431 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
432 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800433 {
Geoff Langa4903b72015-03-02 16:02:48 -0800434 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
435 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
436 {
437 context->recordError(Error(GL_OUT_OF_MEMORY));
438 return false;
439 }
Corentin Walleze0902642014-11-04 12:32:15 -0800440 }
441
442 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
443}
444
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500445bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
446 GLenum renderbuffertarget, GLuint renderbuffer)
447{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400448 if (!ValidFramebufferTarget(target))
449 {
Geoff Langb1196682014-07-23 13:47:29 -0400450 context->recordError(Error(GL_INVALID_ENUM));
451 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400452 }
453
Shannon Woods53a94a82014-06-24 15:20:36 -0400454 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500455
Jamie Madill84115c92015-04-23 15:00:07 -0400456 ASSERT(framebuffer);
457 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500458 {
Jamie Madill84115c92015-04-23 15:00:07 -0400459 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400460 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500461 }
462
Jamie Madillb4472272014-07-03 10:38:55 -0400463 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500464 {
Jamie Madillb4472272014-07-03 10:38:55 -0400465 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500466 }
467
Jamie Madillab9d82c2014-01-21 16:38:14 -0500468 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
469 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
470 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
471 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
472 if (renderbuffer != 0)
473 {
474 if (!context->getRenderbuffer(renderbuffer))
475 {
Geoff Langb1196682014-07-23 13:47:29 -0400476 context->recordError(Error(GL_INVALID_OPERATION));
477 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500478 }
479 }
480
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500481 return true;
482}
483
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400484static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400485 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
486 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
487{
488 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
489 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
490 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
491 {
492 return true;
493 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400494 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400495 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400496 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400497
Shannon Woods53a94a82014-06-24 15:20:36 -0400498 return scissor.x > 0 || scissor.y > 0 ||
499 scissor.width < writeBuffer->getWidth() ||
500 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400501 }
502 else
503 {
504 return false;
505 }
506}
507
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400508bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400509 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
510 GLenum filter, bool fromAngleExtension)
511{
512 switch (filter)
513 {
514 case GL_NEAREST:
515 break;
516 case GL_LINEAR:
517 if (fromAngleExtension)
518 {
Geoff Langb1196682014-07-23 13:47:29 -0400519 context->recordError(Error(GL_INVALID_ENUM));
520 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400521 }
522 break;
523 default:
Geoff Langb1196682014-07-23 13:47:29 -0400524 context->recordError(Error(GL_INVALID_ENUM));
525 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526 }
527
528 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
529 {
Geoff Langb1196682014-07-23 13:47:29 -0400530 context->recordError(Error(GL_INVALID_VALUE));
531 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400532 }
533
534 if (mask == 0)
535 {
536 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
537 // buffers are copied.
538 return false;
539 }
540
541 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
542 {
543 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400544 context->recordError(Error(GL_INVALID_OPERATION));
545 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400546 }
547
548 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
549 // color buffer, leaving only nearest being unfiltered from above
550 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
551 {
Geoff Langb1196682014-07-23 13:47:29 -0400552 context->recordError(Error(GL_INVALID_OPERATION));
553 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400554 }
555
Shannon Woods53a94a82014-06-24 15:20:36 -0400556 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400557 {
558 if (fromAngleExtension)
559 {
560 ERR("Blits with the same source and destination framebuffer are not supported by this "
561 "implementation.");
562 }
Geoff Langb1196682014-07-23 13:47:29 -0400563 context->recordError(Error(GL_INVALID_OPERATION));
564 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400565 }
566
Jamie Madille3ef7152015-04-28 16:55:17 +0000567 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
568 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500569
570 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400571 {
Geoff Langb1196682014-07-23 13:47:29 -0400572 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
573 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400574 }
575
Geoff Lang748f74e2014-12-01 11:25:34 -0500576 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500577 {
578 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
579 return false;
580 }
581
Geoff Lang748f74e2014-12-01 11:25:34 -0500582 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500583 {
584 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
585 return false;
586 }
587
588 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400589 {
Geoff Langb1196682014-07-23 13:47:29 -0400590 context->recordError(Error(GL_INVALID_OPERATION));
591 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400592 }
593
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400594 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
595
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 if (mask & GL_COLOR_BUFFER_BIT)
597 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400598 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
599 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400600
601 if (readColorBuffer && drawColorBuffer)
602 {
Geoff Langd8a22582014-12-17 15:28:23 -0500603 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400604 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605
Corentin Wallez37c39792015-08-20 14:19:46 -0400606 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400607 {
608 if (drawFramebuffer->isEnabledColorAttachment(i))
609 {
Geoff Langd8a22582014-12-17 15:28:23 -0500610 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400611 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612
Geoff Langb2f3d052013-08-13 12:49:27 -0400613 // The GL ES 3.0.2 spec (pg 193) states that:
614 // 1) If the read buffer is fixed point format, the draw buffer must be as well
615 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
616 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400617 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
618 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400619 {
Geoff Langb1196682014-07-23 13:47:29 -0400620 context->recordError(Error(GL_INVALID_OPERATION));
621 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622 }
623
Geoff Lang5d601382014-07-22 15:14:06 -0400624 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400625 {
Geoff Langb1196682014-07-23 13:47:29 -0400626 context->recordError(Error(GL_INVALID_OPERATION));
627 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628 }
629
Geoff Lang5d601382014-07-22 15:14:06 -0400630 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400631 {
Geoff Langb1196682014-07-23 13:47:29 -0400632 context->recordError(Error(GL_INVALID_OPERATION));
633 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 }
635
Geoff Langb2f3d052013-08-13 12:49:27 -0400636 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 {
Geoff Langb1196682014-07-23 13:47:29 -0400638 context->recordError(Error(GL_INVALID_OPERATION));
639 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 }
641 }
642 }
643
Geoff Lang5d601382014-07-22 15:14:06 -0400644 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 {
Geoff Langb1196682014-07-23 13:47:29 -0400646 context->recordError(Error(GL_INVALID_OPERATION));
647 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400648 }
649
650 if (fromAngleExtension)
651 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400652 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500653 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400654 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500655 readColorAttachment->type() != GL_RENDERBUFFER &&
656 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400657 {
Geoff Langb1196682014-07-23 13:47:29 -0400658 context->recordError(Error(GL_INVALID_OPERATION));
659 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400660 }
661
Corentin Wallez37c39792015-08-20 14:19:46 -0400662 for (size_t colorAttachment = 0;
663 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664 {
665 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
666 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000667 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400668 ASSERT(attachment);
669
Jamie Madill8cf4a392015-04-02 11:36:04 -0400670 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500671 attachment->type() != GL_RENDERBUFFER &&
672 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 {
Geoff Langb1196682014-07-23 13:47:29 -0400674 context->recordError(Error(GL_INVALID_OPERATION));
675 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676 }
677
Jamie Madillf8f18f02014-10-02 10:44:17 -0400678 // Return an error if the destination formats do not match
679 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
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 }
685 }
Jamie Madill48faf802014-11-06 15:27:22 -0500686
687 int readSamples = readFramebuffer->getSamples(context->getData());
688
689 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
690 srcX0, srcY0, srcX1, srcY1,
691 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400692 {
Geoff Langb1196682014-07-23 13:47:29 -0400693 context->recordError(Error(GL_INVALID_OPERATION));
694 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400695 }
696 }
697 }
698 }
699
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200700 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
701 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
702 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200704 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400705 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400706 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
707 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400708
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200709 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710 {
Geoff Langd8a22582014-12-17 15:28:23 -0500711 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400712 {
Geoff Langb1196682014-07-23 13:47:29 -0400713 context->recordError(Error(GL_INVALID_OPERATION));
714 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400715 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200717 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400718 {
Geoff Langb1196682014-07-23 13:47:29 -0400719 context->recordError(Error(GL_INVALID_OPERATION));
720 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400721 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200722
723 if (fromAngleExtension)
724 {
725 if (IsPartialBlit(context, readBuffer, drawBuffer,
726 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
727 {
728 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
729 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
730 return false;
731 }
732
733 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
734 {
735 context->recordError(Error(GL_INVALID_OPERATION));
736 return false;
737 }
738 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400739 }
740 }
741 }
742
743 return true;
744}
745
Geoff Langb1196682014-07-23 13:47:29 -0400746bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400747{
748 switch (pname)
749 {
750 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
751 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
752 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
753 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
754 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
755 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
756 case GL_CURRENT_VERTEX_ATTRIB:
757 return true;
758
759 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
760 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
761 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400762 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
763 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400764 return true;
765
766 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400767 if (context->getClientVersion() < 3)
768 {
769 context->recordError(Error(GL_INVALID_ENUM));
770 return false;
771 }
772 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773
774 default:
Geoff Langb1196682014-07-23 13:47:29 -0400775 context->recordError(Error(GL_INVALID_ENUM));
776 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 }
778}
779
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400780bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400781{
782 switch (pname)
783 {
784 case GL_TEXTURE_WRAP_R:
785 case GL_TEXTURE_SWIZZLE_R:
786 case GL_TEXTURE_SWIZZLE_G:
787 case GL_TEXTURE_SWIZZLE_B:
788 case GL_TEXTURE_SWIZZLE_A:
789 case GL_TEXTURE_BASE_LEVEL:
790 case GL_TEXTURE_MAX_LEVEL:
791 case GL_TEXTURE_COMPARE_MODE:
792 case GL_TEXTURE_COMPARE_FUNC:
793 case GL_TEXTURE_MIN_LOD:
794 case GL_TEXTURE_MAX_LOD:
795 if (context->getClientVersion() < 3)
796 {
Geoff Langb1196682014-07-23 13:47:29 -0400797 context->recordError(Error(GL_INVALID_ENUM));
798 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 }
800 break;
801
802 default: break;
803 }
804
805 switch (pname)
806 {
807 case GL_TEXTURE_WRAP_S:
808 case GL_TEXTURE_WRAP_T:
809 case GL_TEXTURE_WRAP_R:
810 switch (param)
811 {
812 case GL_REPEAT:
813 case GL_CLAMP_TO_EDGE:
814 case GL_MIRRORED_REPEAT:
815 return true;
816 default:
Geoff Langb1196682014-07-23 13:47:29 -0400817 context->recordError(Error(GL_INVALID_ENUM));
818 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400819 }
820
821 case GL_TEXTURE_MIN_FILTER:
822 switch (param)
823 {
824 case GL_NEAREST:
825 case GL_LINEAR:
826 case GL_NEAREST_MIPMAP_NEAREST:
827 case GL_LINEAR_MIPMAP_NEAREST:
828 case GL_NEAREST_MIPMAP_LINEAR:
829 case GL_LINEAR_MIPMAP_LINEAR:
830 return true;
831 default:
Geoff Langb1196682014-07-23 13:47:29 -0400832 context->recordError(Error(GL_INVALID_ENUM));
833 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400834 }
835 break;
836
837 case GL_TEXTURE_MAG_FILTER:
838 switch (param)
839 {
840 case GL_NEAREST:
841 case GL_LINEAR:
842 return true;
843 default:
Geoff Langb1196682014-07-23 13:47:29 -0400844 context->recordError(Error(GL_INVALID_ENUM));
845 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846 }
847 break;
848
849 case GL_TEXTURE_USAGE_ANGLE:
850 switch (param)
851 {
852 case GL_NONE:
853 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
854 return true;
855 default:
Geoff Langb1196682014-07-23 13:47:29 -0400856 context->recordError(Error(GL_INVALID_ENUM));
857 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400858 }
859 break;
860
861 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400862 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400863 {
Geoff Langb1196682014-07-23 13:47:29 -0400864 context->recordError(Error(GL_INVALID_ENUM));
865 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400866 }
867
868 // we assume the parameter passed to this validation method is truncated, not rounded
869 if (param < 1)
870 {
Geoff Langb1196682014-07-23 13:47:29 -0400871 context->recordError(Error(GL_INVALID_VALUE));
872 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400873 }
874 return true;
875
876 case GL_TEXTURE_MIN_LOD:
877 case GL_TEXTURE_MAX_LOD:
878 // any value is permissible
879 return true;
880
881 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400882 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400883 switch (param)
884 {
885 case GL_NONE:
886 case GL_COMPARE_REF_TO_TEXTURE:
887 return true;
888 default:
Geoff Langb1196682014-07-23 13:47:29 -0400889 context->recordError(Error(GL_INVALID_ENUM));
890 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400891 }
892 break;
893
894 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400895 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400896 switch (param)
897 {
898 case GL_LEQUAL:
899 case GL_GEQUAL:
900 case GL_LESS:
901 case GL_GREATER:
902 case GL_EQUAL:
903 case GL_NOTEQUAL:
904 case GL_ALWAYS:
905 case GL_NEVER:
906 return true;
907 default:
Geoff Langb1196682014-07-23 13:47:29 -0400908 context->recordError(Error(GL_INVALID_ENUM));
909 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 }
911 break;
912
913 case GL_TEXTURE_SWIZZLE_R:
914 case GL_TEXTURE_SWIZZLE_G:
915 case GL_TEXTURE_SWIZZLE_B:
916 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400917 switch (param)
918 {
919 case GL_RED:
920 case GL_GREEN:
921 case GL_BLUE:
922 case GL_ALPHA:
923 case GL_ZERO:
924 case GL_ONE:
925 return true;
926 default:
Geoff Langb1196682014-07-23 13:47:29 -0400927 context->recordError(Error(GL_INVALID_ENUM));
928 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400929 }
930 break;
931
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400932 case GL_TEXTURE_BASE_LEVEL:
933 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400934 if (param < 0)
935 {
Geoff Langb1196682014-07-23 13:47:29 -0400936 context->recordError(Error(GL_INVALID_VALUE));
937 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400938 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400939 return true;
940
941 default:
Geoff Langb1196682014-07-23 13:47:29 -0400942 context->recordError(Error(GL_INVALID_ENUM));
943 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400944 }
945}
946
Geoff Langb1196682014-07-23 13:47:29 -0400947bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400948{
949 switch (pname)
950 {
951 case GL_TEXTURE_MIN_FILTER:
952 case GL_TEXTURE_MAG_FILTER:
953 case GL_TEXTURE_WRAP_S:
954 case GL_TEXTURE_WRAP_T:
955 case GL_TEXTURE_WRAP_R:
956 case GL_TEXTURE_MIN_LOD:
957 case GL_TEXTURE_MAX_LOD:
958 case GL_TEXTURE_COMPARE_MODE:
959 case GL_TEXTURE_COMPARE_FUNC:
960 return true;
961
962 default:
Geoff Langb1196682014-07-23 13:47:29 -0400963 context->recordError(Error(GL_INVALID_ENUM));
964 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400965 }
966}
967
Jamie Madill26e91952014-03-05 15:01:27 -0500968bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
969 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
970{
Shannon Woods53a94a82014-06-24 15:20:36 -0400971 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400972 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500973
Geoff Lang748f74e2014-12-01 11:25:34 -0500974 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500975 {
Geoff Langb1196682014-07-23 13:47:29 -0400976 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
977 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500978 }
979
Jamie Madill48faf802014-11-06 15:27:22 -0500980 if (context->getState().getReadFramebuffer()->id() != 0 &&
981 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500982 {
Geoff Langb1196682014-07-23 13:47:29 -0400983 context->recordError(Error(GL_INVALID_OPERATION));
984 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500985 }
986
Geoff Langbce529e2014-12-01 12:48:41 -0500987 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
988 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400989 {
Geoff Langb1196682014-07-23 13:47:29 -0400990 context->recordError(Error(GL_INVALID_OPERATION));
991 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400992 }
993
Geoff Langbce529e2014-12-01 12:48:41 -0500994 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
995 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500996 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400997 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500998
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400999 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1000 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001001
1002 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1003 {
Geoff Langb1196682014-07-23 13:47:29 -04001004 context->recordError(Error(GL_INVALID_OPERATION));
1005 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001006 }
1007
Geoff Lang5d601382014-07-22 15:14:06 -04001008 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1009 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001010
Minmin Gongb8aee3b2015-01-27 14:42:36 -08001011 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -05001012 // sized query sanity check
1013 if (bufSize)
1014 {
1015 int requiredSize = outputPitch * height;
1016 if (requiredSize > *bufSize)
1017 {
Geoff Langb1196682014-07-23 13:47:29 -04001018 context->recordError(Error(GL_INVALID_OPERATION));
1019 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001020 }
1021 }
1022
1023 return true;
1024}
1025
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001026bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1027{
1028 if (!ValidQueryType(context, target))
1029 {
Geoff Langb1196682014-07-23 13:47:29 -04001030 context->recordError(Error(GL_INVALID_ENUM));
1031 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001032 }
1033
1034 if (id == 0)
1035 {
Geoff Langb1196682014-07-23 13:47:29 -04001036 context->recordError(Error(GL_INVALID_OPERATION));
1037 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001038 }
1039
1040 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1041 // of zero, if the active query object name for <target> is non-zero (for the
1042 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1043 // the active query for either target is non-zero), if <id> is the name of an
1044 // existing query object whose type does not match <target>, or if <id> is the
1045 // active query object name for any query type, the error INVALID_OPERATION is
1046 // generated.
1047
1048 // Ensure no other queries are active
1049 // NOTE: If other queries than occlusion are supported, we will need to check
1050 // separately that:
1051 // a) The query ID passed is not the current active query for any target/type
1052 // b) There are no active queries for the requested target (and in the case
1053 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1054 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001055 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001056 {
Geoff Langb1196682014-07-23 13:47:29 -04001057 context->recordError(Error(GL_INVALID_OPERATION));
1058 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001059 }
1060
1061 Query *queryObject = context->getQuery(id, true, target);
1062
1063 // check that name was obtained with glGenQueries
1064 if (!queryObject)
1065 {
Geoff Langb1196682014-07-23 13:47:29 -04001066 context->recordError(Error(GL_INVALID_OPERATION));
1067 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001068 }
1069
1070 // check for type mismatch
1071 if (queryObject->getType() != target)
1072 {
Geoff Langb1196682014-07-23 13:47:29 -04001073 context->recordError(Error(GL_INVALID_OPERATION));
1074 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001075 }
1076
1077 return true;
1078}
1079
Jamie Madill45c785d2014-05-13 14:09:34 -04001080bool ValidateEndQuery(gl::Context *context, GLenum target)
1081{
1082 if (!ValidQueryType(context, target))
1083 {
Geoff Langb1196682014-07-23 13:47:29 -04001084 context->recordError(Error(GL_INVALID_ENUM));
1085 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001086 }
1087
Shannon Woods53a94a82014-06-24 15:20:36 -04001088 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001089
1090 if (queryObject == NULL)
1091 {
Geoff Langb1196682014-07-23 13:47:29 -04001092 context->recordError(Error(GL_INVALID_OPERATION));
1093 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001094 }
1095
Jamie Madill45c785d2014-05-13 14:09:34 -04001096 return true;
1097}
1098
Jamie Madill892a6a42015-09-09 10:17:15 -04001099static bool ValidateUniformCommonBase(gl::Context *context,
1100 GLenum targetUniformType,
1101 GLint location,
1102 GLsizei count,
1103 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001104{
1105 if (count < 0)
1106 {
Geoff Langb1196682014-07-23 13:47:29 -04001107 context->recordError(Error(GL_INVALID_VALUE));
1108 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001109 }
1110
Geoff Lang7dd2e102014-11-10 15:19:26 -05001111 gl::Program *program = context->getState().getProgram();
1112 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001113 {
Geoff Langb1196682014-07-23 13:47:29 -04001114 context->recordError(Error(GL_INVALID_OPERATION));
1115 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001116 }
1117
1118 if (location == -1)
1119 {
1120 // Silently ignore the uniform command
1121 return false;
1122 }
1123
Geoff Lang7dd2e102014-11-10 15:19:26 -05001124 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001125 {
Geoff Langb1196682014-07-23 13:47:29 -04001126 context->recordError(Error(GL_INVALID_OPERATION));
1127 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001128 }
1129
Jamie Madill892a6a42015-09-09 10:17:15 -04001130 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001131
1132 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill892a6a42015-09-09 10:17:15 -04001133 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001134 {
Geoff Langb1196682014-07-23 13:47:29 -04001135 context->recordError(Error(GL_INVALID_OPERATION));
1136 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001137 }
1138
Jamie Madill892a6a42015-09-09 10:17:15 -04001139 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001140 return true;
1141}
1142
Jamie Madillaa981bd2014-05-20 10:55:55 -04001143bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1144{
1145 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001146 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001147 {
Geoff Langb1196682014-07-23 13:47:29 -04001148 context->recordError(Error(GL_INVALID_OPERATION));
1149 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001150 }
1151
Jamie Madill892a6a42015-09-09 10:17:15 -04001152 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001153 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1154 {
1155 return false;
1156 }
1157
Jamie Madillf2575982014-06-25 16:04:54 -04001158 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001159 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001160 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1161 {
Geoff Langb1196682014-07-23 13:47:29 -04001162 context->recordError(Error(GL_INVALID_OPERATION));
1163 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001164 }
1165
1166 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001167}
1168
1169bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1170 GLboolean transpose)
1171{
1172 // Check for ES3 uniform entry points
1173 int rows = VariableRowCount(matrixType);
1174 int cols = VariableColumnCount(matrixType);
1175 if (rows != cols && context->getClientVersion() < 3)
1176 {
Geoff Langb1196682014-07-23 13:47:29 -04001177 context->recordError(Error(GL_INVALID_OPERATION));
1178 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001179 }
1180
1181 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1182 {
Geoff Langb1196682014-07-23 13:47:29 -04001183 context->recordError(Error(GL_INVALID_VALUE));
1184 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001185 }
1186
Jamie Madill892a6a42015-09-09 10:17:15 -04001187 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001188 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1189 {
1190 return false;
1191 }
1192
1193 if (uniform->type != matrixType)
1194 {
Geoff Langb1196682014-07-23 13:47:29 -04001195 context->recordError(Error(GL_INVALID_OPERATION));
1196 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001197 }
1198
1199 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001200}
1201
Jamie Madill893ab082014-05-16 16:56:10 -04001202bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1203{
1204 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1205 {
Geoff Langb1196682014-07-23 13:47:29 -04001206 context->recordError(Error(GL_INVALID_ENUM));
1207 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001208 }
1209
Jamie Madill0af26e12015-03-05 19:54:33 -05001210 const Caps &caps = context->getCaps();
1211
Jamie Madill893ab082014-05-16 16:56:10 -04001212 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1213 {
1214 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1215
Jamie Madill0af26e12015-03-05 19:54:33 -05001216 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001217 {
Geoff Langb1196682014-07-23 13:47:29 -04001218 context->recordError(Error(GL_INVALID_OPERATION));
1219 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001220 }
1221 }
1222
1223 switch (pname)
1224 {
1225 case GL_TEXTURE_BINDING_2D:
1226 case GL_TEXTURE_BINDING_CUBE_MAP:
1227 case GL_TEXTURE_BINDING_3D:
1228 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001229 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001230 {
Geoff Langb1196682014-07-23 13:47:29 -04001231 context->recordError(Error(GL_INVALID_OPERATION));
1232 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001233 }
1234 break;
1235
1236 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1237 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1238 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001239 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001240 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001241 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001242 {
Geoff Langb1196682014-07-23 13:47:29 -04001243 context->recordError(Error(GL_INVALID_OPERATION));
1244 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001245 }
1246
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001247 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001248 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001249 {
Geoff Langb1196682014-07-23 13:47:29 -04001250 context->recordError(Error(GL_INVALID_OPERATION));
1251 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001252 }
1253 }
1254 break;
1255
1256 default:
1257 break;
1258 }
1259
1260 // pname is valid, but there are no parameters to return
1261 if (numParams == 0)
1262 {
1263 return false;
1264 }
1265
1266 return true;
1267}
1268
Geoff Lang831b1952015-05-05 11:02:27 -04001269bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001270 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1271 GLint border, GLenum *textureFormatOut)
1272{
1273
1274 if (!ValidTexture2DDestinationTarget(context, target))
1275 {
Geoff Langb1196682014-07-23 13:47:29 -04001276 context->recordError(Error(GL_INVALID_ENUM));
1277 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001278 }
1279
1280 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1281 {
Geoff Langb1196682014-07-23 13:47:29 -04001282 context->recordError(Error(GL_INVALID_VALUE));
1283 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001284 }
1285
1286 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1287 {
Geoff Langb1196682014-07-23 13:47:29 -04001288 context->recordError(Error(GL_INVALID_VALUE));
1289 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001290 }
1291
1292 if (border != 0)
1293 {
Geoff Langb1196682014-07-23 13:47:29 -04001294 context->recordError(Error(GL_INVALID_VALUE));
1295 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001296 }
1297
1298 if (!ValidMipLevel(context, target, level))
1299 {
Geoff Langb1196682014-07-23 13:47:29 -04001300 context->recordError(Error(GL_INVALID_VALUE));
1301 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001302 }
1303
Shannon Woods53a94a82014-06-24 15:20:36 -04001304 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001305 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001306 {
Geoff Langb1196682014-07-23 13:47:29 -04001307 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1308 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001309 }
1310
Jamie Madill48faf802014-11-06 15:27:22 -05001311 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001312 {
Geoff Langb1196682014-07-23 13:47:29 -04001313 context->recordError(Error(GL_INVALID_OPERATION));
1314 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001315 }
1316
Geoff Langaae65a42014-05-26 12:43:44 -04001317 const gl::Caps &caps = context->getCaps();
1318
Geoff Langaae65a42014-05-26 12:43:44 -04001319 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001320 switch (target)
1321 {
1322 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001323 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001324 break;
1325
1326 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1327 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1328 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1329 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1330 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1331 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001332 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001333 break;
1334
1335 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001336 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001337 break;
1338
1339 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001340 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001341 break;
1342
1343 default:
Geoff Langb1196682014-07-23 13:47:29 -04001344 context->recordError(Error(GL_INVALID_ENUM));
1345 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001346 }
1347
Geoff Lang691e58c2014-12-19 17:03:25 -05001348 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001349 if (!texture)
1350 {
Geoff Langb1196682014-07-23 13:47:29 -04001351 context->recordError(Error(GL_INVALID_OPERATION));
1352 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001353 }
1354
1355 if (texture->isImmutable() && !isSubImage)
1356 {
Geoff Langb1196682014-07-23 13:47:29 -04001357 context->recordError(Error(GL_INVALID_OPERATION));
1358 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001359 }
1360
Geoff Lang5d601382014-07-22 15:14:06 -04001361 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1362
1363 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001364 {
Geoff Langb1196682014-07-23 13:47:29 -04001365 context->recordError(Error(GL_INVALID_OPERATION));
1366 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001367 }
1368
Geoff Langa9be0dc2014-12-17 12:34:40 -05001369 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001371 context->recordError(Error(GL_INVALID_OPERATION));
1372 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001373 }
1374
1375 if (isSubImage)
1376 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001377 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1378 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1379 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001380 {
Geoff Langb1196682014-07-23 13:47:29 -04001381 context->recordError(Error(GL_INVALID_VALUE));
1382 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001383 }
1384 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001385 else
1386 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001387 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001388 {
Geoff Langb1196682014-07-23 13:47:29 -04001389 context->recordError(Error(GL_INVALID_VALUE));
1390 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001391 }
1392
Geoff Lang5d601382014-07-22 15:14:06 -04001393 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001394 {
Geoff Langb1196682014-07-23 13:47:29 -04001395 context->recordError(Error(GL_INVALID_ENUM));
1396 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001397 }
1398
1399 int maxLevelDimension = (maxDimension >> level);
1400 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1401 {
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_VALUE));
1403 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001404 }
1405 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001406
Geoff Langa9be0dc2014-12-17 12:34:40 -05001407 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001408 return true;
1409}
1410
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001411static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001412{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001413 switch (mode)
1414 {
1415 case GL_POINTS:
1416 case GL_LINES:
1417 case GL_LINE_LOOP:
1418 case GL_LINE_STRIP:
1419 case GL_TRIANGLES:
1420 case GL_TRIANGLE_STRIP:
1421 case GL_TRIANGLE_FAN:
1422 break;
1423 default:
Geoff Langb1196682014-07-23 13:47:29 -04001424 context->recordError(Error(GL_INVALID_ENUM));
1425 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001426 }
1427
Jamie Madill250d33f2014-06-06 17:09:03 -04001428 if (count < 0)
1429 {
Geoff Langb1196682014-07-23 13:47:29 -04001430 context->recordError(Error(GL_INVALID_VALUE));
1431 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001432 }
1433
Geoff Langb1196682014-07-23 13:47:29 -04001434 const State &state = context->getState();
1435
Jamie Madill250d33f2014-06-06 17:09:03 -04001436 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001437 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001438 {
Geoff Langb1196682014-07-23 13:47:29 -04001439 context->recordError(Error(GL_INVALID_OPERATION));
1440 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001441 }
1442
Geoff Lang3a86ad32015-09-01 11:47:05 -04001443 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001444 {
Geoff Lang3a86ad32015-09-01 11:47:05 -04001445 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
1446 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1447 state.getStencilRef() != state.getStencilBackRef() ||
1448 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1449 {
1450 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1451 // Section 6.10 of the WebGL 1.0 spec
1452 ERR(
1453 "This ANGLE implementation does not support separate front/back stencil "
1454 "writemasks, reference values, or stencil mask values.");
1455 context->recordError(Error(GL_INVALID_OPERATION));
1456 return false;
1457 }
Jamie Madillac528012014-06-20 13:21:23 -04001458 }
1459
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001460 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001461 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001462 {
Geoff Langb1196682014-07-23 13:47:29 -04001463 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1464 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001465 }
1466
Geoff Lang7dd2e102014-11-10 15:19:26 -05001467 gl::Program *program = state.getProgram();
1468 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001469 {
Geoff Langb1196682014-07-23 13:47:29 -04001470 context->recordError(Error(GL_INVALID_OPERATION));
1471 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001472 }
1473
Geoff Lang7dd2e102014-11-10 15:19:26 -05001474 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001475 {
Geoff Langb1196682014-07-23 13:47:29 -04001476 context->recordError(Error(GL_INVALID_OPERATION));
1477 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001478 }
1479
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001480 // Uniform buffer validation
1481 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1482 {
Jamie Madill892a6a42015-09-09 10:17:15 -04001483 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001484 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
1485 const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
1486
1487 if (!uniformBuffer)
1488 {
1489 // undefined behaviour
1490 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1491 return false;
1492 }
1493
1494 size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
1495
1496 if (uniformBufferSize == 0)
1497 {
1498 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001499 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001500 }
1501
Jamie Madill892a6a42015-09-09 10:17:15 -04001502 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001503 {
1504 // undefined behaviour
1505 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1506 return false;
1507 }
1508 }
1509
Jamie Madill250d33f2014-06-06 17:09:03 -04001510 // No-op if zero count
1511 return (count > 0);
1512}
1513
Geoff Langb1196682014-07-23 13:47:29 -04001514bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001515{
Jamie Madillfd716582014-06-06 17:09:04 -04001516 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001517 {
Geoff Langb1196682014-07-23 13:47:29 -04001518 context->recordError(Error(GL_INVALID_VALUE));
1519 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001520 }
1521
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001522 const State &state = context->getState();
1523 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001524 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1525 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001526 {
1527 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1528 // that does not match the current transform feedback object's draw mode (if transform feedback
1529 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001530 context->recordError(Error(GL_INVALID_OPERATION));
1531 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001532 }
1533
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001534 if (!ValidateDrawBase(context, mode, count, primcount))
1535 {
1536 return false;
1537 }
1538
1539 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001540 {
1541 return false;
1542 }
1543
1544 return true;
1545}
1546
Geoff Langb1196682014-07-23 13:47:29 -04001547bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001548{
1549 if (primcount < 0)
1550 {
Geoff Langb1196682014-07-23 13:47:29 -04001551 context->recordError(Error(GL_INVALID_VALUE));
1552 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001553 }
1554
Jamie Madill2b976812014-08-25 15:47:49 -04001555 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001556 {
1557 return false;
1558 }
1559
1560 // No-op if zero primitive count
1561 return (primcount > 0);
1562}
1563
Geoff Lang87a93302014-09-16 13:29:43 -04001564static bool ValidateDrawInstancedANGLE(Context *context)
1565{
1566 // Verify there is at least one active attribute with a divisor of zero
1567 const gl::State& state = context->getState();
1568
Geoff Lang7dd2e102014-11-10 15:19:26 -05001569 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001570
1571 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001572 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001573 {
1574 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001575 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001576 {
1577 return true;
1578 }
1579 }
1580
1581 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1582 "has a divisor of zero."));
1583 return false;
1584}
1585
1586bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1587{
1588 if (!ValidateDrawInstancedANGLE(context))
1589 {
1590 return false;
1591 }
1592
1593 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1594}
1595
Geoff Langb1196682014-07-23 13:47:29 -04001596bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001597 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001598{
Jamie Madill250d33f2014-06-06 17:09:03 -04001599 switch (type)
1600 {
1601 case GL_UNSIGNED_BYTE:
1602 case GL_UNSIGNED_SHORT:
1603 break;
1604 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001605 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001606 {
Geoff Langb1196682014-07-23 13:47:29 -04001607 context->recordError(Error(GL_INVALID_ENUM));
1608 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001609 }
1610 break;
1611 default:
Geoff Langb1196682014-07-23 13:47:29 -04001612 context->recordError(Error(GL_INVALID_ENUM));
1613 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001614 }
1615
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001616 const State &state = context->getState();
1617
1618 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001619 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001620 {
1621 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1622 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001623 context->recordError(Error(GL_INVALID_OPERATION));
1624 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001625 }
1626
1627 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001628 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001629 {
Geoff Langb1196682014-07-23 13:47:29 -04001630 context->recordError(Error(GL_INVALID_OPERATION));
1631 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001632 }
1633
Jamie Madill2b976812014-08-25 15:47:49 -04001634 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001635 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001636 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001637 {
Geoff Langb1196682014-07-23 13:47:29 -04001638 context->recordError(Error(GL_INVALID_OPERATION));
1639 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001640 }
1641
Jamie Madillae3000b2014-08-25 15:47:51 -04001642 if (elementArrayBuffer)
1643 {
1644 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1645
1646 GLint64 offset = reinterpret_cast<GLint64>(indices);
1647 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1648
1649 // check for integer overflows
1650 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1651 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1652 {
Geoff Langb1196682014-07-23 13:47:29 -04001653 context->recordError(Error(GL_OUT_OF_MEMORY));
1654 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001655 }
1656
1657 // Check for reading past the end of the bound buffer object
1658 if (byteCount > elementArrayBuffer->getSize())
1659 {
Geoff Langb1196682014-07-23 13:47:29 -04001660 context->recordError(Error(GL_INVALID_OPERATION));
1661 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001662 }
1663 }
1664 else if (!indices)
1665 {
1666 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001667 context->recordError(Error(GL_INVALID_OPERATION));
1668 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001669 }
1670
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001671 if (!ValidateDrawBase(context, mode, count, primcount))
1672 {
1673 return false;
1674 }
1675
Jamie Madill2b976812014-08-25 15:47:49 -04001676 // Use max index to validate if our vertex buffers are large enough for the pull.
1677 // TODO: offer fast path, with disabled index validation.
1678 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1679 if (elementArrayBuffer)
1680 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001681 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001682 Error error = elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count, indexRangeOut);
1683 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001684 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001685 context->recordError(error);
1686 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001687 }
1688 }
1689 else
1690 {
Geoff Lang831b1952015-05-05 11:02:27 -04001691 *indexRangeOut = ComputeIndexRange(type, indices, count);
Jamie Madill2b976812014-08-25 15:47:49 -04001692 }
1693
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001694 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001695 {
1696 return false;
1697 }
1698
1699 return true;
1700}
1701
Geoff Langb1196682014-07-23 13:47:29 -04001702bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001703 GLenum mode, GLsizei count, GLenum type,
1704 const GLvoid *indices, GLsizei primcount,
Geoff Lang831b1952015-05-05 11:02:27 -04001705 RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001706{
1707 if (primcount < 0)
1708 {
Geoff Langb1196682014-07-23 13:47:29 -04001709 context->recordError(Error(GL_INVALID_VALUE));
1710 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001711 }
1712
Jamie Madill2b976812014-08-25 15:47:49 -04001713 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001714 {
1715 return false;
1716 }
1717
1718 // No-op zero primitive count
1719 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001720}
1721
Geoff Lang87a93302014-09-16 13:29:43 -04001722bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001723 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001724{
1725 if (!ValidateDrawInstancedANGLE(context))
1726 {
1727 return false;
1728 }
1729
1730 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1731}
1732
Geoff Langb1196682014-07-23 13:47:29 -04001733bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001734 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001735{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001736 if (!ValidFramebufferTarget(target))
1737 {
Geoff Langb1196682014-07-23 13:47:29 -04001738 context->recordError(Error(GL_INVALID_ENUM));
1739 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001740 }
1741
1742 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001743 {
1744 return false;
1745 }
1746
Jamie Madill55ec3b12014-07-03 10:38:57 -04001747 if (texture != 0)
1748 {
1749 gl::Texture *tex = context->getTexture(texture);
1750
1751 if (tex == NULL)
1752 {
Geoff Langb1196682014-07-23 13:47:29 -04001753 context->recordError(Error(GL_INVALID_OPERATION));
1754 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001755 }
1756
1757 if (level < 0)
1758 {
Geoff Langb1196682014-07-23 13:47:29 -04001759 context->recordError(Error(GL_INVALID_VALUE));
1760 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001761 }
1762 }
1763
Shannon Woods53a94a82014-06-24 15:20:36 -04001764 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001765 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001766
Jamie Madill84115c92015-04-23 15:00:07 -04001767 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001768 {
Jamie Madill84115c92015-04-23 15:00:07 -04001769 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001770 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001771 }
1772
1773 return true;
1774}
1775
Geoff Langb1196682014-07-23 13:47:29 -04001776bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001777 GLenum textarget, GLuint texture, GLint level)
1778{
Geoff Lang95663912015-04-02 15:54:45 -04001779 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1780 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001781 {
Geoff Langb1196682014-07-23 13:47:29 -04001782 context->recordError(Error(GL_INVALID_VALUE));
1783 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001784 }
1785
1786 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001787 {
1788 return false;
1789 }
1790
Jamie Madill55ec3b12014-07-03 10:38:57 -04001791 if (texture != 0)
1792 {
1793 gl::Texture *tex = context->getTexture(texture);
1794 ASSERT(tex);
1795
Jamie Madill2a6564e2014-07-11 09:53:19 -04001796 const gl::Caps &caps = context->getCaps();
1797
Jamie Madill55ec3b12014-07-03 10:38:57 -04001798 switch (textarget)
1799 {
1800 case GL_TEXTURE_2D:
1801 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001802 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001803 {
Geoff Langb1196682014-07-23 13:47:29 -04001804 context->recordError(Error(GL_INVALID_VALUE));
1805 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001806 }
1807 if (tex->getTarget() != GL_TEXTURE_2D)
1808 {
Geoff Langb1196682014-07-23 13:47:29 -04001809 context->recordError(Error(GL_INVALID_OPERATION));
1810 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001811 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001812 }
1813 break;
1814
1815 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1816 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1817 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1818 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1819 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1820 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1821 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001822 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001823 {
Geoff Langb1196682014-07-23 13:47:29 -04001824 context->recordError(Error(GL_INVALID_VALUE));
1825 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001826 }
1827 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1828 {
Geoff Langb1196682014-07-23 13:47:29 -04001829 context->recordError(Error(GL_INVALID_OPERATION));
1830 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001831 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001832 }
1833 break;
1834
1835 default:
Geoff Langb1196682014-07-23 13:47:29 -04001836 context->recordError(Error(GL_INVALID_ENUM));
1837 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001838 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001839
1840 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1841 if (internalFormatInfo.compressed)
1842 {
1843 context->recordError(Error(GL_INVALID_OPERATION));
1844 return false;
1845 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001846 }
1847
Jamie Madill570f7c82014-07-03 10:38:54 -04001848 return true;
1849}
1850
Geoff Langb1196682014-07-23 13:47:29 -04001851bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001852{
1853 if (program == 0)
1854 {
Geoff Langb1196682014-07-23 13:47:29 -04001855 context->recordError(Error(GL_INVALID_VALUE));
1856 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001857 }
1858
Shannon Woods4de4fd62014-11-07 16:22:02 -05001859 if (!ValidProgram(context, program))
1860 {
1861 return false;
1862 }
1863
Jamie Madill0063c512014-08-25 15:47:53 -04001864 gl::Program *programObject = context->getProgram(program);
1865
1866 if (!programObject || !programObject->isLinked())
1867 {
Geoff Langb1196682014-07-23 13:47:29 -04001868 context->recordError(Error(GL_INVALID_OPERATION));
1869 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001870 }
1871
Geoff Lang7dd2e102014-11-10 15:19:26 -05001872 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001873 {
Geoff Langb1196682014-07-23 13:47:29 -04001874 context->recordError(Error(GL_INVALID_OPERATION));
1875 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001876 }
1877
Jamie Madill0063c512014-08-25 15:47:53 -04001878 return true;
1879}
1880
Geoff Langb1196682014-07-23 13:47:29 -04001881bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001882{
1883 return ValidateGetUniformBase(context, program, location);
1884}
1885
Geoff Langb1196682014-07-23 13:47:29 -04001886bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001887{
Jamie Madill78f41802014-08-25 15:47:55 -04001888 return ValidateGetUniformBase(context, program, location);
1889}
1890
Geoff Langb1196682014-07-23 13:47:29 -04001891static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001892{
1893 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001894 {
Jamie Madill78f41802014-08-25 15:47:55 -04001895 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001896 }
1897
Jamie Madilla502c742014-08-28 17:19:13 -04001898 gl::Program *programObject = context->getProgram(program);
1899 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001900
Jamie Madill78f41802014-08-25 15:47:55 -04001901 // sized queries -- ensure the provided buffer is large enough
Jamie Madill892a6a42015-09-09 10:17:15 -04001902 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
1903 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04001904 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001905 {
Geoff Langb1196682014-07-23 13:47:29 -04001906 context->recordError(Error(GL_INVALID_OPERATION));
1907 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001908 }
1909
1910 return true;
1911}
1912
Geoff Langb1196682014-07-23 13:47:29 -04001913bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001914{
Jamie Madill78f41802014-08-25 15:47:55 -04001915 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001916}
1917
Geoff Langb1196682014-07-23 13:47:29 -04001918bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001919{
Jamie Madill78f41802014-08-25 15:47:55 -04001920 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001921}
1922
Austin Kinross08332632015-05-05 13:35:47 -07001923bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
1924 const GLenum *attachments, bool defaultFramebuffer)
1925{
1926 if (numAttachments < 0)
1927 {
1928 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
1929 return false;
1930 }
1931
1932 for (GLsizei i = 0; i < numAttachments; ++i)
1933 {
1934 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
1935 {
1936 if (defaultFramebuffer)
1937 {
1938 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1939 return false;
1940 }
1941
1942 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
1943 {
1944 context->recordError(Error(GL_INVALID_OPERATION,
1945 "Requested color attachment is greater than the maximum supported color attachments"));
1946 return false;
1947 }
1948 }
1949 else
1950 {
1951 switch (attachments[i])
1952 {
1953 case GL_DEPTH_ATTACHMENT:
1954 case GL_STENCIL_ATTACHMENT:
1955 case GL_DEPTH_STENCIL_ATTACHMENT:
1956 if (defaultFramebuffer)
1957 {
1958 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1959 return false;
1960 }
1961 break;
1962 case GL_COLOR:
1963 case GL_DEPTH:
1964 case GL_STENCIL:
1965 if (!defaultFramebuffer)
1966 {
1967 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
1968 return false;
1969 }
1970 break;
1971 default:
1972 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
1973 return false;
1974 }
1975 }
1976 }
1977
1978 return true;
1979}
1980
Austin Kinross6ee1e782015-05-29 17:05:37 -07001981bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
1982{
1983 // Note that debug marker calls must not set error state
1984
1985 if (length < 0)
1986 {
1987 return false;
1988 }
1989
1990 if (marker == nullptr)
1991 {
1992 return false;
1993 }
1994
1995 return true;
1996}
1997
1998bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
1999{
2000 // Note that debug marker calls must not set error state
2001
2002 if (length < 0)
2003 {
2004 return false;
2005 }
2006
2007 if (length > 0 && marker == nullptr)
2008 {
2009 return false;
2010 }
2011
2012 return true;
2013}
2014
Geoff Langdcab33b2015-07-21 13:03:16 -04002015bool ValidateEGLImageTargetTexture2DOES(Context *context,
2016 egl::Display *display,
2017 GLenum target,
2018 egl::Image *image)
2019{
Geoff Langa8406172015-07-21 16:53:39 -04002020 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2021 {
2022 context->recordError(Error(GL_INVALID_OPERATION));
2023 return false;
2024 }
2025
2026 switch (target)
2027 {
2028 case GL_TEXTURE_2D:
2029 break;
2030
2031 default:
2032 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2033 return false;
2034 }
2035
2036 if (!display->isValidImage(image))
2037 {
2038 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2039 return false;
2040 }
2041
2042 if (image->getSamples() > 0)
2043 {
2044 context->recordError(Error(GL_INVALID_OPERATION,
2045 "cannot create a 2D texture from a multisampled EGL image."));
2046 return false;
2047 }
2048
2049 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2050 if (!textureCaps.texturable)
2051 {
2052 context->recordError(Error(GL_INVALID_OPERATION,
2053 "EGL image internal format is not supported as a texture."));
2054 return false;
2055 }
2056
Geoff Langdcab33b2015-07-21 13:03:16 -04002057 return true;
2058}
2059
2060bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2061 egl::Display *display,
2062 GLenum target,
2063 egl::Image *image)
2064{
Geoff Langa8406172015-07-21 16:53:39 -04002065 if (!context->getExtensions().eglImage)
2066 {
2067 context->recordError(Error(GL_INVALID_OPERATION));
2068 return false;
2069 }
2070
2071 switch (target)
2072 {
2073 case GL_RENDERBUFFER:
2074 break;
2075
2076 default:
2077 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2078 return false;
2079 }
2080
2081 if (!display->isValidImage(image))
2082 {
2083 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2084 return false;
2085 }
2086
2087 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2088 if (!textureCaps.renderable)
2089 {
2090 context->recordError(Error(
2091 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2092 return false;
2093 }
2094
Geoff Langdcab33b2015-07-21 13:03:16 -04002095 return true;
2096}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002097}