blob: b1685c764f66ed31dd92494470f1021951ba3a2a [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.
365 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
366 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
367 {
368 context->recordError(Error(GL_OUT_OF_MEMORY));
369 return false;
370 }
371
372 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
373}
374
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500375bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
376 GLenum renderbuffertarget, GLuint renderbuffer)
377{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400378 if (!ValidFramebufferTarget(target))
379 {
Geoff Langb1196682014-07-23 13:47:29 -0400380 context->recordError(Error(GL_INVALID_ENUM));
381 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400382 }
383
Shannon Woods53a94a82014-06-24 15:20:36 -0400384 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
385 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500386
387 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
388 {
Geoff Langb1196682014-07-23 13:47:29 -0400389 context->recordError(Error(GL_INVALID_OPERATION));
390 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500391 }
392
Jamie Madillb4472272014-07-03 10:38:55 -0400393 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500394 {
Jamie Madillb4472272014-07-03 10:38:55 -0400395 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500396 }
397
Jamie Madillab9d82c2014-01-21 16:38:14 -0500398 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
399 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
400 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
401 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
402 if (renderbuffer != 0)
403 {
404 if (!context->getRenderbuffer(renderbuffer))
405 {
Geoff Langb1196682014-07-23 13:47:29 -0400406 context->recordError(Error(GL_INVALID_OPERATION));
407 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500408 }
409 }
410
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500411 return true;
412}
413
Jamie Madill3c7fa222014-06-05 13:08:51 -0400414static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400415 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
416 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
417{
418 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
419 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
420 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
421 {
422 return true;
423 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400424 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400425 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400426 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400427
Shannon Woods53a94a82014-06-24 15:20:36 -0400428 return scissor.x > 0 || scissor.y > 0 ||
429 scissor.width < writeBuffer->getWidth() ||
430 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400431 }
432 else
433 {
434 return false;
435 }
436}
437
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400438bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400439 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
440 GLenum filter, bool fromAngleExtension)
441{
442 switch (filter)
443 {
444 case GL_NEAREST:
445 break;
446 case GL_LINEAR:
447 if (fromAngleExtension)
448 {
Geoff Langb1196682014-07-23 13:47:29 -0400449 context->recordError(Error(GL_INVALID_ENUM));
450 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400451 }
452 break;
453 default:
Geoff Langb1196682014-07-23 13:47:29 -0400454 context->recordError(Error(GL_INVALID_ENUM));
455 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400456 }
457
458 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
459 {
Geoff Langb1196682014-07-23 13:47:29 -0400460 context->recordError(Error(GL_INVALID_VALUE));
461 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400462 }
463
464 if (mask == 0)
465 {
466 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
467 // buffers are copied.
468 return false;
469 }
470
471 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
472 {
473 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400474 context->recordError(Error(GL_INVALID_OPERATION));
475 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400476 }
477
478 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
479 // color buffer, leaving only nearest being unfiltered from above
480 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
481 {
Geoff Langb1196682014-07-23 13:47:29 -0400482 context->recordError(Error(GL_INVALID_OPERATION));
483 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400484 }
485
Shannon Woods53a94a82014-06-24 15:20:36 -0400486 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400487 {
488 if (fromAngleExtension)
489 {
490 ERR("Blits with the same source and destination framebuffer are not supported by this "
491 "implementation.");
492 }
Geoff Langb1196682014-07-23 13:47:29 -0400493 context->recordError(Error(GL_INVALID_OPERATION));
494 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400495 }
496
Shannon Woods53a94a82014-06-24 15:20:36 -0400497 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
498 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500499
500 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400501 {
Geoff Langb1196682014-07-23 13:47:29 -0400502 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
503 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400504 }
505
Geoff Lang748f74e2014-12-01 11:25:34 -0500506 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500507 {
508 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
509 return false;
510 }
511
Geoff Lang748f74e2014-12-01 11:25:34 -0500512 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500513 {
514 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
515 return false;
516 }
517
518 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 {
Geoff Langb1196682014-07-23 13:47:29 -0400520 context->recordError(Error(GL_INVALID_OPERATION));
521 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 }
523
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
525
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526 if (mask & GL_COLOR_BUFFER_BIT)
527 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400528 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
529 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400530
531 if (readColorBuffer && drawColorBuffer)
532 {
Geoff Langd8a22582014-12-17 15:28:23 -0500533 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400534 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535
Jamie Madill0af26e12015-03-05 19:54:33 -0500536 for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400537 {
538 if (drawFramebuffer->isEnabledColorAttachment(i))
539 {
Geoff Langd8a22582014-12-17 15:28:23 -0500540 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400541 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400542
Geoff Langb2f3d052013-08-13 12:49:27 -0400543 // The GL ES 3.0.2 spec (pg 193) states that:
544 // 1) If the read buffer is fixed point format, the draw buffer must be as well
545 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
546 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400547 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
548 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400549 {
Geoff Langb1196682014-07-23 13:47:29 -0400550 context->recordError(Error(GL_INVALID_OPERATION));
551 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400552 }
553
Geoff Lang5d601382014-07-22 15:14:06 -0400554 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400555 {
Geoff Langb1196682014-07-23 13:47:29 -0400556 context->recordError(Error(GL_INVALID_OPERATION));
557 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400558 }
559
Geoff Lang5d601382014-07-22 15:14:06 -0400560 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400561 {
Geoff Langb1196682014-07-23 13:47:29 -0400562 context->recordError(Error(GL_INVALID_OPERATION));
563 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564 }
565
Geoff Langb2f3d052013-08-13 12:49:27 -0400566 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 {
Geoff Langb1196682014-07-23 13:47:29 -0400568 context->recordError(Error(GL_INVALID_OPERATION));
569 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400570 }
571 }
572 }
573
Geoff Lang5d601382014-07-22 15:14:06 -0400574 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400575 {
Geoff Langb1196682014-07-23 13:47:29 -0400576 context->recordError(Error(GL_INVALID_OPERATION));
577 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400578 }
579
580 if (fromAngleExtension)
581 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500582 FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
583 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400584 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500585 readColorAttachment->type() != GL_RENDERBUFFER &&
586 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400587 {
Geoff Langb1196682014-07-23 13:47:29 -0400588 context->recordError(Error(GL_INVALID_OPERATION));
589 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400590 }
591
Jamie Madill0af26e12015-03-05 19:54:33 -0500592 for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400593 {
594 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
595 {
Jamie Madille92a3542014-07-03 10:38:58 -0400596 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
597 ASSERT(attachment);
598
Jamie Madill8cf4a392015-04-02 11:36:04 -0400599 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500600 attachment->type() != GL_RENDERBUFFER &&
601 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400602 {
Geoff Langb1196682014-07-23 13:47:29 -0400603 context->recordError(Error(GL_INVALID_OPERATION));
604 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605 }
606
Jamie Madillf8f18f02014-10-02 10:44:17 -0400607 // Return an error if the destination formats do not match
608 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400609 {
Geoff Langb1196682014-07-23 13:47:29 -0400610 context->recordError(Error(GL_INVALID_OPERATION));
611 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 }
613 }
614 }
Jamie Madill48faf802014-11-06 15:27:22 -0500615
616 int readSamples = readFramebuffer->getSamples(context->getData());
617
618 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
619 srcX0, srcY0, srcX1, srcY1,
620 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400621 {
Geoff Langb1196682014-07-23 13:47:29 -0400622 context->recordError(Error(GL_INVALID_OPERATION));
623 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 }
625 }
626 }
627 }
628
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200629 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
630 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
631 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200633 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200635 gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
636 gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200638 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 {
Geoff Langd8a22582014-12-17 15:28:23 -0500640 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400641 {
Geoff Langb1196682014-07-23 13:47:29 -0400642 context->recordError(Error(GL_INVALID_OPERATION));
643 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400644 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200646 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400647 {
Geoff Langb1196682014-07-23 13:47:29 -0400648 context->recordError(Error(GL_INVALID_OPERATION));
649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200651
652 if (fromAngleExtension)
653 {
654 if (IsPartialBlit(context, readBuffer, drawBuffer,
655 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
656 {
657 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
658 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
659 return false;
660 }
661
662 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
663 {
664 context->recordError(Error(GL_INVALID_OPERATION));
665 return false;
666 }
667 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668 }
669 }
670 }
671
672 return true;
673}
674
Geoff Langb1196682014-07-23 13:47:29 -0400675bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400676{
677 switch (pname)
678 {
679 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
680 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
681 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
682 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
683 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
684 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
685 case GL_CURRENT_VERTEX_ATTRIB:
686 return true;
687
688 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
689 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
690 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400691 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
692 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 return true;
694
695 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400696 if (context->getClientVersion() < 3)
697 {
698 context->recordError(Error(GL_INVALID_ENUM));
699 return false;
700 }
701 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702
703 default:
Geoff Langb1196682014-07-23 13:47:29 -0400704 context->recordError(Error(GL_INVALID_ENUM));
705 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400706 }
707}
708
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400709bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710{
711 switch (pname)
712 {
713 case GL_TEXTURE_WRAP_R:
714 case GL_TEXTURE_SWIZZLE_R:
715 case GL_TEXTURE_SWIZZLE_G:
716 case GL_TEXTURE_SWIZZLE_B:
717 case GL_TEXTURE_SWIZZLE_A:
718 case GL_TEXTURE_BASE_LEVEL:
719 case GL_TEXTURE_MAX_LEVEL:
720 case GL_TEXTURE_COMPARE_MODE:
721 case GL_TEXTURE_COMPARE_FUNC:
722 case GL_TEXTURE_MIN_LOD:
723 case GL_TEXTURE_MAX_LOD:
724 if (context->getClientVersion() < 3)
725 {
Geoff Langb1196682014-07-23 13:47:29 -0400726 context->recordError(Error(GL_INVALID_ENUM));
727 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400728 }
729 break;
730
731 default: break;
732 }
733
734 switch (pname)
735 {
736 case GL_TEXTURE_WRAP_S:
737 case GL_TEXTURE_WRAP_T:
738 case GL_TEXTURE_WRAP_R:
739 switch (param)
740 {
741 case GL_REPEAT:
742 case GL_CLAMP_TO_EDGE:
743 case GL_MIRRORED_REPEAT:
744 return true;
745 default:
Geoff Langb1196682014-07-23 13:47:29 -0400746 context->recordError(Error(GL_INVALID_ENUM));
747 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 }
749
750 case GL_TEXTURE_MIN_FILTER:
751 switch (param)
752 {
753 case GL_NEAREST:
754 case GL_LINEAR:
755 case GL_NEAREST_MIPMAP_NEAREST:
756 case GL_LINEAR_MIPMAP_NEAREST:
757 case GL_NEAREST_MIPMAP_LINEAR:
758 case GL_LINEAR_MIPMAP_LINEAR:
759 return true;
760 default:
Geoff Langb1196682014-07-23 13:47:29 -0400761 context->recordError(Error(GL_INVALID_ENUM));
762 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400763 }
764 break;
765
766 case GL_TEXTURE_MAG_FILTER:
767 switch (param)
768 {
769 case GL_NEAREST:
770 case GL_LINEAR:
771 return true;
772 default:
Geoff Langb1196682014-07-23 13:47:29 -0400773 context->recordError(Error(GL_INVALID_ENUM));
774 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400775 }
776 break;
777
778 case GL_TEXTURE_USAGE_ANGLE:
779 switch (param)
780 {
781 case GL_NONE:
782 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
783 return true;
784 default:
Geoff Langb1196682014-07-23 13:47:29 -0400785 context->recordError(Error(GL_INVALID_ENUM));
786 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 }
788 break;
789
790 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400791 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 {
Geoff Langb1196682014-07-23 13:47:29 -0400793 context->recordError(Error(GL_INVALID_ENUM));
794 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400795 }
796
797 // we assume the parameter passed to this validation method is truncated, not rounded
798 if (param < 1)
799 {
Geoff Langb1196682014-07-23 13:47:29 -0400800 context->recordError(Error(GL_INVALID_VALUE));
801 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400802 }
803 return true;
804
805 case GL_TEXTURE_MIN_LOD:
806 case GL_TEXTURE_MAX_LOD:
807 // any value is permissible
808 return true;
809
810 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400811 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812 switch (param)
813 {
814 case GL_NONE:
815 case GL_COMPARE_REF_TO_TEXTURE:
816 return true;
817 default:
Geoff Langb1196682014-07-23 13:47:29 -0400818 context->recordError(Error(GL_INVALID_ENUM));
819 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400820 }
821 break;
822
823 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400824 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400825 switch (param)
826 {
827 case GL_LEQUAL:
828 case GL_GEQUAL:
829 case GL_LESS:
830 case GL_GREATER:
831 case GL_EQUAL:
832 case GL_NOTEQUAL:
833 case GL_ALWAYS:
834 case GL_NEVER:
835 return true;
836 default:
Geoff Langb1196682014-07-23 13:47:29 -0400837 context->recordError(Error(GL_INVALID_ENUM));
838 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400839 }
840 break;
841
842 case GL_TEXTURE_SWIZZLE_R:
843 case GL_TEXTURE_SWIZZLE_G:
844 case GL_TEXTURE_SWIZZLE_B:
845 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400846 switch (param)
847 {
848 case GL_RED:
849 case GL_GREEN:
850 case GL_BLUE:
851 case GL_ALPHA:
852 case GL_ZERO:
853 case GL_ONE:
854 return true;
855 default:
Geoff Langb1196682014-07-23 13:47:29 -0400856 context->recordError(Error(GL_INVALID_ENUM));
857 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400858 }
859 break;
860
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400861 case GL_TEXTURE_BASE_LEVEL:
862 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400863 if (param < 0)
864 {
Geoff Langb1196682014-07-23 13:47:29 -0400865 context->recordError(Error(GL_INVALID_VALUE));
866 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400867 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400868 return true;
869
870 default:
Geoff Langb1196682014-07-23 13:47:29 -0400871 context->recordError(Error(GL_INVALID_ENUM));
872 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400873 }
874}
875
Geoff Langb1196682014-07-23 13:47:29 -0400876bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400877{
878 switch (pname)
879 {
880 case GL_TEXTURE_MIN_FILTER:
881 case GL_TEXTURE_MAG_FILTER:
882 case GL_TEXTURE_WRAP_S:
883 case GL_TEXTURE_WRAP_T:
884 case GL_TEXTURE_WRAP_R:
885 case GL_TEXTURE_MIN_LOD:
886 case GL_TEXTURE_MAX_LOD:
887 case GL_TEXTURE_COMPARE_MODE:
888 case GL_TEXTURE_COMPARE_FUNC:
889 return true;
890
891 default:
Geoff Langb1196682014-07-23 13:47:29 -0400892 context->recordError(Error(GL_INVALID_ENUM));
893 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 }
895}
896
Jamie Madill26e91952014-03-05 15:01:27 -0500897bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
898 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
899{
Shannon Woods53a94a82014-06-24 15:20:36 -0400900 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400901 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500902
Geoff Lang748f74e2014-12-01 11:25:34 -0500903 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500904 {
Geoff Langb1196682014-07-23 13:47:29 -0400905 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
906 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500907 }
908
Jamie Madill48faf802014-11-06 15:27:22 -0500909 if (context->getState().getReadFramebuffer()->id() != 0 &&
910 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500911 {
Geoff Langb1196682014-07-23 13:47:29 -0400912 context->recordError(Error(GL_INVALID_OPERATION));
913 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500914 }
915
Geoff Langbce529e2014-12-01 12:48:41 -0500916 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
917 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400918 {
Geoff Langb1196682014-07-23 13:47:29 -0400919 context->recordError(Error(GL_INVALID_OPERATION));
920 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400921 }
922
Geoff Langbce529e2014-12-01 12:48:41 -0500923 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
924 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500925 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400926 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500927
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400928 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
929 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500930
931 if (!(currentFormat == format && currentType == type) && !validReadFormat)
932 {
Geoff Langb1196682014-07-23 13:47:29 -0400933 context->recordError(Error(GL_INVALID_OPERATION));
934 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500935 }
936
Geoff Lang5d601382014-07-22 15:14:06 -0400937 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
938 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500939
Minmin Gongb8aee3b2015-01-27 14:42:36 -0800940 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -0500941 // sized query sanity check
942 if (bufSize)
943 {
944 int requiredSize = outputPitch * height;
945 if (requiredSize > *bufSize)
946 {
Geoff Langb1196682014-07-23 13:47:29 -0400947 context->recordError(Error(GL_INVALID_OPERATION));
948 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500949 }
950 }
951
952 return true;
953}
954
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400955bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
956{
957 if (!ValidQueryType(context, target))
958 {
Geoff Langb1196682014-07-23 13:47:29 -0400959 context->recordError(Error(GL_INVALID_ENUM));
960 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400961 }
962
963 if (id == 0)
964 {
Geoff Langb1196682014-07-23 13:47:29 -0400965 context->recordError(Error(GL_INVALID_OPERATION));
966 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400967 }
968
969 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
970 // of zero, if the active query object name for <target> is non-zero (for the
971 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
972 // the active query for either target is non-zero), if <id> is the name of an
973 // existing query object whose type does not match <target>, or if <id> is the
974 // active query object name for any query type, the error INVALID_OPERATION is
975 // generated.
976
977 // Ensure no other queries are active
978 // NOTE: If other queries than occlusion are supported, we will need to check
979 // separately that:
980 // a) The query ID passed is not the current active query for any target/type
981 // b) There are no active queries for the requested target (and in the case
982 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
983 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400984 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400985 {
Geoff Langb1196682014-07-23 13:47:29 -0400986 context->recordError(Error(GL_INVALID_OPERATION));
987 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400988 }
989
990 Query *queryObject = context->getQuery(id, true, target);
991
992 // check that name was obtained with glGenQueries
993 if (!queryObject)
994 {
Geoff Langb1196682014-07-23 13:47:29 -0400995 context->recordError(Error(GL_INVALID_OPERATION));
996 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400997 }
998
999 // check for type mismatch
1000 if (queryObject->getType() != target)
1001 {
Geoff Langb1196682014-07-23 13:47:29 -04001002 context->recordError(Error(GL_INVALID_OPERATION));
1003 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001004 }
1005
1006 return true;
1007}
1008
Jamie Madill45c785d2014-05-13 14:09:34 -04001009bool ValidateEndQuery(gl::Context *context, GLenum target)
1010{
1011 if (!ValidQueryType(context, target))
1012 {
Geoff Langb1196682014-07-23 13:47:29 -04001013 context->recordError(Error(GL_INVALID_ENUM));
1014 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001015 }
1016
Shannon Woods53a94a82014-06-24 15:20:36 -04001017 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001018
1019 if (queryObject == NULL)
1020 {
Geoff Langb1196682014-07-23 13:47:29 -04001021 context->recordError(Error(GL_INVALID_OPERATION));
1022 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001023 }
1024
Jamie Madill45c785d2014-05-13 14:09:34 -04001025 return true;
1026}
1027
Jamie Madill36398922014-05-20 14:51:53 -04001028static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1029 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001030{
1031 if (count < 0)
1032 {
Geoff Langb1196682014-07-23 13:47:29 -04001033 context->recordError(Error(GL_INVALID_VALUE));
1034 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001035 }
1036
Geoff Lang7dd2e102014-11-10 15:19:26 -05001037 gl::Program *program = context->getState().getProgram();
1038 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001039 {
Geoff Langb1196682014-07-23 13:47:29 -04001040 context->recordError(Error(GL_INVALID_OPERATION));
1041 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001042 }
1043
1044 if (location == -1)
1045 {
1046 // Silently ignore the uniform command
1047 return false;
1048 }
1049
Geoff Lang7dd2e102014-11-10 15:19:26 -05001050 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001051 {
Geoff Langb1196682014-07-23 13:47:29 -04001052 context->recordError(Error(GL_INVALID_OPERATION));
1053 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001054 }
1055
Geoff Lang7dd2e102014-11-10 15:19:26 -05001056 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001057
1058 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1059 if (uniform->elementCount() == 1 && count > 1)
1060 {
Geoff Langb1196682014-07-23 13:47:29 -04001061 context->recordError(Error(GL_INVALID_OPERATION));
1062 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001063 }
1064
1065 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001066 return true;
1067}
1068
Jamie Madillaa981bd2014-05-20 10:55:55 -04001069bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1070{
1071 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001072 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001073 {
Geoff Langb1196682014-07-23 13:47:29 -04001074 context->recordError(Error(GL_INVALID_OPERATION));
1075 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001076 }
1077
Jamie Madill36398922014-05-20 14:51:53 -04001078 LinkedUniform *uniform = NULL;
1079 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1080 {
1081 return false;
1082 }
1083
Jamie Madillf2575982014-06-25 16:04:54 -04001084 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001085 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001086 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1087 {
Geoff Langb1196682014-07-23 13:47:29 -04001088 context->recordError(Error(GL_INVALID_OPERATION));
1089 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001090 }
1091
1092 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001093}
1094
1095bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1096 GLboolean transpose)
1097{
1098 // Check for ES3 uniform entry points
1099 int rows = VariableRowCount(matrixType);
1100 int cols = VariableColumnCount(matrixType);
1101 if (rows != cols && context->getClientVersion() < 3)
1102 {
Geoff Langb1196682014-07-23 13:47:29 -04001103 context->recordError(Error(GL_INVALID_OPERATION));
1104 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001105 }
1106
1107 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1108 {
Geoff Langb1196682014-07-23 13:47:29 -04001109 context->recordError(Error(GL_INVALID_VALUE));
1110 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001111 }
1112
Jamie Madill36398922014-05-20 14:51:53 -04001113 LinkedUniform *uniform = NULL;
1114 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1115 {
1116 return false;
1117 }
1118
1119 if (uniform->type != matrixType)
1120 {
Geoff Langb1196682014-07-23 13:47:29 -04001121 context->recordError(Error(GL_INVALID_OPERATION));
1122 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001123 }
1124
1125 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001126}
1127
Jamie Madill893ab082014-05-16 16:56:10 -04001128bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1129{
1130 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1131 {
Geoff Langb1196682014-07-23 13:47:29 -04001132 context->recordError(Error(GL_INVALID_ENUM));
1133 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001134 }
1135
Jamie Madill0af26e12015-03-05 19:54:33 -05001136 const Caps &caps = context->getCaps();
1137
Jamie Madill893ab082014-05-16 16:56:10 -04001138 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1139 {
1140 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1141
Jamie Madill0af26e12015-03-05 19:54:33 -05001142 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001143 {
Geoff Langb1196682014-07-23 13:47:29 -04001144 context->recordError(Error(GL_INVALID_OPERATION));
1145 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001146 }
1147 }
1148
1149 switch (pname)
1150 {
1151 case GL_TEXTURE_BINDING_2D:
1152 case GL_TEXTURE_BINDING_CUBE_MAP:
1153 case GL_TEXTURE_BINDING_3D:
1154 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001155 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001156 {
Geoff Langb1196682014-07-23 13:47:29 -04001157 context->recordError(Error(GL_INVALID_OPERATION));
1158 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001159 }
1160 break;
1161
1162 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1163 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1164 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001165 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001166 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001167 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001168 {
Geoff Langb1196682014-07-23 13:47:29 -04001169 context->recordError(Error(GL_INVALID_OPERATION));
1170 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001171 }
1172
Jamie Madill3c7fa222014-06-05 13:08:51 -04001173 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1174 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001175 {
Geoff Langb1196682014-07-23 13:47:29 -04001176 context->recordError(Error(GL_INVALID_OPERATION));
1177 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001178 }
1179 }
1180 break;
1181
1182 default:
1183 break;
1184 }
1185
1186 // pname is valid, but there are no parameters to return
1187 if (numParams == 0)
1188 {
1189 return false;
1190 }
1191
1192 return true;
1193}
1194
Jamie Madill560a8d82014-05-21 13:06:20 -04001195bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1196 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1197 GLint border, GLenum *textureFormatOut)
1198{
1199
1200 if (!ValidTexture2DDestinationTarget(context, target))
1201 {
Geoff Langb1196682014-07-23 13:47:29 -04001202 context->recordError(Error(GL_INVALID_ENUM));
1203 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001204 }
1205
1206 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1207 {
Geoff Langb1196682014-07-23 13:47:29 -04001208 context->recordError(Error(GL_INVALID_VALUE));
1209 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001210 }
1211
1212 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1213 {
Geoff Langb1196682014-07-23 13:47:29 -04001214 context->recordError(Error(GL_INVALID_VALUE));
1215 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001216 }
1217
1218 if (border != 0)
1219 {
Geoff Langb1196682014-07-23 13:47:29 -04001220 context->recordError(Error(GL_INVALID_VALUE));
1221 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001222 }
1223
1224 if (!ValidMipLevel(context, target, level))
1225 {
Geoff Langb1196682014-07-23 13:47:29 -04001226 context->recordError(Error(GL_INVALID_VALUE));
1227 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001228 }
1229
Shannon Woods53a94a82014-06-24 15:20:36 -04001230 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001231 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001232 {
Geoff Langb1196682014-07-23 13:47:29 -04001233 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1234 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001235 }
1236
Jamie Madill48faf802014-11-06 15:27:22 -05001237 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001238 {
Geoff Langb1196682014-07-23 13:47:29 -04001239 context->recordError(Error(GL_INVALID_OPERATION));
1240 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001241 }
1242
Geoff Langaae65a42014-05-26 12:43:44 -04001243 const gl::Caps &caps = context->getCaps();
1244
Geoff Langaae65a42014-05-26 12:43:44 -04001245 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001246 switch (target)
1247 {
1248 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001249 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001250 break;
1251
1252 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1253 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1254 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1255 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1256 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1257 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001258 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001259 break;
1260
1261 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001262 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001263 break;
1264
1265 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001266 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001267 break;
1268
1269 default:
Geoff Langb1196682014-07-23 13:47:29 -04001270 context->recordError(Error(GL_INVALID_ENUM));
1271 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001272 }
1273
Geoff Lang691e58c2014-12-19 17:03:25 -05001274 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001275 if (!texture)
1276 {
Geoff Langb1196682014-07-23 13:47:29 -04001277 context->recordError(Error(GL_INVALID_OPERATION));
1278 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001279 }
1280
1281 if (texture->isImmutable() && !isSubImage)
1282 {
Geoff Langb1196682014-07-23 13:47:29 -04001283 context->recordError(Error(GL_INVALID_OPERATION));
1284 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001285 }
1286
Geoff Lang5d601382014-07-22 15:14:06 -04001287 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1288
1289 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001290 {
Geoff Langb1196682014-07-23 13:47:29 -04001291 context->recordError(Error(GL_INVALID_OPERATION));
1292 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001293 }
1294
Geoff Langa9be0dc2014-12-17 12:34:40 -05001295 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001296 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001297 context->recordError(Error(GL_INVALID_OPERATION));
1298 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001299 }
1300
1301 if (isSubImage)
1302 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001303 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1304 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1305 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001306 {
Geoff Langb1196682014-07-23 13:47:29 -04001307 context->recordError(Error(GL_INVALID_VALUE));
1308 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001309 }
1310 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001311 else
1312 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001313 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001314 {
Geoff Langb1196682014-07-23 13:47:29 -04001315 context->recordError(Error(GL_INVALID_VALUE));
1316 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001317 }
1318
Geoff Lang5d601382014-07-22 15:14:06 -04001319 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001320 {
Geoff Langb1196682014-07-23 13:47:29 -04001321 context->recordError(Error(GL_INVALID_ENUM));
1322 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001323 }
1324
1325 int maxLevelDimension = (maxDimension >> level);
1326 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1327 {
Geoff Langb1196682014-07-23 13:47:29 -04001328 context->recordError(Error(GL_INVALID_VALUE));
1329 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001330 }
1331 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001332
Geoff Langa9be0dc2014-12-17 12:34:40 -05001333 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001334 return true;
1335}
1336
Geoff Langb1196682014-07-23 13:47:29 -04001337static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001338{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001339 switch (mode)
1340 {
1341 case GL_POINTS:
1342 case GL_LINES:
1343 case GL_LINE_LOOP:
1344 case GL_LINE_STRIP:
1345 case GL_TRIANGLES:
1346 case GL_TRIANGLE_STRIP:
1347 case GL_TRIANGLE_FAN:
1348 break;
1349 default:
Geoff Langb1196682014-07-23 13:47:29 -04001350 context->recordError(Error(GL_INVALID_ENUM));
1351 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001352 }
1353
Jamie Madill250d33f2014-06-06 17:09:03 -04001354 if (count < 0)
1355 {
Geoff Langb1196682014-07-23 13:47:29 -04001356 context->recordError(Error(GL_INVALID_VALUE));
1357 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001358 }
1359
Geoff Langb1196682014-07-23 13:47:29 -04001360 const State &state = context->getState();
1361
Jamie Madill250d33f2014-06-06 17:09:03 -04001362 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001363 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001364 {
Geoff Langb1196682014-07-23 13:47:29 -04001365 context->recordError(Error(GL_INVALID_OPERATION));
1366 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001367 }
1368
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001369 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001370 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001371 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001372 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1373 {
1374 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1375 // See Section 6.10 of the WebGL 1.0 spec
1376 ERR("This ANGLE implementation does not support separate front/back stencil "
1377 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001378 context->recordError(Error(GL_INVALID_OPERATION));
1379 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001380 }
1381
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001382 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001383 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001384 {
Geoff Langb1196682014-07-23 13:47:29 -04001385 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1386 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001387 }
1388
Geoff Lang7dd2e102014-11-10 15:19:26 -05001389 gl::Program *program = state.getProgram();
1390 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001391 {
Geoff Langb1196682014-07-23 13:47:29 -04001392 context->recordError(Error(GL_INVALID_OPERATION));
1393 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001394 }
1395
Geoff Lang7dd2e102014-11-10 15:19:26 -05001396 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001397 {
Geoff Langb1196682014-07-23 13:47:29 -04001398 context->recordError(Error(GL_INVALID_OPERATION));
1399 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001400 }
1401
Jamie Madill2b976812014-08-25 15:47:49 -04001402 // Buffer validations
1403 const VertexArray *vao = state.getVertexArray();
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001404 const auto &vertexAttribs = vao->getVertexAttributes();
1405 const int *semanticIndexes = program->getSemanticIndexes();
1406 for (size_t attributeIndex = 0; attributeIndex < vertexAttribs.size(); ++attributeIndex)
Jamie Madill2b976812014-08-25 15:47:49 -04001407 {
Jamie Madill56c6e3c2015-04-15 10:18:05 -04001408 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
1409 bool attribActive = (semanticIndexes[attributeIndex] != -1);
Jamie Madill2b976812014-08-25 15:47:49 -04001410 if (attribActive && attrib.enabled)
1411 {
1412 gl::Buffer *buffer = attrib.buffer.get();
1413
1414 if (buffer)
1415 {
1416 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1417 GLint64 maxVertexElement = 0;
1418
1419 if (attrib.divisor > 0)
1420 {
1421 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1422 }
1423 else
1424 {
1425 maxVertexElement = static_cast<GLint64>(maxVertex);
1426 }
1427
1428 GLint64 attribDataSize = maxVertexElement * attribStride;
1429
1430 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1431 // We can return INVALID_OPERATION if our vertex attribute does not have
1432 // enough backing data.
1433 if (attribDataSize > buffer->getSize())
1434 {
Geoff Langb1196682014-07-23 13:47:29 -04001435 context->recordError(Error(GL_INVALID_OPERATION));
1436 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001437 }
1438 }
1439 else if (attrib.pointer == NULL)
1440 {
1441 // This is an application error that would normally result in a crash,
1442 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001443 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1444 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001445 }
1446 }
1447 }
1448
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001449 // Uniform buffer validation
1450 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1451 {
1452 const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
1453 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
1454 const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
1455
1456 if (!uniformBuffer)
1457 {
1458 // undefined behaviour
1459 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1460 return false;
1461 }
1462
1463 size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
1464
1465 if (uniformBufferSize == 0)
1466 {
1467 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001468 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001469 }
1470
1471 if (uniformBufferSize < uniformBlock->dataSize)
1472 {
1473 // undefined behaviour
1474 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1475 return false;
1476 }
1477 }
1478
Jamie Madill250d33f2014-06-06 17:09:03 -04001479 // No-op if zero count
1480 return (count > 0);
1481}
1482
Geoff Langb1196682014-07-23 13:47:29 -04001483bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001484{
Jamie Madillfd716582014-06-06 17:09:04 -04001485 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001486 {
Geoff Langb1196682014-07-23 13:47:29 -04001487 context->recordError(Error(GL_INVALID_VALUE));
1488 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001489 }
1490
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001491 const State &state = context->getState();
1492 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001493 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1494 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001495 {
1496 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1497 // that does not match the current transform feedback object's draw mode (if transform feedback
1498 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001499 context->recordError(Error(GL_INVALID_OPERATION));
1500 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001501 }
1502
Geoff Langb1196682014-07-23 13:47:29 -04001503 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001504 {
1505 return false;
1506 }
1507
1508 return true;
1509}
1510
Geoff Langb1196682014-07-23 13:47:29 -04001511bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001512{
1513 if (primcount < 0)
1514 {
Geoff Langb1196682014-07-23 13:47:29 -04001515 context->recordError(Error(GL_INVALID_VALUE));
1516 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001517 }
1518
Jamie Madill2b976812014-08-25 15:47:49 -04001519 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001520 {
1521 return false;
1522 }
1523
1524 // No-op if zero primitive count
1525 return (primcount > 0);
1526}
1527
Geoff Lang87a93302014-09-16 13:29:43 -04001528static bool ValidateDrawInstancedANGLE(Context *context)
1529{
1530 // Verify there is at least one active attribute with a divisor of zero
1531 const gl::State& state = context->getState();
1532
Geoff Lang7dd2e102014-11-10 15:19:26 -05001533 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001534
1535 const VertexArray *vao = state.getVertexArray();
1536 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1537 {
1538 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001539 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001540 if (active && attrib.divisor == 0)
1541 {
1542 return true;
1543 }
1544 }
1545
1546 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1547 "has a divisor of zero."));
1548 return false;
1549}
1550
1551bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1552{
1553 if (!ValidateDrawInstancedANGLE(context))
1554 {
1555 return false;
1556 }
1557
1558 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1559}
1560
Geoff Langb1196682014-07-23 13:47:29 -04001561bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001562 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001563{
Jamie Madill250d33f2014-06-06 17:09:03 -04001564 switch (type)
1565 {
1566 case GL_UNSIGNED_BYTE:
1567 case GL_UNSIGNED_SHORT:
1568 break;
1569 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001570 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001571 {
Geoff Langb1196682014-07-23 13:47:29 -04001572 context->recordError(Error(GL_INVALID_ENUM));
1573 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001574 }
1575 break;
1576 default:
Geoff Langb1196682014-07-23 13:47:29 -04001577 context->recordError(Error(GL_INVALID_ENUM));
1578 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001579 }
1580
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001581 const State &state = context->getState();
1582
1583 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001584 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001585 {
1586 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1587 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001588 context->recordError(Error(GL_INVALID_OPERATION));
1589 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001590 }
1591
1592 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001593 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001594 {
Geoff Langb1196682014-07-23 13:47:29 -04001595 context->recordError(Error(GL_INVALID_OPERATION));
1596 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001597 }
1598
Jamie Madill2b976812014-08-25 15:47:49 -04001599 const gl::VertexArray *vao = state.getVertexArray();
Olli Etuahoff5e7372015-03-25 16:52:11 +02001600 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
Jamie Madill2b976812014-08-25 15:47:49 -04001601 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001602 {
Geoff Langb1196682014-07-23 13:47:29 -04001603 context->recordError(Error(GL_INVALID_OPERATION));
1604 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001605 }
1606
Jamie Madillae3000b2014-08-25 15:47:51 -04001607 if (elementArrayBuffer)
1608 {
1609 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1610
1611 GLint64 offset = reinterpret_cast<GLint64>(indices);
1612 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1613
1614 // check for integer overflows
1615 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1616 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1617 {
Geoff Langb1196682014-07-23 13:47:29 -04001618 context->recordError(Error(GL_OUT_OF_MEMORY));
1619 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001620 }
1621
1622 // Check for reading past the end of the bound buffer object
1623 if (byteCount > elementArrayBuffer->getSize())
1624 {
Geoff Langb1196682014-07-23 13:47:29 -04001625 context->recordError(Error(GL_INVALID_OPERATION));
1626 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001627 }
1628 }
1629 else if (!indices)
1630 {
1631 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001632 context->recordError(Error(GL_INVALID_OPERATION));
1633 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001634 }
1635
Jamie Madill2b976812014-08-25 15:47:49 -04001636 // Use max index to validate if our vertex buffers are large enough for the pull.
1637 // TODO: offer fast path, with disabled index validation.
1638 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1639 if (elementArrayBuffer)
1640 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001641 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Minmin Gong794e0002015-04-07 18:31:54 -07001642 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, static_cast<unsigned int>(offset), count, indexRangeOut))
Jamie Madill2b976812014-08-25 15:47:49 -04001643 {
Jamie Madill72468832015-01-05 15:03:18 -05001644 rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation();
Geoff Langc8d297a2014-09-19 11:09:08 -04001645 const uint8_t *dataPointer = NULL;
Jamie Madill72468832015-01-05 15:03:18 -05001646 Error error = bufferImpl->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001647 if (error.isError())
1648 {
1649 context->recordError(error);
1650 return false;
1651 }
1652
1653 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001654 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
Minmin Gong794e0002015-04-07 18:31:54 -07001655 elementArrayBuffer->getIndexRangeCache()->addRange(type, static_cast<unsigned int>(offset), count, *indexRangeOut);
Jamie Madill2b976812014-08-25 15:47:49 -04001656 }
1657 }
1658 else
1659 {
1660 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1661 }
1662
Geoff Langb1196682014-07-23 13:47:29 -04001663 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001664 {
1665 return false;
1666 }
1667
1668 return true;
1669}
1670
Geoff Langb1196682014-07-23 13:47:29 -04001671bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001672 GLenum mode, GLsizei count, GLenum type,
1673 const GLvoid *indices, GLsizei primcount,
1674 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001675{
1676 if (primcount < 0)
1677 {
Geoff Langb1196682014-07-23 13:47:29 -04001678 context->recordError(Error(GL_INVALID_VALUE));
1679 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001680 }
1681
Jamie Madill2b976812014-08-25 15:47:49 -04001682 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001683 {
1684 return false;
1685 }
1686
1687 // No-op zero primitive count
1688 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001689}
1690
Geoff Lang87a93302014-09-16 13:29:43 -04001691bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1692 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1693{
1694 if (!ValidateDrawInstancedANGLE(context))
1695 {
1696 return false;
1697 }
1698
1699 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1700}
1701
Geoff Langb1196682014-07-23 13:47:29 -04001702bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001703 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001704{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001705 if (!ValidFramebufferTarget(target))
1706 {
Geoff Langb1196682014-07-23 13:47:29 -04001707 context->recordError(Error(GL_INVALID_ENUM));
1708 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001709 }
1710
1711 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001712 {
1713 return false;
1714 }
1715
Jamie Madill55ec3b12014-07-03 10:38:57 -04001716 if (texture != 0)
1717 {
1718 gl::Texture *tex = context->getTexture(texture);
1719
1720 if (tex == NULL)
1721 {
Geoff Langb1196682014-07-23 13:47:29 -04001722 context->recordError(Error(GL_INVALID_OPERATION));
1723 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001724 }
1725
1726 if (level < 0)
1727 {
Geoff Langb1196682014-07-23 13:47:29 -04001728 context->recordError(Error(GL_INVALID_VALUE));
1729 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001730 }
1731 }
1732
Shannon Woods53a94a82014-06-24 15:20:36 -04001733 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1734 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001735
1736 if (framebufferHandle == 0 || !framebuffer)
1737 {
Geoff Langb1196682014-07-23 13:47:29 -04001738 context->recordError(Error(GL_INVALID_OPERATION));
1739 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001740 }
1741
1742 return true;
1743}
1744
Geoff Langb1196682014-07-23 13:47:29 -04001745bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001746 GLenum textarget, GLuint texture, GLint level)
1747{
Geoff Lang95663912015-04-02 15:54:45 -04001748 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1749 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001750 {
Geoff Langb1196682014-07-23 13:47:29 -04001751 context->recordError(Error(GL_INVALID_VALUE));
1752 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001753 }
1754
1755 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001756 {
1757 return false;
1758 }
1759
Jamie Madill55ec3b12014-07-03 10:38:57 -04001760 if (texture != 0)
1761 {
1762 gl::Texture *tex = context->getTexture(texture);
1763 ASSERT(tex);
1764
Jamie Madill2a6564e2014-07-11 09:53:19 -04001765 const gl::Caps &caps = context->getCaps();
1766
Jamie Madill55ec3b12014-07-03 10:38:57 -04001767 switch (textarget)
1768 {
1769 case GL_TEXTURE_2D:
1770 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001771 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001772 {
Geoff Langb1196682014-07-23 13:47:29 -04001773 context->recordError(Error(GL_INVALID_VALUE));
1774 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001775 }
1776 if (tex->getTarget() != GL_TEXTURE_2D)
1777 {
Geoff Langb1196682014-07-23 13:47:29 -04001778 context->recordError(Error(GL_INVALID_OPERATION));
1779 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001780 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001781 }
1782 break;
1783
1784 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1785 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1786 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1787 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1788 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1789 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1790 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001791 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001792 {
Geoff Langb1196682014-07-23 13:47:29 -04001793 context->recordError(Error(GL_INVALID_VALUE));
1794 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001795 }
1796 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1797 {
Geoff Langb1196682014-07-23 13:47:29 -04001798 context->recordError(Error(GL_INVALID_OPERATION));
1799 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001800 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001801 }
1802 break;
1803
1804 default:
Geoff Langb1196682014-07-23 13:47:29 -04001805 context->recordError(Error(GL_INVALID_ENUM));
1806 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001807 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001808
1809 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1810 if (internalFormatInfo.compressed)
1811 {
1812 context->recordError(Error(GL_INVALID_OPERATION));
1813 return false;
1814 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001815 }
1816
Jamie Madill570f7c82014-07-03 10:38:54 -04001817 return true;
1818}
1819
Geoff Langb1196682014-07-23 13:47:29 -04001820bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001821{
1822 if (program == 0)
1823 {
Geoff Langb1196682014-07-23 13:47:29 -04001824 context->recordError(Error(GL_INVALID_VALUE));
1825 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001826 }
1827
Shannon Woods4de4fd62014-11-07 16:22:02 -05001828 if (!ValidProgram(context, program))
1829 {
1830 return false;
1831 }
1832
Jamie Madill0063c512014-08-25 15:47:53 -04001833 gl::Program *programObject = context->getProgram(program);
1834
1835 if (!programObject || !programObject->isLinked())
1836 {
Geoff Langb1196682014-07-23 13:47:29 -04001837 context->recordError(Error(GL_INVALID_OPERATION));
1838 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001839 }
1840
Geoff Lang7dd2e102014-11-10 15:19:26 -05001841 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001842 {
Geoff Langb1196682014-07-23 13:47:29 -04001843 context->recordError(Error(GL_INVALID_OPERATION));
1844 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001845 }
1846
Jamie Madill0063c512014-08-25 15:47:53 -04001847 return true;
1848}
1849
Geoff Langb1196682014-07-23 13:47:29 -04001850bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001851{
1852 return ValidateGetUniformBase(context, program, location);
1853}
1854
Geoff Langb1196682014-07-23 13:47:29 -04001855bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001856{
Jamie Madill78f41802014-08-25 15:47:55 -04001857 return ValidateGetUniformBase(context, program, location);
1858}
1859
Geoff Langb1196682014-07-23 13:47:29 -04001860static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001861{
1862 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001863 {
Jamie Madill78f41802014-08-25 15:47:55 -04001864 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001865 }
1866
Jamie Madilla502c742014-08-28 17:19:13 -04001867 gl::Program *programObject = context->getProgram(program);
1868 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001869
Jamie Madill78f41802014-08-25 15:47:55 -04001870 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001871 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001872 size_t requiredBytes = VariableExternalSize(uniform->type);
1873 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001874 {
Geoff Langb1196682014-07-23 13:47:29 -04001875 context->recordError(Error(GL_INVALID_OPERATION));
1876 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001877 }
1878
1879 return true;
1880}
1881
Geoff Langb1196682014-07-23 13:47:29 -04001882bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* 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
Geoff Langb1196682014-07-23 13:47:29 -04001887bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001888{
Jamie Madill78f41802014-08-25 15:47:55 -04001889 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001890}
1891
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001892}