blob: 8de5ca41b358b566829aa947e3419fb6bdd667cf [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
13#include "libANGLE/Texture.h"
14#include "libANGLE/Framebuffer.h"
15#include "libANGLE/FramebufferAttachment.h"
16#include "libANGLE/formatutils.h"
17#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050018#include "libANGLE/Program.h"
19#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/TransformFeedback.h"
21#include "libANGLE/VertexArray.h"
22#include "libANGLE/renderer/BufferImpl.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040023
24#include "common/mathutil.h"
25#include "common/utilities.h"
26
27namespace gl
28{
29
Geoff Lang0550d032014-01-30 11:29:07 -050030bool ValidCap(const Context *context, GLenum cap)
31{
32 switch (cap)
33 {
34 case GL_CULL_FACE:
35 case GL_POLYGON_OFFSET_FILL:
36 case GL_SAMPLE_ALPHA_TO_COVERAGE:
37 case GL_SAMPLE_COVERAGE:
38 case GL_SCISSOR_TEST:
39 case GL_STENCIL_TEST:
40 case GL_DEPTH_TEST:
41 case GL_BLEND:
42 case GL_DITHER:
43 return true;
44 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
45 case GL_RASTERIZER_DISCARD:
46 return (context->getClientVersion() >= 3);
47 default:
48 return false;
49 }
50}
51
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050052bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040053{
Jamie Madilld7460c72014-01-21 16:38:14 -050054 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040055 {
Jamie Madilld7460c72014-01-21 16:38:14 -050056 case GL_TEXTURE_2D:
57 case GL_TEXTURE_CUBE_MAP:
58 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040059
Jamie Madilld7460c72014-01-21 16:38:14 -050060 case GL_TEXTURE_3D:
61 case GL_TEXTURE_2D_ARRAY:
62 return (context->getClientVersion() >= 3);
63
64 default:
65 return false;
66 }
Jamie Madill35d15012013-10-07 10:46:37 -040067}
68
Shannon Woods4dfed832014-03-17 20:03:39 -040069// This function differs from ValidTextureTarget in that the target must be
70// usable as the destination of a 2D operation-- so a cube face is valid, but
71// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040072// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040073bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
74{
75 switch (target)
76 {
77 case GL_TEXTURE_2D:
78 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
84 return true;
85 case GL_TEXTURE_2D_ARRAY:
86 case GL_TEXTURE_3D:
87 return (context->getClientVersion() >= 3);
88 default:
89 return false;
90 }
91}
92
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050093bool ValidFramebufferTarget(GLenum target)
94{
Geoff Langd4475812015-03-18 10:53:05 -040095 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
96 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050097
98 switch (target)
99 {
100 case GL_FRAMEBUFFER: return true;
101 case GL_READ_FRAMEBUFFER: return true;
102 case GL_DRAW_FRAMEBUFFER: return true;
103 default: return false;
104 }
105}
106
Jamie Madill8c96d582014-03-05 15:01:23 -0500107bool ValidBufferTarget(const Context *context, GLenum target)
108{
109 switch (target)
110 {
111 case GL_ARRAY_BUFFER:
112 case GL_ELEMENT_ARRAY_BUFFER:
113 return true;
114
Jamie Madill8c96d582014-03-05 15:01:23 -0500115 case GL_PIXEL_PACK_BUFFER:
116 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400117 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400118
Shannon Woodsb3801742014-03-27 14:59:19 -0400119 case GL_COPY_READ_BUFFER:
120 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500121 case GL_TRANSFORM_FEEDBACK_BUFFER:
122 case GL_UNIFORM_BUFFER:
123 return (context->getClientVersion() >= 3);
124
125 default:
126 return false;
127 }
128}
129
Jamie Madill70656a62014-03-05 15:01:26 -0500130bool ValidBufferParameter(const Context *context, GLenum pname)
131{
132 switch (pname)
133 {
134 case GL_BUFFER_USAGE:
135 case GL_BUFFER_SIZE:
136 return true;
137
138 // GL_BUFFER_MAP_POINTER is a special case, and may only be
139 // queried with GetBufferPointerv
140 case GL_BUFFER_ACCESS_FLAGS:
141 case GL_BUFFER_MAPPED:
142 case GL_BUFFER_MAP_OFFSET:
143 case GL_BUFFER_MAP_LENGTH:
144 return (context->getClientVersion() >= 3);
145
146 default:
147 return false;
148 }
149}
150
Jamie Madill8c96d582014-03-05 15:01:23 -0500151bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400152{
Geoff Langaae65a42014-05-26 12:43:44 -0400153 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400154 switch (target)
155 {
Geoff Langaae65a42014-05-26 12:43:44 -0400156 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400157 case GL_TEXTURE_CUBE_MAP:
158 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
159 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
160 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
161 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
162 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400163 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
164 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
165 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400166 default: UNREACHABLE();
167 }
168
Geoff Langaae65a42014-05-26 12:43:44 -0400169 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400170}
171
Geoff Langb1196682014-07-23 13:47:29 -0400172bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400173 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400174{
175 if (level < 0 || width < 0 || height < 0 || depth < 0)
176 {
177 return false;
178 }
179
Geoff Langc0b9ef42014-07-02 10:02:37 -0400180 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400181 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400182 {
183 return false;
184 }
185
186 if (!ValidMipLevel(context, target, level))
187 {
188 return false;
189 }
190
191 return true;
192}
193
Geoff Langb1196682014-07-23 13:47:29 -0400194bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400195{
Geoff Lang5d601382014-07-22 15:14:06 -0400196 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
197 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400198 {
199 return false;
200 }
201
Geoff Lang5d601382014-07-22 15:14:06 -0400202 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
203 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400204 {
205 return false;
206 }
207
208 return true;
209}
210
Geoff Lang37dde692014-01-31 16:34:54 -0500211bool ValidQueryType(const Context *context, GLenum queryType)
212{
Geoff Langd4475812015-03-18 10:53:05 -0400213 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
214 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -0500215
216 switch (queryType)
217 {
218 case GL_ANY_SAMPLES_PASSED:
219 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
220 return true;
221 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
222 return (context->getClientVersion() >= 3);
223 default:
224 return false;
225 }
226}
227
Geoff Langb1196682014-07-23 13:47:29 -0400228bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500229{
230 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
231 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
232 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
233
234 if (context->getProgram(id) != NULL)
235 {
236 return true;
237 }
238 else if (context->getShader(id) != NULL)
239 {
240 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400241 context->recordError(Error(GL_INVALID_OPERATION));
242 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500243 }
244 else
245 {
246 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400247 context->recordError(Error(GL_INVALID_VALUE));
248 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500249 }
250}
251
Geoff Langb1196682014-07-23 13:47:29 -0400252bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400253{
254 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
255 {
256 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
257
Geoff Langaae65a42014-05-26 12:43:44 -0400258 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400259 {
Geoff Langb1196682014-07-23 13:47:29 -0400260 context->recordError(Error(GL_INVALID_VALUE));
261 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400262 }
263 }
264 else
265 {
266 switch (attachment)
267 {
268 case GL_DEPTH_ATTACHMENT:
269 case GL_STENCIL_ATTACHMENT:
270 break;
271
272 case GL_DEPTH_STENCIL_ATTACHMENT:
273 if (context->getClientVersion() < 3)
274 {
Geoff Langb1196682014-07-23 13:47:29 -0400275 context->recordError(Error(GL_INVALID_ENUM));
276 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400277 }
278 break;
279
280 default:
Geoff Langb1196682014-07-23 13:47:29 -0400281 context->recordError(Error(GL_INVALID_ENUM));
282 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400283 }
284 }
285
286 return true;
287}
288
Corentin Walleze0902642014-11-04 12:32:15 -0800289bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
290 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400291{
292 switch (target)
293 {
294 case GL_RENDERBUFFER:
295 break;
296 default:
Geoff Langb1196682014-07-23 13:47:29 -0400297 context->recordError(Error(GL_INVALID_ENUM));
298 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400299 }
300
301 if (width < 0 || height < 0 || samples < 0)
302 {
Geoff Langb1196682014-07-23 13:47:29 -0400303 context->recordError(Error(GL_INVALID_VALUE));
304 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400305 }
306
Geoff Langd87878e2014-09-19 15:42:59 -0400307 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
308 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400309 {
Geoff Langb1196682014-07-23 13:47:29 -0400310 context->recordError(Error(GL_INVALID_ENUM));
311 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400312 }
313
314 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
315 // 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 -0800316 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400317 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400318 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400319 {
Geoff Langb1196682014-07-23 13:47:29 -0400320 context->recordError(Error(GL_INVALID_ENUM));
321 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400322 }
323
Geoff Langaae65a42014-05-26 12:43:44 -0400324 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400325 {
Geoff Langb1196682014-07-23 13:47:29 -0400326 context->recordError(Error(GL_INVALID_VALUE));
327 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400328 }
329
Shannon Woods53a94a82014-06-24 15:20:36 -0400330 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400331 if (handle == 0)
332 {
Geoff Langb1196682014-07-23 13:47:29 -0400333 context->recordError(Error(GL_INVALID_OPERATION));
334 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400335 }
336
337 return true;
338}
339
Corentin Walleze0902642014-11-04 12:32:15 -0800340bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
341 GLenum internalformat, GLsizei width, GLsizei height)
342{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800343 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800344
345 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
346 // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is
347 // generated.
348 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
349 {
350 context->recordError(Error(GL_INVALID_VALUE));
351 return false;
352 }
353
354 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
355 // the specified storage. This is different than ES 3.0 in which a sample number higher
356 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
357 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
358 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
359 {
360 context->recordError(Error(GL_OUT_OF_MEMORY));
361 return false;
362 }
363
364 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
365}
366
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500367bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
368 GLenum renderbuffertarget, GLuint renderbuffer)
369{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400370 if (!ValidFramebufferTarget(target))
371 {
Geoff Langb1196682014-07-23 13:47:29 -0400372 context->recordError(Error(GL_INVALID_ENUM));
373 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400374 }
375
Shannon Woods53a94a82014-06-24 15:20:36 -0400376 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
377 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500378
379 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
380 {
Geoff Langb1196682014-07-23 13:47:29 -0400381 context->recordError(Error(GL_INVALID_OPERATION));
382 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500383 }
384
Jamie Madillb4472272014-07-03 10:38:55 -0400385 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500386 {
Jamie Madillb4472272014-07-03 10:38:55 -0400387 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500388 }
389
Jamie Madillab9d82c2014-01-21 16:38:14 -0500390 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
391 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
392 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
393 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
394 if (renderbuffer != 0)
395 {
396 if (!context->getRenderbuffer(renderbuffer))
397 {
Geoff Langb1196682014-07-23 13:47:29 -0400398 context->recordError(Error(GL_INVALID_OPERATION));
399 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500400 }
401 }
402
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500403 return true;
404}
405
Jamie Madill3c7fa222014-06-05 13:08:51 -0400406static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400407 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
408 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
409{
410 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
411 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
412 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
413 {
414 return true;
415 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400416 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400417 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400418 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400419
Shannon Woods53a94a82014-06-24 15:20:36 -0400420 return scissor.x > 0 || scissor.y > 0 ||
421 scissor.width < writeBuffer->getWidth() ||
422 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400423 }
424 else
425 {
426 return false;
427 }
428}
429
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400430bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400431 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
432 GLenum filter, bool fromAngleExtension)
433{
434 switch (filter)
435 {
436 case GL_NEAREST:
437 break;
438 case GL_LINEAR:
439 if (fromAngleExtension)
440 {
Geoff Langb1196682014-07-23 13:47:29 -0400441 context->recordError(Error(GL_INVALID_ENUM));
442 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400443 }
444 break;
445 default:
Geoff Langb1196682014-07-23 13:47:29 -0400446 context->recordError(Error(GL_INVALID_ENUM));
447 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400448 }
449
450 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
451 {
Geoff Langb1196682014-07-23 13:47:29 -0400452 context->recordError(Error(GL_INVALID_VALUE));
453 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400454 }
455
456 if (mask == 0)
457 {
458 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
459 // buffers are copied.
460 return false;
461 }
462
463 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
464 {
465 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400466 context->recordError(Error(GL_INVALID_OPERATION));
467 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400468 }
469
470 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
471 // color buffer, leaving only nearest being unfiltered from above
472 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
473 {
Geoff Langb1196682014-07-23 13:47:29 -0400474 context->recordError(Error(GL_INVALID_OPERATION));
475 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400476 }
477
Shannon Woods53a94a82014-06-24 15:20:36 -0400478 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400479 {
480 if (fromAngleExtension)
481 {
482 ERR("Blits with the same source and destination framebuffer are not supported by this "
483 "implementation.");
484 }
Geoff Langb1196682014-07-23 13:47:29 -0400485 context->recordError(Error(GL_INVALID_OPERATION));
486 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400487 }
488
Shannon Woods53a94a82014-06-24 15:20:36 -0400489 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
490 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500491
492 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400493 {
Geoff Langb1196682014-07-23 13:47:29 -0400494 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
495 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 }
497
Geoff Lang748f74e2014-12-01 11:25:34 -0500498 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500499 {
500 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
501 return false;
502 }
503
Geoff Lang748f74e2014-12-01 11:25:34 -0500504 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500505 {
506 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
507 return false;
508 }
509
510 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 {
Geoff Langb1196682014-07-23 13:47:29 -0400512 context->recordError(Error(GL_INVALID_OPERATION));
513 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400514 }
515
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
517
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400518 if (mask & GL_COLOR_BUFFER_BIT)
519 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400520 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
521 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522
523 if (readColorBuffer && drawColorBuffer)
524 {
Geoff Langd8a22582014-12-17 15:28:23 -0500525 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400526 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400527
Jamie Madill0af26e12015-03-05 19:54:33 -0500528 for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400529 {
530 if (drawFramebuffer->isEnabledColorAttachment(i))
531 {
Geoff Langd8a22582014-12-17 15:28:23 -0500532 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400533 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400534
Geoff Langb2f3d052013-08-13 12:49:27 -0400535 // The GL ES 3.0.2 spec (pg 193) states that:
536 // 1) If the read buffer is fixed point format, the draw buffer must be as well
537 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
538 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400539 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
540 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400541 {
Geoff Langb1196682014-07-23 13:47:29 -0400542 context->recordError(Error(GL_INVALID_OPERATION));
543 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400544 }
545
Geoff Lang5d601382014-07-22 15:14:06 -0400546 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 {
Geoff Langb1196682014-07-23 13:47:29 -0400548 context->recordError(Error(GL_INVALID_OPERATION));
549 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400550 }
551
Geoff Lang5d601382014-07-22 15:14:06 -0400552 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 {
Geoff Langb1196682014-07-23 13:47:29 -0400554 context->recordError(Error(GL_INVALID_OPERATION));
555 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400556 }
557
Geoff Langb2f3d052013-08-13 12:49:27 -0400558 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400559 {
Geoff Langb1196682014-07-23 13:47:29 -0400560 context->recordError(Error(GL_INVALID_OPERATION));
561 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400562 }
563 }
564 }
565
Geoff Lang5d601382014-07-22 15:14:06 -0400566 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 {
Geoff Langb1196682014-07-23 13:47:29 -0400568 context->recordError(Error(GL_INVALID_OPERATION));
569 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400570 }
571
572 if (fromAngleExtension)
573 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500574 FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
575 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400576 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500577 readColorAttachment->type() != GL_RENDERBUFFER &&
578 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400579 {
Geoff Langb1196682014-07-23 13:47:29 -0400580 context->recordError(Error(GL_INVALID_OPERATION));
581 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400582 }
583
Jamie Madill0af26e12015-03-05 19:54:33 -0500584 for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400585 {
586 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
587 {
Jamie Madille92a3542014-07-03 10:38:58 -0400588 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
589 ASSERT(attachment);
590
Jamie Madill8cf4a392015-04-02 11:36:04 -0400591 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500592 attachment->type() != GL_RENDERBUFFER &&
593 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400594 {
Geoff Langb1196682014-07-23 13:47:29 -0400595 context->recordError(Error(GL_INVALID_OPERATION));
596 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400597 }
598
Jamie Madillf8f18f02014-10-02 10:44:17 -0400599 // Return an error if the destination formats do not match
600 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400601 {
Geoff Langb1196682014-07-23 13:47:29 -0400602 context->recordError(Error(GL_INVALID_OPERATION));
603 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400604 }
605 }
606 }
Jamie Madill48faf802014-11-06 15:27:22 -0500607
608 int readSamples = readFramebuffer->getSamples(context->getData());
609
610 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
611 srcX0, srcY0, srcX1, srcY1,
612 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613 {
Geoff Langb1196682014-07-23 13:47:29 -0400614 context->recordError(Error(GL_INVALID_OPERATION));
615 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 }
617 }
618 }
619 }
620
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200621 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
622 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
623 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400624 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200625 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400626 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200627 gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
628 gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400629
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200630 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400631 {
Geoff Langd8a22582014-12-17 15:28:23 -0500632 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 {
Geoff Langb1196682014-07-23 13:47:29 -0400634 context->recordError(Error(GL_INVALID_OPERATION));
635 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400636 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200638 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639 {
Geoff Langb1196682014-07-23 13:47:29 -0400640 context->recordError(Error(GL_INVALID_OPERATION));
641 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400642 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200643
644 if (fromAngleExtension)
645 {
646 if (IsPartialBlit(context, readBuffer, drawBuffer,
647 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
648 {
649 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
650 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
651 return false;
652 }
653
654 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
655 {
656 context->recordError(Error(GL_INVALID_OPERATION));
657 return false;
658 }
659 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400660 }
661 }
662 }
663
664 return true;
665}
666
Geoff Langb1196682014-07-23 13:47:29 -0400667bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400668{
669 switch (pname)
670 {
671 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
672 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
673 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
674 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
675 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
676 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
677 case GL_CURRENT_VERTEX_ATTRIB:
678 return true;
679
680 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
681 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
682 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400683 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
684 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400685 return true;
686
687 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400688 if (context->getClientVersion() < 3)
689 {
690 context->recordError(Error(GL_INVALID_ENUM));
691 return false;
692 }
693 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694
695 default:
Geoff Langb1196682014-07-23 13:47:29 -0400696 context->recordError(Error(GL_INVALID_ENUM));
697 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400698 }
699}
700
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400701bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400702{
703 switch (pname)
704 {
705 case GL_TEXTURE_WRAP_R:
706 case GL_TEXTURE_SWIZZLE_R:
707 case GL_TEXTURE_SWIZZLE_G:
708 case GL_TEXTURE_SWIZZLE_B:
709 case GL_TEXTURE_SWIZZLE_A:
710 case GL_TEXTURE_BASE_LEVEL:
711 case GL_TEXTURE_MAX_LEVEL:
712 case GL_TEXTURE_COMPARE_MODE:
713 case GL_TEXTURE_COMPARE_FUNC:
714 case GL_TEXTURE_MIN_LOD:
715 case GL_TEXTURE_MAX_LOD:
716 if (context->getClientVersion() < 3)
717 {
Geoff Langb1196682014-07-23 13:47:29 -0400718 context->recordError(Error(GL_INVALID_ENUM));
719 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400720 }
721 break;
722
723 default: break;
724 }
725
726 switch (pname)
727 {
728 case GL_TEXTURE_WRAP_S:
729 case GL_TEXTURE_WRAP_T:
730 case GL_TEXTURE_WRAP_R:
731 switch (param)
732 {
733 case GL_REPEAT:
734 case GL_CLAMP_TO_EDGE:
735 case GL_MIRRORED_REPEAT:
736 return true;
737 default:
Geoff Langb1196682014-07-23 13:47:29 -0400738 context->recordError(Error(GL_INVALID_ENUM));
739 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400740 }
741
742 case GL_TEXTURE_MIN_FILTER:
743 switch (param)
744 {
745 case GL_NEAREST:
746 case GL_LINEAR:
747 case GL_NEAREST_MIPMAP_NEAREST:
748 case GL_LINEAR_MIPMAP_NEAREST:
749 case GL_NEAREST_MIPMAP_LINEAR:
750 case GL_LINEAR_MIPMAP_LINEAR:
751 return true;
752 default:
Geoff Langb1196682014-07-23 13:47:29 -0400753 context->recordError(Error(GL_INVALID_ENUM));
754 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400755 }
756 break;
757
758 case GL_TEXTURE_MAG_FILTER:
759 switch (param)
760 {
761 case GL_NEAREST:
762 case GL_LINEAR:
763 return true;
764 default:
Geoff Langb1196682014-07-23 13:47:29 -0400765 context->recordError(Error(GL_INVALID_ENUM));
766 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400767 }
768 break;
769
770 case GL_TEXTURE_USAGE_ANGLE:
771 switch (param)
772 {
773 case GL_NONE:
774 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
775 return true;
776 default:
Geoff Langb1196682014-07-23 13:47:29 -0400777 context->recordError(Error(GL_INVALID_ENUM));
778 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400779 }
780 break;
781
782 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400783 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 {
Geoff Langb1196682014-07-23 13:47:29 -0400785 context->recordError(Error(GL_INVALID_ENUM));
786 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400787 }
788
789 // we assume the parameter passed to this validation method is truncated, not rounded
790 if (param < 1)
791 {
Geoff Langb1196682014-07-23 13:47:29 -0400792 context->recordError(Error(GL_INVALID_VALUE));
793 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400794 }
795 return true;
796
797 case GL_TEXTURE_MIN_LOD:
798 case GL_TEXTURE_MAX_LOD:
799 // any value is permissible
800 return true;
801
802 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400803 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804 switch (param)
805 {
806 case GL_NONE:
807 case GL_COMPARE_REF_TO_TEXTURE:
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_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400816 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400817 switch (param)
818 {
819 case GL_LEQUAL:
820 case GL_GEQUAL:
821 case GL_LESS:
822 case GL_GREATER:
823 case GL_EQUAL:
824 case GL_NOTEQUAL:
825 case GL_ALWAYS:
826 case GL_NEVER:
827 return true;
828 default:
Geoff Langb1196682014-07-23 13:47:29 -0400829 context->recordError(Error(GL_INVALID_ENUM));
830 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400831 }
832 break;
833
834 case GL_TEXTURE_SWIZZLE_R:
835 case GL_TEXTURE_SWIZZLE_G:
836 case GL_TEXTURE_SWIZZLE_B:
837 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400838 switch (param)
839 {
840 case GL_RED:
841 case GL_GREEN:
842 case GL_BLUE:
843 case GL_ALPHA:
844 case GL_ZERO:
845 case GL_ONE:
846 return true;
847 default:
Geoff Langb1196682014-07-23 13:47:29 -0400848 context->recordError(Error(GL_INVALID_ENUM));
849 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400850 }
851 break;
852
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400853 case GL_TEXTURE_BASE_LEVEL:
854 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400855 if (param < 0)
856 {
Geoff Langb1196682014-07-23 13:47:29 -0400857 context->recordError(Error(GL_INVALID_VALUE));
858 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400859 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400860 return true;
861
862 default:
Geoff Langb1196682014-07-23 13:47:29 -0400863 context->recordError(Error(GL_INVALID_ENUM));
864 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400865 }
866}
867
Geoff Langb1196682014-07-23 13:47:29 -0400868bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400869{
870 switch (pname)
871 {
872 case GL_TEXTURE_MIN_FILTER:
873 case GL_TEXTURE_MAG_FILTER:
874 case GL_TEXTURE_WRAP_S:
875 case GL_TEXTURE_WRAP_T:
876 case GL_TEXTURE_WRAP_R:
877 case GL_TEXTURE_MIN_LOD:
878 case GL_TEXTURE_MAX_LOD:
879 case GL_TEXTURE_COMPARE_MODE:
880 case GL_TEXTURE_COMPARE_FUNC:
881 return true;
882
883 default:
Geoff Langb1196682014-07-23 13:47:29 -0400884 context->recordError(Error(GL_INVALID_ENUM));
885 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400886 }
887}
888
Jamie Madill26e91952014-03-05 15:01:27 -0500889bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
890 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
891{
Shannon Woods53a94a82014-06-24 15:20:36 -0400892 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400893 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500894
Geoff Lang748f74e2014-12-01 11:25:34 -0500895 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500896 {
Geoff Langb1196682014-07-23 13:47:29 -0400897 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
898 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500899 }
900
Jamie Madill48faf802014-11-06 15:27:22 -0500901 if (context->getState().getReadFramebuffer()->id() != 0 &&
902 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500903 {
Geoff Langb1196682014-07-23 13:47:29 -0400904 context->recordError(Error(GL_INVALID_OPERATION));
905 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500906 }
907
Geoff Langbce529e2014-12-01 12:48:41 -0500908 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
909 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -0400910 {
Geoff Langb1196682014-07-23 13:47:29 -0400911 context->recordError(Error(GL_INVALID_OPERATION));
912 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400913 }
914
Geoff Langbce529e2014-12-01 12:48:41 -0500915 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
916 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -0500917 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -0400918 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500919
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400920 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
921 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500922
923 if (!(currentFormat == format && currentType == type) && !validReadFormat)
924 {
Geoff Langb1196682014-07-23 13:47:29 -0400925 context->recordError(Error(GL_INVALID_OPERATION));
926 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500927 }
928
Geoff Lang5d601382014-07-22 15:14:06 -0400929 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
930 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500931
Minmin Gongb8aee3b2015-01-27 14:42:36 -0800932 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -0500933 // sized query sanity check
934 if (bufSize)
935 {
936 int requiredSize = outputPitch * height;
937 if (requiredSize > *bufSize)
938 {
Geoff Langb1196682014-07-23 13:47:29 -0400939 context->recordError(Error(GL_INVALID_OPERATION));
940 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500941 }
942 }
943
944 return true;
945}
946
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400947bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
948{
949 if (!ValidQueryType(context, target))
950 {
Geoff Langb1196682014-07-23 13:47:29 -0400951 context->recordError(Error(GL_INVALID_ENUM));
952 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400953 }
954
955 if (id == 0)
956 {
Geoff Langb1196682014-07-23 13:47:29 -0400957 context->recordError(Error(GL_INVALID_OPERATION));
958 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400959 }
960
961 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
962 // of zero, if the active query object name for <target> is non-zero (for the
963 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
964 // the active query for either target is non-zero), if <id> is the name of an
965 // existing query object whose type does not match <target>, or if <id> is the
966 // active query object name for any query type, the error INVALID_OPERATION is
967 // generated.
968
969 // Ensure no other queries are active
970 // NOTE: If other queries than occlusion are supported, we will need to check
971 // separately that:
972 // a) The query ID passed is not the current active query for any target/type
973 // b) There are no active queries for the requested target (and in the case
974 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
975 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400976 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400977 {
Geoff Langb1196682014-07-23 13:47:29 -0400978 context->recordError(Error(GL_INVALID_OPERATION));
979 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400980 }
981
982 Query *queryObject = context->getQuery(id, true, target);
983
984 // check that name was obtained with glGenQueries
985 if (!queryObject)
986 {
Geoff Langb1196682014-07-23 13:47:29 -0400987 context->recordError(Error(GL_INVALID_OPERATION));
988 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400989 }
990
991 // check for type mismatch
992 if (queryObject->getType() != target)
993 {
Geoff Langb1196682014-07-23 13:47:29 -0400994 context->recordError(Error(GL_INVALID_OPERATION));
995 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400996 }
997
998 return true;
999}
1000
Jamie Madill45c785d2014-05-13 14:09:34 -04001001bool ValidateEndQuery(gl::Context *context, GLenum target)
1002{
1003 if (!ValidQueryType(context, target))
1004 {
Geoff Langb1196682014-07-23 13:47:29 -04001005 context->recordError(Error(GL_INVALID_ENUM));
1006 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001007 }
1008
Shannon Woods53a94a82014-06-24 15:20:36 -04001009 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001010
1011 if (queryObject == NULL)
1012 {
Geoff Langb1196682014-07-23 13:47:29 -04001013 context->recordError(Error(GL_INVALID_OPERATION));
1014 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001015 }
1016
Jamie Madill45c785d2014-05-13 14:09:34 -04001017 return true;
1018}
1019
Jamie Madill36398922014-05-20 14:51:53 -04001020static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1021 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001022{
1023 if (count < 0)
1024 {
Geoff Langb1196682014-07-23 13:47:29 -04001025 context->recordError(Error(GL_INVALID_VALUE));
1026 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001027 }
1028
Geoff Lang7dd2e102014-11-10 15:19:26 -05001029 gl::Program *program = context->getState().getProgram();
1030 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001031 {
Geoff Langb1196682014-07-23 13:47:29 -04001032 context->recordError(Error(GL_INVALID_OPERATION));
1033 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001034 }
1035
1036 if (location == -1)
1037 {
1038 // Silently ignore the uniform command
1039 return false;
1040 }
1041
Geoff Lang7dd2e102014-11-10 15:19:26 -05001042 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001043 {
Geoff Langb1196682014-07-23 13:47:29 -04001044 context->recordError(Error(GL_INVALID_OPERATION));
1045 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001046 }
1047
Geoff Lang7dd2e102014-11-10 15:19:26 -05001048 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001049
1050 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1051 if (uniform->elementCount() == 1 && count > 1)
1052 {
Geoff Langb1196682014-07-23 13:47:29 -04001053 context->recordError(Error(GL_INVALID_OPERATION));
1054 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001055 }
1056
1057 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001058 return true;
1059}
1060
Jamie Madillaa981bd2014-05-20 10:55:55 -04001061bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1062{
1063 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001064 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001065 {
Geoff Langb1196682014-07-23 13:47:29 -04001066 context->recordError(Error(GL_INVALID_OPERATION));
1067 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001068 }
1069
Jamie Madill36398922014-05-20 14:51:53 -04001070 LinkedUniform *uniform = NULL;
1071 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1072 {
1073 return false;
1074 }
1075
Jamie Madillf2575982014-06-25 16:04:54 -04001076 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001077 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001078 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1079 {
Geoff Langb1196682014-07-23 13:47:29 -04001080 context->recordError(Error(GL_INVALID_OPERATION));
1081 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001082 }
1083
1084 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001085}
1086
1087bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1088 GLboolean transpose)
1089{
1090 // Check for ES3 uniform entry points
1091 int rows = VariableRowCount(matrixType);
1092 int cols = VariableColumnCount(matrixType);
1093 if (rows != cols && context->getClientVersion() < 3)
1094 {
Geoff Langb1196682014-07-23 13:47:29 -04001095 context->recordError(Error(GL_INVALID_OPERATION));
1096 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001097 }
1098
1099 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1100 {
Geoff Langb1196682014-07-23 13:47:29 -04001101 context->recordError(Error(GL_INVALID_VALUE));
1102 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001103 }
1104
Jamie Madill36398922014-05-20 14:51:53 -04001105 LinkedUniform *uniform = NULL;
1106 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1107 {
1108 return false;
1109 }
1110
1111 if (uniform->type != matrixType)
1112 {
Geoff Langb1196682014-07-23 13:47:29 -04001113 context->recordError(Error(GL_INVALID_OPERATION));
1114 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001115 }
1116
1117 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001118}
1119
Jamie Madill893ab082014-05-16 16:56:10 -04001120bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1121{
1122 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1123 {
Geoff Langb1196682014-07-23 13:47:29 -04001124 context->recordError(Error(GL_INVALID_ENUM));
1125 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001126 }
1127
Jamie Madill0af26e12015-03-05 19:54:33 -05001128 const Caps &caps = context->getCaps();
1129
Jamie Madill893ab082014-05-16 16:56:10 -04001130 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1131 {
1132 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1133
Jamie Madill0af26e12015-03-05 19:54:33 -05001134 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001135 {
Geoff Langb1196682014-07-23 13:47:29 -04001136 context->recordError(Error(GL_INVALID_OPERATION));
1137 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001138 }
1139 }
1140
1141 switch (pname)
1142 {
1143 case GL_TEXTURE_BINDING_2D:
1144 case GL_TEXTURE_BINDING_CUBE_MAP:
1145 case GL_TEXTURE_BINDING_3D:
1146 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001147 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001148 {
Geoff Langb1196682014-07-23 13:47:29 -04001149 context->recordError(Error(GL_INVALID_OPERATION));
1150 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001151 }
1152 break;
1153
1154 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1155 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1156 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001157 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001158 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001159 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001160 {
Geoff Langb1196682014-07-23 13:47:29 -04001161 context->recordError(Error(GL_INVALID_OPERATION));
1162 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001163 }
1164
Jamie Madill3c7fa222014-06-05 13:08:51 -04001165 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1166 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001167 {
Geoff Langb1196682014-07-23 13:47:29 -04001168 context->recordError(Error(GL_INVALID_OPERATION));
1169 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001170 }
1171 }
1172 break;
1173
1174 default:
1175 break;
1176 }
1177
1178 // pname is valid, but there are no parameters to return
1179 if (numParams == 0)
1180 {
1181 return false;
1182 }
1183
1184 return true;
1185}
1186
Jamie Madill560a8d82014-05-21 13:06:20 -04001187bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1188 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1189 GLint border, GLenum *textureFormatOut)
1190{
1191
1192 if (!ValidTexture2DDestinationTarget(context, target))
1193 {
Geoff Langb1196682014-07-23 13:47:29 -04001194 context->recordError(Error(GL_INVALID_ENUM));
1195 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001196 }
1197
1198 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1199 {
Geoff Langb1196682014-07-23 13:47:29 -04001200 context->recordError(Error(GL_INVALID_VALUE));
1201 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001202 }
1203
1204 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1205 {
Geoff Langb1196682014-07-23 13:47:29 -04001206 context->recordError(Error(GL_INVALID_VALUE));
1207 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001208 }
1209
1210 if (border != 0)
1211 {
Geoff Langb1196682014-07-23 13:47:29 -04001212 context->recordError(Error(GL_INVALID_VALUE));
1213 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001214 }
1215
1216 if (!ValidMipLevel(context, target, level))
1217 {
Geoff Langb1196682014-07-23 13:47:29 -04001218 context->recordError(Error(GL_INVALID_VALUE));
1219 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001220 }
1221
Shannon Woods53a94a82014-06-24 15:20:36 -04001222 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001223 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001224 {
Geoff Langb1196682014-07-23 13:47:29 -04001225 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1226 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001227 }
1228
Jamie Madill48faf802014-11-06 15:27:22 -05001229 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001230 {
Geoff Langb1196682014-07-23 13:47:29 -04001231 context->recordError(Error(GL_INVALID_OPERATION));
1232 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001233 }
1234
Geoff Langaae65a42014-05-26 12:43:44 -04001235 const gl::Caps &caps = context->getCaps();
1236
Geoff Langaae65a42014-05-26 12:43:44 -04001237 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001238 switch (target)
1239 {
1240 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001241 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001242 break;
1243
1244 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1245 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1246 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1247 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1248 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1249 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001250 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001251 break;
1252
1253 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001254 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001255 break;
1256
1257 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001258 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001259 break;
1260
1261 default:
Geoff Langb1196682014-07-23 13:47:29 -04001262 context->recordError(Error(GL_INVALID_ENUM));
1263 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001264 }
1265
Geoff Lang691e58c2014-12-19 17:03:25 -05001266 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001267 if (!texture)
1268 {
Geoff Langb1196682014-07-23 13:47:29 -04001269 context->recordError(Error(GL_INVALID_OPERATION));
1270 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001271 }
1272
1273 if (texture->isImmutable() && !isSubImage)
1274 {
Geoff Langb1196682014-07-23 13:47:29 -04001275 context->recordError(Error(GL_INVALID_OPERATION));
1276 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001277 }
1278
Geoff Lang5d601382014-07-22 15:14:06 -04001279 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1280
1281 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001282 {
Geoff Langb1196682014-07-23 13:47:29 -04001283 context->recordError(Error(GL_INVALID_OPERATION));
1284 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001285 }
1286
Geoff Langa9be0dc2014-12-17 12:34:40 -05001287 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001288 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001289 context->recordError(Error(GL_INVALID_OPERATION));
1290 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001291 }
1292
1293 if (isSubImage)
1294 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001295 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1296 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1297 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001298 {
Geoff Langb1196682014-07-23 13:47:29 -04001299 context->recordError(Error(GL_INVALID_VALUE));
1300 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001301 }
1302 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001303 else
1304 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001305 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001306 {
Geoff Langb1196682014-07-23 13:47:29 -04001307 context->recordError(Error(GL_INVALID_VALUE));
1308 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001309 }
1310
Geoff Lang5d601382014-07-22 15:14:06 -04001311 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001312 {
Geoff Langb1196682014-07-23 13:47:29 -04001313 context->recordError(Error(GL_INVALID_ENUM));
1314 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001315 }
1316
1317 int maxLevelDimension = (maxDimension >> level);
1318 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1319 {
Geoff Langb1196682014-07-23 13:47:29 -04001320 context->recordError(Error(GL_INVALID_VALUE));
1321 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001322 }
1323 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001324
Geoff Langa9be0dc2014-12-17 12:34:40 -05001325 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001326 return true;
1327}
1328
Geoff Langb1196682014-07-23 13:47:29 -04001329static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001330{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001331 switch (mode)
1332 {
1333 case GL_POINTS:
1334 case GL_LINES:
1335 case GL_LINE_LOOP:
1336 case GL_LINE_STRIP:
1337 case GL_TRIANGLES:
1338 case GL_TRIANGLE_STRIP:
1339 case GL_TRIANGLE_FAN:
1340 break;
1341 default:
Geoff Langb1196682014-07-23 13:47:29 -04001342 context->recordError(Error(GL_INVALID_ENUM));
1343 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001344 }
1345
Jamie Madill250d33f2014-06-06 17:09:03 -04001346 if (count < 0)
1347 {
Geoff Langb1196682014-07-23 13:47:29 -04001348 context->recordError(Error(GL_INVALID_VALUE));
1349 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001350 }
1351
Geoff Langb1196682014-07-23 13:47:29 -04001352 const State &state = context->getState();
1353
Jamie Madill250d33f2014-06-06 17:09:03 -04001354 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001355 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001356 {
Geoff Langb1196682014-07-23 13:47:29 -04001357 context->recordError(Error(GL_INVALID_OPERATION));
1358 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001359 }
1360
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001361 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001362 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001363 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001364 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1365 {
1366 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1367 // See Section 6.10 of the WebGL 1.0 spec
1368 ERR("This ANGLE implementation does not support separate front/back stencil "
1369 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001370 context->recordError(Error(GL_INVALID_OPERATION));
1371 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001372 }
1373
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001374 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001375 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001376 {
Geoff Langb1196682014-07-23 13:47:29 -04001377 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1378 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001379 }
1380
Geoff Lang7dd2e102014-11-10 15:19:26 -05001381 gl::Program *program = state.getProgram();
1382 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001383 {
Geoff Langb1196682014-07-23 13:47:29 -04001384 context->recordError(Error(GL_INVALID_OPERATION));
1385 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001386 }
1387
Geoff Lang7dd2e102014-11-10 15:19:26 -05001388 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001389 {
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_OPERATION));
1391 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001392 }
1393
Jamie Madill2b976812014-08-25 15:47:49 -04001394 // Buffer validations
1395 const VertexArray *vao = state.getVertexArray();
1396 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1397 {
1398 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001399 bool attribActive = (program->getSemanticIndex(attributeIndex) != -1);
Jamie Madill2b976812014-08-25 15:47:49 -04001400 if (attribActive && attrib.enabled)
1401 {
1402 gl::Buffer *buffer = attrib.buffer.get();
1403
1404 if (buffer)
1405 {
1406 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1407 GLint64 maxVertexElement = 0;
1408
1409 if (attrib.divisor > 0)
1410 {
1411 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1412 }
1413 else
1414 {
1415 maxVertexElement = static_cast<GLint64>(maxVertex);
1416 }
1417
1418 GLint64 attribDataSize = maxVertexElement * attribStride;
1419
1420 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1421 // We can return INVALID_OPERATION if our vertex attribute does not have
1422 // enough backing data.
1423 if (attribDataSize > buffer->getSize())
1424 {
Geoff Langb1196682014-07-23 13:47:29 -04001425 context->recordError(Error(GL_INVALID_OPERATION));
1426 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001427 }
1428 }
1429 else if (attrib.pointer == NULL)
1430 {
1431 // This is an application error that would normally result in a crash,
1432 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001433 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1434 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001435 }
1436 }
1437 }
1438
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001439 // Uniform buffer validation
1440 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1441 {
1442 const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
1443 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
1444 const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
1445
1446 if (!uniformBuffer)
1447 {
1448 // undefined behaviour
1449 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1450 return false;
1451 }
1452
1453 size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
1454
1455 if (uniformBufferSize == 0)
1456 {
1457 // Bind the whole buffer.
1458 uniformBufferSize = uniformBuffer->getSize();
1459 }
1460
1461 if (uniformBufferSize < uniformBlock->dataSize)
1462 {
1463 // undefined behaviour
1464 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1465 return false;
1466 }
1467 }
1468
Jamie Madill250d33f2014-06-06 17:09:03 -04001469 // No-op if zero count
1470 return (count > 0);
1471}
1472
Geoff Langb1196682014-07-23 13:47:29 -04001473bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001474{
Jamie Madillfd716582014-06-06 17:09:04 -04001475 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001476 {
Geoff Langb1196682014-07-23 13:47:29 -04001477 context->recordError(Error(GL_INVALID_VALUE));
1478 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001479 }
1480
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001481 const State &state = context->getState();
1482 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001483 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1484 curTransformFeedback->getDrawMode() != mode)
1485 {
1486 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1487 // that does not match the current transform feedback object's draw mode (if transform feedback
1488 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001489 context->recordError(Error(GL_INVALID_OPERATION));
1490 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001491 }
1492
Geoff Langb1196682014-07-23 13:47:29 -04001493 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001494 {
1495 return false;
1496 }
1497
1498 return true;
1499}
1500
Geoff Langb1196682014-07-23 13:47:29 -04001501bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001502{
1503 if (primcount < 0)
1504 {
Geoff Langb1196682014-07-23 13:47:29 -04001505 context->recordError(Error(GL_INVALID_VALUE));
1506 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001507 }
1508
Jamie Madill2b976812014-08-25 15:47:49 -04001509 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001510 {
1511 return false;
1512 }
1513
1514 // No-op if zero primitive count
1515 return (primcount > 0);
1516}
1517
Geoff Lang87a93302014-09-16 13:29:43 -04001518static bool ValidateDrawInstancedANGLE(Context *context)
1519{
1520 // Verify there is at least one active attribute with a divisor of zero
1521 const gl::State& state = context->getState();
1522
Geoff Lang7dd2e102014-11-10 15:19:26 -05001523 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001524
1525 const VertexArray *vao = state.getVertexArray();
1526 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1527 {
1528 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001529 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001530 if (active && attrib.divisor == 0)
1531 {
1532 return true;
1533 }
1534 }
1535
1536 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1537 "has a divisor of zero."));
1538 return false;
1539}
1540
1541bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1542{
1543 if (!ValidateDrawInstancedANGLE(context))
1544 {
1545 return false;
1546 }
1547
1548 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1549}
1550
Geoff Langb1196682014-07-23 13:47:29 -04001551bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001552 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001553{
Jamie Madill250d33f2014-06-06 17:09:03 -04001554 switch (type)
1555 {
1556 case GL_UNSIGNED_BYTE:
1557 case GL_UNSIGNED_SHORT:
1558 break;
1559 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001560 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001561 {
Geoff Langb1196682014-07-23 13:47:29 -04001562 context->recordError(Error(GL_INVALID_ENUM));
1563 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001564 }
1565 break;
1566 default:
Geoff Langb1196682014-07-23 13:47:29 -04001567 context->recordError(Error(GL_INVALID_ENUM));
1568 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001569 }
1570
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001571 const State &state = context->getState();
1572
1573 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001574 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1575 {
1576 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1577 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001578 context->recordError(Error(GL_INVALID_OPERATION));
1579 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001580 }
1581
1582 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001583 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001584 {
Geoff Langb1196682014-07-23 13:47:29 -04001585 context->recordError(Error(GL_INVALID_OPERATION));
1586 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001587 }
1588
Jamie Madill2b976812014-08-25 15:47:49 -04001589 const gl::VertexArray *vao = state.getVertexArray();
Olli Etuahoff5e7372015-03-25 16:52:11 +02001590 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
Jamie Madill2b976812014-08-25 15:47:49 -04001591 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001592 {
Geoff Langb1196682014-07-23 13:47:29 -04001593 context->recordError(Error(GL_INVALID_OPERATION));
1594 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001595 }
1596
Jamie Madillae3000b2014-08-25 15:47:51 -04001597 if (elementArrayBuffer)
1598 {
1599 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1600
1601 GLint64 offset = reinterpret_cast<GLint64>(indices);
1602 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1603
1604 // check for integer overflows
1605 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1606 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1607 {
Geoff Langb1196682014-07-23 13:47:29 -04001608 context->recordError(Error(GL_OUT_OF_MEMORY));
1609 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001610 }
1611
1612 // Check for reading past the end of the bound buffer object
1613 if (byteCount > elementArrayBuffer->getSize())
1614 {
Geoff Langb1196682014-07-23 13:47:29 -04001615 context->recordError(Error(GL_INVALID_OPERATION));
1616 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001617 }
1618 }
1619 else if (!indices)
1620 {
1621 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001622 context->recordError(Error(GL_INVALID_OPERATION));
1623 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001624 }
1625
Jamie Madill2b976812014-08-25 15:47:49 -04001626 // Use max index to validate if our vertex buffers are large enough for the pull.
1627 // TODO: offer fast path, with disabled index validation.
1628 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1629 if (elementArrayBuffer)
1630 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001631 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Olli Etuaho3d5f2682015-03-25 17:05:59 +02001632 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut))
Jamie Madill2b976812014-08-25 15:47:49 -04001633 {
Jamie Madill72468832015-01-05 15:03:18 -05001634 rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation();
Geoff Langc8d297a2014-09-19 11:09:08 -04001635 const uint8_t *dataPointer = NULL;
Jamie Madill72468832015-01-05 15:03:18 -05001636 Error error = bufferImpl->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001637 if (error.isError())
1638 {
1639 context->recordError(error);
1640 return false;
1641 }
1642
1643 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001644 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
Olli Etuaho3d5f2682015-03-25 17:05:59 +02001645 elementArrayBuffer->getIndexRangeCache()->addRange(type, offset, count, *indexRangeOut);
Jamie Madill2b976812014-08-25 15:47:49 -04001646 }
1647 }
1648 else
1649 {
1650 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1651 }
1652
Geoff Langb1196682014-07-23 13:47:29 -04001653 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001654 {
1655 return false;
1656 }
1657
1658 return true;
1659}
1660
Geoff Langb1196682014-07-23 13:47:29 -04001661bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001662 GLenum mode, GLsizei count, GLenum type,
1663 const GLvoid *indices, GLsizei primcount,
1664 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001665{
1666 if (primcount < 0)
1667 {
Geoff Langb1196682014-07-23 13:47:29 -04001668 context->recordError(Error(GL_INVALID_VALUE));
1669 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001670 }
1671
Jamie Madill2b976812014-08-25 15:47:49 -04001672 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001673 {
1674 return false;
1675 }
1676
1677 // No-op zero primitive count
1678 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001679}
1680
Geoff Lang87a93302014-09-16 13:29:43 -04001681bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1682 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1683{
1684 if (!ValidateDrawInstancedANGLE(context))
1685 {
1686 return false;
1687 }
1688
1689 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1690}
1691
Geoff Langb1196682014-07-23 13:47:29 -04001692bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001693 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001694{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001695 if (!ValidFramebufferTarget(target))
1696 {
Geoff Langb1196682014-07-23 13:47:29 -04001697 context->recordError(Error(GL_INVALID_ENUM));
1698 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001699 }
1700
1701 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001702 {
1703 return false;
1704 }
1705
Jamie Madill55ec3b12014-07-03 10:38:57 -04001706 if (texture != 0)
1707 {
1708 gl::Texture *tex = context->getTexture(texture);
1709
1710 if (tex == NULL)
1711 {
Geoff Langb1196682014-07-23 13:47:29 -04001712 context->recordError(Error(GL_INVALID_OPERATION));
1713 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001714 }
1715
1716 if (level < 0)
1717 {
Geoff Langb1196682014-07-23 13:47:29 -04001718 context->recordError(Error(GL_INVALID_VALUE));
1719 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001720 }
1721 }
1722
Shannon Woods53a94a82014-06-24 15:20:36 -04001723 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1724 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001725
1726 if (framebufferHandle == 0 || !framebuffer)
1727 {
Geoff Langb1196682014-07-23 13:47:29 -04001728 context->recordError(Error(GL_INVALID_OPERATION));
1729 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001730 }
1731
1732 return true;
1733}
1734
Geoff Langb1196682014-07-23 13:47:29 -04001735bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001736 GLenum textarget, GLuint texture, GLint level)
1737{
1738 // Attachments are required to be bound to level 0 in ES2
1739 if (context->getClientVersion() < 3 && level != 0)
1740 {
Geoff Langb1196682014-07-23 13:47:29 -04001741 context->recordError(Error(GL_INVALID_VALUE));
1742 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001743 }
1744
1745 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001746 {
1747 return false;
1748 }
1749
Jamie Madill55ec3b12014-07-03 10:38:57 -04001750 if (texture != 0)
1751 {
1752 gl::Texture *tex = context->getTexture(texture);
1753 ASSERT(tex);
1754
Jamie Madill2a6564e2014-07-11 09:53:19 -04001755 const gl::Caps &caps = context->getCaps();
1756
Jamie Madill55ec3b12014-07-03 10:38:57 -04001757 switch (textarget)
1758 {
1759 case GL_TEXTURE_2D:
1760 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001761 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001762 {
Geoff Langb1196682014-07-23 13:47:29 -04001763 context->recordError(Error(GL_INVALID_VALUE));
1764 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001765 }
1766 if (tex->getTarget() != GL_TEXTURE_2D)
1767 {
Geoff Langb1196682014-07-23 13:47:29 -04001768 context->recordError(Error(GL_INVALID_OPERATION));
1769 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001770 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001771 }
1772 break;
1773
1774 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1775 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1776 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1777 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1778 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1779 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1780 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001781 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001782 {
Geoff Langb1196682014-07-23 13:47:29 -04001783 context->recordError(Error(GL_INVALID_VALUE));
1784 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001785 }
1786 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1787 {
Geoff Langb1196682014-07-23 13:47:29 -04001788 context->recordError(Error(GL_INVALID_OPERATION));
1789 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001790 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001791 }
1792 break;
1793
1794 default:
Geoff Langb1196682014-07-23 13:47:29 -04001795 context->recordError(Error(GL_INVALID_ENUM));
1796 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001797 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001798
1799 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1800 if (internalFormatInfo.compressed)
1801 {
1802 context->recordError(Error(GL_INVALID_OPERATION));
1803 return false;
1804 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001805 }
1806
Jamie Madill570f7c82014-07-03 10:38:54 -04001807 return true;
1808}
1809
Geoff Langb1196682014-07-23 13:47:29 -04001810bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001811{
1812 if (program == 0)
1813 {
Geoff Langb1196682014-07-23 13:47:29 -04001814 context->recordError(Error(GL_INVALID_VALUE));
1815 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001816 }
1817
Shannon Woods4de4fd62014-11-07 16:22:02 -05001818 if (!ValidProgram(context, program))
1819 {
1820 return false;
1821 }
1822
Jamie Madill0063c512014-08-25 15:47:53 -04001823 gl::Program *programObject = context->getProgram(program);
1824
1825 if (!programObject || !programObject->isLinked())
1826 {
Geoff Langb1196682014-07-23 13:47:29 -04001827 context->recordError(Error(GL_INVALID_OPERATION));
1828 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001829 }
1830
Geoff Lang7dd2e102014-11-10 15:19:26 -05001831 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001832 {
Geoff Langb1196682014-07-23 13:47:29 -04001833 context->recordError(Error(GL_INVALID_OPERATION));
1834 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001835 }
1836
Jamie Madill0063c512014-08-25 15:47:53 -04001837 return true;
1838}
1839
Geoff Langb1196682014-07-23 13:47:29 -04001840bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001841{
1842 return ValidateGetUniformBase(context, program, location);
1843}
1844
Geoff Langb1196682014-07-23 13:47:29 -04001845bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001846{
Jamie Madill78f41802014-08-25 15:47:55 -04001847 return ValidateGetUniformBase(context, program, location);
1848}
1849
Geoff Langb1196682014-07-23 13:47:29 -04001850static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001851{
1852 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001853 {
Jamie Madill78f41802014-08-25 15:47:55 -04001854 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001855 }
1856
Jamie Madilla502c742014-08-28 17:19:13 -04001857 gl::Program *programObject = context->getProgram(program);
1858 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001859
Jamie Madill78f41802014-08-25 15:47:55 -04001860 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001861 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001862 size_t requiredBytes = VariableExternalSize(uniform->type);
1863 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001864 {
Geoff Langb1196682014-07-23 13:47:29 -04001865 context->recordError(Error(GL_INVALID_OPERATION));
1866 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001867 }
1868
1869 return true;
1870}
1871
Geoff Langb1196682014-07-23 13:47:29 -04001872bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001873{
Jamie Madill78f41802014-08-25 15:47:55 -04001874 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001875}
1876
Geoff Langb1196682014-07-23 13:47:29 -04001877bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001878{
Jamie Madill78f41802014-08-25 15:47:55 -04001879 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001880}
1881
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001882}