blob: 0761d938dc5bf4946a5ab4e130812f80157b972f [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"
13#include "libANGLE/Texture.h"
14#include "libANGLE/Framebuffer.h"
15#include "libANGLE/FramebufferAttachment.h"
16#include "libANGLE/formatutils.h"
17#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050018#include "libANGLE/Program.h"
19#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/TransformFeedback.h"
21#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040022
23#include "common/mathutil.h"
24#include "common/utilities.h"
25
26namespace gl
27{
Jamie Madill1ca74672015-07-21 15:14:11 -040028namespace
29{
30bool ValidateDrawAttribs(gl::Context *context, GLint primcount, GLint maxVertex)
31{
32 const gl::State &state = context->getState();
33 const gl::Program *program = state.getProgram();
34
35 const VertexArray *vao = state.getVertexArray();
36 const auto &vertexAttribs = vao->getVertexAttributes();
37 const int *semanticIndexes = program->getSemanticIndexes();
38 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
39 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
40 {
41 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
42 bool attribActive = (semanticIndexes[attributeIndex] != -1);
43 if (attribActive && attrib.enabled)
44 {
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 Langc0b9ef42014-07-02 10:02:37 -0400183 return context->getExtensions().pixelBufferObject;
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
Geoff Langaae65a42014-05-26 12:43:44 -0400243 return level <= gl::log2(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
Jamie Madill0af26e12015-03-05 19:54:33 -0500606 for (GLuint i = 0; i < context->getCaps().maxColorAttachments; 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
Jamie Madill0af26e12015-03-05 19:54:33 -0500662 for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400663 {
664 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
665 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000666 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400667 ASSERT(attachment);
668
Jamie Madill8cf4a392015-04-02 11:36:04 -0400669 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500670 attachment->type() != GL_RENDERBUFFER &&
671 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 {
Geoff Langb1196682014-07-23 13:47:29 -0400673 context->recordError(Error(GL_INVALID_OPERATION));
674 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 }
676
Jamie Madillf8f18f02014-10-02 10:44:17 -0400677 // Return an error if the destination formats do not match
678 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400679 {
Geoff Langb1196682014-07-23 13:47:29 -0400680 context->recordError(Error(GL_INVALID_OPERATION));
681 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400682 }
683 }
684 }
Jamie Madill48faf802014-11-06 15:27:22 -0500685
686 int readSamples = readFramebuffer->getSamples(context->getData());
687
688 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
689 srcX0, srcY0, srcX1, srcY1,
690 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400691 {
Geoff Langb1196682014-07-23 13:47:29 -0400692 context->recordError(Error(GL_INVALID_OPERATION));
693 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 }
695 }
696 }
697 }
698
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200699 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
700 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
701 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200703 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400704 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400705 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
706 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400707
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200708 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 {
Geoff Langd8a22582014-12-17 15:28:23 -0500710 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400711 {
Geoff Langb1196682014-07-23 13:47:29 -0400712 context->recordError(Error(GL_INVALID_OPERATION));
713 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400715
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200716 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400717 {
Geoff Langb1196682014-07-23 13:47:29 -0400718 context->recordError(Error(GL_INVALID_OPERATION));
719 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200721
722 if (fromAngleExtension)
723 {
724 if (IsPartialBlit(context, readBuffer, drawBuffer,
725 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
726 {
727 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
728 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
729 return false;
730 }
731
732 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
733 {
734 context->recordError(Error(GL_INVALID_OPERATION));
735 return false;
736 }
737 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 }
739 }
740 }
741
742 return true;
743}
744
Geoff Langb1196682014-07-23 13:47:29 -0400745bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400746{
747 switch (pname)
748 {
749 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
750 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
751 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
752 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
753 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
754 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
755 case GL_CURRENT_VERTEX_ATTRIB:
756 return true;
757
758 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
759 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
760 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400761 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
762 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400763 return true;
764
765 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400766 if (context->getClientVersion() < 3)
767 {
768 context->recordError(Error(GL_INVALID_ENUM));
769 return false;
770 }
771 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400772
773 default:
Geoff Langb1196682014-07-23 13:47:29 -0400774 context->recordError(Error(GL_INVALID_ENUM));
775 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400776 }
777}
778
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400779bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400780{
781 switch (pname)
782 {
783 case GL_TEXTURE_WRAP_R:
784 case GL_TEXTURE_SWIZZLE_R:
785 case GL_TEXTURE_SWIZZLE_G:
786 case GL_TEXTURE_SWIZZLE_B:
787 case GL_TEXTURE_SWIZZLE_A:
788 case GL_TEXTURE_BASE_LEVEL:
789 case GL_TEXTURE_MAX_LEVEL:
790 case GL_TEXTURE_COMPARE_MODE:
791 case GL_TEXTURE_COMPARE_FUNC:
792 case GL_TEXTURE_MIN_LOD:
793 case GL_TEXTURE_MAX_LOD:
794 if (context->getClientVersion() < 3)
795 {
Geoff Langb1196682014-07-23 13:47:29 -0400796 context->recordError(Error(GL_INVALID_ENUM));
797 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400798 }
799 break;
800
801 default: break;
802 }
803
804 switch (pname)
805 {
806 case GL_TEXTURE_WRAP_S:
807 case GL_TEXTURE_WRAP_T:
808 case GL_TEXTURE_WRAP_R:
809 switch (param)
810 {
811 case GL_REPEAT:
812 case GL_CLAMP_TO_EDGE:
813 case GL_MIRRORED_REPEAT:
814 return true;
815 default:
Geoff Langb1196682014-07-23 13:47:29 -0400816 context->recordError(Error(GL_INVALID_ENUM));
817 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818 }
819
820 case GL_TEXTURE_MIN_FILTER:
821 switch (param)
822 {
823 case GL_NEAREST:
824 case GL_LINEAR:
825 case GL_NEAREST_MIPMAP_NEAREST:
826 case GL_LINEAR_MIPMAP_NEAREST:
827 case GL_NEAREST_MIPMAP_LINEAR:
828 case GL_LINEAR_MIPMAP_LINEAR:
829 return true;
830 default:
Geoff Langb1196682014-07-23 13:47:29 -0400831 context->recordError(Error(GL_INVALID_ENUM));
832 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833 }
834 break;
835
836 case GL_TEXTURE_MAG_FILTER:
837 switch (param)
838 {
839 case GL_NEAREST:
840 case GL_LINEAR:
841 return true;
842 default:
Geoff Langb1196682014-07-23 13:47:29 -0400843 context->recordError(Error(GL_INVALID_ENUM));
844 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400845 }
846 break;
847
848 case GL_TEXTURE_USAGE_ANGLE:
849 switch (param)
850 {
851 case GL_NONE:
852 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
853 return true;
854 default:
Geoff Langb1196682014-07-23 13:47:29 -0400855 context->recordError(Error(GL_INVALID_ENUM));
856 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400857 }
858 break;
859
860 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400861 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400862 {
Geoff Langb1196682014-07-23 13:47:29 -0400863 context->recordError(Error(GL_INVALID_ENUM));
864 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400865 }
866
867 // we assume the parameter passed to this validation method is truncated, not rounded
868 if (param < 1)
869 {
Geoff Langb1196682014-07-23 13:47:29 -0400870 context->recordError(Error(GL_INVALID_VALUE));
871 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400872 }
873 return true;
874
875 case GL_TEXTURE_MIN_LOD:
876 case GL_TEXTURE_MAX_LOD:
877 // any value is permissible
878 return true;
879
880 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400881 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 switch (param)
883 {
884 case GL_NONE:
885 case GL_COMPARE_REF_TO_TEXTURE:
886 return true;
887 default:
Geoff Langb1196682014-07-23 13:47:29 -0400888 context->recordError(Error(GL_INVALID_ENUM));
889 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 }
891 break;
892
893 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400894 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400895 switch (param)
896 {
897 case GL_LEQUAL:
898 case GL_GEQUAL:
899 case GL_LESS:
900 case GL_GREATER:
901 case GL_EQUAL:
902 case GL_NOTEQUAL:
903 case GL_ALWAYS:
904 case GL_NEVER:
905 return true;
906 default:
Geoff Langb1196682014-07-23 13:47:29 -0400907 context->recordError(Error(GL_INVALID_ENUM));
908 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400909 }
910 break;
911
912 case GL_TEXTURE_SWIZZLE_R:
913 case GL_TEXTURE_SWIZZLE_G:
914 case GL_TEXTURE_SWIZZLE_B:
915 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400916 switch (param)
917 {
918 case GL_RED:
919 case GL_GREEN:
920 case GL_BLUE:
921 case GL_ALPHA:
922 case GL_ZERO:
923 case GL_ONE:
924 return true;
925 default:
Geoff Langb1196682014-07-23 13:47:29 -0400926 context->recordError(Error(GL_INVALID_ENUM));
927 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400928 }
929 break;
930
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400931 case GL_TEXTURE_BASE_LEVEL:
932 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400933 if (param < 0)
934 {
Geoff Langb1196682014-07-23 13:47:29 -0400935 context->recordError(Error(GL_INVALID_VALUE));
936 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400937 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400938 return true;
939
940 default:
Geoff Langb1196682014-07-23 13:47:29 -0400941 context->recordError(Error(GL_INVALID_ENUM));
942 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400943 }
944}
945
Geoff Langb1196682014-07-23 13:47:29 -0400946bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400947{
948 switch (pname)
949 {
950 case GL_TEXTURE_MIN_FILTER:
951 case GL_TEXTURE_MAG_FILTER:
952 case GL_TEXTURE_WRAP_S:
953 case GL_TEXTURE_WRAP_T:
954 case GL_TEXTURE_WRAP_R:
955 case GL_TEXTURE_MIN_LOD:
956 case GL_TEXTURE_MAX_LOD:
957 case GL_TEXTURE_COMPARE_MODE:
958 case GL_TEXTURE_COMPARE_FUNC:
959 return true;
960
961 default:
Geoff Langb1196682014-07-23 13:47:29 -0400962 context->recordError(Error(GL_INVALID_ENUM));
963 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400964 }
965}
966
Jamie Madill26e91952014-03-05 15:01:27 -0500967bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
968 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
969{
Shannon Woods53a94a82014-06-24 15:20:36 -0400970 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400971 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500972
Geoff Lang748f74e2014-12-01 11:25:34 -0500973 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500974 {
Geoff Langb1196682014-07-23 13:47:29 -0400975 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
976 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500977 }
978
Jamie Madill48faf802014-11-06 15:27:22 -0500979 if (context->getState().getReadFramebuffer()->id() != 0 &&
980 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500981 {
Geoff Langb1196682014-07-23 13:47:29 -0400982 context->recordError(Error(GL_INVALID_OPERATION));
983 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500984 }
985
Geoff Langbce529e2014-12-01 12:48:41 -0500986 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
987 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400988 {
Geoff Langb1196682014-07-23 13:47:29 -0400989 context->recordError(Error(GL_INVALID_OPERATION));
990 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400991 }
992
Geoff Langbce529e2014-12-01 12:48:41 -0500993 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
994 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500995 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400996 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500997
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400998 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
999 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001000
1001 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1002 {
Geoff Langb1196682014-07-23 13:47:29 -04001003 context->recordError(Error(GL_INVALID_OPERATION));
1004 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001005 }
1006
Geoff Lang5d601382014-07-22 15:14:06 -04001007 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1008 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001009
Minmin Gongb8aee3b2015-01-27 14:42:36 -08001010 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -05001011 // sized query sanity check
1012 if (bufSize)
1013 {
1014 int requiredSize = outputPitch * height;
1015 if (requiredSize > *bufSize)
1016 {
Geoff Langb1196682014-07-23 13:47:29 -04001017 context->recordError(Error(GL_INVALID_OPERATION));
1018 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001019 }
1020 }
1021
1022 return true;
1023}
1024
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001025bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1026{
1027 if (!ValidQueryType(context, target))
1028 {
Geoff Langb1196682014-07-23 13:47:29 -04001029 context->recordError(Error(GL_INVALID_ENUM));
1030 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001031 }
1032
1033 if (id == 0)
1034 {
Geoff Langb1196682014-07-23 13:47:29 -04001035 context->recordError(Error(GL_INVALID_OPERATION));
1036 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001037 }
1038
1039 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1040 // of zero, if the active query object name for <target> is non-zero (for the
1041 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1042 // the active query for either target is non-zero), if <id> is the name of an
1043 // existing query object whose type does not match <target>, or if <id> is the
1044 // active query object name for any query type, the error INVALID_OPERATION is
1045 // generated.
1046
1047 // Ensure no other queries are active
1048 // NOTE: If other queries than occlusion are supported, we will need to check
1049 // separately that:
1050 // a) The query ID passed is not the current active query for any target/type
1051 // b) There are no active queries for the requested target (and in the case
1052 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1053 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001054 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001055 {
Geoff Langb1196682014-07-23 13:47:29 -04001056 context->recordError(Error(GL_INVALID_OPERATION));
1057 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001058 }
1059
1060 Query *queryObject = context->getQuery(id, true, target);
1061
1062 // check that name was obtained with glGenQueries
1063 if (!queryObject)
1064 {
Geoff Langb1196682014-07-23 13:47:29 -04001065 context->recordError(Error(GL_INVALID_OPERATION));
1066 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001067 }
1068
1069 // check for type mismatch
1070 if (queryObject->getType() != target)
1071 {
Geoff Langb1196682014-07-23 13:47:29 -04001072 context->recordError(Error(GL_INVALID_OPERATION));
1073 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001074 }
1075
1076 return true;
1077}
1078
Jamie Madill45c785d2014-05-13 14:09:34 -04001079bool ValidateEndQuery(gl::Context *context, GLenum target)
1080{
1081 if (!ValidQueryType(context, target))
1082 {
Geoff Langb1196682014-07-23 13:47:29 -04001083 context->recordError(Error(GL_INVALID_ENUM));
1084 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001085 }
1086
Shannon Woods53a94a82014-06-24 15:20:36 -04001087 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001088
1089 if (queryObject == NULL)
1090 {
Geoff Langb1196682014-07-23 13:47:29 -04001091 context->recordError(Error(GL_INVALID_OPERATION));
1092 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001093 }
1094
Jamie Madill45c785d2014-05-13 14:09:34 -04001095 return true;
1096}
1097
Jamie Madill36398922014-05-20 14:51:53 -04001098static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1099 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001100{
1101 if (count < 0)
1102 {
Geoff Langb1196682014-07-23 13:47:29 -04001103 context->recordError(Error(GL_INVALID_VALUE));
1104 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001105 }
1106
Geoff Lang7dd2e102014-11-10 15:19:26 -05001107 gl::Program *program = context->getState().getProgram();
1108 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001109 {
Geoff Langb1196682014-07-23 13:47:29 -04001110 context->recordError(Error(GL_INVALID_OPERATION));
1111 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001112 }
1113
1114 if (location == -1)
1115 {
1116 // Silently ignore the uniform command
1117 return false;
1118 }
1119
Geoff Lang7dd2e102014-11-10 15:19:26 -05001120 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001121 {
Geoff Langb1196682014-07-23 13:47:29 -04001122 context->recordError(Error(GL_INVALID_OPERATION));
1123 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001124 }
1125
Geoff Lang7dd2e102014-11-10 15:19:26 -05001126 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001127
1128 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Geoff Lang79d059f2015-07-28 15:03:28 -04001129 if (!uniform->isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001130 {
Geoff Langb1196682014-07-23 13:47:29 -04001131 context->recordError(Error(GL_INVALID_OPERATION));
1132 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001133 }
1134
1135 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001136 return true;
1137}
1138
Jamie Madillaa981bd2014-05-20 10:55:55 -04001139bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1140{
1141 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001142 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001143 {
Geoff Langb1196682014-07-23 13:47:29 -04001144 context->recordError(Error(GL_INVALID_OPERATION));
1145 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001146 }
1147
Jamie Madill36398922014-05-20 14:51:53 -04001148 LinkedUniform *uniform = NULL;
1149 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1150 {
1151 return false;
1152 }
1153
Jamie Madillf2575982014-06-25 16:04:54 -04001154 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001155 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001156 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1157 {
Geoff Langb1196682014-07-23 13:47:29 -04001158 context->recordError(Error(GL_INVALID_OPERATION));
1159 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001160 }
1161
1162 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001163}
1164
1165bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1166 GLboolean transpose)
1167{
1168 // Check for ES3 uniform entry points
1169 int rows = VariableRowCount(matrixType);
1170 int cols = VariableColumnCount(matrixType);
1171 if (rows != cols && context->getClientVersion() < 3)
1172 {
Geoff Langb1196682014-07-23 13:47:29 -04001173 context->recordError(Error(GL_INVALID_OPERATION));
1174 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001175 }
1176
1177 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1178 {
Geoff Langb1196682014-07-23 13:47:29 -04001179 context->recordError(Error(GL_INVALID_VALUE));
1180 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001181 }
1182
Jamie Madill36398922014-05-20 14:51:53 -04001183 LinkedUniform *uniform = NULL;
1184 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1185 {
1186 return false;
1187 }
1188
1189 if (uniform->type != matrixType)
1190 {
Geoff Langb1196682014-07-23 13:47:29 -04001191 context->recordError(Error(GL_INVALID_OPERATION));
1192 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001193 }
1194
1195 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001196}
1197
Jamie Madill893ab082014-05-16 16:56:10 -04001198bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1199{
1200 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1201 {
Geoff Langb1196682014-07-23 13:47:29 -04001202 context->recordError(Error(GL_INVALID_ENUM));
1203 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001204 }
1205
Jamie Madill0af26e12015-03-05 19:54:33 -05001206 const Caps &caps = context->getCaps();
1207
Jamie Madill893ab082014-05-16 16:56:10 -04001208 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1209 {
1210 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1211
Jamie Madill0af26e12015-03-05 19:54:33 -05001212 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001213 {
Geoff Langb1196682014-07-23 13:47:29 -04001214 context->recordError(Error(GL_INVALID_OPERATION));
1215 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001216 }
1217 }
1218
1219 switch (pname)
1220 {
1221 case GL_TEXTURE_BINDING_2D:
1222 case GL_TEXTURE_BINDING_CUBE_MAP:
1223 case GL_TEXTURE_BINDING_3D:
1224 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001225 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001226 {
Geoff Langb1196682014-07-23 13:47:29 -04001227 context->recordError(Error(GL_INVALID_OPERATION));
1228 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001229 }
1230 break;
1231
1232 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1233 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1234 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001235 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001236 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001237 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001238 {
Geoff Langb1196682014-07-23 13:47:29 -04001239 context->recordError(Error(GL_INVALID_OPERATION));
1240 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001241 }
1242
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001243 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001244 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001245 {
Geoff Langb1196682014-07-23 13:47:29 -04001246 context->recordError(Error(GL_INVALID_OPERATION));
1247 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001248 }
1249 }
1250 break;
1251
1252 default:
1253 break;
1254 }
1255
1256 // pname is valid, but there are no parameters to return
1257 if (numParams == 0)
1258 {
1259 return false;
1260 }
1261
1262 return true;
1263}
1264
Geoff Lang831b1952015-05-05 11:02:27 -04001265bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001266 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1267 GLint border, GLenum *textureFormatOut)
1268{
1269
1270 if (!ValidTexture2DDestinationTarget(context, target))
1271 {
Geoff Langb1196682014-07-23 13:47:29 -04001272 context->recordError(Error(GL_INVALID_ENUM));
1273 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001274 }
1275
1276 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1277 {
Geoff Langb1196682014-07-23 13:47:29 -04001278 context->recordError(Error(GL_INVALID_VALUE));
1279 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001280 }
1281
1282 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1283 {
Geoff Langb1196682014-07-23 13:47:29 -04001284 context->recordError(Error(GL_INVALID_VALUE));
1285 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001286 }
1287
1288 if (border != 0)
1289 {
Geoff Langb1196682014-07-23 13:47:29 -04001290 context->recordError(Error(GL_INVALID_VALUE));
1291 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001292 }
1293
1294 if (!ValidMipLevel(context, target, level))
1295 {
Geoff Langb1196682014-07-23 13:47:29 -04001296 context->recordError(Error(GL_INVALID_VALUE));
1297 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001298 }
1299
Shannon Woods53a94a82014-06-24 15:20:36 -04001300 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001301 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001302 {
Geoff Langb1196682014-07-23 13:47:29 -04001303 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1304 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001305 }
1306
Jamie Madill48faf802014-11-06 15:27:22 -05001307 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001308 {
Geoff Langb1196682014-07-23 13:47:29 -04001309 context->recordError(Error(GL_INVALID_OPERATION));
1310 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001311 }
1312
Geoff Langaae65a42014-05-26 12:43:44 -04001313 const gl::Caps &caps = context->getCaps();
1314
Geoff Langaae65a42014-05-26 12:43:44 -04001315 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001316 switch (target)
1317 {
1318 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001319 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001320 break;
1321
1322 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1323 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1324 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1325 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1326 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1327 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001328 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001329 break;
1330
1331 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001332 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001333 break;
1334
1335 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001336 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001337 break;
1338
1339 default:
Geoff Langb1196682014-07-23 13:47:29 -04001340 context->recordError(Error(GL_INVALID_ENUM));
1341 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001342 }
1343
Geoff Lang691e58c2014-12-19 17:03:25 -05001344 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001345 if (!texture)
1346 {
Geoff Langb1196682014-07-23 13:47:29 -04001347 context->recordError(Error(GL_INVALID_OPERATION));
1348 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001349 }
1350
1351 if (texture->isImmutable() && !isSubImage)
1352 {
Geoff Langb1196682014-07-23 13:47:29 -04001353 context->recordError(Error(GL_INVALID_OPERATION));
1354 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001355 }
1356
Geoff Lang5d601382014-07-22 15:14:06 -04001357 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1358
1359 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001360 {
Geoff Langb1196682014-07-23 13:47:29 -04001361 context->recordError(Error(GL_INVALID_OPERATION));
1362 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001363 }
1364
Geoff Langa9be0dc2014-12-17 12:34:40 -05001365 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001366 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001367 context->recordError(Error(GL_INVALID_OPERATION));
1368 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001369 }
1370
1371 if (isSubImage)
1372 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001373 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1374 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1375 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001376 {
Geoff Langb1196682014-07-23 13:47:29 -04001377 context->recordError(Error(GL_INVALID_VALUE));
1378 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001379 }
1380 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001381 else
1382 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001383 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001384 {
Geoff Langb1196682014-07-23 13:47:29 -04001385 context->recordError(Error(GL_INVALID_VALUE));
1386 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001387 }
1388
Geoff Lang5d601382014-07-22 15:14:06 -04001389 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001390 {
Geoff Langb1196682014-07-23 13:47:29 -04001391 context->recordError(Error(GL_INVALID_ENUM));
1392 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001393 }
1394
1395 int maxLevelDimension = (maxDimension >> level);
1396 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1397 {
Geoff Langb1196682014-07-23 13:47:29 -04001398 context->recordError(Error(GL_INVALID_VALUE));
1399 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001400 }
1401 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001402
Geoff Langa9be0dc2014-12-17 12:34:40 -05001403 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001404 return true;
1405}
1406
Geoff Langb1196682014-07-23 13:47:29 -04001407static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001408{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001409 switch (mode)
1410 {
1411 case GL_POINTS:
1412 case GL_LINES:
1413 case GL_LINE_LOOP:
1414 case GL_LINE_STRIP:
1415 case GL_TRIANGLES:
1416 case GL_TRIANGLE_STRIP:
1417 case GL_TRIANGLE_FAN:
1418 break;
1419 default:
Geoff Langb1196682014-07-23 13:47:29 -04001420 context->recordError(Error(GL_INVALID_ENUM));
1421 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001422 }
1423
Jamie Madill250d33f2014-06-06 17:09:03 -04001424 if (count < 0)
1425 {
Geoff Langb1196682014-07-23 13:47:29 -04001426 context->recordError(Error(GL_INVALID_VALUE));
1427 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001428 }
1429
Geoff Langb1196682014-07-23 13:47:29 -04001430 const State &state = context->getState();
1431
Jamie Madill250d33f2014-06-06 17:09:03 -04001432 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001433 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001434 {
Geoff Langb1196682014-07-23 13:47:29 -04001435 context->recordError(Error(GL_INVALID_OPERATION));
1436 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001437 }
1438
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001439 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001440 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001441 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001442 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1443 {
1444 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1445 // See Section 6.10 of the WebGL 1.0 spec
1446 ERR("This ANGLE implementation does not support separate front/back stencil "
1447 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001448 context->recordError(Error(GL_INVALID_OPERATION));
1449 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001450 }
1451
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001452 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001453 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001454 {
Geoff Langb1196682014-07-23 13:47:29 -04001455 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1456 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001457 }
1458
Geoff Lang7dd2e102014-11-10 15:19:26 -05001459 gl::Program *program = state.getProgram();
1460 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001461 {
Geoff Langb1196682014-07-23 13:47:29 -04001462 context->recordError(Error(GL_INVALID_OPERATION));
1463 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001464 }
1465
Geoff Lang7dd2e102014-11-10 15:19:26 -05001466 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001467 {
Geoff Langb1196682014-07-23 13:47:29 -04001468 context->recordError(Error(GL_INVALID_OPERATION));
1469 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001470 }
1471
Jamie Madill2b976812014-08-25 15:47:49 -04001472 // Buffer validations
Jamie Madill1ca74672015-07-21 15:14:11 -04001473 if (!ValidateDrawAttribs(context, primcount, maxVertex))
Jamie Madill2b976812014-08-25 15:47:49 -04001474 {
Jamie Madill1ca74672015-07-21 15:14:11 -04001475 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001476 }
1477
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001478 // Uniform buffer validation
1479 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1480 {
1481 const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
1482 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
1483 const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
1484
1485 if (!uniformBuffer)
1486 {
1487 // undefined behaviour
1488 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1489 return false;
1490 }
1491
1492 size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
1493
1494 if (uniformBufferSize == 0)
1495 {
1496 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001497 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001498 }
1499
1500 if (uniformBufferSize < uniformBlock->dataSize)
1501 {
1502 // undefined behaviour
1503 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1504 return false;
1505 }
1506 }
1507
Jamie Madill250d33f2014-06-06 17:09:03 -04001508 // No-op if zero count
1509 return (count > 0);
1510}
1511
Geoff Langb1196682014-07-23 13:47:29 -04001512bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001513{
Jamie Madillfd716582014-06-06 17:09:04 -04001514 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001515 {
Geoff Langb1196682014-07-23 13:47:29 -04001516 context->recordError(Error(GL_INVALID_VALUE));
1517 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001518 }
1519
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001520 const State &state = context->getState();
1521 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001522 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1523 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001524 {
1525 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1526 // that does not match the current transform feedback object's draw mode (if transform feedback
1527 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001528 context->recordError(Error(GL_INVALID_OPERATION));
1529 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001530 }
1531
Geoff Langb1196682014-07-23 13:47:29 -04001532 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001533 {
1534 return false;
1535 }
1536
1537 return true;
1538}
1539
Geoff Langb1196682014-07-23 13:47:29 -04001540bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001541{
1542 if (primcount < 0)
1543 {
Geoff Langb1196682014-07-23 13:47:29 -04001544 context->recordError(Error(GL_INVALID_VALUE));
1545 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001546 }
1547
Jamie Madill2b976812014-08-25 15:47:49 -04001548 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001549 {
1550 return false;
1551 }
1552
1553 // No-op if zero primitive count
1554 return (primcount > 0);
1555}
1556
Geoff Lang87a93302014-09-16 13:29:43 -04001557static bool ValidateDrawInstancedANGLE(Context *context)
1558{
1559 // Verify there is at least one active attribute with a divisor of zero
1560 const gl::State& state = context->getState();
1561
Geoff Lang7dd2e102014-11-10 15:19:26 -05001562 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001563
1564 const VertexArray *vao = state.getVertexArray();
1565 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1566 {
1567 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001568 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001569 if (active && attrib.divisor == 0)
1570 {
1571 return true;
1572 }
1573 }
1574
1575 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1576 "has a divisor of zero."));
1577 return false;
1578}
1579
1580bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1581{
1582 if (!ValidateDrawInstancedANGLE(context))
1583 {
1584 return false;
1585 }
1586
1587 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1588}
1589
Geoff Langb1196682014-07-23 13:47:29 -04001590bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001591 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001592{
Jamie Madill250d33f2014-06-06 17:09:03 -04001593 switch (type)
1594 {
1595 case GL_UNSIGNED_BYTE:
1596 case GL_UNSIGNED_SHORT:
1597 break;
1598 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001599 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001600 {
Geoff Langb1196682014-07-23 13:47:29 -04001601 context->recordError(Error(GL_INVALID_ENUM));
1602 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001603 }
1604 break;
1605 default:
Geoff Langb1196682014-07-23 13:47:29 -04001606 context->recordError(Error(GL_INVALID_ENUM));
1607 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001608 }
1609
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001610 const State &state = context->getState();
1611
1612 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001613 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001614 {
1615 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1616 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001617 context->recordError(Error(GL_INVALID_OPERATION));
1618 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001619 }
1620
1621 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001622 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001623 {
Geoff Langb1196682014-07-23 13:47:29 -04001624 context->recordError(Error(GL_INVALID_OPERATION));
1625 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001626 }
1627
Jamie Madill2b976812014-08-25 15:47:49 -04001628 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001629 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001630 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001631 {
Geoff Langb1196682014-07-23 13:47:29 -04001632 context->recordError(Error(GL_INVALID_OPERATION));
1633 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001634 }
1635
Jamie Madillae3000b2014-08-25 15:47:51 -04001636 if (elementArrayBuffer)
1637 {
1638 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1639
1640 GLint64 offset = reinterpret_cast<GLint64>(indices);
1641 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1642
1643 // check for integer overflows
1644 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1645 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1646 {
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_OUT_OF_MEMORY));
1648 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001649 }
1650
1651 // Check for reading past the end of the bound buffer object
1652 if (byteCount > elementArrayBuffer->getSize())
1653 {
Geoff Langb1196682014-07-23 13:47:29 -04001654 context->recordError(Error(GL_INVALID_OPERATION));
1655 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001656 }
1657 }
1658 else if (!indices)
1659 {
1660 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001661 context->recordError(Error(GL_INVALID_OPERATION));
1662 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001663 }
1664
Jamie Madill2b976812014-08-25 15:47:49 -04001665 // Use max index to validate if our vertex buffers are large enough for the pull.
1666 // TODO: offer fast path, with disabled index validation.
1667 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1668 if (elementArrayBuffer)
1669 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001670 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001671 Error error = elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count, indexRangeOut);
1672 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001673 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001674 context->recordError(error);
1675 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001676 }
1677 }
1678 else
1679 {
Geoff Lang831b1952015-05-05 11:02:27 -04001680 *indexRangeOut = ComputeIndexRange(type, indices, count);
Jamie Madill2b976812014-08-25 15:47:49 -04001681 }
1682
Geoff Langb1196682014-07-23 13:47:29 -04001683 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001684 {
1685 return false;
1686 }
1687
1688 return true;
1689}
1690
Geoff Langb1196682014-07-23 13:47:29 -04001691bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001692 GLenum mode, GLsizei count, GLenum type,
1693 const GLvoid *indices, GLsizei primcount,
Geoff Lang831b1952015-05-05 11:02:27 -04001694 RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001695{
1696 if (primcount < 0)
1697 {
Geoff Langb1196682014-07-23 13:47:29 -04001698 context->recordError(Error(GL_INVALID_VALUE));
1699 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001700 }
1701
Jamie Madill2b976812014-08-25 15:47:49 -04001702 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001703 {
1704 return false;
1705 }
1706
1707 // No-op zero primitive count
1708 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001709}
1710
Geoff Lang87a93302014-09-16 13:29:43 -04001711bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001712 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001713{
1714 if (!ValidateDrawInstancedANGLE(context))
1715 {
1716 return false;
1717 }
1718
1719 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1720}
1721
Geoff Langb1196682014-07-23 13:47:29 -04001722bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001723 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001724{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001725 if (!ValidFramebufferTarget(target))
1726 {
Geoff Langb1196682014-07-23 13:47:29 -04001727 context->recordError(Error(GL_INVALID_ENUM));
1728 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001729 }
1730
1731 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001732 {
1733 return false;
1734 }
1735
Jamie Madill55ec3b12014-07-03 10:38:57 -04001736 if (texture != 0)
1737 {
1738 gl::Texture *tex = context->getTexture(texture);
1739
1740 if (tex == NULL)
1741 {
Geoff Langb1196682014-07-23 13:47:29 -04001742 context->recordError(Error(GL_INVALID_OPERATION));
1743 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001744 }
1745
1746 if (level < 0)
1747 {
Geoff Langb1196682014-07-23 13:47:29 -04001748 context->recordError(Error(GL_INVALID_VALUE));
1749 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001750 }
1751 }
1752
Shannon Woods53a94a82014-06-24 15:20:36 -04001753 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001754 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001755
Jamie Madill84115c92015-04-23 15:00:07 -04001756 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001757 {
Jamie Madill84115c92015-04-23 15:00:07 -04001758 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001759 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001760 }
1761
1762 return true;
1763}
1764
Geoff Langb1196682014-07-23 13:47:29 -04001765bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001766 GLenum textarget, GLuint texture, GLint level)
1767{
Geoff Lang95663912015-04-02 15:54:45 -04001768 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1769 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001770 {
Geoff Langb1196682014-07-23 13:47:29 -04001771 context->recordError(Error(GL_INVALID_VALUE));
1772 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001773 }
1774
1775 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001776 {
1777 return false;
1778 }
1779
Jamie Madill55ec3b12014-07-03 10:38:57 -04001780 if (texture != 0)
1781 {
1782 gl::Texture *tex = context->getTexture(texture);
1783 ASSERT(tex);
1784
Jamie Madill2a6564e2014-07-11 09:53:19 -04001785 const gl::Caps &caps = context->getCaps();
1786
Jamie Madill55ec3b12014-07-03 10:38:57 -04001787 switch (textarget)
1788 {
1789 case GL_TEXTURE_2D:
1790 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001791 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001792 {
Geoff Langb1196682014-07-23 13:47:29 -04001793 context->recordError(Error(GL_INVALID_VALUE));
1794 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001795 }
1796 if (tex->getTarget() != GL_TEXTURE_2D)
1797 {
Geoff Langb1196682014-07-23 13:47:29 -04001798 context->recordError(Error(GL_INVALID_OPERATION));
1799 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001800 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001801 }
1802 break;
1803
1804 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1805 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1806 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1807 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1808 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1809 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1810 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001811 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001812 {
Geoff Langb1196682014-07-23 13:47:29 -04001813 context->recordError(Error(GL_INVALID_VALUE));
1814 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001815 }
1816 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1817 {
Geoff Langb1196682014-07-23 13:47:29 -04001818 context->recordError(Error(GL_INVALID_OPERATION));
1819 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001820 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001821 }
1822 break;
1823
1824 default:
Geoff Langb1196682014-07-23 13:47:29 -04001825 context->recordError(Error(GL_INVALID_ENUM));
1826 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001827 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001828
1829 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1830 if (internalFormatInfo.compressed)
1831 {
1832 context->recordError(Error(GL_INVALID_OPERATION));
1833 return false;
1834 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001835 }
1836
Jamie Madill570f7c82014-07-03 10:38:54 -04001837 return true;
1838}
1839
Geoff Langb1196682014-07-23 13:47:29 -04001840bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001841{
1842 if (program == 0)
1843 {
Geoff Langb1196682014-07-23 13:47:29 -04001844 context->recordError(Error(GL_INVALID_VALUE));
1845 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001846 }
1847
Shannon Woods4de4fd62014-11-07 16:22:02 -05001848 if (!ValidProgram(context, program))
1849 {
1850 return false;
1851 }
1852
Jamie Madill0063c512014-08-25 15:47:53 -04001853 gl::Program *programObject = context->getProgram(program);
1854
1855 if (!programObject || !programObject->isLinked())
1856 {
Geoff Langb1196682014-07-23 13:47:29 -04001857 context->recordError(Error(GL_INVALID_OPERATION));
1858 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001859 }
1860
Geoff Lang7dd2e102014-11-10 15:19:26 -05001861 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001862 {
Geoff Langb1196682014-07-23 13:47:29 -04001863 context->recordError(Error(GL_INVALID_OPERATION));
1864 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001865 }
1866
Jamie Madill0063c512014-08-25 15:47:53 -04001867 return true;
1868}
1869
Geoff Langb1196682014-07-23 13:47:29 -04001870bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001871{
1872 return ValidateGetUniformBase(context, program, location);
1873}
1874
Geoff Langb1196682014-07-23 13:47:29 -04001875bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001876{
Jamie Madill78f41802014-08-25 15:47:55 -04001877 return ValidateGetUniformBase(context, program, location);
1878}
1879
Geoff Langb1196682014-07-23 13:47:29 -04001880static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001881{
1882 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001883 {
Jamie Madill78f41802014-08-25 15:47:55 -04001884 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001885 }
1886
Jamie Madilla502c742014-08-28 17:19:13 -04001887 gl::Program *programObject = context->getProgram(program);
1888 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001889
Jamie Madill78f41802014-08-25 15:47:55 -04001890 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001891 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001892 size_t requiredBytes = VariableExternalSize(uniform->type);
1893 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001894 {
Geoff Langb1196682014-07-23 13:47:29 -04001895 context->recordError(Error(GL_INVALID_OPERATION));
1896 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001897 }
1898
1899 return true;
1900}
1901
Geoff Langb1196682014-07-23 13:47:29 -04001902bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001903{
Jamie Madill78f41802014-08-25 15:47:55 -04001904 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001905}
1906
Geoff Langb1196682014-07-23 13:47:29 -04001907bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001908{
Jamie Madill78f41802014-08-25 15:47:55 -04001909 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001910}
1911
Austin Kinross08332632015-05-05 13:35:47 -07001912bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
1913 const GLenum *attachments, bool defaultFramebuffer)
1914{
1915 if (numAttachments < 0)
1916 {
1917 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
1918 return false;
1919 }
1920
1921 for (GLsizei i = 0; i < numAttachments; ++i)
1922 {
1923 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
1924 {
1925 if (defaultFramebuffer)
1926 {
1927 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1928 return false;
1929 }
1930
1931 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
1932 {
1933 context->recordError(Error(GL_INVALID_OPERATION,
1934 "Requested color attachment is greater than the maximum supported color attachments"));
1935 return false;
1936 }
1937 }
1938 else
1939 {
1940 switch (attachments[i])
1941 {
1942 case GL_DEPTH_ATTACHMENT:
1943 case GL_STENCIL_ATTACHMENT:
1944 case GL_DEPTH_STENCIL_ATTACHMENT:
1945 if (defaultFramebuffer)
1946 {
1947 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1948 return false;
1949 }
1950 break;
1951 case GL_COLOR:
1952 case GL_DEPTH:
1953 case GL_STENCIL:
1954 if (!defaultFramebuffer)
1955 {
1956 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
1957 return false;
1958 }
1959 break;
1960 default:
1961 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
1962 return false;
1963 }
1964 }
1965 }
1966
1967 return true;
1968}
1969
Austin Kinross6ee1e782015-05-29 17:05:37 -07001970bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
1971{
1972 // Note that debug marker calls must not set error state
1973
1974 if (length < 0)
1975 {
1976 return false;
1977 }
1978
1979 if (marker == nullptr)
1980 {
1981 return false;
1982 }
1983
1984 return true;
1985}
1986
1987bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
1988{
1989 // Note that debug marker calls must not set error state
1990
1991 if (length < 0)
1992 {
1993 return false;
1994 }
1995
1996 if (length > 0 && marker == nullptr)
1997 {
1998 return false;
1999 }
2000
2001 return true;
2002}
2003
Geoff Langdcab33b2015-07-21 13:03:16 -04002004bool ValidateEGLImageTargetTexture2DOES(Context *context,
2005 egl::Display *display,
2006 GLenum target,
2007 egl::Image *image)
2008{
Geoff Lang4274f7d2015-08-05 23:07:38 +00002009 UNIMPLEMENTED();
Geoff Langdcab33b2015-07-21 13:03:16 -04002010 return true;
2011}
2012
2013bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2014 egl::Display *display,
2015 GLenum target,
2016 egl::Image *image)
2017{
Geoff Lang4274f7d2015-08-05 23:07:38 +00002018 UNIMPLEMENTED();
Geoff Langdcab33b2015-07-21 13:03:16 -04002019 return true;
2020}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002021}