blob: 2c58af50bb0ea7b3814adc5bfe1c864249aaea54 [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"
Geoff Langa8406172015-07-21 16:53:39 -040013#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#include "libANGLE/Texture.h"
15#include "libANGLE/Framebuffer.h"
16#include "libANGLE/FramebufferAttachment.h"
17#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040018#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050020#include "libANGLE/Program.h"
21#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050022#include "libANGLE/TransformFeedback.h"
23#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040024
25#include "common/mathutil.h"
26#include "common/utilities.h"
27
28namespace gl
29{
Jamie Madill1ca74672015-07-21 15:14:11 -040030namespace
31{
32bool ValidateDrawAttribs(gl::Context *context, GLint primcount, GLint maxVertex)
33{
34 const gl::State &state = context->getState();
35 const gl::Program *program = state.getProgram();
36
37 const VertexArray *vao = state.getVertexArray();
38 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040039 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
40 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
41 {
42 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040043 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040044 {
45 gl::Buffer *buffer = attrib.buffer.get();
46
47 if (buffer)
48 {
49 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
50 GLint64 maxVertexElement = 0;
51
52 if (attrib.divisor > 0)
53 {
54 maxVertexElement =
55 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
56 }
57 else
58 {
59 maxVertexElement = static_cast<GLint64>(maxVertex);
60 }
61
62 // If we're drawing zero vertices, we have enough data.
63 if (maxVertexElement > 0)
64 {
65 // Note: Last vertex element does not take the full stride!
66 GLint64 attribSize =
67 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
68 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
69
70 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
71 // We can return INVALID_OPERATION if our vertex attribute does not have
72 // enough backing data.
73 if (attribDataSize > buffer->getSize())
74 {
75 context->recordError(Error(GL_INVALID_OPERATION));
76 return false;
77 }
78 }
79 }
80 else if (attrib.pointer == NULL)
81 {
82 // This is an application error that would normally result in a crash,
83 // but we catch it and return an error
84 context->recordError(Error(
85 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
86 return false;
87 }
88 }
89 }
90
91 return true;
92}
93
94} // anonymous namespace
Geoff Lange8ebe7f2013-08-05 15:03:13 -040095
Geoff Lang0550d032014-01-30 11:29:07 -050096bool ValidCap(const Context *context, GLenum cap)
97{
98 switch (cap)
99 {
100 case GL_CULL_FACE:
101 case GL_POLYGON_OFFSET_FILL:
102 case GL_SAMPLE_ALPHA_TO_COVERAGE:
103 case GL_SAMPLE_COVERAGE:
104 case GL_SCISSOR_TEST:
105 case GL_STENCIL_TEST:
106 case GL_DEPTH_TEST:
107 case GL_BLEND:
108 case GL_DITHER:
109 return true;
110 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
111 case GL_RASTERIZER_DISCARD:
112 return (context->getClientVersion() >= 3);
113 default:
114 return false;
115 }
116}
117
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500118bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400119{
Jamie Madilld7460c72014-01-21 16:38:14 -0500120 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400121 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500122 case GL_TEXTURE_2D:
123 case GL_TEXTURE_CUBE_MAP:
124 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400125
Jamie Madilld7460c72014-01-21 16:38:14 -0500126 case GL_TEXTURE_3D:
127 case GL_TEXTURE_2D_ARRAY:
128 return (context->getClientVersion() >= 3);
129
130 default:
131 return false;
132 }
Jamie Madill35d15012013-10-07 10:46:37 -0400133}
134
Shannon Woods4dfed832014-03-17 20:03:39 -0400135// This function differs from ValidTextureTarget in that the target must be
136// usable as the destination of a 2D operation-- so a cube face is valid, but
137// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400138// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -0400139bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
140{
141 switch (target)
142 {
143 case GL_TEXTURE_2D:
144 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
145 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
146 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
150 return true;
151 case GL_TEXTURE_2D_ARRAY:
152 case GL_TEXTURE_3D:
153 return (context->getClientVersion() >= 3);
154 default:
155 return false;
156 }
157}
158
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500159bool ValidFramebufferTarget(GLenum target)
160{
Geoff Langd4475812015-03-18 10:53:05 -0400161 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
162 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500163
164 switch (target)
165 {
166 case GL_FRAMEBUFFER: return true;
167 case GL_READ_FRAMEBUFFER: return true;
168 case GL_DRAW_FRAMEBUFFER: return true;
169 default: return false;
170 }
171}
172
Jamie Madill8c96d582014-03-05 15:01:23 -0500173bool ValidBufferTarget(const Context *context, GLenum target)
174{
175 switch (target)
176 {
177 case GL_ARRAY_BUFFER:
178 case GL_ELEMENT_ARRAY_BUFFER:
179 return true;
180
Jamie Madill8c96d582014-03-05 15:01:23 -0500181 case GL_PIXEL_PACK_BUFFER:
182 case GL_PIXEL_UNPACK_BUFFER:
Geoff Lange4de3072015-09-02 11:01:32 -0400183 return (context->getExtensions().pixelBufferObject || context->getClientVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400184
Shannon Woodsb3801742014-03-27 14:59:19 -0400185 case GL_COPY_READ_BUFFER:
186 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500187 case GL_TRANSFORM_FEEDBACK_BUFFER:
188 case GL_UNIFORM_BUFFER:
189 return (context->getClientVersion() >= 3);
190
191 default:
192 return false;
193 }
194}
195
Jamie Madill70656a62014-03-05 15:01:26 -0500196bool ValidBufferParameter(const Context *context, GLenum pname)
197{
Geoff Langcc6f55d2015-03-20 13:01:02 -0400198 const Extensions &extensions = context->getExtensions();
199
Jamie Madill70656a62014-03-05 15:01:26 -0500200 switch (pname)
201 {
202 case GL_BUFFER_USAGE:
203 case GL_BUFFER_SIZE:
204 return true;
205
Geoff Langcc6f55d2015-03-20 13:01:02 -0400206 case GL_BUFFER_ACCESS_OES:
207 return extensions.mapBuffer;
208
209 case GL_BUFFER_MAPPED:
210 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
211 return (context->getClientVersion() >= 3) || extensions.mapBuffer || extensions.mapBufferRange;
212
Jamie Madill70656a62014-03-05 15:01:26 -0500213 // GL_BUFFER_MAP_POINTER is a special case, and may only be
214 // queried with GetBufferPointerv
215 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500216 case GL_BUFFER_MAP_OFFSET:
217 case GL_BUFFER_MAP_LENGTH:
Geoff Langcc6f55d2015-03-20 13:01:02 -0400218 return (context->getClientVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500219
220 default:
221 return false;
222 }
223}
224
Jamie Madill8c96d582014-03-05 15:01:23 -0500225bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400226{
Geoff Langaae65a42014-05-26 12:43:44 -0400227 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400228 switch (target)
229 {
Geoff Langaae65a42014-05-26 12:43:44 -0400230 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400231 case GL_TEXTURE_CUBE_MAP:
232 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
233 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
235 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
236 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400237 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
238 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
239 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400240 default: UNREACHABLE();
241 }
242
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700243 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400244}
245
Geoff Langb1196682014-07-23 13:47:29 -0400246bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400247 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400248{
249 if (level < 0 || width < 0 || height < 0 || depth < 0)
250 {
251 return false;
252 }
253
Geoff Langc0b9ef42014-07-02 10:02:37 -0400254 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400255 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400256 {
257 return false;
258 }
259
260 if (!ValidMipLevel(context, target, level))
261 {
262 return false;
263 }
264
265 return true;
266}
267
Geoff Lang0d8b7242015-09-09 14:56:53 -0400268bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
269{
270 // List of compressed format that require that the texture size is smaller than or a multiple of
271 // the compressed block size.
272 switch (internalFormat)
273 {
274 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
275 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
276 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
277 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
278 return true;
279
280 default:
281 return false;
282 }
283}
284
Geoff Langb1196682014-07-23 13:47:29 -0400285bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400286{
Geoff Lang5d601382014-07-22 15:14:06 -0400287 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
288 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400289 {
290 return false;
291 }
292
Geoff Lang0d8b7242015-09-09 14:56:53 -0400293 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400294 {
295 return false;
296 }
297
Geoff Lang0d8b7242015-09-09 14:56:53 -0400298 if (CompressedTextureFormatRequiresExactSize(internalFormat))
299 {
300 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
301 width % formatInfo.compressedBlockWidth != 0) ||
302 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
303 height % formatInfo.compressedBlockHeight != 0))
304 {
305 return false;
306 }
307 }
308
Geoff Langd4f180b2013-09-24 13:57:44 -0400309 return true;
310}
311
Geoff Lang37dde692014-01-31 16:34:54 -0500312bool ValidQueryType(const Context *context, GLenum queryType)
313{
Geoff Langd4475812015-03-18 10:53:05 -0400314 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
315 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 -0500316
317 switch (queryType)
318 {
319 case GL_ANY_SAMPLES_PASSED:
320 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
321 return true;
322 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
323 return (context->getClientVersion() >= 3);
324 default:
325 return false;
326 }
327}
328
Geoff Langb1196682014-07-23 13:47:29 -0400329bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500330{
331 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
332 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
333 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
334
335 if (context->getProgram(id) != NULL)
336 {
337 return true;
338 }
339 else if (context->getShader(id) != NULL)
340 {
341 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400342 context->recordError(Error(GL_INVALID_OPERATION));
343 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500344 }
345 else
346 {
347 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400348 context->recordError(Error(GL_INVALID_VALUE));
349 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500350 }
351}
352
Geoff Langb1196682014-07-23 13:47:29 -0400353bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400354{
355 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
356 {
357 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
358
Geoff Langaae65a42014-05-26 12:43:44 -0400359 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400360 {
Geoff Langb1196682014-07-23 13:47:29 -0400361 context->recordError(Error(GL_INVALID_VALUE));
362 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400363 }
364 }
365 else
366 {
367 switch (attachment)
368 {
369 case GL_DEPTH_ATTACHMENT:
370 case GL_STENCIL_ATTACHMENT:
371 break;
372
373 case GL_DEPTH_STENCIL_ATTACHMENT:
374 if (context->getClientVersion() < 3)
375 {
Geoff Langb1196682014-07-23 13:47:29 -0400376 context->recordError(Error(GL_INVALID_ENUM));
377 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400378 }
379 break;
380
381 default:
Geoff Langb1196682014-07-23 13:47:29 -0400382 context->recordError(Error(GL_INVALID_ENUM));
383 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400384 }
385 }
386
387 return true;
388}
389
Corentin Walleze0902642014-11-04 12:32:15 -0800390bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
391 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400392{
393 switch (target)
394 {
395 case GL_RENDERBUFFER:
396 break;
397 default:
Geoff Langb1196682014-07-23 13:47:29 -0400398 context->recordError(Error(GL_INVALID_ENUM));
399 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400400 }
401
402 if (width < 0 || height < 0 || samples < 0)
403 {
Geoff Langb1196682014-07-23 13:47:29 -0400404 context->recordError(Error(GL_INVALID_VALUE));
405 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400406 }
407
Geoff Langd87878e2014-09-19 15:42:59 -0400408 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
409 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400410 {
Geoff Langb1196682014-07-23 13:47:29 -0400411 context->recordError(Error(GL_INVALID_ENUM));
412 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400413 }
414
415 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
416 // 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 -0800417 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400418 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400419 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400420 {
Geoff Langb1196682014-07-23 13:47:29 -0400421 context->recordError(Error(GL_INVALID_ENUM));
422 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400423 }
424
Geoff Langaae65a42014-05-26 12:43:44 -0400425 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400426 {
Geoff Langb1196682014-07-23 13:47:29 -0400427 context->recordError(Error(GL_INVALID_VALUE));
428 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400429 }
430
Shannon Woods53a94a82014-06-24 15:20:36 -0400431 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400432 if (handle == 0)
433 {
Geoff Langb1196682014-07-23 13:47:29 -0400434 context->recordError(Error(GL_INVALID_OPERATION));
435 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400436 }
437
438 return true;
439}
440
Corentin Walleze0902642014-11-04 12:32:15 -0800441bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
442 GLenum internalformat, GLsizei width, GLsizei height)
443{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800444 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800445
446 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400447 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800448 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400449 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800450 {
451 context->recordError(Error(GL_INVALID_VALUE));
452 return false;
453 }
454
455 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
456 // the specified storage. This is different than ES 3.0 in which a sample number higher
457 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800458 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
459 if (context->getClientVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800460 {
Geoff Langa4903b72015-03-02 16:02:48 -0800461 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
462 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
463 {
464 context->recordError(Error(GL_OUT_OF_MEMORY));
465 return false;
466 }
Corentin Walleze0902642014-11-04 12:32:15 -0800467 }
468
469 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
470}
471
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500472bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
473 GLenum renderbuffertarget, GLuint renderbuffer)
474{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400475 if (!ValidFramebufferTarget(target))
476 {
Geoff Langb1196682014-07-23 13:47:29 -0400477 context->recordError(Error(GL_INVALID_ENUM));
478 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400479 }
480
Shannon Woods53a94a82014-06-24 15:20:36 -0400481 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500482
Jamie Madill84115c92015-04-23 15:00:07 -0400483 ASSERT(framebuffer);
484 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500485 {
Jamie Madill84115c92015-04-23 15:00:07 -0400486 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400487 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500488 }
489
Jamie Madillb4472272014-07-03 10:38:55 -0400490 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500491 {
Jamie Madillb4472272014-07-03 10:38:55 -0400492 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500493 }
494
Jamie Madillab9d82c2014-01-21 16:38:14 -0500495 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
496 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
497 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
498 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
499 if (renderbuffer != 0)
500 {
501 if (!context->getRenderbuffer(renderbuffer))
502 {
Geoff Langb1196682014-07-23 13:47:29 -0400503 context->recordError(Error(GL_INVALID_OPERATION));
504 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500505 }
506 }
507
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500508 return true;
509}
510
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400511static bool IsPartialBlit(gl::Context *context, const gl::FramebufferAttachment *readBuffer, const gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400512 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
513 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
514{
515 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
516 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
517 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
518 {
519 return true;
520 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400521 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400522 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400523 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400524
Shannon Woods53a94a82014-06-24 15:20:36 -0400525 return scissor.x > 0 || scissor.y > 0 ||
526 scissor.width < writeBuffer->getWidth() ||
527 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400528 }
529 else
530 {
531 return false;
532 }
533}
534
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400535bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400536 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
537 GLenum filter, bool fromAngleExtension)
538{
539 switch (filter)
540 {
541 case GL_NEAREST:
542 break;
543 case GL_LINEAR:
544 if (fromAngleExtension)
545 {
Geoff Langb1196682014-07-23 13:47:29 -0400546 context->recordError(Error(GL_INVALID_ENUM));
547 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400548 }
549 break;
550 default:
Geoff Langb1196682014-07-23 13:47:29 -0400551 context->recordError(Error(GL_INVALID_ENUM));
552 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 }
554
555 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
556 {
Geoff Langb1196682014-07-23 13:47:29 -0400557 context->recordError(Error(GL_INVALID_VALUE));
558 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400559 }
560
561 if (mask == 0)
562 {
563 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
564 // buffers are copied.
565 return false;
566 }
567
568 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
569 {
570 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400571 context->recordError(Error(GL_INVALID_OPERATION));
572 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400573 }
574
575 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
576 // color buffer, leaving only nearest being unfiltered from above
577 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
578 {
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
Shannon Woods53a94a82014-06-24 15:20:36 -0400583 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400584 {
585 if (fromAngleExtension)
586 {
587 ERR("Blits with the same source and destination framebuffer are not supported by this "
588 "implementation.");
589 }
Geoff Langb1196682014-07-23 13:47:29 -0400590 context->recordError(Error(GL_INVALID_OPERATION));
591 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400592 }
593
Jamie Madille3ef7152015-04-28 16:55:17 +0000594 const gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
595 const gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500596
597 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400598 {
Geoff Langb1196682014-07-23 13:47:29 -0400599 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
600 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400601 }
602
Geoff Lang748f74e2014-12-01 11:25:34 -0500603 if (!readFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500604 {
605 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
606 return false;
607 }
608
Geoff Lang748f74e2014-12-01 11:25:34 -0500609 if (!drawFramebuffer->checkStatus(context->getData()))
Jamie Madill48faf802014-11-06 15:27:22 -0500610 {
611 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
612 return false;
613 }
614
615 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400616 {
Geoff Langb1196682014-07-23 13:47:29 -0400617 context->recordError(Error(GL_INVALID_OPERATION));
618 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400619 }
620
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400621 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
622
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400623 if (mask & GL_COLOR_BUFFER_BIT)
624 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400625 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
626 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627
628 if (readColorBuffer && drawColorBuffer)
629 {
Geoff Langd8a22582014-12-17 15:28:23 -0500630 GLenum readInternalFormat = readColorBuffer->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400631 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632
Corentin Wallez37c39792015-08-20 14:19:46 -0400633 for (size_t i = 0; i < drawFramebuffer->getNumColorBuffers(); i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 {
635 if (drawFramebuffer->isEnabledColorAttachment(i))
636 {
Geoff Langd8a22582014-12-17 15:28:23 -0500637 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400638 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400639
Geoff Langb2f3d052013-08-13 12:49:27 -0400640 // The GL ES 3.0.2 spec (pg 193) states that:
641 // 1) If the read buffer is fixed point format, the draw buffer must be as well
642 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
643 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400644 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
645 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 {
Geoff Langb1196682014-07-23 13:47:29 -0400647 context->recordError(Error(GL_INVALID_OPERATION));
648 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400649 }
650
Geoff Lang5d601382014-07-22 15:14:06 -0400651 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652 {
Geoff Langb1196682014-07-23 13:47:29 -0400653 context->recordError(Error(GL_INVALID_OPERATION));
654 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400655 }
656
Geoff Lang5d601382014-07-22 15:14:06 -0400657 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400658 {
Geoff Langb1196682014-07-23 13:47:29 -0400659 context->recordError(Error(GL_INVALID_OPERATION));
660 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661 }
662
Geoff Langb2f3d052013-08-13 12:49:27 -0400663 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400664 {
Geoff Langb1196682014-07-23 13:47:29 -0400665 context->recordError(Error(GL_INVALID_OPERATION));
666 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 }
668 }
669 }
670
Geoff Lang5d601382014-07-22 15:14:06 -0400671 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 {
Geoff Langb1196682014-07-23 13:47:29 -0400673 context->recordError(Error(GL_INVALID_OPERATION));
674 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 }
676
677 if (fromAngleExtension)
678 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -0400679 const FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500680 if (!readColorAttachment ||
Jamie Madill8cf4a392015-04-02 11:36:04 -0400681 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500682 readColorAttachment->type() != GL_RENDERBUFFER &&
683 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684 {
Geoff Langb1196682014-07-23 13:47:29 -0400685 context->recordError(Error(GL_INVALID_OPERATION));
686 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400687 }
688
Corentin Wallez37c39792015-08-20 14:19:46 -0400689 for (size_t colorAttachment = 0;
690 colorAttachment < drawFramebuffer->getNumColorBuffers(); ++colorAttachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400691 {
692 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
693 {
Jamie Madille3ef7152015-04-28 16:55:17 +0000694 const FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
Jamie Madille92a3542014-07-03 10:38:58 -0400695 ASSERT(attachment);
696
Jamie Madill8cf4a392015-04-02 11:36:04 -0400697 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex().type == GL_TEXTURE_2D) &&
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500698 attachment->type() != GL_RENDERBUFFER &&
699 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400700 {
Geoff Langb1196682014-07-23 13:47:29 -0400701 context->recordError(Error(GL_INVALID_OPERATION));
702 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703 }
704
Jamie Madillf8f18f02014-10-02 10:44:17 -0400705 // Return an error if the destination formats do not match
706 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400707 {
Geoff Langb1196682014-07-23 13:47:29 -0400708 context->recordError(Error(GL_INVALID_OPERATION));
709 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400710 }
711 }
712 }
Jamie Madill48faf802014-11-06 15:27:22 -0500713
714 int readSamples = readFramebuffer->getSamples(context->getData());
715
716 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
717 srcX0, srcY0, srcX1, srcY1,
718 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 {
Geoff Langb1196682014-07-23 13:47:29 -0400720 context->recordError(Error(GL_INVALID_OPERATION));
721 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400722 }
723 }
724 }
725 }
726
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200727 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
728 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
729 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400730 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200731 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 {
Jamie Madill2d06b732015-04-20 12:53:28 -0400733 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
734 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400735
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200736 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400737 {
Geoff Langd8a22582014-12-17 15:28:23 -0500738 if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400739 {
Geoff Langb1196682014-07-23 13:47:29 -0400740 context->recordError(Error(GL_INVALID_OPERATION));
741 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400742 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400743
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200744 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400745 {
Geoff Langb1196682014-07-23 13:47:29 -0400746 context->recordError(Error(GL_INVALID_OPERATION));
747 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400748 }
Dongseong Hwang44b422c2014-12-09 15:42:01 +0200749
750 if (fromAngleExtension)
751 {
752 if (IsPartialBlit(context, readBuffer, drawBuffer,
753 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
754 {
755 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
756 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
757 return false;
758 }
759
760 if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0)
761 {
762 context->recordError(Error(GL_INVALID_OPERATION));
763 return false;
764 }
765 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 }
767 }
768 }
769
770 return true;
771}
772
Geoff Langb1196682014-07-23 13:47:29 -0400773bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774{
775 switch (pname)
776 {
777 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
778 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
779 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
780 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
781 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
782 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
783 case GL_CURRENT_VERTEX_ATTRIB:
784 return true;
785
786 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
787 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
788 // the same constant.
Geoff Langd4475812015-03-18 10:53:05 -0400789 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
790 "ANGLE extension enums not equal to GL enums.");
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400791 return true;
792
793 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400794 if (context->getClientVersion() < 3)
795 {
796 context->recordError(Error(GL_INVALID_ENUM));
797 return false;
798 }
799 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800
801 default:
Geoff Langb1196682014-07-23 13:47:29 -0400802 context->recordError(Error(GL_INVALID_ENUM));
803 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400804 }
805}
806
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400807bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808{
809 switch (pname)
810 {
811 case GL_TEXTURE_WRAP_R:
812 case GL_TEXTURE_SWIZZLE_R:
813 case GL_TEXTURE_SWIZZLE_G:
814 case GL_TEXTURE_SWIZZLE_B:
815 case GL_TEXTURE_SWIZZLE_A:
816 case GL_TEXTURE_BASE_LEVEL:
817 case GL_TEXTURE_MAX_LEVEL:
818 case GL_TEXTURE_COMPARE_MODE:
819 case GL_TEXTURE_COMPARE_FUNC:
820 case GL_TEXTURE_MIN_LOD:
821 case GL_TEXTURE_MAX_LOD:
822 if (context->getClientVersion() < 3)
823 {
Geoff Langb1196682014-07-23 13:47:29 -0400824 context->recordError(Error(GL_INVALID_ENUM));
825 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400826 }
827 break;
828
829 default: break;
830 }
831
832 switch (pname)
833 {
834 case GL_TEXTURE_WRAP_S:
835 case GL_TEXTURE_WRAP_T:
836 case GL_TEXTURE_WRAP_R:
837 switch (param)
838 {
839 case GL_REPEAT:
840 case GL_CLAMP_TO_EDGE:
841 case GL_MIRRORED_REPEAT:
842 return true;
843 default:
Geoff Langb1196682014-07-23 13:47:29 -0400844 context->recordError(Error(GL_INVALID_ENUM));
845 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846 }
847
848 case GL_TEXTURE_MIN_FILTER:
849 switch (param)
850 {
851 case GL_NEAREST:
852 case GL_LINEAR:
853 case GL_NEAREST_MIPMAP_NEAREST:
854 case GL_LINEAR_MIPMAP_NEAREST:
855 case GL_NEAREST_MIPMAP_LINEAR:
856 case GL_LINEAR_MIPMAP_LINEAR:
857 return true;
858 default:
Geoff Langb1196682014-07-23 13:47:29 -0400859 context->recordError(Error(GL_INVALID_ENUM));
860 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400861 }
862 break;
863
864 case GL_TEXTURE_MAG_FILTER:
865 switch (param)
866 {
867 case GL_NEAREST:
868 case GL_LINEAR:
869 return true;
870 default:
Geoff Langb1196682014-07-23 13:47:29 -0400871 context->recordError(Error(GL_INVALID_ENUM));
872 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400873 }
874 break;
875
876 case GL_TEXTURE_USAGE_ANGLE:
877 switch (param)
878 {
879 case GL_NONE:
880 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
881 return true;
882 default:
Geoff Langb1196682014-07-23 13:47:29 -0400883 context->recordError(Error(GL_INVALID_ENUM));
884 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400885 }
886 break;
887
888 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400889 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 {
Geoff Langb1196682014-07-23 13:47:29 -0400891 context->recordError(Error(GL_INVALID_ENUM));
892 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400893 }
894
895 // we assume the parameter passed to this validation method is truncated, not rounded
896 if (param < 1)
897 {
Geoff Langb1196682014-07-23 13:47:29 -0400898 context->recordError(Error(GL_INVALID_VALUE));
899 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400900 }
901 return true;
902
903 case GL_TEXTURE_MIN_LOD:
904 case GL_TEXTURE_MAX_LOD:
905 // any value is permissible
906 return true;
907
908 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400909 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400910 switch (param)
911 {
912 case GL_NONE:
913 case GL_COMPARE_REF_TO_TEXTURE:
914 return true;
915 default:
Geoff Langb1196682014-07-23 13:47:29 -0400916 context->recordError(Error(GL_INVALID_ENUM));
917 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400918 }
919 break;
920
921 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400922 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400923 switch (param)
924 {
925 case GL_LEQUAL:
926 case GL_GEQUAL:
927 case GL_LESS:
928 case GL_GREATER:
929 case GL_EQUAL:
930 case GL_NOTEQUAL:
931 case GL_ALWAYS:
932 case GL_NEVER:
933 return true;
934 default:
Geoff Langb1196682014-07-23 13:47:29 -0400935 context->recordError(Error(GL_INVALID_ENUM));
936 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400937 }
938 break;
939
940 case GL_TEXTURE_SWIZZLE_R:
941 case GL_TEXTURE_SWIZZLE_G:
942 case GL_TEXTURE_SWIZZLE_B:
943 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400944 switch (param)
945 {
946 case GL_RED:
947 case GL_GREEN:
948 case GL_BLUE:
949 case GL_ALPHA:
950 case GL_ZERO:
951 case GL_ONE:
952 return true;
953 default:
Geoff Langb1196682014-07-23 13:47:29 -0400954 context->recordError(Error(GL_INVALID_ENUM));
955 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400956 }
957 break;
958
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400959 case GL_TEXTURE_BASE_LEVEL:
960 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400961 if (param < 0)
962 {
Geoff Langb1196682014-07-23 13:47:29 -0400963 context->recordError(Error(GL_INVALID_VALUE));
964 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400965 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400966 return true;
967
968 default:
Geoff Langb1196682014-07-23 13:47:29 -0400969 context->recordError(Error(GL_INVALID_ENUM));
970 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400971 }
972}
973
Geoff Langb1196682014-07-23 13:47:29 -0400974bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400975{
976 switch (pname)
977 {
978 case GL_TEXTURE_MIN_FILTER:
979 case GL_TEXTURE_MAG_FILTER:
980 case GL_TEXTURE_WRAP_S:
981 case GL_TEXTURE_WRAP_T:
982 case GL_TEXTURE_WRAP_R:
983 case GL_TEXTURE_MIN_LOD:
984 case GL_TEXTURE_MAX_LOD:
985 case GL_TEXTURE_COMPARE_MODE:
986 case GL_TEXTURE_COMPARE_FUNC:
987 return true;
988
989 default:
Geoff Langb1196682014-07-23 13:47:29 -0400990 context->recordError(Error(GL_INVALID_ENUM));
991 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400992 }
993}
994
Jamie Madill26e91952014-03-05 15:01:27 -0500995bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
996 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
997{
Shannon Woods53a94a82014-06-24 15:20:36 -0400998 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400999 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -05001000
Geoff Lang748f74e2014-12-01 11:25:34 -05001001 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -05001002 {
Geoff Langb1196682014-07-23 13:47:29 -04001003 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1004 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001005 }
1006
Jamie Madill48faf802014-11-06 15:27:22 -05001007 if (context->getState().getReadFramebuffer()->id() != 0 &&
1008 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -05001009 {
Geoff Langb1196682014-07-23 13:47:29 -04001010 context->recordError(Error(GL_INVALID_OPERATION));
1011 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001012 }
1013
Geoff Langbce529e2014-12-01 12:48:41 -05001014 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
1015 if (!readBuffer)
Jamie Madill893ab082014-05-16 16:56:10 -04001016 {
Geoff Langb1196682014-07-23 13:47:29 -04001017 context->recordError(Error(GL_INVALID_OPERATION));
1018 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001019 }
1020
Geoff Langbce529e2014-12-01 12:48:41 -05001021 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
1022 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langd8a22582014-12-17 15:28:23 -05001023 GLenum currentInternalFormat = readBuffer->getInternalFormat();
Geoff Lange4a492b2014-06-19 14:14:41 -04001024 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -05001025
Geoff Langbdc9b2f2014-04-16 14:41:54 -04001026 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
1027 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -05001028
1029 if (!(currentFormat == format && currentType == type) && !validReadFormat)
1030 {
Geoff Langb1196682014-07-23 13:47:29 -04001031 context->recordError(Error(GL_INVALID_OPERATION));
1032 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001033 }
1034
Geoff Lang5d601382014-07-22 15:14:06 -04001035 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
1036 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -05001037
Minmin Gongb8aee3b2015-01-27 14:42:36 -08001038 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0);
Jamie Madill26e91952014-03-05 15:01:27 -05001039 // sized query sanity check
1040 if (bufSize)
1041 {
1042 int requiredSize = outputPitch * height;
1043 if (requiredSize > *bufSize)
1044 {
Geoff Langb1196682014-07-23 13:47:29 -04001045 context->recordError(Error(GL_INVALID_OPERATION));
1046 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001047 }
1048 }
1049
1050 return true;
1051}
1052
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001053bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
1054{
1055 if (!ValidQueryType(context, target))
1056 {
Geoff Langb1196682014-07-23 13:47:29 -04001057 context->recordError(Error(GL_INVALID_ENUM));
1058 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001059 }
1060
1061 if (id == 0)
1062 {
Geoff Langb1196682014-07-23 13:47:29 -04001063 context->recordError(Error(GL_INVALID_OPERATION));
1064 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001065 }
1066
1067 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1068 // of zero, if the active query object name for <target> is non-zero (for the
1069 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1070 // the active query for either target is non-zero), if <id> is the name of an
1071 // existing query object whose type does not match <target>, or if <id> is the
1072 // active query object name for any query type, the error INVALID_OPERATION is
1073 // generated.
1074
1075 // Ensure no other queries are active
1076 // NOTE: If other queries than occlusion are supported, we will need to check
1077 // separately that:
1078 // a) The query ID passed is not the current active query for any target/type
1079 // b) There are no active queries for the requested target (and in the case
1080 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1081 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001082 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001083 {
Geoff Langb1196682014-07-23 13:47:29 -04001084 context->recordError(Error(GL_INVALID_OPERATION));
1085 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001086 }
1087
1088 Query *queryObject = context->getQuery(id, true, target);
1089
1090 // check that name was obtained with glGenQueries
1091 if (!queryObject)
1092 {
Geoff Langb1196682014-07-23 13:47:29 -04001093 context->recordError(Error(GL_INVALID_OPERATION));
1094 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001095 }
1096
1097 // check for type mismatch
1098 if (queryObject->getType() != target)
1099 {
Geoff Langb1196682014-07-23 13:47:29 -04001100 context->recordError(Error(GL_INVALID_OPERATION));
1101 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001102 }
1103
1104 return true;
1105}
1106
Jamie Madill45c785d2014-05-13 14:09:34 -04001107bool ValidateEndQuery(gl::Context *context, GLenum target)
1108{
1109 if (!ValidQueryType(context, target))
1110 {
Geoff Langb1196682014-07-23 13:47:29 -04001111 context->recordError(Error(GL_INVALID_ENUM));
1112 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001113 }
1114
Shannon Woods53a94a82014-06-24 15:20:36 -04001115 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001116
1117 if (queryObject == NULL)
1118 {
Geoff Langb1196682014-07-23 13:47:29 -04001119 context->recordError(Error(GL_INVALID_OPERATION));
1120 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001121 }
1122
Jamie Madill45c785d2014-05-13 14:09:34 -04001123 return true;
1124}
1125
Jamie Madill61b8dd92015-09-09 19:04:04 +00001126static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1127 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001128{
1129 if (count < 0)
1130 {
Geoff Langb1196682014-07-23 13:47:29 -04001131 context->recordError(Error(GL_INVALID_VALUE));
1132 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001133 }
1134
Geoff Lang7dd2e102014-11-10 15:19:26 -05001135 gl::Program *program = context->getState().getProgram();
1136 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001137 {
Geoff Langb1196682014-07-23 13:47:29 -04001138 context->recordError(Error(GL_INVALID_OPERATION));
1139 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001140 }
1141
1142 if (location == -1)
1143 {
1144 // Silently ignore the uniform command
1145 return false;
1146 }
1147
Geoff Lang7dd2e102014-11-10 15:19:26 -05001148 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001149 {
Geoff Langb1196682014-07-23 13:47:29 -04001150 context->recordError(Error(GL_INVALID_OPERATION));
1151 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001152 }
1153
Jamie Madill61b8dd92015-09-09 19:04:04 +00001154 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001155
1156 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill61b8dd92015-09-09 19:04:04 +00001157 if (!uniform->isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001158 {
Geoff Langb1196682014-07-23 13:47:29 -04001159 context->recordError(Error(GL_INVALID_OPERATION));
1160 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001161 }
1162
Jamie Madill61b8dd92015-09-09 19:04:04 +00001163 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001164 return true;
1165}
1166
Jamie Madillaa981bd2014-05-20 10:55:55 -04001167bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1168{
1169 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001170 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001171 {
Geoff Langb1196682014-07-23 13:47:29 -04001172 context->recordError(Error(GL_INVALID_OPERATION));
1173 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001174 }
1175
Jamie Madill61b8dd92015-09-09 19:04:04 +00001176 LinkedUniform *uniform = NULL;
Jamie Madill36398922014-05-20 14:51:53 -04001177 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1178 {
1179 return false;
1180 }
1181
Jamie Madillf2575982014-06-25 16:04:54 -04001182 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001183 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001184 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1185 {
Geoff Langb1196682014-07-23 13:47:29 -04001186 context->recordError(Error(GL_INVALID_OPERATION));
1187 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001188 }
1189
1190 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001191}
1192
1193bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1194 GLboolean transpose)
1195{
1196 // Check for ES3 uniform entry points
1197 int rows = VariableRowCount(matrixType);
1198 int cols = VariableColumnCount(matrixType);
1199 if (rows != cols && context->getClientVersion() < 3)
1200 {
Geoff Langb1196682014-07-23 13:47:29 -04001201 context->recordError(Error(GL_INVALID_OPERATION));
1202 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001203 }
1204
1205 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1206 {
Geoff Langb1196682014-07-23 13:47:29 -04001207 context->recordError(Error(GL_INVALID_VALUE));
1208 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001209 }
1210
Jamie Madill61b8dd92015-09-09 19:04:04 +00001211 LinkedUniform *uniform = NULL;
Jamie Madill36398922014-05-20 14:51:53 -04001212 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1213 {
1214 return false;
1215 }
1216
1217 if (uniform->type != matrixType)
1218 {
Geoff Langb1196682014-07-23 13:47:29 -04001219 context->recordError(Error(GL_INVALID_OPERATION));
1220 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001221 }
1222
1223 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001224}
1225
Jamie Madill893ab082014-05-16 16:56:10 -04001226bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1227{
1228 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1229 {
Geoff Langb1196682014-07-23 13:47:29 -04001230 context->recordError(Error(GL_INVALID_ENUM));
1231 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001232 }
1233
Jamie Madill0af26e12015-03-05 19:54:33 -05001234 const Caps &caps = context->getCaps();
1235
Jamie Madill893ab082014-05-16 16:56:10 -04001236 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1237 {
1238 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1239
Jamie Madill0af26e12015-03-05 19:54:33 -05001240 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001241 {
Geoff Langb1196682014-07-23 13:47:29 -04001242 context->recordError(Error(GL_INVALID_OPERATION));
1243 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001244 }
1245 }
1246
1247 switch (pname)
1248 {
1249 case GL_TEXTURE_BINDING_2D:
1250 case GL_TEXTURE_BINDING_CUBE_MAP:
1251 case GL_TEXTURE_BINDING_3D:
1252 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill0af26e12015-03-05 19:54:33 -05001253 if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001254 {
Geoff Langb1196682014-07-23 13:47:29 -04001255 context->recordError(Error(GL_INVALID_OPERATION));
1256 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001257 }
1258 break;
1259
1260 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1261 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1262 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001263 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001264 ASSERT(framebuffer);
Geoff Lang748f74e2014-12-01 11:25:34 -05001265 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001266 {
Geoff Langb1196682014-07-23 13:47:29 -04001267 context->recordError(Error(GL_INVALID_OPERATION));
1268 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001269 }
1270
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001271 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001272 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001273 {
Geoff Langb1196682014-07-23 13:47:29 -04001274 context->recordError(Error(GL_INVALID_OPERATION));
1275 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001276 }
1277 }
1278 break;
1279
1280 default:
1281 break;
1282 }
1283
1284 // pname is valid, but there are no parameters to return
1285 if (numParams == 0)
1286 {
1287 return false;
1288 }
1289
1290 return true;
1291}
1292
Geoff Lang831b1952015-05-05 11:02:27 -04001293bool ValidateCopyTexImageParametersBase(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
Jamie Madill560a8d82014-05-21 13:06:20 -04001294 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1295 GLint border, GLenum *textureFormatOut)
1296{
1297
1298 if (!ValidTexture2DDestinationTarget(context, target))
1299 {
Geoff Langb1196682014-07-23 13:47:29 -04001300 context->recordError(Error(GL_INVALID_ENUM));
1301 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001302 }
1303
1304 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1305 {
Geoff Langb1196682014-07-23 13:47:29 -04001306 context->recordError(Error(GL_INVALID_VALUE));
1307 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001308 }
1309
1310 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1311 {
Geoff Langb1196682014-07-23 13:47:29 -04001312 context->recordError(Error(GL_INVALID_VALUE));
1313 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001314 }
1315
1316 if (border != 0)
1317 {
Geoff Langb1196682014-07-23 13:47:29 -04001318 context->recordError(Error(GL_INVALID_VALUE));
1319 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001320 }
1321
1322 if (!ValidMipLevel(context, target, level))
1323 {
Geoff Langb1196682014-07-23 13:47:29 -04001324 context->recordError(Error(GL_INVALID_VALUE));
1325 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001326 }
1327
Shannon Woods53a94a82014-06-24 15:20:36 -04001328 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001329 if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001330 {
Geoff Langb1196682014-07-23 13:47:29 -04001331 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1332 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001333 }
1334
Jamie Madill48faf802014-11-06 15:27:22 -05001335 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
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
Geoff Langaae65a42014-05-26 12:43:44 -04001341 const gl::Caps &caps = context->getCaps();
1342
Geoff Langaae65a42014-05-26 12:43:44 -04001343 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001344 switch (target)
1345 {
1346 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001347 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001348 break;
1349
1350 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1351 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1352 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1353 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1354 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1355 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001356 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 break;
1358
1359 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001360 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001361 break;
1362
1363 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05001364 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001365 break;
1366
1367 default:
Geoff Langb1196682014-07-23 13:47:29 -04001368 context->recordError(Error(GL_INVALID_ENUM));
1369 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001370 }
1371
Geoff Lang691e58c2014-12-19 17:03:25 -05001372 gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04001373 if (!texture)
1374 {
Geoff Langb1196682014-07-23 13:47:29 -04001375 context->recordError(Error(GL_INVALID_OPERATION));
1376 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001377 }
1378
1379 if (texture->isImmutable() && !isSubImage)
1380 {
Geoff Langb1196682014-07-23 13:47:29 -04001381 context->recordError(Error(GL_INVALID_OPERATION));
1382 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001383 }
1384
Geoff Lang5d601382014-07-22 15:14:06 -04001385 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1386
1387 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001388 {
Geoff Langb1196682014-07-23 13:47:29 -04001389 context->recordError(Error(GL_INVALID_OPERATION));
1390 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001391 }
1392
Geoff Langa9be0dc2014-12-17 12:34:40 -05001393 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04001394 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001395 context->recordError(Error(GL_INVALID_OPERATION));
1396 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001397 }
1398
1399 if (isSubImage)
1400 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05001401 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
1402 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
1403 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04001404 {
Geoff Langb1196682014-07-23 13:47:29 -04001405 context->recordError(Error(GL_INVALID_VALUE));
1406 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001407 }
1408 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001409 else
1410 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001411 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04001412 {
Geoff Langb1196682014-07-23 13:47:29 -04001413 context->recordError(Error(GL_INVALID_VALUE));
1414 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001415 }
1416
Geoff Lang5d601382014-07-22 15:14:06 -04001417 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001418 {
Geoff Langb1196682014-07-23 13:47:29 -04001419 context->recordError(Error(GL_INVALID_ENUM));
1420 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001421 }
1422
1423 int maxLevelDimension = (maxDimension >> level);
1424 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1425 {
Geoff Langb1196682014-07-23 13:47:29 -04001426 context->recordError(Error(GL_INVALID_VALUE));
1427 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001428 }
1429 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001430
Geoff Langa9be0dc2014-12-17 12:34:40 -05001431 *textureFormatOut = texture->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001432 return true;
1433}
1434
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001435static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001436{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001437 switch (mode)
1438 {
1439 case GL_POINTS:
1440 case GL_LINES:
1441 case GL_LINE_LOOP:
1442 case GL_LINE_STRIP:
1443 case GL_TRIANGLES:
1444 case GL_TRIANGLE_STRIP:
1445 case GL_TRIANGLE_FAN:
1446 break;
1447 default:
Geoff Langb1196682014-07-23 13:47:29 -04001448 context->recordError(Error(GL_INVALID_ENUM));
1449 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001450 }
1451
Jamie Madill250d33f2014-06-06 17:09:03 -04001452 if (count < 0)
1453 {
Geoff Langb1196682014-07-23 13:47:29 -04001454 context->recordError(Error(GL_INVALID_VALUE));
1455 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001456 }
1457
Geoff Langb1196682014-07-23 13:47:29 -04001458 const State &state = context->getState();
1459
Jamie Madill250d33f2014-06-06 17:09:03 -04001460 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001461 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001462 {
Geoff Langb1196682014-07-23 13:47:29 -04001463 context->recordError(Error(GL_INVALID_OPERATION));
1464 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001465 }
1466
Geoff Lang3a86ad32015-09-01 11:47:05 -04001467 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04001468 {
Geoff Lang3a86ad32015-09-01 11:47:05 -04001469 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
1470 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1471 state.getStencilRef() != state.getStencilBackRef() ||
1472 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1473 {
1474 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
1475 // Section 6.10 of the WebGL 1.0 spec
1476 ERR(
1477 "This ANGLE implementation does not support separate front/back stencil "
1478 "writemasks, reference values, or stencil mask values.");
1479 context->recordError(Error(GL_INVALID_OPERATION));
1480 return false;
1481 }
Jamie Madillac528012014-06-20 13:21:23 -04001482 }
1483
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001484 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Geoff Lang748f74e2014-12-01 11:25:34 -05001485 if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001486 {
Geoff Langb1196682014-07-23 13:47:29 -04001487 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1488 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001489 }
1490
Geoff Lang7dd2e102014-11-10 15:19:26 -05001491 gl::Program *program = state.getProgram();
1492 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001493 {
Geoff Langb1196682014-07-23 13:47:29 -04001494 context->recordError(Error(GL_INVALID_OPERATION));
1495 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001496 }
1497
Geoff Lang7dd2e102014-11-10 15:19:26 -05001498 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001499 {
Geoff Langb1196682014-07-23 13:47:29 -04001500 context->recordError(Error(GL_INVALID_OPERATION));
1501 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001502 }
1503
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001504 // Uniform buffer validation
1505 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
1506 {
Jamie Madill61b8dd92015-09-09 19:04:04 +00001507 const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001508 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
1509 const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding);
1510
1511 if (!uniformBuffer)
1512 {
1513 // undefined behaviour
1514 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."));
1515 return false;
1516 }
1517
1518 size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding);
1519
1520 if (uniformBufferSize == 0)
1521 {
1522 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07001523 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001524 }
1525
Jamie Madill61b8dd92015-09-09 19:04:04 +00001526 if (uniformBufferSize < uniformBlock->dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00001527 {
1528 // undefined behaviour
1529 context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."));
1530 return false;
1531 }
1532 }
1533
Jamie Madill250d33f2014-06-06 17:09:03 -04001534 // No-op if zero count
1535 return (count > 0);
1536}
1537
Geoff Langb1196682014-07-23 13:47:29 -04001538bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001539{
Jamie Madillfd716582014-06-06 17:09:04 -04001540 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001541 {
Geoff Langb1196682014-07-23 13:47:29 -04001542 context->recordError(Error(GL_INVALID_VALUE));
1543 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001544 }
1545
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001546 const State &state = context->getState();
1547 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001548 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
1549 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04001550 {
1551 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1552 // that does not match the current transform feedback object's draw mode (if transform feedback
1553 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001554 context->recordError(Error(GL_INVALID_OPERATION));
1555 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001556 }
1557
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001558 if (!ValidateDrawBase(context, mode, count, primcount))
1559 {
1560 return false;
1561 }
1562
1563 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001564 {
1565 return false;
1566 }
1567
1568 return true;
1569}
1570
Geoff Langb1196682014-07-23 13:47:29 -04001571bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001572{
1573 if (primcount < 0)
1574 {
Geoff Langb1196682014-07-23 13:47:29 -04001575 context->recordError(Error(GL_INVALID_VALUE));
1576 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001577 }
1578
Jamie Madill2b976812014-08-25 15:47:49 -04001579 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001580 {
1581 return false;
1582 }
1583
1584 // No-op if zero primitive count
1585 return (primcount > 0);
1586}
1587
Geoff Lang87a93302014-09-16 13:29:43 -04001588static bool ValidateDrawInstancedANGLE(Context *context)
1589{
1590 // Verify there is at least one active attribute with a divisor of zero
1591 const gl::State& state = context->getState();
1592
Geoff Lang7dd2e102014-11-10 15:19:26 -05001593 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001594
1595 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04001596 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04001597 {
1598 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04001599 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04001600 {
1601 return true;
1602 }
1603 }
1604
1605 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1606 "has a divisor of zero."));
1607 return false;
1608}
1609
1610bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1611{
1612 if (!ValidateDrawInstancedANGLE(context))
1613 {
1614 return false;
1615 }
1616
1617 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1618}
1619
Geoff Langb1196682014-07-23 13:47:29 -04001620bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001621 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001622{
Jamie Madill250d33f2014-06-06 17:09:03 -04001623 switch (type)
1624 {
1625 case GL_UNSIGNED_BYTE:
1626 case GL_UNSIGNED_SHORT:
1627 break;
1628 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001629 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001630 {
Geoff Langb1196682014-07-23 13:47:29 -04001631 context->recordError(Error(GL_INVALID_ENUM));
1632 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001633 }
1634 break;
1635 default:
Geoff Langb1196682014-07-23 13:47:29 -04001636 context->recordError(Error(GL_INVALID_ENUM));
1637 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001638 }
1639
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001640 const State &state = context->getState();
1641
1642 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04001643 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04001644 {
1645 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1646 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_INVALID_OPERATION));
1648 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001649 }
1650
1651 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001652 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001653 {
Geoff Langb1196682014-07-23 13:47:29 -04001654 context->recordError(Error(GL_INVALID_OPERATION));
1655 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001656 }
1657
Jamie Madill2b976812014-08-25 15:47:49 -04001658 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04001659 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04001660 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001661 {
Geoff Langb1196682014-07-23 13:47:29 -04001662 context->recordError(Error(GL_INVALID_OPERATION));
1663 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001664 }
1665
Jamie Madillae3000b2014-08-25 15:47:51 -04001666 if (elementArrayBuffer)
1667 {
1668 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1669
1670 GLint64 offset = reinterpret_cast<GLint64>(indices);
1671 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1672
1673 // check for integer overflows
1674 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1675 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1676 {
Geoff Langb1196682014-07-23 13:47:29 -04001677 context->recordError(Error(GL_OUT_OF_MEMORY));
1678 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001679 }
1680
1681 // Check for reading past the end of the bound buffer object
1682 if (byteCount > elementArrayBuffer->getSize())
1683 {
Geoff Langb1196682014-07-23 13:47:29 -04001684 context->recordError(Error(GL_INVALID_OPERATION));
1685 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001686 }
1687 }
1688 else if (!indices)
1689 {
1690 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001691 context->recordError(Error(GL_INVALID_OPERATION));
1692 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001693 }
1694
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001695 if (!ValidateDrawBase(context, mode, count, primcount))
1696 {
1697 return false;
1698 }
1699
Jamie Madill2b976812014-08-25 15:47:49 -04001700 // Use max index to validate if our vertex buffers are large enough for the pull.
1701 // TODO: offer fast path, with disabled index validation.
1702 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1703 if (elementArrayBuffer)
1704 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001705 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang520c4ae2015-05-05 13:12:36 -04001706 Error error = elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count, indexRangeOut);
1707 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04001708 {
Geoff Lang520c4ae2015-05-05 13:12:36 -04001709 context->recordError(error);
1710 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001711 }
1712 }
1713 else
1714 {
Geoff Lang831b1952015-05-05 11:02:27 -04001715 *indexRangeOut = ComputeIndexRange(type, indices, count);
Jamie Madill2b976812014-08-25 15:47:49 -04001716 }
1717
Corentin Wallez18a2fb32015-08-10 12:58:14 -07001718 if (!ValidateDrawAttribs(context, primcount, static_cast<GLsizei>(indexRangeOut->end)))
Jamie Madillfd716582014-06-06 17:09:04 -04001719 {
1720 return false;
1721 }
1722
1723 return true;
1724}
1725
Geoff Langb1196682014-07-23 13:47:29 -04001726bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001727 GLenum mode, GLsizei count, GLenum type,
1728 const GLvoid *indices, GLsizei primcount,
Geoff Lang831b1952015-05-05 11:02:27 -04001729 RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001730{
1731 if (primcount < 0)
1732 {
Geoff Langb1196682014-07-23 13:47:29 -04001733 context->recordError(Error(GL_INVALID_VALUE));
1734 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001735 }
1736
Jamie Madill2b976812014-08-25 15:47:49 -04001737 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001738 {
1739 return false;
1740 }
1741
1742 // No-op zero primitive count
1743 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001744}
1745
Geoff Lang87a93302014-09-16 13:29:43 -04001746bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
Geoff Lang831b1952015-05-05 11:02:27 -04001747 const GLvoid *indices, GLsizei primcount, RangeUI *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04001748{
1749 if (!ValidateDrawInstancedANGLE(context))
1750 {
1751 return false;
1752 }
1753
1754 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1755}
1756
Geoff Langb1196682014-07-23 13:47:29 -04001757bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001758 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001759{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001760 if (!ValidFramebufferTarget(target))
1761 {
Geoff Langb1196682014-07-23 13:47:29 -04001762 context->recordError(Error(GL_INVALID_ENUM));
1763 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001764 }
1765
1766 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001767 {
1768 return false;
1769 }
1770
Jamie Madill55ec3b12014-07-03 10:38:57 -04001771 if (texture != 0)
1772 {
1773 gl::Texture *tex = context->getTexture(texture);
1774
1775 if (tex == NULL)
1776 {
Geoff Langb1196682014-07-23 13:47:29 -04001777 context->recordError(Error(GL_INVALID_OPERATION));
1778 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001779 }
1780
1781 if (level < 0)
1782 {
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 }
1787
Shannon Woods53a94a82014-06-24 15:20:36 -04001788 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04001789 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04001790
Jamie Madill84115c92015-04-23 15:00:07 -04001791 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001792 {
Jamie Madill84115c92015-04-23 15:00:07 -04001793 context->recordError(Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001794 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001795 }
1796
1797 return true;
1798}
1799
Geoff Langb1196682014-07-23 13:47:29 -04001800bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001801 GLenum textarget, GLuint texture, GLint level)
1802{
Geoff Lang95663912015-04-02 15:54:45 -04001803 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
1804 if (context->getClientVersion() < 3 && !context->getExtensions().fboRenderMipmap && level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04001805 {
Geoff Langb1196682014-07-23 13:47:29 -04001806 context->recordError(Error(GL_INVALID_VALUE));
1807 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001808 }
1809
1810 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001811 {
1812 return false;
1813 }
1814
Jamie Madill55ec3b12014-07-03 10:38:57 -04001815 if (texture != 0)
1816 {
1817 gl::Texture *tex = context->getTexture(texture);
1818 ASSERT(tex);
1819
Jamie Madill2a6564e2014-07-11 09:53:19 -04001820 const gl::Caps &caps = context->getCaps();
1821
Jamie Madill55ec3b12014-07-03 10:38:57 -04001822 switch (textarget)
1823 {
1824 case GL_TEXTURE_2D:
1825 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001826 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001827 {
Geoff Langb1196682014-07-23 13:47:29 -04001828 context->recordError(Error(GL_INVALID_VALUE));
1829 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001830 }
1831 if (tex->getTarget() != GL_TEXTURE_2D)
1832 {
Geoff Langb1196682014-07-23 13:47:29 -04001833 context->recordError(Error(GL_INVALID_OPERATION));
1834 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001835 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001836 }
1837 break;
1838
1839 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1840 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1841 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1842 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1843 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1844 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1845 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001846 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001847 {
Geoff Langb1196682014-07-23 13:47:29 -04001848 context->recordError(Error(GL_INVALID_VALUE));
1849 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001850 }
1851 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1852 {
Geoff Langb1196682014-07-23 13:47:29 -04001853 context->recordError(Error(GL_INVALID_OPERATION));
1854 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001855 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001856 }
1857 break;
1858
1859 default:
Geoff Langb1196682014-07-23 13:47:29 -04001860 context->recordError(Error(GL_INVALID_ENUM));
1861 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001862 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05001863
1864 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level));
1865 if (internalFormatInfo.compressed)
1866 {
1867 context->recordError(Error(GL_INVALID_OPERATION));
1868 return false;
1869 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04001870 }
1871
Jamie Madill570f7c82014-07-03 10:38:54 -04001872 return true;
1873}
1874
Geoff Langb1196682014-07-23 13:47:29 -04001875bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001876{
1877 if (program == 0)
1878 {
Geoff Langb1196682014-07-23 13:47:29 -04001879 context->recordError(Error(GL_INVALID_VALUE));
1880 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001881 }
1882
Shannon Woods4de4fd62014-11-07 16:22:02 -05001883 if (!ValidProgram(context, program))
1884 {
1885 return false;
1886 }
1887
Jamie Madill0063c512014-08-25 15:47:53 -04001888 gl::Program *programObject = context->getProgram(program);
1889
1890 if (!programObject || !programObject->isLinked())
1891 {
Geoff Langb1196682014-07-23 13:47:29 -04001892 context->recordError(Error(GL_INVALID_OPERATION));
1893 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001894 }
1895
Geoff Lang7dd2e102014-11-10 15:19:26 -05001896 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001897 {
Geoff Langb1196682014-07-23 13:47:29 -04001898 context->recordError(Error(GL_INVALID_OPERATION));
1899 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001900 }
1901
Jamie Madill0063c512014-08-25 15:47:53 -04001902 return true;
1903}
1904
Geoff Langb1196682014-07-23 13:47:29 -04001905bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001906{
1907 return ValidateGetUniformBase(context, program, location);
1908}
1909
Geoff Langb1196682014-07-23 13:47:29 -04001910bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001911{
Jamie Madill78f41802014-08-25 15:47:55 -04001912 return ValidateGetUniformBase(context, program, location);
1913}
1914
Geoff Langb1196682014-07-23 13:47:29 -04001915static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001916{
1917 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001918 {
Jamie Madill78f41802014-08-25 15:47:55 -04001919 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001920 }
1921
Jamie Madilla502c742014-08-28 17:19:13 -04001922 gl::Program *programObject = context->getProgram(program);
1923 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001924
Jamie Madill78f41802014-08-25 15:47:55 -04001925 // sized queries -- ensure the provided buffer is large enough
Jamie Madill61b8dd92015-09-09 19:04:04 +00001926 LinkedUniform *uniform = programObject->getUniformByLocation(location);
1927 size_t requiredBytes = VariableExternalSize(uniform->type);
Jamie Madill78f41802014-08-25 15:47:55 -04001928 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001929 {
Geoff Langb1196682014-07-23 13:47:29 -04001930 context->recordError(Error(GL_INVALID_OPERATION));
1931 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001932 }
1933
1934 return true;
1935}
1936
Geoff Langb1196682014-07-23 13:47:29 -04001937bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001938{
Jamie Madill78f41802014-08-25 15:47:55 -04001939 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001940}
1941
Geoff Langb1196682014-07-23 13:47:29 -04001942bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001943{
Jamie Madill78f41802014-08-25 15:47:55 -04001944 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001945}
1946
Austin Kinross08332632015-05-05 13:35:47 -07001947bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
1948 const GLenum *attachments, bool defaultFramebuffer)
1949{
1950 if (numAttachments < 0)
1951 {
1952 context->recordError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
1953 return false;
1954 }
1955
1956 for (GLsizei i = 0; i < numAttachments; ++i)
1957 {
1958 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
1959 {
1960 if (defaultFramebuffer)
1961 {
1962 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1963 return false;
1964 }
1965
1966 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
1967 {
1968 context->recordError(Error(GL_INVALID_OPERATION,
1969 "Requested color attachment is greater than the maximum supported color attachments"));
1970 return false;
1971 }
1972 }
1973 else
1974 {
1975 switch (attachments[i])
1976 {
1977 case GL_DEPTH_ATTACHMENT:
1978 case GL_STENCIL_ATTACHMENT:
1979 case GL_DEPTH_STENCIL_ATTACHMENT:
1980 if (defaultFramebuffer)
1981 {
1982 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
1983 return false;
1984 }
1985 break;
1986 case GL_COLOR:
1987 case GL_DEPTH:
1988 case GL_STENCIL:
1989 if (!defaultFramebuffer)
1990 {
1991 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is not bound"));
1992 return false;
1993 }
1994 break;
1995 default:
1996 context->recordError(Error(GL_INVALID_ENUM, "Invalid attachment"));
1997 return false;
1998 }
1999 }
2000 }
2001
2002 return true;
2003}
2004
Austin Kinross6ee1e782015-05-29 17:05:37 -07002005bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2006{
2007 // Note that debug marker calls must not set error state
2008
2009 if (length < 0)
2010 {
2011 return false;
2012 }
2013
2014 if (marker == nullptr)
2015 {
2016 return false;
2017 }
2018
2019 return true;
2020}
2021
2022bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2023{
2024 // Note that debug marker calls must not set error state
2025
2026 if (length < 0)
2027 {
2028 return false;
2029 }
2030
2031 if (length > 0 && marker == nullptr)
2032 {
2033 return false;
2034 }
2035
2036 return true;
2037}
2038
Geoff Langdcab33b2015-07-21 13:03:16 -04002039bool ValidateEGLImageTargetTexture2DOES(Context *context,
2040 egl::Display *display,
2041 GLenum target,
2042 egl::Image *image)
2043{
Geoff Langa8406172015-07-21 16:53:39 -04002044 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2045 {
2046 context->recordError(Error(GL_INVALID_OPERATION));
2047 return false;
2048 }
2049
2050 switch (target)
2051 {
2052 case GL_TEXTURE_2D:
2053 break;
2054
2055 default:
2056 context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
2057 return false;
2058 }
2059
2060 if (!display->isValidImage(image))
2061 {
2062 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2063 return false;
2064 }
2065
2066 if (image->getSamples() > 0)
2067 {
2068 context->recordError(Error(GL_INVALID_OPERATION,
2069 "cannot create a 2D texture from a multisampled EGL image."));
2070 return false;
2071 }
2072
2073 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2074 if (!textureCaps.texturable)
2075 {
2076 context->recordError(Error(GL_INVALID_OPERATION,
2077 "EGL image internal format is not supported as a texture."));
2078 return false;
2079 }
2080
Geoff Langdcab33b2015-07-21 13:03:16 -04002081 return true;
2082}
2083
2084bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2085 egl::Display *display,
2086 GLenum target,
2087 egl::Image *image)
2088{
Geoff Langa8406172015-07-21 16:53:39 -04002089 if (!context->getExtensions().eglImage)
2090 {
2091 context->recordError(Error(GL_INVALID_OPERATION));
2092 return false;
2093 }
2094
2095 switch (target)
2096 {
2097 case GL_RENDERBUFFER:
2098 break;
2099
2100 default:
2101 context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
2102 return false;
2103 }
2104
2105 if (!display->isValidImage(image))
2106 {
2107 context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
2108 return false;
2109 }
2110
2111 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
2112 if (!textureCaps.renderable)
2113 {
2114 context->recordError(Error(
2115 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2116 return false;
2117 }
2118
Geoff Langdcab33b2015-07-21 13:03:16 -04002119 return true;
2120}
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002121}