blob: 7310112e6a0901e4f979592a89f14d1146fe1d13 [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"
Jamie Madille2e406c2016-06-02 13:04:10 -040010
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/validationES2.h"
12#include "libANGLE/validationES3.h"
13#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040014#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/Texture.h"
16#include "libANGLE/Framebuffer.h"
17#include "libANGLE/FramebufferAttachment.h"
18#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040019#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/Program.h"
22#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050023#include "libANGLE/TransformFeedback.h"
24#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025
26#include "common/mathutil.h"
27#include "common/utilities.h"
28
Jamie Madille2e406c2016-06-02 13:04:10 -040029using namespace angle;
30
Geoff Lange8ebe7f2013-08-05 15:03:13 -040031namespace gl
32{
Jamie Madille79b1e12015-11-04 16:36:37 -050033const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
34
Jamie Madill1ca74672015-07-21 15:14:11 -040035namespace
36{
Jamie Madillf25855c2015-11-03 11:06:18 -050037bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
Jamie Madill1ca74672015-07-21 15:14:11 -040038{
Jamie Madilldfde6ab2016-06-09 07:07:18 -070039 const gl::State &state = context->getGLState();
Jamie Madill1ca74672015-07-21 15:14:11 -040040 const gl::Program *program = state.getProgram();
41
42 const VertexArray *vao = state.getVertexArray();
43 const auto &vertexAttribs = vao->getVertexAttributes();
Jamie Madill1ca74672015-07-21 15:14:11 -040044 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
45 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
46 {
47 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Jamie Madill63805b42015-08-25 13:17:39 -040048 if (program->isAttribLocationActive(attributeIndex) && attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040049 {
50 gl::Buffer *buffer = attrib.buffer.get();
51
52 if (buffer)
53 {
54 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
55 GLint64 maxVertexElement = 0;
56
57 if (attrib.divisor > 0)
58 {
59 maxVertexElement =
60 static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
61 }
62 else
63 {
64 maxVertexElement = static_cast<GLint64>(maxVertex);
65 }
66
67 // If we're drawing zero vertices, we have enough data.
68 if (maxVertexElement > 0)
69 {
70 // Note: Last vertex element does not take the full stride!
71 GLint64 attribSize =
72 static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
73 GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040074 GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
Jamie Madill1ca74672015-07-21 15:14:11 -040075
76 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
77 // We can return INVALID_OPERATION if our vertex attribute does not have
78 // enough backing data.
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040079 if (attribDataSize + attribOffset > buffer->getSize())
Jamie Madill1ca74672015-07-21 15:14:11 -040080 {
Jamie Madill437fa652016-05-03 15:13:24 -040081 context->handleError(
Jamie Madillbc4c4bc2016-03-23 21:04:43 -040082 Error(GL_INVALID_OPERATION,
83 "Vertex buffer is not big enough for the draw call"));
Jamie Madill1ca74672015-07-21 15:14:11 -040084 return false;
85 }
86 }
87 }
88 else if (attrib.pointer == NULL)
89 {
90 // This is an application error that would normally result in a crash,
91 // but we catch it and return an error
Jamie Madill437fa652016-05-03 15:13:24 -040092 context->handleError(Error(
Jamie Madill1ca74672015-07-21 15:14:11 -040093 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
94 return false;
95 }
96 }
97 }
98
99 return true;
100}
101
Geoff Langf607c602016-09-21 11:46:48 -0400102bool ValidReadPixelsFormatType(ValidationContext *context,
103 GLenum framebufferComponentType,
104 GLenum format,
105 GLenum type)
106{
107 switch (framebufferComponentType)
108 {
109 case GL_UNSIGNED_NORMALIZED:
110 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
111 // ReadPixels with BGRA even if the extension is not present
112 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
113 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
114 type == GL_UNSIGNED_BYTE);
115
116 case GL_SIGNED_NORMALIZED:
117 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
118
119 case GL_INT:
120 return (format == GL_RGBA_INTEGER && type == GL_INT);
121
122 case GL_UNSIGNED_INT:
123 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
124
125 case GL_FLOAT:
126 return (format == GL_RGBA && type == GL_FLOAT);
127
128 default:
129 UNREACHABLE();
130 return false;
131 }
132}
133
Geoff Langf41a7152016-09-19 15:11:17 -0400134bool ValidCap(const Context *context, GLenum cap, bool queryOnly)
Geoff Lang0550d032014-01-30 11:29:07 -0500135{
136 switch (cap)
137 {
Geoff Langf41a7152016-09-19 15:11:17 -0400138 // EXT_multisample_compatibility
139 case GL_MULTISAMPLE_EXT:
140 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
141 return context->getExtensions().multisampleCompatibility;
Sami Väisänen74c23472016-05-09 17:30:30 +0300142
Geoff Langf41a7152016-09-19 15:11:17 -0400143 case GL_CULL_FACE:
144 case GL_POLYGON_OFFSET_FILL:
145 case GL_SAMPLE_ALPHA_TO_COVERAGE:
146 case GL_SAMPLE_COVERAGE:
147 case GL_SCISSOR_TEST:
148 case GL_STENCIL_TEST:
149 case GL_DEPTH_TEST:
150 case GL_BLEND:
151 case GL_DITHER:
152 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500153
Geoff Langf41a7152016-09-19 15:11:17 -0400154 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
155 case GL_RASTERIZER_DISCARD:
156 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500157
Geoff Langf41a7152016-09-19 15:11:17 -0400158 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
159 case GL_DEBUG_OUTPUT:
160 return context->getExtensions().debug;
Geoff Lang70d0f492015-12-10 17:45:46 -0500161
Geoff Langf41a7152016-09-19 15:11:17 -0400162 case GL_BIND_GENERATES_RESOURCE_CHROMIUM:
163 return queryOnly && context->getExtensions().bindGeneratesResource;
164
165 default:
166 return false;
Geoff Lang0550d032014-01-30 11:29:07 -0500167 }
168}
169
Geoff Langff5b2d52016-09-07 11:32:23 -0400170bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
171{
172 if (bufSize < numParams)
173 {
174 context->handleError(Error(GL_INVALID_OPERATION,
175 "%u parameters are required but %i were provided.", numParams,
176 bufSize));
177 return false;
178 }
179
180 return true;
181}
182
Geoff Lang62fce5b2016-09-30 10:46:35 -0400183bool ValidateReadPixelsBase(ValidationContext *context,
184 GLint x,
185 GLint y,
186 GLsizei width,
187 GLsizei height,
188 GLenum format,
189 GLenum type,
190 GLsizei bufSize,
191 GLsizei *length,
192 GLvoid *pixels)
193{
194 if (length != nullptr)
195 {
196 *length = 0;
197 }
198
199 if (width < 0 || height < 0)
200 {
201 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
202 return false;
203 }
204
205 auto readFramebuffer = context->getGLState().getReadFramebuffer();
206
207 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
208 {
209 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
210 return false;
211 }
212
213 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
214 {
215 context->handleError(Error(GL_INVALID_OPERATION));
216 return false;
217 }
218
219 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
220 ASSERT(framebuffer);
221
222 if (framebuffer->getReadBufferState() == GL_NONE)
223 {
224 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
225 return false;
226 }
227
228 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
229 if (!readBuffer)
230 {
231 context->handleError(Error(GL_INVALID_OPERATION));
232 return false;
233 }
234
235 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
236 GLenum currentType = framebuffer->getImplementationColorReadType();
237 GLenum currentInternalFormat = readBuffer->getFormat().asSized();
238
239 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(currentInternalFormat);
240 bool validFormatTypeCombination =
241 ValidReadPixelsFormatType(context, internalFormatInfo.componentType, format, type);
242
243 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
244 {
245 context->handleError(Error(GL_INVALID_OPERATION));
246 return false;
247 }
248
249 // Check for pixel pack buffer related API errors
250 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
251 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
252 {
253 // ...the buffer object's data store is currently mapped.
254 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
255 return false;
256 }
257
258 // .. the data would be packed to the buffer object such that the memory writes required
259 // would exceed the data store size.
260 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
261 const InternalFormat &formatInfo = GetInternalFormatInfo(sizedInternalFormat);
262 const gl::Extents size(width, height, 1);
263 const auto &pack = context->getGLState().getPackState();
264
265 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
266 if (endByteOrErr.isError())
267 {
268 context->handleError(endByteOrErr.getError());
269 return false;
270 }
271
272 size_t endByte = endByteOrErr.getResult();
273 if (bufSize >= 0)
274 {
275
276 if (static_cast<size_t>(bufSize) < endByte)
277 {
278 context->handleError(
279 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
280 return false;
281 }
282 }
283
284 if (pixelPackBuffer != nullptr)
285 {
286 CheckedNumeric<size_t> checkedEndByte(endByte);
287 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
288 checkedEndByte += checkedOffset;
289
290 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
291 {
292 // Overflow past the end of the buffer
293 context->handleError(
294 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
295 return false;
296 }
297 }
298
299 if (length != nullptr)
300 {
301 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
302 {
303 context->handleError(
304 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
305 return false;
306 }
307
308 *length = static_cast<GLsizei>(endByte);
309 }
310
311 return true;
312}
313
Geoff Lang740d9022016-10-07 11:20:52 -0400314bool ValidateGetRenderbufferParameterivBase(Context *context,
315 GLenum target,
316 GLenum pname,
317 GLsizei *length)
318{
319 if (length)
320 {
321 *length = 0;
322 }
323
324 if (target != GL_RENDERBUFFER)
325 {
326 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
327 return false;
328 }
329
330 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
331 if (renderbuffer == nullptr)
332 {
333 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
334 return false;
335 }
336
337 switch (pname)
338 {
339 case GL_RENDERBUFFER_WIDTH:
340 case GL_RENDERBUFFER_HEIGHT:
341 case GL_RENDERBUFFER_INTERNAL_FORMAT:
342 case GL_RENDERBUFFER_RED_SIZE:
343 case GL_RENDERBUFFER_GREEN_SIZE:
344 case GL_RENDERBUFFER_BLUE_SIZE:
345 case GL_RENDERBUFFER_ALPHA_SIZE:
346 case GL_RENDERBUFFER_DEPTH_SIZE:
347 case GL_RENDERBUFFER_STENCIL_SIZE:
348 break;
349
350 case GL_RENDERBUFFER_SAMPLES_ANGLE:
351 if (!context->getExtensions().framebufferMultisample)
352 {
353 context->handleError(
354 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
355 return false;
356 }
357 break;
358
359 default:
360 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
361 return false;
362 }
363
364 if (length)
365 {
366 *length = 1;
367 }
368 return true;
369}
370
Geoff Langd7d0ed32016-10-07 11:33:51 -0400371bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
372{
373 if (length)
374 {
375 *length = 0;
376 }
377
378 if (GetValidShader(context, shader) == nullptr)
379 {
380 return false;
381 }
382
383 switch (pname)
384 {
385 case GL_SHADER_TYPE:
386 case GL_DELETE_STATUS:
387 case GL_COMPILE_STATUS:
388 case GL_INFO_LOG_LENGTH:
389 case GL_SHADER_SOURCE_LENGTH:
390 break;
391
392 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
393 if (!context->getExtensions().translatedShaderSource)
394 {
395 context->handleError(
396 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
397 return false;
398 }
399 break;
400
401 default:
402 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
403 return false;
404 }
405
406 if (length)
407 {
408 *length = 1;
409 }
410 return true;
411}
412
Geoff Langf41a7152016-09-19 15:11:17 -0400413} // anonymous namespace
414
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500415bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400416{
Jamie Madilld7460c72014-01-21 16:38:14 -0500417 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400418 {
Jamie Madilld7460c72014-01-21 16:38:14 -0500419 case GL_TEXTURE_2D:
420 case GL_TEXTURE_CUBE_MAP:
421 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400422
Jamie Madilld7460c72014-01-21 16:38:14 -0500423 case GL_TEXTURE_3D:
424 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300425 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500426
427 default:
428 return false;
429 }
Jamie Madill35d15012013-10-07 10:46:37 -0400430}
431
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500432bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
433{
434 switch (target)
435 {
436 case GL_TEXTURE_2D:
437 case GL_TEXTURE_CUBE_MAP:
438 return true;
439
440 default:
441 return false;
442 }
443}
444
445bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
446{
447 switch (target)
448 {
449 case GL_TEXTURE_3D:
450 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300451 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500452
453 default:
454 return false;
455 }
456}
457
Ian Ewellbda75592016-04-18 17:25:54 -0400458// Most texture GL calls are not compatible with external textures, so we have a separate validation
459// function for use in the GL calls that do
460bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
461{
462 return (target == GL_TEXTURE_EXTERNAL_OES) &&
463 (context->getExtensions().eglImageExternal ||
464 context->getExtensions().eglStreamConsumerExternal);
465}
466
Shannon Woods4dfed832014-03-17 20:03:39 -0400467// This function differs from ValidTextureTarget in that the target must be
468// usable as the destination of a 2D operation-- so a cube face is valid, but
469// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400470// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500471bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400472{
473 switch (target)
474 {
475 case GL_TEXTURE_2D:
476 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
477 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
478 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
479 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
480 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
481 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
482 return true;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500483 default:
484 return false;
485 }
486}
487
488bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
489{
490 switch (target)
491 {
Shannon Woods4dfed832014-03-17 20:03:39 -0400492 case GL_TEXTURE_3D:
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500493 case GL_TEXTURE_2D_ARRAY:
494 return true;
Shannon Woods4dfed832014-03-17 20:03:39 -0400495 default:
496 return false;
497 }
498}
499
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500500bool ValidFramebufferTarget(GLenum target)
501{
Geoff Langd4475812015-03-18 10:53:05 -0400502 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
503 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500504
505 switch (target)
506 {
507 case GL_FRAMEBUFFER: return true;
508 case GL_READ_FRAMEBUFFER: return true;
509 case GL_DRAW_FRAMEBUFFER: return true;
510 default: return false;
511 }
512}
513
Jamie Madill29639852016-09-02 15:00:09 -0400514bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500515{
516 switch (target)
517 {
518 case GL_ARRAY_BUFFER:
519 case GL_ELEMENT_ARRAY_BUFFER:
520 return true;
521
Jamie Madill8c96d582014-03-05 15:01:23 -0500522 case GL_PIXEL_PACK_BUFFER:
523 case GL_PIXEL_UNPACK_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300524 return (context->getExtensions().pixelBufferObject ||
525 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400526
Shannon Woodsb3801742014-03-27 14:59:19 -0400527 case GL_COPY_READ_BUFFER:
528 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500529 case GL_TRANSFORM_FEEDBACK_BUFFER:
530 case GL_UNIFORM_BUFFER:
Martin Radev1be913c2016-07-11 17:59:16 +0300531 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500532
533 default:
534 return false;
535 }
536}
537
Geoff Langff5b2d52016-09-07 11:32:23 -0400538bool ValidBufferParameter(const ValidationContext *context, GLenum pname, GLsizei *numParams)
Jamie Madill70656a62014-03-05 15:01:26 -0500539{
Geoff Langff5b2d52016-09-07 11:32:23 -0400540 // All buffer parameter queries return one value.
541 *numParams = 1;
542
Geoff Langcc6f55d2015-03-20 13:01:02 -0400543 const Extensions &extensions = context->getExtensions();
544
Jamie Madill70656a62014-03-05 15:01:26 -0500545 switch (pname)
546 {
547 case GL_BUFFER_USAGE:
548 case GL_BUFFER_SIZE:
549 return true;
550
Geoff Langcc6f55d2015-03-20 13:01:02 -0400551 case GL_BUFFER_ACCESS_OES:
552 return extensions.mapBuffer;
553
554 case GL_BUFFER_MAPPED:
555 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
Martin Radev1be913c2016-07-11 17:59:16 +0300556 return (context->getClientMajorVersion() >= 3) || extensions.mapBuffer ||
557 extensions.mapBufferRange;
Geoff Langcc6f55d2015-03-20 13:01:02 -0400558
Jamie Madill70656a62014-03-05 15:01:26 -0500559 // GL_BUFFER_MAP_POINTER is a special case, and may only be
560 // queried with GetBufferPointerv
561 case GL_BUFFER_ACCESS_FLAGS:
Jamie Madill70656a62014-03-05 15:01:26 -0500562 case GL_BUFFER_MAP_OFFSET:
563 case GL_BUFFER_MAP_LENGTH:
Martin Radev1be913c2016-07-11 17:59:16 +0300564 return (context->getClientMajorVersion() >= 3) || extensions.mapBufferRange;
Jamie Madill70656a62014-03-05 15:01:26 -0500565
566 default:
567 return false;
568 }
569}
570
Jamie Madillc29968b2016-01-20 11:17:23 -0500571bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400572{
Jamie Madillc29968b2016-01-20 11:17:23 -0500573 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400574 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400575 switch (target)
576 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500577 case GL_TEXTURE_2D:
578 maxDimension = caps.max2DTextureSize;
579 break;
Geoff Langce635692013-09-24 13:56:32 -0400580 case GL_TEXTURE_CUBE_MAP:
581 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
582 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
583 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
584 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
585 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Jamie Madillc29968b2016-01-20 11:17:23 -0500586 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
587 maxDimension = caps.maxCubeMapTextureSize;
588 break;
589 case GL_TEXTURE_3D:
590 maxDimension = caps.max3DTextureSize;
591 break;
592 case GL_TEXTURE_2D_ARRAY:
593 maxDimension = caps.max2DTextureSize;
594 break;
Geoff Langce635692013-09-24 13:56:32 -0400595 default: UNREACHABLE();
596 }
597
Cooper Partin4d61f7e2015-08-12 10:56:50 -0700598 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -0400599}
600
Austin Kinross08528e12015-10-07 16:24:40 -0700601bool ValidImageSizeParameters(const Context *context,
602 GLenum target,
603 GLint level,
604 GLsizei width,
605 GLsizei height,
606 GLsizei depth,
607 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -0400608{
609 if (level < 0 || width < 0 || height < 0 || depth < 0)
610 {
611 return false;
612 }
613
Austin Kinross08528e12015-10-07 16:24:40 -0700614 // TexSubImage parameters can be NPOT without textureNPOT extension,
615 // as long as the destination texture is POT.
616 if (!isSubImage && !context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400617 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400618 {
619 return false;
620 }
621
622 if (!ValidMipLevel(context, target, level))
623 {
624 return false;
625 }
626
627 return true;
628}
629
Geoff Lang0d8b7242015-09-09 14:56:53 -0400630bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
631{
632 // List of compressed format that require that the texture size is smaller than or a multiple of
633 // the compressed block size.
634 switch (internalFormat)
635 {
636 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
637 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
638 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
639 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -0800640 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -0400641 return true;
642
643 default:
644 return false;
645 }
646}
647
Jamie Madillc29968b2016-01-20 11:17:23 -0500648bool ValidCompressedImageSize(const ValidationContext *context,
649 GLenum internalFormat,
650 GLsizei width,
651 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400652{
Geoff Lang5d601382014-07-22 15:14:06 -0400653 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
654 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400655 {
656 return false;
657 }
658
Geoff Lang0d8b7242015-09-09 14:56:53 -0400659 if (width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -0400660 {
661 return false;
662 }
663
Geoff Lang0d8b7242015-09-09 14:56:53 -0400664 if (CompressedTextureFormatRequiresExactSize(internalFormat))
665 {
666 if ((static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
667 width % formatInfo.compressedBlockWidth != 0) ||
668 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
669 height % formatInfo.compressedBlockHeight != 0))
670 {
671 return false;
672 }
673 }
674
Geoff Langd4f180b2013-09-24 13:57:44 -0400675 return true;
676}
677
Geoff Langff5b2d52016-09-07 11:32:23 -0400678bool ValidImageDataSize(ValidationContext *context,
679 GLenum textureTarget,
680 GLsizei width,
681 GLsizei height,
682 GLsizei depth,
683 GLenum internalFormat,
684 GLenum type,
685 const GLvoid *pixels,
686 GLsizei imageSize)
687{
688 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
689 if (pixelUnpackBuffer == nullptr && imageSize < 0)
690 {
691 // Checks are not required
692 return true;
693 }
694
695 // ...the data would be unpacked from the buffer object such that the memory reads required
696 // would exceed the data store size.
697 GLenum sizedFormat = GetSizedInternalFormat(internalFormat, type);
698 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat);
699 const gl::Extents size(width, height, depth);
700 const auto &unpack = context->getGLState().getUnpackState();
701
702 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
703 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
704 if (endByteOrErr.isError())
705 {
706 context->handleError(endByteOrErr.getError());
707 return false;
708 }
709
710 GLuint endByte = endByteOrErr.getResult();
711
712 if (pixelUnpackBuffer)
713 {
714 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
715 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
716 checkedEndByte += checkedOffset;
717
718 if (!checkedEndByte.IsValid() ||
719 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
720 {
721 // Overflow past the end of the buffer
722 context->handleError(Error(GL_INVALID_OPERATION));
723 return false;
724 }
725 }
726 else
727 {
728 ASSERT(imageSize >= 0);
729 if (pixels == nullptr && imageSize != 0)
730 {
731 context->handleError(
732 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
733 }
734
735 if (endByte > static_cast<GLuint>(imageSize))
736 {
737 context->handleError(
738 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
739 return false;
740 }
741 }
742
743 return true;
744}
745
Geoff Lang37dde692014-01-31 16:34:54 -0500746bool ValidQueryType(const Context *context, GLenum queryType)
747{
Geoff Langd4475812015-03-18 10:53:05 -0400748 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal.");
749 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 -0500750
751 switch (queryType)
752 {
753 case GL_ANY_SAMPLES_PASSED:
754 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
755 return true;
756 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
Martin Radev1be913c2016-07-11 17:59:16 +0300757 return (context->getClientMajorVersion() >= 3);
Ian Ewell3ffd78b2016-01-22 16:09:42 -0500758 case GL_TIME_ELAPSED_EXT:
759 return context->getExtensions().disjointTimerQuery;
Geoff Lang2b4ce802016-04-28 13:34:50 -0400760 case GL_COMMANDS_COMPLETED_CHROMIUM:
761 return context->getExtensions().syncQuery;
Geoff Lang37dde692014-01-31 16:34:54 -0500762 default:
763 return false;
764 }
765}
766
Jamie Madillef300b12016-10-07 15:12:09 -0400767Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500768{
769 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
770 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
771 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
772
Dian Xiang769769a2015-09-09 15:20:08 -0700773 Program *validProgram = context->getProgram(id);
774
775 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -0500776 {
Dian Xiang769769a2015-09-09 15:20:08 -0700777 if (context->getShader(id))
778 {
Jamie Madill437fa652016-05-03 15:13:24 -0400779 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700780 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
781 }
782 else
783 {
Jamie Madill437fa652016-05-03 15:13:24 -0400784 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700785 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500786 }
Dian Xiang769769a2015-09-09 15:20:08 -0700787
788 return validProgram;
789}
790
Jamie Madillef300b12016-10-07 15:12:09 -0400791Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -0700792{
793 // See ValidProgram for spec details.
794
795 Shader *validShader = context->getShader(id);
796
797 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -0500798 {
Dian Xiang769769a2015-09-09 15:20:08 -0700799 if (context->getProgram(id))
800 {
Jamie Madill437fa652016-05-03 15:13:24 -0400801 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -0700802 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
803 }
804 else
805 {
Jamie Madill437fa652016-05-03 15:13:24 -0400806 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -0700807 }
Geoff Lang48dcae72014-02-05 16:28:24 -0500808 }
Dian Xiang769769a2015-09-09 15:20:08 -0700809
810 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -0500811}
812
Geoff Langb1196682014-07-23 13:47:29 -0400813bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400814{
815 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
816 {
817 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
818
Geoff Langaae65a42014-05-26 12:43:44 -0400819 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400820 {
Jamie Madill437fa652016-05-03 15:13:24 -0400821 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400822 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400823 }
824 }
825 else
826 {
827 switch (attachment)
828 {
829 case GL_DEPTH_ATTACHMENT:
830 case GL_STENCIL_ATTACHMENT:
Martin Radev1be913c2016-07-11 17:59:16 +0300831 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400832
833 case GL_DEPTH_STENCIL_ATTACHMENT:
Geoff Langc287ea62016-09-16 14:46:51 -0400834 if (!context->getExtensions().webglCompatibility &&
835 context->getClientMajorVersion() < 3)
Martin Radev1be913c2016-07-11 17:59:16 +0300836 {
837 context->handleError(Error(GL_INVALID_ENUM));
838 return false;
839 }
840 break;
Jamie Madillb4472272014-07-03 10:38:55 -0400841
842 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400843 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +0300844 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400845 }
846 }
847
848 return true;
849}
850
Corentin Walleze0902642014-11-04 12:32:15 -0800851bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
852 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400853{
854 switch (target)
855 {
856 case GL_RENDERBUFFER:
857 break;
858 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400859 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400860 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400861 }
862
863 if (width < 0 || height < 0 || samples < 0)
864 {
Jamie Madill437fa652016-05-03 15:13:24 -0400865 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400866 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400867 }
868
Geoff Langd87878e2014-09-19 15:42:59 -0400869 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
870 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400871 {
Jamie Madill437fa652016-05-03 15:13:24 -0400872 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400873 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400874 }
875
876 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
877 // 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 -0800878 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400879 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400880 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400881 {
Jamie Madill437fa652016-05-03 15:13:24 -0400882 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400883 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400884 }
885
Geoff Langaae65a42014-05-26 12:43:44 -0400886 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 {
Jamie Madill437fa652016-05-03 15:13:24 -0400888 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400889 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890 }
891
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700892 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400893 if (handle == 0)
894 {
Jamie Madill437fa652016-05-03 15:13:24 -0400895 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400896 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400897 }
898
899 return true;
900}
901
Corentin Walleze0902642014-11-04 12:32:15 -0800902bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
903 GLenum internalformat, GLsizei width, GLsizei height)
904{
Austin Kinrossd2cf3ad2015-01-07 14:00:30 -0800905 ASSERT(samples == 0 || context->getExtensions().framebufferMultisample);
Corentin Walleze0902642014-11-04 12:32:15 -0800906
907 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
Geoff Langdef624b2015-04-13 10:46:56 -0400908 // to MAX_SAMPLES_ANGLE (Context::getCaps().maxSamples) otherwise GL_INVALID_VALUE is
Corentin Walleze0902642014-11-04 12:32:15 -0800909 // generated.
Geoff Langdef624b2015-04-13 10:46:56 -0400910 if (static_cast<GLuint>(samples) > context->getCaps().maxSamples)
Corentin Walleze0902642014-11-04 12:32:15 -0800911 {
Jamie Madill437fa652016-05-03 15:13:24 -0400912 context->handleError(Error(GL_INVALID_VALUE));
Corentin Walleze0902642014-11-04 12:32:15 -0800913 return false;
914 }
915
916 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
917 // the specified storage. This is different than ES 3.0 in which a sample number higher
918 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
Geoff Langa4903b72015-03-02 16:02:48 -0800919 // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
Martin Radev1be913c2016-07-11 17:59:16 +0300920 if (context->getClientMajorVersion() >= 3)
Corentin Walleze0902642014-11-04 12:32:15 -0800921 {
Geoff Langa4903b72015-03-02 16:02:48 -0800922 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
923 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
924 {
Jamie Madill437fa652016-05-03 15:13:24 -0400925 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langa4903b72015-03-02 16:02:48 -0800926 return false;
927 }
Corentin Walleze0902642014-11-04 12:32:15 -0800928 }
929
930 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
931}
932
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500933bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
934 GLenum renderbuffertarget, GLuint renderbuffer)
935{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400936 if (!ValidFramebufferTarget(target))
937 {
Jamie Madill437fa652016-05-03 15:13:24 -0400938 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400939 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400940 }
941
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700942 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500943
Jamie Madill84115c92015-04-23 15:00:07 -0400944 ASSERT(framebuffer);
945 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500946 {
Jamie Madill437fa652016-05-03 15:13:24 -0400947 context->handleError(
948 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -0400949 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500950 }
951
Jamie Madillb4472272014-07-03 10:38:55 -0400952 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500953 {
Jamie Madillb4472272014-07-03 10:38:55 -0400954 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500955 }
956
Jamie Madillab9d82c2014-01-21 16:38:14 -0500957 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
958 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
959 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
960 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
961 if (renderbuffer != 0)
962 {
963 if (!context->getRenderbuffer(renderbuffer))
964 {
Jamie Madill437fa652016-05-03 15:13:24 -0400965 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -0400966 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500967 }
968 }
969
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500970 return true;
971}
972
Jamie Madilldfde6ab2016-06-09 07:07:18 -0700973bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -0500974 GLint srcX0,
975 GLint srcY0,
976 GLint srcX1,
977 GLint srcY1,
978 GLint dstX0,
979 GLint dstY0,
980 GLint dstX1,
981 GLint dstY1,
982 GLbitfield mask,
983 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400984{
985 switch (filter)
986 {
987 case GL_NEAREST:
988 break;
989 case GL_LINEAR:
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400990 break;
991 default:
Jamie Madill437fa652016-05-03 15:13:24 -0400992 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -0400993 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400994 }
995
996 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
997 {
Jamie Madill437fa652016-05-03 15:13:24 -0400998 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -0400999 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001000 }
1001
1002 if (mask == 0)
1003 {
1004 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
1005 // buffers are copied.
1006 return false;
1007 }
1008
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001009 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1010 // color buffer, leaving only nearest being unfiltered from above
1011 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1012 {
Jamie Madill437fa652016-05-03 15:13:24 -04001013 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001014 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001015 }
1016
Jamie Madill51f40ec2016-06-15 14:06:00 -04001017 const auto &glState = context->getGLState();
1018 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1019 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001020
1021 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001022 {
Jamie Madill437fa652016-05-03 15:13:24 -04001023 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001024 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001025 }
1026
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001027 if (readFramebuffer->id() == drawFramebuffer->id())
1028 {
1029 context->handleError(Error(GL_INVALID_OPERATION));
1030 return false;
1031 }
1032
Jamie Madill51f40ec2016-06-15 14:06:00 -04001033 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001034 {
Jamie Madill437fa652016-05-03 15:13:24 -04001035 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001036 return false;
1037 }
1038
Jamie Madill51f40ec2016-06-15 14:06:00 -04001039 if (drawFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001040 {
Jamie Madill437fa652016-05-03 15:13:24 -04001041 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001042 return false;
1043 }
1044
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001045 if (drawFramebuffer->getSamples(context->getContextState()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001046 {
Jamie Madill437fa652016-05-03 15:13:24 -04001047 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001048 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001049 }
1050
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001051 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1052
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001053 if (mask & GL_COLOR_BUFFER_BIT)
1054 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001055 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
1056 const gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05001057 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001058
1059 if (readColorBuffer && drawColorBuffer)
1060 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001061 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001062
Geoff Langa15472a2015-08-11 11:48:03 -04001063 for (size_t drawbufferIdx = 0;
1064 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001065 {
Geoff Langa15472a2015-08-11 11:48:03 -04001066 const FramebufferAttachment *attachment =
1067 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1068 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001069 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001070 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001071
Geoff Langb2f3d052013-08-13 12:49:27 -04001072 // The GL ES 3.0.2 spec (pg 193) states that:
1073 // 1) If the read buffer is fixed point format, the draw buffer must be as well
1074 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
1075 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Jamie Madill6163c752015-12-07 16:32:59 -05001076 // Changes with EXT_color_buffer_float:
1077 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04001078 GLenum readComponentType = readFormat.info->componentType;
1079 GLenum drawComponentType = drawFormat.info->componentType;
Jamie Madill6163c752015-12-07 16:32:59 -05001080 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
1081 readComponentType == GL_SIGNED_NORMALIZED);
1082 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1083 drawComponentType == GL_SIGNED_NORMALIZED);
1084
1085 if (extensions.colorBufferFloat)
1086 {
1087 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1088 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1089
1090 if (readFixedOrFloat != drawFixedOrFloat)
1091 {
Jamie Madill437fa652016-05-03 15:13:24 -04001092 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001093 "If the read buffer contains fixed-point or "
1094 "floating-point values, the draw buffer "
1095 "must as well."));
1096 return false;
1097 }
1098 }
1099 else if (readFixedPoint != drawFixedPoint)
1100 {
Jamie Madill437fa652016-05-03 15:13:24 -04001101 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001102 "If the read buffer contains fixed-point "
1103 "values, the draw buffer must as well."));
1104 return false;
1105 }
1106
1107 if (readComponentType == GL_UNSIGNED_INT &&
1108 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001109 {
Jamie Madill437fa652016-05-03 15:13:24 -04001110 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001111 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001112 }
1113
Jamie Madill6163c752015-12-07 16:32:59 -05001114 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001115 {
Jamie Madill437fa652016-05-03 15:13:24 -04001116 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001117 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001118 }
1119
Jamie Madilla3944d42016-07-22 22:13:26 -04001120 if (readColorBuffer->getSamples() > 0 &&
1121 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001122 {
Jamie Madill437fa652016-05-03 15:13:24 -04001123 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001124 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001125 }
1126 }
1127 }
1128
Jamie Madilla3944d42016-07-22 22:13:26 -04001129 if ((readFormat.info->componentType == GL_INT ||
1130 readFormat.info->componentType == GL_UNSIGNED_INT) &&
1131 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001132 {
Jamie Madill437fa652016-05-03 15:13:24 -04001133 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001134 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001135 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001136 }
1137 }
1138
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001139 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
1140 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1141 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001142 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001143 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001144 {
Jamie Madill2d06b732015-04-20 12:53:28 -04001145 const gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]);
1146 const gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001147
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001148 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001149 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001150 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001151 {
Jamie Madill437fa652016-05-03 15:13:24 -04001152 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001153 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001154 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001155
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001156 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001157 {
Jamie Madill437fa652016-05-03 15:13:24 -04001158 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001159 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001160 }
1161 }
1162 }
1163 }
1164
1165 return true;
1166}
1167
Geoff Langb1196682014-07-23 13:47:29 -04001168bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001169{
1170 switch (pname)
1171 {
1172 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1173 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1174 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1175 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1176 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1177 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1178 case GL_CURRENT_VERTEX_ATTRIB:
Martin Radev1be913c2016-07-11 17:59:16 +03001179 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001180
1181 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
Martin Radev1be913c2016-07-11 17:59:16 +03001182 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
1183 // the same constant.
1184 static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
1185 "ANGLE extension enums not equal to GL enums.");
1186 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001187
1188 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Martin Radev1be913c2016-07-11 17:59:16 +03001189 if (context->getClientMajorVersion() < 3)
1190 {
1191 context->handleError(Error(GL_INVALID_ENUM));
1192 return false;
1193 }
1194 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001195
1196 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001197 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03001198 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001199 }
1200}
1201
Ian Ewellbda75592016-04-18 17:25:54 -04001202bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001203{
1204 switch (pname)
1205 {
1206 case GL_TEXTURE_WRAP_R:
1207 case GL_TEXTURE_SWIZZLE_R:
1208 case GL_TEXTURE_SWIZZLE_G:
1209 case GL_TEXTURE_SWIZZLE_B:
1210 case GL_TEXTURE_SWIZZLE_A:
1211 case GL_TEXTURE_BASE_LEVEL:
1212 case GL_TEXTURE_MAX_LEVEL:
1213 case GL_TEXTURE_COMPARE_MODE:
1214 case GL_TEXTURE_COMPARE_FUNC:
1215 case GL_TEXTURE_MIN_LOD:
1216 case GL_TEXTURE_MAX_LOD:
Martin Radev1be913c2016-07-11 17:59:16 +03001217 if (context->getClientMajorVersion() < 3)
1218 {
1219 context->handleError(Error(GL_INVALID_ENUM));
1220 return false;
1221 }
1222 if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3)
1223 {
1224 context->handleError(Error(GL_INVALID_ENUM,
1225 "ES3 texture parameters are not available without "
1226 "GL_OES_EGL_image_external_essl3."));
1227 return false;
1228 }
1229 break;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001230
1231 default: break;
1232 }
1233
1234 switch (pname)
1235 {
1236 case GL_TEXTURE_WRAP_S:
1237 case GL_TEXTURE_WRAP_T:
1238 case GL_TEXTURE_WRAP_R:
1239 switch (param)
1240 {
Corentin Wallez9670b032016-04-29 09:47:47 +00001241 case GL_CLAMP_TO_EDGE:
Ian Ewellbda75592016-04-18 17:25:54 -04001242 return true;
1243 case GL_REPEAT:
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001244 case GL_MIRRORED_REPEAT:
Olli Etuahobd329092016-04-29 12:51:42 +03001245 if (target == GL_TEXTURE_EXTERNAL_OES)
1246 {
1247 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -04001248 context->handleError(Error(
Olli Etuahobd329092016-04-29 12:51:42 +03001249 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
1250 return false;
1251 }
1252 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001253 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001254 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001255 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001256 }
1257
1258 case GL_TEXTURE_MIN_FILTER:
1259 switch (param)
1260 {
1261 case GL_NEAREST:
1262 case GL_LINEAR:
Ian Ewellbda75592016-04-18 17:25:54 -04001263 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001264 case GL_NEAREST_MIPMAP_NEAREST:
1265 case GL_LINEAR_MIPMAP_NEAREST:
1266 case GL_NEAREST_MIPMAP_LINEAR:
1267 case GL_LINEAR_MIPMAP_LINEAR:
Olli Etuahobd329092016-04-29 12:51:42 +03001268 if (target == GL_TEXTURE_EXTERNAL_OES)
1269 {
1270 // OES_EGL_image_external specifies this error.
Jamie Madill437fa652016-05-03 15:13:24 -04001271 context->handleError(
Olli Etuahobd329092016-04-29 12:51:42 +03001272 Error(GL_INVALID_ENUM,
1273 "external textures only support NEAREST and LINEAR filtering"));
1274 return false;
1275 }
1276 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001277 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001278 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001279 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001280 }
1281 break;
1282
1283 case GL_TEXTURE_MAG_FILTER:
1284 switch (param)
1285 {
1286 case GL_NEAREST:
1287 case GL_LINEAR:
1288 return true;
1289 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001290 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001291 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001292 }
1293 break;
1294
1295 case GL_TEXTURE_USAGE_ANGLE:
1296 switch (param)
1297 {
1298 case GL_NONE:
1299 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
1300 return true;
1301 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001302 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001303 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001304 }
1305 break;
1306
1307 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001308 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001309 {
Jamie Madill437fa652016-05-03 15:13:24 -04001310 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001311 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001312 }
1313
1314 // we assume the parameter passed to this validation method is truncated, not rounded
1315 if (param < 1)
1316 {
Jamie Madill437fa652016-05-03 15:13:24 -04001317 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001318 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001319 }
1320 return true;
1321
1322 case GL_TEXTURE_MIN_LOD:
1323 case GL_TEXTURE_MAX_LOD:
1324 // any value is permissible
1325 return true;
1326
1327 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -04001328 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001329 switch (param)
1330 {
1331 case GL_NONE:
1332 case GL_COMPARE_REF_TO_TEXTURE:
1333 return true;
1334 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001335 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001336 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001337 }
1338 break;
1339
1340 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -04001341 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001342 switch (param)
1343 {
1344 case GL_LEQUAL:
1345 case GL_GEQUAL:
1346 case GL_LESS:
1347 case GL_GREATER:
1348 case GL_EQUAL:
1349 case GL_NOTEQUAL:
1350 case GL_ALWAYS:
1351 case GL_NEVER:
1352 return true;
1353 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001354 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001355 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001356 }
1357 break;
1358
1359 case GL_TEXTURE_SWIZZLE_R:
1360 case GL_TEXTURE_SWIZZLE_G:
1361 case GL_TEXTURE_SWIZZLE_B:
1362 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -04001363 switch (param)
1364 {
1365 case GL_RED:
1366 case GL_GREEN:
1367 case GL_BLUE:
1368 case GL_ALPHA:
1369 case GL_ZERO:
1370 case GL_ONE:
1371 return true;
1372 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001373 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001374 return false;
Geoff Langbc90a482013-09-17 16:51:27 -04001375 }
1376 break;
1377
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001378 case GL_TEXTURE_BASE_LEVEL:
Geoff Langb66a9092016-05-16 15:59:14 -04001379 if (param < 0)
Olli Etuahoa314b612016-03-10 16:43:00 +02001380 {
Geoff Langb66a9092016-05-16 15:59:14 -04001381 context->handleError(Error(GL_INVALID_VALUE));
Olli Etuahoa314b612016-03-10 16:43:00 +02001382 return false;
1383 }
Geoff Langb66a9092016-05-16 15:59:14 -04001384 if (target == GL_TEXTURE_EXTERNAL_OES && param != 0)
1385 {
1386 context->handleError(
1387 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
1388 return false;
1389 }
1390 return true;
1391
1392 case GL_TEXTURE_MAX_LEVEL:
Olli Etuahoa314b612016-03-10 16:43:00 +02001393 if (param < 0)
1394 {
1395 context->handleError(Error(GL_INVALID_VALUE));
1396 return false;
1397 }
1398 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001399 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001400 context->handleError(Error(GL_INVALID_ENUM));
Olli Etuahoa314b612016-03-10 16:43:00 +02001401 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001402 }
1403}
1404
Geoff Langb1196682014-07-23 13:47:29 -04001405bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001406{
1407 switch (pname)
1408 {
1409 case GL_TEXTURE_MIN_FILTER:
1410 case GL_TEXTURE_MAG_FILTER:
1411 case GL_TEXTURE_WRAP_S:
1412 case GL_TEXTURE_WRAP_T:
1413 case GL_TEXTURE_WRAP_R:
1414 case GL_TEXTURE_MIN_LOD:
1415 case GL_TEXTURE_MAX_LOD:
1416 case GL_TEXTURE_COMPARE_MODE:
1417 case GL_TEXTURE_COMPARE_FUNC:
1418 return true;
1419
1420 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001421 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001422 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001423 }
1424}
1425
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001426bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001427 GLint x,
1428 GLint y,
1429 GLsizei width,
1430 GLsizei height,
1431 GLenum format,
1432 GLenum type,
1433 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05001434{
Geoff Lang62fce5b2016-09-30 10:46:35 -04001435 return ValidateReadPixelsBase(context, x, y, width, height, format, type, -1, nullptr, pixels);
1436}
1437
1438bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
1439 GLint x,
1440 GLint y,
1441 GLsizei width,
1442 GLsizei height,
1443 GLenum format,
1444 GLenum type,
1445 GLsizei bufSize,
1446 GLsizei *length,
1447 GLvoid *pixels)
1448{
1449 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05001450 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001451 return false;
1452 }
1453
Geoff Lang62fce5b2016-09-30 10:46:35 -04001454 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
1455 pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05001456 {
Geoff Langb1196682014-07-23 13:47:29 -04001457 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001458 }
1459
Geoff Lang62fce5b2016-09-30 10:46:35 -04001460 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05001461 {
Geoff Langb1196682014-07-23 13:47:29 -04001462 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001463 }
1464
Jamie Madillc29968b2016-01-20 11:17:23 -05001465 return true;
1466}
1467
1468bool ValidateReadnPixelsEXT(Context *context,
1469 GLint x,
1470 GLint y,
1471 GLsizei width,
1472 GLsizei height,
1473 GLenum format,
1474 GLenum type,
1475 GLsizei bufSize,
1476 GLvoid *pixels)
1477{
1478 if (bufSize < 0)
1479 {
Jamie Madill437fa652016-05-03 15:13:24 -04001480 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001481 return false;
1482 }
1483
Geoff Lang62fce5b2016-09-30 10:46:35 -04001484 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
1485 pixels);
1486}
Jamie Madill26e91952014-03-05 15:01:27 -05001487
Geoff Lang62fce5b2016-09-30 10:46:35 -04001488bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
1489 GLint x,
1490 GLint y,
1491 GLsizei width,
1492 GLsizei height,
1493 GLenum format,
1494 GLenum type,
1495 GLsizei bufSize,
1496 GLsizei *length,
1497 GLvoid *data)
1498{
1499 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04001500 {
Jamie Madille2e406c2016-06-02 13:04:10 -04001501 return false;
1502 }
1503
Geoff Lang62fce5b2016-09-30 10:46:35 -04001504 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04001505 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001506 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001507 }
1508
Geoff Lang62fce5b2016-09-30 10:46:35 -04001509 if (!ValidateRobustBufferSize(context, bufSize, *length))
1510 {
1511 return false;
1512 }
1513
1514 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05001515}
1516
Olli Etuaho41997e72016-03-10 13:38:39 +02001517bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001518{
1519 if (!context->getExtensions().occlusionQueryBoolean &&
1520 !context->getExtensions().disjointTimerQuery)
1521 {
Jamie Madill437fa652016-05-03 15:13:24 -04001522 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001523 return false;
1524 }
1525
Olli Etuaho41997e72016-03-10 13:38:39 +02001526 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001527}
1528
Olli Etuaho41997e72016-03-10 13:38:39 +02001529bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001530{
1531 if (!context->getExtensions().occlusionQueryBoolean &&
1532 !context->getExtensions().disjointTimerQuery)
1533 {
Jamie Madill437fa652016-05-03 15:13:24 -04001534 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001535 return false;
1536 }
1537
Olli Etuaho41997e72016-03-10 13:38:39 +02001538 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001539}
1540
1541bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001542{
1543 if (!ValidQueryType(context, target))
1544 {
Jamie Madill437fa652016-05-03 15:13:24 -04001545 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001546 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001547 }
1548
1549 if (id == 0)
1550 {
Jamie Madill437fa652016-05-03 15:13:24 -04001551 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001552 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001553 }
1554
1555 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1556 // of zero, if the active query object name for <target> is non-zero (for the
1557 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1558 // the active query for either target is non-zero), if <id> is the name of an
1559 // existing query object whose type does not match <target>, or if <id> is the
1560 // active query object name for any query type, the error INVALID_OPERATION is
1561 // generated.
1562
1563 // Ensure no other queries are active
1564 // NOTE: If other queries than occlusion are supported, we will need to check
1565 // separately that:
1566 // a) The query ID passed is not the current active query for any target/type
1567 // b) There are no active queries for the requested target (and in the case
1568 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1569 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001570
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001571 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001572 {
Jamie Madill437fa652016-05-03 15:13:24 -04001573 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001574 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001575 }
1576
1577 Query *queryObject = context->getQuery(id, true, target);
1578
1579 // check that name was obtained with glGenQueries
1580 if (!queryObject)
1581 {
Jamie Madill437fa652016-05-03 15:13:24 -04001582 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001583 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001584 }
1585
1586 // check for type mismatch
1587 if (queryObject->getType() != target)
1588 {
Jamie Madill437fa652016-05-03 15:13:24 -04001589 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001590 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001591 }
1592
1593 return true;
1594}
1595
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001596bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1597{
1598 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001599 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001600 {
Jamie Madill437fa652016-05-03 15:13:24 -04001601 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001602 return false;
1603 }
1604
1605 return ValidateBeginQueryBase(context, target, id);
1606}
1607
1608bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001609{
1610 if (!ValidQueryType(context, target))
1611 {
Jamie Madill437fa652016-05-03 15:13:24 -04001612 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001613 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001614 }
1615
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001616 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001617
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001618 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001619 {
Jamie Madill437fa652016-05-03 15:13:24 -04001620 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001621 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001622 }
1623
Jamie Madill45c785d2014-05-13 14:09:34 -04001624 return true;
1625}
1626
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001627bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1628{
1629 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001630 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001631 {
Jamie Madill437fa652016-05-03 15:13:24 -04001632 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001633 return false;
1634 }
1635
1636 return ValidateEndQueryBase(context, target);
1637}
1638
1639bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1640{
1641 if (!context->getExtensions().disjointTimerQuery)
1642 {
Jamie Madill437fa652016-05-03 15:13:24 -04001643 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001644 return false;
1645 }
1646
1647 if (target != GL_TIMESTAMP_EXT)
1648 {
Jamie Madill437fa652016-05-03 15:13:24 -04001649 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001650 return false;
1651 }
1652
1653 Query *queryObject = context->getQuery(id, true, target);
1654 if (queryObject == nullptr)
1655 {
Jamie Madill437fa652016-05-03 15:13:24 -04001656 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001657 return false;
1658 }
1659
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001660 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001661 {
Jamie Madill437fa652016-05-03 15:13:24 -04001662 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001663 return false;
1664 }
1665
1666 return true;
1667}
1668
1669bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname)
1670{
1671 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1672 {
Jamie Madill437fa652016-05-03 15:13:24 -04001673 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001674 return false;
1675 }
1676
1677 switch (pname)
1678 {
1679 case GL_CURRENT_QUERY_EXT:
1680 if (target == GL_TIMESTAMP_EXT)
1681 {
Jamie Madill437fa652016-05-03 15:13:24 -04001682 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001683 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1684 return false;
1685 }
1686 break;
1687 case GL_QUERY_COUNTER_BITS_EXT:
1688 if (!context->getExtensions().disjointTimerQuery ||
1689 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1690 {
Jamie Madill437fa652016-05-03 15:13:24 -04001691 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001692 return false;
1693 }
1694 break;
1695 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001696 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001697 return false;
1698 }
1699
1700 return true;
1701}
1702
1703bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1704{
1705 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001706 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001707 {
Jamie Madill437fa652016-05-03 15:13:24 -04001708 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001709 return false;
1710 }
1711
1712 return ValidateGetQueryivBase(context, target, pname);
1713}
1714
1715bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname)
1716{
1717 Query *queryObject = context->getQuery(id, false, GL_NONE);
1718
1719 if (!queryObject)
1720 {
Jamie Madill437fa652016-05-03 15:13:24 -04001721 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001722 return false;
1723 }
1724
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001725 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001726 {
Jamie Madill437fa652016-05-03 15:13:24 -04001727 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001728 return false;
1729 }
1730
1731 switch (pname)
1732 {
1733 case GL_QUERY_RESULT_EXT:
1734 case GL_QUERY_RESULT_AVAILABLE_EXT:
1735 break;
1736
1737 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001738 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001739 return false;
1740 }
1741
1742 return true;
1743}
1744
1745bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
1746{
1747 if (!context->getExtensions().disjointTimerQuery)
1748 {
Jamie Madill437fa652016-05-03 15:13:24 -04001749 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001750 return false;
1751 }
1752 return ValidateGetQueryObjectValueBase(context, id, pname);
1753}
1754
1755bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
1756{
1757 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001758 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001759 {
Jamie Madill437fa652016-05-03 15:13:24 -04001760 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001761 return false;
1762 }
1763 return ValidateGetQueryObjectValueBase(context, id, pname);
1764}
1765
1766bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
1767{
1768 if (!context->getExtensions().disjointTimerQuery)
1769 {
Jamie Madill437fa652016-05-03 15:13:24 -04001770 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001771 return false;
1772 }
1773 return ValidateGetQueryObjectValueBase(context, id, pname);
1774}
1775
1776bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
1777{
1778 if (!context->getExtensions().disjointTimerQuery)
1779 {
Jamie Madill437fa652016-05-03 15:13:24 -04001780 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001781 return false;
1782 }
1783 return ValidateGetQueryObjectValueBase(context, id, pname);
1784}
1785
Jamie Madill62d31cb2015-09-11 13:25:51 -04001786static bool ValidateUniformCommonBase(gl::Context *context,
1787 GLenum targetUniformType,
1788 GLint location,
1789 GLsizei count,
1790 const LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001791{
1792 if (count < 0)
1793 {
Jamie Madill437fa652016-05-03 15:13:24 -04001794 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001795 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001796 }
1797
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001798 gl::Program *program = context->getGLState().getProgram();
Geoff Lang7dd2e102014-11-10 15:19:26 -05001799 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001800 {
Jamie Madill437fa652016-05-03 15:13:24 -04001801 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001802 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001803 }
1804
Geoff Langd8605522016-04-13 10:19:12 -04001805 if (program->isIgnoredUniformLocation(location))
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001806 {
1807 // Silently ignore the uniform command
1808 return false;
1809 }
1810
Geoff Lang7dd2e102014-11-10 15:19:26 -05001811 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001812 {
Jamie Madill437fa652016-05-03 15:13:24 -04001813 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001814 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001815 }
1816
Jamie Madill62d31cb2015-09-11 13:25:51 -04001817 const LinkedUniform &uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001818
1819 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
Jamie Madill62d31cb2015-09-11 13:25:51 -04001820 if (!uniform.isArray() && count > 1)
Jamie Madill36398922014-05-20 14:51:53 -04001821 {
Jamie Madill437fa652016-05-03 15:13:24 -04001822 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001823 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001824 }
1825
Jamie Madill62d31cb2015-09-11 13:25:51 -04001826 *uniformOut = &uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001827 return true;
1828}
1829
Jamie Madillaa981bd2014-05-20 10:55:55 -04001830bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1831{
1832 // Check for ES3 uniform entry points
Martin Radev1be913c2016-07-11 17:59:16 +03001833 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT &&
1834 context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001835 {
Jamie Madill437fa652016-05-03 15:13:24 -04001836 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001837 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001838 }
1839
Jamie Madill62d31cb2015-09-11 13:25:51 -04001840 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001841 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1842 {
1843 return false;
1844 }
1845
Jamie Madillf2575982014-06-25 16:04:54 -04001846 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001847 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001848 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1849 {
Jamie Madill437fa652016-05-03 15:13:24 -04001850 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001851 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001852 }
1853
1854 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001855}
1856
1857bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1858 GLboolean transpose)
1859{
1860 // Check for ES3 uniform entry points
1861 int rows = VariableRowCount(matrixType);
1862 int cols = VariableColumnCount(matrixType);
Martin Radev1be913c2016-07-11 17:59:16 +03001863 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001864 {
Jamie Madill437fa652016-05-03 15:13:24 -04001865 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001866 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001867 }
1868
Martin Radev1be913c2016-07-11 17:59:16 +03001869 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001870 {
Jamie Madill437fa652016-05-03 15:13:24 -04001871 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001872 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001873 }
1874
Jamie Madill62d31cb2015-09-11 13:25:51 -04001875 const LinkedUniform *uniform = nullptr;
Jamie Madill36398922014-05-20 14:51:53 -04001876 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1877 {
1878 return false;
1879 }
1880
1881 if (uniform->type != matrixType)
1882 {
Jamie Madill437fa652016-05-03 15:13:24 -04001883 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001884 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001885 }
1886
1887 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001888}
1889
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001890bool ValidateStateQuery(ValidationContext *context,
1891 GLenum pname,
1892 GLenum *nativeType,
1893 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04001894{
1895 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1896 {
Jamie Madill437fa652016-05-03 15:13:24 -04001897 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001898 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001899 }
1900
Jamie Madill0af26e12015-03-05 19:54:33 -05001901 const Caps &caps = context->getCaps();
1902
Jamie Madill893ab082014-05-16 16:56:10 -04001903 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1904 {
1905 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1906
Jamie Madill0af26e12015-03-05 19:54:33 -05001907 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001908 {
Jamie Madill437fa652016-05-03 15:13:24 -04001909 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001910 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001911 }
1912 }
1913
1914 switch (pname)
1915 {
1916 case GL_TEXTURE_BINDING_2D:
1917 case GL_TEXTURE_BINDING_CUBE_MAP:
1918 case GL_TEXTURE_BINDING_3D:
1919 case GL_TEXTURE_BINDING_2D_ARRAY:
Jamie Madill893ab082014-05-16 16:56:10 -04001920 break;
Ian Ewell54f87462016-03-10 13:47:21 -05001921 case GL_TEXTURE_BINDING_EXTERNAL_OES:
John Bauman18319182016-09-28 14:22:27 -07001922 if (!context->getExtensions().eglStreamConsumerExternal &&
1923 !context->getExtensions().eglImageExternal)
Ian Ewell54f87462016-03-10 13:47:21 -05001924 {
John Bauman18319182016-09-28 14:22:27 -07001925 context->handleError(Error(GL_INVALID_ENUM,
1926 "Neither NV_EGL_stream_consumer_external nor "
1927 "GL_OES_EGL_image_external extensions enabled"));
Ian Ewell54f87462016-03-10 13:47:21 -05001928 return false;
1929 }
1930 break;
Jamie Madill893ab082014-05-16 16:56:10 -04001931
1932 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1933 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1934 {
Jamie Madill51f40ec2016-06-15 14:06:00 -04001935 if (context->getGLState().getReadFramebuffer()->checkStatus(
1936 context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001937 {
Jamie Madill437fa652016-05-03 15:13:24 -04001938 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001939 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001940 }
1941
Jamie Madill51f40ec2016-06-15 14:06:00 -04001942 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1943 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03001944
1945 if (framebuffer->getReadBufferState() == GL_NONE)
1946 {
1947 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
1948 return false;
1949 }
1950
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001951 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04001952 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001953 {
Jamie Madill437fa652016-05-03 15:13:24 -04001954 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001955 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001956 }
1957 }
1958 break;
1959
1960 default:
1961 break;
1962 }
1963
1964 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04001965 if (*numParams == 0)
1966 {
1967 return false;
1968 }
1969
1970 return true;
1971}
1972
1973bool ValidateRobustStateQuery(ValidationContext *context,
1974 GLenum pname,
1975 GLsizei bufSize,
1976 GLenum *nativeType,
1977 unsigned int *numParams)
1978{
1979 if (!ValidateRobustEntryPoint(context, bufSize))
1980 {
1981 return false;
1982 }
1983
1984 if (!ValidateStateQuery(context, pname, nativeType, numParams))
1985 {
1986 return false;
1987 }
1988
1989 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04001990 {
1991 return false;
1992 }
1993
1994 return true;
1995}
1996
Jamie Madillc29968b2016-01-20 11:17:23 -05001997bool ValidateCopyTexImageParametersBase(ValidationContext *context,
1998 GLenum target,
1999 GLint level,
2000 GLenum internalformat,
2001 bool isSubImage,
2002 GLint xoffset,
2003 GLint yoffset,
2004 GLint zoffset,
2005 GLint x,
2006 GLint y,
2007 GLsizei width,
2008 GLsizei height,
2009 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04002010 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04002011{
Jamie Madill560a8d82014-05-21 13:06:20 -04002012 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
2013 {
Jamie Madill437fa652016-05-03 15:13:24 -04002014 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002015 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002016 }
2017
2018 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
2019 {
Jamie Madill437fa652016-05-03 15:13:24 -04002020 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002021 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002022 }
2023
2024 if (border != 0)
2025 {
Jamie Madill437fa652016-05-03 15:13:24 -04002026 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002027 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002028 }
2029
2030 if (!ValidMipLevel(context, target, level))
2031 {
Jamie Madill437fa652016-05-03 15:13:24 -04002032 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002033 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002034 }
2035
Jamie Madill51f40ec2016-06-15 14:06:00 -04002036 const auto &state = context->getGLState();
2037 auto readFramebuffer = state.getReadFramebuffer();
2038 if (readFramebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04002039 {
Jamie Madill437fa652016-05-03 15:13:24 -04002040 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002041 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002042 }
2043
Jamie Madill51f40ec2016-06-15 14:06:00 -04002044 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context->getContextState()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04002045 {
Jamie Madill437fa652016-05-03 15:13:24 -04002046 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002047 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002048 }
2049
Martin Radev138064f2016-07-15 12:03:41 +03002050 if (readFramebuffer->getReadBufferState() == GL_NONE)
2051 {
2052 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2053 return false;
2054 }
2055
Geoff Langaae65a42014-05-26 12:43:44 -04002056 const gl::Caps &caps = context->getCaps();
2057
Geoff Langaae65a42014-05-26 12:43:44 -04002058 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04002059 switch (target)
2060 {
2061 case GL_TEXTURE_2D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05002062 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04002063 break;
2064
2065 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2066 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2067 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2068 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2069 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2070 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Geoff Langa9be0dc2014-12-17 12:34:40 -05002071 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04002072 break;
2073
2074 case GL_TEXTURE_2D_ARRAY:
Geoff Langa9be0dc2014-12-17 12:34:40 -05002075 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04002076 break;
2077
2078 case GL_TEXTURE_3D:
Geoff Langa9be0dc2014-12-17 12:34:40 -05002079 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04002080 break;
2081
2082 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002083 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002084 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002085 }
2086
Jamie Madillc29968b2016-01-20 11:17:23 -05002087 gl::Texture *texture =
2088 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04002089 if (!texture)
2090 {
Jamie Madill437fa652016-05-03 15:13:24 -04002091 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002092 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002093 }
2094
Geoff Lang69cce582015-09-17 13:20:36 -04002095 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04002096 {
Jamie Madill437fa652016-05-03 15:13:24 -04002097 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002098 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002099 }
2100
Geoff Lang5d601382014-07-22 15:14:06 -04002101 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
2102
2103 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04002104 {
Jamie Madill437fa652016-05-03 15:13:24 -04002105 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002106 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002107 }
2108
Geoff Langa9be0dc2014-12-17 12:34:40 -05002109 if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04002110 {
Jamie Madill437fa652016-05-03 15:13:24 -04002111 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002112 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002113 }
2114
2115 if (isSubImage)
2116 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05002117 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
2118 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
2119 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04002120 {
Jamie Madill437fa652016-05-03 15:13:24 -04002121 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002122 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002123 }
2124 }
Jamie Madill6f38f822014-06-06 17:12:20 -04002125 else
2126 {
Geoff Lang691e58c2014-12-19 17:03:25 -05002127 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04002128 {
Jamie Madill437fa652016-05-03 15:13:24 -04002129 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002130 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002131 }
2132
Martin Radev1be913c2016-07-11 17:59:16 +03002133 if (!formatInfo.textureSupport(context->getClientMajorVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04002134 {
Jamie Madill437fa652016-05-03 15:13:24 -04002135 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002136 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002137 }
2138
2139 int maxLevelDimension = (maxDimension >> level);
2140 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
2141 {
Jamie Madill437fa652016-05-03 15:13:24 -04002142 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002143 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002144 }
2145 }
Jamie Madill560a8d82014-05-21 13:06:20 -04002146
Jamie Madill0c8abca2016-07-22 20:21:26 -04002147 if (textureFormatOut)
2148 {
2149 *textureFormatOut = texture->getFormat(target, level);
2150 }
Jamie Madill560a8d82014-05-21 13:06:20 -04002151 return true;
2152}
2153
Jamie Madillf25855c2015-11-03 11:06:18 -05002154static bool ValidateDrawBase(ValidationContext *context,
2155 GLenum mode,
2156 GLsizei count,
2157 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04002158{
Jamie Madill1aeb1312014-06-20 13:21:25 -04002159 switch (mode)
2160 {
2161 case GL_POINTS:
2162 case GL_LINES:
2163 case GL_LINE_LOOP:
2164 case GL_LINE_STRIP:
2165 case GL_TRIANGLES:
2166 case GL_TRIANGLE_STRIP:
2167 case GL_TRIANGLE_FAN:
2168 break;
2169 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002170 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002171 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04002172 }
2173
Jamie Madill250d33f2014-06-06 17:09:03 -04002174 if (count < 0)
2175 {
Jamie Madill437fa652016-05-03 15:13:24 -04002176 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002177 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002178 }
2179
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002180 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04002181
Jamie Madill250d33f2014-06-06 17:09:03 -04002182 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002183 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002184 {
Jamie Madill437fa652016-05-03 15:13:24 -04002185 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002186 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002187 }
2188
Jamie Madill51f40ec2016-06-15 14:06:00 -04002189 Framebuffer *framebuffer = state.getDrawFramebuffer();
Geoff Lang3a86ad32015-09-01 11:47:05 -04002190 if (context->getLimitations().noSeparateStencilRefsAndMasks)
Jamie Madillac528012014-06-20 13:21:23 -04002191 {
Jinyoung Hur85769f02015-10-20 17:08:44 -04002192 const FramebufferAttachment *stencilBuffer = framebuffer->getStencilbuffer();
2193 GLuint stencilBits = stencilBuffer ? stencilBuffer->getStencilSize() : 0;
2194 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
2195 const DepthStencilState &depthStencilState = state.getDepthStencilState();
2196 if ((depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
2197 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask) ||
Geoff Lang3a86ad32015-09-01 11:47:05 -04002198 state.getStencilRef() != state.getStencilBackRef() ||
Jinyoung Hur85769f02015-10-20 17:08:44 -04002199 (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
2200 (depthStencilState.stencilBackMask & minimumRequiredStencilMask))
Geoff Lang3a86ad32015-09-01 11:47:05 -04002201 {
2202 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
2203 // Section 6.10 of the WebGL 1.0 spec
2204 ERR(
2205 "This ANGLE implementation does not support separate front/back stencil "
2206 "writemasks, reference values, or stencil mask values.");
Jamie Madill437fa652016-05-03 15:13:24 -04002207 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04002208 return false;
2209 }
Jamie Madillac528012014-06-20 13:21:23 -04002210 }
2211
Jamie Madill51f40ec2016-06-15 14:06:00 -04002212 if (framebuffer->checkStatus(context->getContextState()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002213 {
Jamie Madill437fa652016-05-03 15:13:24 -04002214 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002215 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002216 }
2217
Geoff Lang7dd2e102014-11-10 15:19:26 -05002218 gl::Program *program = state.getProgram();
2219 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002220 {
Jamie Madill437fa652016-05-03 15:13:24 -04002221 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002222 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002223 }
2224
Geoff Lang7dd2e102014-11-10 15:19:26 -05002225 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04002226 {
Jamie Madill437fa652016-05-03 15:13:24 -04002227 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002228 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002229 }
2230
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002231 // Uniform buffer validation
2232 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
2233 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04002234 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002235 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04002236 const OffsetBindingPointer<Buffer> &uniformBuffer =
2237 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002238
Geoff Lang5d124a62015-09-15 13:03:27 -04002239 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002240 {
2241 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002242 context->handleError(
2243 Error(GL_INVALID_OPERATION,
2244 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002245 return false;
2246 }
2247
Geoff Lang5d124a62015-09-15 13:03:27 -04002248 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002249 if (uniformBufferSize == 0)
2250 {
2251 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07002252 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002253 }
2254
Jamie Madill62d31cb2015-09-11 13:25:51 -04002255 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002256 {
2257 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002258 context->handleError(
2259 Error(GL_INVALID_OPERATION,
2260 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002261 return false;
2262 }
2263 }
2264
Jamie Madill250d33f2014-06-06 17:09:03 -04002265 // No-op if zero count
2266 return (count > 0);
2267}
2268
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002269bool ValidateDrawArrays(ValidationContext *context,
2270 GLenum mode,
2271 GLint first,
2272 GLsizei count,
2273 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04002274{
Jamie Madillfd716582014-06-06 17:09:04 -04002275 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04002276 {
Jamie Madill437fa652016-05-03 15:13:24 -04002277 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002278 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002279 }
2280
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002281 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002282 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002283 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused() &&
2284 curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04002285 {
2286 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
2287 // that does not match the current transform feedback object's draw mode (if transform feedback
2288 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002289 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002290 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002291 }
2292
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002293 if (!ValidateDrawBase(context, mode, count, primcount))
2294 {
2295 return false;
2296 }
2297
2298 if (!ValidateDrawAttribs(context, primcount, count))
Jamie Madillfd716582014-06-06 17:09:04 -04002299 {
2300 return false;
2301 }
2302
2303 return true;
2304}
2305
Geoff Langb1196682014-07-23 13:47:29 -04002306bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04002307{
2308 if (primcount < 0)
2309 {
Jamie Madill437fa652016-05-03 15:13:24 -04002310 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002311 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002312 }
2313
Jamie Madill2b976812014-08-25 15:47:49 -04002314 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04002315 {
2316 return false;
2317 }
2318
2319 // No-op if zero primitive count
2320 return (primcount > 0);
2321}
2322
Geoff Lang87a93302014-09-16 13:29:43 -04002323static bool ValidateDrawInstancedANGLE(Context *context)
2324{
2325 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002326 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04002327
Geoff Lang7dd2e102014-11-10 15:19:26 -05002328 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04002329
2330 const VertexArray *vao = state.getVertexArray();
Jamie Madill63805b42015-08-25 13:17:39 -04002331 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04002332 {
2333 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Jamie Madill63805b42015-08-25 13:17:39 -04002334 if (program->isAttribLocationActive(attributeIndex) && attrib.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04002335 {
2336 return true;
2337 }
2338 }
2339
Jamie Madill437fa652016-05-03 15:13:24 -04002340 context->handleError(Error(GL_INVALID_OPERATION,
2341 "ANGLE_instanced_arrays requires that at least one active attribute"
2342 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04002343 return false;
2344}
2345
2346bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
2347{
2348 if (!ValidateDrawInstancedANGLE(context))
2349 {
2350 return false;
2351 }
2352
2353 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
2354}
2355
Jamie Madillf25855c2015-11-03 11:06:18 -05002356bool ValidateDrawElements(ValidationContext *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002357 GLenum mode,
2358 GLsizei count,
2359 GLenum type,
2360 const GLvoid *indices,
2361 GLsizei primcount,
2362 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002363{
Jamie Madill250d33f2014-06-06 17:09:03 -04002364 switch (type)
2365 {
2366 case GL_UNSIGNED_BYTE:
2367 case GL_UNSIGNED_SHORT:
Martin Radev1be913c2016-07-11 17:59:16 +03002368 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002369 case GL_UNSIGNED_INT:
Martin Radev1be913c2016-07-11 17:59:16 +03002370 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2371 {
2372 context->handleError(Error(GL_INVALID_ENUM));
2373 return false;
2374 }
2375 break;
Jamie Madill250d33f2014-06-06 17:09:03 -04002376 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002377 context->handleError(Error(GL_INVALID_ENUM));
Martin Radev1be913c2016-07-11 17:59:16 +03002378 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002379 }
2380
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002381 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002382
2383 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Geoff Langbb0a0bb2015-03-27 12:16:57 -04002384 if (curTransformFeedback && curTransformFeedback->isActive() && !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002385 {
2386 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
2387 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002388 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002389 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002390 }
2391
2392 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002393 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002394 {
Jamie Madill437fa652016-05-03 15:13:24 -04002395 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002396 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002397 }
2398
Jamie Madill2b976812014-08-25 15:47:49 -04002399 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002400 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madill2b976812014-08-25 15:47:49 -04002401 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002402 {
Jamie Madill437fa652016-05-03 15:13:24 -04002403 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002404 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002405 }
2406
Jamie Madillae3000b2014-08-25 15:47:51 -04002407 if (elementArrayBuffer)
2408 {
2409 const gl::Type &typeInfo = gl::GetTypeInfo(type);
2410
2411 GLint64 offset = reinterpret_cast<GLint64>(indices);
2412 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
2413
2414 // check for integer overflows
2415 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
2416 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
2417 {
Jamie Madill437fa652016-05-03 15:13:24 -04002418 context->handleError(Error(GL_OUT_OF_MEMORY));
Geoff Langb1196682014-07-23 13:47:29 -04002419 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002420 }
2421
2422 // Check for reading past the end of the bound buffer object
2423 if (byteCount > elementArrayBuffer->getSize())
2424 {
Jamie Madill437fa652016-05-03 15:13:24 -04002425 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002426 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002427 }
2428 }
2429 else if (!indices)
2430 {
2431 // Catch this programming error here
Jamie Madill437fa652016-05-03 15:13:24 -04002432 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002433 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002434 }
2435
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002436 if (!ValidateDrawBase(context, mode, count, primcount))
2437 {
2438 return false;
2439 }
2440
Jamie Madill2b976812014-08-25 15:47:49 -04002441 // Use max index to validate if our vertex buffers are large enough for the pull.
2442 // TODO: offer fast path, with disabled index validation.
2443 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
2444 if (elementArrayBuffer)
2445 {
Jacek Cabana5521de2014-10-01 17:23:46 +02002446 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04002447 Error error =
2448 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
2449 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002450 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04002451 {
Jamie Madill437fa652016-05-03 15:13:24 -04002452 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04002453 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002454 }
2455 }
2456 else
2457 {
Geoff Lang3edfe032015-09-04 16:38:24 -04002458 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04002459 }
2460
Jamie Madille79b1e12015-11-04 16:36:37 -05002461 // If we use an index greater than our maximum supported index range, return an error.
2462 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2463 // return an error if possible here.
2464 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
2465 {
Jamie Madill437fa652016-05-03 15:13:24 -04002466 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05002467 return false;
2468 }
2469
Jamie Madillbc4c4bc2016-03-23 21:04:43 -04002470 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04002471 {
2472 return false;
2473 }
2474
Geoff Lang3edfe032015-09-04 16:38:24 -04002475 // No op if there are no real indices in the index data (all are primitive restart).
2476 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04002477}
2478
Geoff Langb1196682014-07-23 13:47:29 -04002479bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04002480 GLenum mode,
2481 GLsizei count,
2482 GLenum type,
2483 const GLvoid *indices,
2484 GLsizei primcount,
2485 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04002486{
2487 if (primcount < 0)
2488 {
Jamie Madill437fa652016-05-03 15:13:24 -04002489 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002490 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002491 }
2492
Jamie Madill2b976812014-08-25 15:47:49 -04002493 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04002494 {
2495 return false;
2496 }
2497
2498 // No-op zero primitive count
2499 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04002500}
2501
Geoff Lang3edfe032015-09-04 16:38:24 -04002502bool ValidateDrawElementsInstancedANGLE(Context *context,
2503 GLenum mode,
2504 GLsizei count,
2505 GLenum type,
2506 const GLvoid *indices,
2507 GLsizei primcount,
2508 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04002509{
2510 if (!ValidateDrawInstancedANGLE(context))
2511 {
2512 return false;
2513 }
2514
2515 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
2516}
2517
Geoff Langb1196682014-07-23 13:47:29 -04002518bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002519 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04002520{
Jamie Madill55ec3b12014-07-03 10:38:57 -04002521 if (!ValidFramebufferTarget(target))
2522 {
Jamie Madill437fa652016-05-03 15:13:24 -04002523 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002524 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002525 }
2526
2527 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04002528 {
2529 return false;
2530 }
2531
Jamie Madill55ec3b12014-07-03 10:38:57 -04002532 if (texture != 0)
2533 {
2534 gl::Texture *tex = context->getTexture(texture);
2535
2536 if (tex == NULL)
2537 {
Jamie Madill437fa652016-05-03 15:13:24 -04002538 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002539 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002540 }
2541
2542 if (level < 0)
2543 {
Jamie Madill437fa652016-05-03 15:13:24 -04002544 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002545 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002546 }
2547 }
2548
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002549 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04002550 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04002551
Jamie Madill84115c92015-04-23 15:00:07 -04002552 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002553 {
Jamie Madill437fa652016-05-03 15:13:24 -04002554 context->handleError(
2555 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002556 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002557 }
2558
2559 return true;
2560}
2561
Geoff Langb1196682014-07-23 13:47:29 -04002562bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04002563 GLenum textarget, GLuint texture, GLint level)
2564{
Geoff Lang95663912015-04-02 15:54:45 -04002565 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap extension
Martin Radev1be913c2016-07-11 17:59:16 +03002566 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
2567 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04002568 {
Jamie Madill437fa652016-05-03 15:13:24 -04002569 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002570 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002571 }
2572
2573 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04002574 {
2575 return false;
2576 }
2577
Jamie Madill55ec3b12014-07-03 10:38:57 -04002578 if (texture != 0)
2579 {
2580 gl::Texture *tex = context->getTexture(texture);
2581 ASSERT(tex);
2582
Jamie Madill2a6564e2014-07-11 09:53:19 -04002583 const gl::Caps &caps = context->getCaps();
2584
Jamie Madill55ec3b12014-07-03 10:38:57 -04002585 switch (textarget)
2586 {
2587 case GL_TEXTURE_2D:
2588 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002589 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002590 {
Jamie Madill437fa652016-05-03 15:13:24 -04002591 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002592 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002593 }
2594 if (tex->getTarget() != GL_TEXTURE_2D)
2595 {
Jamie Madill437fa652016-05-03 15:13:24 -04002596 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002597 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002598 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002599 }
2600 break;
2601
2602 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2603 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2604 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2605 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2606 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2607 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2608 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04002609 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04002610 {
Jamie Madill437fa652016-05-03 15:13:24 -04002611 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002612 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002613 }
2614 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
2615 {
Jamie Madill437fa652016-05-03 15:13:24 -04002616 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002617 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002618 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002619 }
2620 break;
2621
2622 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002623 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002624 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04002625 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05002626
Jamie Madilla3944d42016-07-22 22:13:26 -04002627 const Format &format = tex->getFormat(textarget, level);
2628 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05002629 {
Jamie Madill437fa652016-05-03 15:13:24 -04002630 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002631 return false;
2632 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04002633 }
2634
Jamie Madill570f7c82014-07-03 10:38:54 -04002635 return true;
2636}
2637
Geoff Langb1196682014-07-23 13:47:29 -04002638bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04002639{
2640 if (program == 0)
2641 {
Jamie Madill437fa652016-05-03 15:13:24 -04002642 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002643 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002644 }
2645
Dian Xiang769769a2015-09-09 15:20:08 -07002646 gl::Program *programObject = GetValidProgram(context, program);
2647 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05002648 {
2649 return false;
2650 }
2651
Jamie Madill0063c512014-08-25 15:47:53 -04002652 if (!programObject || !programObject->isLinked())
2653 {
Jamie Madill437fa652016-05-03 15:13:24 -04002654 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002655 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002656 }
2657
Geoff Lang7dd2e102014-11-10 15:19:26 -05002658 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04002659 {
Jamie Madill437fa652016-05-03 15:13:24 -04002660 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002661 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04002662 }
2663
Jamie Madill0063c512014-08-25 15:47:53 -04002664 return true;
2665}
2666
Geoff Langb1196682014-07-23 13:47:29 -04002667bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04002668{
2669 return ValidateGetUniformBase(context, program, location);
2670}
2671
Geoff Langb1196682014-07-23 13:47:29 -04002672bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002673{
Jamie Madill78f41802014-08-25 15:47:55 -04002674 return ValidateGetUniformBase(context, program, location);
2675}
2676
Geoff Langf41d0ee2016-10-07 13:04:23 -04002677static bool ValidateSizedGetUniform(Context *context,
2678 GLuint program,
2679 GLint location,
2680 GLsizei bufSize,
2681 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04002682{
Geoff Langf41d0ee2016-10-07 13:04:23 -04002683 if (length)
2684 {
2685 *length = 0;
2686 }
2687
Jamie Madill78f41802014-08-25 15:47:55 -04002688 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04002689 {
Jamie Madill78f41802014-08-25 15:47:55 -04002690 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002691 }
2692
Geoff Langf41d0ee2016-10-07 13:04:23 -04002693 if (bufSize < 0)
2694 {
2695 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
2696 return false;
2697 }
2698
Jamie Madilla502c742014-08-28 17:19:13 -04002699 gl::Program *programObject = context->getProgram(program);
2700 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04002701
Jamie Madill78f41802014-08-25 15:47:55 -04002702 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04002703 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
2704 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04002705 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04002706 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04002707 context->handleError(
2708 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04002709 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04002710 }
2711
Geoff Langf41d0ee2016-10-07 13:04:23 -04002712 if (length)
2713 {
2714 // Cast is safe because of comparison to bufSize.
2715 *length = static_cast<GLsizei>(requiredBytes);
2716 }
2717
Jamie Madill0063c512014-08-25 15:47:53 -04002718 return true;
2719}
2720
Geoff Langb1196682014-07-23 13:47:29 -04002721bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002722{
Geoff Langf41d0ee2016-10-07 13:04:23 -04002723 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04002724}
2725
Geoff Langb1196682014-07-23 13:47:29 -04002726bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04002727{
Geoff Langf41d0ee2016-10-07 13:04:23 -04002728 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
2729}
2730
2731bool ValidateGetUniformfvRobustANGLE(Context *context,
2732 GLuint program,
2733 GLint location,
2734 GLsizei bufSize,
2735 GLsizei *length,
2736 GLfloat *params)
2737{
2738 if (!ValidateRobustEntryPoint(context, bufSize))
2739 {
2740 return false;
2741 }
2742
2743 // bufSize is validated in ValidateSizedGetUniform
2744 return ValidateSizedGetUniform(context, program, location, bufSize, length);
2745}
2746
2747bool ValidateGetUniformivRobustANGLE(Context *context,
2748 GLuint program,
2749 GLint location,
2750 GLsizei bufSize,
2751 GLsizei *length,
2752 GLint *params)
2753{
2754 if (!ValidateRobustEntryPoint(context, bufSize))
2755 {
2756 return false;
2757 }
2758
2759 // bufSize is validated in ValidateSizedGetUniform
2760 return ValidateSizedGetUniform(context, program, location, bufSize, length);
2761}
2762
2763bool ValidateGetUniformuivRobustANGLE(Context *context,
2764 GLuint program,
2765 GLint location,
2766 GLsizei bufSize,
2767 GLsizei *length,
2768 GLuint *params)
2769{
2770 if (!ValidateRobustEntryPoint(context, bufSize))
2771 {
2772 return false;
2773 }
2774
2775 if (context->getClientMajorVersion() < 3)
2776 {
2777 context->handleError(
2778 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
2779 return false;
2780 }
2781
2782 // bufSize is validated in ValidateSizedGetUniform
2783 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04002784}
2785
Austin Kinross08332632015-05-05 13:35:47 -07002786bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,
2787 const GLenum *attachments, bool defaultFramebuffer)
2788{
2789 if (numAttachments < 0)
2790 {
Jamie Madill437fa652016-05-03 15:13:24 -04002791 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07002792 return false;
2793 }
2794
2795 for (GLsizei i = 0; i < numAttachments; ++i)
2796 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02002797 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07002798 {
2799 if (defaultFramebuffer)
2800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(Error(
2802 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002803 return false;
2804 }
2805
2806 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
2807 {
Jamie Madill437fa652016-05-03 15:13:24 -04002808 context->handleError(Error(GL_INVALID_OPERATION,
2809 "Requested color attachment is greater than the maximum "
2810 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07002811 return false;
2812 }
2813 }
2814 else
2815 {
2816 switch (attachments[i])
2817 {
2818 case GL_DEPTH_ATTACHMENT:
2819 case GL_STENCIL_ATTACHMENT:
2820 case GL_DEPTH_STENCIL_ATTACHMENT:
2821 if (defaultFramebuffer)
2822 {
Jamie Madill437fa652016-05-03 15:13:24 -04002823 context->handleError(
2824 Error(GL_INVALID_ENUM,
2825 "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002826 return false;
2827 }
2828 break;
2829 case GL_COLOR:
2830 case GL_DEPTH:
2831 case GL_STENCIL:
2832 if (!defaultFramebuffer)
2833 {
Jamie Madill437fa652016-05-03 15:13:24 -04002834 context->handleError(
2835 Error(GL_INVALID_ENUM,
2836 "Invalid attachment when the default framebuffer is not bound"));
Austin Kinross08332632015-05-05 13:35:47 -07002837 return false;
2838 }
2839 break;
2840 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002841 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07002842 return false;
2843 }
2844 }
2845 }
2846
2847 return true;
2848}
2849
Austin Kinross6ee1e782015-05-29 17:05:37 -07002850bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
2851{
2852 // Note that debug marker calls must not set error state
2853
2854 if (length < 0)
2855 {
2856 return false;
2857 }
2858
2859 if (marker == nullptr)
2860 {
2861 return false;
2862 }
2863
2864 return true;
2865}
2866
2867bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
2868{
2869 // Note that debug marker calls must not set error state
2870
2871 if (length < 0)
2872 {
2873 return false;
2874 }
2875
2876 if (length > 0 && marker == nullptr)
2877 {
2878 return false;
2879 }
2880
2881 return true;
2882}
2883
Geoff Langdcab33b2015-07-21 13:03:16 -04002884bool ValidateEGLImageTargetTexture2DOES(Context *context,
2885 egl::Display *display,
2886 GLenum target,
2887 egl::Image *image)
2888{
Geoff Langa8406172015-07-21 16:53:39 -04002889 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
2890 {
Jamie Madill437fa652016-05-03 15:13:24 -04002891 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002892 return false;
2893 }
2894
2895 switch (target)
2896 {
2897 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04002898 if (!context->getExtensions().eglImage)
2899 {
2900 context->handleError(Error(
2901 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
2902 }
2903 break;
2904
2905 case GL_TEXTURE_EXTERNAL_OES:
2906 if (!context->getExtensions().eglImageExternal)
2907 {
2908 context->handleError(Error(
2909 GL_INVALID_ENUM,
2910 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
2911 }
Geoff Langa8406172015-07-21 16:53:39 -04002912 break;
2913
2914 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002915 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04002916 return false;
2917 }
2918
2919 if (!display->isValidImage(image))
2920 {
Jamie Madill437fa652016-05-03 15:13:24 -04002921 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002922 return false;
2923 }
2924
2925 if (image->getSamples() > 0)
2926 {
Jamie Madill437fa652016-05-03 15:13:24 -04002927 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002928 "cannot create a 2D texture from a multisampled EGL image."));
2929 return false;
2930 }
2931
Jamie Madilla3944d42016-07-22 22:13:26 -04002932 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002933 if (!textureCaps.texturable)
2934 {
Jamie Madill437fa652016-05-03 15:13:24 -04002935 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04002936 "EGL image internal format is not supported as a texture."));
2937 return false;
2938 }
2939
Geoff Langdcab33b2015-07-21 13:03:16 -04002940 return true;
2941}
2942
2943bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
2944 egl::Display *display,
2945 GLenum target,
2946 egl::Image *image)
2947{
Geoff Langa8406172015-07-21 16:53:39 -04002948 if (!context->getExtensions().eglImage)
2949 {
Jamie Madill437fa652016-05-03 15:13:24 -04002950 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04002951 return false;
2952 }
2953
2954 switch (target)
2955 {
2956 case GL_RENDERBUFFER:
2957 break;
2958
2959 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002960 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04002961 return false;
2962 }
2963
2964 if (!display->isValidImage(image))
2965 {
Jamie Madill437fa652016-05-03 15:13:24 -04002966 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04002967 return false;
2968 }
2969
Jamie Madilla3944d42016-07-22 22:13:26 -04002970 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04002971 if (!textureCaps.renderable)
2972 {
Jamie Madill437fa652016-05-03 15:13:24 -04002973 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04002974 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
2975 return false;
2976 }
2977
Geoff Langdcab33b2015-07-21 13:03:16 -04002978 return true;
2979}
Austin Kinrossbc781f32015-10-26 09:27:38 -07002980
2981bool ValidateBindVertexArrayBase(Context *context, GLuint array)
2982{
Geoff Lang36167ab2015-12-07 10:27:14 -05002983 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07002984 {
2985 // The default VAO should always exist
2986 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04002987 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07002988 return false;
2989 }
2990
2991 return true;
2992}
2993
Olli Etuahoc3e55a42016-03-09 16:29:18 +02002994bool ValidateLinkProgram(Context *context, GLuint program)
2995{
2996 if (context->hasActiveTransformFeedback(program))
2997 {
2998 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04002999 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003000 "Cannot link program while program is associated with an active "
3001 "transform feedback object."));
3002 return false;
3003 }
3004 return true;
3005}
3006
Geoff Langc5629752015-12-07 16:29:04 -05003007bool ValidateProgramBinaryBase(Context *context,
3008 GLuint program,
3009 GLenum binaryFormat,
3010 const void *binary,
3011 GLint length)
3012{
3013 Program *programObject = GetValidProgram(context, program);
3014 if (programObject == nullptr)
3015 {
3016 return false;
3017 }
3018
3019 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3020 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3021 programBinaryFormats.end())
3022 {
Jamie Madill437fa652016-05-03 15:13:24 -04003023 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05003024 return false;
3025 }
3026
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003027 if (context->hasActiveTransformFeedback(program))
3028 {
3029 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04003030 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003031 "Cannot change program binary while program is associated with "
3032 "an active transform feedback object."));
3033 return false;
3034 }
3035
Geoff Langc5629752015-12-07 16:29:04 -05003036 return true;
3037}
3038
3039bool ValidateGetProgramBinaryBase(Context *context,
3040 GLuint program,
3041 GLsizei bufSize,
3042 GLsizei *length,
3043 GLenum *binaryFormat,
3044 void *binary)
3045{
3046 Program *programObject = GetValidProgram(context, program);
3047 if (programObject == nullptr)
3048 {
3049 return false;
3050 }
3051
3052 if (!programObject->isLinked())
3053 {
Jamie Madill437fa652016-05-03 15:13:24 -04003054 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05003055 return false;
3056 }
3057
3058 return true;
3059}
Jamie Madillc29968b2016-01-20 11:17:23 -05003060
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003061bool ValidateUseProgram(Context *context, GLuint program)
3062{
3063 if (program != 0)
3064 {
3065 Program *programObject = context->getProgram(program);
3066 if (!programObject)
3067 {
3068 // ES 3.1.0 section 7.3 page 72
3069 if (context->getShader(program))
3070 {
Jamie Madill437fa652016-05-03 15:13:24 -04003071 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003072 Error(GL_INVALID_OPERATION,
3073 "Attempted to use a single shader instead of a shader program."));
3074 return false;
3075 }
3076 else
3077 {
Jamie Madill437fa652016-05-03 15:13:24 -04003078 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003079 return false;
3080 }
3081 }
3082 if (!programObject->isLinked())
3083 {
Jamie Madill437fa652016-05-03 15:13:24 -04003084 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003085 return false;
3086 }
3087 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003088 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003089 {
3090 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04003091 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003092 Error(GL_INVALID_OPERATION,
3093 "Cannot change active program while transform feedback is unpaused."));
3094 return false;
3095 }
3096
3097 return true;
3098}
3099
Jamie Madillc29968b2016-01-20 11:17:23 -05003100bool ValidateCopyTexImage2D(ValidationContext *context,
3101 GLenum target,
3102 GLint level,
3103 GLenum internalformat,
3104 GLint x,
3105 GLint y,
3106 GLsizei width,
3107 GLsizei height,
3108 GLint border)
3109{
Martin Radev1be913c2016-07-11 17:59:16 +03003110 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05003111 {
3112 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
3113 0, x, y, width, height, border);
3114 }
3115
Martin Radev1be913c2016-07-11 17:59:16 +03003116 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05003117 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
3118 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003119}
Jamie Madillc29968b2016-01-20 11:17:23 -05003120
3121bool ValidateFramebufferRenderbuffer(Context *context,
3122 GLenum target,
3123 GLenum attachment,
3124 GLenum renderbuffertarget,
3125 GLuint renderbuffer)
3126{
3127 if (!ValidFramebufferTarget(target) ||
3128 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
3129 {
Jamie Madill437fa652016-05-03 15:13:24 -04003130 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05003131 return false;
3132 }
3133
3134 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
3135 renderbuffertarget, renderbuffer);
3136}
3137
3138bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
3139{
3140 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3141 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3142 {
Jamie Madill437fa652016-05-03 15:13:24 -04003143 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003144 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
3145 return false;
3146 }
3147
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003148 ASSERT(context->getGLState().getDrawFramebuffer());
3149 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05003150 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3151
3152 // This should come first before the check for the default frame buffer
3153 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3154 // rather than INVALID_OPERATION
3155 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3156 {
3157 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3158
3159 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02003160 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3161 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05003162 {
3163 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02003164 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3165 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3166 // 3.1 is still a bit ambiguous about the error, but future specs are
3167 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04003168 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02003169 return false;
3170 }
3171 else if (bufs[colorAttachment] >= maxColorAttachment)
3172 {
Jamie Madill437fa652016-05-03 15:13:24 -04003173 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02003174 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05003175 return false;
3176 }
3177 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3178 frameBufferId != 0)
3179 {
3180 // INVALID_OPERATION-GL is bound to buffer and ith argument
3181 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04003182 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003183 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
3184 return false;
3185 }
3186 }
3187
3188 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3189 // and n is not 1 or bufs is bound to value other than BACK and NONE
3190 if (frameBufferId == 0)
3191 {
3192 if (n != 1)
3193 {
Jamie Madill437fa652016-05-03 15:13:24 -04003194 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05003195 "n must be 1 when GL is bound to the default framebuffer"));
3196 return false;
3197 }
3198
3199 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3200 {
Jamie Madill437fa652016-05-03 15:13:24 -04003201 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05003202 GL_INVALID_OPERATION,
3203 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
3204 return false;
3205 }
3206 }
3207
3208 return true;
3209}
3210
3211bool ValidateCopyTexSubImage2D(Context *context,
3212 GLenum target,
3213 GLint level,
3214 GLint xoffset,
3215 GLint yoffset,
3216 GLint x,
3217 GLint y,
3218 GLsizei width,
3219 GLsizei height)
3220{
Martin Radev1be913c2016-07-11 17:59:16 +03003221 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05003222 {
3223 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
3224 yoffset, x, y, width, height, 0);
3225 }
3226
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05003227 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
3228 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05003229}
3230
Olli Etuaho4f667482016-03-30 15:56:35 +03003231bool ValidateGetBufferPointervBase(Context *context, GLenum target, GLenum pname, void **params)
3232{
3233 if (!ValidBufferTarget(context, target))
3234 {
Jamie Madill437fa652016-05-03 15:13:24 -04003235 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03003236 return false;
3237 }
3238
3239 if (pname != GL_BUFFER_MAP_POINTER)
3240 {
Jamie Madill437fa652016-05-03 15:13:24 -04003241 context->handleError(Error(GL_INVALID_ENUM, "pname not valid: 0x%X", pname));
Olli Etuaho4f667482016-03-30 15:56:35 +03003242 return false;
3243 }
3244
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003245 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003246
3247 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3248 // target bound to zero generate an INVALID_OPERATION error."
3249 // GLES 3.1 section 6.6 explicitly specifies this error.
3250 if (!buffer)
3251 {
Jamie Madill437fa652016-05-03 15:13:24 -04003252 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003253 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
3254 return false;
3255 }
3256
3257 return true;
3258}
3259
3260bool ValidateUnmapBufferBase(Context *context, GLenum target)
3261{
3262 if (!ValidBufferTarget(context, target))
3263 {
Jamie Madill437fa652016-05-03 15:13:24 -04003264 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003265 return false;
3266 }
3267
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003268 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003269
3270 if (buffer == nullptr || !buffer->isMapped())
3271 {
Jamie Madill437fa652016-05-03 15:13:24 -04003272 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003273 return false;
3274 }
3275
3276 return true;
3277}
3278
3279bool ValidateMapBufferRangeBase(Context *context,
3280 GLenum target,
3281 GLintptr offset,
3282 GLsizeiptr length,
3283 GLbitfield access)
3284{
3285 if (!ValidBufferTarget(context, target))
3286 {
Jamie Madill437fa652016-05-03 15:13:24 -04003287 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003288 return false;
3289 }
3290
3291 if (offset < 0 || length < 0)
3292 {
Jamie Madill437fa652016-05-03 15:13:24 -04003293 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003294 return false;
3295 }
3296
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003297 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003298
3299 if (!buffer)
3300 {
Jamie Madill437fa652016-05-03 15:13:24 -04003301 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003302 return false;
3303 }
3304
3305 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003306 CheckedNumeric<size_t> checkedOffset(offset);
3307 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003308
Jamie Madille2e406c2016-06-02 13:04:10 -04003309 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003310 {
Jamie Madill437fa652016-05-03 15:13:24 -04003311 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003312 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
3313 return false;
3314 }
3315
3316 // Check for invalid bits in the mask
3317 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3318 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3319 GL_MAP_UNSYNCHRONIZED_BIT;
3320
3321 if (access & ~(allAccessBits))
3322 {
Jamie Madill437fa652016-05-03 15:13:24 -04003323 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03003324 return false;
3325 }
3326
3327 if (length == 0)
3328 {
Jamie Madill437fa652016-05-03 15:13:24 -04003329 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003330 return false;
3331 }
3332
3333 if (buffer->isMapped())
3334 {
Jamie Madill437fa652016-05-03 15:13:24 -04003335 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003336 return false;
3337 }
3338
3339 // Check for invalid bit combinations
3340 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3341 {
Jamie Madill437fa652016-05-03 15:13:24 -04003342 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003343 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
3344 return false;
3345 }
3346
3347 GLbitfield writeOnlyBits =
3348 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3349
3350 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3351 {
Jamie Madill437fa652016-05-03 15:13:24 -04003352 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03003353 "Invalid access bits when mapping buffer for reading: 0x%X.",
3354 access));
3355 return false;
3356 }
3357
3358 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3359 {
Jamie Madill437fa652016-05-03 15:13:24 -04003360 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003361 GL_INVALID_OPERATION,
3362 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
3363 return false;
3364 }
3365 return true;
3366}
3367
3368bool ValidateFlushMappedBufferRangeBase(Context *context,
3369 GLenum target,
3370 GLintptr offset,
3371 GLsizeiptr length)
3372{
3373 if (offset < 0 || length < 0)
3374 {
Jamie Madill437fa652016-05-03 15:13:24 -04003375 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003376 return false;
3377 }
3378
3379 if (!ValidBufferTarget(context, target))
3380 {
Jamie Madill437fa652016-05-03 15:13:24 -04003381 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003382 return false;
3383 }
3384
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003385 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003386
3387 if (buffer == nullptr)
3388 {
Jamie Madill437fa652016-05-03 15:13:24 -04003389 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003390 return false;
3391 }
3392
3393 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3394 {
Jamie Madill437fa652016-05-03 15:13:24 -04003395 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003396 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
3397 return false;
3398 }
3399
3400 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003401 CheckedNumeric<size_t> checkedOffset(offset);
3402 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003403
Jamie Madille2e406c2016-06-02 13:04:10 -04003404 if (!checkedSize.IsValid() ||
3405 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003406 {
Jamie Madill437fa652016-05-03 15:13:24 -04003407 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003408 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3409 return false;
3410 }
3411
3412 return true;
3413}
3414
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003415bool ValidateGenerateMipmap(Context *context, GLenum target)
3416{
3417 if (!ValidTextureTarget(context, target))
3418 {
3419 context->handleError(Error(GL_INVALID_ENUM));
3420 return false;
3421 }
3422
3423 Texture *texture = context->getTargetTexture(target);
3424
3425 if (texture == nullptr)
3426 {
3427 context->handleError(Error(GL_INVALID_OPERATION));
3428 return false;
3429 }
3430
3431 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
3432
3433 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
3434 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
3435 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3436 {
3437 context->handleError(Error(GL_INVALID_OPERATION));
3438 return false;
3439 }
3440
Jamie Madilla3944d42016-07-22 22:13:26 -04003441 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
3442 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
3443 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003444
3445 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
3446 // unsized formats or that are color renderable and filterable. Since we do not track if
3447 // the texture was created with sized or unsized format (only sized formats are stored),
3448 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
3449 // be able to) because they aren't color renderable. Simply do a special case for LUMA
3450 // textures since they're the only texture format that can be created with unsized formats
3451 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
3452 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04003453 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
3454 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003455 {
3456 context->handleError(Error(GL_INVALID_OPERATION));
3457 return false;
3458 }
3459
3460 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04003461 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003462 {
3463 context->handleError(Error(GL_INVALID_OPERATION));
3464 return false;
3465 }
3466
3467 // Non-power of 2 ES2 check
3468 if (!context->getExtensions().textureNPOT &&
3469 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
3470 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
3471 {
Martin Radev1be913c2016-07-11 17:59:16 +03003472 ASSERT(context->getClientMajorVersion() <= 2 &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03003473 (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP));
3474 context->handleError(Error(GL_INVALID_OPERATION));
3475 return false;
3476 }
3477
3478 // Cube completeness check
3479 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
3480 {
3481 context->handleError(Error(GL_INVALID_OPERATION));
3482 return false;
3483 }
3484
3485 return true;
3486}
3487
Olli Etuaho41997e72016-03-10 13:38:39 +02003488bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
3489{
3490 return ValidateGenOrDelete(context, n);
3491}
3492
3493bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
3494{
3495 return ValidateGenOrDelete(context, n);
3496}
3497
3498bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
3499{
3500 return ValidateGenOrDelete(context, n);
3501}
3502
3503bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
3504{
3505 return ValidateGenOrDelete(context, n);
3506}
3507
3508bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
3509{
3510 return ValidateGenOrDelete(context, n);
3511}
3512
3513bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
3514{
3515 return ValidateGenOrDelete(context, n);
3516}
3517
3518bool ValidateGenTextures(Context *context, GLint n, GLuint *)
3519{
3520 return ValidateGenOrDelete(context, n);
3521}
3522
3523bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
3524{
3525 return ValidateGenOrDelete(context, n);
3526}
3527
3528bool ValidateGenOrDelete(Context *context, GLint n)
3529{
3530 if (n < 0)
3531 {
Jamie Madill437fa652016-05-03 15:13:24 -04003532 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003533 return false;
3534 }
3535 return true;
3536}
3537
Geoff Langf41a7152016-09-19 15:11:17 -04003538bool ValidateEnable(Context *context, GLenum cap)
3539{
3540 if (!ValidCap(context, cap, false))
3541 {
3542 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3543 return false;
3544 }
3545
3546 if (context->getLimitations().noSampleAlphaToCoverageSupport &&
3547 cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
3548 {
3549 const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
3550 context->handleError(Error(GL_INVALID_OPERATION, errorMessage));
3551
3552 // We also output an error message to the debugger window if tracing is active, so that
3553 // developers can see the error message.
3554 ERR("%s", errorMessage);
Geoff Langf41a7152016-09-19 15:11:17 -04003555 return false;
3556 }
3557
3558 return true;
3559}
3560
3561bool ValidateDisable(Context *context, GLenum cap)
3562{
3563 if (!ValidCap(context, cap, false))
3564 {
3565 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3566 return false;
3567 }
3568
3569 return true;
3570}
3571
3572bool ValidateIsEnabled(Context *context, GLenum cap)
3573{
3574 if (!ValidCap(context, cap, true))
3575 {
3576 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
3577 return false;
3578 }
3579
3580 return true;
3581}
3582
Geoff Langff5b2d52016-09-07 11:32:23 -04003583bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
3584{
3585 if (!context->getExtensions().robustClientMemory)
3586 {
3587 context->handleError(
3588 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
3589 return false;
3590 }
3591
3592 if (bufSize < 0)
3593 {
3594 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3595 return false;
3596 }
3597
3598 return true;
3599}
3600
3601bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context,
3602 GLenum target,
3603 GLenum attachment,
3604 GLenum pname,
3605 GLsizei *numParams)
3606{
3607 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
3608 *numParams = 1;
3609
3610 if (!ValidFramebufferTarget(target))
3611 {
3612 context->handleError(Error(GL_INVALID_ENUM));
3613 return false;
3614 }
3615
3616 int clientVersion = context->getClientMajorVersion();
3617
3618 switch (pname)
3619 {
3620 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3621 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3622 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3623 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3624 break;
3625
3626 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3627 if (clientVersion < 3 && !context->getExtensions().sRGB)
3628 {
3629 context->handleError(Error(GL_INVALID_ENUM));
3630 return false;
3631 }
3632 break;
3633
3634 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3635 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3636 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3637 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3638 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3639 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3640 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3641 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3642 if (clientVersion < 3)
3643 {
3644 context->handleError(Error(GL_INVALID_ENUM));
3645 return false;
3646 }
3647 break;
3648
3649 default:
3650 context->handleError(Error(GL_INVALID_ENUM));
3651 return false;
3652 }
3653
3654 // Determine if the attachment is a valid enum
3655 switch (attachment)
3656 {
3657 case GL_BACK:
3658 case GL_FRONT:
3659 case GL_DEPTH:
3660 case GL_STENCIL:
3661 case GL_DEPTH_STENCIL_ATTACHMENT:
3662 if (clientVersion < 3)
3663 {
3664 context->handleError(Error(GL_INVALID_ENUM));
3665 return false;
3666 }
3667 break;
3668
3669 case GL_DEPTH_ATTACHMENT:
3670 case GL_STENCIL_ATTACHMENT:
3671 break;
3672
3673 default:
3674 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
3675 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3676 {
3677 context->handleError(Error(GL_INVALID_ENUM));
3678 return false;
3679 }
3680 break;
3681 }
3682
3683 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
3684 ASSERT(framebuffer);
3685
3686 if (framebuffer->id() == 0)
3687 {
3688 if (clientVersion < 3)
3689 {
3690 context->handleError(Error(GL_INVALID_OPERATION));
3691 return false;
3692 }
3693
3694 switch (attachment)
3695 {
3696 case GL_BACK:
3697 case GL_DEPTH:
3698 case GL_STENCIL:
3699 break;
3700
3701 default:
3702 context->handleError(Error(GL_INVALID_OPERATION));
3703 return false;
3704 }
3705 }
3706 else
3707 {
3708 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3709 {
3710 // Valid attachment query
3711 }
3712 else
3713 {
3714 switch (attachment)
3715 {
3716 case GL_DEPTH_ATTACHMENT:
3717 case GL_STENCIL_ATTACHMENT:
3718 break;
3719
3720 case GL_DEPTH_STENCIL_ATTACHMENT:
3721 if (!framebuffer->hasValidDepthStencil())
3722 {
3723 context->handleError(Error(GL_INVALID_OPERATION));
3724 return false;
3725 }
3726 break;
3727
3728 default:
3729 context->handleError(Error(GL_INVALID_OPERATION));
3730 return false;
3731 }
3732 }
3733 }
3734
3735 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
3736 if (attachmentObject)
3737 {
3738 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
3739 attachmentObject->type() == GL_TEXTURE ||
3740 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
3741
3742 switch (pname)
3743 {
3744 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3745 if (attachmentObject->type() != GL_RENDERBUFFER &&
3746 attachmentObject->type() != GL_TEXTURE)
3747 {
3748 context->handleError(Error(GL_INVALID_ENUM));
3749 return false;
3750 }
3751 break;
3752
3753 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3754 if (attachmentObject->type() != GL_TEXTURE)
3755 {
3756 context->handleError(Error(GL_INVALID_ENUM));
3757 return false;
3758 }
3759 break;
3760
3761 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3762 if (attachmentObject->type() != GL_TEXTURE)
3763 {
3764 context->handleError(Error(GL_INVALID_ENUM));
3765 return false;
3766 }
3767 break;
3768
3769 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3770 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
3771 {
3772 context->handleError(Error(GL_INVALID_OPERATION));
3773 return false;
3774 }
3775 break;
3776
3777 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3778 if (attachmentObject->type() != GL_TEXTURE)
3779 {
3780 context->handleError(Error(GL_INVALID_ENUM));
3781 return false;
3782 }
3783 break;
3784
3785 default:
3786 break;
3787 }
3788 }
3789 else
3790 {
3791 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
3792 // is NONE, then querying any other pname will generate INVALID_ENUM.
3793
3794 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
3795 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
3796 // INVALID_OPERATION for all other pnames
3797
3798 switch (pname)
3799 {
3800 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3801 break;
3802
3803 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3804 if (clientVersion < 3)
3805 {
3806 context->handleError(Error(GL_INVALID_ENUM));
3807 return false;
3808 }
3809 break;
3810
3811 default:
3812 if (clientVersion < 3)
3813 {
3814 context->handleError(Error(GL_INVALID_ENUM));
3815 return false;
3816 }
3817 else
3818 {
3819 context->handleError(Error(GL_INVALID_OPERATION));
3820 return false;
3821 }
3822 }
3823 }
3824
3825 return true;
3826}
3827
3828bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
3829 GLenum target,
3830 GLenum attachment,
3831 GLenum pname,
3832 GLsizei bufSize,
3833 GLsizei *numParams)
3834{
3835 if (!ValidateRobustEntryPoint(context, bufSize))
3836 {
3837 return false;
3838 }
3839
3840 if (!ValidateGetFramebufferAttachmentParameteriv(context, target, attachment, pname, numParams))
3841 {
3842 return false;
3843 }
3844
3845 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
3846 {
3847 return false;
3848 }
3849
3850 return true;
3851}
3852
3853bool ValidateGetBufferParameteriv(ValidationContext *context,
3854 GLenum target,
3855 GLenum pname,
3856 GLsizei *numParams)
3857{
3858 // Initialize result
3859 *numParams = 0;
3860
3861 if (!ValidBufferTarget(context, target))
3862 {
3863 context->handleError(Error(GL_INVALID_ENUM));
3864 return false;
3865 }
3866
3867 if (!ValidBufferParameter(context, pname, numParams))
3868 {
3869 context->handleError(Error(GL_INVALID_ENUM));
3870 return false;
3871 }
3872
3873 if (context->getGLState().getTargetBuffer(target) == nullptr)
3874 {
3875 // A null buffer means that "0" is bound to the requested buffer target
3876 context->handleError(Error(GL_INVALID_OPERATION));
3877 return false;
3878 }
3879
3880 return true;
3881}
3882
3883bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
3884 GLenum target,
3885 GLenum pname,
3886 GLsizei bufSize,
3887 GLsizei *numParams)
3888{
3889 if (!ValidateRobustEntryPoint(context, bufSize))
3890 {
3891 return false;
3892 }
3893
3894 if (!ValidateGetBufferParameteriv(context, target, pname, numParams))
3895 {
3896 return false;
3897 }
3898
3899 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
3900 {
3901 return false;
3902 }
3903
3904 return true;
3905}
3906
3907bool ValidateGetProgramiv(Context *context, GLuint program, GLenum pname, GLsizei *numParams)
3908{
3909 // Currently, all GetProgramiv queries return 1 parameter
3910 *numParams = 1;
3911
3912 Program *programObject = GetValidProgram(context, program);
3913 if (!programObject)
3914 {
3915 return false;
3916 }
3917
3918 switch (pname)
3919 {
3920 case GL_DELETE_STATUS:
3921 case GL_LINK_STATUS:
3922 case GL_VALIDATE_STATUS:
3923 case GL_INFO_LOG_LENGTH:
3924 case GL_ATTACHED_SHADERS:
3925 case GL_ACTIVE_ATTRIBUTES:
3926 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
3927 case GL_ACTIVE_UNIFORMS:
3928 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
3929 break;
3930
3931 case GL_PROGRAM_BINARY_LENGTH:
3932 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
3933 {
3934 context->handleError(Error(GL_INVALID_ENUM,
3935 "Querying GL_PROGRAM_BINARY_LENGTH requires "
3936 "GL_OES_get_program_binary or ES 3.0."));
3937 return false;
3938 }
3939 break;
3940
3941 case GL_ACTIVE_UNIFORM_BLOCKS:
3942 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
3943 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
3944 case GL_TRANSFORM_FEEDBACK_VARYINGS:
3945 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
3946 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
3947 if (context->getClientMajorVersion() < 3)
3948 {
3949 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
3950 return false;
3951 }
3952 break;
3953
3954 default:
3955 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
3956 return false;
3957 }
3958
3959 return true;
3960}
3961
3962bool ValidateGetProgramivRobustANGLE(Context *context,
3963 GLuint program,
3964 GLenum pname,
3965 GLsizei bufSize,
3966 GLsizei *numParams)
3967{
3968 if (!ValidateRobustEntryPoint(context, bufSize))
3969 {
3970 return false;
3971 }
3972
3973 if (!ValidateGetProgramiv(context, program, pname, numParams))
3974 {
3975 return false;
3976 }
3977
3978 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
3979 {
3980 return false;
3981 }
3982
3983 return true;
3984}
3985
Geoff Lang740d9022016-10-07 11:20:52 -04003986bool ValidateGetRenderbufferParameteriv(Context *context,
3987 GLenum target,
3988 GLenum pname,
3989 GLint *params)
3990{
3991 return ValidateGetRenderbufferParameterivBase(context, target, pname, nullptr);
3992}
3993
3994bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
3995 GLenum target,
3996 GLenum pname,
3997 GLsizei bufSize,
3998 GLsizei *length,
3999 GLint *params)
4000{
4001 if (!ValidateRobustEntryPoint(context, bufSize))
4002 {
4003 return false;
4004 }
4005
4006 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
4007 {
4008 return false;
4009 }
4010
4011 if (!ValidateRobustBufferSize(context, bufSize, *length))
4012 {
4013 return false;
4014 }
4015
4016 return true;
4017}
4018
Geoff Langd7d0ed32016-10-07 11:33:51 -04004019bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params)
4020{
4021 return ValidateGetShaderivBase(context, shader, pname, nullptr);
4022}
4023
4024bool ValidateGetShaderivRobustANGLE(Context *context,
4025 GLuint shader,
4026 GLenum pname,
4027 GLsizei bufSize,
4028 GLsizei *length,
4029 GLint *params)
4030{
4031 if (!ValidateRobustEntryPoint(context, bufSize))
4032 {
4033 return false;
4034 }
4035
4036 if (!ValidateGetShaderivBase(context, shader, pname, length))
4037 {
4038 return false;
4039 }
4040
4041 if (!ValidateRobustBufferSize(context, bufSize, *length))
4042 {
4043 return false;
4044 }
4045
4046 return true;
4047}
4048
Jamie Madillc29968b2016-01-20 11:17:23 -05004049} // namespace gl