blob: 372642d3156e9ce7abcfa6981d3e3ea1042d15c5 [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{
95 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
96
97 switch (target)
98 {
99 case GL_FRAMEBUFFER: return true;
100 case GL_READ_FRAMEBUFFER: return true;
101 case GL_DRAW_FRAMEBUFFER: return true;
102 default: return false;
103 }
104}
105
Jamie Madill8c96d582014-03-05 15:01:23 -0500106bool ValidBufferTarget(const Context *context, GLenum target)
107{
108 switch (target)
109 {
110 case GL_ARRAY_BUFFER:
111 case GL_ELEMENT_ARRAY_BUFFER:
112 return true;
113
Jamie Madill8c96d582014-03-05 15:01:23 -0500114 case GL_PIXEL_PACK_BUFFER:
115 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400116 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400117
Shannon Woodsb3801742014-03-27 14:59:19 -0400118 case GL_COPY_READ_BUFFER:
119 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500120 case GL_TRANSFORM_FEEDBACK_BUFFER:
121 case GL_UNIFORM_BUFFER:
122 return (context->getClientVersion() >= 3);
123
124 default:
125 return false;
126 }
127}
128
Jamie Madill70656a62014-03-05 15:01:26 -0500129bool ValidBufferParameter(const Context *context, GLenum pname)
130{
131 switch (pname)
132 {
133 case GL_BUFFER_USAGE:
134 case GL_BUFFER_SIZE:
135 return true;
136
137 // GL_BUFFER_MAP_POINTER is a special case, and may only be
138 // queried with GetBufferPointerv
139 case GL_BUFFER_ACCESS_FLAGS:
140 case GL_BUFFER_MAPPED:
141 case GL_BUFFER_MAP_OFFSET:
142 case GL_BUFFER_MAP_LENGTH:
143 return (context->getClientVersion() >= 3);
144
145 default:
146 return false;
147 }
148}
149
Jamie Madill8c96d582014-03-05 15:01:23 -0500150bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400151{
Geoff Langaae65a42014-05-26 12:43:44 -0400152 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400153 switch (target)
154 {
Geoff Langaae65a42014-05-26 12:43:44 -0400155 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400156 case GL_TEXTURE_CUBE_MAP:
157 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
159 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
160 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
161 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400162 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
163 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
164 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400165 default: UNREACHABLE();
166 }
167
Geoff Langaae65a42014-05-26 12:43:44 -0400168 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400169}
170
Geoff Langb1196682014-07-23 13:47:29 -0400171bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400172 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400173{
174 if (level < 0 || width < 0 || height < 0 || depth < 0)
175 {
176 return false;
177 }
178
Geoff Langc0b9ef42014-07-02 10:02:37 -0400179 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400180 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400181 {
182 return false;
183 }
184
185 if (!ValidMipLevel(context, target, level))
186 {
187 return false;
188 }
189
190 return true;
191}
192
Geoff Langb1196682014-07-23 13:47:29 -0400193bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400194{
Geoff Lang5d601382014-07-22 15:14:06 -0400195 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
196 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400197 {
198 return false;
199 }
200
Geoff Lang5d601382014-07-22 15:14:06 -0400201 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
202 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400203 {
204 return false;
205 }
206
207 return true;
208}
209
Geoff Lang37dde692014-01-31 16:34:54 -0500210bool ValidQueryType(const Context *context, GLenum queryType)
211{
212 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
213 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
214
215 switch (queryType)
216 {
217 case GL_ANY_SAMPLES_PASSED:
218 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
219 return true;
220 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
221 return (context->getClientVersion() >= 3);
222 default:
223 return false;
224 }
225}
226
Geoff Langb1196682014-07-23 13:47:29 -0400227bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500228{
229 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
230 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
231 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
232
233 if (context->getProgram(id) != NULL)
234 {
235 return true;
236 }
237 else if (context->getShader(id) != NULL)
238 {
239 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400240 context->recordError(Error(GL_INVALID_OPERATION));
241 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500242 }
243 else
244 {
245 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400246 context->recordError(Error(GL_INVALID_VALUE));
247 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500248 }
249}
250
Geoff Langb1196682014-07-23 13:47:29 -0400251bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400252{
253 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
254 {
255 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
256
Geoff Langaae65a42014-05-26 12:43:44 -0400257 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400258 {
Geoff Langb1196682014-07-23 13:47:29 -0400259 context->recordError(Error(GL_INVALID_VALUE));
260 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400261 }
262 }
263 else
264 {
265 switch (attachment)
266 {
267 case GL_DEPTH_ATTACHMENT:
268 case GL_STENCIL_ATTACHMENT:
269 break;
270
271 case GL_DEPTH_STENCIL_ATTACHMENT:
272 if (context->getClientVersion() < 3)
273 {
Geoff Langb1196682014-07-23 13:47:29 -0400274 context->recordError(Error(GL_INVALID_ENUM));
275 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400276 }
277 break;
278
279 default:
Geoff Langb1196682014-07-23 13:47:29 -0400280 context->recordError(Error(GL_INVALID_ENUM));
281 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400282 }
283 }
284
285 return true;
286}
287
Corentin Walleze0902642014-11-04 12:32:15 -0800288bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
289 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400290{
291 switch (target)
292 {
293 case GL_RENDERBUFFER:
294 break;
295 default:
Geoff Langb1196682014-07-23 13:47:29 -0400296 context->recordError(Error(GL_INVALID_ENUM));
297 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400298 }
299
300 if (width < 0 || height < 0 || samples < 0)
301 {
Geoff Langb1196682014-07-23 13:47:29 -0400302 context->recordError(Error(GL_INVALID_VALUE));
303 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400304 }
305
Geoff Langd87878e2014-09-19 15:42:59 -0400306 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
307 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400308 {
Geoff Langb1196682014-07-23 13:47:29 -0400309 context->recordError(Error(GL_INVALID_ENUM));
310 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400311 }
312
313 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
314 // 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 -0800315 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400316 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400317 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400318 {
Geoff Langb1196682014-07-23 13:47:29 -0400319 context->recordError(Error(GL_INVALID_ENUM));
320 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400321 }
322
Geoff Langaae65a42014-05-26 12:43:44 -0400323 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400324 {
Geoff Langb1196682014-07-23 13:47:29 -0400325 context->recordError(Error(GL_INVALID_VALUE));
326 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400327 }
328
Shannon Woods53a94a82014-06-24 15:20:36 -0400329 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400330 if (handle == 0)
331 {
Geoff Langb1196682014-07-23 13:47:29 -0400332 context->recordError(Error(GL_INVALID_OPERATION));
333 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400334 }
335
336 return true;
337}
338
Corentin Walleze0902642014-11-04 12:32:15 -0800339bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
340 GLenum internalformat, GLsizei width, GLsizei height)
341{
342 ASSERT(context->getExtensions().framebufferMultisample);
343
344 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
345 // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is
346 // generated.
347 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
348 {
349 context->recordError(Error(GL_INVALID_VALUE));
350 return false;
351 }
352
353 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
354 // the specified storage. This is different than ES 3.0 in which a sample number higher
355 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
356 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
357 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
358 {
359 context->recordError(Error(GL_OUT_OF_MEMORY));
360 return false;
361 }
362
363 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
364}
365
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500366bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
367 GLenum renderbuffertarget, GLuint renderbuffer)
368{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400369 if (!ValidFramebufferTarget(target))
370 {
Geoff Langb1196682014-07-23 13:47:29 -0400371 context->recordError(Error(GL_INVALID_ENUM));
372 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400373 }
374
Shannon Woods53a94a82014-06-24 15:20:36 -0400375 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
376 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500377
378 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
379 {
Geoff Langb1196682014-07-23 13:47:29 -0400380 context->recordError(Error(GL_INVALID_OPERATION));
381 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500382 }
383
Jamie Madillb4472272014-07-03 10:38:55 -0400384 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500385 {
Jamie Madillb4472272014-07-03 10:38:55 -0400386 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500387 }
388
Jamie Madillab9d82c2014-01-21 16:38:14 -0500389 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
390 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
391 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
392 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
393 if (renderbuffer != 0)
394 {
395 if (!context->getRenderbuffer(renderbuffer))
396 {
Geoff Langb1196682014-07-23 13:47:29 -0400397 context->recordError(Error(GL_INVALID_OPERATION));
398 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500399 }
400 }
401
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500402 return true;
403}
404
Jamie Madill3c7fa222014-06-05 13:08:51 -0400405static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400406 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
407 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
408{
409 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
410 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
411 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
412 {
413 return true;
414 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400415 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400416 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400417 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400418
Shannon Woods53a94a82014-06-24 15:20:36 -0400419 return scissor.x > 0 || scissor.y > 0 ||
420 scissor.width < writeBuffer->getWidth() ||
421 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400422 }
423 else
424 {
425 return false;
426 }
427}
428
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400429bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400430 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
431 GLenum filter, bool fromAngleExtension)
432{
433 switch (filter)
434 {
435 case GL_NEAREST:
436 break;
437 case GL_LINEAR:
438 if (fromAngleExtension)
439 {
Geoff Langb1196682014-07-23 13:47:29 -0400440 context->recordError(Error(GL_INVALID_ENUM));
441 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400442 }
443 break;
444 default:
Geoff Langb1196682014-07-23 13:47:29 -0400445 context->recordError(Error(GL_INVALID_ENUM));
446 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400447 }
448
449 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
450 {
Geoff Langb1196682014-07-23 13:47:29 -0400451 context->recordError(Error(GL_INVALID_VALUE));
452 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400453 }
454
455 if (mask == 0)
456 {
457 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
458 // buffers are copied.
459 return false;
460 }
461
462 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
463 {
464 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400465 context->recordError(Error(GL_INVALID_OPERATION));
466 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400467 }
468
469 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
470 // color buffer, leaving only nearest being unfiltered from above
471 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
472 {
Geoff Langb1196682014-07-23 13:47:29 -0400473 context->recordError(Error(GL_INVALID_OPERATION));
474 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400475 }
476
Shannon Woods53a94a82014-06-24 15:20:36 -0400477 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400478 {
479 if (fromAngleExtension)
480 {
481 ERR("Blits with the same source and destination framebuffer are not supported by this "
482 "implementation.");
483 }
Geoff Langb1196682014-07-23 13:47:29 -0400484 context->recordError(Error(GL_INVALID_OPERATION));
485 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400486 }
487
Shannon Woods53a94a82014-06-24 15:20:36 -0400488 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
489 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500490
491 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400492 {
Geoff Langb1196682014-07-23 13:47:29 -0400493 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
494 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400495 }
496
Geoff Lang748f74e2014-12-01 11:25:34 -0500497 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500498 {
499 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
500 return false;
501 }
502
Geoff Lang748f74e2014-12-01 11:25:34 -0500503 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500504 {
505 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
506 return false;
507 }
508
509 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
Geoff Langb1196682014-07-23 13:47:29 -0400511 context->recordError(Error(GL_INVALID_OPERATION));
512 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 }
514
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
516
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400517 if (mask & GL_COLOR_BUFFER_BIT)
518 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400519 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
520 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400521
522 if (readColorBuffer && drawColorBuffer)
523 {
Geoff Lang005df412013-10-16 14:12:50 -0400524 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400525 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400526
527 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
528 {
529 if (drawFramebuffer->isEnabledColorAttachment(i))
530 {
Geoff Lang005df412013-10-16 14:12:50 -0400531 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400532 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400533
Geoff Langb2f3d052013-08-13 12:49:27 -0400534 // The GL ES 3.0.2 spec (pg 193) states that:
535 // 1) If the read buffer is fixed point format, the draw buffer must be as well
536 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
537 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400538 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
539 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400540 {
Geoff Langb1196682014-07-23 13:47:29 -0400541 context->recordError(Error(GL_INVALID_OPERATION));
542 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400543 }
544
Geoff Lang5d601382014-07-22 15:14:06 -0400545 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400546 {
Geoff Langb1196682014-07-23 13:47:29 -0400547 context->recordError(Error(GL_INVALID_OPERATION));
548 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400549 }
550
Geoff Lang5d601382014-07-22 15:14:06 -0400551 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400552 {
Geoff Langb1196682014-07-23 13:47:29 -0400553 context->recordError(Error(GL_INVALID_OPERATION));
554 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400555 }
556
Geoff Langb2f3d052013-08-13 12:49:27 -0400557 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400558 {
Geoff Langb1196682014-07-23 13:47:29 -0400559 context->recordError(Error(GL_INVALID_OPERATION));
560 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400561 }
562 }
563 }
564
Geoff Lang5d601382014-07-22 15:14:06 -0400565 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400566 {
Geoff Langb1196682014-07-23 13:47:29 -0400567 context->recordError(Error(GL_INVALID_OPERATION));
568 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400569 }
570
571 if (fromAngleExtension)
572 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500573 FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
574 if (!readColorAttachment ||
575 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
576 readColorAttachment->type() != GL_RENDERBUFFER &&
577 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400578 {
Geoff Langb1196682014-07-23 13:47:29 -0400579 context->recordError(Error(GL_INVALID_OPERATION));
580 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 }
582
583 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
584 {
585 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
586 {
Jamie Madille92a3542014-07-03 10:38:58 -0400587 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
588 ASSERT(attachment);
589
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500590 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
591 attachment->type() != GL_RENDERBUFFER &&
592 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400593 {
Geoff Langb1196682014-07-23 13:47:29 -0400594 context->recordError(Error(GL_INVALID_OPERATION));
595 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 }
597
Jamie Madillf8f18f02014-10-02 10:44:17 -0400598 // Return an error if the destination formats do not match
599 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400600 {
Geoff Langb1196682014-07-23 13:47:29 -0400601 context->recordError(Error(GL_INVALID_OPERATION));
602 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400603 }
604 }
605 }
Jamie Madill48faf802014-11-06 15:27:22 -0500606
607 int readSamples = readFramebuffer->getSamples(context->getData());
608
609 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
610 srcX0, srcY0, srcX1, srcY1,
611 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400612 {
Geoff Langb1196682014-07-23 13:47:29 -0400613 context->recordError(Error(GL_INVALID_OPERATION));
614 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 }
616 }
617 }
618 }
619
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200620 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
621 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
622 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400623 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200624 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400625 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200626 gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
627 gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400628
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200629 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400630 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200631 if (readBuffer->getActualFormat() != drawBuffer->getActualFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632 {
Geoff Langb1196682014-07-23 13:47:29 -0400633 context->recordError(Error(GL_INVALID_OPERATION));
634 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200637 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400638 {
Geoff Langb1196682014-07-23 13:47:29 -0400639 context->recordError(Error(GL_INVALID_OPERATION));
640 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400641 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200642
643 if (fromAngleExtension)
644 {
645 if (IsPartialBlit(context, readBuffer, drawBuffer,
646 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
647 {
648 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
649 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
650 return false;
651 }
652
653 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
654 {
655 context->recordError(Error(GL_INVALID_OPERATION));
656 return false;
657 }
658 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 }
660 }
661 }
662
663 return true;
664}
665
Geoff Langb1196682014-07-23 13:47:29 -0400666bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667{
668 switch (pname)
669 {
670 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
671 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
672 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
673 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
674 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
675 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
676 case GL_CURRENT_VERTEX_ATTRIB:
677 return true;
678
679 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
680 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
681 // the same constant.
682 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
683 return true;
684
685 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400686 if (context->getClientVersion() < 3)
687 {
688 context->recordError(Error(GL_INVALID_ENUM));
689 return false;
690 }
691 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400692
693 default:
Geoff Langb1196682014-07-23 13:47:29 -0400694 context->recordError(Error(GL_INVALID_ENUM));
695 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400696 }
697}
698
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400699bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700{
701 switch (pname)
702 {
703 case GL_TEXTURE_WRAP_R:
704 case GL_TEXTURE_SWIZZLE_R:
705 case GL_TEXTURE_SWIZZLE_G:
706 case GL_TEXTURE_SWIZZLE_B:
707 case GL_TEXTURE_SWIZZLE_A:
708 case GL_TEXTURE_BASE_LEVEL:
709 case GL_TEXTURE_MAX_LEVEL:
710 case GL_TEXTURE_COMPARE_MODE:
711 case GL_TEXTURE_COMPARE_FUNC:
712 case GL_TEXTURE_MIN_LOD:
713 case GL_TEXTURE_MAX_LOD:
714 if (context->getClientVersion() < 3)
715 {
Geoff Langb1196682014-07-23 13:47:29 -0400716 context->recordError(Error(GL_INVALID_ENUM));
717 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400718 }
719 break;
720
721 default: break;
722 }
723
724 switch (pname)
725 {
726 case GL_TEXTURE_WRAP_S:
727 case GL_TEXTURE_WRAP_T:
728 case GL_TEXTURE_WRAP_R:
729 switch (param)
730 {
731 case GL_REPEAT:
732 case GL_CLAMP_TO_EDGE:
733 case GL_MIRRORED_REPEAT:
734 return true;
735 default:
Geoff Langb1196682014-07-23 13:47:29 -0400736 context->recordError(Error(GL_INVALID_ENUM));
737 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400738 }
739
740 case GL_TEXTURE_MIN_FILTER:
741 switch (param)
742 {
743 case GL_NEAREST:
744 case GL_LINEAR:
745 case GL_NEAREST_MIPMAP_NEAREST:
746 case GL_LINEAR_MIPMAP_NEAREST:
747 case GL_NEAREST_MIPMAP_LINEAR:
748 case GL_LINEAR_MIPMAP_LINEAR:
749 return true;
750 default:
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 case GL_TEXTURE_MAG_FILTER:
757 switch (param)
758 {
759 case GL_NEAREST:
760 case GL_LINEAR:
761 return true;
762 default:
Geoff Langb1196682014-07-23 13:47:29 -0400763 context->recordError(Error(GL_INVALID_ENUM));
764 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400765 }
766 break;
767
768 case GL_TEXTURE_USAGE_ANGLE:
769 switch (param)
770 {
771 case GL_NONE:
772 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
773 return true;
774 default:
Geoff Langb1196682014-07-23 13:47:29 -0400775 context->recordError(Error(GL_INVALID_ENUM));
776 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400777 }
778 break;
779
780 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400781 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400782 {
Geoff Langb1196682014-07-23 13:47:29 -0400783 context->recordError(Error(GL_INVALID_ENUM));
784 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400785 }
786
787 // we assume the parameter passed to this validation method is truncated, not rounded
788 if (param < 1)
789 {
Geoff Langb1196682014-07-23 13:47:29 -0400790 context->recordError(Error(GL_INVALID_VALUE));
791 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400792 }
793 return true;
794
795 case GL_TEXTURE_MIN_LOD:
796 case GL_TEXTURE_MAX_LOD:
797 // any value is permissible
798 return true;
799
800 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400801 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400802 switch (param)
803 {
804 case GL_NONE:
805 case GL_COMPARE_REF_TO_TEXTURE:
806 return true;
807 default:
Geoff Langb1196682014-07-23 13:47:29 -0400808 context->recordError(Error(GL_INVALID_ENUM));
809 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400810 }
811 break;
812
813 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400814 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815 switch (param)
816 {
817 case GL_LEQUAL:
818 case GL_GEQUAL:
819 case GL_LESS:
820 case GL_GREATER:
821 case GL_EQUAL:
822 case GL_NOTEQUAL:
823 case GL_ALWAYS:
824 case GL_NEVER:
825 return true;
826 default:
Geoff Langb1196682014-07-23 13:47:29 -0400827 context->recordError(Error(GL_INVALID_ENUM));
828 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400829 }
830 break;
831
832 case GL_TEXTURE_SWIZZLE_R:
833 case GL_TEXTURE_SWIZZLE_G:
834 case GL_TEXTURE_SWIZZLE_B:
835 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400836 switch (param)
837 {
838 case GL_RED:
839 case GL_GREEN:
840 case GL_BLUE:
841 case GL_ALPHA:
842 case GL_ZERO:
843 case GL_ONE:
844 return true;
845 default:
Geoff Langb1196682014-07-23 13:47:29 -0400846 context->recordError(Error(GL_INVALID_ENUM));
847 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400848 }
849 break;
850
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400851 case GL_TEXTURE_BASE_LEVEL:
852 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400853 if (param < 0)
854 {
Geoff Langb1196682014-07-23 13:47:29 -0400855 context->recordError(Error(GL_INVALID_VALUE));
856 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400857 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400858 return true;
859
860 default:
Geoff Langb1196682014-07-23 13:47:29 -0400861 context->recordError(Error(GL_INVALID_ENUM));
862 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400863 }
864}
865
Geoff Langb1196682014-07-23 13:47:29 -0400866bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867{
868 switch (pname)
869 {
870 case GL_TEXTURE_MIN_FILTER:
871 case GL_TEXTURE_MAG_FILTER:
872 case GL_TEXTURE_WRAP_S:
873 case GL_TEXTURE_WRAP_T:
874 case GL_TEXTURE_WRAP_R:
875 case GL_TEXTURE_MIN_LOD:
876 case GL_TEXTURE_MAX_LOD:
877 case GL_TEXTURE_COMPARE_MODE:
878 case GL_TEXTURE_COMPARE_FUNC:
879 return true;
880
881 default:
Geoff Langb1196682014-07-23 13:47:29 -0400882 context->recordError(Error(GL_INVALID_ENUM));
883 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400884 }
885}
886
Jamie Madill26e91952014-03-05 15:01:27 -0500887bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
888 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
889{
Shannon Woods53a94a82014-06-24 15:20:36 -0400890 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400891 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500892
Geoff Lang748f74e2014-12-01 11:25:34 -0500893 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500894 {
Geoff Langb1196682014-07-23 13:47:29 -0400895 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
896 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500897 }
898
Jamie Madill48faf802014-11-06 15:27:22 -0500899 if (context->getState().getReadFramebuffer()->id() != 0 &&
900 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500901 {
Geoff Langb1196682014-07-23 13:47:29 -0400902 context->recordError(Error(GL_INVALID_OPERATION));
903 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500904 }
905
Geoff Langbce529e2014-12-01 12:48:41 -0500906 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
907 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400908 {
Geoff Langb1196682014-07-23 13:47:29 -0400909 context->recordError(Error(GL_INVALID_OPERATION));
910 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400911 }
912
Geoff Langbce529e2014-12-01 12:48:41 -0500913 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
914 GLenum currentType = framebuffer->getImplementationColorReadType();
915 GLenum currentInternalFormat = readBuffer->getActualFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400916 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500917
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400918 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
919 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500920
921 if (!(currentFormat == format && currentType == type) && !validReadFormat)
922 {
Geoff Langb1196682014-07-23 13:47:29 -0400923 context->recordError(Error(GL_INVALID_OPERATION));
924 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500925 }
926
Geoff Lang5d601382014-07-22 15:14:06 -0400927 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
928 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500929
Geoff Lang5d601382014-07-22 15:14:06 -0400930 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
Jamie Madill26e91952014-03-05 15:01:27 -0500931 // sized query sanity check
932 if (bufSize)
933 {
934 int requiredSize = outputPitch * height;
935 if (requiredSize > *bufSize)
936 {
Geoff Langb1196682014-07-23 13:47:29 -0400937 context->recordError(Error(GL_INVALID_OPERATION));
938 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500939 }
940 }
941
942 return true;
943}
944
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400945bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
946{
947 if (!ValidQueryType(context, target))
948 {
Geoff Langb1196682014-07-23 13:47:29 -0400949 context->recordError(Error(GL_INVALID_ENUM));
950 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400951 }
952
953 if (id == 0)
954 {
Geoff Langb1196682014-07-23 13:47:29 -0400955 context->recordError(Error(GL_INVALID_OPERATION));
956 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400957 }
958
959 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
960 // of zero, if the active query object name for <target> is non-zero (for the
961 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
962 // the active query for either target is non-zero), if <id> is the name of an
963 // existing query object whose type does not match <target>, or if <id> is the
964 // active query object name for any query type, the error INVALID_OPERATION is
965 // generated.
966
967 // Ensure no other queries are active
968 // NOTE: If other queries than occlusion are supported, we will need to check
969 // separately that:
970 // a) The query ID passed is not the current active query for any target/type
971 // b) There are no active queries for the requested target (and in the case
972 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
973 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400974 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400975 {
Geoff Langb1196682014-07-23 13:47:29 -0400976 context->recordError(Error(GL_INVALID_OPERATION));
977 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400978 }
979
980 Query *queryObject = context->getQuery(id, true, target);
981
982 // check that name was obtained with glGenQueries
983 if (!queryObject)
984 {
Geoff Langb1196682014-07-23 13:47:29 -0400985 context->recordError(Error(GL_INVALID_OPERATION));
986 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400987 }
988
989 // check for type mismatch
990 if (queryObject->getType() != target)
991 {
Geoff Langb1196682014-07-23 13:47:29 -0400992 context->recordError(Error(GL_INVALID_OPERATION));
993 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400994 }
995
996 return true;
997}
998
Jamie Madill45c785d2014-05-13 14:09:34 -0400999bool ValidateEndQuery(gl::Context *context, GLenum target)
1000{
1001 if (!ValidQueryType(context, target))
1002 {
Geoff Langb1196682014-07-23 13:47:29 -04001003 context->recordError(Error(GL_INVALID_ENUM));
1004 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001005 }
1006
Shannon Woods53a94a82014-06-24 15:20:36 -04001007 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001008
1009 if (queryObject == NULL)
1010 {
Geoff Langb1196682014-07-23 13:47:29 -04001011 context->recordError(Error(GL_INVALID_OPERATION));
1012 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001013 }
1014
Jamie Madill45c785d2014-05-13 14:09:34 -04001015 return true;
1016}
1017
Jamie Madill36398922014-05-20 14:51:53 -04001018static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1019 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001020{
1021 if (count < 0)
1022 {
Geoff Langb1196682014-07-23 13:47:29 -04001023 context->recordError(Error(GL_INVALID_VALUE));
1024 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001025 }
1026
Geoff Lang7dd2e102014-11-10 15:19:26 -05001027 gl::Program *program = context->getState().getProgram();
1028 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001029 {
Geoff Langb1196682014-07-23 13:47:29 -04001030 context->recordError(Error(GL_INVALID_OPERATION));
1031 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001032 }
1033
1034 if (location == -1)
1035 {
1036 // Silently ignore the uniform command
1037 return false;
1038 }
1039
Geoff Lang7dd2e102014-11-10 15:19:26 -05001040 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001041 {
Geoff Langb1196682014-07-23 13:47:29 -04001042 context->recordError(Error(GL_INVALID_OPERATION));
1043 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001044 }
1045
Geoff Lang7dd2e102014-11-10 15:19:26 -05001046 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001047
1048 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1049 if (uniform->elementCount() == 1 && count > 1)
1050 {
Geoff Langb1196682014-07-23 13:47:29 -04001051 context->recordError(Error(GL_INVALID_OPERATION));
1052 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001053 }
1054
1055 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001056 return true;
1057}
1058
Jamie Madillaa981bd2014-05-20 10:55:55 -04001059bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1060{
1061 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001062 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001063 {
Geoff Langb1196682014-07-23 13:47:29 -04001064 context->recordError(Error(GL_INVALID_OPERATION));
1065 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001066 }
1067
Jamie Madill36398922014-05-20 14:51:53 -04001068 LinkedUniform *uniform = NULL;
1069 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1070 {
1071 return false;
1072 }
1073
Jamie Madillf2575982014-06-25 16:04:54 -04001074 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001075 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001076 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1077 {
Geoff Langb1196682014-07-23 13:47:29 -04001078 context->recordError(Error(GL_INVALID_OPERATION));
1079 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001080 }
1081
1082 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001083}
1084
1085bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1086 GLboolean transpose)
1087{
1088 // Check for ES3 uniform entry points
1089 int rows = VariableRowCount(matrixType);
1090 int cols = VariableColumnCount(matrixType);
1091 if (rows != cols && context->getClientVersion() < 3)
1092 {
Geoff Langb1196682014-07-23 13:47:29 -04001093 context->recordError(Error(GL_INVALID_OPERATION));
1094 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001095 }
1096
1097 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1098 {
Geoff Langb1196682014-07-23 13:47:29 -04001099 context->recordError(Error(GL_INVALID_VALUE));
1100 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001101 }
1102
Jamie Madill36398922014-05-20 14:51:53 -04001103 LinkedUniform *uniform = NULL;
1104 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1105 {
1106 return false;
1107 }
1108
1109 if (uniform->type != matrixType)
1110 {
Geoff Langb1196682014-07-23 13:47:29 -04001111 context->recordError(Error(GL_INVALID_OPERATION));
1112 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001113 }
1114
1115 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001116}
1117
Jamie Madill893ab082014-05-16 16:56:10 -04001118bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1119{
1120 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1121 {
Geoff Langb1196682014-07-23 13:47:29 -04001122 context->recordError(Error(GL_INVALID_ENUM));
1123 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001124 }
1125
1126 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1127 {
1128 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1129
Geoff Langaae65a42014-05-26 12:43:44 -04001130 if (colorAttachment >= context->getCaps().maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001131 {
Geoff Langb1196682014-07-23 13:47:29 -04001132 context->recordError(Error(GL_INVALID_OPERATION));
1133 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001134 }
1135 }
1136
1137 switch (pname)
1138 {
1139 case GL_TEXTURE_BINDING_2D:
1140 case GL_TEXTURE_BINDING_CUBE_MAP:
1141 case GL_TEXTURE_BINDING_3D:
1142 case GL_TEXTURE_BINDING_2D_ARRAY:
Geoff Lang3a61c322014-07-10 13:01:54 -04001143 if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001144 {
Geoff Langb1196682014-07-23 13:47:29 -04001145 context->recordError(Error(GL_INVALID_OPERATION));
1146 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001147 }
1148 break;
1149
1150 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1151 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1152 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001153 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001154 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001155 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
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
Jamie Madill3c7fa222014-06-05 13:08:51 -04001161 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1162 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001163 {
Geoff Langb1196682014-07-23 13:47:29 -04001164 context->recordError(Error(GL_INVALID_OPERATION));
1165 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001166 }
1167 }
1168 break;
1169
1170 default:
1171 break;
1172 }
1173
1174 // pname is valid, but there are no parameters to return
1175 if (numParams == 0)
1176 {
1177 return false;
1178 }
1179
1180 return true;
1181}
1182
Jamie Madill560a8d82014-05-21 13:06:20 -04001183bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1184 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1185 GLint border, GLenum *textureFormatOut)
1186{
1187
1188 if (!ValidTexture2DDestinationTarget(context, target))
1189 {
Geoff Langb1196682014-07-23 13:47:29 -04001190 context->recordError(Error(GL_INVALID_ENUM));
1191 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001192 }
1193
1194 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1195 {
Geoff Langb1196682014-07-23 13:47:29 -04001196 context->recordError(Error(GL_INVALID_VALUE));
1197 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001198 }
1199
1200 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1201 {
Geoff Langb1196682014-07-23 13:47:29 -04001202 context->recordError(Error(GL_INVALID_VALUE));
1203 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001204 }
1205
1206 if (border != 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 (!ValidMipLevel(context, target, level))
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
Shannon Woods53a94a82014-06-24 15:20:36 -04001218 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001219 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001220 {
Geoff Langb1196682014-07-23 13:47:29 -04001221 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1222 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001223 }
1224
Jamie Madill48faf802014-11-06 15:27:22 -05001225 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001226 {
Geoff Langb1196682014-07-23 13:47:29 -04001227 context->recordError(Error(GL_INVALID_OPERATION));
1228 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001229 }
1230
Geoff Langaae65a42014-05-26 12:43:44 -04001231 const gl::Caps &caps = context->getCaps();
1232
Jamie Madill560a8d82014-05-21 13:06:20 -04001233 gl::Texture *texture = NULL;
1234 GLenum textureInternalFormat = GL_NONE;
Jamie Madill560a8d82014-05-21 13:06:20 -04001235 GLint textureLevelWidth = 0;
1236 GLint textureLevelHeight = 0;
1237 GLint textureLevelDepth = 0;
Geoff Langaae65a42014-05-26 12:43:44 -04001238 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001239
1240 switch (target)
1241 {
1242 case GL_TEXTURE_2D:
1243 {
1244 gl::Texture2D *texture2d = context->getTexture2D();
1245 if (texture2d)
1246 {
1247 textureInternalFormat = texture2d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001248 textureLevelWidth = texture2d->getWidth(level);
1249 textureLevelHeight = texture2d->getHeight(level);
1250 textureLevelDepth = 1;
1251 texture = texture2d;
Geoff Langaae65a42014-05-26 12:43:44 -04001252 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001253 }
1254 }
1255 break;
1256
1257 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1258 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1259 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1260 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1261 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1262 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1263 {
1264 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1265 if (textureCube)
1266 {
1267 textureInternalFormat = textureCube->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001268 textureLevelWidth = textureCube->getWidth(target, level);
1269 textureLevelHeight = textureCube->getHeight(target, level);
1270 textureLevelDepth = 1;
1271 texture = textureCube;
Geoff Langaae65a42014-05-26 12:43:44 -04001272 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001273 }
1274 }
1275 break;
1276
1277 case GL_TEXTURE_2D_ARRAY:
1278 {
1279 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1280 if (texture2dArray)
1281 {
1282 textureInternalFormat = texture2dArray->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001283 textureLevelWidth = texture2dArray->getWidth(level);
1284 textureLevelHeight = texture2dArray->getHeight(level);
1285 textureLevelDepth = texture2dArray->getLayers(level);
1286 texture = texture2dArray;
Geoff Langaae65a42014-05-26 12:43:44 -04001287 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001288 }
1289 }
1290 break;
1291
1292 case GL_TEXTURE_3D:
1293 {
1294 gl::Texture3D *texture3d = context->getTexture3D();
1295 if (texture3d)
1296 {
1297 textureInternalFormat = texture3d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001298 textureLevelWidth = texture3d->getWidth(level);
1299 textureLevelHeight = texture3d->getHeight(level);
1300 textureLevelDepth = texture3d->getDepth(level);
1301 texture = texture3d;
Geoff Langaae65a42014-05-26 12:43:44 -04001302 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001303 }
1304 }
1305 break;
1306
1307 default:
Geoff Langb1196682014-07-23 13:47:29 -04001308 context->recordError(Error(GL_INVALID_ENUM));
1309 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001310 }
1311
1312 if (!texture)
1313 {
Geoff Langb1196682014-07-23 13:47:29 -04001314 context->recordError(Error(GL_INVALID_OPERATION));
1315 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001316 }
1317
1318 if (texture->isImmutable() && !isSubImage)
1319 {
Geoff Langb1196682014-07-23 13:47:29 -04001320 context->recordError(Error(GL_INVALID_OPERATION));
1321 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001322 }
1323
Geoff Lang5d601382014-07-22 15:14:06 -04001324 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1325
1326 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001327 {
Geoff Langb1196682014-07-23 13:47:29 -04001328 context->recordError(Error(GL_INVALID_OPERATION));
1329 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001330 }
1331
Geoff Lang5d601382014-07-22 15:14:06 -04001332 if (formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04001333 {
Geoff Lang5d601382014-07-22 15:14:06 -04001334 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1335 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
Jamie Madill560a8d82014-05-21 13:06:20 -04001336 {
Geoff Langb1196682014-07-23 13:47:29 -04001337 context->recordError(Error(GL_INVALID_OPERATION));
1338 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001339 }
1340 }
1341
1342 if (isSubImage)
1343 {
1344 if (xoffset + width > textureLevelWidth ||
1345 yoffset + height > textureLevelHeight ||
1346 zoffset >= textureLevelDepth)
1347 {
Geoff Langb1196682014-07-23 13:47:29 -04001348 context->recordError(Error(GL_INVALID_VALUE));
1349 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001350 }
1351 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001352 else
1353 {
1354 if (IsCubemapTextureTarget(target) && width != height)
1355 {
Geoff Langb1196682014-07-23 13:47:29 -04001356 context->recordError(Error(GL_INVALID_VALUE));
1357 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001358 }
1359
Geoff Lang5d601382014-07-22 15:14:06 -04001360 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001361 {
Geoff Langb1196682014-07-23 13:47:29 -04001362 context->recordError(Error(GL_INVALID_ENUM));
1363 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001364 }
1365
1366 int maxLevelDimension = (maxDimension >> level);
1367 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1368 {
Geoff Langb1196682014-07-23 13:47:29 -04001369 context->recordError(Error(GL_INVALID_VALUE));
1370 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001371 }
1372 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001373
1374 *textureFormatOut = textureInternalFormat;
1375 return true;
1376}
1377
Geoff Langb1196682014-07-23 13:47:29 -04001378static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001379{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001380 switch (mode)
1381 {
1382 case GL_POINTS:
1383 case GL_LINES:
1384 case GL_LINE_LOOP:
1385 case GL_LINE_STRIP:
1386 case GL_TRIANGLES:
1387 case GL_TRIANGLE_STRIP:
1388 case GL_TRIANGLE_FAN:
1389 break;
1390 default:
Geoff Langb1196682014-07-23 13:47:29 -04001391 context->recordError(Error(GL_INVALID_ENUM));
1392 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001393 }
1394
Jamie Madill250d33f2014-06-06 17:09:03 -04001395 if (count < 0)
1396 {
Geoff Langb1196682014-07-23 13:47:29 -04001397 context->recordError(Error(GL_INVALID_VALUE));
1398 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001399 }
1400
Geoff Langb1196682014-07-23 13:47:29 -04001401 const State &state = context->getState();
1402
Jamie Madill250d33f2014-06-06 17:09:03 -04001403 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001404 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001405 {
Geoff Langb1196682014-07-23 13:47:29 -04001406 context->recordError(Error(GL_INVALID_OPERATION));
1407 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001408 }
1409
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001410 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001411 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001412 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001413 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1414 {
1415 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1416 // See Section 6.10 of the WebGL 1.0 spec
1417 ERR("This ANGLE implementation does not support separate front/back stencil "
1418 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001419 context->recordError(Error(GL_INVALID_OPERATION));
1420 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001421 }
1422
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001423 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001424 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001425 {
Geoff Langb1196682014-07-23 13:47:29 -04001426 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1427 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001428 }
1429
Geoff Lang7dd2e102014-11-10 15:19:26 -05001430 gl::Program *program = state.getProgram();
1431 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001432 {
Geoff Langb1196682014-07-23 13:47:29 -04001433 context->recordError(Error(GL_INVALID_OPERATION));
1434 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001435 }
1436
Geoff Lang7dd2e102014-11-10 15:19:26 -05001437 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001438 {
Geoff Langb1196682014-07-23 13:47:29 -04001439 context->recordError(Error(GL_INVALID_OPERATION));
1440 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001441 }
1442
Jamie Madill2b976812014-08-25 15:47:49 -04001443 // Buffer validations
1444 const VertexArray *vao = state.getVertexArray();
1445 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1446 {
1447 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001448 bool attribActive = (program->getSemanticIndex(attributeIndex) != -1);
Jamie Madill2b976812014-08-25 15:47:49 -04001449 if (attribActive && attrib.enabled)
1450 {
1451 gl::Buffer *buffer = attrib.buffer.get();
1452
1453 if (buffer)
1454 {
1455 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1456 GLint64 maxVertexElement = 0;
1457
1458 if (attrib.divisor > 0)
1459 {
1460 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1461 }
1462 else
1463 {
1464 maxVertexElement = static_cast<GLint64>(maxVertex);
1465 }
1466
1467 GLint64 attribDataSize = maxVertexElement * attribStride;
1468
1469 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1470 // We can return INVALID_OPERATION if our vertex attribute does not have
1471 // enough backing data.
1472 if (attribDataSize > buffer->getSize())
1473 {
Geoff Langb1196682014-07-23 13:47:29 -04001474 context->recordError(Error(GL_INVALID_OPERATION));
1475 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001476 }
1477 }
1478 else if (attrib.pointer == NULL)
1479 {
1480 // This is an application error that would normally result in a crash,
1481 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001482 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1483 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001484 }
1485 }
1486 }
1487
Jamie Madill250d33f2014-06-06 17:09:03 -04001488 // No-op if zero count
1489 return (count > 0);
1490}
1491
Geoff Langb1196682014-07-23 13:47:29 -04001492bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001493{
Jamie Madillfd716582014-06-06 17:09:04 -04001494 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001495 {
Geoff Langb1196682014-07-23 13:47:29 -04001496 context->recordError(Error(GL_INVALID_VALUE));
1497 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001498 }
1499
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001500 const State &state = context->getState();
1501 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001502 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1503 curTransformFeedback->getDrawMode() != mode)
1504 {
1505 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1506 // that does not match the current transform feedback object's draw mode (if transform feedback
1507 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001508 context->recordError(Error(GL_INVALID_OPERATION));
1509 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001510 }
1511
Geoff Langb1196682014-07-23 13:47:29 -04001512 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001513 {
1514 return false;
1515 }
1516
1517 return true;
1518}
1519
Geoff Langb1196682014-07-23 13:47:29 -04001520bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001521{
1522 if (primcount < 0)
1523 {
Geoff Langb1196682014-07-23 13:47:29 -04001524 context->recordError(Error(GL_INVALID_VALUE));
1525 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001526 }
1527
Jamie Madill2b976812014-08-25 15:47:49 -04001528 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001529 {
1530 return false;
1531 }
1532
1533 // No-op if zero primitive count
1534 return (primcount > 0);
1535}
1536
Geoff Lang87a93302014-09-16 13:29:43 -04001537static bool ValidateDrawInstancedANGLE(Context *context)
1538{
1539 // Verify there is at least one active attribute with a divisor of zero
1540 const gl::State& state = context->getState();
1541
Geoff Lang7dd2e102014-11-10 15:19:26 -05001542 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001543
1544 const VertexArray *vao = state.getVertexArray();
1545 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1546 {
1547 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001548 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001549 if (active && attrib.divisor == 0)
1550 {
1551 return true;
1552 }
1553 }
1554
1555 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1556 "has a divisor of zero."));
1557 return false;
1558}
1559
1560bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1561{
1562 if (!ValidateDrawInstancedANGLE(context))
1563 {
1564 return false;
1565 }
1566
1567 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1568}
1569
Geoff Langb1196682014-07-23 13:47:29 -04001570bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001571 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001572{
Jamie Madill250d33f2014-06-06 17:09:03 -04001573 switch (type)
1574 {
1575 case GL_UNSIGNED_BYTE:
1576 case GL_UNSIGNED_SHORT:
1577 break;
1578 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001579 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001580 {
Geoff Langb1196682014-07-23 13:47:29 -04001581 context->recordError(Error(GL_INVALID_ENUM));
1582 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001583 }
1584 break;
1585 default:
Geoff Langb1196682014-07-23 13:47:29 -04001586 context->recordError(Error(GL_INVALID_ENUM));
1587 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001588 }
1589
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001590 const State &state = context->getState();
1591
1592 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001593 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1594 {
1595 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1596 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001597 context->recordError(Error(GL_INVALID_OPERATION));
1598 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001599 }
1600
1601 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001602 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001603 {
Geoff Langb1196682014-07-23 13:47:29 -04001604 context->recordError(Error(GL_INVALID_OPERATION));
1605 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001606 }
1607
Jamie Madill2b976812014-08-25 15:47:49 -04001608 const gl::VertexArray *vao = state.getVertexArray();
1609 const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1610 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001611 {
Geoff Langb1196682014-07-23 13:47:29 -04001612 context->recordError(Error(GL_INVALID_OPERATION));
1613 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001614 }
1615
Jamie Madillae3000b2014-08-25 15:47:51 -04001616 if (elementArrayBuffer)
1617 {
1618 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1619
1620 GLint64 offset = reinterpret_cast<GLint64>(indices);
1621 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1622
1623 // check for integer overflows
1624 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1625 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1626 {
Geoff Langb1196682014-07-23 13:47:29 -04001627 context->recordError(Error(GL_OUT_OF_MEMORY));
1628 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001629 }
1630
1631 // Check for reading past the end of the bound buffer object
1632 if (byteCount > elementArrayBuffer->getSize())
1633 {
Geoff Langb1196682014-07-23 13:47:29 -04001634 context->recordError(Error(GL_INVALID_OPERATION));
1635 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001636 }
1637 }
1638 else if (!indices)
1639 {
1640 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001641 context->recordError(Error(GL_INVALID_OPERATION));
1642 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001643 }
1644
Jamie Madill2b976812014-08-25 15:47:49 -04001645 // Use max index to validate if our vertex buffers are large enough for the pull.
1646 // TODO: offer fast path, with disabled index validation.
1647 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1648 if (elementArrayBuffer)
1649 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001650 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Jamie Madill2b976812014-08-25 15:47:49 -04001651 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1652 {
Jamie Madill72468832015-01-05 15:03:18 -05001653 rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation();
Geoff Langc8d297a2014-09-19 11:09:08 -04001654 const uint8_t *dataPointer = NULL;
Jamie Madill72468832015-01-05 15:03:18 -05001655 Error error = bufferImpl->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001656 if (error.isError())
1657 {
1658 context->recordError(error);
1659 return false;
1660 }
1661
1662 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001663 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1664 }
1665 }
1666 else
1667 {
1668 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1669 }
1670
Geoff Langb1196682014-07-23 13:47:29 -04001671 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001672 {
1673 return false;
1674 }
1675
1676 return true;
1677}
1678
Geoff Langb1196682014-07-23 13:47:29 -04001679bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001680 GLenum mode, GLsizei count, GLenum type,
1681 const GLvoid *indices, GLsizei primcount,
1682 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001683{
1684 if (primcount < 0)
1685 {
Geoff Langb1196682014-07-23 13:47:29 -04001686 context->recordError(Error(GL_INVALID_VALUE));
1687 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001688 }
1689
Jamie Madill2b976812014-08-25 15:47:49 -04001690 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001691 {
1692 return false;
1693 }
1694
1695 // No-op zero primitive count
1696 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001697}
1698
Geoff Lang87a93302014-09-16 13:29:43 -04001699bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1700 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1701{
1702 if (!ValidateDrawInstancedANGLE(context))
1703 {
1704 return false;
1705 }
1706
1707 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1708}
1709
Geoff Langb1196682014-07-23 13:47:29 -04001710bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001711 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001712{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001713 if (!ValidFramebufferTarget(target))
1714 {
Geoff Langb1196682014-07-23 13:47:29 -04001715 context->recordError(Error(GL_INVALID_ENUM));
1716 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001717 }
1718
1719 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001720 {
1721 return false;
1722 }
1723
Jamie Madill55ec3b12014-07-03 10:38:57 -04001724 if (texture != 0)
1725 {
1726 gl::Texture *tex = context->getTexture(texture);
1727
1728 if (tex == NULL)
1729 {
Geoff Langb1196682014-07-23 13:47:29 -04001730 context->recordError(Error(GL_INVALID_OPERATION));
1731 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001732 }
1733
1734 if (level < 0)
1735 {
Geoff Langb1196682014-07-23 13:47:29 -04001736 context->recordError(Error(GL_INVALID_VALUE));
1737 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001738 }
1739 }
1740
Shannon Woods53a94a82014-06-24 15:20:36 -04001741 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1742 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001743
1744 if (framebufferHandle == 0 || !framebuffer)
1745 {
Geoff Langb1196682014-07-23 13:47:29 -04001746 context->recordError(Error(GL_INVALID_OPERATION));
1747 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001748 }
1749
1750 return true;
1751}
1752
Geoff Langb1196682014-07-23 13:47:29 -04001753bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001754 GLenum textarget, GLuint texture, GLint level)
1755{
1756 // Attachments are required to be bound to level 0 in ES2
1757 if (context->getClientVersion() < 3 && level != 0)
1758 {
Geoff Langb1196682014-07-23 13:47:29 -04001759 context->recordError(Error(GL_INVALID_VALUE));
1760 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001761 }
1762
1763 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001764 {
1765 return false;
1766 }
1767
Jamie Madill55ec3b12014-07-03 10:38:57 -04001768 if (texture != 0)
1769 {
1770 gl::Texture *tex = context->getTexture(texture);
1771 ASSERT(tex);
1772
Jamie Madill2a6564e2014-07-11 09:53:19 -04001773 const gl::Caps &caps = context->getCaps();
1774
Jamie Madill55ec3b12014-07-03 10:38:57 -04001775 switch (textarget)
1776 {
1777 case GL_TEXTURE_2D:
1778 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001779 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001780 {
Geoff Langb1196682014-07-23 13:47:29 -04001781 context->recordError(Error(GL_INVALID_VALUE));
1782 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001783 }
1784 if (tex->getTarget() != GL_TEXTURE_2D)
1785 {
Geoff Langb1196682014-07-23 13:47:29 -04001786 context->recordError(Error(GL_INVALID_OPERATION));
1787 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001788 }
1789 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1790 if (tex2d->isCompressed(level))
1791 {
Geoff Langb1196682014-07-23 13:47:29 -04001792 context->recordError(Error(GL_INVALID_OPERATION));
1793 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001794 }
1795 }
1796 break;
1797
1798 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1799 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1800 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1801 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1802 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1803 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1804 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001805 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001806 {
Geoff Langb1196682014-07-23 13:47:29 -04001807 context->recordError(Error(GL_INVALID_VALUE));
1808 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001809 }
1810 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1811 {
Geoff Langb1196682014-07-23 13:47:29 -04001812 context->recordError(Error(GL_INVALID_OPERATION));
1813 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001814 }
1815 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1816 if (texcube->isCompressed(textarget, level))
1817 {
Geoff Langb1196682014-07-23 13:47:29 -04001818 context->recordError(Error(GL_INVALID_OPERATION));
1819 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001820 }
1821 }
1822 break;
1823
1824 default:
Geoff Langb1196682014-07-23 13:47:29 -04001825 context->recordError(Error(GL_INVALID_ENUM));
1826 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001827 }
1828 }
1829
Jamie Madill570f7c82014-07-03 10:38:54 -04001830 return true;
1831}
1832
Geoff Langb1196682014-07-23 13:47:29 -04001833bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001834{
1835 if (program == 0)
1836 {
Geoff Langb1196682014-07-23 13:47:29 -04001837 context->recordError(Error(GL_INVALID_VALUE));
1838 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001839 }
1840
Shannon Woods4de4fd62014-11-07 16:22:02 -05001841 if (!ValidProgram(context, program))
1842 {
1843 return false;
1844 }
1845
Jamie Madill0063c512014-08-25 15:47:53 -04001846 gl::Program *programObject = context->getProgram(program);
1847
1848 if (!programObject || !programObject->isLinked())
1849 {
Geoff Langb1196682014-07-23 13:47:29 -04001850 context->recordError(Error(GL_INVALID_OPERATION));
1851 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001852 }
1853
Geoff Lang7dd2e102014-11-10 15:19:26 -05001854 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001855 {
Geoff Langb1196682014-07-23 13:47:29 -04001856 context->recordError(Error(GL_INVALID_OPERATION));
1857 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001858 }
1859
Jamie Madill0063c512014-08-25 15:47:53 -04001860 return true;
1861}
1862
Geoff Langb1196682014-07-23 13:47:29 -04001863bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001864{
1865 return ValidateGetUniformBase(context, program, location);
1866}
1867
Geoff Langb1196682014-07-23 13:47:29 -04001868bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001869{
Jamie Madill78f41802014-08-25 15:47:55 -04001870 return ValidateGetUniformBase(context, program, location);
1871}
1872
Geoff Langb1196682014-07-23 13:47:29 -04001873static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001874{
1875 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001876 {
Jamie Madill78f41802014-08-25 15:47:55 -04001877 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001878 }
1879
Jamie Madilla502c742014-08-28 17:19:13 -04001880 gl::Program *programObject = context->getProgram(program);
1881 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001882
Jamie Madill78f41802014-08-25 15:47:55 -04001883 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001884 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001885 size_t requiredBytes = VariableExternalSize(uniform->type);
1886 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001887 {
Geoff Langb1196682014-07-23 13:47:29 -04001888 context->recordError(Error(GL_INVALID_OPERATION));
1889 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001890 }
1891
1892 return true;
1893}
1894
Geoff Langb1196682014-07-23 13:47:29 -04001895bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001896{
Jamie Madill78f41802014-08-25 15:47:55 -04001897 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001898}
1899
Geoff Langb1196682014-07-23 13:47:29 -04001900bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001901{
Jamie Madill78f41802014-08-25 15:47:55 -04001902 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001903}
1904
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001905}