blob: 4ddc9e48fc2d061532bd6d30ea8d88a2cc975605 [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"
22#include "libANGLE/renderer/BufferImpl.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040023
24#include "common/mathutil.h"
25#include "common/utilities.h"
26
27namespace gl
28{
29
Geoff Lang0550d032014-01-30 11:29:07 -050030bool ValidCap(const Context *context, GLenum cap)
31{
32 switch (cap)
33 {
34 case GL_CULL_FACE:
35 case GL_POLYGON_OFFSET_FILL:
36 case GL_SAMPLE_ALPHA_TO_COVERAGE:
37 case GL_SAMPLE_COVERAGE:
38 case GL_SCISSOR_TEST:
39 case GL_STENCIL_TEST:
40 case GL_DEPTH_TEST:
41 case GL_BLEND:
42 case GL_DITHER:
43 return true;
44 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
45 case GL_RASTERIZER_DISCARD:
46 return (context->getClientVersion() >= 3);
47 default:
48 return false;
49 }
50}
51
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050052bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040053{
Jamie Madilld7460c72014-01-21 16:38:14 -050054 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040055 {
Jamie Madilld7460c72014-01-21 16:38:14 -050056 case GL_TEXTURE_2D:
57 case GL_TEXTURE_CUBE_MAP:
58 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040059
Jamie Madilld7460c72014-01-21 16:38:14 -050060 case GL_TEXTURE_3D:
61 case GL_TEXTURE_2D_ARRAY:
62 return (context->getClientVersion() >= 3);
63
64 default:
65 return false;
66 }
Jamie Madill35d15012013-10-07 10:46:37 -040067}
68
Shannon Woods4dfed832014-03-17 20:03:39 -040069// This function differs from ValidTextureTarget in that the target must be
70// usable as the destination of a 2D operation-- so a cube face is valid, but
71// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040072// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040073bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
74{
75 switch (target)
76 {
77 case GL_TEXTURE_2D:
78 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
84 return true;
85 case GL_TEXTURE_2D_ARRAY:
86 case GL_TEXTURE_3D:
87 return (context->getClientVersion() >= 3);
88 default:
89 return false;
90 }
91}
92
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050093bool ValidFramebufferTarget(GLenum target)
94{
Geoff Langd4475812015-03-18 10:53:05 -040095 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
96 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050097
98 switch (target)
99 {
100 case GL_FRAMEBUFFER: return true;
101 case GL_READ_FRAMEBUFFER: return true;
102 case GL_DRAW_FRAMEBUFFER: return true;
103 default: return false;
104 }
105}
106
Jamie Madill8c96d582014-03-05 15:01:23 -0500107bool ValidBufferTarget(const Context *context, GLenum target)
108{
109 switch (target)
110 {
111 case GL_ARRAY_BUFFER:
112 case GL_ELEMENT_ARRAY_BUFFER:
113 return true;
114
Jamie Madill8c96d582014-03-05 15:01:23 -0500115 case GL_PIXEL_PACK_BUFFER:
116 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400117 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400118
Shannon Woodsb3801742014-03-27 14:59:19 -0400119 case GL_COPY_READ_BUFFER:
120 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500121 case GL_TRANSFORM_FEEDBACK_BUFFER:
122 case GL_UNIFORM_BUFFER:
123 return (context->getClientVersion() >= 3);
124
125 default:
126 return false;
127 }
128}
129
Jamie Madill70656a62014-03-05 15:01:26 -0500130bool ValidBufferParameter(const Context *context, GLenum pname)
131{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400132 const Extensions &extensions = context->getExtensions();
133
Jamie Madill70656a62014-03-05 15:01:26 -0500134 switch (pname)
135 {
136 case GL_BUFFER_USAGE:
137 case GL_BUFFER_SIZE:
138 return true;
139
Geoff Langcc6f55d2015-03-20 13:01:02 -0400140 case GL_BUFFER_ACCESS_OES:
141 return extensions.mapBuffer;
142
143 case GL_BUFFER_MAPPED:
144 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
145 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
146
Jamie Madill70656a62014-03-05 15:01:26 -0500147 // GL_BUFFER_MAP_POINTER is a special case, and may only be
148 // queried with GetBufferPointerv
149 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500150 case GL_BUFFER_MAP_OFFSET:
151 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400152 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500153
154 default:
155 return false;
156 }
157}
158
Jamie Madill8c96d582014-03-05 15:01:23 -0500159bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400160{
Geoff Langaae65a42014-05-26 12:43:44 -0400161 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400162 switch (target)
163 {
Geoff Langaae65a42014-05-26 12:43:44 -0400164 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400165 case GL_TEXTURE_CUBE_MAP:
166 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
167 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
168 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
169 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
170 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400171 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
172 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
173 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400174 default: UNREACHABLE();
175 }
176
Geoff Langaae65a42014-05-26 12:43:44 -0400177 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400178}
179
Geoff Langb1196682014-07-23 13:47:29 -0400180bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400181 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400182{
183 if (level < 0 || width < 0 || height < 0 || depth < 0)
184 {
185 return false;
186 }
187
Geoff Langc0b9ef42014-07-02 10:02:37 -0400188 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400189 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400190 {
191 return false;
192 }
193
194 if (!ValidMipLevel(context, target, level))
195 {
196 return false;
197 }
198
199 return true;
200}
201
Geoff Langb1196682014-07-23 13:47:29 -0400202bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400203{
Geoff Lang5d601382014-07-22 15:14:06 -0400204 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
205 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400206 {
207 return false;
208 }
209
Geoff Lang5d601382014-07-22 15:14:06 -0400210 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
211 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400212 {
213 return false;
214 }
215
216 return true;
217}
218
Geoff Lang37dde692014-01-31 16:34:54 -0500219bool ValidQueryType(const Context *context, GLenum queryType)
220{
Geoff Langd4475812015-03-18 10:53:05 -0400221 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
222 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 -0500223
224 switch (queryType)
225 {
226 case GL_ANY_SAMPLES_PASSED:
227 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
228 return true;
229 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
230 return (context->getClientVersion() >= 3);
231 default:
232 return false;
233 }
234}
235
Geoff Langb1196682014-07-23 13:47:29 -0400236bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500237{
238 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
239 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
240 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
241
242 if (context->getProgram(id) != NULL)
243 {
244 return true;
245 }
246 else if (context->getShader(id) != NULL)
247 {
248 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400249 context->recordError(Error(GL_INVALID_OPERATION));
250 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500251 }
252 else
253 {
254 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400255 context->recordError(Error(GL_INVALID_VALUE));
256 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500257 }
258}
259
Geoff Langb1196682014-07-23 13:47:29 -0400260bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400261{
262 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
263 {
264 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
265
Geoff Langaae65a42014-05-26 12:43:44 -0400266 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400267 {
Geoff Langb1196682014-07-23 13:47:29 -0400268 context->recordError(Error(GL_INVALID_VALUE));
269 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400270 }
271 }
272 else
273 {
274 switch (attachment)
275 {
276 case GL_DEPTH_ATTACHMENT:
277 case GL_STENCIL_ATTACHMENT:
278 break;
279
280 case GL_DEPTH_STENCIL_ATTACHMENT:
281 if (context->getClientVersion() < 3)
282 {
Geoff Langb1196682014-07-23 13:47:29 -0400283 context->recordError(Error(GL_INVALID_ENUM));
284 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400285 }
286 break;
287
288 default:
Geoff Langb1196682014-07-23 13:47:29 -0400289 context->recordError(Error(GL_INVALID_ENUM));
290 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400291 }
292 }
293
294 return true;
295}
296
Corentin Walleze0902642014-11-04 12:32:15 -0800297bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
298 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400299{
300 switch (target)
301 {
302 case GL_RENDERBUFFER:
303 break;
304 default:
Geoff Langb1196682014-07-23 13:47:29 -0400305 context->recordError(Error(GL_INVALID_ENUM));
306 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400307 }
308
309 if (width < 0 || height < 0 || samples < 0)
310 {
Geoff Langb1196682014-07-23 13:47:29 -0400311 context->recordError(Error(GL_INVALID_VALUE));
312 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400313 }
314
Geoff Langd87878e2014-09-19 15:42:59 -0400315 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
316 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400317 {
Geoff Langb1196682014-07-23 13:47:29 -0400318 context->recordError(Error(GL_INVALID_ENUM));
319 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400320 }
321
322 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
323 // 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 -0800324 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400325 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400326 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400327 {
Geoff Langb1196682014-07-23 13:47:29 -0400328 context->recordError(Error(GL_INVALID_ENUM));
329 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400330 }
331
Geoff Langaae65a42014-05-26 12:43:44 -0400332 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400333 {
Geoff Langb1196682014-07-23 13:47:29 -0400334 context->recordError(Error(GL_INVALID_VALUE));
335 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400336 }
337
Shannon Woods53a94a82014-06-24 15:20:36 -0400338 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400339 if (handle == 0)
340 {
Geoff Langb1196682014-07-23 13:47:29 -0400341 context->recordError(Error(GL_INVALID_OPERATION));
342 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400343 }
344
345 return true;
346}
347
Corentin Walleze0902642014-11-04 12:32:15 -0800348bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
349 GLenum internalformat, GLsizei width, GLsizei height)
350{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800351 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800352
353 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400354 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800355 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400356 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800357 {
358 context->recordError(Error(GL_INVALID_VALUE));
359 return false;
360 }
361
362 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
363 // the specified storage. This is different than ES 3.0 in which a sample number higher
364 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800365 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
366 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800367 {
Geoff Langa4903b72015-03-02 16:02:48 -0800368 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
369 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
370 {
371 context->recordError(Error(GL_OUT_OF_MEMORY));
372 return false;
373 }
Corentin Walleze0902642014-11-04 12:32:15 -0800374 }
375
376 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
377}
378
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500379bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
380 GLenum renderbuffertarget, GLuint renderbuffer)
381{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400382 if (!ValidFramebufferTarget(target))
383 {
Geoff Langb1196682014-07-23 13:47:29 -0400384 context->recordError(Error(GL_INVALID_ENUM));
385 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400386 }
387
Shannon Woods53a94a82014-06-24 15:20:36 -0400388 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500389
Jamie Madill84115c92015-04-23 15:00:07 -0400390 ASSERT(framebuffer);
391 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500392 {
Jamie Madill84115c92015-04-23 15:00:07 -0400393 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400394 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500395 }
396
Jamie Madillb4472272014-07-03 10:38:55 -0400397 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500398 {
Jamie Madillb4472272014-07-03 10:38:55 -0400399 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500400 }
401
Jamie Madillab9d82c2014-01-21 16:38:14 -0500402 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
403 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
404 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
405 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
406 if (renderbuffer != 0)
407 {
408 if (!context->getRenderbuffer(renderbuffer))
409 {
Geoff Langb1196682014-07-23 13:47:29 -0400410 context->recordError(Error(GL_INVALID_OPERATION));
411 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500412 }
413 }
414
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500415 return true;
416}
417
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400418static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400419 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
420 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
421{
422 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
423 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
424 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
425 {
426 return true;
427 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400428 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400429 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400430 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400431
Shannon Woods53a94a82014-06-24 15:20:36 -0400432 return scissor.x > 0 || scissor.y > 0 ||
433 scissor.width < writeBuffer->getWidth() ||
434 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400435 }
436 else
437 {
438 return false;
439 }
440}
441
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400442bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400443 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
444 GLenum filter, bool fromAngleExtension)
445{
446 switch (filter)
447 {
448 case GL_NEAREST:
449 break;
450 case GL_LINEAR:
451 if (fromAngleExtension)
452 {
Geoff Langb1196682014-07-23 13:47:29 -0400453 context->recordError(Error(GL_INVALID_ENUM));
454 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400455 }
456 break;
457 default:
Geoff Langb1196682014-07-23 13:47:29 -0400458 context->recordError(Error(GL_INVALID_ENUM));
459 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400460 }
461
462 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
463 {
Geoff Langb1196682014-07-23 13:47:29 -0400464 context->recordError(Error(GL_INVALID_VALUE));
465 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400466 }
467
468 if (mask == 0)
469 {
470 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
471 // buffers are copied.
472 return false;
473 }
474
475 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
476 {
477 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400478 context->recordError(Error(GL_INVALID_OPERATION));
479 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400480 }
481
482 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
483 // color buffer, leaving only nearest being unfiltered from above
484 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
485 {
Geoff Langb1196682014-07-23 13:47:29 -0400486 context->recordError(Error(GL_INVALID_OPERATION));
487 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488 }
489
Shannon Woods53a94a82014-06-24 15:20:36 -0400490 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400491 {
492 if (fromAngleExtension)
493 {
494 ERR("Blits with the same source and destination framebuffer are not supported by this "
495 "implementation.");
496 }
Geoff Langb1196682014-07-23 13:47:29 -0400497 context->recordError(Error(GL_INVALID_OPERATION));
498 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400499 }
500
Jamie Madill34771622015-04-21 13:54:34 +0000501 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
502 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500503
504 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 {
Geoff Langb1196682014-07-23 13:47:29 -0400506 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
507 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400508 }
509
Geoff Lang748f74e2014-12-01 11:25:34 -0500510 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500511 {
512 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
513 return false;
514 }
515
Geoff Lang748f74e2014-12-01 11:25:34 -0500516 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500517 {
518 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
519 return false;
520 }
521
522 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400523 {
Geoff Langb1196682014-07-23 13:47:29 -0400524 context->recordError(Error(GL_INVALID_OPERATION));
525 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526 }
527
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400528 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
529
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400530 if (mask & GL_COLOR_BUFFER_BIT)
531 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400532 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
533 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400534
535 if (readColorBuffer && drawColorBuffer)
536 {
Geoff Langd8a22582014-12-17 15:28:23 -0500537 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400538 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400539
Jamie Madill0af26e12015-03-05 19:54:33 -0500540 for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400541 {
542 if (drawFramebuffer->isEnabledColorAttachment(i))
543 {
Geoff Langd8a22582014-12-17 15:28:23 -0500544 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400545 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400546
Geoff Langb2f3d052013-08-13 12:49:27 -0400547 // The GL ES 3.0.2 spec (pg 193) states that:
548 // 1) If the read buffer is fixed point format, the draw buffer must be as well
549 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
550 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400551 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
552 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 {
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
Geoff Lang5d601382014-07-22 15:14:06 -0400558 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400559 {
Geoff Langb1196682014-07-23 13:47:29 -0400560 context->recordError(Error(GL_INVALID_OPERATION));
561 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400562 }
563
Geoff Lang5d601382014-07-22 15:14:06 -0400564 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400565 {
Geoff Langb1196682014-07-23 13:47:29 -0400566 context->recordError(Error(GL_INVALID_OPERATION));
567 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400568 }
569
Geoff Langb2f3d052013-08-13 12:49:27 -0400570 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400571 {
Geoff Langb1196682014-07-23 13:47:29 -0400572 context->recordError(Error(GL_INVALID_OPERATION));
573 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400574 }
575 }
576 }
577
Geoff Lang5d601382014-07-22 15:14:06 -0400578 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400579 {
Geoff Langb1196682014-07-23 13:47:29 -0400580 context->recordError(Error(GL_INVALID_OPERATION));
581 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400582 }
583
584 if (fromAngleExtension)
585 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400586 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500587 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400588 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500589 readColorAttachment->type() != GL_RENDERBUFFER &&
590 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
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
Jamie Madill0af26e12015-03-05 19:54:33 -0500596 for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400597 {
598 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
599 {
Jamie Madill34771622015-04-21 13:54:34 +0000600 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400601 ASSERT(attachment);
602
Jamie Madill8cf4a392015-04-02 11:36:04 -0400603 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500604 attachment->type() != GL_RENDERBUFFER &&
605 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606 {
Geoff Langb1196682014-07-23 13:47:29 -0400607 context->recordError(Error(GL_INVALID_OPERATION));
608 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400609 }
610
Jamie Madillf8f18f02014-10-02 10:44:17 -0400611 // Return an error if the destination formats do not match
612 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613 {
Geoff Langb1196682014-07-23 13:47:29 -0400614 context->recordError(Error(GL_INVALID_OPERATION));
615 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 }
617 }
618 }
Jamie Madill48faf802014-11-06 15:27:22 -0500619
620 int readSamples = readFramebuffer->getSamples(context->getData());
621
622 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
623 srcX0, srcY0, srcX1, srcY1,
624 dstX0, dstY0, dstX1, dstY1))
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 }
630 }
631 }
632
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200633 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
634 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
635 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200637 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400638 {
Jamie Madillaed081c2015-04-21 13:55:21 +0000639 gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
640 gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400641
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200642 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 {
Geoff Langd8a22582014-12-17 15:28:23 -0500644 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
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 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200650 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 {
Geoff Langb1196682014-07-23 13:47:29 -0400652 context->recordError(Error(GL_INVALID_OPERATION));
653 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400654 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200655
656 if (fromAngleExtension)
657 {
658 if (IsPartialBlit(context, readBuffer, drawBuffer,
659 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
660 {
661 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
662 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
663 return false;
664 }
665
666 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
667 {
668 context->recordError(Error(GL_INVALID_OPERATION));
669 return false;
670 }
671 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 }
673 }
674 }
675
676 return true;
677}
678
Geoff Langb1196682014-07-23 13:47:29 -0400679bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400680{
681 switch (pname)
682 {
683 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
684 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
685 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
686 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
687 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
688 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
689 case GL_CURRENT_VERTEX_ATTRIB:
690 return true;
691
692 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
693 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
694 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400695 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
696 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400697 return true;
698
699 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400700 if (context->getClientVersion() < 3)
701 {
702 context->recordError(Error(GL_INVALID_ENUM));
703 return false;
704 }
705 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706
707 default:
Geoff Langb1196682014-07-23 13:47:29 -0400708 context->recordError(Error(GL_INVALID_ENUM));
709 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710 }
711}
712
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400713bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400714{
715 switch (pname)
716 {
717 case GL_TEXTURE_WRAP_R:
718 case GL_TEXTURE_SWIZZLE_R:
719 case GL_TEXTURE_SWIZZLE_G:
720 case GL_TEXTURE_SWIZZLE_B:
721 case GL_TEXTURE_SWIZZLE_A:
722 case GL_TEXTURE_BASE_LEVEL:
723 case GL_TEXTURE_MAX_LEVEL:
724 case GL_TEXTURE_COMPARE_MODE:
725 case GL_TEXTURE_COMPARE_FUNC:
726 case GL_TEXTURE_MIN_LOD:
727 case GL_TEXTURE_MAX_LOD:
728 if (context->getClientVersion() < 3)
729 {
Geoff Langb1196682014-07-23 13:47:29 -0400730 context->recordError(Error(GL_INVALID_ENUM));
731 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 }
733 break;
734
735 default: break;
736 }
737
738 switch (pname)
739 {
740 case GL_TEXTURE_WRAP_S:
741 case GL_TEXTURE_WRAP_T:
742 case GL_TEXTURE_WRAP_R:
743 switch (param)
744 {
745 case GL_REPEAT:
746 case GL_CLAMP_TO_EDGE:
747 case GL_MIRRORED_REPEAT:
748 return true;
749 default:
Geoff Langb1196682014-07-23 13:47:29 -0400750 context->recordError(Error(GL_INVALID_ENUM));
751 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400752 }
753
754 case GL_TEXTURE_MIN_FILTER:
755 switch (param)
756 {
757 case GL_NEAREST:
758 case GL_LINEAR:
759 case GL_NEAREST_MIPMAP_NEAREST:
760 case GL_LINEAR_MIPMAP_NEAREST:
761 case GL_NEAREST_MIPMAP_LINEAR:
762 case GL_LINEAR_MIPMAP_LINEAR:
763 return true;
764 default:
Geoff Langb1196682014-07-23 13:47:29 -0400765 context->recordError(Error(GL_INVALID_ENUM));
766 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 }
768 break;
769
770 case GL_TEXTURE_MAG_FILTER:
771 switch (param)
772 {
773 case GL_NEAREST:
774 case GL_LINEAR:
775 return true;
776 default:
Geoff Langb1196682014-07-23 13:47:29 -0400777 context->recordError(Error(GL_INVALID_ENUM));
778 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 }
780 break;
781
782 case GL_TEXTURE_USAGE_ANGLE:
783 switch (param)
784 {
785 case GL_NONE:
786 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
787 return true;
788 default:
Geoff Langb1196682014-07-23 13:47:29 -0400789 context->recordError(Error(GL_INVALID_ENUM));
790 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 }
792 break;
793
794 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400795 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796 {
Geoff Langb1196682014-07-23 13:47:29 -0400797 context->recordError(Error(GL_INVALID_ENUM));
798 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400799 }
800
801 // we assume the parameter passed to this validation method is truncated, not rounded
802 if (param < 1)
803 {
Geoff Langb1196682014-07-23 13:47:29 -0400804 context->recordError(Error(GL_INVALID_VALUE));
805 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 }
807 return true;
808
809 case GL_TEXTURE_MIN_LOD:
810 case GL_TEXTURE_MAX_LOD:
811 // any value is permissible
812 return true;
813
814 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400815 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400816 switch (param)
817 {
818 case GL_NONE:
819 case GL_COMPARE_REF_TO_TEXTURE:
820 return true;
821 default:
Geoff Langb1196682014-07-23 13:47:29 -0400822 context->recordError(Error(GL_INVALID_ENUM));
823 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400824 }
825 break;
826
827 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400828 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829 switch (param)
830 {
831 case GL_LEQUAL:
832 case GL_GEQUAL:
833 case GL_LESS:
834 case GL_GREATER:
835 case GL_EQUAL:
836 case GL_NOTEQUAL:
837 case GL_ALWAYS:
838 case GL_NEVER:
839 return true;
840 default:
Geoff Langb1196682014-07-23 13:47:29 -0400841 context->recordError(Error(GL_INVALID_ENUM));
842 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400843 }
844 break;
845
846 case GL_TEXTURE_SWIZZLE_R:
847 case GL_TEXTURE_SWIZZLE_G:
848 case GL_TEXTURE_SWIZZLE_B:
849 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400850 switch (param)
851 {
852 case GL_RED:
853 case GL_GREEN:
854 case GL_BLUE:
855 case GL_ALPHA:
856 case GL_ZERO:
857 case GL_ONE:
858 return true;
859 default:
Geoff Langb1196682014-07-23 13:47:29 -0400860 context->recordError(Error(GL_INVALID_ENUM));
861 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400862 }
863 break;
864
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400865 case GL_TEXTURE_BASE_LEVEL:
866 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400867 if (param < 0)
868 {
Geoff Langb1196682014-07-23 13:47:29 -0400869 context->recordError(Error(GL_INVALID_VALUE));
870 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400871 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400872 return true;
873
874 default:
Geoff Langb1196682014-07-23 13:47:29 -0400875 context->recordError(Error(GL_INVALID_ENUM));
876 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877 }
878}
879
Geoff Langb1196682014-07-23 13:47:29 -0400880bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400881{
882 switch (pname)
883 {
884 case GL_TEXTURE_MIN_FILTER:
885 case GL_TEXTURE_MAG_FILTER:
886 case GL_TEXTURE_WRAP_S:
887 case GL_TEXTURE_WRAP_T:
888 case GL_TEXTURE_WRAP_R:
889 case GL_TEXTURE_MIN_LOD:
890 case GL_TEXTURE_MAX_LOD:
891 case GL_TEXTURE_COMPARE_MODE:
892 case GL_TEXTURE_COMPARE_FUNC:
893 return true;
894
895 default:
Geoff Langb1196682014-07-23 13:47:29 -0400896 context->recordError(Error(GL_INVALID_ENUM));
897 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400898 }
899}
900
Jamie Madill26e91952014-03-05 15:01:27 -0500901bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
902 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
903{
Shannon Woods53a94a82014-06-24 15:20:36 -0400904 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400905 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500906
Geoff Lang748f74e2014-12-01 11:25:34 -0500907 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500908 {
Geoff Langb1196682014-07-23 13:47:29 -0400909 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
910 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500911 }
912
Jamie Madill48faf802014-11-06 15:27:22 -0500913 if (context->getState().getReadFramebuffer()->id() != 0 &&
914 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500915 {
Geoff Langb1196682014-07-23 13:47:29 -0400916 context->recordError(Error(GL_INVALID_OPERATION));
917 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500918 }
919
Geoff Langbce529e2014-12-01 12:48:41 -0500920 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
921 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400922 {
Geoff Langb1196682014-07-23 13:47:29 -0400923 context->recordError(Error(GL_INVALID_OPERATION));
924 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400925 }
926
Geoff Langbce529e2014-12-01 12:48:41 -0500927 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
928 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500929 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400930 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500931
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400932 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
933 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500934
935 if (!(currentFormat == format && currentType == type) && !validReadFormat)
936 {
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_OPERATION));
938 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500939 }
940
Geoff Lang5d601382014-07-22 15:14:06 -0400941 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
942 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500943
Minmin Gongb8aee3b2015-01-27 14:42:36 -0800944 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -0500945 // sized query sanity check
946 if (bufSize)
947 {
948 int requiredSize = outputPitch * height;
949 if (requiredSize > *bufSize)
950 {
Geoff Langb1196682014-07-23 13:47:29 -0400951 context->recordError(Error(GL_INVALID_OPERATION));
952 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500953 }
954 }
955
956 return true;
957}
958
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400959bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
960{
961 if (!ValidQueryType(context, target))
962 {
Geoff Langb1196682014-07-23 13:47:29 -0400963 context->recordError(Error(GL_INVALID_ENUM));
964 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400965 }
966
967 if (id == 0)
968 {
Geoff Langb1196682014-07-23 13:47:29 -0400969 context->recordError(Error(GL_INVALID_OPERATION));
970 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400971 }
972
973 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
974 // of zero, if the active query object name for <target> is non-zero (for the
975 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
976 // the active query for either target is non-zero), if <id> is the name of an
977 // existing query object whose type does not match <target>, or if <id> is the
978 // active query object name for any query type, the error INVALID_OPERATION is
979 // generated.
980
981 // Ensure no other queries are active
982 // NOTE: If other queries than occlusion are supported, we will need to check
983 // separately that:
984 // a) The query ID passed is not the current active query for any target/type
985 // b) There are no active queries for the requested target (and in the case
986 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
987 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400988 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400989 {
Geoff Langb1196682014-07-23 13:47:29 -0400990 context->recordError(Error(GL_INVALID_OPERATION));
991 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400992 }
993
994 Query *queryObject = context->getQuery(id, true, target);
995
996 // check that name was obtained with glGenQueries
997 if (!queryObject)
998 {
Geoff Langb1196682014-07-23 13:47:29 -0400999 context->recordError(Error(GL_INVALID_OPERATION));
1000 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001001 }
1002
1003 // check for type mismatch
1004 if (queryObject->getType() != target)
1005 {
Geoff Langb1196682014-07-23 13:47:29 -04001006 context->recordError(Error(GL_INVALID_OPERATION));
1007 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001008 }
1009
1010 return true;
1011}
1012
Jamie Madill45c785d2014-05-13 14:09:34 -04001013bool ValidateEndQuery(gl::Context *context, GLenum target)
1014{
1015 if (!ValidQueryType(context, target))
1016 {
Geoff Langb1196682014-07-23 13:47:29 -04001017 context->recordError(Error(GL_INVALID_ENUM));
1018 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001019 }
1020
Shannon Woods53a94a82014-06-24 15:20:36 -04001021 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001022
1023 if (queryObject == NULL)
1024 {
Geoff Langb1196682014-07-23 13:47:29 -04001025 context->recordError(Error(GL_INVALID_OPERATION));
1026 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001027 }
1028
Jamie Madill45c785d2014-05-13 14:09:34 -04001029 return true;
1030}
1031
Jamie Madill36398922014-05-20 14:51:53 -04001032static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1033 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001034{
1035 if (count < 0)
1036 {
Geoff Langb1196682014-07-23 13:47:29 -04001037 context->recordError(Error(GL_INVALID_VALUE));
1038 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001039 }
1040
Geoff Lang7dd2e102014-11-10 15:19:26 -05001041 gl::Program *program = context->getState().getProgram();
1042 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001043 {
Geoff Langb1196682014-07-23 13:47:29 -04001044 context->recordError(Error(GL_INVALID_OPERATION));
1045 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001046 }
1047
1048 if (location == -1)
1049 {
1050 // Silently ignore the uniform command
1051 return false;
1052 }
1053
Geoff Lang7dd2e102014-11-10 15:19:26 -05001054 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001055 {
Geoff Langb1196682014-07-23 13:47:29 -04001056 context->recordError(Error(GL_INVALID_OPERATION));
1057 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001058 }
1059
Geoff Lang7dd2e102014-11-10 15:19:26 -05001060 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001061
1062 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1063 if (uniform->elementCount() == 1 && count > 1)
1064 {
Geoff Langb1196682014-07-23 13:47:29 -04001065 context->recordError(Error(GL_INVALID_OPERATION));
1066 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001067 }
1068
1069 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001070 return true;
1071}
1072
Jamie Madillaa981bd2014-05-20 10:55:55 -04001073bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1074{
1075 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001076 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001077 {
Geoff Langb1196682014-07-23 13:47:29 -04001078 context->recordError(Error(GL_INVALID_OPERATION));
1079 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001080 }
1081
Jamie Madill36398922014-05-20 14:51:53 -04001082 LinkedUniform *uniform = NULL;
1083 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1084 {
1085 return false;
1086 }
1087
Jamie Madillf2575982014-06-25 16:04:54 -04001088 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001089 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001090 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1091 {
Geoff Langb1196682014-07-23 13:47:29 -04001092 context->recordError(Error(GL_INVALID_OPERATION));
1093 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001094 }
1095
1096 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001097}
1098
1099bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1100 GLboolean transpose)
1101{
1102 // Check for ES3 uniform entry points
1103 int rows = VariableRowCount(matrixType);
1104 int cols = VariableColumnCount(matrixType);
1105 if (rows != cols && context->getClientVersion() < 3)
1106 {
Geoff Langb1196682014-07-23 13:47:29 -04001107 context->recordError(Error(GL_INVALID_OPERATION));
1108 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001109 }
1110
1111 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1112 {
Geoff Langb1196682014-07-23 13:47:29 -04001113 context->recordError(Error(GL_INVALID_VALUE));
1114 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001115 }
1116
Jamie Madill36398922014-05-20 14:51:53 -04001117 LinkedUniform *uniform = NULL;
1118 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1119 {
1120 return false;
1121 }
1122
1123 if (uniform->type != matrixType)
1124 {
Geoff Langb1196682014-07-23 13:47:29 -04001125 context->recordError(Error(GL_INVALID_OPERATION));
1126 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001127 }
1128
1129 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001130}
1131
Jamie Madill893ab082014-05-16 16:56:10 -04001132bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1133{
1134 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1135 {
Geoff Langb1196682014-07-23 13:47:29 -04001136 context->recordError(Error(GL_INVALID_ENUM));
1137 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001138 }
1139
Jamie Madill0af26e12015-03-05 19:54:33 -05001140 const Caps &caps = context->getCaps();
1141
Jamie Madill893ab082014-05-16 16:56:10 -04001142 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1143 {
1144 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1145
Jamie Madill0af26e12015-03-05 19:54:33 -05001146 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001147 {
Geoff Langb1196682014-07-23 13:47:29 -04001148 context->recordError(Error(GL_INVALID_OPERATION));
1149 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001150 }
1151 }
1152
1153 switch (pname)
1154 {
1155 case GL_TEXTURE_BINDING_2D:
1156 case GL_TEXTURE_BINDING_CUBE_MAP:
1157 case GL_TEXTURE_BINDING_3D:
1158 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001159 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001160 {
Geoff Langb1196682014-07-23 13:47:29 -04001161 context->recordError(Error(GL_INVALID_OPERATION));
1162 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001163 }
1164 break;
1165
1166 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1167 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1168 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001169 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001170 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001171 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001172 {
Geoff Langb1196682014-07-23 13:47:29 -04001173 context->recordError(Error(GL_INVALID_OPERATION));
1174 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001175 }
1176
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001177 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001178 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001179 {
Geoff Langb1196682014-07-23 13:47:29 -04001180 context->recordError(Error(GL_INVALID_OPERATION));
1181 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001182 }
1183 }
1184 break;
1185
1186 default:
1187 break;
1188 }
1189
1190 // pname is valid, but there are no parameters to return
1191 if (numParams == 0)
1192 {
1193 return false;
1194 }
1195
1196 return true;
1197}
1198
Jamie Madill560a8d82014-05-21 13:06:20 -04001199bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1200 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1201 GLint border, GLenum *textureFormatOut)
1202{
1203
1204 if (!ValidTexture2DDestinationTarget(context, target))
1205 {
Geoff Langb1196682014-07-23 13:47:29 -04001206 context->recordError(Error(GL_INVALID_ENUM));
1207 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001208 }
1209
1210 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1211 {
Geoff Langb1196682014-07-23 13:47:29 -04001212 context->recordError(Error(GL_INVALID_VALUE));
1213 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001214 }
1215
1216 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1217 {
Geoff Langb1196682014-07-23 13:47:29 -04001218 context->recordError(Error(GL_INVALID_VALUE));
1219 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001220 }
1221
1222 if (border != 0)
1223 {
Geoff Langb1196682014-07-23 13:47:29 -04001224 context->recordError(Error(GL_INVALID_VALUE));
1225 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001226 }
1227
1228 if (!ValidMipLevel(context, target, level))
1229 {
Geoff Langb1196682014-07-23 13:47:29 -04001230 context->recordError(Error(GL_INVALID_VALUE));
1231 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001232 }
1233
Shannon Woods53a94a82014-06-24 15:20:36 -04001234 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001235 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001236 {
Geoff Langb1196682014-07-23 13:47:29 -04001237 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1238 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001239 }
1240
Jamie Madill48faf802014-11-06 15:27:22 -05001241 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001242 {
Geoff Langb1196682014-07-23 13:47:29 -04001243 context->recordError(Error(GL_INVALID_OPERATION));
1244 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001245 }
1246
Geoff Langaae65a42014-05-26 12:43:44 -04001247 const gl::Caps &caps = context->getCaps();
1248
Geoff Langaae65a42014-05-26 12:43:44 -04001249 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001250 switch (target)
1251 {
1252 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001253 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001254 break;
1255
1256 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1257 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1258 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1259 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1260 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1261 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001262 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001263 break;
1264
1265 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001266 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001267 break;
1268
1269 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001270 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001271 break;
1272
1273 default:
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
Geoff Lang691e58c2014-12-19 17:03:25 -05001278 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001279 if (!texture)
1280 {
Geoff Langb1196682014-07-23 13:47:29 -04001281 context->recordError(Error(GL_INVALID_OPERATION));
1282 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001283 }
1284
1285 if (texture->isImmutable() && !isSubImage)
1286 {
Geoff Langb1196682014-07-23 13:47:29 -04001287 context->recordError(Error(GL_INVALID_OPERATION));
1288 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001289 }
1290
Geoff Lang5d601382014-07-22 15:14:06 -04001291 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1292
1293 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001294 {
Geoff Langb1196682014-07-23 13:47:29 -04001295 context->recordError(Error(GL_INVALID_OPERATION));
1296 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001297 }
1298
Geoff Langa9be0dc2014-12-17 12:34:40 -05001299 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001300 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001301 context->recordError(Error(GL_INVALID_OPERATION));
1302 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001303 }
1304
1305 if (isSubImage)
1306 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001307 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1308 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1309 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001310 {
Geoff Langb1196682014-07-23 13:47:29 -04001311 context->recordError(Error(GL_INVALID_VALUE));
1312 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001313 }
1314 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001315 else
1316 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001317 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001318 {
Geoff Langb1196682014-07-23 13:47:29 -04001319 context->recordError(Error(GL_INVALID_VALUE));
1320 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001321 }
1322
Geoff Lang5d601382014-07-22 15:14:06 -04001323 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001324 {
Geoff Langb1196682014-07-23 13:47:29 -04001325 context->recordError(Error(GL_INVALID_ENUM));
1326 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001327 }
1328
1329 int maxLevelDimension = (maxDimension >> level);
1330 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1331 {
Geoff Langb1196682014-07-23 13:47:29 -04001332 context->recordError(Error(GL_INVALID_VALUE));
1333 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001334 }
1335 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001336
Geoff Langa9be0dc2014-12-17 12:34:40 -05001337 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001338 return true;
1339}
1340
Geoff Langb1196682014-07-23 13:47:29 -04001341static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001342{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001343 switch (mode)
1344 {
1345 case GL_POINTS:
1346 case GL_LINES:
1347 case GL_LINE_LOOP:
1348 case GL_LINE_STRIP:
1349 case GL_TRIANGLES:
1350 case GL_TRIANGLE_STRIP:
1351 case GL_TRIANGLE_FAN:
1352 break;
1353 default:
Geoff Langb1196682014-07-23 13:47:29 -04001354 context->recordError(Error(GL_INVALID_ENUM));
1355 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001356 }
1357
Jamie Madill250d33f2014-06-06 17:09:03 -04001358 if (count < 0)
1359 {
Geoff Langb1196682014-07-23 13:47:29 -04001360 context->recordError(Error(GL_INVALID_VALUE));
1361 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001362 }
1363
Geoff Langb1196682014-07-23 13:47:29 -04001364 const State &state = context->getState();
1365
Jamie Madill250d33f2014-06-06 17:09:03 -04001366 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001367 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001368 {
Geoff Langb1196682014-07-23 13:47:29 -04001369 context->recordError(Error(GL_INVALID_OPERATION));
1370 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001371 }
1372
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001373 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001374 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001375 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001376 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1377 {
1378 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1379 // See Section 6.10 of the WebGL 1.0 spec
1380 ERR("This ANGLE implementation does not support separate front/back stencil "
1381 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001382 context->recordError(Error(GL_INVALID_OPERATION));
1383 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001384 }
1385
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001386 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001387 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001388 {
Geoff Langb1196682014-07-23 13:47:29 -04001389 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1390 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001391 }
1392
Geoff Lang7dd2e102014-11-10 15:19:26 -05001393 gl::Program *program = state.getProgram();
1394 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001395 {
Geoff Langb1196682014-07-23 13:47:29 -04001396 context->recordError(Error(GL_INVALID_OPERATION));
1397 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001398 }
1399
Geoff Lang7dd2e102014-11-10 15:19:26 -05001400 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001401 {
Geoff Langb1196682014-07-23 13:47:29 -04001402 context->recordError(Error(GL_INVALID_OPERATION));
1403 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001404 }
1405
Jamie Madill2b976812014-08-25 15:47:49 -04001406 // Buffer validations
1407 const VertexArray *vao = state.getVertexArray();
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001408 const auto &vertexAttribs = vao->getVertexAttributes();
1409 const int *semanticIndexes = program->getSemanticIndexes();
1410 for (size_t attributeIndex = 0; attributeIndex < vertexAttribs.size(); ++attributeIndex)
Jamie Madill2b976812014-08-25 15:47:49 -04001411 {
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001412 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
1413 bool attribActive = (semanticIndexes[attributeIndex] != -1);
Jamie Madill2b976812014-08-25 15:47:49 -04001414 if (attribActive && attrib.enabled)
1415 {
1416 gl::Buffer *buffer = attrib.buffer.get();
1417
1418 if (buffer)
1419 {
1420 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1421 GLint64 maxVertexElement = 0;
1422
1423 if (attrib.divisor > 0)
1424 {
1425 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1426 }
1427 else
1428 {
1429 maxVertexElement = static_cast<GLint64>(maxVertex);
1430 }
1431
1432 GLint64 attribDataSize = maxVertexElement * attribStride;
1433
1434 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1435 // We can return INVALID_OPERATION if our vertex attribute does not have
1436 // enough backing data.
1437 if (attribDataSize > buffer->getSize())
1438 {
Geoff Langb1196682014-07-23 13:47:29 -04001439 context->recordError(Error(GL_INVALID_OPERATION));
1440 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001441 }
1442 }
1443 else if (attrib.pointer == NULL)
1444 {
1445 // This is an application error that would normally result in a crash,
1446 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001447 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1448 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001449 }
1450 }
1451 }
1452
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001453 // Uniform buffer validation
1454 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1455 {
1456 const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
1457 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
1458 const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
1459
1460 if (!uniformBuffer)
1461 {
1462 // undefined behaviour
1463 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1464 return false;
1465 }
1466
1467 size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
1468
1469 if (uniformBufferSize == 0)
1470 {
1471 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001472 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001473 }
1474
1475 if (uniformBufferSize < uniformBlock->dataSize)
1476 {
1477 // undefined behaviour
1478 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1479 return false;
1480 }
1481 }
1482
Jamie Madill250d33f2014-06-06 17:09:03 -04001483 // No-op if zero count
1484 return (count > 0);
1485}
1486
Geoff Langb1196682014-07-23 13:47:29 -04001487bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001488{
Jamie Madillfd716582014-06-06 17:09:04 -04001489 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001490 {
Geoff Langb1196682014-07-23 13:47:29 -04001491 context->recordError(Error(GL_INVALID_VALUE));
1492 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001493 }
1494
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001495 const State &state = context->getState();
1496 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001497 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1498 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001499 {
1500 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1501 // that does not match the current transform feedback object's draw mode (if transform feedback
1502 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001503 context->recordError(Error(GL_INVALID_OPERATION));
1504 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001505 }
1506
Geoff Langb1196682014-07-23 13:47:29 -04001507 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001508 {
1509 return false;
1510 }
1511
1512 return true;
1513}
1514
Geoff Langb1196682014-07-23 13:47:29 -04001515bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001516{
1517 if (primcount < 0)
1518 {
Geoff Langb1196682014-07-23 13:47:29 -04001519 context->recordError(Error(GL_INVALID_VALUE));
1520 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001521 }
1522
Jamie Madill2b976812014-08-25 15:47:49 -04001523 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001524 {
1525 return false;
1526 }
1527
1528 // No-op if zero primitive count
1529 return (primcount > 0);
1530}
1531
Geoff Lang87a93302014-09-16 13:29:43 -04001532static bool ValidateDrawInstancedANGLE(Context *context)
1533{
1534 // Verify there is at least one active attribute with a divisor of zero
1535 const gl::State& state = context->getState();
1536
Geoff Lang7dd2e102014-11-10 15:19:26 -05001537 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001538
1539 const VertexArray *vao = state.getVertexArray();
1540 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1541 {
1542 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001543 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001544 if (active && attrib.divisor == 0)
1545 {
1546 return true;
1547 }
1548 }
1549
1550 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1551 "has a divisor of zero."));
1552 return false;
1553}
1554
1555bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1556{
1557 if (!ValidateDrawInstancedANGLE(context))
1558 {
1559 return false;
1560 }
1561
1562 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1563}
1564
Geoff Langb1196682014-07-23 13:47:29 -04001565bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001566 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001567{
Jamie Madill250d33f2014-06-06 17:09:03 -04001568 switch (type)
1569 {
1570 case GL_UNSIGNED_BYTE:
1571 case GL_UNSIGNED_SHORT:
1572 break;
1573 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001574 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001575 {
Geoff Langb1196682014-07-23 13:47:29 -04001576 context->recordError(Error(GL_INVALID_ENUM));
1577 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001578 }
1579 break;
1580 default:
Geoff Langb1196682014-07-23 13:47:29 -04001581 context->recordError(Error(GL_INVALID_ENUM));
1582 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001583 }
1584
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001585 const State &state = context->getState();
1586
1587 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001588 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001589 {
1590 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1591 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001592 context->recordError(Error(GL_INVALID_OPERATION));
1593 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001594 }
1595
1596 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001597 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001598 {
Geoff Langb1196682014-07-23 13:47:29 -04001599 context->recordError(Error(GL_INVALID_OPERATION));
1600 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001601 }
1602
Jamie Madill2b976812014-08-25 15:47:49 -04001603 const gl::VertexArray *vao = state.getVertexArray();
Olli Etuahoff5e7372015-03-25 16:52:11 +02001604 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
Jamie Madill2b976812014-08-25 15:47:49 -04001605 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001606 {
Geoff Langb1196682014-07-23 13:47:29 -04001607 context->recordError(Error(GL_INVALID_OPERATION));
1608 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001609 }
1610
Jamie Madillae3000b2014-08-25 15:47:51 -04001611 if (elementArrayBuffer)
1612 {
1613 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1614
1615 GLint64 offset = reinterpret_cast<GLint64>(indices);
1616 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1617
1618 // check for integer overflows
1619 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1620 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1621 {
Geoff Langb1196682014-07-23 13:47:29 -04001622 context->recordError(Error(GL_OUT_OF_MEMORY));
1623 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001624 }
1625
1626 // Check for reading past the end of the bound buffer object
1627 if (byteCount > elementArrayBuffer->getSize())
1628 {
Geoff Langb1196682014-07-23 13:47:29 -04001629 context->recordError(Error(GL_INVALID_OPERATION));
1630 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001631 }
1632 }
1633 else if (!indices)
1634 {
1635 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001636 context->recordError(Error(GL_INVALID_OPERATION));
1637 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001638 }
1639
Jamie Madill2b976812014-08-25 15:47:49 -04001640 // Use max index to validate if our vertex buffers are large enough for the pull.
1641 // TODO: offer fast path, with disabled index validation.
1642 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1643 if (elementArrayBuffer)
1644 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001645 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Minmin Gong794e0002015-04-07 18:31:54 -07001646 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, static_cast<unsigned int>(offset), count, indexRangeOut))
Jamie Madill2b976812014-08-25 15:47:49 -04001647 {
Jamie Madill72468832015-01-05 15:03:18 -05001648 rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation();
Geoff Langc8d297a2014-09-19 11:09:08 -04001649 const uint8_t *dataPointer = NULL;
Jamie Madill72468832015-01-05 15:03:18 -05001650 Error error = bufferImpl->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001651 if (error.isError())
1652 {
1653 context->recordError(error);
1654 return false;
1655 }
1656
1657 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001658 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
Minmin Gong794e0002015-04-07 18:31:54 -07001659 elementArrayBuffer->getIndexRangeCache()->addRange(type, static_cast<unsigned int>(offset), count, *indexRangeOut);
Jamie Madill2b976812014-08-25 15:47:49 -04001660 }
1661 }
1662 else
1663 {
1664 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1665 }
1666
Geoff Langb1196682014-07-23 13:47:29 -04001667 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001668 {
1669 return false;
1670 }
1671
1672 return true;
1673}
1674
Geoff Langb1196682014-07-23 13:47:29 -04001675bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001676 GLenum mode, GLsizei count, GLenum type,
1677 const GLvoid *indices, GLsizei primcount,
1678 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001679{
1680 if (primcount < 0)
1681 {
Geoff Langb1196682014-07-23 13:47:29 -04001682 context->recordError(Error(GL_INVALID_VALUE));
1683 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001684 }
1685
Jamie Madill2b976812014-08-25 15:47:49 -04001686 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001687 {
1688 return false;
1689 }
1690
1691 // No-op zero primitive count
1692 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001693}
1694
Geoff Lang87a93302014-09-16 13:29:43 -04001695bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1696 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1697{
1698 if (!ValidateDrawInstancedANGLE(context))
1699 {
1700 return false;
1701 }
1702
1703 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1704}
1705
Geoff Langb1196682014-07-23 13:47:29 -04001706bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001707 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001708{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001709 if (!ValidFramebufferTarget(target))
1710 {
Geoff Langb1196682014-07-23 13:47:29 -04001711 context->recordError(Error(GL_INVALID_ENUM));
1712 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001713 }
1714
1715 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001716 {
1717 return false;
1718 }
1719
Jamie Madill55ec3b12014-07-03 10:38:57 -04001720 if (texture != 0)
1721 {
1722 gl::Texture *tex = context->getTexture(texture);
1723
1724 if (tex == NULL)
1725 {
Geoff Langb1196682014-07-23 13:47:29 -04001726 context->recordError(Error(GL_INVALID_OPERATION));
1727 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001728 }
1729
1730 if (level < 0)
1731 {
Geoff Langb1196682014-07-23 13:47:29 -04001732 context->recordError(Error(GL_INVALID_VALUE));
1733 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001734 }
1735 }
1736
Shannon Woods53a94a82014-06-24 15:20:36 -04001737 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001738 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001739
Jamie Madill84115c92015-04-23 15:00:07 -04001740 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001741 {
Jamie Madill84115c92015-04-23 15:00:07 -04001742 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001743 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001744 }
1745
1746 return true;
1747}
1748
Geoff Langb1196682014-07-23 13:47:29 -04001749bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001750 GLenum textarget, GLuint texture, GLint level)
1751{
Geoff Lang95663912015-04-02 15:54:45 -04001752 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1753 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001754 {
Geoff Langb1196682014-07-23 13:47:29 -04001755 context->recordError(Error(GL_INVALID_VALUE));
1756 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001757 }
1758
1759 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001760 {
1761 return false;
1762 }
1763
Jamie Madill55ec3b12014-07-03 10:38:57 -04001764 if (texture != 0)
1765 {
1766 gl::Texture *tex = context->getTexture(texture);
1767 ASSERT(tex);
1768
Jamie Madill2a6564e2014-07-11 09:53:19 -04001769 const gl::Caps &caps = context->getCaps();
1770
Jamie Madill55ec3b12014-07-03 10:38:57 -04001771 switch (textarget)
1772 {
1773 case GL_TEXTURE_2D:
1774 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001775 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001776 {
Geoff Langb1196682014-07-23 13:47:29 -04001777 context->recordError(Error(GL_INVALID_VALUE));
1778 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001779 }
1780 if (tex->getTarget() != GL_TEXTURE_2D)
1781 {
Geoff Langb1196682014-07-23 13:47:29 -04001782 context->recordError(Error(GL_INVALID_OPERATION));
1783 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001784 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001785 }
1786 break;
1787
1788 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1789 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1790 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1791 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1792 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1793 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1794 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001795 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001796 {
Geoff Langb1196682014-07-23 13:47:29 -04001797 context->recordError(Error(GL_INVALID_VALUE));
1798 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001799 }
1800 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1801 {
Geoff Langb1196682014-07-23 13:47:29 -04001802 context->recordError(Error(GL_INVALID_OPERATION));
1803 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001804 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001805 }
1806 break;
1807
1808 default:
Geoff Langb1196682014-07-23 13:47:29 -04001809 context->recordError(Error(GL_INVALID_ENUM));
1810 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001811 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001812
1813 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1814 if (internalFormatInfo.compressed)
1815 {
1816 context->recordError(Error(GL_INVALID_OPERATION));
1817 return false;
1818 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001819 }
1820
Jamie Madill570f7c82014-07-03 10:38:54 -04001821 return true;
1822}
1823
Geoff Langb1196682014-07-23 13:47:29 -04001824bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001825{
1826 if (program == 0)
1827 {
Geoff Langb1196682014-07-23 13:47:29 -04001828 context->recordError(Error(GL_INVALID_VALUE));
1829 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001830 }
1831
Shannon Woods4de4fd62014-11-07 16:22:02 -05001832 if (!ValidProgram(context, program))
1833 {
1834 return false;
1835 }
1836
Jamie Madill0063c512014-08-25 15:47:53 -04001837 gl::Program *programObject = context->getProgram(program);
1838
1839 if (!programObject || !programObject->isLinked())
1840 {
Geoff Langb1196682014-07-23 13:47:29 -04001841 context->recordError(Error(GL_INVALID_OPERATION));
1842 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001843 }
1844
Geoff Lang7dd2e102014-11-10 15:19:26 -05001845 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001846 {
Geoff Langb1196682014-07-23 13:47:29 -04001847 context->recordError(Error(GL_INVALID_OPERATION));
1848 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001849 }
1850
Jamie Madill0063c512014-08-25 15:47:53 -04001851 return true;
1852}
1853
Geoff Langb1196682014-07-23 13:47:29 -04001854bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001855{
1856 return ValidateGetUniformBase(context, program, location);
1857}
1858
Geoff Langb1196682014-07-23 13:47:29 -04001859bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001860{
Jamie Madill78f41802014-08-25 15:47:55 -04001861 return ValidateGetUniformBase(context, program, location);
1862}
1863
Geoff Langb1196682014-07-23 13:47:29 -04001864static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001865{
1866 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001867 {
Jamie Madill78f41802014-08-25 15:47:55 -04001868 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001869 }
1870
Jamie Madilla502c742014-08-28 17:19:13 -04001871 gl::Program *programObject = context->getProgram(program);
1872 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001873
Jamie Madill78f41802014-08-25 15:47:55 -04001874 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001875 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001876 size_t requiredBytes = VariableExternalSize(uniform->type);
1877 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001878 {
Geoff Langb1196682014-07-23 13:47:29 -04001879 context->recordError(Error(GL_INVALID_OPERATION));
1880 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001881 }
1882
1883 return true;
1884}
1885
Geoff Langb1196682014-07-23 13:47:29 -04001886bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001887{
Jamie Madill78f41802014-08-25 15:47:55 -04001888 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001889}
1890
Geoff Langb1196682014-07-23 13:47:29 -04001891bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001892{
Jamie Madill78f41802014-08-25 15:47:55 -04001893 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001894}
1895
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001896}