blob: c647c5744f31fa6a3350ed1775c1b0ec8d7b7803 [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{
28
Geoff Lang0550d032014-01-30 11:29:07 -050029bool ValidCap(const Context *context, GLenum cap)
30{
31 switch (cap)
32 {
33 case GL_CULL_FACE:
34 case GL_POLYGON_OFFSET_FILL:
35 case GL_SAMPLE_ALPHA_TO_COVERAGE:
36 case GL_SAMPLE_COVERAGE:
37 case GL_SCISSOR_TEST:
38 case GL_STENCIL_TEST:
39 case GL_DEPTH_TEST:
40 case GL_BLEND:
41 case GL_DITHER:
42 return true;
43 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
44 case GL_RASTERIZER_DISCARD:
45 return (context->getClientVersion() >= 3);
46 default:
47 return false;
48 }
49}
50
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050051bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040052{
Jamie Madilld7460c72014-01-21 16:38:14 -050053 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040054 {
Jamie Madilld7460c72014-01-21 16:38:14 -050055 case GL_TEXTURE_2D:
56 case GL_TEXTURE_CUBE_MAP:
57 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040058
Jamie Madilld7460c72014-01-21 16:38:14 -050059 case GL_TEXTURE_3D:
60 case GL_TEXTURE_2D_ARRAY:
61 return (context->getClientVersion() >= 3);
62
63 default:
64 return false;
65 }
Jamie Madill35d15012013-10-07 10:46:37 -040066}
67
Shannon Woods4dfed832014-03-17 20:03:39 -040068// This function differs from ValidTextureTarget in that the target must be
69// usable as the destination of a 2D operation-- so a cube face is valid, but
70// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040071// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040072bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
73{
74 switch (target)
75 {
76 case GL_TEXTURE_2D:
77 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
78 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
79 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
80 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
81 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
82 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
83 return true;
84 case GL_TEXTURE_2D_ARRAY:
85 case GL_TEXTURE_3D:
86 return (context->getClientVersion() >= 3);
87 default:
88 return false;
89 }
90}
91
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050092bool ValidFramebufferTarget(GLenum target)
93{
Geoff Langd4475812015-03-18 10:53:05 -040094 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
95 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050096
97 switch (target)
98 {
99 case GL_FRAMEBUFFER: return true;
100 case GL_READ_FRAMEBUFFER: return true;
101 case GL_DRAW_FRAMEBUFFER: return true;
102 default: return false;
103 }
104}
105
Jamie Madill8c96d582014-03-05 15:01:23 -0500106bool ValidBufferTarget(const Context *context, GLenum target)
107{
108 switch (target)
109 {
110 case GL_ARRAY_BUFFER:
111 case GL_ELEMENT_ARRAY_BUFFER:
112 return true;
113
Jamie Madill8c96d582014-03-05 15:01:23 -0500114 case GL_PIXEL_PACK_BUFFER:
115 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400116 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400117
Shannon Woodsb3801742014-03-27 14:59:19 -0400118 case GL_COPY_READ_BUFFER:
119 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500120 case GL_TRANSFORM_FEEDBACK_BUFFER:
121 case GL_UNIFORM_BUFFER:
122 return (context->getClientVersion() >= 3);
123
124 default:
125 return false;
126 }
127}
128
Jamie Madill70656a62014-03-05 15:01:26 -0500129bool ValidBufferParameter(const Context *context, GLenum pname)
130{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400131 const Extensions &extensions = context->getExtensions();
132
Jamie Madill70656a62014-03-05 15:01:26 -0500133 switch (pname)
134 {
135 case GL_BUFFER_USAGE:
136 case GL_BUFFER_SIZE:
137 return true;
138
Geoff Langcc6f55d2015-03-20 13:01:02 -0400139 case GL_BUFFER_ACCESS_OES:
140 return extensions.mapBuffer;
141
142 case GL_BUFFER_MAPPED:
143 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
144 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
145
Jamie Madill70656a62014-03-05 15:01:26 -0500146 // GL_BUFFER_MAP_POINTER is a special case, and may only be
147 // queried with GetBufferPointerv
148 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500149 case GL_BUFFER_MAP_OFFSET:
150 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400151 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500152
153 default:
154 return false;
155 }
156}
157
Jamie Madill8c96d582014-03-05 15:01:23 -0500158bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400159{
Geoff Langaae65a42014-05-26 12:43:44 -0400160 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400161 switch (target)
162 {
Geoff Langaae65a42014-05-26 12:43:44 -0400163 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400164 case GL_TEXTURE_CUBE_MAP:
165 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
166 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
167 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
168 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
169 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400170 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
171 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
172 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400173 default: UNREACHABLE();
174 }
175
Geoff Langaae65a42014-05-26 12:43:44 -0400176 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400177}
178
Geoff Langb1196682014-07-23 13:47:29 -0400179bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400180 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400181{
182 if (level < 0 || width < 0 || height < 0 || depth < 0)
183 {
184 return false;
185 }
186
Geoff Langc0b9ef42014-07-02 10:02:37 -0400187 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400188 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400189 {
190 return false;
191 }
192
193 if (!ValidMipLevel(context, target, level))
194 {
195 return false;
196 }
197
198 return true;
199}
200
Geoff Langb1196682014-07-23 13:47:29 -0400201bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400202{
Geoff Lang5d601382014-07-22 15:14:06 -0400203 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
204 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400205 {
206 return false;
207 }
208
Geoff Lang5d601382014-07-22 15:14:06 -0400209 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
210 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400211 {
212 return false;
213 }
214
215 return true;
216}
217
Geoff Lang37dde692014-01-31 16:34:54 -0500218bool ValidQueryType(const Context *context, GLenum queryType)
219{
Geoff Langd4475812015-03-18 10:53:05 -0400220 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
221 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 -0500222
223 switch (queryType)
224 {
225 case GL_ANY_SAMPLES_PASSED:
226 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
227 return true;
228 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
229 return (context->getClientVersion() >= 3);
230 default:
231 return false;
232 }
233}
234
Geoff Langb1196682014-07-23 13:47:29 -0400235bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500236{
237 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
238 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
239 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
240
241 if (context->getProgram(id) != NULL)
242 {
243 return true;
244 }
245 else if (context->getShader(id) != NULL)
246 {
247 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400248 context->recordError(Error(GL_INVALID_OPERATION));
249 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500250 }
251 else
252 {
253 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400254 context->recordError(Error(GL_INVALID_VALUE));
255 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500256 }
257}
258
Geoff Langb1196682014-07-23 13:47:29 -0400259bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400260{
261 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
262 {
263 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
264
Geoff Langaae65a42014-05-26 12:43:44 -0400265 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400266 {
Geoff Langb1196682014-07-23 13:47:29 -0400267 context->recordError(Error(GL_INVALID_VALUE));
268 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400269 }
270 }
271 else
272 {
273 switch (attachment)
274 {
275 case GL_DEPTH_ATTACHMENT:
276 case GL_STENCIL_ATTACHMENT:
277 break;
278
279 case GL_DEPTH_STENCIL_ATTACHMENT:
280 if (context->getClientVersion() < 3)
281 {
Geoff Langb1196682014-07-23 13:47:29 -0400282 context->recordError(Error(GL_INVALID_ENUM));
283 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400284 }
285 break;
286
287 default:
Geoff Langb1196682014-07-23 13:47:29 -0400288 context->recordError(Error(GL_INVALID_ENUM));
289 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400290 }
291 }
292
293 return true;
294}
295
Corentin Walleze0902642014-11-04 12:32:15 -0800296bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
297 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400298{
299 switch (target)
300 {
301 case GL_RENDERBUFFER:
302 break;
303 default:
Geoff Langb1196682014-07-23 13:47:29 -0400304 context->recordError(Error(GL_INVALID_ENUM));
305 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400306 }
307
308 if (width < 0 || height < 0 || samples < 0)
309 {
Geoff Langb1196682014-07-23 13:47:29 -0400310 context->recordError(Error(GL_INVALID_VALUE));
311 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400312 }
313
Geoff Langd87878e2014-09-19 15:42:59 -0400314 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
315 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400316 {
Geoff Langb1196682014-07-23 13:47:29 -0400317 context->recordError(Error(GL_INVALID_ENUM));
318 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400319 }
320
321 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
322 // 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 -0800323 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400324 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400325 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400326 {
Geoff Langb1196682014-07-23 13:47:29 -0400327 context->recordError(Error(GL_INVALID_ENUM));
328 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400329 }
330
Geoff Langaae65a42014-05-26 12:43:44 -0400331 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400332 {
Geoff Langb1196682014-07-23 13:47:29 -0400333 context->recordError(Error(GL_INVALID_VALUE));
334 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400335 }
336
Shannon Woods53a94a82014-06-24 15:20:36 -0400337 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400338 if (handle == 0)
339 {
Geoff Langb1196682014-07-23 13:47:29 -0400340 context->recordError(Error(GL_INVALID_OPERATION));
341 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400342 }
343
344 return true;
345}
346
Corentin Walleze0902642014-11-04 12:32:15 -0800347bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
348 GLenum internalformat, GLsizei width, GLsizei height)
349{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800350 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800351
352 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400353 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800354 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400355 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800356 {
357 context->recordError(Error(GL_INVALID_VALUE));
358 return false;
359 }
360
361 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
362 // the specified storage. This is different than ES 3.0 in which a sample number higher
363 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800364 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
365 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800366 {
Geoff Langa4903b72015-03-02 16:02:48 -0800367 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
368 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
369 {
370 context->recordError(Error(GL_OUT_OF_MEMORY));
371 return false;
372 }
Corentin Walleze0902642014-11-04 12:32:15 -0800373 }
374
375 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
376}
377
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500378bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
379 GLenum renderbuffertarget, GLuint renderbuffer)
380{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400381 if (!ValidFramebufferTarget(target))
382 {
Geoff Langb1196682014-07-23 13:47:29 -0400383 context->recordError(Error(GL_INVALID_ENUM));
384 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400385 }
386
Shannon Woods53a94a82014-06-24 15:20:36 -0400387 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500388
Jamie Madill84115c92015-04-23 15:00:07 -0400389 ASSERT(framebuffer);
390 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500391 {
Jamie Madill84115c92015-04-23 15:00:07 -0400392 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400393 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500394 }
395
Jamie Madillb4472272014-07-03 10:38:55 -0400396 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500397 {
Jamie Madillb4472272014-07-03 10:38:55 -0400398 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500399 }
400
Jamie Madillab9d82c2014-01-21 16:38:14 -0500401 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
402 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
403 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
404 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
405 if (renderbuffer != 0)
406 {
407 if (!context->getRenderbuffer(renderbuffer))
408 {
Geoff Langb1196682014-07-23 13:47:29 -0400409 context->recordError(Error(GL_INVALID_OPERATION));
410 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500411 }
412 }
413
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500414 return true;
415}
416
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400417static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400418 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
419 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
420{
421 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
422 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
423 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
424 {
425 return true;
426 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400427 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400428 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400429 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400430
Shannon Woods53a94a82014-06-24 15:20:36 -0400431 return scissor.x > 0 || scissor.y > 0 ||
432 scissor.width < writeBuffer->getWidth() ||
433 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400434 }
435 else
436 {
437 return false;
438 }
439}
440
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400441bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
443 GLenum filter, bool fromAngleExtension)
444{
445 switch (filter)
446 {
447 case GL_NEAREST:
448 break;
449 case GL_LINEAR:
450 if (fromAngleExtension)
451 {
Geoff Langb1196682014-07-23 13:47:29 -0400452 context->recordError(Error(GL_INVALID_ENUM));
453 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400454 }
455 break;
456 default:
Geoff Langb1196682014-07-23 13:47:29 -0400457 context->recordError(Error(GL_INVALID_ENUM));
458 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400459 }
460
461 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
462 {
Geoff Langb1196682014-07-23 13:47:29 -0400463 context->recordError(Error(GL_INVALID_VALUE));
464 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400465 }
466
467 if (mask == 0)
468 {
469 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
470 // buffers are copied.
471 return false;
472 }
473
474 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
475 {
476 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400477 context->recordError(Error(GL_INVALID_OPERATION));
478 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400479 }
480
481 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
482 // color buffer, leaving only nearest being unfiltered from above
483 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
484 {
Geoff Langb1196682014-07-23 13:47:29 -0400485 context->recordError(Error(GL_INVALID_OPERATION));
486 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400487 }
488
Shannon Woods53a94a82014-06-24 15:20:36 -0400489 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400490 {
491 if (fromAngleExtension)
492 {
493 ERR("Blits with the same source and destination framebuffer are not supported by this "
494 "implementation.");
495 }
Geoff Langb1196682014-07-23 13:47:29 -0400496 context->recordError(Error(GL_INVALID_OPERATION));
497 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400498 }
499
Jamie Madille3ef7152015-04-28 16:55:17 +0000500 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
501 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500502
503 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400504 {
Geoff Langb1196682014-07-23 13:47:29 -0400505 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
506 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400507 }
508
Geoff Lang748f74e2014-12-01 11:25:34 -0500509 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500510 {
511 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
512 return false;
513 }
514
Geoff Lang748f74e2014-12-01 11:25:34 -0500515 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500516 {
517 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
518 return false;
519 }
520
521 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 {
Geoff Langb1196682014-07-23 13:47:29 -0400523 context->recordError(Error(GL_INVALID_OPERATION));
524 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400525 }
526
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400527 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
528
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400529 if (mask & GL_COLOR_BUFFER_BIT)
530 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400531 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
532 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400533
534 if (readColorBuffer && drawColorBuffer)
535 {
Geoff Langd8a22582014-12-17 15:28:23 -0500536 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400537 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400538
Jamie Madill0af26e12015-03-05 19:54:33 -0500539 for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400540 {
541 if (drawFramebuffer->isEnabledColorAttachment(i))
542 {
Geoff Langd8a22582014-12-17 15:28:23 -0500543 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400544 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400545
Geoff Langb2f3d052013-08-13 12:49:27 -0400546 // The GL ES 3.0.2 spec (pg 193) states that:
547 // 1) If the read buffer is fixed point format, the draw buffer must be as well
548 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
549 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400550 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
551 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400552 {
Geoff Langb1196682014-07-23 13:47:29 -0400553 context->recordError(Error(GL_INVALID_OPERATION));
554 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400555 }
556
Geoff Lang5d601382014-07-22 15:14:06 -0400557 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400558 {
Geoff Langb1196682014-07-23 13:47:29 -0400559 context->recordError(Error(GL_INVALID_OPERATION));
560 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400561 }
562
Geoff Lang5d601382014-07-22 15:14:06 -0400563 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564 {
Geoff Langb1196682014-07-23 13:47:29 -0400565 context->recordError(Error(GL_INVALID_OPERATION));
566 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 }
568
Geoff Langb2f3d052013-08-13 12:49:27 -0400569 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400570 {
Geoff Langb1196682014-07-23 13:47:29 -0400571 context->recordError(Error(GL_INVALID_OPERATION));
572 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400573 }
574 }
575 }
576
Geoff Lang5d601382014-07-22 15:14:06 -0400577 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400578 {
Geoff Langb1196682014-07-23 13:47:29 -0400579 context->recordError(Error(GL_INVALID_OPERATION));
580 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 }
582
583 if (fromAngleExtension)
584 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400585 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500586 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400587 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500588 readColorAttachment->type() != GL_RENDERBUFFER &&
589 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400590 {
Geoff Langb1196682014-07-23 13:47:29 -0400591 context->recordError(Error(GL_INVALID_OPERATION));
592 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400593 }
594
Jamie Madill0af26e12015-03-05 19:54:33 -0500595 for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 {
597 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
598 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000599 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400600 ASSERT(attachment);
601
Jamie Madill8cf4a392015-04-02 11:36:04 -0400602 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500603 attachment->type() != GL_RENDERBUFFER &&
604 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605 {
Geoff Langb1196682014-07-23 13:47:29 -0400606 context->recordError(Error(GL_INVALID_OPERATION));
607 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400608 }
609
Jamie Madillf8f18f02014-10-02 10:44:17 -0400610 // Return an error if the destination formats do not match
611 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 {
Geoff Langb1196682014-07-23 13:47:29 -0400613 context->recordError(Error(GL_INVALID_OPERATION));
614 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 }
616 }
617 }
Jamie Madill48faf802014-11-06 15:27:22 -0500618
619 int readSamples = readFramebuffer->getSamples(context->getData());
620
621 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
622 srcX0, srcY0, srcX1, srcY1,
623 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 {
Geoff Langb1196682014-07-23 13:47:29 -0400625 context->recordError(Error(GL_INVALID_OPERATION));
626 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627 }
628 }
629 }
630 }
631
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200632 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
633 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
634 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200636 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400638 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
639 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200641 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400642 {
Geoff Langd8a22582014-12-17 15:28:23 -0500643 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644 {
Geoff Langb1196682014-07-23 13:47:29 -0400645 context->recordError(Error(GL_INVALID_OPERATION));
646 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400647 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400648
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200649 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 {
Geoff Langb1196682014-07-23 13:47:29 -0400651 context->recordError(Error(GL_INVALID_OPERATION));
652 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200654
655 if (fromAngleExtension)
656 {
657 if (IsPartialBlit(context, readBuffer, drawBuffer,
658 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
659 {
660 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
661 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
662 return false;
663 }
664
665 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
666 {
667 context->recordError(Error(GL_INVALID_OPERATION));
668 return false;
669 }
670 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400671 }
672 }
673 }
674
675 return true;
676}
677
Geoff Langb1196682014-07-23 13:47:29 -0400678bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400679{
680 switch (pname)
681 {
682 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
683 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
684 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
685 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
686 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
687 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
688 case GL_CURRENT_VERTEX_ATTRIB:
689 return true;
690
691 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
692 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
693 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400694 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
695 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 return true;
697
698 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400699 if (context->getClientVersion() < 3)
700 {
701 context->recordError(Error(GL_INVALID_ENUM));
702 return false;
703 }
704 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400705
706 default:
Geoff Langb1196682014-07-23 13:47:29 -0400707 context->recordError(Error(GL_INVALID_ENUM));
708 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400709 }
710}
711
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400712bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400713{
714 switch (pname)
715 {
716 case GL_TEXTURE_WRAP_R:
717 case GL_TEXTURE_SWIZZLE_R:
718 case GL_TEXTURE_SWIZZLE_G:
719 case GL_TEXTURE_SWIZZLE_B:
720 case GL_TEXTURE_SWIZZLE_A:
721 case GL_TEXTURE_BASE_LEVEL:
722 case GL_TEXTURE_MAX_LEVEL:
723 case GL_TEXTURE_COMPARE_MODE:
724 case GL_TEXTURE_COMPARE_FUNC:
725 case GL_TEXTURE_MIN_LOD:
726 case GL_TEXTURE_MAX_LOD:
727 if (context->getClientVersion() < 3)
728 {
Geoff Langb1196682014-07-23 13:47:29 -0400729 context->recordError(Error(GL_INVALID_ENUM));
730 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400731 }
732 break;
733
734 default: break;
735 }
736
737 switch (pname)
738 {
739 case GL_TEXTURE_WRAP_S:
740 case GL_TEXTURE_WRAP_T:
741 case GL_TEXTURE_WRAP_R:
742 switch (param)
743 {
744 case GL_REPEAT:
745 case GL_CLAMP_TO_EDGE:
746 case GL_MIRRORED_REPEAT:
747 return true;
748 default:
Geoff Langb1196682014-07-23 13:47:29 -0400749 context->recordError(Error(GL_INVALID_ENUM));
750 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400751 }
752
753 case GL_TEXTURE_MIN_FILTER:
754 switch (param)
755 {
756 case GL_NEAREST:
757 case GL_LINEAR:
758 case GL_NEAREST_MIPMAP_NEAREST:
759 case GL_LINEAR_MIPMAP_NEAREST:
760 case GL_NEAREST_MIPMAP_LINEAR:
761 case GL_LINEAR_MIPMAP_LINEAR:
762 return true;
763 default:
Geoff Langb1196682014-07-23 13:47:29 -0400764 context->recordError(Error(GL_INVALID_ENUM));
765 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 }
767 break;
768
769 case GL_TEXTURE_MAG_FILTER:
770 switch (param)
771 {
772 case GL_NEAREST:
773 case GL_LINEAR:
774 return true;
775 default:
Geoff Langb1196682014-07-23 13:47:29 -0400776 context->recordError(Error(GL_INVALID_ENUM));
777 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400778 }
779 break;
780
781 case GL_TEXTURE_USAGE_ANGLE:
782 switch (param)
783 {
784 case GL_NONE:
785 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
786 return true;
787 default:
Geoff Langb1196682014-07-23 13:47:29 -0400788 context->recordError(Error(GL_INVALID_ENUM));
789 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400790 }
791 break;
792
793 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400794 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 {
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
800 // we assume the parameter passed to this validation method is truncated, not rounded
801 if (param < 1)
802 {
Geoff Langb1196682014-07-23 13:47:29 -0400803 context->recordError(Error(GL_INVALID_VALUE));
804 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805 }
806 return true;
807
808 case GL_TEXTURE_MIN_LOD:
809 case GL_TEXTURE_MAX_LOD:
810 // any value is permissible
811 return true;
812
813 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400814 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815 switch (param)
816 {
817 case GL_NONE:
818 case GL_COMPARE_REF_TO_TEXTURE:
819 return true;
820 default:
Geoff Langb1196682014-07-23 13:47:29 -0400821 context->recordError(Error(GL_INVALID_ENUM));
822 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400823 }
824 break;
825
826 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400827 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400828 switch (param)
829 {
830 case GL_LEQUAL:
831 case GL_GEQUAL:
832 case GL_LESS:
833 case GL_GREATER:
834 case GL_EQUAL:
835 case GL_NOTEQUAL:
836 case GL_ALWAYS:
837 case GL_NEVER:
838 return true;
839 default:
Geoff Langb1196682014-07-23 13:47:29 -0400840 context->recordError(Error(GL_INVALID_ENUM));
841 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400842 }
843 break;
844
845 case GL_TEXTURE_SWIZZLE_R:
846 case GL_TEXTURE_SWIZZLE_G:
847 case GL_TEXTURE_SWIZZLE_B:
848 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400849 switch (param)
850 {
851 case GL_RED:
852 case GL_GREEN:
853 case GL_BLUE:
854 case GL_ALPHA:
855 case GL_ZERO:
856 case GL_ONE:
857 return true;
858 default:
Geoff Langb1196682014-07-23 13:47:29 -0400859 context->recordError(Error(GL_INVALID_ENUM));
860 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400861 }
862 break;
863
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864 case GL_TEXTURE_BASE_LEVEL:
865 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400866 if (param < 0)
867 {
Geoff Langb1196682014-07-23 13:47:29 -0400868 context->recordError(Error(GL_INVALID_VALUE));
869 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400870 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400871 return true;
872
873 default:
Geoff Langb1196682014-07-23 13:47:29 -0400874 context->recordError(Error(GL_INVALID_ENUM));
875 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400876 }
877}
878
Geoff Langb1196682014-07-23 13:47:29 -0400879bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400880{
881 switch (pname)
882 {
883 case GL_TEXTURE_MIN_FILTER:
884 case GL_TEXTURE_MAG_FILTER:
885 case GL_TEXTURE_WRAP_S:
886 case GL_TEXTURE_WRAP_T:
887 case GL_TEXTURE_WRAP_R:
888 case GL_TEXTURE_MIN_LOD:
889 case GL_TEXTURE_MAX_LOD:
890 case GL_TEXTURE_COMPARE_MODE:
891 case GL_TEXTURE_COMPARE_FUNC:
892 return true;
893
894 default:
Geoff Langb1196682014-07-23 13:47:29 -0400895 context->recordError(Error(GL_INVALID_ENUM));
896 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400897 }
898}
899
Jamie Madill26e91952014-03-05 15:01:27 -0500900bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
901 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
902{
Shannon Woods53a94a82014-06-24 15:20:36 -0400903 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400904 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500905
Geoff Lang748f74e2014-12-01 11:25:34 -0500906 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500907 {
Geoff Langb1196682014-07-23 13:47:29 -0400908 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
909 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500910 }
911
Jamie Madill48faf802014-11-06 15:27:22 -0500912 if (context->getState().getReadFramebuffer()->id() != 0 &&
913 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500914 {
Geoff Langb1196682014-07-23 13:47:29 -0400915 context->recordError(Error(GL_INVALID_OPERATION));
916 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500917 }
918
Geoff Langbce529e2014-12-01 12:48:41 -0500919 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
920 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400921 {
Geoff Langb1196682014-07-23 13:47:29 -0400922 context->recordError(Error(GL_INVALID_OPERATION));
923 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400924 }
925
Geoff Langbce529e2014-12-01 12:48:41 -0500926 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
927 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500928 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400929 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500930
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400931 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
932 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500933
934 if (!(currentFormat == format && currentType == type) && !validReadFormat)
935 {
Geoff Langb1196682014-07-23 13:47:29 -0400936 context->recordError(Error(GL_INVALID_OPERATION));
937 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500938 }
939
Geoff Lang5d601382014-07-22 15:14:06 -0400940 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
941 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500942
Minmin Gongb8aee3b2015-01-27 14:42:36 -0800943 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -0500944 // sized query sanity check
945 if (bufSize)
946 {
947 int requiredSize = outputPitch * height;
948 if (requiredSize > *bufSize)
949 {
Geoff Langb1196682014-07-23 13:47:29 -0400950 context->recordError(Error(GL_INVALID_OPERATION));
951 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500952 }
953 }
954
955 return true;
956}
957
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400958bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
959{
960 if (!ValidQueryType(context, target))
961 {
Geoff Langb1196682014-07-23 13:47:29 -0400962 context->recordError(Error(GL_INVALID_ENUM));
963 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400964 }
965
966 if (id == 0)
967 {
Geoff Langb1196682014-07-23 13:47:29 -0400968 context->recordError(Error(GL_INVALID_OPERATION));
969 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400970 }
971
972 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
973 // of zero, if the active query object name for <target> is non-zero (for the
974 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
975 // the active query for either target is non-zero), if <id> is the name of an
976 // existing query object whose type does not match <target>, or if <id> is the
977 // active query object name for any query type, the error INVALID_OPERATION is
978 // generated.
979
980 // Ensure no other queries are active
981 // NOTE: If other queries than occlusion are supported, we will need to check
982 // separately that:
983 // a) The query ID passed is not the current active query for any target/type
984 // b) There are no active queries for the requested target (and in the case
985 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
986 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400987 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400988 {
Geoff Langb1196682014-07-23 13:47:29 -0400989 context->recordError(Error(GL_INVALID_OPERATION));
990 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400991 }
992
993 Query *queryObject = context->getQuery(id, true, target);
994
995 // check that name was obtained with glGenQueries
996 if (!queryObject)
997 {
Geoff Langb1196682014-07-23 13:47:29 -0400998 context->recordError(Error(GL_INVALID_OPERATION));
999 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001000 }
1001
1002 // check for type mismatch
1003 if (queryObject->getType() != target)
1004 {
Geoff Langb1196682014-07-23 13:47:29 -04001005 context->recordError(Error(GL_INVALID_OPERATION));
1006 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001007 }
1008
1009 return true;
1010}
1011
Jamie Madill45c785d2014-05-13 14:09:34 -04001012bool ValidateEndQuery(gl::Context *context, GLenum target)
1013{
1014 if (!ValidQueryType(context, target))
1015 {
Geoff Langb1196682014-07-23 13:47:29 -04001016 context->recordError(Error(GL_INVALID_ENUM));
1017 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001018 }
1019
Shannon Woods53a94a82014-06-24 15:20:36 -04001020 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001021
1022 if (queryObject == NULL)
1023 {
Geoff Langb1196682014-07-23 13:47:29 -04001024 context->recordError(Error(GL_INVALID_OPERATION));
1025 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001026 }
1027
Jamie Madill45c785d2014-05-13 14:09:34 -04001028 return true;
1029}
1030
Jamie Madill36398922014-05-20 14:51:53 -04001031static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1032 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001033{
1034 if (count < 0)
1035 {
Geoff Langb1196682014-07-23 13:47:29 -04001036 context->recordError(Error(GL_INVALID_VALUE));
1037 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001038 }
1039
Geoff Lang7dd2e102014-11-10 15:19:26 -05001040 gl::Program *program = context->getState().getProgram();
1041 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001042 {
Geoff Langb1196682014-07-23 13:47:29 -04001043 context->recordError(Error(GL_INVALID_OPERATION));
1044 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001045 }
1046
1047 if (location == -1)
1048 {
1049 // Silently ignore the uniform command
1050 return false;
1051 }
1052
Geoff Lang7dd2e102014-11-10 15:19:26 -05001053 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001054 {
Geoff Langb1196682014-07-23 13:47:29 -04001055 context->recordError(Error(GL_INVALID_OPERATION));
1056 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001057 }
1058
Geoff Lang7dd2e102014-11-10 15:19:26 -05001059 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001060
1061 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1062 if (uniform->elementCount() == 1 && count > 1)
1063 {
Geoff Langb1196682014-07-23 13:47:29 -04001064 context->recordError(Error(GL_INVALID_OPERATION));
1065 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001066 }
1067
1068 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001069 return true;
1070}
1071
Jamie Madillaa981bd2014-05-20 10:55:55 -04001072bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1073{
1074 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001075 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001076 {
Geoff Langb1196682014-07-23 13:47:29 -04001077 context->recordError(Error(GL_INVALID_OPERATION));
1078 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001079 }
1080
Jamie Madill36398922014-05-20 14:51:53 -04001081 LinkedUniform *uniform = NULL;
1082 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1083 {
1084 return false;
1085 }
1086
Jamie Madillf2575982014-06-25 16:04:54 -04001087 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001088 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001089 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1090 {
Geoff Langb1196682014-07-23 13:47:29 -04001091 context->recordError(Error(GL_INVALID_OPERATION));
1092 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001093 }
1094
1095 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001096}
1097
1098bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1099 GLboolean transpose)
1100{
1101 // Check for ES3 uniform entry points
1102 int rows = VariableRowCount(matrixType);
1103 int cols = VariableColumnCount(matrixType);
1104 if (rows != cols && context->getClientVersion() < 3)
1105 {
Geoff Langb1196682014-07-23 13:47:29 -04001106 context->recordError(Error(GL_INVALID_OPERATION));
1107 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001108 }
1109
1110 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1111 {
Geoff Langb1196682014-07-23 13:47:29 -04001112 context->recordError(Error(GL_INVALID_VALUE));
1113 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001114 }
1115
Jamie Madill36398922014-05-20 14:51:53 -04001116 LinkedUniform *uniform = NULL;
1117 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1118 {
1119 return false;
1120 }
1121
1122 if (uniform->type != matrixType)
1123 {
Geoff Langb1196682014-07-23 13:47:29 -04001124 context->recordError(Error(GL_INVALID_OPERATION));
1125 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001126 }
1127
1128 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001129}
1130
Jamie Madill893ab082014-05-16 16:56:10 -04001131bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1132{
1133 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1134 {
Geoff Langb1196682014-07-23 13:47:29 -04001135 context->recordError(Error(GL_INVALID_ENUM));
1136 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001137 }
1138
Jamie Madill0af26e12015-03-05 19:54:33 -05001139 const Caps &caps = context->getCaps();
1140
Jamie Madill893ab082014-05-16 16:56:10 -04001141 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1142 {
1143 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1144
Jamie Madill0af26e12015-03-05 19:54:33 -05001145 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001146 {
Geoff Langb1196682014-07-23 13:47:29 -04001147 context->recordError(Error(GL_INVALID_OPERATION));
1148 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001149 }
1150 }
1151
1152 switch (pname)
1153 {
1154 case GL_TEXTURE_BINDING_2D:
1155 case GL_TEXTURE_BINDING_CUBE_MAP:
1156 case GL_TEXTURE_BINDING_3D:
1157 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001158 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001159 {
Geoff Langb1196682014-07-23 13:47:29 -04001160 context->recordError(Error(GL_INVALID_OPERATION));
1161 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001162 }
1163 break;
1164
1165 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1166 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1167 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001168 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001169 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001170 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001171 {
Geoff Langb1196682014-07-23 13:47:29 -04001172 context->recordError(Error(GL_INVALID_OPERATION));
1173 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001174 }
1175
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001176 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001177 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001178 {
Geoff Langb1196682014-07-23 13:47:29 -04001179 context->recordError(Error(GL_INVALID_OPERATION));
1180 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001181 }
1182 }
1183 break;
1184
1185 default:
1186 break;
1187 }
1188
1189 // pname is valid, but there are no parameters to return
1190 if (numParams == 0)
1191 {
1192 return false;
1193 }
1194
1195 return true;
1196}
1197
Geoff Lang831b1952015-05-05 11:02:27 -04001198bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001199 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1200 GLint border, GLenum *textureFormatOut)
1201{
1202
1203 if (!ValidTexture2DDestinationTarget(context, target))
1204 {
Geoff Langb1196682014-07-23 13:47:29 -04001205 context->recordError(Error(GL_INVALID_ENUM));
1206 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001207 }
1208
1209 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1210 {
Geoff Langb1196682014-07-23 13:47:29 -04001211 context->recordError(Error(GL_INVALID_VALUE));
1212 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001213 }
1214
1215 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1216 {
Geoff Langb1196682014-07-23 13:47:29 -04001217 context->recordError(Error(GL_INVALID_VALUE));
1218 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001219 }
1220
1221 if (border != 0)
1222 {
Geoff Langb1196682014-07-23 13:47:29 -04001223 context->recordError(Error(GL_INVALID_VALUE));
1224 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001225 }
1226
1227 if (!ValidMipLevel(context, target, level))
1228 {
Geoff Langb1196682014-07-23 13:47:29 -04001229 context->recordError(Error(GL_INVALID_VALUE));
1230 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001231 }
1232
Shannon Woods53a94a82014-06-24 15:20:36 -04001233 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001234 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001235 {
Geoff Langb1196682014-07-23 13:47:29 -04001236 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1237 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001238 }
1239
Jamie Madill48faf802014-11-06 15:27:22 -05001240 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001241 {
Geoff Langb1196682014-07-23 13:47:29 -04001242 context->recordError(Error(GL_INVALID_OPERATION));
1243 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001244 }
1245
Geoff Langaae65a42014-05-26 12:43:44 -04001246 const gl::Caps &caps = context->getCaps();
1247
Geoff Langaae65a42014-05-26 12:43:44 -04001248 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001249 switch (target)
1250 {
1251 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001252 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001253 break;
1254
1255 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1256 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1257 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1258 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1259 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1260 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001261 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001262 break;
1263
1264 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001265 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001266 break;
1267
1268 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001269 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001270 break;
1271
1272 default:
Geoff Langb1196682014-07-23 13:47:29 -04001273 context->recordError(Error(GL_INVALID_ENUM));
1274 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001275 }
1276
Geoff Lang691e58c2014-12-19 17:03:25 -05001277 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001278 if (!texture)
1279 {
Geoff Langb1196682014-07-23 13:47:29 -04001280 context->recordError(Error(GL_INVALID_OPERATION));
1281 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001282 }
1283
1284 if (texture->isImmutable() && !isSubImage)
1285 {
Geoff Langb1196682014-07-23 13:47:29 -04001286 context->recordError(Error(GL_INVALID_OPERATION));
1287 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001288 }
1289
Geoff Lang5d601382014-07-22 15:14:06 -04001290 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1291
1292 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001293 {
Geoff Langb1196682014-07-23 13:47:29 -04001294 context->recordError(Error(GL_INVALID_OPERATION));
1295 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001296 }
1297
Geoff Langa9be0dc2014-12-17 12:34:40 -05001298 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001299 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001300 context->recordError(Error(GL_INVALID_OPERATION));
1301 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001302 }
1303
1304 if (isSubImage)
1305 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001306 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1307 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1308 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001309 {
Geoff Langb1196682014-07-23 13:47:29 -04001310 context->recordError(Error(GL_INVALID_VALUE));
1311 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001312 }
1313 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001314 else
1315 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001316 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001317 {
Geoff Langb1196682014-07-23 13:47:29 -04001318 context->recordError(Error(GL_INVALID_VALUE));
1319 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001320 }
1321
Geoff Lang5d601382014-07-22 15:14:06 -04001322 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001323 {
Geoff Langb1196682014-07-23 13:47:29 -04001324 context->recordError(Error(GL_INVALID_ENUM));
1325 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001326 }
1327
1328 int maxLevelDimension = (maxDimension >> level);
1329 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1330 {
Geoff Langb1196682014-07-23 13:47:29 -04001331 context->recordError(Error(GL_INVALID_VALUE));
1332 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001333 }
1334 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001335
Geoff Langa9be0dc2014-12-17 12:34:40 -05001336 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001337 return true;
1338}
1339
Geoff Langb1196682014-07-23 13:47:29 -04001340static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001341{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001342 switch (mode)
1343 {
1344 case GL_POINTS:
1345 case GL_LINES:
1346 case GL_LINE_LOOP:
1347 case GL_LINE_STRIP:
1348 case GL_TRIANGLES:
1349 case GL_TRIANGLE_STRIP:
1350 case GL_TRIANGLE_FAN:
1351 break;
1352 default:
Geoff Langb1196682014-07-23 13:47:29 -04001353 context->recordError(Error(GL_INVALID_ENUM));
1354 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001355 }
1356
Jamie Madill250d33f2014-06-06 17:09:03 -04001357 if (count < 0)
1358 {
Geoff Langb1196682014-07-23 13:47:29 -04001359 context->recordError(Error(GL_INVALID_VALUE));
1360 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001361 }
1362
Geoff Langb1196682014-07-23 13:47:29 -04001363 const State &state = context->getState();
1364
Jamie Madill250d33f2014-06-06 17:09:03 -04001365 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001366 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001367 {
Geoff Langb1196682014-07-23 13:47:29 -04001368 context->recordError(Error(GL_INVALID_OPERATION));
1369 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001370 }
1371
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001372 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001373 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001374 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001375 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1376 {
1377 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1378 // See Section 6.10 of the WebGL 1.0 spec
1379 ERR("This ANGLE implementation does not support separate front/back stencil "
1380 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001381 context->recordError(Error(GL_INVALID_OPERATION));
1382 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001383 }
1384
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001385 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001386 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001387 {
Geoff Langb1196682014-07-23 13:47:29 -04001388 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1389 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001390 }
1391
Geoff Lang7dd2e102014-11-10 15:19:26 -05001392 gl::Program *program = state.getProgram();
1393 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001394 {
Geoff Langb1196682014-07-23 13:47:29 -04001395 context->recordError(Error(GL_INVALID_OPERATION));
1396 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001397 }
1398
Geoff Lang7dd2e102014-11-10 15:19:26 -05001399 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001400 {
Geoff Langb1196682014-07-23 13:47:29 -04001401 context->recordError(Error(GL_INVALID_OPERATION));
1402 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001403 }
1404
Jamie Madill2b976812014-08-25 15:47:49 -04001405 // Buffer validations
1406 const VertexArray *vao = state.getVertexArray();
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001407 const auto &vertexAttribs = vao->getVertexAttributes();
1408 const int *semanticIndexes = program->getSemanticIndexes();
Jamie Madillaebf9dd2015-04-28 12:39:07 -04001409 unsigned int maxEnabledAttrib = vao->getMaxEnabledAttribute();
1410 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++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,
Geoff Lang831b1952015-05-05 11:02:27 -04001566 const GLvoid *indices, GLsizei primcount, 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);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001646 Error error = elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count, indexRangeOut);
1647 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001648 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001649 context->recordError(error);
1650 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001651 }
1652 }
1653 else
1654 {
Geoff Lang831b1952015-05-05 11:02:27 -04001655 *indexRangeOut = ComputeIndexRange(type, indices, count);
Jamie Madill2b976812014-08-25 15:47:49 -04001656 }
1657
Geoff Langb1196682014-07-23 13:47:29 -04001658 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001659 {
1660 return false;
1661 }
1662
1663 return true;
1664}
1665
Geoff Langb1196682014-07-23 13:47:29 -04001666bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001667 GLenum mode, GLsizei count, GLenum type,
1668 const GLvoid *indices, GLsizei primcount,
Geoff Lang831b1952015-05-05 11:02:27 -04001669 RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001670{
1671 if (primcount < 0)
1672 {
Geoff Langb1196682014-07-23 13:47:29 -04001673 context->recordError(Error(GL_INVALID_VALUE));
1674 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001675 }
1676
Jamie Madill2b976812014-08-25 15:47:49 -04001677 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001678 {
1679 return false;
1680 }
1681
1682 // No-op zero primitive count
1683 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001684}
1685
Geoff Lang87a93302014-09-16 13:29:43 -04001686bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001687 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001688{
1689 if (!ValidateDrawInstancedANGLE(context))
1690 {
1691 return false;
1692 }
1693
1694 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1695}
1696
Geoff Langb1196682014-07-23 13:47:29 -04001697bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001698 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001699{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001700 if (!ValidFramebufferTarget(target))
1701 {
Geoff Langb1196682014-07-23 13:47:29 -04001702 context->recordError(Error(GL_INVALID_ENUM));
1703 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001704 }
1705
1706 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001707 {
1708 return false;
1709 }
1710
Jamie Madill55ec3b12014-07-03 10:38:57 -04001711 if (texture != 0)
1712 {
1713 gl::Texture *tex = context->getTexture(texture);
1714
1715 if (tex == NULL)
1716 {
Geoff Langb1196682014-07-23 13:47:29 -04001717 context->recordError(Error(GL_INVALID_OPERATION));
1718 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001719 }
1720
1721 if (level < 0)
1722 {
Geoff Langb1196682014-07-23 13:47:29 -04001723 context->recordError(Error(GL_INVALID_VALUE));
1724 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001725 }
1726 }
1727
Shannon Woods53a94a82014-06-24 15:20:36 -04001728 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001729 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001730
Jamie Madill84115c92015-04-23 15:00:07 -04001731 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001732 {
Jamie Madill84115c92015-04-23 15:00:07 -04001733 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001734 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001735 }
1736
1737 return true;
1738}
1739
Geoff Langb1196682014-07-23 13:47:29 -04001740bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001741 GLenum textarget, GLuint texture, GLint level)
1742{
Geoff Lang95663912015-04-02 15:54:45 -04001743 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1744 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001745 {
Geoff Langb1196682014-07-23 13:47:29 -04001746 context->recordError(Error(GL_INVALID_VALUE));
1747 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001748 }
1749
1750 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001751 {
1752 return false;
1753 }
1754
Jamie Madill55ec3b12014-07-03 10:38:57 -04001755 if (texture != 0)
1756 {
1757 gl::Texture *tex = context->getTexture(texture);
1758 ASSERT(tex);
1759
Jamie Madill2a6564e2014-07-11 09:53:19 -04001760 const gl::Caps &caps = context->getCaps();
1761
Jamie Madill55ec3b12014-07-03 10:38:57 -04001762 switch (textarget)
1763 {
1764 case GL_TEXTURE_2D:
1765 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001766 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001767 {
Geoff Langb1196682014-07-23 13:47:29 -04001768 context->recordError(Error(GL_INVALID_VALUE));
1769 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001770 }
1771 if (tex->getTarget() != GL_TEXTURE_2D)
1772 {
Geoff Langb1196682014-07-23 13:47:29 -04001773 context->recordError(Error(GL_INVALID_OPERATION));
1774 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001775 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001776 }
1777 break;
1778
1779 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1780 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1781 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1782 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1783 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1784 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1785 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001786 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001787 {
Geoff Langb1196682014-07-23 13:47:29 -04001788 context->recordError(Error(GL_INVALID_VALUE));
1789 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001790 }
1791 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1792 {
Geoff Langb1196682014-07-23 13:47:29 -04001793 context->recordError(Error(GL_INVALID_OPERATION));
1794 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001795 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001796 }
1797 break;
1798
1799 default:
Geoff Langb1196682014-07-23 13:47:29 -04001800 context->recordError(Error(GL_INVALID_ENUM));
1801 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001802 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001803
1804 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1805 if (internalFormatInfo.compressed)
1806 {
1807 context->recordError(Error(GL_INVALID_OPERATION));
1808 return false;
1809 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001810 }
1811
Jamie Madill570f7c82014-07-03 10:38:54 -04001812 return true;
1813}
1814
Geoff Langb1196682014-07-23 13:47:29 -04001815bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001816{
1817 if (program == 0)
1818 {
Geoff Langb1196682014-07-23 13:47:29 -04001819 context->recordError(Error(GL_INVALID_VALUE));
1820 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001821 }
1822
Shannon Woods4de4fd62014-11-07 16:22:02 -05001823 if (!ValidProgram(context, program))
1824 {
1825 return false;
1826 }
1827
Jamie Madill0063c512014-08-25 15:47:53 -04001828 gl::Program *programObject = context->getProgram(program);
1829
1830 if (!programObject || !programObject->isLinked())
1831 {
Geoff Langb1196682014-07-23 13:47:29 -04001832 context->recordError(Error(GL_INVALID_OPERATION));
1833 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001834 }
1835
Geoff Lang7dd2e102014-11-10 15:19:26 -05001836 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001837 {
Geoff Langb1196682014-07-23 13:47:29 -04001838 context->recordError(Error(GL_INVALID_OPERATION));
1839 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001840 }
1841
Jamie Madill0063c512014-08-25 15:47:53 -04001842 return true;
1843}
1844
Geoff Langb1196682014-07-23 13:47:29 -04001845bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001846{
1847 return ValidateGetUniformBase(context, program, location);
1848}
1849
Geoff Langb1196682014-07-23 13:47:29 -04001850bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001851{
Jamie Madill78f41802014-08-25 15:47:55 -04001852 return ValidateGetUniformBase(context, program, location);
1853}
1854
Geoff Langb1196682014-07-23 13:47:29 -04001855static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001856{
1857 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001858 {
Jamie Madill78f41802014-08-25 15:47:55 -04001859 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001860 }
1861
Jamie Madilla502c742014-08-28 17:19:13 -04001862 gl::Program *programObject = context->getProgram(program);
1863 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001864
Jamie Madill78f41802014-08-25 15:47:55 -04001865 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001866 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001867 size_t requiredBytes = VariableExternalSize(uniform->type);
1868 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001869 {
Geoff Langb1196682014-07-23 13:47:29 -04001870 context->recordError(Error(GL_INVALID_OPERATION));
1871 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001872 }
1873
1874 return true;
1875}
1876
Geoff Langb1196682014-07-23 13:47:29 -04001877bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001878{
Jamie Madill78f41802014-08-25 15:47:55 -04001879 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001880}
1881
Geoff Langb1196682014-07-23 13:47:29 -04001882bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001883{
Jamie Madill78f41802014-08-25 15:47:55 -04001884 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001885}
1886
Austin Kinross08332632015-05-05 13:35:47 -07001887bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
1888 const GLenum *attachments, bool defaultFramebuffer)
1889{
1890 if (numAttachments < 0)
1891 {
1892 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
1893 return false;
1894 }
1895
1896 for (GLsizei i = 0; i < numAttachments; ++i)
1897 {
1898 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
1899 {
1900 if (defaultFramebuffer)
1901 {
1902 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1903 return false;
1904 }
1905
1906 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
1907 {
1908 context->recordError(Error(GL_INVALID_OPERATION,
1909 "Requested color attachment is greater than the maximum supported color attachments"));
1910 return false;
1911 }
1912 }
1913 else
1914 {
1915 switch (attachments[i])
1916 {
1917 case GL_DEPTH_ATTACHMENT:
1918 case GL_STENCIL_ATTACHMENT:
1919 case GL_DEPTH_STENCIL_ATTACHMENT:
1920 if (defaultFramebuffer)
1921 {
1922 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1923 return false;
1924 }
1925 break;
1926 case GL_COLOR:
1927 case GL_DEPTH:
1928 case GL_STENCIL:
1929 if (!defaultFramebuffer)
1930 {
1931 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
1932 return false;
1933 }
1934 break;
1935 default:
1936 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
1937 return false;
1938 }
1939 }
1940 }
1941
1942 return true;
1943}
1944
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001945}