blob: 695f94f62081369a9917fdf9a6a2de25a5c7160b [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"
18#include "libANGLE/ProgramBinary.h"
19#include "libANGLE/TransformFeedback.h"
20#include "libANGLE/VertexArray.h"
21#include "libANGLE/renderer/BufferImpl.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040022
23#include "common/mathutil.h"
24#include "common/utilities.h"
25
Jamie Madill9ae396b2014-10-21 17:46:30 -040026// FIXME(jmadill): remove this when we support buffer data caching
Geoff Lang2b5420c2014-11-19 14:20:15 -050027#include "libANGLE/renderer/d3d/BufferD3D.h"
Jamie Madill9ae396b2014-10-21 17:46:30 -040028
Geoff Lange8ebe7f2013-08-05 15:03:13 -040029namespace gl
30{
31
Geoff Lang0550d032014-01-30 11:29:07 -050032bool ValidCap(const Context *context, GLenum cap)
33{
34 switch (cap)
35 {
36 case GL_CULL_FACE:
37 case GL_POLYGON_OFFSET_FILL:
38 case GL_SAMPLE_ALPHA_TO_COVERAGE:
39 case GL_SAMPLE_COVERAGE:
40 case GL_SCISSOR_TEST:
41 case GL_STENCIL_TEST:
42 case GL_DEPTH_TEST:
43 case GL_BLEND:
44 case GL_DITHER:
45 return true;
46 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
47 case GL_RASTERIZER_DISCARD:
48 return (context->getClientVersion() >= 3);
49 default:
50 return false;
51 }
52}
53
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050054bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040055{
Jamie Madilld7460c72014-01-21 16:38:14 -050056 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040057 {
Jamie Madilld7460c72014-01-21 16:38:14 -050058 case GL_TEXTURE_2D:
59 case GL_TEXTURE_CUBE_MAP:
60 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040061
Jamie Madilld7460c72014-01-21 16:38:14 -050062 case GL_TEXTURE_3D:
63 case GL_TEXTURE_2D_ARRAY:
64 return (context->getClientVersion() >= 3);
65
66 default:
67 return false;
68 }
Jamie Madill35d15012013-10-07 10:46:37 -040069}
70
Shannon Woods4dfed832014-03-17 20:03:39 -040071// This function differs from ValidTextureTarget in that the target must be
72// usable as the destination of a 2D operation-- so a cube face is valid, but
73// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040074// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040075bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
76{
77 switch (target)
78 {
79 case GL_TEXTURE_2D:
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
84 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
85 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
86 return true;
87 case GL_TEXTURE_2D_ARRAY:
88 case GL_TEXTURE_3D:
89 return (context->getClientVersion() >= 3);
90 default:
91 return false;
92 }
93}
94
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050095bool ValidFramebufferTarget(GLenum target)
96{
97 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
98
99 switch (target)
100 {
101 case GL_FRAMEBUFFER: return true;
102 case GL_READ_FRAMEBUFFER: return true;
103 case GL_DRAW_FRAMEBUFFER: return true;
104 default: return false;
105 }
106}
107
Jamie Madill8c96d582014-03-05 15:01:23 -0500108bool ValidBufferTarget(const Context *context, GLenum target)
109{
110 switch (target)
111 {
112 case GL_ARRAY_BUFFER:
113 case GL_ELEMENT_ARRAY_BUFFER:
114 return true;
115
Jamie Madill8c96d582014-03-05 15:01:23 -0500116 case GL_PIXEL_PACK_BUFFER:
117 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400118 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400119
Shannon Woodsb3801742014-03-27 14:59:19 -0400120 case GL_COPY_READ_BUFFER:
121 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500122 case GL_TRANSFORM_FEEDBACK_BUFFER:
123 case GL_UNIFORM_BUFFER:
124 return (context->getClientVersion() >= 3);
125
126 default:
127 return false;
128 }
129}
130
Jamie Madill70656a62014-03-05 15:01:26 -0500131bool ValidBufferParameter(const Context *context, GLenum pname)
132{
133 switch (pname)
134 {
135 case GL_BUFFER_USAGE:
136 case GL_BUFFER_SIZE:
137 return true;
138
139 // GL_BUFFER_MAP_POINTER is a special case, and may only be
140 // queried with GetBufferPointerv
141 case GL_BUFFER_ACCESS_FLAGS:
142 case GL_BUFFER_MAPPED:
143 case GL_BUFFER_MAP_OFFSET:
144 case GL_BUFFER_MAP_LENGTH:
145 return (context->getClientVersion() >= 3);
146
147 default:
148 return false;
149 }
150}
151
Jamie Madill8c96d582014-03-05 15:01:23 -0500152bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400153{
Geoff Langaae65a42014-05-26 12:43:44 -0400154 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400155 switch (target)
156 {
Geoff Langaae65a42014-05-26 12:43:44 -0400157 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400158 case GL_TEXTURE_CUBE_MAP:
159 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
160 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
161 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
162 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
163 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400164 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
165 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
166 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400167 default: UNREACHABLE();
168 }
169
Geoff Langaae65a42014-05-26 12:43:44 -0400170 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400171}
172
Geoff Langb1196682014-07-23 13:47:29 -0400173bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400174 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400175{
176 if (level < 0 || width < 0 || height < 0 || depth < 0)
177 {
178 return false;
179 }
180
Geoff Langc0b9ef42014-07-02 10:02:37 -0400181 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400182 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400183 {
184 return false;
185 }
186
187 if (!ValidMipLevel(context, target, level))
188 {
189 return false;
190 }
191
192 return true;
193}
194
Geoff Langb1196682014-07-23 13:47:29 -0400195bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400196{
Geoff Lang5d601382014-07-22 15:14:06 -0400197 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
198 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400199 {
200 return false;
201 }
202
Geoff Lang5d601382014-07-22 15:14:06 -0400203 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
204 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400205 {
206 return false;
207 }
208
209 return true;
210}
211
Geoff Lang37dde692014-01-31 16:34:54 -0500212bool ValidQueryType(const Context *context, GLenum queryType)
213{
214 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
215 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
216
217 switch (queryType)
218 {
219 case GL_ANY_SAMPLES_PASSED:
220 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
221 return true;
222 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
223 return (context->getClientVersion() >= 3);
224 default:
225 return false;
226 }
227}
228
Geoff Langb1196682014-07-23 13:47:29 -0400229bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500230{
231 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
232 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
233 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
234
235 if (context->getProgram(id) != NULL)
236 {
237 return true;
238 }
239 else if (context->getShader(id) != NULL)
240 {
241 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400242 context->recordError(Error(GL_INVALID_OPERATION));
243 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500244 }
245 else
246 {
247 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400248 context->recordError(Error(GL_INVALID_VALUE));
249 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500250 }
251}
252
Geoff Langb1196682014-07-23 13:47:29 -0400253bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400254{
255 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
256 {
257 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
258
Geoff Langaae65a42014-05-26 12:43:44 -0400259 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400260 {
Geoff Langb1196682014-07-23 13:47:29 -0400261 context->recordError(Error(GL_INVALID_VALUE));
262 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400263 }
264 }
265 else
266 {
267 switch (attachment)
268 {
269 case GL_DEPTH_ATTACHMENT:
270 case GL_STENCIL_ATTACHMENT:
271 break;
272
273 case GL_DEPTH_STENCIL_ATTACHMENT:
274 if (context->getClientVersion() < 3)
275 {
Geoff Langb1196682014-07-23 13:47:29 -0400276 context->recordError(Error(GL_INVALID_ENUM));
277 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400278 }
279 break;
280
281 default:
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 }
286
287 return true;
288}
289
Corentin Walleze0902642014-11-04 12:32:15 -0800290bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
291 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400292{
293 switch (target)
294 {
295 case GL_RENDERBUFFER:
296 break;
297 default:
Geoff Langb1196682014-07-23 13:47:29 -0400298 context->recordError(Error(GL_INVALID_ENUM));
299 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400300 }
301
302 if (width < 0 || height < 0 || samples < 0)
303 {
Geoff Langb1196682014-07-23 13:47:29 -0400304 context->recordError(Error(GL_INVALID_VALUE));
305 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400306 }
307
Geoff Langd87878e2014-09-19 15:42:59 -0400308 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
309 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400310 {
Geoff Langb1196682014-07-23 13:47:29 -0400311 context->recordError(Error(GL_INVALID_ENUM));
312 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400313 }
314
315 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
316 // 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 -0800317 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400318 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400319 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400320 {
Geoff Langb1196682014-07-23 13:47:29 -0400321 context->recordError(Error(GL_INVALID_ENUM));
322 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400323 }
324
Geoff Langaae65a42014-05-26 12:43:44 -0400325 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400326 {
Geoff Langb1196682014-07-23 13:47:29 -0400327 context->recordError(Error(GL_INVALID_VALUE));
328 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400329 }
330
Shannon Woods53a94a82014-06-24 15:20:36 -0400331 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400332 if (handle == 0)
333 {
Geoff Langb1196682014-07-23 13:47:29 -0400334 context->recordError(Error(GL_INVALID_OPERATION));
335 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400336 }
337
338 return true;
339}
340
Corentin Walleze0902642014-11-04 12:32:15 -0800341bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
342 GLenum internalformat, GLsizei width, GLsizei height)
343{
344 ASSERT(context->getExtensions().framebufferMultisample);
345
346 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
347 // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is
348 // generated.
349 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
350 {
351 context->recordError(Error(GL_INVALID_VALUE));
352 return false;
353 }
354
355 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
356 // the specified storage. This is different than ES 3.0 in which a sample number higher
357 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
358 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
359 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
360 {
361 context->recordError(Error(GL_OUT_OF_MEMORY));
362 return false;
363 }
364
365 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
366}
367
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500368bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
369 GLenum renderbuffertarget, GLuint renderbuffer)
370{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400371 if (!ValidFramebufferTarget(target))
372 {
Geoff Langb1196682014-07-23 13:47:29 -0400373 context->recordError(Error(GL_INVALID_ENUM));
374 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400375 }
376
Shannon Woods53a94a82014-06-24 15:20:36 -0400377 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
378 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500379
380 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
381 {
Geoff Langb1196682014-07-23 13:47:29 -0400382 context->recordError(Error(GL_INVALID_OPERATION));
383 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500384 }
385
Jamie Madillb4472272014-07-03 10:38:55 -0400386 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500387 {
Jamie Madillb4472272014-07-03 10:38:55 -0400388 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500389 }
390
Jamie Madillab9d82c2014-01-21 16:38:14 -0500391 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
392 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
393 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
394 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
395 if (renderbuffer != 0)
396 {
397 if (!context->getRenderbuffer(renderbuffer))
398 {
Geoff Langb1196682014-07-23 13:47:29 -0400399 context->recordError(Error(GL_INVALID_OPERATION));
400 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500401 }
402 }
403
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500404 return true;
405}
406
Jamie Madill3c7fa222014-06-05 13:08:51 -0400407static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400408 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
409 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
410{
411 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
412 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
413 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
414 {
415 return true;
416 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400417 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400418 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400419 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400420
Shannon Woods53a94a82014-06-24 15:20:36 -0400421 return scissor.x > 0 || scissor.y > 0 ||
422 scissor.width < writeBuffer->getWidth() ||
423 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400424 }
425 else
426 {
427 return false;
428 }
429}
430
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400431bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400432 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
433 GLenum filter, bool fromAngleExtension)
434{
435 switch (filter)
436 {
437 case GL_NEAREST:
438 break;
439 case GL_LINEAR:
440 if (fromAngleExtension)
441 {
Geoff Langb1196682014-07-23 13:47:29 -0400442 context->recordError(Error(GL_INVALID_ENUM));
443 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400444 }
445 break;
446 default:
Geoff Langb1196682014-07-23 13:47:29 -0400447 context->recordError(Error(GL_INVALID_ENUM));
448 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400449 }
450
451 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
452 {
Geoff Langb1196682014-07-23 13:47:29 -0400453 context->recordError(Error(GL_INVALID_VALUE));
454 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400455 }
456
457 if (mask == 0)
458 {
459 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
460 // buffers are copied.
461 return false;
462 }
463
464 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
465 {
466 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400467 context->recordError(Error(GL_INVALID_OPERATION));
468 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400469 }
470
471 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
472 // color buffer, leaving only nearest being unfiltered from above
473 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
474 {
Geoff Langb1196682014-07-23 13:47:29 -0400475 context->recordError(Error(GL_INVALID_OPERATION));
476 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400477 }
478
Shannon Woods53a94a82014-06-24 15:20:36 -0400479 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400480 {
481 if (fromAngleExtension)
482 {
483 ERR("Blits with the same source and destination framebuffer are not supported by this "
484 "implementation.");
485 }
Geoff Langb1196682014-07-23 13:47:29 -0400486 context->recordError(Error(GL_INVALID_OPERATION));
487 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488 }
489
Shannon Woods53a94a82014-06-24 15:20:36 -0400490 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
491 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500492
493 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400494 {
Geoff Langb1196682014-07-23 13:47:29 -0400495 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
496 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400497 }
498
Jamie Madill48faf802014-11-06 15:27:22 -0500499 if (!readFramebuffer->completeness(context->getData()))
500 {
501 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
502 return false;
503 }
504
505 if (!drawFramebuffer->completeness(context->getData()))
506 {
507 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
508 return false;
509 }
510
511 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400512 {
Geoff Langb1196682014-07-23 13:47:29 -0400513 context->recordError(Error(GL_INVALID_OPERATION));
514 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 }
516
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400517 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
518
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519 if (mask & GL_COLOR_BUFFER_BIT)
520 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400521 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
522 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400523
524 if (readColorBuffer && drawColorBuffer)
525 {
Geoff Lang005df412013-10-16 14:12:50 -0400526 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400527 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400528
529 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
530 {
531 if (drawFramebuffer->isEnabledColorAttachment(i))
532 {
Geoff Lang005df412013-10-16 14:12:50 -0400533 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400534 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400535
Geoff Langb2f3d052013-08-13 12:49:27 -0400536 // The GL ES 3.0.2 spec (pg 193) states that:
537 // 1) If the read buffer is fixed point format, the draw buffer must be as well
538 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
539 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400540 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
541 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400542 {
Geoff Langb1196682014-07-23 13:47:29 -0400543 context->recordError(Error(GL_INVALID_OPERATION));
544 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400545 }
546
Geoff Lang5d601382014-07-22 15:14:06 -0400547 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400548 {
Geoff Langb1196682014-07-23 13:47:29 -0400549 context->recordError(Error(GL_INVALID_OPERATION));
550 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400551 }
552
Geoff Lang5d601382014-07-22 15:14:06 -0400553 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400554 {
Geoff Langb1196682014-07-23 13:47:29 -0400555 context->recordError(Error(GL_INVALID_OPERATION));
556 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400557 }
558
Geoff Langb2f3d052013-08-13 12:49:27 -0400559 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400560 {
Geoff Langb1196682014-07-23 13:47:29 -0400561 context->recordError(Error(GL_INVALID_OPERATION));
562 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400563 }
564 }
565 }
566
Geoff Lang5d601382014-07-22 15:14:06 -0400567 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400568 {
Geoff Langb1196682014-07-23 13:47:29 -0400569 context->recordError(Error(GL_INVALID_OPERATION));
570 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400571 }
572
573 if (fromAngleExtension)
574 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500575 FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
576 if (!readColorAttachment ||
577 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
578 readColorAttachment->type() != GL_RENDERBUFFER &&
579 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400580 {
Geoff Langb1196682014-07-23 13:47:29 -0400581 context->recordError(Error(GL_INVALID_OPERATION));
582 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400583 }
584
585 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
586 {
587 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
588 {
Jamie Madille92a3542014-07-03 10:38:58 -0400589 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
590 ASSERT(attachment);
591
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500592 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
593 attachment->type() != GL_RENDERBUFFER &&
594 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400595 {
Geoff Langb1196682014-07-23 13:47:29 -0400596 context->recordError(Error(GL_INVALID_OPERATION));
597 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400598 }
599
Jamie Madillf8f18f02014-10-02 10:44:17 -0400600 // Return an error if the destination formats do not match
601 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
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 }
607 }
Jamie Madill48faf802014-11-06 15:27:22 -0500608
609 int readSamples = readFramebuffer->getSamples(context->getData());
610
611 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
612 srcX0, srcY0, srcX1, srcY1,
613 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400614 {
Geoff Langb1196682014-07-23 13:47:29 -0400615 context->recordError(Error(GL_INVALID_OPERATION));
616 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400617 }
618 }
619 }
620 }
621
622 if (mask & GL_DEPTH_BUFFER_BIT)
623 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400624 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
625 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400626
627 if (readDepthBuffer && drawDepthBuffer)
628 {
629 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
630 {
Geoff Langb1196682014-07-23 13:47:29 -0400631 context->recordError(Error(GL_INVALID_OPERATION));
632 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 }
634
635 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
636 {
Geoff Langb1196682014-07-23 13:47:29 -0400637 context->recordError(Error(GL_INVALID_OPERATION));
638 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 }
640
641 if (fromAngleExtension)
642 {
Geoff Lang125deab2013-08-09 13:34:16 -0400643 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
644 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 {
646 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400647 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
648 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 }
650
651 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
652 {
Geoff Langb1196682014-07-23 13:47:29 -0400653 context->recordError(Error(GL_INVALID_OPERATION));
654 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 }
656 }
657 }
658 }
659
660 if (mask & GL_STENCIL_BUFFER_BIT)
661 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400662 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
663 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 if (readStencilBuffer && drawStencilBuffer)
666 {
667 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
668 {
Geoff Langb1196682014-07-23 13:47:29 -0400669 context->recordError(Error(GL_INVALID_OPERATION));
670 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400671 }
672
673 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
674 {
Geoff Langb1196682014-07-23 13:47:29 -0400675 context->recordError(Error(GL_INVALID_OPERATION));
676 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400677 }
678
679 if (fromAngleExtension)
680 {
Geoff Lang125deab2013-08-09 13:34:16 -0400681 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
682 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 {
684 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400685 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
686 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 }
688
689 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
690 {
Geoff Langb1196682014-07-23 13:47:29 -0400691 context->recordError(Error(GL_INVALID_OPERATION));
692 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400693 }
694 }
695 }
696 }
697
698 return true;
699}
700
Geoff Langb1196682014-07-23 13:47:29 -0400701bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702{
703 switch (pname)
704 {
705 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
706 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
707 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
708 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
709 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
710 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
711 case GL_CURRENT_VERTEX_ATTRIB:
712 return true;
713
714 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
715 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
716 // the same constant.
717 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
718 return true;
719
720 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400721 if (context->getClientVersion() < 3)
722 {
723 context->recordError(Error(GL_INVALID_ENUM));
724 return false;
725 }
726 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400727
728 default:
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}
733
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400734bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735{
736 switch (pname)
737 {
738 case GL_TEXTURE_WRAP_R:
739 case GL_TEXTURE_SWIZZLE_R:
740 case GL_TEXTURE_SWIZZLE_G:
741 case GL_TEXTURE_SWIZZLE_B:
742 case GL_TEXTURE_SWIZZLE_A:
743 case GL_TEXTURE_BASE_LEVEL:
744 case GL_TEXTURE_MAX_LEVEL:
745 case GL_TEXTURE_COMPARE_MODE:
746 case GL_TEXTURE_COMPARE_FUNC:
747 case GL_TEXTURE_MIN_LOD:
748 case GL_TEXTURE_MAX_LOD:
749 if (context->getClientVersion() < 3)
750 {
Geoff Langb1196682014-07-23 13:47:29 -0400751 context->recordError(Error(GL_INVALID_ENUM));
752 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400753 }
754 break;
755
756 default: break;
757 }
758
759 switch (pname)
760 {
761 case GL_TEXTURE_WRAP_S:
762 case GL_TEXTURE_WRAP_T:
763 case GL_TEXTURE_WRAP_R:
764 switch (param)
765 {
766 case GL_REPEAT:
767 case GL_CLAMP_TO_EDGE:
768 case GL_MIRRORED_REPEAT:
769 return true;
770 default:
Geoff Langb1196682014-07-23 13:47:29 -0400771 context->recordError(Error(GL_INVALID_ENUM));
772 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400773 }
774
775 case GL_TEXTURE_MIN_FILTER:
776 switch (param)
777 {
778 case GL_NEAREST:
779 case GL_LINEAR:
780 case GL_NEAREST_MIPMAP_NEAREST:
781 case GL_LINEAR_MIPMAP_NEAREST:
782 case GL_NEAREST_MIPMAP_LINEAR:
783 case GL_LINEAR_MIPMAP_LINEAR:
784 return true;
785 default:
Geoff Langb1196682014-07-23 13:47:29 -0400786 context->recordError(Error(GL_INVALID_ENUM));
787 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400788 }
789 break;
790
791 case GL_TEXTURE_MAG_FILTER:
792 switch (param)
793 {
794 case GL_NEAREST:
795 case GL_LINEAR:
796 return true;
797 default:
Geoff Langb1196682014-07-23 13:47:29 -0400798 context->recordError(Error(GL_INVALID_ENUM));
799 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 }
801 break;
802
803 case GL_TEXTURE_USAGE_ANGLE:
804 switch (param)
805 {
806 case GL_NONE:
807 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
808 return true;
809 default:
Geoff Langb1196682014-07-23 13:47:29 -0400810 context->recordError(Error(GL_INVALID_ENUM));
811 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400812 }
813 break;
814
815 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400816 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400817 {
Geoff Langb1196682014-07-23 13:47:29 -0400818 context->recordError(Error(GL_INVALID_ENUM));
819 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400820 }
821
822 // we assume the parameter passed to this validation method is truncated, not rounded
823 if (param < 1)
824 {
Geoff Langb1196682014-07-23 13:47:29 -0400825 context->recordError(Error(GL_INVALID_VALUE));
826 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400827 }
828 return true;
829
830 case GL_TEXTURE_MIN_LOD:
831 case GL_TEXTURE_MAX_LOD:
832 // any value is permissible
833 return true;
834
835 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400836 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400837 switch (param)
838 {
839 case GL_NONE:
840 case GL_COMPARE_REF_TO_TEXTURE:
841 return true;
842 default:
Geoff Langb1196682014-07-23 13:47:29 -0400843 context->recordError(Error(GL_INVALID_ENUM));
844 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400845 }
846 break;
847
848 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400849 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400850 switch (param)
851 {
852 case GL_LEQUAL:
853 case GL_GEQUAL:
854 case GL_LESS:
855 case GL_GREATER:
856 case GL_EQUAL:
857 case GL_NOTEQUAL:
858 case GL_ALWAYS:
859 case GL_NEVER:
860 return true;
861 default:
Geoff Langb1196682014-07-23 13:47:29 -0400862 context->recordError(Error(GL_INVALID_ENUM));
863 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400864 }
865 break;
866
867 case GL_TEXTURE_SWIZZLE_R:
868 case GL_TEXTURE_SWIZZLE_G:
869 case GL_TEXTURE_SWIZZLE_B:
870 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400871 switch (param)
872 {
873 case GL_RED:
874 case GL_GREEN:
875 case GL_BLUE:
876 case GL_ALPHA:
877 case GL_ZERO:
878 case GL_ONE:
879 return true;
880 default:
Geoff Langb1196682014-07-23 13:47:29 -0400881 context->recordError(Error(GL_INVALID_ENUM));
882 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400883 }
884 break;
885
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400886 case GL_TEXTURE_BASE_LEVEL:
887 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400888 if (param < 0)
889 {
Geoff Langb1196682014-07-23 13:47:29 -0400890 context->recordError(Error(GL_INVALID_VALUE));
891 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400892 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400893 return true;
894
895 default:
Geoff Langb1196682014-07-23 13:47:29 -0400896 context->recordError(Error(GL_INVALID_ENUM));
897 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400898 }
899}
900
Geoff Langb1196682014-07-23 13:47:29 -0400901bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400902{
903 switch (pname)
904 {
905 case GL_TEXTURE_MIN_FILTER:
906 case GL_TEXTURE_MAG_FILTER:
907 case GL_TEXTURE_WRAP_S:
908 case GL_TEXTURE_WRAP_T:
909 case GL_TEXTURE_WRAP_R:
910 case GL_TEXTURE_MIN_LOD:
911 case GL_TEXTURE_MAX_LOD:
912 case GL_TEXTURE_COMPARE_MODE:
913 case GL_TEXTURE_COMPARE_FUNC:
914 return true;
915
916 default:
Geoff Langb1196682014-07-23 13:47:29 -0400917 context->recordError(Error(GL_INVALID_ENUM));
918 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400919 }
920}
921
Jamie Madill26e91952014-03-05 15:01:27 -0500922bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
923 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
924{
Shannon Woods53a94a82014-06-24 15:20:36 -0400925 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400926 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500927
Jamie Madill48faf802014-11-06 15:27:22 -0500928 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500929 {
Geoff Langb1196682014-07-23 13:47:29 -0400930 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
931 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500932 }
933
Jamie Madill48faf802014-11-06 15:27:22 -0500934 if (context->getState().getReadFramebuffer()->id() != 0 &&
935 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500936 {
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_OPERATION));
938 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500939 }
940
Jamie Madill893ab082014-05-16 16:56:10 -0400941 if (!framebuffer->getReadColorbuffer())
942 {
Geoff Langb1196682014-07-23 13:47:29 -0400943 context->recordError(Error(GL_INVALID_OPERATION));
944 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400945 }
946
Jamie Madill26e91952014-03-05 15:01:27 -0500947 GLenum currentInternalFormat, currentFormat, currentType;
Geoff Lange4a492b2014-06-19 14:14:41 -0400948 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500949
Jamie Madill893ab082014-05-16 16:56:10 -0400950 context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
Jamie Madill26e91952014-03-05 15:01:27 -0500951
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400952 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
953 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500954
955 if (!(currentFormat == format && currentType == type) && !validReadFormat)
956 {
Geoff Langb1196682014-07-23 13:47:29 -0400957 context->recordError(Error(GL_INVALID_OPERATION));
958 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500959 }
960
Geoff Lang5d601382014-07-22 15:14:06 -0400961 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
962 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500963
Geoff Lang5d601382014-07-22 15:14:06 -0400964 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
Jamie Madill26e91952014-03-05 15:01:27 -0500965 // sized query sanity check
966 if (bufSize)
967 {
968 int requiredSize = outputPitch * height;
969 if (requiredSize > *bufSize)
970 {
Geoff Langb1196682014-07-23 13:47:29 -0400971 context->recordError(Error(GL_INVALID_OPERATION));
972 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500973 }
974 }
975
976 return true;
977}
978
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400979bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
980{
981 if (!ValidQueryType(context, target))
982 {
Geoff Langb1196682014-07-23 13:47:29 -0400983 context->recordError(Error(GL_INVALID_ENUM));
984 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400985 }
986
987 if (id == 0)
988 {
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 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
994 // of zero, if the active query object name for <target> is non-zero (for the
995 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
996 // the active query for either target is non-zero), if <id> is the name of an
997 // existing query object whose type does not match <target>, or if <id> is the
998 // active query object name for any query type, the error INVALID_OPERATION is
999 // generated.
1000
1001 // Ensure no other queries are active
1002 // NOTE: If other queries than occlusion are supported, we will need to check
1003 // separately that:
1004 // a) The query ID passed is not the current active query for any target/type
1005 // b) There are no active queries for the requested target (and in the case
1006 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1007 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001008 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001009 {
Geoff Langb1196682014-07-23 13:47:29 -04001010 context->recordError(Error(GL_INVALID_OPERATION));
1011 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001012 }
1013
1014 Query *queryObject = context->getQuery(id, true, target);
1015
1016 // check that name was obtained with glGenQueries
1017 if (!queryObject)
1018 {
Geoff Langb1196682014-07-23 13:47:29 -04001019 context->recordError(Error(GL_INVALID_OPERATION));
1020 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001021 }
1022
1023 // check for type mismatch
1024 if (queryObject->getType() != target)
1025 {
Geoff Langb1196682014-07-23 13:47:29 -04001026 context->recordError(Error(GL_INVALID_OPERATION));
1027 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001028 }
1029
1030 return true;
1031}
1032
Jamie Madill45c785d2014-05-13 14:09:34 -04001033bool ValidateEndQuery(gl::Context *context, GLenum target)
1034{
1035 if (!ValidQueryType(context, target))
1036 {
Geoff Langb1196682014-07-23 13:47:29 -04001037 context->recordError(Error(GL_INVALID_ENUM));
1038 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001039 }
1040
Shannon Woods53a94a82014-06-24 15:20:36 -04001041 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001042
1043 if (queryObject == NULL)
1044 {
Geoff Langb1196682014-07-23 13:47:29 -04001045 context->recordError(Error(GL_INVALID_OPERATION));
1046 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001047 }
1048
Jamie Madill45c785d2014-05-13 14:09:34 -04001049 return true;
1050}
1051
Jamie Madill36398922014-05-20 14:51:53 -04001052static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1053 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001054{
1055 if (count < 0)
1056 {
Geoff Langb1196682014-07-23 13:47:29 -04001057 context->recordError(Error(GL_INVALID_VALUE));
1058 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001059 }
1060
Shannon Woods53a94a82014-06-24 15:20:36 -04001061 gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001062 if (!programBinary)
1063 {
Geoff Langb1196682014-07-23 13:47:29 -04001064 context->recordError(Error(GL_INVALID_OPERATION));
1065 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001066 }
1067
1068 if (location == -1)
1069 {
1070 // Silently ignore the uniform command
1071 return false;
1072 }
1073
Jamie Madill36398922014-05-20 14:51:53 -04001074 if (!programBinary->isValidUniformLocation(location))
1075 {
Geoff Langb1196682014-07-23 13:47:29 -04001076 context->recordError(Error(GL_INVALID_OPERATION));
1077 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001078 }
1079
1080 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1081
1082 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1083 if (uniform->elementCount() == 1 && count > 1)
1084 {
Geoff Langb1196682014-07-23 13:47:29 -04001085 context->recordError(Error(GL_INVALID_OPERATION));
1086 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001087 }
1088
1089 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001090 return true;
1091}
1092
Jamie Madillaa981bd2014-05-20 10:55:55 -04001093bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1094{
1095 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001096 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001097 {
Geoff Langb1196682014-07-23 13:47:29 -04001098 context->recordError(Error(GL_INVALID_OPERATION));
1099 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001100 }
1101
Jamie Madill36398922014-05-20 14:51:53 -04001102 LinkedUniform *uniform = NULL;
1103 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1104 {
1105 return false;
1106 }
1107
Jamie Madillf2575982014-06-25 16:04:54 -04001108 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Jamie Madill36398922014-05-20 14:51:53 -04001109 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1110 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1111 {
Geoff Langb1196682014-07-23 13:47:29 -04001112 context->recordError(Error(GL_INVALID_OPERATION));
1113 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001114 }
1115
1116 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001117}
1118
1119bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1120 GLboolean transpose)
1121{
1122 // Check for ES3 uniform entry points
1123 int rows = VariableRowCount(matrixType);
1124 int cols = VariableColumnCount(matrixType);
1125 if (rows != cols && context->getClientVersion() < 3)
1126 {
Geoff Langb1196682014-07-23 13:47:29 -04001127 context->recordError(Error(GL_INVALID_OPERATION));
1128 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001129 }
1130
1131 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1132 {
Geoff Langb1196682014-07-23 13:47:29 -04001133 context->recordError(Error(GL_INVALID_VALUE));
1134 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001135 }
1136
Jamie Madill36398922014-05-20 14:51:53 -04001137 LinkedUniform *uniform = NULL;
1138 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1139 {
1140 return false;
1141 }
1142
1143 if (uniform->type != matrixType)
1144 {
Geoff Langb1196682014-07-23 13:47:29 -04001145 context->recordError(Error(GL_INVALID_OPERATION));
1146 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001147 }
1148
1149 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001150}
1151
Jamie Madill893ab082014-05-16 16:56:10 -04001152bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1153{
1154 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1155 {
Geoff Langb1196682014-07-23 13:47:29 -04001156 context->recordError(Error(GL_INVALID_ENUM));
1157 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001158 }
1159
1160 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1161 {
1162 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1163
Geoff Langaae65a42014-05-26 12:43:44 -04001164 if (colorAttachment >= context->getCaps().maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001165 {
Geoff Langb1196682014-07-23 13:47:29 -04001166 context->recordError(Error(GL_INVALID_OPERATION));
1167 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001168 }
1169 }
1170
1171 switch (pname)
1172 {
1173 case GL_TEXTURE_BINDING_2D:
1174 case GL_TEXTURE_BINDING_CUBE_MAP:
1175 case GL_TEXTURE_BINDING_3D:
1176 case GL_TEXTURE_BINDING_2D_ARRAY:
Geoff Lang3a61c322014-07-10 13:01:54 -04001177 if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
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 break;
1183
1184 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1185 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1186 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001187 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001188 ASSERT(framebuffer);
Jamie Madill48faf802014-11-06 15:27:22 -05001189 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001190 {
Geoff Langb1196682014-07-23 13:47:29 -04001191 context->recordError(Error(GL_INVALID_OPERATION));
1192 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001193 }
1194
Jamie Madill3c7fa222014-06-05 13:08:51 -04001195 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1196 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001197 {
Geoff Langb1196682014-07-23 13:47:29 -04001198 context->recordError(Error(GL_INVALID_OPERATION));
1199 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001200 }
1201 }
1202 break;
1203
1204 default:
1205 break;
1206 }
1207
1208 // pname is valid, but there are no parameters to return
1209 if (numParams == 0)
1210 {
1211 return false;
1212 }
1213
1214 return true;
1215}
1216
Jamie Madill560a8d82014-05-21 13:06:20 -04001217bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1218 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1219 GLint border, GLenum *textureFormatOut)
1220{
1221
1222 if (!ValidTexture2DDestinationTarget(context, target))
1223 {
Geoff Langb1196682014-07-23 13:47:29 -04001224 context->recordError(Error(GL_INVALID_ENUM));
1225 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001226 }
1227
1228 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1229 {
Geoff Langb1196682014-07-23 13:47:29 -04001230 context->recordError(Error(GL_INVALID_VALUE));
1231 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001232 }
1233
1234 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1235 {
Geoff Langb1196682014-07-23 13:47:29 -04001236 context->recordError(Error(GL_INVALID_VALUE));
1237 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001238 }
1239
1240 if (border != 0)
1241 {
Geoff Langb1196682014-07-23 13:47:29 -04001242 context->recordError(Error(GL_INVALID_VALUE));
1243 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001244 }
1245
1246 if (!ValidMipLevel(context, target, level))
1247 {
Geoff Langb1196682014-07-23 13:47:29 -04001248 context->recordError(Error(GL_INVALID_VALUE));
1249 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001250 }
1251
Shannon Woods53a94a82014-06-24 15:20:36 -04001252 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001253 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001254 {
Geoff Langb1196682014-07-23 13:47:29 -04001255 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1256 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001257 }
1258
Jamie Madill48faf802014-11-06 15:27:22 -05001259 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001260 {
Geoff Langb1196682014-07-23 13:47:29 -04001261 context->recordError(Error(GL_INVALID_OPERATION));
1262 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001263 }
1264
Geoff Langaae65a42014-05-26 12:43:44 -04001265 const gl::Caps &caps = context->getCaps();
1266
Jamie Madill560a8d82014-05-21 13:06:20 -04001267 gl::Texture *texture = NULL;
1268 GLenum textureInternalFormat = GL_NONE;
Jamie Madill560a8d82014-05-21 13:06:20 -04001269 GLint textureLevelWidth = 0;
1270 GLint textureLevelHeight = 0;
1271 GLint textureLevelDepth = 0;
Geoff Langaae65a42014-05-26 12:43:44 -04001272 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001273
1274 switch (target)
1275 {
1276 case GL_TEXTURE_2D:
1277 {
1278 gl::Texture2D *texture2d = context->getTexture2D();
1279 if (texture2d)
1280 {
1281 textureInternalFormat = texture2d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001282 textureLevelWidth = texture2d->getWidth(level);
1283 textureLevelHeight = texture2d->getHeight(level);
1284 textureLevelDepth = 1;
1285 texture = texture2d;
Geoff Langaae65a42014-05-26 12:43:44 -04001286 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001287 }
1288 }
1289 break;
1290
1291 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1292 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1293 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1294 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1295 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1296 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1297 {
1298 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1299 if (textureCube)
1300 {
1301 textureInternalFormat = textureCube->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001302 textureLevelWidth = textureCube->getWidth(target, level);
1303 textureLevelHeight = textureCube->getHeight(target, level);
1304 textureLevelDepth = 1;
1305 texture = textureCube;
Geoff Langaae65a42014-05-26 12:43:44 -04001306 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001307 }
1308 }
1309 break;
1310
1311 case GL_TEXTURE_2D_ARRAY:
1312 {
1313 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1314 if (texture2dArray)
1315 {
1316 textureInternalFormat = texture2dArray->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001317 textureLevelWidth = texture2dArray->getWidth(level);
1318 textureLevelHeight = texture2dArray->getHeight(level);
1319 textureLevelDepth = texture2dArray->getLayers(level);
1320 texture = texture2dArray;
Geoff Langaae65a42014-05-26 12:43:44 -04001321 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001322 }
1323 }
1324 break;
1325
1326 case GL_TEXTURE_3D:
1327 {
1328 gl::Texture3D *texture3d = context->getTexture3D();
1329 if (texture3d)
1330 {
1331 textureInternalFormat = texture3d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001332 textureLevelWidth = texture3d->getWidth(level);
1333 textureLevelHeight = texture3d->getHeight(level);
1334 textureLevelDepth = texture3d->getDepth(level);
1335 texture = texture3d;
Geoff Langaae65a42014-05-26 12:43:44 -04001336 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001337 }
1338 }
1339 break;
1340
1341 default:
Geoff Langb1196682014-07-23 13:47:29 -04001342 context->recordError(Error(GL_INVALID_ENUM));
1343 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001344 }
1345
1346 if (!texture)
1347 {
Geoff Langb1196682014-07-23 13:47:29 -04001348 context->recordError(Error(GL_INVALID_OPERATION));
1349 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001350 }
1351
1352 if (texture->isImmutable() && !isSubImage)
1353 {
Geoff Langb1196682014-07-23 13:47:29 -04001354 context->recordError(Error(GL_INVALID_OPERATION));
1355 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001356 }
1357
Geoff Lang5d601382014-07-22 15:14:06 -04001358 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1359
1360 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001361 {
Geoff Langb1196682014-07-23 13:47:29 -04001362 context->recordError(Error(GL_INVALID_OPERATION));
1363 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001364 }
1365
Geoff Lang5d601382014-07-22 15:14:06 -04001366 if (formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04001367 {
Geoff Lang5d601382014-07-22 15:14:06 -04001368 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1369 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 {
Geoff Langb1196682014-07-23 13:47:29 -04001371 context->recordError(Error(GL_INVALID_OPERATION));
1372 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001373 }
1374 }
1375
1376 if (isSubImage)
1377 {
1378 if (xoffset + width > textureLevelWidth ||
1379 yoffset + height > textureLevelHeight ||
1380 zoffset >= textureLevelDepth)
1381 {
Geoff Langb1196682014-07-23 13:47:29 -04001382 context->recordError(Error(GL_INVALID_VALUE));
1383 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001384 }
1385 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001386 else
1387 {
1388 if (IsCubemapTextureTarget(target) && width != height)
1389 {
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_VALUE));
1391 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001392 }
1393
Geoff Lang5d601382014-07-22 15:14:06 -04001394 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001395 {
Geoff Langb1196682014-07-23 13:47:29 -04001396 context->recordError(Error(GL_INVALID_ENUM));
1397 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001398 }
1399
1400 int maxLevelDimension = (maxDimension >> level);
1401 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1402 {
Geoff Langb1196682014-07-23 13:47:29 -04001403 context->recordError(Error(GL_INVALID_VALUE));
1404 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001405 }
1406 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001407
1408 *textureFormatOut = textureInternalFormat;
1409 return true;
1410}
1411
Geoff Langb1196682014-07-23 13:47:29 -04001412static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001413{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001414 switch (mode)
1415 {
1416 case GL_POINTS:
1417 case GL_LINES:
1418 case GL_LINE_LOOP:
1419 case GL_LINE_STRIP:
1420 case GL_TRIANGLES:
1421 case GL_TRIANGLE_STRIP:
1422 case GL_TRIANGLE_FAN:
1423 break;
1424 default:
Geoff Langb1196682014-07-23 13:47:29 -04001425 context->recordError(Error(GL_INVALID_ENUM));
1426 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001427 }
1428
Jamie Madill250d33f2014-06-06 17:09:03 -04001429 if (count < 0)
1430 {
Geoff Langb1196682014-07-23 13:47:29 -04001431 context->recordError(Error(GL_INVALID_VALUE));
1432 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001433 }
1434
Geoff Langb1196682014-07-23 13:47:29 -04001435 const State &state = context->getState();
1436
Jamie Madill250d33f2014-06-06 17:09:03 -04001437 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001438 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001439 {
Geoff Langb1196682014-07-23 13:47:29 -04001440 context->recordError(Error(GL_INVALID_OPERATION));
1441 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001442 }
1443
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001444 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001445 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001446 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001447 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1448 {
1449 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1450 // See Section 6.10 of the WebGL 1.0 spec
1451 ERR("This ANGLE implementation does not support separate front/back stencil "
1452 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001453 context->recordError(Error(GL_INVALID_OPERATION));
1454 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001455 }
1456
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001457 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001458 if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001459 {
Geoff Langb1196682014-07-23 13:47:29 -04001460 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1461 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001462 }
1463
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001464 if (state.getCurrentProgramId() == 0)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001465 {
Geoff Langb1196682014-07-23 13:47:29 -04001466 context->recordError(Error(GL_INVALID_OPERATION));
1467 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001468 }
1469
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001470 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
Brandon Jones43a53e22014-08-28 16:23:22 -07001471 if (!programBinary->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001472 {
Geoff Langb1196682014-07-23 13:47:29 -04001473 context->recordError(Error(GL_INVALID_OPERATION));
1474 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001475 }
1476
Jamie Madill2b976812014-08-25 15:47:49 -04001477 // Buffer validations
1478 const VertexArray *vao = state.getVertexArray();
1479 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1480 {
1481 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1482 bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
1483 if (attribActive && attrib.enabled)
1484 {
1485 gl::Buffer *buffer = attrib.buffer.get();
1486
1487 if (buffer)
1488 {
1489 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1490 GLint64 maxVertexElement = 0;
1491
1492 if (attrib.divisor > 0)
1493 {
1494 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1495 }
1496 else
1497 {
1498 maxVertexElement = static_cast<GLint64>(maxVertex);
1499 }
1500
1501 GLint64 attribDataSize = maxVertexElement * attribStride;
1502
1503 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1504 // We can return INVALID_OPERATION if our vertex attribute does not have
1505 // enough backing data.
1506 if (attribDataSize > buffer->getSize())
1507 {
Geoff Langb1196682014-07-23 13:47:29 -04001508 context->recordError(Error(GL_INVALID_OPERATION));
1509 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001510 }
1511 }
1512 else if (attrib.pointer == NULL)
1513 {
1514 // This is an application error that would normally result in a crash,
1515 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001516 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1517 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001518 }
1519 }
1520 }
1521
Jamie Madill250d33f2014-06-06 17:09:03 -04001522 // No-op if zero count
1523 return (count > 0);
1524}
1525
Geoff Langb1196682014-07-23 13:47:29 -04001526bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001527{
Jamie Madillfd716582014-06-06 17:09:04 -04001528 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001529 {
Geoff Langb1196682014-07-23 13:47:29 -04001530 context->recordError(Error(GL_INVALID_VALUE));
1531 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001532 }
1533
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001534 const State &state = context->getState();
1535 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001536 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1537 curTransformFeedback->getDrawMode() != mode)
1538 {
1539 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1540 // that does not match the current transform feedback object's draw mode (if transform feedback
1541 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001542 context->recordError(Error(GL_INVALID_OPERATION));
1543 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001544 }
1545
Geoff Langb1196682014-07-23 13:47:29 -04001546 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001547 {
1548 return false;
1549 }
1550
1551 return true;
1552}
1553
Geoff Langb1196682014-07-23 13:47:29 -04001554bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001555{
1556 if (primcount < 0)
1557 {
Geoff Langb1196682014-07-23 13:47:29 -04001558 context->recordError(Error(GL_INVALID_VALUE));
1559 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001560 }
1561
Jamie Madill2b976812014-08-25 15:47:49 -04001562 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001563 {
1564 return false;
1565 }
1566
1567 // No-op if zero primitive count
1568 return (primcount > 0);
1569}
1570
Geoff Lang87a93302014-09-16 13:29:43 -04001571static bool ValidateDrawInstancedANGLE(Context *context)
1572{
1573 // Verify there is at least one active attribute with a divisor of zero
1574 const gl::State& state = context->getState();
1575
1576 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1577
1578 const VertexArray *vao = state.getVertexArray();
1579 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1580 {
1581 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1582 bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
1583 if (active && attrib.divisor == 0)
1584 {
1585 return true;
1586 }
1587 }
1588
1589 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1590 "has a divisor of zero."));
1591 return false;
1592}
1593
1594bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1595{
1596 if (!ValidateDrawInstancedANGLE(context))
1597 {
1598 return false;
1599 }
1600
1601 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1602}
1603
Geoff Langb1196682014-07-23 13:47:29 -04001604bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001605 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001606{
Jamie Madill250d33f2014-06-06 17:09:03 -04001607 switch (type)
1608 {
1609 case GL_UNSIGNED_BYTE:
1610 case GL_UNSIGNED_SHORT:
1611 break;
1612 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001613 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001614 {
Geoff Langb1196682014-07-23 13:47:29 -04001615 context->recordError(Error(GL_INVALID_ENUM));
1616 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001617 }
1618 break;
1619 default:
Geoff Langb1196682014-07-23 13:47:29 -04001620 context->recordError(Error(GL_INVALID_ENUM));
1621 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001622 }
1623
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001624 const State &state = context->getState();
1625
1626 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001627 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1628 {
1629 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1630 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001631 context->recordError(Error(GL_INVALID_OPERATION));
1632 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001633 }
1634
1635 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001636 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001637 {
Geoff Langb1196682014-07-23 13:47:29 -04001638 context->recordError(Error(GL_INVALID_OPERATION));
1639 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001640 }
1641
Jamie Madill2b976812014-08-25 15:47:49 -04001642 const gl::VertexArray *vao = state.getVertexArray();
1643 const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1644 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001645 {
Geoff Langb1196682014-07-23 13:47:29 -04001646 context->recordError(Error(GL_INVALID_OPERATION));
1647 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001648 }
1649
Jamie Madillae3000b2014-08-25 15:47:51 -04001650 if (elementArrayBuffer)
1651 {
1652 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1653
1654 GLint64 offset = reinterpret_cast<GLint64>(indices);
1655 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1656
1657 // check for integer overflows
1658 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1659 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1660 {
Geoff Langb1196682014-07-23 13:47:29 -04001661 context->recordError(Error(GL_OUT_OF_MEMORY));
1662 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001663 }
1664
1665 // Check for reading past the end of the bound buffer object
1666 if (byteCount > elementArrayBuffer->getSize())
1667 {
Geoff Langb1196682014-07-23 13:47:29 -04001668 context->recordError(Error(GL_INVALID_OPERATION));
1669 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001670 }
1671 }
1672 else if (!indices)
1673 {
1674 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001675 context->recordError(Error(GL_INVALID_OPERATION));
1676 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001677 }
1678
Jamie Madill2b976812014-08-25 15:47:49 -04001679 // Use max index to validate if our vertex buffers are large enough for the pull.
1680 // TODO: offer fast path, with disabled index validation.
1681 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1682 if (elementArrayBuffer)
1683 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001684 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Jamie Madill2b976812014-08-25 15:47:49 -04001685 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1686 {
Jamie Madill9ae396b2014-10-21 17:46:30 -04001687 // FIXME(jmadill): Use buffer data caching instead of the D3D back-end
1688 rx::BufferD3D *bufferD3D = rx::BufferD3D::makeBufferD3D(elementArrayBuffer->getImplementation());
Geoff Langc8d297a2014-09-19 11:09:08 -04001689 const uint8_t *dataPointer = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -04001690 Error error = bufferD3D->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001691 if (error.isError())
1692 {
1693 context->recordError(error);
1694 return false;
1695 }
1696
1697 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001698 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1699 }
1700 }
1701 else
1702 {
1703 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1704 }
1705
Geoff Langb1196682014-07-23 13:47:29 -04001706 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001707 {
1708 return false;
1709 }
1710
1711 return true;
1712}
1713
Geoff Langb1196682014-07-23 13:47:29 -04001714bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001715 GLenum mode, GLsizei count, GLenum type,
1716 const GLvoid *indices, GLsizei primcount,
1717 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001718{
1719 if (primcount < 0)
1720 {
Geoff Langb1196682014-07-23 13:47:29 -04001721 context->recordError(Error(GL_INVALID_VALUE));
1722 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001723 }
1724
Jamie Madill2b976812014-08-25 15:47:49 -04001725 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001726 {
1727 return false;
1728 }
1729
1730 // No-op zero primitive count
1731 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001732}
1733
Geoff Lang87a93302014-09-16 13:29:43 -04001734bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1735 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1736{
1737 if (!ValidateDrawInstancedANGLE(context))
1738 {
1739 return false;
1740 }
1741
1742 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1743}
1744
Geoff Langb1196682014-07-23 13:47:29 -04001745bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001746 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001747{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001748 if (!ValidFramebufferTarget(target))
1749 {
Geoff Langb1196682014-07-23 13:47:29 -04001750 context->recordError(Error(GL_INVALID_ENUM));
1751 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001752 }
1753
1754 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001755 {
1756 return false;
1757 }
1758
Jamie Madill55ec3b12014-07-03 10:38:57 -04001759 if (texture != 0)
1760 {
1761 gl::Texture *tex = context->getTexture(texture);
1762
1763 if (tex == NULL)
1764 {
Geoff Langb1196682014-07-23 13:47:29 -04001765 context->recordError(Error(GL_INVALID_OPERATION));
1766 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001767 }
1768
1769 if (level < 0)
1770 {
Geoff Langb1196682014-07-23 13:47:29 -04001771 context->recordError(Error(GL_INVALID_VALUE));
1772 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001773 }
1774 }
1775
Shannon Woods53a94a82014-06-24 15:20:36 -04001776 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1777 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001778
1779 if (framebufferHandle == 0 || !framebuffer)
1780 {
Geoff Langb1196682014-07-23 13:47:29 -04001781 context->recordError(Error(GL_INVALID_OPERATION));
1782 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001783 }
1784
1785 return true;
1786}
1787
Geoff Langb1196682014-07-23 13:47:29 -04001788bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001789 GLenum textarget, GLuint texture, GLint level)
1790{
1791 // Attachments are required to be bound to level 0 in ES2
1792 if (context->getClientVersion() < 3 && level != 0)
1793 {
Geoff Langb1196682014-07-23 13:47:29 -04001794 context->recordError(Error(GL_INVALID_VALUE));
1795 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001796 }
1797
1798 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001799 {
1800 return false;
1801 }
1802
Jamie Madill55ec3b12014-07-03 10:38:57 -04001803 if (texture != 0)
1804 {
1805 gl::Texture *tex = context->getTexture(texture);
1806 ASSERT(tex);
1807
Jamie Madill2a6564e2014-07-11 09:53:19 -04001808 const gl::Caps &caps = context->getCaps();
1809
Jamie Madill55ec3b12014-07-03 10:38:57 -04001810 switch (textarget)
1811 {
1812 case GL_TEXTURE_2D:
1813 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001814 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001815 {
Geoff Langb1196682014-07-23 13:47:29 -04001816 context->recordError(Error(GL_INVALID_VALUE));
1817 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001818 }
1819 if (tex->getTarget() != GL_TEXTURE_2D)
1820 {
Geoff Langb1196682014-07-23 13:47:29 -04001821 context->recordError(Error(GL_INVALID_OPERATION));
1822 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001823 }
1824 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1825 if (tex2d->isCompressed(level))
1826 {
Geoff Langb1196682014-07-23 13:47:29 -04001827 context->recordError(Error(GL_INVALID_OPERATION));
1828 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001829 }
1830 }
1831 break;
1832
1833 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1834 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1835 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1836 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1837 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1838 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1839 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001840 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001841 {
Geoff Langb1196682014-07-23 13:47:29 -04001842 context->recordError(Error(GL_INVALID_VALUE));
1843 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001844 }
1845 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1846 {
Geoff Langb1196682014-07-23 13:47:29 -04001847 context->recordError(Error(GL_INVALID_OPERATION));
1848 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001849 }
1850 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1851 if (texcube->isCompressed(textarget, level))
1852 {
Geoff Langb1196682014-07-23 13:47:29 -04001853 context->recordError(Error(GL_INVALID_OPERATION));
1854 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001855 }
1856 }
1857 break;
1858
1859 default:
Geoff Langb1196682014-07-23 13:47:29 -04001860 context->recordError(Error(GL_INVALID_ENUM));
1861 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001862 }
1863 }
1864
Jamie Madill570f7c82014-07-03 10:38:54 -04001865 return true;
1866}
1867
Geoff Langb1196682014-07-23 13:47:29 -04001868bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001869{
1870 if (program == 0)
1871 {
Geoff Langb1196682014-07-23 13:47:29 -04001872 context->recordError(Error(GL_INVALID_VALUE));
1873 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001874 }
1875
Shannon Woods4de4fd62014-11-07 16:22:02 -05001876 if (!ValidProgram(context, program))
1877 {
1878 return false;
1879 }
1880
Jamie Madill0063c512014-08-25 15:47:53 -04001881 gl::Program *programObject = context->getProgram(program);
1882
1883 if (!programObject || !programObject->isLinked())
1884 {
Geoff Langb1196682014-07-23 13:47:29 -04001885 context->recordError(Error(GL_INVALID_OPERATION));
1886 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001887 }
1888
1889 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
1890 if (!programBinary)
1891 {
Geoff Langb1196682014-07-23 13:47:29 -04001892 context->recordError(Error(GL_INVALID_OPERATION));
1893 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001894 }
1895
Jamie Madill549c7fd2014-08-25 15:47:56 -04001896 if (!programBinary->isValidUniformLocation(location))
1897 {
Geoff Langb1196682014-07-23 13:47:29 -04001898 context->recordError(Error(GL_INVALID_OPERATION));
1899 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001900 }
1901
Jamie Madill0063c512014-08-25 15:47:53 -04001902 return true;
1903}
1904
Geoff Langb1196682014-07-23 13:47:29 -04001905bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001906{
1907 return ValidateGetUniformBase(context, program, location);
1908}
1909
Geoff Langb1196682014-07-23 13:47:29 -04001910bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001911{
Jamie Madill78f41802014-08-25 15:47:55 -04001912 return ValidateGetUniformBase(context, program, location);
1913}
1914
Geoff Langb1196682014-07-23 13:47:29 -04001915static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001916{
1917 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001918 {
Jamie Madill78f41802014-08-25 15:47:55 -04001919 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001920 }
1921
Jamie Madilla502c742014-08-28 17:19:13 -04001922 gl::Program *programObject = context->getProgram(program);
1923 ASSERT(programObject);
1924 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
Jamie Madill0063c512014-08-25 15:47:53 -04001925
Jamie Madill78f41802014-08-25 15:47:55 -04001926 // sized queries -- ensure the provided buffer is large enough
1927 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1928 size_t requiredBytes = VariableExternalSize(uniform->type);
1929 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001930 {
Geoff Langb1196682014-07-23 13:47:29 -04001931 context->recordError(Error(GL_INVALID_OPERATION));
1932 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001933 }
1934
1935 return true;
1936}
1937
Geoff Langb1196682014-07-23 13:47:29 -04001938bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001939{
Jamie Madill78f41802014-08-25 15:47:55 -04001940 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001941}
1942
Geoff Langb1196682014-07-23 13:47:29 -04001943bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001944{
Jamie Madill78f41802014-08-25 15:47:55 -04001945 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001946}
1947
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001948}