blob: 60d1a9fd47a55cffa015fe473919416e69507618 [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();
39 const int *semanticIndexes = program->getSemanticIndexes();
40 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
41 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
42 {
43 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
44 bool attribActive = (semanticIndexes[attributeIndex] != -1);
45 if (attribActive && attrib.enabled)
46 {
47 gl::Buffer *buffer = attrib.buffer.get();
48
49 if (buffer)
50 {
51 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
52 GLint64 maxVertexElement = 0;
53
54 if (attrib.divisor > 0)
55 {
56 maxVertexElement =
57 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
58 }
59 else
60 {
61 maxVertexElement = static_cast<GLint64>(maxVertex);
62 }
63
64 // If we're drawing zero vertices, we have enough data.
65 if (maxVertexElement > 0)
66 {
67 // Note: Last vertex element does not take the full stride!
68 GLint64 attribSize =
69 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
70 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
71
72 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
73 // We can return INVALID_OPERATION if our vertex attribute does not have
74 // enough backing data.
75 if (attribDataSize > buffer->getSize())
76 {
77 context->recordError(Error(GL_INVALID_OPERATION));
78 return false;
79 }
80 }
81 }
82 else if (attrib.pointer == NULL)
83 {
84 // This is an application error that would normally result in a crash,
85 // but we catch it and return an error
86 context->recordError(Error(
87 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
88 return false;
89 }
90 }
91 }
92
93 return true;
94}
95
96} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040097
Geoff Lang0550d032014-01-30 11:29:07 -050098bool ValidCap(const Context *context, GLenum cap)
99{
100 switch (cap)
101 {
102 case GL_CULL_FACE:
103 case GL_POLYGON_OFFSET_FILL:
104 case GL_SAMPLE_ALPHA_TO_COVERAGE:
105 case GL_SAMPLE_COVERAGE:
106 case GL_SCISSOR_TEST:
107 case GL_STENCIL_TEST:
108 case GL_DEPTH_TEST:
109 case GL_BLEND:
110 case GL_DITHER:
111 return true;
112 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
113 case GL_RASTERIZER_DISCARD:
114 return (context->getClientVersion() >= 3);
115 default:
116 return false;
117 }
118}
119
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500120bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121{
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400123 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500124 case GL_TEXTURE_2D:
125 case GL_TEXTURE_CUBE_MAP:
126 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400127
Jamie Madilld7460c72014-01-21 16:38:14 -0500128 case GL_TEXTURE_3D:
129 case GL_TEXTURE_2D_ARRAY:
130 return (context->getClientVersion() >= 3);
131
132 default:
133 return false;
134 }
Jamie Madill35d15012013-10-07 10:46:37 -0400135}
136
Shannon Woods4dfed832014-03-17 20:03:39 -0400137// This function differs from ValidTextureTarget in that the target must be
138// usable as the destination of a 2D operation-- so a cube face is valid, but
139// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400140// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400141bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
142{
143 switch (target)
144 {
145 case GL_TEXTURE_2D:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
150 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
151 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
152 return true;
153 case GL_TEXTURE_2D_ARRAY:
154 case GL_TEXTURE_3D:
155 return (context->getClientVersion() >= 3);
156 default:
157 return false;
158 }
159}
160
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500161bool ValidFramebufferTarget(GLenum target)
162{
Geoff Langd4475812015-03-18 10:53:05 -0400163 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
164 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500165
166 switch (target)
167 {
168 case GL_FRAMEBUFFER: return true;
169 case GL_READ_FRAMEBUFFER: return true;
170 case GL_DRAW_FRAMEBUFFER: return true;
171 default: return false;
172 }
173}
174
Jamie Madill8c96d582014-03-05 15:01:23 -0500175bool ValidBufferTarget(const Context *context, GLenum target)
176{
177 switch (target)
178 {
179 case GL_ARRAY_BUFFER:
180 case GL_ELEMENT_ARRAY_BUFFER:
181 return true;
182
Jamie Madill8c96d582014-03-05 15:01:23 -0500183 case GL_PIXEL_PACK_BUFFER:
184 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400185 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400186
Shannon Woodsb3801742014-03-27 14:59:19 -0400187 case GL_COPY_READ_BUFFER:
188 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500189 case GL_TRANSFORM_FEEDBACK_BUFFER:
190 case GL_UNIFORM_BUFFER:
191 return (context->getClientVersion() >= 3);
192
193 default:
194 return false;
195 }
196}
197
Jamie Madill70656a62014-03-05 15:01:26 -0500198bool ValidBufferParameter(const Context *context, GLenum pname)
199{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400200 const Extensions &extensions = context->getExtensions();
201
Jamie Madill70656a62014-03-05 15:01:26 -0500202 switch (pname)
203 {
204 case GL_BUFFER_USAGE:
205 case GL_BUFFER_SIZE:
206 return true;
207
Geoff Langcc6f55d2015-03-20 13:01:02 -0400208 case GL_BUFFER_ACCESS_OES:
209 return extensions.mapBuffer;
210
211 case GL_BUFFER_MAPPED:
212 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
213 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
214
Jamie Madill70656a62014-03-05 15:01:26 -0500215 // GL_BUFFER_MAP_POINTER is a special case, and may only be
216 // queried with GetBufferPointerv
217 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500218 case GL_BUFFER_MAP_OFFSET:
219 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400220 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500221
222 default:
223 return false;
224 }
225}
226
Jamie Madill8c96d582014-03-05 15:01:23 -0500227bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400228{
Geoff Langaae65a42014-05-26 12:43:44 -0400229 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400230 switch (target)
231 {
Geoff Langaae65a42014-05-26 12:43:44 -0400232 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400233 case GL_TEXTURE_CUBE_MAP:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
238 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400239 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
240 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
241 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400242 default: UNREACHABLE();
243 }
244
Geoff Langaae65a42014-05-26 12:43:44 -0400245 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400246}
247
Geoff Langb1196682014-07-23 13:47:29 -0400248bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400249 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400250{
251 if (level < 0 || width < 0 || height < 0 || depth < 0)
252 {
253 return false;
254 }
255
Geoff Langc0b9ef42014-07-02 10:02:37 -0400256 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400257 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400258 {
259 return false;
260 }
261
262 if (!ValidMipLevel(context, target, level))
263 {
264 return false;
265 }
266
267 return true;
268}
269
Geoff Langb1196682014-07-23 13:47:29 -0400270bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400271{
Geoff Lang5d601382014-07-22 15:14:06 -0400272 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
273 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400274 {
275 return false;
276 }
277
Geoff Lang5d601382014-07-22 15:14:06 -0400278 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
279 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400280 {
281 return false;
282 }
283
284 return true;
285}
286
Geoff Lang37dde692014-01-31 16:34:54 -0500287bool ValidQueryType(const Context *context, GLenum queryType)
288{
Geoff Langd4475812015-03-18 10:53:05 -0400289 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
290 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 -0500291
292 switch (queryType)
293 {
294 case GL_ANY_SAMPLES_PASSED:
295 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
296 return true;
297 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
298 return (context->getClientVersion() >= 3);
299 default:
300 return false;
301 }
302}
303
Geoff Langb1196682014-07-23 13:47:29 -0400304bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500305{
306 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
307 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
308 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
309
310 if (context->getProgram(id) != NULL)
311 {
312 return true;
313 }
314 else if (context->getShader(id) != NULL)
315 {
316 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400317 context->recordError(Error(GL_INVALID_OPERATION));
318 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500319 }
320 else
321 {
322 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400323 context->recordError(Error(GL_INVALID_VALUE));
324 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500325 }
326}
327
Geoff Langb1196682014-07-23 13:47:29 -0400328bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400329{
330 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
331 {
332 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
333
Geoff Langaae65a42014-05-26 12:43:44 -0400334 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400335 {
Geoff Langb1196682014-07-23 13:47:29 -0400336 context->recordError(Error(GL_INVALID_VALUE));
337 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400338 }
339 }
340 else
341 {
342 switch (attachment)
343 {
344 case GL_DEPTH_ATTACHMENT:
345 case GL_STENCIL_ATTACHMENT:
346 break;
347
348 case GL_DEPTH_STENCIL_ATTACHMENT:
349 if (context->getClientVersion() < 3)
350 {
Geoff Langb1196682014-07-23 13:47:29 -0400351 context->recordError(Error(GL_INVALID_ENUM));
352 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400353 }
354 break;
355
356 default:
Geoff Langb1196682014-07-23 13:47:29 -0400357 context->recordError(Error(GL_INVALID_ENUM));
358 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400359 }
360 }
361
362 return true;
363}
364
Corentin Walleze0902642014-11-04 12:32:15 -0800365bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
366 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400367{
368 switch (target)
369 {
370 case GL_RENDERBUFFER:
371 break;
372 default:
Geoff Langb1196682014-07-23 13:47:29 -0400373 context->recordError(Error(GL_INVALID_ENUM));
374 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400375 }
376
377 if (width < 0 || height < 0 || samples < 0)
378 {
Geoff Langb1196682014-07-23 13:47:29 -0400379 context->recordError(Error(GL_INVALID_VALUE));
380 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400381 }
382
Geoff Langd87878e2014-09-19 15:42:59 -0400383 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
384 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400385 {
Geoff Langb1196682014-07-23 13:47:29 -0400386 context->recordError(Error(GL_INVALID_ENUM));
387 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400388 }
389
390 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
391 // 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 -0800392 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400393 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400394 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400395 {
Geoff Langb1196682014-07-23 13:47:29 -0400396 context->recordError(Error(GL_INVALID_ENUM));
397 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400398 }
399
Geoff Langaae65a42014-05-26 12:43:44 -0400400 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400401 {
Geoff Langb1196682014-07-23 13:47:29 -0400402 context->recordError(Error(GL_INVALID_VALUE));
403 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400404 }
405
Shannon Woods53a94a82014-06-24 15:20:36 -0400406 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400407 if (handle == 0)
408 {
Geoff Langb1196682014-07-23 13:47:29 -0400409 context->recordError(Error(GL_INVALID_OPERATION));
410 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400411 }
412
413 return true;
414}
415
Corentin Walleze0902642014-11-04 12:32:15 -0800416bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
417 GLenum internalformat, GLsizei width, GLsizei height)
418{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800419 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800420
421 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400422 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800423 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400424 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800425 {
426 context->recordError(Error(GL_INVALID_VALUE));
427 return false;
428 }
429
430 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
431 // the specified storage. This is different than ES 3.0 in which a sample number higher
432 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800433 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
434 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800435 {
Geoff Langa4903b72015-03-02 16:02:48 -0800436 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
437 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
438 {
439 context->recordError(Error(GL_OUT_OF_MEMORY));
440 return false;
441 }
Corentin Walleze0902642014-11-04 12:32:15 -0800442 }
443
444 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
445}
446
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500447bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
448 GLenum renderbuffertarget, GLuint renderbuffer)
449{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400450 if (!ValidFramebufferTarget(target))
451 {
Geoff Langb1196682014-07-23 13:47:29 -0400452 context->recordError(Error(GL_INVALID_ENUM));
453 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400454 }
455
Shannon Woods53a94a82014-06-24 15:20:36 -0400456 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500457
Jamie Madill84115c92015-04-23 15:00:07 -0400458 ASSERT(framebuffer);
459 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500460 {
Jamie Madill84115c92015-04-23 15:00:07 -0400461 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400462 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500463 }
464
Jamie Madillb4472272014-07-03 10:38:55 -0400465 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500466 {
Jamie Madillb4472272014-07-03 10:38:55 -0400467 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500468 }
469
Jamie Madillab9d82c2014-01-21 16:38:14 -0500470 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
471 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
472 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
473 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
474 if (renderbuffer != 0)
475 {
476 if (!context->getRenderbuffer(renderbuffer))
477 {
Geoff Langb1196682014-07-23 13:47:29 -0400478 context->recordError(Error(GL_INVALID_OPERATION));
479 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500480 }
481 }
482
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500483 return true;
484}
485
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400486static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400487 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
488 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
489{
490 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
491 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
492 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
493 {
494 return true;
495 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400496 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400497 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400498 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400499
Shannon Woods53a94a82014-06-24 15:20:36 -0400500 return scissor.x > 0 || scissor.y > 0 ||
501 scissor.width < writeBuffer->getWidth() ||
502 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400503 }
504 else
505 {
506 return false;
507 }
508}
509
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400510bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
512 GLenum filter, bool fromAngleExtension)
513{
514 switch (filter)
515 {
516 case GL_NEAREST:
517 break;
518 case GL_LINEAR:
519 if (fromAngleExtension)
520 {
Geoff Langb1196682014-07-23 13:47:29 -0400521 context->recordError(Error(GL_INVALID_ENUM));
522 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400523 }
524 break;
525 default:
Geoff Langb1196682014-07-23 13:47:29 -0400526 context->recordError(Error(GL_INVALID_ENUM));
527 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400528 }
529
530 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
531 {
Geoff Langb1196682014-07-23 13:47:29 -0400532 context->recordError(Error(GL_INVALID_VALUE));
533 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400534 }
535
536 if (mask == 0)
537 {
538 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
539 // buffers are copied.
540 return false;
541 }
542
543 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
544 {
545 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400546 context->recordError(Error(GL_INVALID_OPERATION));
547 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400548 }
549
550 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
551 // color buffer, leaving only nearest being unfiltered from above
552 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
553 {
Geoff Langb1196682014-07-23 13:47:29 -0400554 context->recordError(Error(GL_INVALID_OPERATION));
555 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400556 }
557
Shannon Woods53a94a82014-06-24 15:20:36 -0400558 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400559 {
560 if (fromAngleExtension)
561 {
562 ERR("Blits with the same source and destination framebuffer are not supported by this "
563 "implementation.");
564 }
Geoff Langb1196682014-07-23 13:47:29 -0400565 context->recordError(Error(GL_INVALID_OPERATION));
566 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 }
568
Jamie Madille3ef7152015-04-28 16:55:17 +0000569 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
570 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500571
572 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400573 {
Geoff Langb1196682014-07-23 13:47:29 -0400574 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
575 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400576 }
577
Geoff Lang748f74e2014-12-01 11:25:34 -0500578 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500579 {
580 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
581 return false;
582 }
583
Geoff Lang748f74e2014-12-01 11:25:34 -0500584 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500585 {
586 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
587 return false;
588 }
589
590 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400591 {
Geoff Langb1196682014-07-23 13:47:29 -0400592 context->recordError(Error(GL_INVALID_OPERATION));
593 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400594 }
595
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
597
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400598 if (mask & GL_COLOR_BUFFER_BIT)
599 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400600 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
601 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400602
603 if (readColorBuffer && drawColorBuffer)
604 {
Geoff Langd8a22582014-12-17 15:28:23 -0500605 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400606 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400607
Jamie Madill0af26e12015-03-05 19:54:33 -0500608 for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400609 {
610 if (drawFramebuffer->isEnabledColorAttachment(i))
611 {
Geoff Langd8a22582014-12-17 15:28:23 -0500612 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400613 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400614
Geoff Langb2f3d052013-08-13 12:49:27 -0400615 // The GL ES 3.0.2 spec (pg 193) states that:
616 // 1) If the read buffer is fixed point format, the draw buffer must be as well
617 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
618 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400619 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
620 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400621 {
Geoff Langb1196682014-07-23 13:47:29 -0400622 context->recordError(Error(GL_INVALID_OPERATION));
623 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 }
625
Geoff Lang5d601382014-07-22 15:14:06 -0400626 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627 {
Geoff Langb1196682014-07-23 13:47:29 -0400628 context->recordError(Error(GL_INVALID_OPERATION));
629 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 }
631
Geoff Lang5d601382014-07-22 15:14:06 -0400632 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 {
Geoff Langb1196682014-07-23 13:47:29 -0400634 context->recordError(Error(GL_INVALID_OPERATION));
635 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636 }
637
Geoff Langb2f3d052013-08-13 12:49:27 -0400638 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 {
Geoff Langb1196682014-07-23 13:47:29 -0400640 context->recordError(Error(GL_INVALID_OPERATION));
641 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400642 }
643 }
644 }
645
Geoff Lang5d601382014-07-22 15:14:06 -0400646 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400647 {
Geoff Langb1196682014-07-23 13:47:29 -0400648 context->recordError(Error(GL_INVALID_OPERATION));
649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 }
651
652 if (fromAngleExtension)
653 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400654 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500655 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400656 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500657 readColorAttachment->type() != GL_RENDERBUFFER &&
658 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 {
Geoff Langb1196682014-07-23 13:47:29 -0400660 context->recordError(Error(GL_INVALID_OPERATION));
661 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400662 }
663
Jamie Madill0af26e12015-03-05 19:54:33 -0500664 for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 {
666 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
667 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000668 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400669 ASSERT(attachment);
670
Jamie Madill8cf4a392015-04-02 11:36:04 -0400671 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500672 attachment->type() != GL_RENDERBUFFER &&
673 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
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
Jamie Madillf8f18f02014-10-02 10:44:17 -0400679 // Return an error if the destination formats do not match
680 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400681 {
Geoff Langb1196682014-07-23 13:47:29 -0400682 context->recordError(Error(GL_INVALID_OPERATION));
683 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684 }
685 }
686 }
Jamie Madill48faf802014-11-06 15:27:22 -0500687
688 int readSamples = readFramebuffer->getSamples(context->getData());
689
690 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
691 srcX0, srcY0, srcX1, srcY1,
692 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 {
Geoff Langb1196682014-07-23 13:47:29 -0400694 context->recordError(Error(GL_INVALID_OPERATION));
695 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 }
697 }
698 }
699 }
700
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200701 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
702 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
703 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400704 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200705 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400707 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
708 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200710 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400711 {
Geoff Langd8a22582014-12-17 15:28:23 -0500712 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713 {
Geoff Langb1196682014-07-23 13:47:29 -0400714 context->recordError(Error(GL_INVALID_OPERATION));
715 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400716 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400717
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200718 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 {
Geoff Langb1196682014-07-23 13:47:29 -0400720 context->recordError(Error(GL_INVALID_OPERATION));
721 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200723
724 if (fromAngleExtension)
725 {
726 if (IsPartialBlit(context, readBuffer, drawBuffer,
727 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
728 {
729 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
730 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
731 return false;
732 }
733
734 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
735 {
736 context->recordError(Error(GL_INVALID_OPERATION));
737 return false;
738 }
739 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400740 }
741 }
742 }
743
744 return true;
745}
746
Geoff Langb1196682014-07-23 13:47:29 -0400747bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748{
749 switch (pname)
750 {
751 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
752 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
753 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
754 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
755 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
756 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
757 case GL_CURRENT_VERTEX_ATTRIB:
758 return true;
759
760 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
761 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
762 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400763 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
764 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 return true;
766
767 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400768 if (context->getClientVersion() < 3)
769 {
770 context->recordError(Error(GL_INVALID_ENUM));
771 return false;
772 }
773 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774
775 default:
Geoff Langb1196682014-07-23 13:47:29 -0400776 context->recordError(Error(GL_INVALID_ENUM));
777 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778 }
779}
780
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400781bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782{
783 switch (pname)
784 {
785 case GL_TEXTURE_WRAP_R:
786 case GL_TEXTURE_SWIZZLE_R:
787 case GL_TEXTURE_SWIZZLE_G:
788 case GL_TEXTURE_SWIZZLE_B:
789 case GL_TEXTURE_SWIZZLE_A:
790 case GL_TEXTURE_BASE_LEVEL:
791 case GL_TEXTURE_MAX_LEVEL:
792 case GL_TEXTURE_COMPARE_MODE:
793 case GL_TEXTURE_COMPARE_FUNC:
794 case GL_TEXTURE_MIN_LOD:
795 case GL_TEXTURE_MAX_LOD:
796 if (context->getClientVersion() < 3)
797 {
Geoff Langb1196682014-07-23 13:47:29 -0400798 context->recordError(Error(GL_INVALID_ENUM));
799 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 }
801 break;
802
803 default: break;
804 }
805
806 switch (pname)
807 {
808 case GL_TEXTURE_WRAP_S:
809 case GL_TEXTURE_WRAP_T:
810 case GL_TEXTURE_WRAP_R:
811 switch (param)
812 {
813 case GL_REPEAT:
814 case GL_CLAMP_TO_EDGE:
815 case GL_MIRRORED_REPEAT:
816 return true;
817 default:
Geoff Langb1196682014-07-23 13:47:29 -0400818 context->recordError(Error(GL_INVALID_ENUM));
819 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400820 }
821
822 case GL_TEXTURE_MIN_FILTER:
823 switch (param)
824 {
825 case GL_NEAREST:
826 case GL_LINEAR:
827 case GL_NEAREST_MIPMAP_NEAREST:
828 case GL_LINEAR_MIPMAP_NEAREST:
829 case GL_NEAREST_MIPMAP_LINEAR:
830 case GL_LINEAR_MIPMAP_LINEAR:
831 return true;
832 default:
Geoff Langb1196682014-07-23 13:47:29 -0400833 context->recordError(Error(GL_INVALID_ENUM));
834 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400835 }
836 break;
837
838 case GL_TEXTURE_MAG_FILTER:
839 switch (param)
840 {
841 case GL_NEAREST:
842 case GL_LINEAR:
843 return true;
844 default:
Geoff Langb1196682014-07-23 13:47:29 -0400845 context->recordError(Error(GL_INVALID_ENUM));
846 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400847 }
848 break;
849
850 case GL_TEXTURE_USAGE_ANGLE:
851 switch (param)
852 {
853 case GL_NONE:
854 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
855 return true;
856 default:
Geoff Langb1196682014-07-23 13:47:29 -0400857 context->recordError(Error(GL_INVALID_ENUM));
858 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400859 }
860 break;
861
862 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400863 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864 {
Geoff Langb1196682014-07-23 13:47:29 -0400865 context->recordError(Error(GL_INVALID_ENUM));
866 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867 }
868
869 // we assume the parameter passed to this validation method is truncated, not rounded
870 if (param < 1)
871 {
Geoff Langb1196682014-07-23 13:47:29 -0400872 context->recordError(Error(GL_INVALID_VALUE));
873 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400874 }
875 return true;
876
877 case GL_TEXTURE_MIN_LOD:
878 case GL_TEXTURE_MAX_LOD:
879 // any value is permissible
880 return true;
881
882 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400883 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400884 switch (param)
885 {
886 case GL_NONE:
887 case GL_COMPARE_REF_TO_TEXTURE:
888 return true;
889 default:
Geoff Langb1196682014-07-23 13:47:29 -0400890 context->recordError(Error(GL_INVALID_ENUM));
891 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400892 }
893 break;
894
895 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400896 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400897 switch (param)
898 {
899 case GL_LEQUAL:
900 case GL_GEQUAL:
901 case GL_LESS:
902 case GL_GREATER:
903 case GL_EQUAL:
904 case GL_NOTEQUAL:
905 case GL_ALWAYS:
906 case GL_NEVER:
907 return true;
908 default:
Geoff Langb1196682014-07-23 13:47:29 -0400909 context->recordError(Error(GL_INVALID_ENUM));
910 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400911 }
912 break;
913
914 case GL_TEXTURE_SWIZZLE_R:
915 case GL_TEXTURE_SWIZZLE_G:
916 case GL_TEXTURE_SWIZZLE_B:
917 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400918 switch (param)
919 {
920 case GL_RED:
921 case GL_GREEN:
922 case GL_BLUE:
923 case GL_ALPHA:
924 case GL_ZERO:
925 case GL_ONE:
926 return true;
927 default:
Geoff Langb1196682014-07-23 13:47:29 -0400928 context->recordError(Error(GL_INVALID_ENUM));
929 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400930 }
931 break;
932
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400933 case GL_TEXTURE_BASE_LEVEL:
934 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400935 if (param < 0)
936 {
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_VALUE));
938 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400939 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400940 return true;
941
942 default:
Geoff Langb1196682014-07-23 13:47:29 -0400943 context->recordError(Error(GL_INVALID_ENUM));
944 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400945 }
946}
947
Geoff Langb1196682014-07-23 13:47:29 -0400948bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400949{
950 switch (pname)
951 {
952 case GL_TEXTURE_MIN_FILTER:
953 case GL_TEXTURE_MAG_FILTER:
954 case GL_TEXTURE_WRAP_S:
955 case GL_TEXTURE_WRAP_T:
956 case GL_TEXTURE_WRAP_R:
957 case GL_TEXTURE_MIN_LOD:
958 case GL_TEXTURE_MAX_LOD:
959 case GL_TEXTURE_COMPARE_MODE:
960 case GL_TEXTURE_COMPARE_FUNC:
961 return true;
962
963 default:
Geoff Langb1196682014-07-23 13:47:29 -0400964 context->recordError(Error(GL_INVALID_ENUM));
965 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400966 }
967}
968
Jamie Madill26e91952014-03-05 15:01:27 -0500969bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
970 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
971{
Shannon Woods53a94a82014-06-24 15:20:36 -0400972 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400973 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500974
Geoff Lang748f74e2014-12-01 11:25:34 -0500975 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500976 {
Geoff Langb1196682014-07-23 13:47:29 -0400977 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
978 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500979 }
980
Jamie Madill48faf802014-11-06 15:27:22 -0500981 if (context->getState().getReadFramebuffer()->id() != 0 &&
982 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500983 {
Geoff Langb1196682014-07-23 13:47:29 -0400984 context->recordError(Error(GL_INVALID_OPERATION));
985 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500986 }
987
Geoff Langbce529e2014-12-01 12:48:41 -0500988 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
989 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400990 {
Geoff Langb1196682014-07-23 13:47:29 -0400991 context->recordError(Error(GL_INVALID_OPERATION));
992 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400993 }
994
Geoff Langbce529e2014-12-01 12:48:41 -0500995 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
996 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500997 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400998 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500999
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001000 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1001 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001002
1003 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1004 {
Geoff Langb1196682014-07-23 13:47:29 -04001005 context->recordError(Error(GL_INVALID_OPERATION));
1006 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001007 }
1008
Geoff Lang5d601382014-07-22 15:14:06 -04001009 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1010 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001011
Minmin Gongb8aee3b2015-01-27 14:42:36 -08001012 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -05001013 // sized query sanity check
1014 if (bufSize)
1015 {
1016 int requiredSize = outputPitch * height;
1017 if (requiredSize > *bufSize)
1018 {
Geoff Langb1196682014-07-23 13:47:29 -04001019 context->recordError(Error(GL_INVALID_OPERATION));
1020 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001021 }
1022 }
1023
1024 return true;
1025}
1026
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001027bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1028{
1029 if (!ValidQueryType(context, target))
1030 {
Geoff Langb1196682014-07-23 13:47:29 -04001031 context->recordError(Error(GL_INVALID_ENUM));
1032 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001033 }
1034
1035 if (id == 0)
1036 {
Geoff Langb1196682014-07-23 13:47:29 -04001037 context->recordError(Error(GL_INVALID_OPERATION));
1038 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001039 }
1040
1041 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1042 // of zero, if the active query object name for <target> is non-zero (for the
1043 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1044 // the active query for either target is non-zero), if <id> is the name of an
1045 // existing query object whose type does not match <target>, or if <id> is the
1046 // active query object name for any query type, the error INVALID_OPERATION is
1047 // generated.
1048
1049 // Ensure no other queries are active
1050 // NOTE: If other queries than occlusion are supported, we will need to check
1051 // separately that:
1052 // a) The query ID passed is not the current active query for any target/type
1053 // b) There are no active queries for the requested target (and in the case
1054 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1055 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001056 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001057 {
Geoff Langb1196682014-07-23 13:47:29 -04001058 context->recordError(Error(GL_INVALID_OPERATION));
1059 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001060 }
1061
1062 Query *queryObject = context->getQuery(id, true, target);
1063
1064 // check that name was obtained with glGenQueries
1065 if (!queryObject)
1066 {
Geoff Langb1196682014-07-23 13:47:29 -04001067 context->recordError(Error(GL_INVALID_OPERATION));
1068 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001069 }
1070
1071 // check for type mismatch
1072 if (queryObject->getType() != target)
1073 {
Geoff Langb1196682014-07-23 13:47:29 -04001074 context->recordError(Error(GL_INVALID_OPERATION));
1075 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001076 }
1077
1078 return true;
1079}
1080
Jamie Madill45c785d2014-05-13 14:09:34 -04001081bool ValidateEndQuery(gl::Context *context, GLenum target)
1082{
1083 if (!ValidQueryType(context, target))
1084 {
Geoff Langb1196682014-07-23 13:47:29 -04001085 context->recordError(Error(GL_INVALID_ENUM));
1086 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001087 }
1088
Shannon Woods53a94a82014-06-24 15:20:36 -04001089 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001090
1091 if (queryObject == NULL)
1092 {
Geoff Langb1196682014-07-23 13:47:29 -04001093 context->recordError(Error(GL_INVALID_OPERATION));
1094 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001095 }
1096
Jamie Madill45c785d2014-05-13 14:09:34 -04001097 return true;
1098}
1099
Jamie Madill36398922014-05-20 14:51:53 -04001100static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1101 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001102{
1103 if (count < 0)
1104 {
Geoff Langb1196682014-07-23 13:47:29 -04001105 context->recordError(Error(GL_INVALID_VALUE));
1106 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001107 }
1108
Geoff Lang7dd2e102014-11-10 15:19:26 -05001109 gl::Program *program = context->getState().getProgram();
1110 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001111 {
Geoff Langb1196682014-07-23 13:47:29 -04001112 context->recordError(Error(GL_INVALID_OPERATION));
1113 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001114 }
1115
1116 if (location == -1)
1117 {
1118 // Silently ignore the uniform command
1119 return false;
1120 }
1121
Geoff Lang7dd2e102014-11-10 15:19:26 -05001122 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001123 {
Geoff Langb1196682014-07-23 13:47:29 -04001124 context->recordError(Error(GL_INVALID_OPERATION));
1125 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001126 }
1127
Geoff Lang7dd2e102014-11-10 15:19:26 -05001128 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001129
1130 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Geoff Lang79d059f2015-07-28 15:03:28 -04001131 if (!uniform->isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001132 {
Geoff Langb1196682014-07-23 13:47:29 -04001133 context->recordError(Error(GL_INVALID_OPERATION));
1134 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001135 }
1136
1137 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001138 return true;
1139}
1140
Jamie Madillaa981bd2014-05-20 10:55:55 -04001141bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1142{
1143 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001144 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001145 {
Geoff Langb1196682014-07-23 13:47:29 -04001146 context->recordError(Error(GL_INVALID_OPERATION));
1147 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001148 }
1149
Jamie Madill36398922014-05-20 14:51:53 -04001150 LinkedUniform *uniform = NULL;
1151 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1152 {
1153 return false;
1154 }
1155
Jamie Madillf2575982014-06-25 16:04:54 -04001156 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001157 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001158 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1159 {
Geoff Langb1196682014-07-23 13:47:29 -04001160 context->recordError(Error(GL_INVALID_OPERATION));
1161 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001162 }
1163
1164 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001165}
1166
1167bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1168 GLboolean transpose)
1169{
1170 // Check for ES3 uniform entry points
1171 int rows = VariableRowCount(matrixType);
1172 int cols = VariableColumnCount(matrixType);
1173 if (rows != cols && context->getClientVersion() < 3)
1174 {
Geoff Langb1196682014-07-23 13:47:29 -04001175 context->recordError(Error(GL_INVALID_OPERATION));
1176 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001177 }
1178
1179 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1180 {
Geoff Langb1196682014-07-23 13:47:29 -04001181 context->recordError(Error(GL_INVALID_VALUE));
1182 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001183 }
1184
Jamie Madill36398922014-05-20 14:51:53 -04001185 LinkedUniform *uniform = NULL;
1186 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1187 {
1188 return false;
1189 }
1190
1191 if (uniform->type != matrixType)
1192 {
Geoff Langb1196682014-07-23 13:47:29 -04001193 context->recordError(Error(GL_INVALID_OPERATION));
1194 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001195 }
1196
1197 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001198}
1199
Jamie Madill893ab082014-05-16 16:56:10 -04001200bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1201{
1202 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1203 {
Geoff Langb1196682014-07-23 13:47:29 -04001204 context->recordError(Error(GL_INVALID_ENUM));
1205 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001206 }
1207
Jamie Madill0af26e12015-03-05 19:54:33 -05001208 const Caps &caps = context->getCaps();
1209
Jamie Madill893ab082014-05-16 16:56:10 -04001210 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1211 {
1212 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1213
Jamie Madill0af26e12015-03-05 19:54:33 -05001214 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001215 {
Geoff Langb1196682014-07-23 13:47:29 -04001216 context->recordError(Error(GL_INVALID_OPERATION));
1217 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001218 }
1219 }
1220
1221 switch (pname)
1222 {
1223 case GL_TEXTURE_BINDING_2D:
1224 case GL_TEXTURE_BINDING_CUBE_MAP:
1225 case GL_TEXTURE_BINDING_3D:
1226 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001227 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001228 {
Geoff Langb1196682014-07-23 13:47:29 -04001229 context->recordError(Error(GL_INVALID_OPERATION));
1230 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001231 }
1232 break;
1233
1234 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1235 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1236 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001237 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001238 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001239 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001240 {
Geoff Langb1196682014-07-23 13:47:29 -04001241 context->recordError(Error(GL_INVALID_OPERATION));
1242 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001243 }
1244
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001245 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001246 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001247 {
Geoff Langb1196682014-07-23 13:47:29 -04001248 context->recordError(Error(GL_INVALID_OPERATION));
1249 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001250 }
1251 }
1252 break;
1253
1254 default:
1255 break;
1256 }
1257
1258 // pname is valid, but there are no parameters to return
1259 if (numParams == 0)
1260 {
1261 return false;
1262 }
1263
1264 return true;
1265}
1266
Geoff Lang831b1952015-05-05 11:02:27 -04001267bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001268 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1269 GLint border, GLenum *textureFormatOut)
1270{
1271
1272 if (!ValidTexture2DDestinationTarget(context, target))
1273 {
Geoff Langb1196682014-07-23 13:47:29 -04001274 context->recordError(Error(GL_INVALID_ENUM));
1275 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001276 }
1277
1278 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1279 {
Geoff Langb1196682014-07-23 13:47:29 -04001280 context->recordError(Error(GL_INVALID_VALUE));
1281 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001282 }
1283
1284 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1285 {
Geoff Langb1196682014-07-23 13:47:29 -04001286 context->recordError(Error(GL_INVALID_VALUE));
1287 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001288 }
1289
1290 if (border != 0)
1291 {
Geoff Langb1196682014-07-23 13:47:29 -04001292 context->recordError(Error(GL_INVALID_VALUE));
1293 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001294 }
1295
1296 if (!ValidMipLevel(context, target, level))
1297 {
Geoff Langb1196682014-07-23 13:47:29 -04001298 context->recordError(Error(GL_INVALID_VALUE));
1299 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001300 }
1301
Shannon Woods53a94a82014-06-24 15:20:36 -04001302 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001303 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001304 {
Geoff Langb1196682014-07-23 13:47:29 -04001305 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1306 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001307 }
1308
Jamie Madill48faf802014-11-06 15:27:22 -05001309 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001310 {
Geoff Langb1196682014-07-23 13:47:29 -04001311 context->recordError(Error(GL_INVALID_OPERATION));
1312 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001313 }
1314
Geoff Langaae65a42014-05-26 12:43:44 -04001315 const gl::Caps &caps = context->getCaps();
1316
Geoff Langaae65a42014-05-26 12:43:44 -04001317 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001318 switch (target)
1319 {
1320 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001321 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001322 break;
1323
1324 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1325 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1326 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1327 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1328 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1329 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001330 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001331 break;
1332
1333 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001334 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001335 break;
1336
1337 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001338 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001339 break;
1340
1341 default:
Geoff Langb1196682014-07-23 13:47:29 -04001342 context->recordError(Error(GL_INVALID_ENUM));
1343 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001344 }
1345
Geoff Lang691e58c2014-12-19 17:03:25 -05001346 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001347 if (!texture)
1348 {
Geoff Langb1196682014-07-23 13:47:29 -04001349 context->recordError(Error(GL_INVALID_OPERATION));
1350 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001351 }
1352
1353 if (texture->isImmutable() && !isSubImage)
1354 {
Geoff Langb1196682014-07-23 13:47:29 -04001355 context->recordError(Error(GL_INVALID_OPERATION));
1356 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 }
1358
Geoff Lang5d601382014-07-22 15:14:06 -04001359 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1360
1361 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001362 {
Geoff Langb1196682014-07-23 13:47:29 -04001363 context->recordError(Error(GL_INVALID_OPERATION));
1364 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001365 }
1366
Geoff Langa9be0dc2014-12-17 12:34:40 -05001367 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001368 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001369 context->recordError(Error(GL_INVALID_OPERATION));
1370 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001371 }
1372
1373 if (isSubImage)
1374 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001375 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1376 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1377 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001378 {
Geoff Langb1196682014-07-23 13:47:29 -04001379 context->recordError(Error(GL_INVALID_VALUE));
1380 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001381 }
1382 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001383 else
1384 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001385 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001386 {
Geoff Langb1196682014-07-23 13:47:29 -04001387 context->recordError(Error(GL_INVALID_VALUE));
1388 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001389 }
1390
Geoff Lang5d601382014-07-22 15:14:06 -04001391 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001392 {
Geoff Langb1196682014-07-23 13:47:29 -04001393 context->recordError(Error(GL_INVALID_ENUM));
1394 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001395 }
1396
1397 int maxLevelDimension = (maxDimension >> level);
1398 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1399 {
Geoff Langb1196682014-07-23 13:47:29 -04001400 context->recordError(Error(GL_INVALID_VALUE));
1401 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001402 }
1403 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001404
Geoff Langa9be0dc2014-12-17 12:34:40 -05001405 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001406 return true;
1407}
1408
Geoff Langb1196682014-07-23 13:47:29 -04001409static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001410{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001411 switch (mode)
1412 {
1413 case GL_POINTS:
1414 case GL_LINES:
1415 case GL_LINE_LOOP:
1416 case GL_LINE_STRIP:
1417 case GL_TRIANGLES:
1418 case GL_TRIANGLE_STRIP:
1419 case GL_TRIANGLE_FAN:
1420 break;
1421 default:
Geoff Langb1196682014-07-23 13:47:29 -04001422 context->recordError(Error(GL_INVALID_ENUM));
1423 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001424 }
1425
Jamie Madill250d33f2014-06-06 17:09:03 -04001426 if (count < 0)
1427 {
Geoff Langb1196682014-07-23 13:47:29 -04001428 context->recordError(Error(GL_INVALID_VALUE));
1429 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001430 }
1431
Geoff Langb1196682014-07-23 13:47:29 -04001432 const State &state = context->getState();
1433
Jamie Madill250d33f2014-06-06 17:09:03 -04001434 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001435 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001436 {
Geoff Langb1196682014-07-23 13:47:29 -04001437 context->recordError(Error(GL_INVALID_OPERATION));
1438 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001439 }
1440
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001441 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001442 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001443 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001444 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1445 {
1446 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1447 // See Section 6.10 of the WebGL 1.0 spec
1448 ERR("This ANGLE implementation does not support separate front/back stencil "
1449 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001450 context->recordError(Error(GL_INVALID_OPERATION));
1451 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001452 }
1453
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001454 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001455 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001456 {
Geoff Langb1196682014-07-23 13:47:29 -04001457 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1458 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001459 }
1460
Geoff Lang7dd2e102014-11-10 15:19:26 -05001461 gl::Program *program = state.getProgram();
1462 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001463 {
Geoff Langb1196682014-07-23 13:47:29 -04001464 context->recordError(Error(GL_INVALID_OPERATION));
1465 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001466 }
1467
Geoff Lang7dd2e102014-11-10 15:19:26 -05001468 if (!program->validateSamplers(NULL, context->getCaps()))
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
Jamie Madill2b976812014-08-25 15:47:49 -04001474 // Buffer validations
Jamie Madill1ca74672015-07-21 15:14:11 -04001475 if (!ValidateDrawAttribs(context, primcount, maxVertex))
Jamie Madill2b976812014-08-25 15:47:49 -04001476 {
Jamie Madill1ca74672015-07-21 15:14:11 -04001477 return false;
Jamie Madill2b976812014-08-25 15:47:49 -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 {
1483 const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
1484 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
1502 if (uniformBufferSize < uniformBlock->dataSize)
1503 {
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
Geoff Langb1196682014-07-23 13:47:29 -04001534 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001535 {
1536 return false;
1537 }
1538
1539 return true;
1540}
1541
Geoff Langb1196682014-07-23 13:47:29 -04001542bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001543{
1544 if (primcount < 0)
1545 {
Geoff Langb1196682014-07-23 13:47:29 -04001546 context->recordError(Error(GL_INVALID_VALUE));
1547 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001548 }
1549
Jamie Madill2b976812014-08-25 15:47:49 -04001550 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001551 {
1552 return false;
1553 }
1554
1555 // No-op if zero primitive count
1556 return (primcount > 0);
1557}
1558
Geoff Lang87a93302014-09-16 13:29:43 -04001559static bool ValidateDrawInstancedANGLE(Context *context)
1560{
1561 // Verify there is at least one active attribute with a divisor of zero
1562 const gl::State& state = context->getState();
1563
Geoff Lang7dd2e102014-11-10 15:19:26 -05001564 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001565
1566 const VertexArray *vao = state.getVertexArray();
1567 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1568 {
1569 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001570 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001571 if (active && attrib.divisor == 0)
1572 {
1573 return true;
1574 }
1575 }
1576
1577 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1578 "has a divisor of zero."));
1579 return false;
1580}
1581
1582bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1583{
1584 if (!ValidateDrawInstancedANGLE(context))
1585 {
1586 return false;
1587 }
1588
1589 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1590}
1591
Geoff Langb1196682014-07-23 13:47:29 -04001592bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001593 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001594{
Jamie Madill250d33f2014-06-06 17:09:03 -04001595 switch (type)
1596 {
1597 case GL_UNSIGNED_BYTE:
1598 case GL_UNSIGNED_SHORT:
1599 break;
1600 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001601 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001602 {
Geoff Langb1196682014-07-23 13:47:29 -04001603 context->recordError(Error(GL_INVALID_ENUM));
1604 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001605 }
1606 break;
1607 default:
Geoff Langb1196682014-07-23 13:47:29 -04001608 context->recordError(Error(GL_INVALID_ENUM));
1609 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001610 }
1611
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001612 const State &state = context->getState();
1613
1614 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001615 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001616 {
1617 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1618 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001619 context->recordError(Error(GL_INVALID_OPERATION));
1620 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001621 }
1622
1623 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001624 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001625 {
Geoff Langb1196682014-07-23 13:47:29 -04001626 context->recordError(Error(GL_INVALID_OPERATION));
1627 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001628 }
1629
Jamie Madill2b976812014-08-25 15:47:49 -04001630 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001631 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001632 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001633 {
Geoff Langb1196682014-07-23 13:47:29 -04001634 context->recordError(Error(GL_INVALID_OPERATION));
1635 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001636 }
1637
Jamie Madillae3000b2014-08-25 15:47:51 -04001638 if (elementArrayBuffer)
1639 {
1640 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1641
1642 GLint64 offset = reinterpret_cast<GLint64>(indices);
1643 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1644
1645 // check for integer overflows
1646 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1647 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1648 {
Geoff Langb1196682014-07-23 13:47:29 -04001649 context->recordError(Error(GL_OUT_OF_MEMORY));
1650 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001651 }
1652
1653 // Check for reading past the end of the bound buffer object
1654 if (byteCount > elementArrayBuffer->getSize())
1655 {
Geoff Langb1196682014-07-23 13:47:29 -04001656 context->recordError(Error(GL_INVALID_OPERATION));
1657 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001658 }
1659 }
1660 else if (!indices)
1661 {
1662 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001663 context->recordError(Error(GL_INVALID_OPERATION));
1664 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001665 }
1666
Jamie Madill2b976812014-08-25 15:47:49 -04001667 // Use max index to validate if our vertex buffers are large enough for the pull.
1668 // TODO: offer fast path, with disabled index validation.
1669 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1670 if (elementArrayBuffer)
1671 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001672 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001673 Error error = elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count, indexRangeOut);
1674 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001675 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001676 context->recordError(error);
1677 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001678 }
1679 }
1680 else
1681 {
Geoff Lang831b1952015-05-05 11:02:27 -04001682 *indexRangeOut = ComputeIndexRange(type, indices, count);
Jamie Madill2b976812014-08-25 15:47:49 -04001683 }
1684
Geoff Langb1196682014-07-23 13:47:29 -04001685 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001686 {
1687 return false;
1688 }
1689
1690 return true;
1691}
1692
Geoff Langb1196682014-07-23 13:47:29 -04001693bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001694 GLenum mode, GLsizei count, GLenum type,
1695 const GLvoid *indices, GLsizei primcount,
Geoff Lang831b1952015-05-05 11:02:27 -04001696 RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001697{
1698 if (primcount < 0)
1699 {
Geoff Langb1196682014-07-23 13:47:29 -04001700 context->recordError(Error(GL_INVALID_VALUE));
1701 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001702 }
1703
Jamie Madill2b976812014-08-25 15:47:49 -04001704 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001705 {
1706 return false;
1707 }
1708
1709 // No-op zero primitive count
1710 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001711}
1712
Geoff Lang87a93302014-09-16 13:29:43 -04001713bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001714 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001715{
1716 if (!ValidateDrawInstancedANGLE(context))
1717 {
1718 return false;
1719 }
1720
1721 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1722}
1723
Geoff Langb1196682014-07-23 13:47:29 -04001724bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001725 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001726{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001727 if (!ValidFramebufferTarget(target))
1728 {
Geoff Langb1196682014-07-23 13:47:29 -04001729 context->recordError(Error(GL_INVALID_ENUM));
1730 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001731 }
1732
1733 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001734 {
1735 return false;
1736 }
1737
Jamie Madill55ec3b12014-07-03 10:38:57 -04001738 if (texture != 0)
1739 {
1740 gl::Texture *tex = context->getTexture(texture);
1741
1742 if (tex == NULL)
1743 {
Geoff Langb1196682014-07-23 13:47:29 -04001744 context->recordError(Error(GL_INVALID_OPERATION));
1745 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001746 }
1747
1748 if (level < 0)
1749 {
Geoff Langb1196682014-07-23 13:47:29 -04001750 context->recordError(Error(GL_INVALID_VALUE));
1751 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001752 }
1753 }
1754
Shannon Woods53a94a82014-06-24 15:20:36 -04001755 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001756 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001757
Jamie Madill84115c92015-04-23 15:00:07 -04001758 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001759 {
Jamie Madill84115c92015-04-23 15:00:07 -04001760 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001761 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001762 }
1763
1764 return true;
1765}
1766
Geoff Langb1196682014-07-23 13:47:29 -04001767bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001768 GLenum textarget, GLuint texture, GLint level)
1769{
Geoff Lang95663912015-04-02 15:54:45 -04001770 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1771 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001772 {
Geoff Langb1196682014-07-23 13:47:29 -04001773 context->recordError(Error(GL_INVALID_VALUE));
1774 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001775 }
1776
1777 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001778 {
1779 return false;
1780 }
1781
Jamie Madill55ec3b12014-07-03 10:38:57 -04001782 if (texture != 0)
1783 {
1784 gl::Texture *tex = context->getTexture(texture);
1785 ASSERT(tex);
1786
Jamie Madill2a6564e2014-07-11 09:53:19 -04001787 const gl::Caps &caps = context->getCaps();
1788
Jamie Madill55ec3b12014-07-03 10:38:57 -04001789 switch (textarget)
1790 {
1791 case GL_TEXTURE_2D:
1792 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001793 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001794 {
Geoff Langb1196682014-07-23 13:47:29 -04001795 context->recordError(Error(GL_INVALID_VALUE));
1796 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001797 }
1798 if (tex->getTarget() != GL_TEXTURE_2D)
1799 {
Geoff Langb1196682014-07-23 13:47:29 -04001800 context->recordError(Error(GL_INVALID_OPERATION));
1801 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001802 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001803 }
1804 break;
1805
1806 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1807 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1808 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1809 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1810 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1811 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1812 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001813 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001814 {
Geoff Langb1196682014-07-23 13:47:29 -04001815 context->recordError(Error(GL_INVALID_VALUE));
1816 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001817 }
1818 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
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 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001823 }
1824 break;
1825
1826 default:
Geoff Langb1196682014-07-23 13:47:29 -04001827 context->recordError(Error(GL_INVALID_ENUM));
1828 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001829 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001830
1831 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1832 if (internalFormatInfo.compressed)
1833 {
1834 context->recordError(Error(GL_INVALID_OPERATION));
1835 return false;
1836 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001837 }
1838
Jamie Madill570f7c82014-07-03 10:38:54 -04001839 return true;
1840}
1841
Geoff Langb1196682014-07-23 13:47:29 -04001842bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001843{
1844 if (program == 0)
1845 {
Geoff Langb1196682014-07-23 13:47:29 -04001846 context->recordError(Error(GL_INVALID_VALUE));
1847 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001848 }
1849
Shannon Woods4de4fd62014-11-07 16:22:02 -05001850 if (!ValidProgram(context, program))
1851 {
1852 return false;
1853 }
1854
Jamie Madill0063c512014-08-25 15:47:53 -04001855 gl::Program *programObject = context->getProgram(program);
1856
1857 if (!programObject || !programObject->isLinked())
1858 {
Geoff Langb1196682014-07-23 13:47:29 -04001859 context->recordError(Error(GL_INVALID_OPERATION));
1860 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001861 }
1862
Geoff Lang7dd2e102014-11-10 15:19:26 -05001863 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001864 {
Geoff Langb1196682014-07-23 13:47:29 -04001865 context->recordError(Error(GL_INVALID_OPERATION));
1866 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001867 }
1868
Jamie Madill0063c512014-08-25 15:47:53 -04001869 return true;
1870}
1871
Geoff Langb1196682014-07-23 13:47:29 -04001872bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001873{
1874 return ValidateGetUniformBase(context, program, location);
1875}
1876
Geoff Langb1196682014-07-23 13:47:29 -04001877bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001878{
Jamie Madill78f41802014-08-25 15:47:55 -04001879 return ValidateGetUniformBase(context, program, location);
1880}
1881
Geoff Langb1196682014-07-23 13:47:29 -04001882static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001883{
1884 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001885 {
Jamie Madill78f41802014-08-25 15:47:55 -04001886 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001887 }
1888
Jamie Madilla502c742014-08-28 17:19:13 -04001889 gl::Program *programObject = context->getProgram(program);
1890 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001891
Jamie Madill78f41802014-08-25 15:47:55 -04001892 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001893 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001894 size_t requiredBytes = VariableExternalSize(uniform->type);
1895 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001896 {
Geoff Langb1196682014-07-23 13:47:29 -04001897 context->recordError(Error(GL_INVALID_OPERATION));
1898 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001899 }
1900
1901 return true;
1902}
1903
Geoff Langb1196682014-07-23 13:47:29 -04001904bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001905{
Jamie Madill78f41802014-08-25 15:47:55 -04001906 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001907}
1908
Geoff Langb1196682014-07-23 13:47:29 -04001909bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001910{
Jamie Madill78f41802014-08-25 15:47:55 -04001911 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001912}
1913
Austin Kinross08332632015-05-05 13:35:47 -07001914bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
1915 const GLenum *attachments, bool defaultFramebuffer)
1916{
1917 if (numAttachments < 0)
1918 {
1919 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
1920 return false;
1921 }
1922
1923 for (GLsizei i = 0; i < numAttachments; ++i)
1924 {
1925 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
1926 {
1927 if (defaultFramebuffer)
1928 {
1929 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1930 return false;
1931 }
1932
1933 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
1934 {
1935 context->recordError(Error(GL_INVALID_OPERATION,
1936 "Requested color attachment is greater than the maximum supported color attachments"));
1937 return false;
1938 }
1939 }
1940 else
1941 {
1942 switch (attachments[i])
1943 {
1944 case GL_DEPTH_ATTACHMENT:
1945 case GL_STENCIL_ATTACHMENT:
1946 case GL_DEPTH_STENCIL_ATTACHMENT:
1947 if (defaultFramebuffer)
1948 {
1949 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1950 return false;
1951 }
1952 break;
1953 case GL_COLOR:
1954 case GL_DEPTH:
1955 case GL_STENCIL:
1956 if (!defaultFramebuffer)
1957 {
1958 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
1959 return false;
1960 }
1961 break;
1962 default:
1963 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
1964 return false;
1965 }
1966 }
1967 }
1968
1969 return true;
1970}
1971
Austin Kinross6ee1e782015-05-29 17:05:37 -07001972bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
1973{
1974 // Note that debug marker calls must not set error state
1975
1976 if (length < 0)
1977 {
1978 return false;
1979 }
1980
1981 if (marker == nullptr)
1982 {
1983 return false;
1984 }
1985
1986 return true;
1987}
1988
1989bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
1990{
1991 // Note that debug marker calls must not set error state
1992
1993 if (length < 0)
1994 {
1995 return false;
1996 }
1997
1998 if (length > 0 && marker == nullptr)
1999 {
2000 return false;
2001 }
2002
2003 return true;
2004}
2005
Geoff Langdcab33b2015-07-21 13:03:16 -04002006bool ValidateEGLImageTargetTexture2DOES(Context *context,
2007 egl::Display *display,
2008 GLenum target,
2009 egl::Image *image)
2010{
Geoff Langa8406172015-07-21 16:53:39 -04002011 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2012 {
2013 context->recordError(Error(GL_INVALID_OPERATION));
2014 return false;
2015 }
2016
2017 switch (target)
2018 {
2019 case GL_TEXTURE_2D:
2020 break;
2021
2022 default:
2023 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2024 return false;
2025 }
2026
2027 if (!display->isValidImage(image))
2028 {
2029 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2030 return false;
2031 }
2032
2033 if (image->getSamples() > 0)
2034 {
2035 context->recordError(Error(GL_INVALID_OPERATION,
2036 "cannot create a 2D texture from a multisampled EGL image."));
2037 return false;
2038 }
2039
2040 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2041 if (!textureCaps.texturable)
2042 {
2043 context->recordError(Error(GL_INVALID_OPERATION,
2044 "EGL image internal format is not supported as a texture."));
2045 return false;
2046 }
2047
Geoff Langdcab33b2015-07-21 13:03:16 -04002048 return true;
2049}
2050
2051bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2052 egl::Display *display,
2053 GLenum target,
2054 egl::Image *image)
2055{
Geoff Langa8406172015-07-21 16:53:39 -04002056 if (!context->getExtensions().eglImage)
2057 {
2058 context->recordError(Error(GL_INVALID_OPERATION));
2059 return false;
2060 }
2061
2062 switch (target)
2063 {
2064 case GL_RENDERBUFFER:
2065 break;
2066
2067 default:
2068 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2069 return false;
2070 }
2071
2072 if (!display->isValidImage(image))
2073 {
2074 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2075 return false;
2076 }
2077
2078 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2079 if (!textureCaps.renderable)
2080 {
2081 context->recordError(Error(
2082 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2083 return false;
2084 }
2085
Geoff Langdcab33b2015-07-21 13:03:16 -04002086 return true;
2087}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002088}