blob: 348f4ad26a983f1c925a8e5eadd21d10e43f119c [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{
Corentin Wallez92db6942016-12-09 13:10:36 -050037bool ValidateDrawAttribs(ValidationContext *context,
38 GLint primcount,
39 GLint maxVertex,
40 GLint vertexCount)
Jamie Madill1ca74672015-07-21 15:14:11 -040041{
Jamie Madilldfde6ab2016-06-09 07:07:18 -070042 const gl::State &state = context->getGLState();
Jamie Madill1ca74672015-07-21 15:14:11 -040043 const gl::Program *program = state.getProgram();
44
Corentin Wallez327411e2016-12-09 11:09:17 -050045 bool webglCompatibility = context->getExtensions().webglCompatibility;
46
He Yunchaoced53ae2016-11-29 15:00:51 +080047 const VertexArray *vao = state.getVertexArray();
48 const auto &vertexAttribs = vao->getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +080049 const auto &vertexBindings = vao->getVertexBindings();
He Yunchaoced53ae2016-11-29 15:00:51 +080050 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
Jamie Madill1ca74672015-07-21 15:14:11 -040051 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
52 {
53 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Corentin Wallezfd456442016-12-21 17:57:00 -050054 if (!program->isAttribLocationActive(attributeIndex) || !attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040055 {
Corentin Wallezfd456442016-12-21 17:57:00 -050056 continue;
57 }
Jamie Madill1ca74672015-07-21 15:14:11 -040058
Jiawei-Shao2597fb62016-12-09 16:38:02 +080059 const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
Corentin Wallezfd456442016-12-21 17:57:00 -050060 // If we have no buffer, then we either get an error, or there are no more checks to be done.
Jiawei-Shao2597fb62016-12-09 16:38:02 +080061 gl::Buffer *buffer = binding.buffer.get();
Corentin Wallezfd456442016-12-21 17:57:00 -050062 if (!buffer)
63 {
Geoff Langfeb8c682017-02-13 16:07:35 -050064 if (webglCompatibility || !state.areClientArraysEnabled())
Corentin Wallez327411e2016-12-09 11:09:17 -050065 {
66 // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
Corentin Wallezfd456442016-12-21 17:57:00 -050067 // If a vertex attribute is enabled as an array via enableVertexAttribArray but
68 // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer,
69 // then calls to drawArrays or drawElements will generate an INVALID_OPERATION
70 // error.
Corentin Wallez327411e2016-12-09 11:09:17 -050071 context->handleError(
72 Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer."));
Corentin Wallezfd456442016-12-21 17:57:00 -050073 return false;
Corentin Wallez327411e2016-12-09 11:09:17 -050074 }
Corentin Wallezfd456442016-12-21 17:57:00 -050075 else if (attrib.pointer == nullptr)
Jamie Madill1ca74672015-07-21 15:14:11 -040076 {
77 // This is an application error that would normally result in a crash,
78 // but we catch it and return an error
Corentin Wallezfd456442016-12-21 17:57:00 -050079 context->handleError(
80 Error(GL_INVALID_OPERATION,
81 "An enabled vertex array has no buffer and no pointer."));
Jamie Madill1ca74672015-07-21 15:14:11 -040082 return false;
83 }
Corentin Wallezfd456442016-12-21 17:57:00 -050084 continue;
85 }
86
87 // If we're drawing zero vertices, we have enough data.
88 if (vertexCount <= 0 || primcount <= 0)
89 {
90 continue;
91 }
92
93 GLint maxVertexElement = 0;
Jiawei-Shao2597fb62016-12-09 16:38:02 +080094 if (binding.divisor == 0)
Corentin Wallezfd456442016-12-21 17:57:00 -050095 {
96 maxVertexElement = maxVertex;
97 }
98 else
99 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800100 maxVertexElement = (primcount - 1) / binding.divisor;
Corentin Wallezfd456442016-12-21 17:57:00 -0500101 }
102
103 // We do manual overflow checks here instead of using safe_math.h because it was
104 // a bottleneck. Thanks to some properties of GL we know inequalities that can
105 // help us make the overflow checks faster.
106
107 // The max possible attribSize is 16 for a vector of 4 32 bit values.
108 constexpr uint64_t kMaxAttribSize = 16;
109 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
110 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
111
112 // We know attribStride is given as a GLsizei which is typedefed to int.
113 // We also know an upper bound for attribSize.
114 static_assert(std::is_same<int, GLsizei>::value, "");
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800115 uint64_t attribStride = ComputeVertexAttributeStride(attrib, binding);
Corentin Wallezfd456442016-12-21 17:57:00 -0500116 uint64_t attribSize = ComputeVertexAttributeTypeSize(attrib);
117 ASSERT(attribStride <= kIntMax && attribSize <= kMaxAttribSize);
118
119 // Computing the max offset using uint64_t without attrib.offset is overflow
120 // safe. Note: Last vertex element does not take the full stride!
121 static_assert(kIntMax * kIntMax < kUint64Max - kMaxAttribSize, "");
122 uint64_t attribDataSizeNoOffset = maxVertexElement * attribStride + attribSize;
123
124 // An overflow can happen when adding the offset, check for it.
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800125 uint64_t attribOffset = ComputeVertexAttributeOffset(attrib, binding);
126 if (attribDataSizeNoOffset > kUint64Max - attribOffset)
Corentin Wallezfd456442016-12-21 17:57:00 -0500127 {
128 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
129 return false;
130 }
131 uint64_t attribDataSizeWithOffset = attribDataSizeNoOffset + attribOffset;
132
133 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
134 // We can return INVALID_OPERATION if our vertex attribute does not have
135 // enough backing data.
136 if (attribDataSizeWithOffset > static_cast<uint64_t>(buffer->getSize()))
137 {
138 context->handleError(Error(GL_INVALID_OPERATION,
139 "Vertex buffer is not big enough for the draw call"));
140 return false;
Jamie Madill1ca74672015-07-21 15:14:11 -0400141 }
142 }
143
144 return true;
145}
146
Geoff Langf607c602016-09-21 11:46:48 -0400147bool ValidReadPixelsFormatType(ValidationContext *context,
148 GLenum framebufferComponentType,
149 GLenum format,
150 GLenum type)
151{
152 switch (framebufferComponentType)
153 {
154 case GL_UNSIGNED_NORMALIZED:
155 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
156 // ReadPixels with BGRA even if the extension is not present
157 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
158 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
159 type == GL_UNSIGNED_BYTE);
160
161 case GL_SIGNED_NORMALIZED:
162 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
163
164 case GL_INT:
165 return (format == GL_RGBA_INTEGER && type == GL_INT);
166
167 case GL_UNSIGNED_INT:
168 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
169
170 case GL_FLOAT:
171 return (format == GL_RGBA && type == GL_FLOAT);
172
173 default:
174 UNREACHABLE();
175 return false;
176 }
177}
178
Geoff Langf41a7152016-09-19 15:11:17 -0400179bool ValidCap(const Context *context, GLenum cap, bool queryOnly)
Geoff Lang0550d032014-01-30 11:29:07 -0500180{
181 switch (cap)
182 {
Geoff Langf41a7152016-09-19 15:11:17 -0400183 // EXT_multisample_compatibility
184 case GL_MULTISAMPLE_EXT:
185 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
186 return context->getExtensions().multisampleCompatibility;
Sami Väisänen74c23472016-05-09 17:30:30 +0300187
Geoff Langf41a7152016-09-19 15:11:17 -0400188 case GL_CULL_FACE:
189 case GL_POLYGON_OFFSET_FILL:
190 case GL_SAMPLE_ALPHA_TO_COVERAGE:
191 case GL_SAMPLE_COVERAGE:
192 case GL_SCISSOR_TEST:
193 case GL_STENCIL_TEST:
194 case GL_DEPTH_TEST:
195 case GL_BLEND:
196 case GL_DITHER:
197 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500198
Geoff Langf41a7152016-09-19 15:11:17 -0400199 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
200 case GL_RASTERIZER_DISCARD:
201 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500202
Geoff Langf41a7152016-09-19 15:11:17 -0400203 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
204 case GL_DEBUG_OUTPUT:
205 return context->getExtensions().debug;
Geoff Lang70d0f492015-12-10 17:45:46 -0500206
Geoff Langf41a7152016-09-19 15:11:17 -0400207 case GL_BIND_GENERATES_RESOURCE_CHROMIUM:
208 return queryOnly && context->getExtensions().bindGeneratesResource;
209
Geoff Langfeb8c682017-02-13 16:07:35 -0500210 case GL_CLIENT_ARRAYS_ANGLE:
211 return queryOnly && context->getExtensions().clientArrays;
212
Geoff Lang1d2c41d2016-10-19 16:14:46 -0700213 case GL_FRAMEBUFFER_SRGB_EXT:
214 return context->getExtensions().sRGBWriteControl;
215
Geoff Lang3b573612016-10-31 14:08:10 -0400216 case GL_SAMPLE_MASK:
Geoff Lang3b573612016-10-31 14:08:10 -0400217 return context->getClientVersion() >= Version(3, 1);
218
Jamie Madille08a1d32017-03-07 17:24:06 -0500219 case GL_CONTEXT_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
220 return queryOnly && context->getExtensions().robustResourceInitialization;
221
Geoff Langf41a7152016-09-19 15:11:17 -0400222 default:
223 return false;
Geoff Lang0550d032014-01-30 11:29:07 -0500224 }
225}
226
Geoff Lang62fce5b2016-09-30 10:46:35 -0400227bool ValidateReadPixelsBase(ValidationContext *context,
228 GLint x,
229 GLint y,
230 GLsizei width,
231 GLsizei height,
232 GLenum format,
233 GLenum type,
234 GLsizei bufSize,
235 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -0400236 GLsizei *columns,
237 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -0400238 GLvoid *pixels)
239{
240 if (length != nullptr)
241 {
242 *length = 0;
243 }
Geoff Lange93daba2017-03-30 13:54:40 -0400244 if (rows != nullptr)
245 {
246 *rows = 0;
247 }
248 if (columns != nullptr)
249 {
250 *columns = 0;
251 }
Geoff Lang62fce5b2016-09-30 10:46:35 -0400252
253 if (width < 0 || height < 0)
254 {
255 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
256 return false;
257 }
258
259 auto readFramebuffer = context->getGLState().getReadFramebuffer();
260
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400261 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400262 {
263 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
264 return false;
265 }
266
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400267 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400268 {
269 context->handleError(Error(GL_INVALID_OPERATION));
270 return false;
271 }
272
273 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
274 ASSERT(framebuffer);
275
276 if (framebuffer->getReadBufferState() == GL_NONE)
277 {
278 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
279 return false;
280 }
281
282 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
Corentin Wallez3c90ed62016-12-16 16:19:28 -0500283 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
284 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
285 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
286 // situation is an application error that would lead to a crash in ANGLE.
287 if (readBuffer == nullptr)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400288 {
Corentin Wallez3c90ed62016-12-16 16:19:28 -0500289 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
Geoff Lang62fce5b2016-09-30 10:46:35 -0400290 return false;
291 }
292
293 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
294 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langca271392017-04-05 12:30:00 -0400295 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
Geoff Lang62fce5b2016-09-30 10:46:35 -0400296
Geoff Lang62fce5b2016-09-30 10:46:35 -0400297 bool validFormatTypeCombination =
Geoff Langca271392017-04-05 12:30:00 -0400298 ValidReadPixelsFormatType(context, currentComponentType, format, type);
Geoff Lang62fce5b2016-09-30 10:46:35 -0400299
300 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
301 {
302 context->handleError(Error(GL_INVALID_OPERATION));
303 return false;
304 }
305
306 // Check for pixel pack buffer related API errors
307 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
308 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
309 {
310 // ...the buffer object's data store is currently mapped.
311 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
312 return false;
313 }
314
315 // .. the data would be packed to the buffer object such that the memory writes required
316 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -0400317 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
Geoff Lang62fce5b2016-09-30 10:46:35 -0400318 const gl::Extents size(width, height, 1);
319 const auto &pack = context->getGLState().getPackState();
320
321 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
322 if (endByteOrErr.isError())
323 {
324 context->handleError(endByteOrErr.getError());
325 return false;
326 }
327
328 size_t endByte = endByteOrErr.getResult();
329 if (bufSize >= 0)
330 {
Geoff Lange93daba2017-03-30 13:54:40 -0400331 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400332 {
333 context->handleError(
334 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
335 return false;
336 }
337 }
338
339 if (pixelPackBuffer != nullptr)
340 {
341 CheckedNumeric<size_t> checkedEndByte(endByte);
342 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
343 checkedEndByte += checkedOffset;
344
345 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
346 {
347 // Overflow past the end of the buffer
348 context->handleError(
349 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
350 return false;
351 }
352 }
353
Geoff Lange93daba2017-03-30 13:54:40 -0400354 if (pixelPackBuffer == nullptr && length != nullptr)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400355 {
356 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
357 {
358 context->handleError(
359 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
360 return false;
361 }
362
363 *length = static_cast<GLsizei>(endByte);
364 }
365
Geoff Lange93daba2017-03-30 13:54:40 -0400366 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
367 angle::CheckedNumeric<int> clippedExtent(length);
368 if (start < 0)
369 {
370 // "subtract" the area that is less than 0
371 clippedExtent += start;
372 }
373
374 const int readExtent = start + length;
375 if (readExtent > bufferSize)
376 {
377 // Subtract the region to the right of the read buffer
378 clippedExtent -= (readExtent - bufferSize);
379 }
380
381 if (!clippedExtent.IsValid())
382 {
383 return 0;
384 }
385
386 return std::max(clippedExtent.ValueOrDie(), 0);
387 };
388
389 if (columns != nullptr)
390 {
391 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
392 }
393
394 if (rows != nullptr)
395 {
396 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
397 }
398
Geoff Lang62fce5b2016-09-30 10:46:35 -0400399 return true;
400}
401
Geoff Lang740d9022016-10-07 11:20:52 -0400402bool ValidateGetRenderbufferParameterivBase(Context *context,
403 GLenum target,
404 GLenum pname,
405 GLsizei *length)
406{
407 if (length)
408 {
409 *length = 0;
410 }
411
412 if (target != GL_RENDERBUFFER)
413 {
414 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
415 return false;
416 }
417
418 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
419 if (renderbuffer == nullptr)
420 {
421 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
422 return false;
423 }
424
425 switch (pname)
426 {
427 case GL_RENDERBUFFER_WIDTH:
428 case GL_RENDERBUFFER_HEIGHT:
429 case GL_RENDERBUFFER_INTERNAL_FORMAT:
430 case GL_RENDERBUFFER_RED_SIZE:
431 case GL_RENDERBUFFER_GREEN_SIZE:
432 case GL_RENDERBUFFER_BLUE_SIZE:
433 case GL_RENDERBUFFER_ALPHA_SIZE:
434 case GL_RENDERBUFFER_DEPTH_SIZE:
435 case GL_RENDERBUFFER_STENCIL_SIZE:
436 break;
437
438 case GL_RENDERBUFFER_SAMPLES_ANGLE:
439 if (!context->getExtensions().framebufferMultisample)
440 {
441 context->handleError(
442 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
443 return false;
444 }
445 break;
446
447 default:
448 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
449 return false;
450 }
451
452 if (length)
453 {
454 *length = 1;
455 }
456 return true;
457}
458
Geoff Langd7d0ed32016-10-07 11:33:51 -0400459bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
460{
461 if (length)
462 {
463 *length = 0;
464 }
465
466 if (GetValidShader(context, shader) == nullptr)
467 {
468 return false;
469 }
470
471 switch (pname)
472 {
473 case GL_SHADER_TYPE:
474 case GL_DELETE_STATUS:
475 case GL_COMPILE_STATUS:
476 case GL_INFO_LOG_LENGTH:
477 case GL_SHADER_SOURCE_LENGTH:
478 break;
479
480 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
481 if (!context->getExtensions().translatedShaderSource)
482 {
483 context->handleError(
484 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
485 return false;
486 }
487 break;
488
489 default:
490 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
491 return false;
492 }
493
494 if (length)
495 {
496 *length = 1;
497 }
498 return true;
499}
500
Geoff Langc1984ed2016-10-07 12:41:00 -0400501bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
502{
503 if (length)
504 {
505 *length = 0;
506 }
507
508 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
509 {
510 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
511 return false;
512 }
513
514 if (context->getTargetTexture(target) == nullptr)
515 {
516 // Should only be possible for external textures
517 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
518 return false;
519 }
520
521 switch (pname)
522 {
523 case GL_TEXTURE_MAG_FILTER:
524 case GL_TEXTURE_MIN_FILTER:
525 case GL_TEXTURE_WRAP_S:
526 case GL_TEXTURE_WRAP_T:
527 break;
528
529 case GL_TEXTURE_USAGE_ANGLE:
530 if (!context->getExtensions().textureUsage)
531 {
532 context->handleError(
533 Error(GL_INVALID_ENUM, "GL_ANGLE_texture_usage is not enabled."));
534 return false;
535 }
536 break;
537
538 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
539 if (!context->getExtensions().textureFilterAnisotropic)
540 {
541 context->handleError(
542 Error(GL_INVALID_ENUM, "GL_EXT_texture_filter_anisotropic is not enabled."));
543 return false;
544 }
545 break;
546
547 case GL_TEXTURE_IMMUTABLE_FORMAT:
548 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
549 {
550 context->handleError(
551 Error(GL_INVALID_ENUM, "GL_EXT_texture_storage is not enabled."));
552 return false;
553 }
554 break;
555
556 case GL_TEXTURE_WRAP_R:
557 case GL_TEXTURE_IMMUTABLE_LEVELS:
558 case GL_TEXTURE_SWIZZLE_R:
559 case GL_TEXTURE_SWIZZLE_G:
560 case GL_TEXTURE_SWIZZLE_B:
561 case GL_TEXTURE_SWIZZLE_A:
562 case GL_TEXTURE_BASE_LEVEL:
563 case GL_TEXTURE_MAX_LEVEL:
564 case GL_TEXTURE_MIN_LOD:
565 case GL_TEXTURE_MAX_LOD:
566 case GL_TEXTURE_COMPARE_MODE:
567 case GL_TEXTURE_COMPARE_FUNC:
568 if (context->getClientMajorVersion() < 3)
569 {
570 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
571 return false;
572 }
573 break;
574
Geoff Lang81c6b572016-10-19 14:07:52 -0700575 case GL_TEXTURE_SRGB_DECODE_EXT:
576 if (!context->getExtensions().textureSRGBDecode)
577 {
578 context->handleError(
579 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
580 return false;
581 }
582 break;
583
Geoff Langc1984ed2016-10-07 12:41:00 -0400584 default:
585 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
586 return false;
587 }
588
589 if (length)
590 {
591 *length = 1;
592 }
593 return true;
594}
595
596template <typename ParamType>
597bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isExternalTextureTarget)
598{
599 switch (ConvertToGLenum(params[0]))
600 {
601 case GL_CLAMP_TO_EDGE:
602 break;
603
604 case GL_REPEAT:
605 case GL_MIRRORED_REPEAT:
606 if (isExternalTextureTarget)
607 {
608 // OES_EGL_image_external specifies this error.
609 context->handleError(Error(
610 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
611 return false;
612 }
613 break;
614
615 default:
616 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
617 return false;
618 }
619
620 return true;
621}
622
623template <typename ParamType>
624bool ValidateTextureMinFilterValue(Context *context,
625 ParamType *params,
626 bool isExternalTextureTarget)
627{
628 switch (ConvertToGLenum(params[0]))
629 {
630 case GL_NEAREST:
631 case GL_LINEAR:
632 break;
633
634 case GL_NEAREST_MIPMAP_NEAREST:
635 case GL_LINEAR_MIPMAP_NEAREST:
636 case GL_NEAREST_MIPMAP_LINEAR:
637 case GL_LINEAR_MIPMAP_LINEAR:
638 if (isExternalTextureTarget)
639 {
640 // OES_EGL_image_external specifies this error.
641 context->handleError(
642 Error(GL_INVALID_ENUM,
643 "external textures only support NEAREST and LINEAR filtering"));
644 return false;
645 }
646 break;
647
648 default:
649 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
650 return false;
651 }
652
653 return true;
654}
655
656template <typename ParamType>
657bool ValidateTextureMagFilterValue(Context *context, ParamType *params)
658{
659 switch (ConvertToGLenum(params[0]))
660 {
661 case GL_NEAREST:
662 case GL_LINEAR:
663 break;
664
665 default:
666 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
667 return false;
668 }
669
670 return true;
671}
672
673template <typename ParamType>
674bool ValidateTextureCompareModeValue(Context *context, ParamType *params)
675{
676 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
677 switch (ConvertToGLenum(params[0]))
678 {
679 case GL_NONE:
680 case GL_COMPARE_REF_TO_TEXTURE:
681 break;
682
683 default:
684 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
685 return false;
686 }
687
688 return true;
689}
690
691template <typename ParamType>
692bool ValidateTextureCompareFuncValue(Context *context, ParamType *params)
693{
694 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
695 switch (ConvertToGLenum(params[0]))
696 {
697 case GL_LEQUAL:
698 case GL_GEQUAL:
699 case GL_LESS:
700 case GL_GREATER:
701 case GL_EQUAL:
702 case GL_NOTEQUAL:
703 case GL_ALWAYS:
704 case GL_NEVER:
705 break;
706
707 default:
708 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
709 return false;
710 }
711
712 return true;
713}
714
715template <typename ParamType>
Geoff Lang81c6b572016-10-19 14:07:52 -0700716bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params)
717{
718 if (!context->getExtensions().textureSRGBDecode)
719 {
720 context->handleError(Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
721 return false;
722 }
723
724 switch (ConvertToGLenum(params[0]))
725 {
726 case GL_DECODE_EXT:
727 case GL_SKIP_DECODE_EXT:
728 break;
729
730 default:
731 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
732 return false;
733 }
734
735 return true;
736}
737
738template <typename ParamType>
Geoff Langc1984ed2016-10-07 12:41:00 -0400739bool ValidateTexParameterBase(Context *context,
740 GLenum target,
741 GLenum pname,
742 GLsizei bufSize,
743 ParamType *params)
744{
745 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
746 {
747 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
748 return false;
749 }
750
751 if (context->getTargetTexture(target) == nullptr)
752 {
753 // Should only be possible for external textures
754 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
755 return false;
756 }
757
758 const GLsizei minBufSize = 1;
759 if (bufSize >= 0 && bufSize < minBufSize)
760 {
761 context->handleError(
762 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
763 return false;
764 }
765
766 switch (pname)
767 {
768 case GL_TEXTURE_WRAP_R:
769 case GL_TEXTURE_SWIZZLE_R:
770 case GL_TEXTURE_SWIZZLE_G:
771 case GL_TEXTURE_SWIZZLE_B:
772 case GL_TEXTURE_SWIZZLE_A:
773 case GL_TEXTURE_BASE_LEVEL:
774 case GL_TEXTURE_MAX_LEVEL:
775 case GL_TEXTURE_COMPARE_MODE:
776 case GL_TEXTURE_COMPARE_FUNC:
777 case GL_TEXTURE_MIN_LOD:
778 case GL_TEXTURE_MAX_LOD:
779 if (context->getClientMajorVersion() < 3)
780 {
781 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
782 return false;
783 }
784 if (target == GL_TEXTURE_EXTERNAL_OES &&
785 !context->getExtensions().eglImageExternalEssl3)
786 {
787 context->handleError(Error(GL_INVALID_ENUM,
788 "ES3 texture parameters are not available without "
789 "GL_OES_EGL_image_external_essl3."));
790 return false;
791 }
792 break;
793
794 default:
795 break;
796 }
797
798 switch (pname)
799 {
800 case GL_TEXTURE_WRAP_S:
801 case GL_TEXTURE_WRAP_T:
802 case GL_TEXTURE_WRAP_R:
803 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
804 {
805 return false;
806 }
807 break;
808
809 case GL_TEXTURE_MIN_FILTER:
810 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
811 {
812 return false;
813 }
814 break;
815
816 case GL_TEXTURE_MAG_FILTER:
817 if (!ValidateTextureMagFilterValue(context, params))
818 {
819 return false;
820 }
821 break;
822
823 case GL_TEXTURE_USAGE_ANGLE:
824 switch (ConvertToGLenum(params[0]))
825 {
826 case GL_NONE:
827 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
828 break;
829
830 default:
831 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
832 return false;
833 }
834 break;
835
836 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
837 if (!context->getExtensions().textureFilterAnisotropic)
838 {
839 context->handleError(
840 Error(GL_INVALID_ENUM, "GL_EXT_texture_anisotropic is not enabled."));
841 return false;
842 }
843
844 // we assume the parameter passed to this validation method is truncated, not rounded
845 if (params[0] < 1)
846 {
847 context->handleError(Error(GL_INVALID_VALUE, "Max anisotropy must be at least 1."));
848 return false;
849 }
850 break;
851
852 case GL_TEXTURE_MIN_LOD:
853 case GL_TEXTURE_MAX_LOD:
854 // any value is permissible
855 break;
856
857 case GL_TEXTURE_COMPARE_MODE:
858 if (!ValidateTextureCompareModeValue(context, params))
859 {
860 return false;
861 }
862 break;
863
864 case GL_TEXTURE_COMPARE_FUNC:
865 if (!ValidateTextureCompareFuncValue(context, params))
866 {
867 return false;
868 }
869 break;
870
871 case GL_TEXTURE_SWIZZLE_R:
872 case GL_TEXTURE_SWIZZLE_G:
873 case GL_TEXTURE_SWIZZLE_B:
874 case GL_TEXTURE_SWIZZLE_A:
875 switch (ConvertToGLenum(params[0]))
876 {
877 case GL_RED:
878 case GL_GREEN:
879 case GL_BLUE:
880 case GL_ALPHA:
881 case GL_ZERO:
882 case GL_ONE:
883 break;
884
885 default:
886 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
887 return false;
888 }
889 break;
890
891 case GL_TEXTURE_BASE_LEVEL:
892 if (params[0] < 0)
893 {
894 context->handleError(Error(GL_INVALID_VALUE, "Base level must be at least 0."));
895 return false;
896 }
897 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
898 {
899 context->handleError(
900 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
901 return false;
902 }
903 break;
904
905 case GL_TEXTURE_MAX_LEVEL:
906 if (params[0] < 0)
907 {
908 context->handleError(Error(GL_INVALID_VALUE, "Max level must be at least 0."));
909 return false;
910 }
911 break;
912
Geoff Lang3b573612016-10-31 14:08:10 -0400913 case GL_DEPTH_STENCIL_TEXTURE_MODE:
914 if (context->getClientVersion() < Version(3, 1))
915 {
916 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.1."));
917 return false;
918 }
Geoff Lang9f090372016-12-02 10:20:43 -0500919 switch (ConvertToGLenum(params[0]))
920 {
921 case GL_DEPTH_COMPONENT:
922 case GL_STENCIL_INDEX:
923 break;
924
925 default:
926 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
927 return false;
928 }
Geoff Lang3b573612016-10-31 14:08:10 -0400929 break;
930
Geoff Lang81c6b572016-10-19 14:07:52 -0700931 case GL_TEXTURE_SRGB_DECODE_EXT:
932 if (!ValidateTextureSRGBDecodeValue(context, params))
933 {
934 return false;
935 }
936 break;
937
Geoff Langc1984ed2016-10-07 12:41:00 -0400938 default:
939 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
940 return false;
941 }
942
943 return true;
944}
945
946template <typename ParamType>
947bool ValidateSamplerParameterBase(Context *context,
948 GLuint sampler,
949 GLenum pname,
950 GLsizei bufSize,
951 ParamType *params)
952{
953 if (context->getClientMajorVersion() < 3)
954 {
955 context->handleError(
956 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
957 return false;
958 }
959
960 if (!context->isSampler(sampler))
961 {
962 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
963 return false;
964 }
965
966 const GLsizei minBufSize = 1;
967 if (bufSize >= 0 && bufSize < minBufSize)
968 {
969 context->handleError(
970 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
971 return false;
972 }
973
974 switch (pname)
975 {
976 case GL_TEXTURE_WRAP_S:
977 case GL_TEXTURE_WRAP_T:
978 case GL_TEXTURE_WRAP_R:
979 if (!ValidateTextureWrapModeValue(context, params, false))
980 {
981 return false;
982 }
983 break;
984
985 case GL_TEXTURE_MIN_FILTER:
986 if (!ValidateTextureMinFilterValue(context, params, false))
987 {
988 return false;
989 }
990 break;
991
992 case GL_TEXTURE_MAG_FILTER:
993 if (!ValidateTextureMagFilterValue(context, params))
994 {
995 return false;
996 }
997 break;
998
999 case GL_TEXTURE_MIN_LOD:
1000 case GL_TEXTURE_MAX_LOD:
1001 // any value is permissible
1002 break;
1003
1004 case GL_TEXTURE_COMPARE_MODE:
1005 if (!ValidateTextureCompareModeValue(context, params))
1006 {
1007 return false;
1008 }
1009 break;
1010
1011 case GL_TEXTURE_COMPARE_FUNC:
1012 if (!ValidateTextureCompareFuncValue(context, params))
1013 {
1014 return false;
1015 }
1016 break;
1017
Geoff Lang81c6b572016-10-19 14:07:52 -07001018 case GL_TEXTURE_SRGB_DECODE_EXT:
1019 if (!ValidateTextureSRGBDecodeValue(context, params))
1020 {
1021 return false;
1022 }
1023 break;
1024
Geoff Langc1984ed2016-10-07 12:41:00 -04001025 default:
1026 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1027 return false;
1028 }
1029
1030 return true;
1031}
1032
1033bool ValidateGetSamplerParameterBase(Context *context,
1034 GLuint sampler,
1035 GLenum pname,
1036 GLsizei *length)
1037{
1038 if (length)
1039 {
1040 *length = 0;
1041 }
1042
1043 if (context->getClientMajorVersion() < 3)
1044 {
1045 context->handleError(
1046 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1047 return false;
1048 }
1049
1050 if (!context->isSampler(sampler))
1051 {
1052 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
1053 return false;
1054 }
1055
1056 switch (pname)
1057 {
1058 case GL_TEXTURE_WRAP_S:
1059 case GL_TEXTURE_WRAP_T:
1060 case GL_TEXTURE_WRAP_R:
1061 case GL_TEXTURE_MIN_FILTER:
1062 case GL_TEXTURE_MAG_FILTER:
1063 case GL_TEXTURE_MIN_LOD:
1064 case GL_TEXTURE_MAX_LOD:
1065 case GL_TEXTURE_COMPARE_MODE:
1066 case GL_TEXTURE_COMPARE_FUNC:
1067 break;
1068
Geoff Lang81c6b572016-10-19 14:07:52 -07001069 case GL_TEXTURE_SRGB_DECODE_EXT:
1070 if (!context->getExtensions().textureSRGBDecode)
1071 {
1072 context->handleError(
1073 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
1074 return false;
1075 }
1076 break;
1077
Geoff Langc1984ed2016-10-07 12:41:00 -04001078 default:
1079 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1080 return false;
1081 }
1082
1083 if (length)
1084 {
1085 *length = 1;
1086 }
1087 return true;
1088}
1089
Geoff Lang0b031062016-10-13 14:30:04 -04001090bool ValidateGetVertexAttribBase(Context *context,
1091 GLuint index,
1092 GLenum pname,
1093 GLsizei *length,
1094 bool pointer,
1095 bool pureIntegerEntryPoint)
1096{
1097 if (length)
1098 {
1099 *length = 0;
1100 }
1101
1102 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
1103 {
1104 context->handleError(
1105 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1106 return false;
1107 }
1108
1109 if (index >= context->getCaps().maxVertexAttributes)
1110 {
1111 context->handleError(Error(
1112 GL_INVALID_VALUE, "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES."));
1113 return false;
1114 }
1115
1116 if (pointer)
1117 {
1118 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
1119 {
1120 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1121 return false;
1122 }
1123 }
1124 else
1125 {
1126 switch (pname)
1127 {
1128 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1129 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1130 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1131 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1132 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1133 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1134 case GL_CURRENT_VERTEX_ATTRIB:
1135 break;
1136
1137 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1138 static_assert(
1139 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
1140 "ANGLE extension enums not equal to GL enums.");
1141 if (context->getClientMajorVersion() < 3 &&
1142 !context->getExtensions().instancedArrays)
1143 {
1144 context->handleError(Error(GL_INVALID_ENUM,
1145 "GL_VERTEX_ATTRIB_ARRAY_DIVISOR requires OpenGL ES "
1146 "3.0 or GL_ANGLE_instanced_arrays."));
1147 return false;
1148 }
1149 break;
1150
1151 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
1152 if (context->getClientMajorVersion() < 3)
1153 {
Shao80957d92017-02-20 21:25:59 +08001154 context->handleError(Error(
1155 GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
1156 return false;
1157 }
1158 break;
1159
1160 case GL_VERTEX_ATTRIB_BINDING:
1161 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
1162 if (context->getClientVersion() < ES_3_1)
1163 {
1164 context->handleError(
1165 Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
Geoff Lang0b031062016-10-13 14:30:04 -04001166 return false;
1167 }
1168 break;
1169
1170 default:
1171 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1172 return false;
1173 }
1174 }
1175
1176 if (length)
1177 {
1178 if (pname == GL_CURRENT_VERTEX_ATTRIB)
1179 {
1180 *length = 4;
1181 }
1182 else
1183 {
1184 *length = 1;
1185 }
1186 }
1187
1188 return true;
1189}
1190
Geoff Lang6899b872016-10-14 11:30:13 -04001191bool ValidateGetActiveUniformBlockivBase(Context *context,
1192 GLuint program,
1193 GLuint uniformBlockIndex,
1194 GLenum pname,
1195 GLsizei *length)
1196{
1197 if (length)
1198 {
1199 *length = 0;
1200 }
1201
1202 if (context->getClientMajorVersion() < 3)
1203 {
1204 context->handleError(
1205 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1206 return false;
1207 }
1208
1209 Program *programObject = GetValidProgram(context, program);
1210 if (!programObject)
1211 {
1212 return false;
1213 }
1214
1215 if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
1216 {
1217 context->handleError(
1218 Error(GL_INVALID_VALUE, "uniformBlockIndex exceeds active uniform block count."));
1219 return false;
1220 }
1221
1222 switch (pname)
1223 {
1224 case GL_UNIFORM_BLOCK_BINDING:
1225 case GL_UNIFORM_BLOCK_DATA_SIZE:
1226 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1227 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1228 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1229 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1230 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1231 break;
1232
1233 default:
1234 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1235 return false;
1236 }
1237
1238 if (length)
1239 {
1240 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
1241 {
1242 const UniformBlock &uniformBlock =
1243 programObject->getUniformBlockByIndex(uniformBlockIndex);
1244 *length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
1245 }
1246 else
1247 {
1248 *length = 1;
1249 }
1250 }
1251
1252 return true;
1253}
1254
Geoff Langebebe1c2016-10-14 12:01:31 -04001255bool ValidateGetBufferParameterBase(ValidationContext *context,
1256 GLenum target,
1257 GLenum pname,
1258 bool pointerVersion,
1259 GLsizei *numParams)
1260{
1261 if (numParams)
1262 {
1263 *numParams = 0;
1264 }
1265
1266 if (!ValidBufferTarget(context, target))
1267 {
1268 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
1269 return false;
1270 }
1271
1272 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
1273 if (!buffer)
1274 {
1275 // A null buffer means that "0" is bound to the requested buffer target
1276 context->handleError(Error(GL_INVALID_OPERATION, "No buffer bound."));
1277 return false;
1278 }
1279
1280 const Extensions &extensions = context->getExtensions();
1281
1282 switch (pname)
1283 {
1284 case GL_BUFFER_USAGE:
1285 case GL_BUFFER_SIZE:
1286 break;
1287
1288 case GL_BUFFER_ACCESS_OES:
1289 if (!extensions.mapBuffer)
1290 {
1291 context->handleError(
Jamie Madillcc6ac252017-01-25 12:57:21 -08001292 Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
Geoff Langebebe1c2016-10-14 12:01:31 -04001293 return false;
1294 }
1295 break;
1296
1297 case GL_BUFFER_MAPPED:
1298 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
1299 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
1300 !extensions.mapBufferRange)
1301 {
1302 context->handleError(Error(
1303 GL_INVALID_ENUM,
Jamie Madillcc6ac252017-01-25 12:57:21 -08001304 "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
Geoff Langebebe1c2016-10-14 12:01:31 -04001305 return false;
1306 }
1307 break;
1308
1309 case GL_BUFFER_MAP_POINTER:
1310 if (!pointerVersion)
1311 {
1312 context->handleError(
1313 Error(GL_INVALID_ENUM,
1314 "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."));
1315 return false;
1316 }
1317 break;
1318
1319 case GL_BUFFER_ACCESS_FLAGS:
1320 case GL_BUFFER_MAP_OFFSET:
1321 case GL_BUFFER_MAP_LENGTH:
1322 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
1323 {
1324 context->handleError(Error(
1325 GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."));
1326 return false;
1327 }
1328 break;
1329
1330 default:
1331 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1332 return false;
1333 }
1334
1335 // All buffer parameter queries return one value.
1336 if (numParams)
1337 {
1338 *numParams = 1;
1339 }
1340
1341 return true;
1342}
1343
Geoff Lang0a9661f2016-10-20 10:59:20 -07001344bool ValidateGetInternalFormativBase(Context *context,
1345 GLenum target,
1346 GLenum internalformat,
1347 GLenum pname,
1348 GLsizei bufSize,
1349 GLsizei *numParams)
1350{
1351 if (numParams)
1352 {
1353 *numParams = 0;
1354 }
1355
1356 if (context->getClientMajorVersion() < 3)
1357 {
1358 context->handleError(
1359 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1360 return false;
1361 }
1362
1363 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
1364 if (!formatCaps.renderable)
1365 {
1366 context->handleError(Error(GL_INVALID_ENUM, "Internal format is not renderable."));
1367 return false;
1368 }
1369
1370 switch (target)
1371 {
1372 case GL_RENDERBUFFER:
1373 break;
1374
JiangYizhoubddc46b2016-12-09 09:50:51 +08001375 case GL_TEXTURE_2D_MULTISAMPLE:
1376 if (context->getClientVersion() < ES_3_1)
1377 {
1378 context->handleError(
1379 Error(GL_INVALID_OPERATION, "Texture target requires at least OpenGL ES 3.1."));
1380 return false;
1381 }
1382 break;
1383
Geoff Lang0a9661f2016-10-20 10:59:20 -07001384 default:
1385 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
1386 return false;
1387 }
1388
1389 if (bufSize < 0)
1390 {
1391 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
1392 return false;
1393 }
1394
1395 GLsizei maxWriteParams = 0;
1396 switch (pname)
1397 {
1398 case GL_NUM_SAMPLE_COUNTS:
1399 maxWriteParams = 1;
1400 break;
1401
1402 case GL_SAMPLES:
1403 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
1404 break;
1405
1406 default:
1407 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1408 return false;
1409 }
1410
1411 if (numParams)
1412 {
1413 // glGetInternalFormativ will not overflow bufSize
1414 *numParams = std::min(bufSize, maxWriteParams);
1415 }
1416
1417 return true;
1418}
1419
Jamie Madillc1d770e2017-04-13 17:31:24 -04001420bool ValidateUniformCommonBase(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001421 gl::Program *program,
1422 GLint location,
1423 GLsizei count,
1424 const LinkedUniform **uniformOut)
1425{
1426 // TODO(Jiajia): Add image uniform check in future.
1427 if (count < 0)
1428 {
1429 context->handleError(Error(GL_INVALID_VALUE));
1430 return false;
1431 }
1432
1433 if (!program || !program->isLinked())
1434 {
1435 context->handleError(Error(GL_INVALID_OPERATION));
1436 return false;
1437 }
1438
1439 if (location == -1)
1440 {
1441 // Silently ignore the uniform command
1442 return false;
1443 }
1444
1445 const auto &uniformLocations = program->getUniformLocations();
1446 size_t castedLocation = static_cast<size_t>(location);
1447 if (castedLocation >= uniformLocations.size())
1448 {
1449 context->handleError(Error(GL_INVALID_OPERATION, "Invalid uniform location"));
1450 return false;
1451 }
1452
1453 const auto &uniformLocation = uniformLocations[castedLocation];
1454 if (uniformLocation.ignored)
1455 {
1456 // Silently ignore the uniform command
1457 return false;
1458 }
1459
1460 if (!uniformLocation.used)
1461 {
1462 context->handleError(Error(GL_INVALID_OPERATION));
1463 return false;
1464 }
1465
1466 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
1467
1468 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1469 if (!uniform.isArray() && count > 1)
1470 {
1471 context->handleError(Error(GL_INVALID_OPERATION));
1472 return false;
1473 }
1474
1475 *uniformOut = &uniform;
1476 return true;
1477}
1478
Frank Henigman999b0fd2017-02-02 21:45:55 -05001479bool ValidateUniform1ivValue(ValidationContext *context,
Frank Henigmana98a6472017-02-02 21:38:32 -05001480 GLenum uniformType,
1481 GLsizei count,
1482 const GLint *value)
1483{
1484 // Value type is GL_INT, because we only get here from glUniform1i{v}.
1485 // It is compatible with INT or BOOL.
1486 // Do these cheap tests first, for a little extra speed.
1487 if (GL_INT == uniformType || GL_BOOL == uniformType)
1488 {
1489 return true;
1490 }
1491
1492 if (IsSamplerType(uniformType))
1493 {
Frank Henigman999b0fd2017-02-02 21:45:55 -05001494 // Check that the values are in range.
1495 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
1496 for (GLsizei i = 0; i < count; ++i)
1497 {
1498 if (value[i] < 0 || value[i] >= max)
1499 {
1500 context->handleError(Error(GL_INVALID_VALUE, "sampler uniform value out of range"));
1501 return false;
1502 }
1503 }
Frank Henigmana98a6472017-02-02 21:38:32 -05001504 return true;
1505 }
1506
1507 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1508 return false;
1509}
1510
Jamie Madillc1d770e2017-04-13 17:31:24 -04001511bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001512{
1513 // Check that the value type is compatible with uniform type.
Frank Henigmana98a6472017-02-02 21:38:32 -05001514 // Do the cheaper test first, for a little extra speed.
1515 if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001516 {
1517 return true;
1518 }
1519
1520 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1521 return false;
1522}
1523
Jamie Madillc1d770e2017-04-13 17:31:24 -04001524bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001525{
1526 // Check that the value type is compatible with uniform type.
1527 if (valueType == uniformType)
1528 {
1529 return true;
1530 }
1531
1532 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1533 return false;
1534}
1535
Jamie Madillc1d770e2017-04-13 17:31:24 -04001536bool ValidateES2CopyTexImageParameters(ValidationContext *context,
1537 GLenum target,
1538 GLint level,
1539 GLenum internalformat,
1540 bool isSubImage,
1541 GLint xoffset,
1542 GLint yoffset,
1543 GLint x,
1544 GLint y,
1545 GLsizei width,
1546 GLsizei height,
1547 GLint border)
1548{
1549 if (!ValidTexture2DDestinationTarget(context, target))
1550 {
1551 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
1552 return false;
1553 }
1554
1555 if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage))
1556 {
1557 context->handleError(Error(GL_INVALID_VALUE, "Invalid texture dimensions."));
1558 return false;
1559 }
1560
1561 Format textureFormat = Format::Invalid();
1562 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
1563 xoffset, yoffset, 0, x, y, width, height, border,
1564 &textureFormat))
1565 {
1566 return false;
1567 }
1568
1569 const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
Geoff Langca271392017-04-05 12:30:00 -04001570 GLenum colorbufferFormat =
1571 framebuffer->getReadColorbuffer()->getFormat().info->sizedInternalFormat;
Jamie Madillc1d770e2017-04-13 17:31:24 -04001572 const auto &formatInfo = *textureFormat.info;
1573
1574 // [OpenGL ES 2.0.24] table 3.9
1575 if (isSubImage)
1576 {
1577 switch (formatInfo.format)
1578 {
1579 case GL_ALPHA:
1580 if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
1581 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES)
1582 {
1583 context->handleError(Error(GL_INVALID_OPERATION));
1584 return false;
1585 }
1586 break;
1587 case GL_LUMINANCE:
1588 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1589 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1590 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1591 colorbufferFormat != GL_RGBA8_OES)
1592 {
1593 context->handleError(Error(GL_INVALID_OPERATION));
1594 return false;
1595 }
1596 break;
1597 case GL_RED_EXT:
1598 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1599 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1600 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1601 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_R32F &&
1602 colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
1603 colorbufferFormat != GL_RGBA32F)
1604 {
1605 context->handleError(Error(GL_INVALID_OPERATION));
1606 return false;
1607 }
1608 break;
1609 case GL_RG_EXT:
1610 if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
1611 colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
1612 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES &&
1613 colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
1614 colorbufferFormat != GL_RGBA32F)
1615 {
1616 context->handleError(Error(GL_INVALID_OPERATION));
1617 return false;
1618 }
1619 break;
1620 case GL_RGB:
1621 if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1622 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1623 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGB32F &&
1624 colorbufferFormat != GL_RGBA32F)
1625 {
1626 context->handleError(Error(GL_INVALID_OPERATION));
1627 return false;
1628 }
1629 break;
1630 case GL_LUMINANCE_ALPHA:
1631 case GL_RGBA:
1632 if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1633 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGBA32F)
1634 {
1635 context->handleError(Error(GL_INVALID_OPERATION));
1636 return false;
1637 }
1638 break;
1639 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1640 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1641 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1642 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1643 case GL_ETC1_RGB8_OES:
1644 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
1645 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1646 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1647 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1648 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1649 context->handleError(Error(GL_INVALID_OPERATION));
1650 return false;
1651 case GL_DEPTH_COMPONENT:
1652 case GL_DEPTH_STENCIL_OES:
1653 context->handleError(Error(GL_INVALID_OPERATION));
1654 return false;
1655 default:
1656 context->handleError(Error(GL_INVALID_OPERATION));
1657 return false;
1658 }
1659
1660 if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat)
1661 {
1662 context->handleError(Error(GL_INVALID_OPERATION));
1663 return false;
1664 }
1665 }
1666 else
1667 {
1668 switch (internalformat)
1669 {
1670 case GL_ALPHA:
1671 if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
1672 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
1673 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX)
1674 {
1675 context->handleError(Error(GL_INVALID_OPERATION));
1676 return false;
1677 }
1678 break;
1679 case GL_LUMINANCE:
1680 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1681 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1682 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1683 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1684 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1685 {
1686 context->handleError(Error(GL_INVALID_OPERATION));
1687 return false;
1688 }
1689 break;
1690 case GL_RED_EXT:
1691 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1692 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1693 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1694 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1695 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1696 {
1697 context->handleError(Error(GL_INVALID_OPERATION));
1698 return false;
1699 }
1700 break;
1701 case GL_RG_EXT:
1702 if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
1703 colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
1704 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
1705 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX)
1706 {
1707 context->handleError(Error(GL_INVALID_OPERATION));
1708 return false;
1709 }
1710 break;
1711 case GL_RGB:
1712 if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1713 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1714 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1715 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1716 {
1717 context->handleError(Error(GL_INVALID_OPERATION));
1718 return false;
1719 }
1720 break;
1721 case GL_LUMINANCE_ALPHA:
1722 case GL_RGBA:
1723 if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1724 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1725 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1726 {
1727 context->handleError(Error(GL_INVALID_OPERATION));
1728 return false;
1729 }
1730 break;
1731 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1732 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1733 if (context->getExtensions().textureCompressionDXT1)
1734 {
1735 context->handleError(Error(GL_INVALID_OPERATION));
1736 return false;
1737 }
1738 else
1739 {
1740 context->handleError(Error(GL_INVALID_ENUM));
1741 return false;
1742 }
1743 break;
1744 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1745 if (context->getExtensions().textureCompressionDXT3)
1746 {
1747 context->handleError(Error(GL_INVALID_OPERATION));
1748 return false;
1749 }
1750 else
1751 {
1752 context->handleError(Error(GL_INVALID_ENUM));
1753 return false;
1754 }
1755 break;
1756 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1757 if (context->getExtensions().textureCompressionDXT5)
1758 {
1759 context->handleError(Error(GL_INVALID_OPERATION));
1760 return false;
1761 }
1762 else
1763 {
1764 context->handleError(Error(GL_INVALID_ENUM));
1765 return false;
1766 }
1767 break;
1768 case GL_ETC1_RGB8_OES:
1769 if (context->getExtensions().compressedETC1RGB8Texture)
1770 {
1771 context->handleError(Error(GL_INVALID_OPERATION));
1772 return false;
1773 }
1774 else
1775 {
1776 context->handleError(Error(GL_INVALID_ENUM));
1777 return false;
1778 }
1779 break;
1780 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
1781 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1782 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1783 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1784 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1785 if (context->getExtensions().lossyETCDecode)
1786 {
1787 context->handleError(Error(GL_INVALID_OPERATION,
1788 "ETC lossy decode formats can't be copied to."));
1789 return false;
1790 }
1791 else
1792 {
1793 context->handleError(Error(
1794 GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported."));
1795 return false;
1796 }
1797 break;
1798 case GL_DEPTH_COMPONENT:
1799 case GL_DEPTH_COMPONENT16:
1800 case GL_DEPTH_COMPONENT32_OES:
1801 case GL_DEPTH_STENCIL_OES:
1802 case GL_DEPTH24_STENCIL8_OES:
1803 if (context->getExtensions().depthTextures)
1804 {
1805 context->handleError(Error(GL_INVALID_OPERATION));
1806 return false;
1807 }
1808 else
1809 {
1810 context->handleError(Error(GL_INVALID_ENUM));
1811 return false;
1812 }
1813 default:
1814 context->handleError(Error(GL_INVALID_ENUM));
1815 return false;
1816 }
1817 }
1818
1819 // If width or height is zero, it is a no-op. Return false without setting an error.
1820 return (width > 0 && height > 0);
1821}
1822
Geoff Lang407d4e72017-04-12 14:54:11 -04001823bool ValidateDrawElementsInstancedBase(Context *context,
1824 GLenum mode,
1825 GLsizei count,
1826 GLenum type,
1827 const GLvoid *indices,
1828 GLsizei primcount,
1829 IndexRange *indexRangeOut)
1830{
1831 if (primcount < 0)
1832 {
1833 context->handleError(Error(GL_INVALID_VALUE, "primcount cannot be negative."));
1834 return false;
1835 }
1836
1837 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
1838 {
1839 return false;
1840 }
1841
1842 // No-op zero primitive count
1843 return (primcount > 0);
1844}
1845
1846bool ValidateDrawArraysInstancedBase(Context *context,
1847 GLenum mode,
1848 GLint first,
1849 GLsizei count,
1850 GLsizei primcount)
1851{
1852 if (primcount < 0)
1853 {
1854 context->handleError(Error(GL_INVALID_VALUE, "primcount cannot be negative."));
1855 return false;
1856 }
1857
1858 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
1859 {
1860 return false;
1861 }
1862
1863 // No-op if zero primitive count
1864 return (primcount > 0);
1865}
1866
1867bool ValidateDrawInstancedANGLEAndWebGL(Context *context)
1868{
1869 // Verify there is at least one active attribute with a divisor of zero
1870 const State &state = context->getGLState();
1871
1872 Program *program = state.getProgram();
1873
1874 const auto &attribs = state.getVertexArray()->getVertexAttributes();
1875 const auto &bindings = state.getVertexArray()->getVertexBindings();
1876 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1877 {
1878 const VertexAttribute &attrib = attribs[attributeIndex];
1879 const VertexBinding &binding = bindings[attrib.bindingIndex];
1880 if (program->isAttribLocationActive(attributeIndex) && binding.divisor == 0)
1881 {
1882 return true;
1883 }
1884 }
1885
1886 context->handleError(
1887 Error(GL_INVALID_OPERATION, "At least one attribute must have a divisor of zero."));
1888 return false;
1889}
1890
Geoff Langf41a7152016-09-19 15:11:17 -04001891} // anonymous namespace
1892
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001893bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -04001894{
Jamie Madilld7460c72014-01-21 16:38:14 -05001895 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -04001896 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001897 case GL_TEXTURE_2D:
1898 case GL_TEXTURE_CUBE_MAP:
1899 return true;
Jamie Madill35d15012013-10-07 10:46:37 -04001900
He Yunchaoced53ae2016-11-29 15:00:51 +08001901 case GL_TEXTURE_3D:
1902 case GL_TEXTURE_2D_ARRAY:
1903 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -05001904
He Yunchaoced53ae2016-11-29 15:00:51 +08001905 case GL_TEXTURE_2D_MULTISAMPLE:
He Yunchaoced53ae2016-11-29 15:00:51 +08001906 return (context->getClientVersion() >= Version(3, 1));
Geoff Lang3b573612016-10-31 14:08:10 -04001907
He Yunchaoced53ae2016-11-29 15:00:51 +08001908 default:
1909 return false;
Jamie Madilld7460c72014-01-21 16:38:14 -05001910 }
Jamie Madill35d15012013-10-07 10:46:37 -04001911}
1912
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001913bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
1914{
1915 switch (target)
1916 {
1917 case GL_TEXTURE_2D:
1918 case GL_TEXTURE_CUBE_MAP:
1919 return true;
1920
1921 default:
1922 return false;
1923 }
1924}
1925
1926bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
1927{
1928 switch (target)
1929 {
1930 case GL_TEXTURE_3D:
1931 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +03001932 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001933
1934 default:
1935 return false;
1936 }
1937}
1938
Ian Ewellbda75592016-04-18 17:25:54 -04001939// Most texture GL calls are not compatible with external textures, so we have a separate validation
1940// function for use in the GL calls that do
1941bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
1942{
1943 return (target == GL_TEXTURE_EXTERNAL_OES) &&
1944 (context->getExtensions().eglImageExternal ||
1945 context->getExtensions().eglStreamConsumerExternal);
1946}
1947
Shannon Woods4dfed832014-03-17 20:03:39 -04001948// This function differs from ValidTextureTarget in that the target must be
1949// usable as the destination of a 2D operation-- so a cube face is valid, but
1950// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -04001951// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -05001952bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -04001953{
1954 switch (target)
1955 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001956 case GL_TEXTURE_2D:
1957 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1958 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1959 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1960 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1961 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1962 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1963 return true;
1964 default:
1965 return false;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001966 }
1967}
1968
1969bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
1970{
1971 switch (target)
1972 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001973 case GL_TEXTURE_3D:
1974 case GL_TEXTURE_2D_ARRAY:
1975 return true;
1976 default:
1977 return false;
Shannon Woods4dfed832014-03-17 20:03:39 -04001978 }
1979}
1980
He Yunchao11b038b2016-11-22 21:24:04 +08001981bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target)
1982{
1983 switch (target)
1984 {
1985 case GL_TEXTURE_2D:
1986 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1987 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1988 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1989 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1990 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1991 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1992 case GL_TEXTURE_3D:
1993 case GL_TEXTURE_2D_ARRAY:
1994 case GL_TEXTURE_2D_MULTISAMPLE:
1995 return true;
1996 default:
1997 return false;
1998 }
1999}
2000
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002001bool ValidFramebufferTarget(GLenum target)
2002{
He Yunchaoced53ae2016-11-29 15:00:51 +08002003 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
2004 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
Geoff Langd4475812015-03-18 10:53:05 -04002005 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002006
2007 switch (target)
2008 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002009 case GL_FRAMEBUFFER:
2010 return true;
2011 case GL_READ_FRAMEBUFFER:
2012 return true;
2013 case GL_DRAW_FRAMEBUFFER:
2014 return true;
2015 default:
2016 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002017 }
2018}
2019
Jamie Madill29639852016-09-02 15:00:09 -04002020bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -05002021{
2022 switch (target)
2023 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002024 case GL_ARRAY_BUFFER:
2025 case GL_ELEMENT_ARRAY_BUFFER:
2026 return true;
Jamie Madill8c96d582014-03-05 15:01:23 -05002027
He Yunchaoced53ae2016-11-29 15:00:51 +08002028 case GL_PIXEL_PACK_BUFFER:
2029 case GL_PIXEL_UNPACK_BUFFER:
2030 return (context->getExtensions().pixelBufferObject ||
2031 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -04002032
He Yunchaoced53ae2016-11-29 15:00:51 +08002033 case GL_COPY_READ_BUFFER:
2034 case GL_COPY_WRITE_BUFFER:
2035 case GL_TRANSFORM_FEEDBACK_BUFFER:
2036 case GL_UNIFORM_BUFFER:
2037 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -05002038
He Yunchaoced53ae2016-11-29 15:00:51 +08002039 case GL_ATOMIC_COUNTER_BUFFER:
2040 case GL_SHADER_STORAGE_BUFFER:
2041 case GL_DRAW_INDIRECT_BUFFER:
2042 case GL_DISPATCH_INDIRECT_BUFFER:
He Yunchaoced53ae2016-11-29 15:00:51 +08002043 return context->getClientVersion() >= Version(3, 1);
Geoff Lang3b573612016-10-31 14:08:10 -04002044
He Yunchaoced53ae2016-11-29 15:00:51 +08002045 default:
2046 return false;
Jamie Madill8c96d582014-03-05 15:01:23 -05002047 }
2048}
2049
Jamie Madillc29968b2016-01-20 11:17:23 -05002050bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -04002051{
Jamie Madillc29968b2016-01-20 11:17:23 -05002052 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -04002053 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -04002054 switch (target)
2055 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002056 case GL_TEXTURE_2D:
2057 maxDimension = caps.max2DTextureSize;
2058 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08002059 case GL_TEXTURE_CUBE_MAP:
2060 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2061 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2062 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2063 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2064 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2065 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2066 maxDimension = caps.maxCubeMapTextureSize;
2067 break;
2068 case GL_TEXTURE_3D:
2069 maxDimension = caps.max3DTextureSize;
2070 break;
2071 case GL_TEXTURE_2D_ARRAY:
2072 maxDimension = caps.max2DTextureSize;
2073 break;
He Yunchao11b038b2016-11-22 21:24:04 +08002074 case GL_TEXTURE_2D_MULTISAMPLE:
2075 maxDimension = caps.max2DTextureSize;
2076 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08002077 default:
2078 UNREACHABLE();
Geoff Langce635692013-09-24 13:56:32 -04002079 }
2080
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002081 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -04002082}
2083
Geoff Langcc507aa2016-12-12 10:09:52 -05002084bool ValidImageSizeParameters(const ValidationContext *context,
Austin Kinross08528e12015-10-07 16:24:40 -07002085 GLenum target,
2086 GLint level,
2087 GLsizei width,
2088 GLsizei height,
2089 GLsizei depth,
2090 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -04002091{
2092 if (level < 0 || width < 0 || height < 0 || depth < 0)
2093 {
2094 return false;
2095 }
2096
Austin Kinross08528e12015-10-07 16:24:40 -07002097 // TexSubImage parameters can be NPOT without textureNPOT extension,
2098 // as long as the destination texture is POT.
Geoff Langcc507aa2016-12-12 10:09:52 -05002099 bool hasNPOTSupport =
Geoff Lang5f319a42017-01-09 16:49:19 -05002100 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
Geoff Langcc507aa2016-12-12 10:09:52 -05002101 if (!isSubImage && !hasNPOTSupport &&
Jamie Madill4fd75c12014-06-23 10:53:54 -04002102 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -04002103 {
2104 return false;
2105 }
2106
2107 if (!ValidMipLevel(context, target, level))
2108 {
2109 return false;
2110 }
2111
2112 return true;
2113}
2114
Geoff Lang0d8b7242015-09-09 14:56:53 -04002115bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
2116{
2117 // List of compressed format that require that the texture size is smaller than or a multiple of
2118 // the compressed block size.
2119 switch (internalFormat)
2120 {
2121 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2122 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
2123 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
2124 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -08002125 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08002126 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
2127 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
2128 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
2129 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
2130 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
2131 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04002132 return true;
2133
2134 default:
2135 return false;
2136 }
2137}
2138
Jamie Madillc29968b2016-01-20 11:17:23 -05002139bool ValidCompressedImageSize(const ValidationContext *context,
2140 GLenum internalFormat,
Geoff Lang44ff5a72017-02-03 15:15:43 -05002141 GLint xoffset,
2142 GLint yoffset,
Jamie Madillc29968b2016-01-20 11:17:23 -05002143 GLsizei width,
2144 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04002145{
Geoff Langca271392017-04-05 12:30:00 -04002146 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04002147 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04002148 {
2149 return false;
2150 }
2151
Geoff Lang44ff5a72017-02-03 15:15:43 -05002152 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04002153 {
2154 return false;
2155 }
2156
Geoff Lang0d8b7242015-09-09 14:56:53 -04002157 if (CompressedTextureFormatRequiresExactSize(internalFormat))
2158 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05002159 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
2160 yoffset % formatInfo.compressedBlockHeight != 0 ||
2161 (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
Geoff Lang0d8b7242015-09-09 14:56:53 -04002162 width % formatInfo.compressedBlockWidth != 0) ||
2163 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
2164 height % formatInfo.compressedBlockHeight != 0))
2165 {
2166 return false;
2167 }
2168 }
2169
Geoff Langd4f180b2013-09-24 13:57:44 -04002170 return true;
2171}
2172
Geoff Langff5b2d52016-09-07 11:32:23 -04002173bool ValidImageDataSize(ValidationContext *context,
2174 GLenum textureTarget,
2175 GLsizei width,
2176 GLsizei height,
2177 GLsizei depth,
2178 GLenum internalFormat,
2179 GLenum type,
2180 const GLvoid *pixels,
2181 GLsizei imageSize)
2182{
2183 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
2184 if (pixelUnpackBuffer == nullptr && imageSize < 0)
2185 {
2186 // Checks are not required
2187 return true;
2188 }
2189
2190 // ...the data would be unpacked from the buffer object such that the memory reads required
2191 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -04002192 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
Geoff Langff5b2d52016-09-07 11:32:23 -04002193 const gl::Extents size(width, height, depth);
2194 const auto &unpack = context->getGLState().getUnpackState();
2195
2196 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
2197 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
2198 if (endByteOrErr.isError())
2199 {
2200 context->handleError(endByteOrErr.getError());
2201 return false;
2202 }
2203
2204 GLuint endByte = endByteOrErr.getResult();
2205
2206 if (pixelUnpackBuffer)
2207 {
2208 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
2209 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
2210 checkedEndByte += checkedOffset;
2211
2212 if (!checkedEndByte.IsValid() ||
2213 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
2214 {
2215 // Overflow past the end of the buffer
2216 context->handleError(Error(GL_INVALID_OPERATION));
2217 return false;
2218 }
2219 }
2220 else
2221 {
2222 ASSERT(imageSize >= 0);
2223 if (pixels == nullptr && imageSize != 0)
2224 {
2225 context->handleError(
2226 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
Geoff Lang3feb3ff2016-10-26 10:57:45 -04002227 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04002228 }
2229
Geoff Lang3feb3ff2016-10-26 10:57:45 -04002230 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04002231 {
2232 context->handleError(
2233 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
2234 return false;
2235 }
2236 }
2237
2238 return true;
2239}
2240
Geoff Lang37dde692014-01-31 16:34:54 -05002241bool ValidQueryType(const Context *context, GLenum queryType)
2242{
He Yunchaoced53ae2016-11-29 15:00:51 +08002243 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
2244 "GL extension enums not equal.");
2245 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2246 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05002247
2248 switch (queryType)
2249 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002250 case GL_ANY_SAMPLES_PASSED:
2251 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
2252 return true;
2253 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
2254 return (context->getClientMajorVersion() >= 3);
2255 case GL_TIME_ELAPSED_EXT:
2256 return context->getExtensions().disjointTimerQuery;
2257 case GL_COMMANDS_COMPLETED_CHROMIUM:
2258 return context->getExtensions().syncQuery;
2259 default:
2260 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05002261 }
2262}
2263
Geoff Lang2d62ab72017-03-23 16:54:40 -04002264bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
2265 GLenum type,
2266 GLboolean normalized,
2267 GLsizei stride,
2268 const GLvoid *ptr,
2269 bool pureInteger)
2270{
2271 ASSERT(context->getExtensions().webglCompatibility);
2272
2273 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
2274 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
2275 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
2276 // parameter exceeds 255.
2277 constexpr GLsizei kMaxWebGLStride = 255;
2278 if (stride > kMaxWebGLStride)
2279 {
2280 context->handleError(
2281 Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
2282 return false;
2283 }
2284
2285 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
2286 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
2287 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
2288 // or an INVALID_OPERATION error is generated.
2289 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
2290 size_t typeSize = GetVertexFormatTypeSize(internalType);
2291
2292 ASSERT(isPow2(typeSize) && typeSize > 0);
2293 size_t sizeMask = (typeSize - 1);
2294 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
2295 {
2296 context->handleError(
2297 Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
2298 return false;
2299 }
2300
2301 if ((stride & sizeMask) != 0)
2302 {
2303 context->handleError(
2304 Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
2305 return false;
2306 }
2307
2308 return true;
2309}
2310
Jamie Madillef300b12016-10-07 15:12:09 -04002311Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05002312{
He Yunchaoced53ae2016-11-29 15:00:51 +08002313 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
2314 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
2315 // or program object and INVALID_OPERATION if the provided name identifies an object
2316 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05002317
Dian Xiang769769a2015-09-09 15:20:08 -07002318 Program *validProgram = context->getProgram(id);
2319
2320 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05002321 {
Dian Xiang769769a2015-09-09 15:20:08 -07002322 if (context->getShader(id))
2323 {
Jamie Madill437fa652016-05-03 15:13:24 -04002324 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07002325 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
2326 }
2327 else
2328 {
Jamie Madill437fa652016-05-03 15:13:24 -04002329 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -07002330 }
Geoff Lang48dcae72014-02-05 16:28:24 -05002331 }
Dian Xiang769769a2015-09-09 15:20:08 -07002332
2333 return validProgram;
2334}
2335
Jamie Madillef300b12016-10-07 15:12:09 -04002336Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07002337{
2338 // See ValidProgram for spec details.
2339
2340 Shader *validShader = context->getShader(id);
2341
2342 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05002343 {
Dian Xiang769769a2015-09-09 15:20:08 -07002344 if (context->getProgram(id))
2345 {
Jamie Madill437fa652016-05-03 15:13:24 -04002346 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07002347 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
2348 }
2349 else
2350 {
Jamie Madill437fa652016-05-03 15:13:24 -04002351 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -07002352 }
Geoff Lang48dcae72014-02-05 16:28:24 -05002353 }
Dian Xiang769769a2015-09-09 15:20:08 -07002354
2355 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05002356}
2357
Geoff Langb1196682014-07-23 13:47:29 -04002358bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04002359{
2360 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
2361 {
2362 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
2363
Geoff Langaae65a42014-05-26 12:43:44 -04002364 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04002365 {
Jamie Madill437fa652016-05-03 15:13:24 -04002366 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002367 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04002368 }
2369 }
2370 else
2371 {
2372 switch (attachment)
2373 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002374 case GL_DEPTH_ATTACHMENT:
2375 case GL_STENCIL_ATTACHMENT:
2376 break;
Jamie Madillb4472272014-07-03 10:38:55 -04002377
He Yunchaoced53ae2016-11-29 15:00:51 +08002378 case GL_DEPTH_STENCIL_ATTACHMENT:
2379 if (!context->getExtensions().webglCompatibility &&
2380 context->getClientMajorVersion() < 3)
2381 {
2382 context->handleError(Error(GL_INVALID_ENUM));
2383 return false;
2384 }
2385 break;
Jamie Madillb4472272014-07-03 10:38:55 -04002386
He Yunchaoced53ae2016-11-29 15:00:51 +08002387 default:
2388 context->handleError(Error(GL_INVALID_ENUM));
2389 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04002390 }
2391 }
2392
2393 return true;
2394}
2395
Jamie Madille8fb6402017-02-14 17:56:40 -05002396bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08002397 GLenum target,
2398 GLsizei samples,
2399 GLenum internalformat,
2400 GLsizei width,
2401 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002402{
2403 switch (target)
2404 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002405 case GL_RENDERBUFFER:
2406 break;
2407 default:
2408 context->handleError(Error(GL_INVALID_ENUM));
2409 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002410 }
2411
2412 if (width < 0 || height < 0 || samples < 0)
2413 {
Jamie Madill437fa652016-05-03 15:13:24 -04002414 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002415 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002416 }
2417
Jamie Madill4e0e6f82017-02-17 11:06:03 -05002418 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
2419 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
2420
2421 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04002422 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002423 {
Jamie Madill437fa652016-05-03 15:13:24 -04002424 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002425 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002426 }
2427
2428 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
2429 // 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 -08002430 // only sized internal formats.
Geoff Langca271392017-04-05 12:30:00 -04002431 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat);
2432 if (formatInfo.internalFormat == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002433 {
Jamie Madill437fa652016-05-03 15:13:24 -04002434 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002435 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002436 }
2437
Geoff Langaae65a42014-05-26 12:43:44 -04002438 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002439 {
Jamie Madill437fa652016-05-03 15:13:24 -04002440 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002441 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002442 }
2443
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002444 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002445 if (handle == 0)
2446 {
Jamie Madill437fa652016-05-03 15:13:24 -04002447 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002448 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002449 }
2450
2451 return true;
2452}
2453
He Yunchaoced53ae2016-11-29 15:00:51 +08002454bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
2455 GLenum target,
2456 GLenum attachment,
2457 GLenum renderbuffertarget,
2458 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002459{
Shannon Woods1da3cf62014-06-27 15:32:23 -04002460 if (!ValidFramebufferTarget(target))
2461 {
Jamie Madill437fa652016-05-03 15:13:24 -04002462 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002463 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04002464 }
2465
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002466 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002467
Jamie Madill84115c92015-04-23 15:00:07 -04002468 ASSERT(framebuffer);
2469 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002470 {
Jamie Madill437fa652016-05-03 15:13:24 -04002471 context->handleError(
2472 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002473 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002474 }
2475
Jamie Madillb4472272014-07-03 10:38:55 -04002476 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002477 {
Jamie Madillb4472272014-07-03 10:38:55 -04002478 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002479 }
2480
Jamie Madillab9d82c2014-01-21 16:38:14 -05002481 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
2482 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
2483 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
2484 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
2485 if (renderbuffer != 0)
2486 {
2487 if (!context->getRenderbuffer(renderbuffer))
2488 {
Jamie Madill437fa652016-05-03 15:13:24 -04002489 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002490 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05002491 }
2492 }
2493
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002494 return true;
2495}
2496
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002497bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05002498 GLint srcX0,
2499 GLint srcY0,
2500 GLint srcX1,
2501 GLint srcY1,
2502 GLint dstX0,
2503 GLint dstY0,
2504 GLint dstX1,
2505 GLint dstY1,
2506 GLbitfield mask,
2507 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002508{
2509 switch (filter)
2510 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002511 case GL_NEAREST:
2512 break;
2513 case GL_LINEAR:
2514 break;
2515 default:
2516 context->handleError(Error(GL_INVALID_ENUM));
2517 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002518 }
2519
2520 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
2521 {
Jamie Madill437fa652016-05-03 15:13:24 -04002522 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002523 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002524 }
2525
2526 if (mask == 0)
2527 {
2528 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
2529 // buffers are copied.
2530 return false;
2531 }
2532
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002533 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
2534 // color buffer, leaving only nearest being unfiltered from above
2535 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
2536 {
Jamie Madill437fa652016-05-03 15:13:24 -04002537 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002538 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002539 }
2540
Jamie Madill51f40ec2016-06-15 14:06:00 -04002541 const auto &glState = context->getGLState();
2542 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
2543 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05002544
2545 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002546 {
Jamie Madill437fa652016-05-03 15:13:24 -04002547 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002548 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002549 }
2550
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002551 if (readFramebuffer->id() == drawFramebuffer->id())
2552 {
2553 context->handleError(Error(GL_INVALID_OPERATION));
2554 return false;
2555 }
2556
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002557 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05002558 {
Jamie Madill437fa652016-05-03 15:13:24 -04002559 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05002560 return false;
2561 }
2562
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002563 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05002564 {
Jamie Madill437fa652016-05-03 15:13:24 -04002565 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05002566 return false;
2567 }
2568
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002569 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002570 {
Jamie Madill437fa652016-05-03 15:13:24 -04002571 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002572 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002573 }
2574
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002575 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
2576
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002577 if (mask & GL_COLOR_BUFFER_BIT)
2578 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002579 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05002580 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002581
He Yunchao66a41a22016-12-15 16:45:05 +08002582 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002583 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002584 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002585
Geoff Langa15472a2015-08-11 11:48:03 -04002586 for (size_t drawbufferIdx = 0;
2587 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002588 {
Geoff Langa15472a2015-08-11 11:48:03 -04002589 const FramebufferAttachment *attachment =
2590 drawFramebuffer->getDrawBuffer(drawbufferIdx);
2591 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002592 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002593 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002594
Geoff Langb2f3d052013-08-13 12:49:27 -04002595 // The GL ES 3.0.2 spec (pg 193) states that:
2596 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08002597 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
2598 // as well
2599 // 3) If the read buffer is a signed integer format, the draw buffer must be as
2600 // well
Jamie Madill6163c752015-12-07 16:32:59 -05002601 // Changes with EXT_color_buffer_float:
2602 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04002603 GLenum readComponentType = readFormat.info->componentType;
2604 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08002605 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05002606 readComponentType == GL_SIGNED_NORMALIZED);
2607 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
2608 drawComponentType == GL_SIGNED_NORMALIZED);
2609
2610 if (extensions.colorBufferFloat)
2611 {
2612 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
2613 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
2614
2615 if (readFixedOrFloat != drawFixedOrFloat)
2616 {
Jamie Madill437fa652016-05-03 15:13:24 -04002617 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05002618 "If the read buffer contains fixed-point or "
2619 "floating-point values, the draw buffer "
2620 "must as well."));
2621 return false;
2622 }
2623 }
2624 else if (readFixedPoint != drawFixedPoint)
2625 {
Jamie Madill437fa652016-05-03 15:13:24 -04002626 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05002627 "If the read buffer contains fixed-point "
2628 "values, the draw buffer must as well."));
2629 return false;
2630 }
2631
2632 if (readComponentType == GL_UNSIGNED_INT &&
2633 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002634 {
Jamie Madill437fa652016-05-03 15:13:24 -04002635 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002636 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002637 }
2638
Jamie Madill6163c752015-12-07 16:32:59 -05002639 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002640 {
Jamie Madill437fa652016-05-03 15:13:24 -04002641 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002642 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002643 }
2644
Jamie Madilla3944d42016-07-22 22:13:26 -04002645 if (readColorBuffer->getSamples() > 0 &&
2646 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002647 {
Jamie Madill437fa652016-05-03 15:13:24 -04002648 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002650 }
2651 }
2652 }
2653
Jamie Madilla3944d42016-07-22 22:13:26 -04002654 if ((readFormat.info->componentType == GL_INT ||
2655 readFormat.info->componentType == GL_UNSIGNED_INT) &&
2656 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002657 {
Jamie Madill437fa652016-05-03 15:13:24 -04002658 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002659 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002660 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002661 }
He Yunchao66a41a22016-12-15 16:45:05 +08002662 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
2663 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
2664 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
2665 // situation is an application error that would lead to a crash in ANGLE.
2666 else if (drawFramebuffer->hasEnabledDrawBuffer())
2667 {
2668 context->handleError(Error(
2669 GL_INVALID_OPERATION,
2670 "Attempt to read from a missing color attachment of a complete framebuffer."));
2671 return false;
2672 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002673 }
2674
He Yunchaoced53ae2016-11-29 15:00:51 +08002675 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002676 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
2677 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002678 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002679 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002680 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002681 const gl::FramebufferAttachment *readBuffer =
2682 readFramebuffer->getAttachment(attachments[i]);
2683 const gl::FramebufferAttachment *drawBuffer =
2684 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002685
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002686 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002687 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002688 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002689 {
Jamie Madill437fa652016-05-03 15:13:24 -04002690 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002691 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002692 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002693
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002694 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002695 {
Jamie Madill437fa652016-05-03 15:13:24 -04002696 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002697 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002698 }
2699 }
He Yunchao66a41a22016-12-15 16:45:05 +08002700 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
2701 else if (drawBuffer)
2702 {
2703 context->handleError(Error(GL_INVALID_OPERATION,
2704 "Attempt to read from a missing depth/stencil "
2705 "attachment of a complete framebuffer."));
2706 return false;
2707 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002708 }
2709 }
2710
2711 return true;
2712}
2713
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002714bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05002715 GLint x,
2716 GLint y,
2717 GLsizei width,
2718 GLsizei height,
2719 GLenum format,
2720 GLenum type,
2721 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05002722{
Geoff Lange93daba2017-03-30 13:54:40 -04002723 return ValidateReadPixelsBase(context, x, y, width, height, format, type, -1, nullptr, nullptr,
2724 nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04002725}
2726
2727bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
2728 GLint x,
2729 GLint y,
2730 GLsizei width,
2731 GLsizei height,
2732 GLenum format,
2733 GLenum type,
2734 GLsizei bufSize,
2735 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04002736 GLsizei *columns,
2737 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -04002738 GLvoid *pixels)
2739{
2740 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05002741 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002742 return false;
2743 }
2744
Geoff Lang62fce5b2016-09-30 10:46:35 -04002745 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04002746 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05002747 {
Geoff Langb1196682014-07-23 13:47:29 -04002748 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002749 }
2750
Geoff Lang62fce5b2016-09-30 10:46:35 -04002751 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05002752 {
Geoff Langb1196682014-07-23 13:47:29 -04002753 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002754 }
2755
Jamie Madillc29968b2016-01-20 11:17:23 -05002756 return true;
2757}
2758
2759bool ValidateReadnPixelsEXT(Context *context,
2760 GLint x,
2761 GLint y,
2762 GLsizei width,
2763 GLsizei height,
2764 GLenum format,
2765 GLenum type,
2766 GLsizei bufSize,
2767 GLvoid *pixels)
2768{
2769 if (bufSize < 0)
2770 {
Jamie Madill437fa652016-05-03 15:13:24 -04002771 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002772 return false;
2773 }
2774
Geoff Lang62fce5b2016-09-30 10:46:35 -04002775 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04002776 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04002777}
Jamie Madill26e91952014-03-05 15:01:27 -05002778
Geoff Lang62fce5b2016-09-30 10:46:35 -04002779bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
2780 GLint x,
2781 GLint y,
2782 GLsizei width,
2783 GLsizei height,
2784 GLenum format,
2785 GLenum type,
2786 GLsizei bufSize,
2787 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04002788 GLsizei *columns,
2789 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -04002790 GLvoid *data)
2791{
2792 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04002793 {
Jamie Madille2e406c2016-06-02 13:04:10 -04002794 return false;
2795 }
2796
Geoff Lange93daba2017-03-30 13:54:40 -04002797 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
2798 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04002799 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002800 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002801 }
2802
Geoff Lang62fce5b2016-09-30 10:46:35 -04002803 if (!ValidateRobustBufferSize(context, bufSize, *length))
2804 {
2805 return false;
2806 }
2807
2808 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05002809}
2810
Olli Etuaho41997e72016-03-10 13:38:39 +02002811bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002812{
2813 if (!context->getExtensions().occlusionQueryBoolean &&
2814 !context->getExtensions().disjointTimerQuery)
2815 {
Jamie Madill437fa652016-05-03 15:13:24 -04002816 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002817 return false;
2818 }
2819
Olli Etuaho41997e72016-03-10 13:38:39 +02002820 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002821}
2822
Olli Etuaho41997e72016-03-10 13:38:39 +02002823bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002824{
2825 if (!context->getExtensions().occlusionQueryBoolean &&
2826 !context->getExtensions().disjointTimerQuery)
2827 {
Jamie Madill437fa652016-05-03 15:13:24 -04002828 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002829 return false;
2830 }
2831
Olli Etuaho41997e72016-03-10 13:38:39 +02002832 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002833}
2834
2835bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002836{
2837 if (!ValidQueryType(context, target))
2838 {
Jamie Madill437fa652016-05-03 15:13:24 -04002839 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04002840 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002841 }
2842
2843 if (id == 0)
2844 {
Jamie Madill437fa652016-05-03 15:13:24 -04002845 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04002846 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002847 }
2848
2849 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
2850 // of zero, if the active query object name for <target> is non-zero (for the
2851 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
2852 // the active query for either target is non-zero), if <id> is the name of an
2853 // existing query object whose type does not match <target>, or if <id> is the
2854 // active query object name for any query type, the error INVALID_OPERATION is
2855 // generated.
2856
2857 // Ensure no other queries are active
2858 // NOTE: If other queries than occlusion are supported, we will need to check
2859 // separately that:
2860 // a) The query ID passed is not the current active query for any target/type
2861 // b) There are no active queries for the requested target (and in the case
2862 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2863 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002864
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002865 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002866 {
Jamie Madill437fa652016-05-03 15:13:24 -04002867 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04002868 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002869 }
2870
2871 Query *queryObject = context->getQuery(id, true, target);
2872
2873 // check that name was obtained with glGenQueries
2874 if (!queryObject)
2875 {
Jamie Madill437fa652016-05-03 15:13:24 -04002876 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04002877 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002878 }
2879
2880 // check for type mismatch
2881 if (queryObject->getType() != target)
2882 {
Jamie Madill437fa652016-05-03 15:13:24 -04002883 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04002884 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002885 }
2886
2887 return true;
2888}
2889
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002890bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
2891{
2892 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002893 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002894 {
Jamie Madill437fa652016-05-03 15:13:24 -04002895 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002896 return false;
2897 }
2898
2899 return ValidateBeginQueryBase(context, target, id);
2900}
2901
2902bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04002903{
2904 if (!ValidQueryType(context, target))
2905 {
Jamie Madill437fa652016-05-03 15:13:24 -04002906 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04002907 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04002908 }
2909
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002910 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04002911
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002912 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04002913 {
Jamie Madill437fa652016-05-03 15:13:24 -04002914 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04002915 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04002916 }
2917
Jamie Madill45c785d2014-05-13 14:09:34 -04002918 return true;
2919}
2920
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002921bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
2922{
2923 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002924 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002925 {
Jamie Madill437fa652016-05-03 15:13:24 -04002926 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002927 return false;
2928 }
2929
2930 return ValidateEndQueryBase(context, target);
2931}
2932
2933bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
2934{
2935 if (!context->getExtensions().disjointTimerQuery)
2936 {
Jamie Madill437fa652016-05-03 15:13:24 -04002937 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002938 return false;
2939 }
2940
2941 if (target != GL_TIMESTAMP_EXT)
2942 {
Jamie Madill437fa652016-05-03 15:13:24 -04002943 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002944 return false;
2945 }
2946
2947 Query *queryObject = context->getQuery(id, true, target);
2948 if (queryObject == nullptr)
2949 {
Jamie Madill437fa652016-05-03 15:13:24 -04002950 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002951 return false;
2952 }
2953
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002954 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002955 {
Jamie Madill437fa652016-05-03 15:13:24 -04002956 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002957 return false;
2958 }
2959
2960 return true;
2961}
2962
Geoff Lang2186c382016-10-14 10:54:54 -04002963bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002964{
Geoff Lang2186c382016-10-14 10:54:54 -04002965 if (numParams)
2966 {
2967 *numParams = 0;
2968 }
2969
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002970 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
2971 {
Jamie Madill437fa652016-05-03 15:13:24 -04002972 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002973 return false;
2974 }
2975
2976 switch (pname)
2977 {
2978 case GL_CURRENT_QUERY_EXT:
2979 if (target == GL_TIMESTAMP_EXT)
2980 {
Jamie Madill437fa652016-05-03 15:13:24 -04002981 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002982 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
2983 return false;
2984 }
2985 break;
2986 case GL_QUERY_COUNTER_BITS_EXT:
2987 if (!context->getExtensions().disjointTimerQuery ||
2988 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
2989 {
Jamie Madill437fa652016-05-03 15:13:24 -04002990 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002991 return false;
2992 }
2993 break;
2994 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002995 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002996 return false;
2997 }
2998
Geoff Lang2186c382016-10-14 10:54:54 -04002999 if (numParams)
3000 {
3001 // All queries return only one value
3002 *numParams = 1;
3003 }
3004
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003005 return true;
3006}
3007
3008bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
3009{
3010 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04003011 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003012 {
Jamie Madill437fa652016-05-03 15:13:24 -04003013 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003014 return false;
3015 }
3016
Geoff Lang2186c382016-10-14 10:54:54 -04003017 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003018}
3019
Geoff Lang2186c382016-10-14 10:54:54 -04003020bool ValidateGetQueryivRobustANGLE(Context *context,
3021 GLenum target,
3022 GLenum pname,
3023 GLsizei bufSize,
3024 GLsizei *length,
3025 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003026{
Geoff Lang2186c382016-10-14 10:54:54 -04003027 if (!ValidateRobustEntryPoint(context, bufSize))
3028 {
3029 return false;
3030 }
3031
3032 if (!ValidateGetQueryivBase(context, target, pname, length))
3033 {
3034 return false;
3035 }
3036
3037 if (!ValidateRobustBufferSize(context, bufSize, *length))
3038 {
3039 return false;
3040 }
3041
3042 return true;
3043}
3044
3045bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
3046{
3047 if (numParams)
3048 {
3049 *numParams = 0;
3050 }
3051
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003052 Query *queryObject = context->getQuery(id, false, GL_NONE);
3053
3054 if (!queryObject)
3055 {
Jamie Madill437fa652016-05-03 15:13:24 -04003056 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003057 return false;
3058 }
3059
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003060 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003061 {
Jamie Madill437fa652016-05-03 15:13:24 -04003062 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003063 return false;
3064 }
3065
3066 switch (pname)
3067 {
3068 case GL_QUERY_RESULT_EXT:
3069 case GL_QUERY_RESULT_AVAILABLE_EXT:
3070 break;
3071
3072 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003073 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003074 return false;
3075 }
3076
Geoff Lang2186c382016-10-14 10:54:54 -04003077 if (numParams)
3078 {
3079 *numParams = 1;
3080 }
3081
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003082 return true;
3083}
3084
3085bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
3086{
3087 if (!context->getExtensions().disjointTimerQuery)
3088 {
Jamie Madill437fa652016-05-03 15:13:24 -04003089 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003090 return false;
3091 }
Geoff Lang2186c382016-10-14 10:54:54 -04003092 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3093}
3094
3095bool ValidateGetQueryObjectivRobustANGLE(Context *context,
3096 GLuint id,
3097 GLenum pname,
3098 GLsizei bufSize,
3099 GLsizei *length,
3100 GLint *params)
3101{
3102 if (!context->getExtensions().disjointTimerQuery)
3103 {
3104 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3105 return false;
3106 }
3107
3108 if (!ValidateRobustEntryPoint(context, bufSize))
3109 {
3110 return false;
3111 }
3112
3113 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3114 {
3115 return false;
3116 }
3117
3118 if (!ValidateRobustBufferSize(context, bufSize, *length))
3119 {
3120 return false;
3121 }
3122
3123 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003124}
3125
3126bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
3127{
3128 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04003129 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003130 {
Jamie Madill437fa652016-05-03 15:13:24 -04003131 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003132 return false;
3133 }
Geoff Lang2186c382016-10-14 10:54:54 -04003134 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3135}
3136
3137bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
3138 GLuint id,
3139 GLenum pname,
3140 GLsizei bufSize,
3141 GLsizei *length,
3142 GLuint *params)
3143{
3144 if (!context->getExtensions().disjointTimerQuery &&
3145 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
3146 {
3147 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
3148 return false;
3149 }
3150
3151 if (!ValidateRobustEntryPoint(context, bufSize))
3152 {
3153 return false;
3154 }
3155
3156 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3157 {
3158 return false;
3159 }
3160
3161 if (!ValidateRobustBufferSize(context, bufSize, *length))
3162 {
3163 return false;
3164 }
3165
3166 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003167}
3168
3169bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
3170{
3171 if (!context->getExtensions().disjointTimerQuery)
3172 {
Jamie Madill437fa652016-05-03 15:13:24 -04003173 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003174 return false;
3175 }
Geoff Lang2186c382016-10-14 10:54:54 -04003176 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3177}
3178
3179bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
3180 GLuint id,
3181 GLenum pname,
3182 GLsizei bufSize,
3183 GLsizei *length,
3184 GLint64 *params)
3185{
3186 if (!context->getExtensions().disjointTimerQuery)
3187 {
3188 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3189 return false;
3190 }
3191
3192 if (!ValidateRobustEntryPoint(context, bufSize))
3193 {
3194 return false;
3195 }
3196
3197 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3198 {
3199 return false;
3200 }
3201
3202 if (!ValidateRobustBufferSize(context, bufSize, *length))
3203 {
3204 return false;
3205 }
3206
3207 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003208}
3209
3210bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
3211{
3212 if (!context->getExtensions().disjointTimerQuery)
3213 {
Jamie Madill437fa652016-05-03 15:13:24 -04003214 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003215 return false;
3216 }
Geoff Lang2186c382016-10-14 10:54:54 -04003217 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3218}
3219
3220bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
3221 GLuint id,
3222 GLenum pname,
3223 GLsizei bufSize,
3224 GLsizei *length,
3225 GLuint64 *params)
3226{
3227 if (!context->getExtensions().disjointTimerQuery)
3228 {
3229 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3230 return false;
3231 }
3232
3233 if (!ValidateRobustEntryPoint(context, bufSize))
3234 {
3235 return false;
3236 }
3237
3238 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3239 {
3240 return false;
3241 }
3242
3243 if (!ValidateRobustBufferSize(context, bufSize, *length))
3244 {
3245 return false;
3246 }
3247
3248 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003249}
3250
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003251bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003252 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003253 GLuint program,
3254 GLint location,
3255 GLsizei count)
3256{
3257 // Check for ES31 program uniform entry points
3258 if (context->getClientVersion() < Version(3, 1))
3259 {
3260 context->handleError(Error(GL_INVALID_OPERATION));
3261 return false;
3262 }
3263
3264 const LinkedUniform *uniform = nullptr;
3265 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003266 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3267 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003268}
3269
Frank Henigmana98a6472017-02-02 21:38:32 -05003270bool ValidateProgramUniform1iv(gl::Context *context,
3271 GLuint program,
3272 GLint location,
3273 GLsizei count,
3274 const GLint *value)
3275{
3276 // Check for ES31 program uniform entry points
3277 if (context->getClientVersion() < Version(3, 1))
3278 {
3279 context->handleError(Error(GL_INVALID_OPERATION));
3280 return false;
3281 }
3282
3283 const LinkedUniform *uniform = nullptr;
3284 gl::Program *programObject = GetValidProgram(context, program);
3285 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3286 ValidateUniform1ivValue(context, uniform->type, count, value);
3287}
3288
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003289bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003290 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003291 GLuint program,
3292 GLint location,
3293 GLsizei count,
3294 GLboolean transpose)
3295{
3296 // Check for ES31 program uniform entry points
3297 if (context->getClientVersion() < Version(3, 1))
3298 {
3299 context->handleError(Error(GL_INVALID_OPERATION));
3300 return false;
3301 }
3302
3303 const LinkedUniform *uniform = nullptr;
3304 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003305 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3306 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003307}
3308
Jamie Madillc1d770e2017-04-13 17:31:24 -04003309bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003310{
3311 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003312 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003313 {
Jamie Madill437fa652016-05-03 15:13:24 -04003314 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003315 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003316 }
3317
Jamie Madill62d31cb2015-09-11 13:25:51 -04003318 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003319 gl::Program *programObject = context->getGLState().getProgram();
3320 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3321 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04003322}
3323
Frank Henigmana98a6472017-02-02 21:38:32 -05003324bool ValidateUniform1iv(gl::Context *context, GLint location, GLsizei count, const GLint *value)
3325{
3326 const LinkedUniform *uniform = nullptr;
3327 gl::Program *programObject = context->getGLState().getProgram();
3328 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3329 ValidateUniform1ivValue(context, uniform->type, count, value);
3330}
3331
Jamie Madillc1d770e2017-04-13 17:31:24 -04003332bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003333 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08003334 GLint location,
3335 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04003336 GLboolean transpose)
3337{
3338 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003339 int rows = VariableRowCount(valueType);
3340 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03003341 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003342 {
Jamie Madill437fa652016-05-03 15:13:24 -04003343 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003344 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003345 }
3346
Martin Radev1be913c2016-07-11 17:59:16 +03003347 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003348 {
Jamie Madill437fa652016-05-03 15:13:24 -04003349 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003350 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003351 }
3352
Jamie Madill62d31cb2015-09-11 13:25:51 -04003353 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003354 gl::Program *programObject = context->getGLState().getProgram();
3355 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3356 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04003357}
3358
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003359bool ValidateStateQuery(ValidationContext *context,
3360 GLenum pname,
3361 GLenum *nativeType,
3362 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04003363{
3364 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
3365 {
Jamie Madill437fa652016-05-03 15:13:24 -04003366 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003367 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003368 }
3369
Jamie Madill0af26e12015-03-05 19:54:33 -05003370 const Caps &caps = context->getCaps();
3371
Jamie Madill893ab082014-05-16 16:56:10 -04003372 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
3373 {
3374 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
3375
Jamie Madill0af26e12015-03-05 19:54:33 -05003376 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04003377 {
Jamie Madill437fa652016-05-03 15:13:24 -04003378 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003379 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003380 }
3381 }
3382
3383 switch (pname)
3384 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003385 case GL_TEXTURE_BINDING_2D:
3386 case GL_TEXTURE_BINDING_CUBE_MAP:
3387 case GL_TEXTURE_BINDING_3D:
3388 case GL_TEXTURE_BINDING_2D_ARRAY:
3389 break;
3390 case GL_TEXTURE_BINDING_EXTERNAL_OES:
3391 if (!context->getExtensions().eglStreamConsumerExternal &&
3392 !context->getExtensions().eglImageExternal)
3393 {
3394 context->handleError(Error(GL_INVALID_ENUM,
3395 "Neither NV_EGL_stream_consumer_external nor "
3396 "GL_OES_EGL_image_external extensions enabled"));
3397 return false;
3398 }
3399 break;
Jamie Madill893ab082014-05-16 16:56:10 -04003400
He Yunchaoced53ae2016-11-29 15:00:51 +08003401 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
3402 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04003403 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003404 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
3405 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04003406 {
Jamie Madill437fa652016-05-03 15:13:24 -04003407 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003408 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003409 }
3410
Jamie Madill51f40ec2016-06-15 14:06:00 -04003411 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
3412 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03003413
3414 if (framebuffer->getReadBufferState() == GL_NONE)
3415 {
3416 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
3417 return false;
3418 }
3419
Jamie Madillb6bda4a2015-04-20 12:53:26 -04003420 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04003421 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04003422 {
Jamie Madill437fa652016-05-03 15:13:24 -04003423 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003424 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003425 }
3426 }
3427 break;
3428
He Yunchaoced53ae2016-11-29 15:00:51 +08003429 default:
3430 break;
Jamie Madill893ab082014-05-16 16:56:10 -04003431 }
3432
3433 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04003434 if (*numParams == 0)
3435 {
3436 return false;
3437 }
3438
3439 return true;
3440}
3441
3442bool ValidateRobustStateQuery(ValidationContext *context,
3443 GLenum pname,
3444 GLsizei bufSize,
3445 GLenum *nativeType,
3446 unsigned int *numParams)
3447{
3448 if (!ValidateRobustEntryPoint(context, bufSize))
3449 {
3450 return false;
3451 }
3452
3453 if (!ValidateStateQuery(context, pname, nativeType, numParams))
3454 {
3455 return false;
3456 }
3457
3458 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04003459 {
3460 return false;
3461 }
3462
3463 return true;
3464}
3465
Jamie Madillc29968b2016-01-20 11:17:23 -05003466bool ValidateCopyTexImageParametersBase(ValidationContext *context,
3467 GLenum target,
3468 GLint level,
3469 GLenum internalformat,
3470 bool isSubImage,
3471 GLint xoffset,
3472 GLint yoffset,
3473 GLint zoffset,
3474 GLint x,
3475 GLint y,
3476 GLsizei width,
3477 GLsizei height,
3478 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04003479 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04003480{
Jamie Madill560a8d82014-05-21 13:06:20 -04003481 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
3482 {
Jamie Madill437fa652016-05-03 15:13:24 -04003483 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003484 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003485 }
3486
He Yunchaoced53ae2016-11-29 15:00:51 +08003487 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
3488 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04003489 {
Jamie Madill437fa652016-05-03 15:13:24 -04003490 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003491 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003492 }
3493
3494 if (border != 0)
3495 {
Jamie Madill437fa652016-05-03 15:13:24 -04003496 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003497 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003498 }
3499
3500 if (!ValidMipLevel(context, target, level))
3501 {
Jamie Madill437fa652016-05-03 15:13:24 -04003502 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003503 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003504 }
3505
Jamie Madill51f40ec2016-06-15 14:06:00 -04003506 const auto &state = context->getGLState();
3507 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003508 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04003509 {
Jamie Madill437fa652016-05-03 15:13:24 -04003510 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003511 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003512 }
3513
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003514 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04003515 {
Jamie Madill437fa652016-05-03 15:13:24 -04003516 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003517 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003518 }
3519
Martin Radev138064f2016-07-15 12:03:41 +03003520 if (readFramebuffer->getReadBufferState() == GL_NONE)
3521 {
3522 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
3523 return false;
3524 }
3525
Corentin Wallez3c90ed62016-12-16 16:19:28 -05003526 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
3527 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08003528 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05003529 // situation is an application error that would lead to a crash in ANGLE.
3530 if (readFramebuffer->getReadColorbuffer() == nullptr)
3531 {
3532 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
3533 return false;
3534 }
3535
Geoff Langaae65a42014-05-26 12:43:44 -04003536 const gl::Caps &caps = context->getCaps();
3537
Geoff Langaae65a42014-05-26 12:43:44 -04003538 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04003539 switch (target)
3540 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003541 case GL_TEXTURE_2D:
3542 maxDimension = caps.max2DTextureSize;
3543 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003544
He Yunchaoced53ae2016-11-29 15:00:51 +08003545 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
3546 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
3547 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
3548 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
3549 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
3550 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
3551 maxDimension = caps.maxCubeMapTextureSize;
3552 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003553
He Yunchaoced53ae2016-11-29 15:00:51 +08003554 case GL_TEXTURE_2D_ARRAY:
3555 maxDimension = caps.max2DTextureSize;
3556 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003557
He Yunchaoced53ae2016-11-29 15:00:51 +08003558 case GL_TEXTURE_3D:
3559 maxDimension = caps.max3DTextureSize;
3560 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003561
He Yunchaoced53ae2016-11-29 15:00:51 +08003562 default:
3563 context->handleError(Error(GL_INVALID_ENUM));
3564 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003565 }
3566
Jamie Madillc29968b2016-01-20 11:17:23 -05003567 gl::Texture *texture =
3568 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04003569 if (!texture)
3570 {
Jamie Madill437fa652016-05-03 15:13:24 -04003571 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003572 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003573 }
3574
Geoff Lang69cce582015-09-17 13:20:36 -04003575 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04003576 {
Jamie Madill437fa652016-05-03 15:13:24 -04003577 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003578 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003579 }
3580
Geoff Langca271392017-04-05 12:30:00 -04003581 const gl::InternalFormat &formatInfo =
3582 gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04003583
3584 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04003585 {
Jamie Madill437fa652016-05-03 15:13:24 -04003586 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003587 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003588 }
3589
Geoff Lang44ff5a72017-02-03 15:15:43 -05003590 if (formatInfo.compressed &&
3591 !ValidCompressedImageSize(context, internalformat, xoffset, yoffset, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04003592 {
Jamie Madill437fa652016-05-03 15:13:24 -04003593 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05003594 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003595 }
3596
3597 if (isSubImage)
3598 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05003599 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
3600 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
3601 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04003602 {
Jamie Madill437fa652016-05-03 15:13:24 -04003603 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003604 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003605 }
3606 }
Jamie Madill6f38f822014-06-06 17:12:20 -04003607 else
3608 {
Geoff Lang691e58c2014-12-19 17:03:25 -05003609 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04003610 {
Jamie Madill437fa652016-05-03 15:13:24 -04003611 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003612 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003613 }
3614
Geoff Langeb66a6e2016-10-31 13:06:12 -04003615 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04003616 {
Jamie Madill437fa652016-05-03 15:13:24 -04003617 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003618 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003619 }
3620
3621 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08003622 if (static_cast<int>(width) > maxLevelDimension ||
3623 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04003624 {
Jamie Madill437fa652016-05-03 15:13:24 -04003625 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003626 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003627 }
3628 }
Jamie Madill560a8d82014-05-21 13:06:20 -04003629
Jamie Madill0c8abca2016-07-22 20:21:26 -04003630 if (textureFormatOut)
3631 {
3632 *textureFormatOut = texture->getFormat(target, level);
3633 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05003634
3635 // Detect texture copying feedback loops for WebGL.
3636 if (context->getExtensions().webglCompatibility)
3637 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05003638 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05003639 {
3640 context->handleError(Error(GL_INVALID_OPERATION,
3641 "Texture copying feedback loop formed between Framebuffer "
3642 "and specified Texture level."));
3643 return false;
3644 }
3645 }
3646
Jamie Madill560a8d82014-05-21 13:06:20 -04003647 return true;
3648}
3649
Jiajia Qind9671222016-11-29 16:30:31 +08003650bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04003651{
Jamie Madill1aeb1312014-06-20 13:21:25 -04003652 switch (mode)
3653 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003654 case GL_POINTS:
3655 case GL_LINES:
3656 case GL_LINE_LOOP:
3657 case GL_LINE_STRIP:
3658 case GL_TRIANGLES:
3659 case GL_TRIANGLE_STRIP:
3660 case GL_TRIANGLE_FAN:
3661 break;
3662 default:
3663 context->handleError(Error(GL_INVALID_ENUM));
3664 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04003665 }
3666
Jamie Madill250d33f2014-06-06 17:09:03 -04003667 if (count < 0)
3668 {
Jamie Madill437fa652016-05-03 15:13:24 -04003669 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003670 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003671 }
3672
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003673 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04003674
Jamie Madill250d33f2014-06-06 17:09:03 -04003675 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003676 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04003677 {
Jamie Madill437fa652016-05-03 15:13:24 -04003678 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003679 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003680 }
3681
Jamie Madillcbcde722017-01-06 14:50:00 -05003682 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
3683 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04003684 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003685 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
3686 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04003687 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003688 const FramebufferAttachment *dsAttachment =
3689 framebuffer->getStencilOrDepthStencilAttachment();
3690 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08003691 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04003692 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003693
3694 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
3695 bool differentWritemasks =
3696 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
3697 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
3698 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
3699 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
3700
3701 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04003702 {
Jamie Madillcbcde722017-01-06 14:50:00 -05003703 if (!context->getExtensions().webglCompatibility)
3704 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05003705 ERR() << "This ANGLE implementation does not support separate front/back stencil "
3706 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05003707 }
Jamie Madill437fa652016-05-03 15:13:24 -04003708 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04003709 return false;
3710 }
Jamie Madillac528012014-06-20 13:21:23 -04003711 }
3712
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003713 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04003714 {
Jamie Madill437fa652016-05-03 15:13:24 -04003715 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003716 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04003717 }
3718
Geoff Lang7dd2e102014-11-10 15:19:26 -05003719 gl::Program *program = state.getProgram();
3720 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04003721 {
Jamie Madill437fa652016-05-03 15:13:24 -04003722 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003723 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04003724 }
3725
Geoff Lang7dd2e102014-11-10 15:19:26 -05003726 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04003727 {
Jamie Madill437fa652016-05-03 15:13:24 -04003728 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003729 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04003730 }
3731
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003732 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08003733 for (unsigned int uniformBlockIndex = 0;
3734 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003735 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003736 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08003737 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04003738 const OffsetBindingPointer<Buffer> &uniformBuffer =
3739 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003740
Geoff Lang5d124a62015-09-15 13:03:27 -04003741 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003742 {
3743 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04003744 context->handleError(
3745 Error(GL_INVALID_OPERATION,
3746 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003747 return false;
3748 }
3749
Geoff Lang5d124a62015-09-15 13:03:27 -04003750 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003751 if (uniformBufferSize == 0)
3752 {
3753 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07003754 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003755 }
3756
Jamie Madill62d31cb2015-09-11 13:25:51 -04003757 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003758 {
3759 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04003760 context->handleError(
3761 Error(GL_INVALID_OPERATION,
3762 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003763 return false;
3764 }
3765 }
3766
Jamie Madilla4595b82017-01-11 17:36:34 -05003767 // Detect rendering feedback loops for WebGL.
3768 if (context->getExtensions().webglCompatibility)
3769 {
3770 if (framebuffer->formsRenderingFeedbackLoopWith(state))
3771 {
3772 context->handleError(
3773 Error(GL_INVALID_OPERATION,
3774 "Rendering feedback loop formed between Framebuffer and active Texture."));
3775 return false;
3776 }
3777 }
3778
Jamie Madill250d33f2014-06-06 17:09:03 -04003779 // No-op if zero count
3780 return (count > 0);
3781}
3782
Jamie Madillc1d770e2017-04-13 17:31:24 -04003783bool ValidateDrawArraysCommon(ValidationContext *context,
3784 GLenum mode,
3785 GLint first,
3786 GLsizei count,
3787 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04003788{
Jamie Madillfd716582014-06-06 17:09:04 -04003789 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04003790 {
Jamie Madill437fa652016-05-03 15:13:24 -04003791 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003792 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003793 }
3794
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003795 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003796 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08003797 if (curTransformFeedback && curTransformFeedback->isActive() &&
3798 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04003799 {
3800 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08003801 // that does not match the current transform feedback object's draw mode (if transform
3802 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04003803 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04003804 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003805 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04003806 }
3807
Jiajia Qind9671222016-11-29 16:30:31 +08003808 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07003809 {
3810 return false;
3811 }
3812
Corentin Wallez71168a02016-12-19 15:11:18 -08003813 // Check the computation of maxVertex doesn't overflow.
3814 // - first < 0 or count < 0 have been checked as an error condition
3815 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
3816 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
3817 ASSERT(count > 0 && first >= 0);
3818 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
3819 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05003820 {
3821 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
3822 return false;
3823 }
3824
Corentin Wallez71168a02016-12-19 15:11:18 -08003825 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04003826 {
3827 return false;
3828 }
3829
3830 return true;
3831}
3832
He Yunchaoced53ae2016-11-29 15:00:51 +08003833bool ValidateDrawArraysInstanced(Context *context,
3834 GLenum mode,
3835 GLint first,
3836 GLsizei count,
3837 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003838{
Geoff Lang407d4e72017-04-12 14:54:11 -04003839 if (context->getExtensions().webglCompatibility && !ValidateDrawInstancedANGLEAndWebGL(context))
Jamie Madillfd716582014-06-06 17:09:04 -04003840 {
3841 return false;
3842 }
3843
Geoff Lang407d4e72017-04-12 14:54:11 -04003844 return ValidateDrawArraysInstancedBase(context, mode, first, count, primcount);
Geoff Lang87a93302014-09-16 13:29:43 -04003845}
3846
He Yunchaoced53ae2016-11-29 15:00:51 +08003847bool ValidateDrawArraysInstancedANGLE(Context *context,
3848 GLenum mode,
3849 GLint first,
3850 GLsizei count,
3851 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003852{
Geoff Lang407d4e72017-04-12 14:54:11 -04003853 if (!ValidateDrawInstancedANGLEAndWebGL(context))
Geoff Lang87a93302014-09-16 13:29:43 -04003854 {
3855 return false;
3856 }
3857
Geoff Lang407d4e72017-04-12 14:54:11 -04003858 return ValidateDrawArraysInstancedBase(context, mode, first, count, primcount);
Geoff Lang87a93302014-09-16 13:29:43 -04003859}
3860
Jiajia Qind9671222016-11-29 16:30:31 +08003861bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04003862{
Jamie Madill250d33f2014-06-06 17:09:03 -04003863 switch (type)
3864 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003865 case GL_UNSIGNED_BYTE:
3866 case GL_UNSIGNED_SHORT:
3867 break;
3868 case GL_UNSIGNED_INT:
3869 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
3870 {
3871 context->handleError(Error(GL_INVALID_ENUM));
3872 return false;
3873 }
3874 break;
3875 default:
3876 context->handleError(Error(GL_INVALID_ENUM));
3877 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003878 }
3879
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003880 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003881
3882 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08003883 if (curTransformFeedback && curTransformFeedback->isActive() &&
3884 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04003885 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003886 // It is an invalid operation to call DrawElements, DrawRangeElements or
3887 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04003888 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04003889 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003890 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003891 }
3892
Jiajia Qind9671222016-11-29 16:30:31 +08003893 return true;
3894}
3895
3896bool ValidateDrawElements(ValidationContext *context,
3897 GLenum mode,
3898 GLsizei count,
3899 GLenum type,
3900 const GLvoid *indices,
3901 GLsizei primcount,
3902 IndexRange *indexRangeOut)
3903{
3904 if (!ValidateDrawElementsBase(context, type))
3905 return false;
3906
3907 const State &state = context->getGLState();
3908
Jamie Madill250d33f2014-06-06 17:09:03 -04003909 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003910 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04003911 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003912 context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
Geoff Langb1196682014-07-23 13:47:29 -04003913 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003914 }
3915
He Yunchaoced53ae2016-11-29 15:00:51 +08003916 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04003917 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04003918
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05003919 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
3920
3921 if (context->getExtensions().webglCompatibility)
3922 {
3923 ASSERT(isPow2(typeBytes) && typeBytes > 0);
3924 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
3925 {
3926 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
3927 // The offset arguments to drawElements and [...], must be a multiple of the size of the
3928 // data type passed to the call, or an INVALID_OPERATION error is generated.
3929 context->handleError(Error(GL_INVALID_OPERATION,
3930 "indices must be a multiple of the element type size."));
3931 return false;
3932 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003933
3934 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
3935 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
3936 // error is generated.
3937 if (reinterpret_cast<intptr_t>(indices) < 0)
3938 {
3939 context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
3940 return false;
3941 }
Geoff Langfeb8c682017-02-13 16:07:35 -05003942 }
3943
3944 if (context->getExtensions().webglCompatibility ||
3945 !context->getGLState().areClientArraysEnabled())
3946 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05003947 if (!elementArrayBuffer && count > 0)
3948 {
3949 // [WebGL 1.0] Section 6.2 No Client Side Arrays
3950 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
3951 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
3952 context->handleError(Error(GL_INVALID_OPERATION,
3953 "There is no element array buffer bound and count > 0."));
3954 return false;
3955 }
3956 }
3957
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003958 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04003959 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003960 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04003961 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003962 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
3963 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
3964 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
3965 constexpr uint64_t kMaxTypeSize = 8;
3966 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
3967 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
3968 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003969
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003970 uint64_t typeSize = typeBytes;
3971 uint64_t elementCount = static_cast<uint64_t>(count);
3972 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
3973
3974 // Doing the multiplication here is overflow-safe
3975 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
3976
3977 // The offset can be any value, check for overflows
3978 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
3979 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003980 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003981 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003982 return false;
3983 }
3984
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003985 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
3986 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003987 {
3988 context->handleError(
3989 Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
3990 return false;
3991 }
3992 }
3993 else if (!indices)
3994 {
3995 // This is an application error that would normally result in a crash,
3996 // but we catch it and return an error
3997 context->handleError(
3998 Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
Geoff Langb1196682014-07-23 13:47:29 -04003999 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04004000 }
Jamie Madillae3000b2014-08-25 15:47:51 -04004001 }
4002
Jiajia Qind9671222016-11-29 16:30:31 +08004003 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07004004 {
4005 return false;
4006 }
4007
Jamie Madill2b976812014-08-25 15:47:49 -04004008 // Use max index to validate if our vertex buffers are large enough for the pull.
4009 // TODO: offer fast path, with disabled index validation.
4010 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
4011 if (elementArrayBuffer)
4012 {
Jacek Cabana5521de2014-10-01 17:23:46 +02004013 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04004014 Error error =
4015 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
4016 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04004017 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04004018 {
Jamie Madill437fa652016-05-03 15:13:24 -04004019 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04004020 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04004021 }
4022 }
4023 else
4024 {
Geoff Lang3edfe032015-09-04 16:38:24 -04004025 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04004026 }
4027
Jamie Madille79b1e12015-11-04 16:36:37 -05004028 // If we use an index greater than our maximum supported index range, return an error.
4029 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
4030 // return an error if possible here.
4031 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
4032 {
Jamie Madill437fa652016-05-03 15:13:24 -04004033 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05004034 return false;
4035 }
4036
Corentin Wallez92db6942016-12-09 13:10:36 -05004037 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->end),
4038 static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04004039 {
4040 return false;
4041 }
4042
Geoff Lang3edfe032015-09-04 16:38:24 -04004043 // No op if there are no real indices in the index data (all are primitive restart).
4044 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04004045}
4046
Geoff Langb1196682014-07-23 13:47:29 -04004047bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04004048 GLenum mode,
4049 GLsizei count,
4050 GLenum type,
4051 const GLvoid *indices,
4052 GLsizei primcount,
4053 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04004054{
Geoff Lang407d4e72017-04-12 14:54:11 -04004055 if (context->getExtensions().webglCompatibility && !ValidateDrawInstancedANGLEAndWebGL(context))
Jamie Madillfd716582014-06-06 17:09:04 -04004056 {
4057 return false;
4058 }
4059
Geoff Lang407d4e72017-04-12 14:54:11 -04004060 return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount,
4061 indexRangeOut);
Jamie Madill250d33f2014-06-06 17:09:03 -04004062}
4063
Geoff Lang3edfe032015-09-04 16:38:24 -04004064bool ValidateDrawElementsInstancedANGLE(Context *context,
4065 GLenum mode,
4066 GLsizei count,
4067 GLenum type,
4068 const GLvoid *indices,
4069 GLsizei primcount,
4070 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04004071{
Geoff Lang407d4e72017-04-12 14:54:11 -04004072 if (!ValidateDrawInstancedANGLEAndWebGL(context))
Geoff Lang87a93302014-09-16 13:29:43 -04004073 {
4074 return false;
4075 }
4076
Geoff Lang407d4e72017-04-12 14:54:11 -04004077 return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount,
4078 indexRangeOut);
Geoff Lang87a93302014-09-16 13:29:43 -04004079}
4080
He Yunchaoced53ae2016-11-29 15:00:51 +08004081bool ValidateFramebufferTextureBase(Context *context,
4082 GLenum target,
4083 GLenum attachment,
4084 GLuint texture,
4085 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04004086{
Jamie Madill55ec3b12014-07-03 10:38:57 -04004087 if (!ValidFramebufferTarget(target))
4088 {
Jamie Madill437fa652016-05-03 15:13:24 -04004089 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04004090 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004091 }
4092
4093 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04004094 {
4095 return false;
4096 }
4097
Jamie Madill55ec3b12014-07-03 10:38:57 -04004098 if (texture != 0)
4099 {
4100 gl::Texture *tex = context->getTexture(texture);
4101
Yunchao He4f285442017-04-21 12:15:49 +08004102 if (tex == nullptr)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004103 {
Jamie Madill437fa652016-05-03 15:13:24 -04004104 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004105 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004106 }
4107
4108 if (level < 0)
4109 {
Jamie Madill437fa652016-05-03 15:13:24 -04004110 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004111 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004112 }
4113 }
4114
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004115 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04004116 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04004117
Jamie Madill84115c92015-04-23 15:00:07 -04004118 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004119 {
Jamie Madill437fa652016-05-03 15:13:24 -04004120 context->handleError(
4121 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04004122 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004123 }
4124
4125 return true;
4126}
4127
He Yunchaoced53ae2016-11-29 15:00:51 +08004128bool ValidateFramebufferTexture2D(Context *context,
4129 GLenum target,
4130 GLenum attachment,
4131 GLenum textarget,
4132 GLuint texture,
4133 GLint level)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004134{
He Yunchaoced53ae2016-11-29 15:00:51 +08004135 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap
4136 // extension
Martin Radev1be913c2016-07-11 17:59:16 +03004137 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
4138 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004139 {
Jamie Madill437fa652016-05-03 15:13:24 -04004140 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004141 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004142 }
4143
4144 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04004145 {
4146 return false;
4147 }
4148
Jamie Madill55ec3b12014-07-03 10:38:57 -04004149 if (texture != 0)
4150 {
4151 gl::Texture *tex = context->getTexture(texture);
4152 ASSERT(tex);
4153
Jamie Madill2a6564e2014-07-11 09:53:19 -04004154 const gl::Caps &caps = context->getCaps();
4155
Jamie Madill55ec3b12014-07-03 10:38:57 -04004156 switch (textarget)
4157 {
He Yunchaoced53ae2016-11-29 15:00:51 +08004158 case GL_TEXTURE_2D:
Jamie Madill55ec3b12014-07-03 10:38:57 -04004159 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04004160 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04004161 {
Jamie Madill437fa652016-05-03 15:13:24 -04004162 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004163 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004164 }
4165 if (tex->getTarget() != GL_TEXTURE_2D)
4166 {
JiangYizhoubddc46b2016-12-09 09:50:51 +08004167 context->handleError(Error(GL_INVALID_OPERATION,
4168 "Textarget must match the texture target type."));
Geoff Langb1196682014-07-23 13:47:29 -04004169 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004170 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004171 }
4172 break;
4173
He Yunchaoced53ae2016-11-29 15:00:51 +08004174 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4175 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4176 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4177 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4178 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4179 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Jamie Madill55ec3b12014-07-03 10:38:57 -04004180 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04004181 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04004182 {
Jamie Madill437fa652016-05-03 15:13:24 -04004183 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004184 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004185 }
4186 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
4187 {
JiangYizhoubddc46b2016-12-09 09:50:51 +08004188 context->handleError(Error(GL_INVALID_OPERATION,
4189 "Textarget must match the texture target type."));
4190 return false;
4191 }
4192 }
4193 break;
4194
4195 case GL_TEXTURE_2D_MULTISAMPLE:
4196 {
4197 if (context->getClientVersion() < ES_3_1)
4198 {
4199 context->handleError(Error(GL_INVALID_OPERATION,
4200 "Texture target requires at least OpenGL ES 3.1."));
4201 return false;
4202 }
4203
4204 if (level != 0)
4205 {
4206 context->handleError(
4207 Error(GL_INVALID_VALUE, "Level must be 0 for TEXTURE_2D_MULTISAMPLE."));
4208 return false;
4209 }
4210 if (tex->getTarget() != GL_TEXTURE_2D_MULTISAMPLE)
4211 {
4212 context->handleError(Error(GL_INVALID_OPERATION,
4213 "Textarget must match the texture target type."));
Geoff Langb1196682014-07-23 13:47:29 -04004214 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004215 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004216 }
4217 break;
4218
He Yunchaoced53ae2016-11-29 15:00:51 +08004219 default:
4220 context->handleError(Error(GL_INVALID_ENUM));
4221 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004222 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05004223
Jamie Madilla3944d42016-07-22 22:13:26 -04004224 const Format &format = tex->getFormat(textarget, level);
4225 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05004226 {
Jamie Madill437fa652016-05-03 15:13:24 -04004227 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05004228 return false;
4229 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004230 }
4231
Jamie Madill570f7c82014-07-03 10:38:54 -04004232 return true;
4233}
4234
Geoff Langb1196682014-07-23 13:47:29 -04004235bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04004236{
4237 if (program == 0)
4238 {
Jamie Madill437fa652016-05-03 15:13:24 -04004239 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004240 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004241 }
4242
Dian Xiang769769a2015-09-09 15:20:08 -07004243 gl::Program *programObject = GetValidProgram(context, program);
4244 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05004245 {
4246 return false;
4247 }
4248
Jamie Madill0063c512014-08-25 15:47:53 -04004249 if (!programObject || !programObject->isLinked())
4250 {
Jamie Madill437fa652016-05-03 15:13:24 -04004251 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004252 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004253 }
4254
Geoff Lang7dd2e102014-11-10 15:19:26 -05004255 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04004256 {
Jamie Madill437fa652016-05-03 15:13:24 -04004257 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004258 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04004259 }
4260
Jamie Madill0063c512014-08-25 15:47:53 -04004261 return true;
4262}
4263
He Yunchaoced53ae2016-11-29 15:00:51 +08004264bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params)
Jamie Madill78f41802014-08-25 15:47:55 -04004265{
4266 return ValidateGetUniformBase(context, program, location);
4267}
4268
He Yunchaoced53ae2016-11-29 15:00:51 +08004269bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004270{
Jamie Madill78f41802014-08-25 15:47:55 -04004271 return ValidateGetUniformBase(context, program, location);
4272}
4273
Geoff Langf41d0ee2016-10-07 13:04:23 -04004274static bool ValidateSizedGetUniform(Context *context,
4275 GLuint program,
4276 GLint location,
4277 GLsizei bufSize,
4278 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04004279{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004280 if (length)
4281 {
4282 *length = 0;
4283 }
4284
Jamie Madill78f41802014-08-25 15:47:55 -04004285 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04004286 {
Jamie Madill78f41802014-08-25 15:47:55 -04004287 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004288 }
4289
Geoff Langf41d0ee2016-10-07 13:04:23 -04004290 if (bufSize < 0)
4291 {
4292 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
4293 return false;
4294 }
4295
Jamie Madilla502c742014-08-28 17:19:13 -04004296 gl::Program *programObject = context->getProgram(program);
4297 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04004298
Jamie Madill78f41802014-08-25 15:47:55 -04004299 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04004300 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08004301 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04004302 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04004303 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04004304 context->handleError(
4305 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04004306 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004307 }
4308
Geoff Langf41d0ee2016-10-07 13:04:23 -04004309 if (length)
4310 {
Geoff Lang94177fb2016-11-14 16:12:26 -05004311 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04004312 }
4313
Jamie Madill0063c512014-08-25 15:47:53 -04004314 return true;
4315}
4316
He Yunchaoced53ae2016-11-29 15:00:51 +08004317bool ValidateGetnUniformfvEXT(Context *context,
4318 GLuint program,
4319 GLint location,
4320 GLsizei bufSize,
4321 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004322{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004323 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04004324}
4325
He Yunchaoced53ae2016-11-29 15:00:51 +08004326bool ValidateGetnUniformivEXT(Context *context,
4327 GLuint program,
4328 GLint location,
4329 GLsizei bufSize,
4330 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004331{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004332 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
4333}
4334
4335bool ValidateGetUniformfvRobustANGLE(Context *context,
4336 GLuint program,
4337 GLint location,
4338 GLsizei bufSize,
4339 GLsizei *length,
4340 GLfloat *params)
4341{
4342 if (!ValidateRobustEntryPoint(context, bufSize))
4343 {
4344 return false;
4345 }
4346
4347 // bufSize is validated in ValidateSizedGetUniform
4348 return ValidateSizedGetUniform(context, program, location, bufSize, length);
4349}
4350
4351bool ValidateGetUniformivRobustANGLE(Context *context,
4352 GLuint program,
4353 GLint location,
4354 GLsizei bufSize,
4355 GLsizei *length,
4356 GLint *params)
4357{
4358 if (!ValidateRobustEntryPoint(context, bufSize))
4359 {
4360 return false;
4361 }
4362
4363 // bufSize is validated in ValidateSizedGetUniform
4364 return ValidateSizedGetUniform(context, program, location, bufSize, length);
4365}
4366
4367bool ValidateGetUniformuivRobustANGLE(Context *context,
4368 GLuint program,
4369 GLint location,
4370 GLsizei bufSize,
4371 GLsizei *length,
4372 GLuint *params)
4373{
4374 if (!ValidateRobustEntryPoint(context, bufSize))
4375 {
4376 return false;
4377 }
4378
4379 if (context->getClientMajorVersion() < 3)
4380 {
4381 context->handleError(
4382 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
4383 return false;
4384 }
4385
4386 // bufSize is validated in ValidateSizedGetUniform
4387 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04004388}
4389
He Yunchaoced53ae2016-11-29 15:00:51 +08004390bool ValidateDiscardFramebufferBase(Context *context,
4391 GLenum target,
4392 GLsizei numAttachments,
4393 const GLenum *attachments,
4394 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07004395{
4396 if (numAttachments < 0)
4397 {
Jamie Madill437fa652016-05-03 15:13:24 -04004398 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07004399 return false;
4400 }
4401
4402 for (GLsizei i = 0; i < numAttachments; ++i)
4403 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02004404 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07004405 {
4406 if (defaultFramebuffer)
4407 {
Jamie Madill437fa652016-05-03 15:13:24 -04004408 context->handleError(Error(
4409 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07004410 return false;
4411 }
4412
4413 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
4414 {
Jamie Madill437fa652016-05-03 15:13:24 -04004415 context->handleError(Error(GL_INVALID_OPERATION,
4416 "Requested color attachment is greater than the maximum "
4417 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07004418 return false;
4419 }
4420 }
4421 else
4422 {
4423 switch (attachments[i])
4424 {
He Yunchaoced53ae2016-11-29 15:00:51 +08004425 case GL_DEPTH_ATTACHMENT:
4426 case GL_STENCIL_ATTACHMENT:
4427 case GL_DEPTH_STENCIL_ATTACHMENT:
4428 if (defaultFramebuffer)
4429 {
4430 context->handleError(
4431 Error(GL_INVALID_ENUM,
4432 "Invalid attachment when the default framebuffer is bound"));
4433 return false;
4434 }
4435 break;
4436 case GL_COLOR:
4437 case GL_DEPTH:
4438 case GL_STENCIL:
4439 if (!defaultFramebuffer)
4440 {
4441 context->handleError(
4442 Error(GL_INVALID_ENUM,
4443 "Invalid attachment when the default framebuffer is not bound"));
4444 return false;
4445 }
4446 break;
4447 default:
4448 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07004449 return false;
Austin Kinross08332632015-05-05 13:35:47 -07004450 }
4451 }
4452 }
4453
4454 return true;
4455}
4456
Austin Kinross6ee1e782015-05-29 17:05:37 -07004457bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
4458{
4459 // Note that debug marker calls must not set error state
4460
4461 if (length < 0)
4462 {
4463 return false;
4464 }
4465
4466 if (marker == nullptr)
4467 {
4468 return false;
4469 }
4470
4471 return true;
4472}
4473
4474bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
4475{
4476 // Note that debug marker calls must not set error state
4477
4478 if (length < 0)
4479 {
4480 return false;
4481 }
4482
4483 if (length > 0 && marker == nullptr)
4484 {
4485 return false;
4486 }
4487
4488 return true;
4489}
4490
Geoff Langdcab33b2015-07-21 13:03:16 -04004491bool ValidateEGLImageTargetTexture2DOES(Context *context,
4492 egl::Display *display,
4493 GLenum target,
4494 egl::Image *image)
4495{
Geoff Langa8406172015-07-21 16:53:39 -04004496 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
4497 {
Jamie Madill437fa652016-05-03 15:13:24 -04004498 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04004499 return false;
4500 }
4501
4502 switch (target)
4503 {
4504 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04004505 if (!context->getExtensions().eglImage)
4506 {
4507 context->handleError(Error(
4508 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
4509 }
4510 break;
4511
4512 case GL_TEXTURE_EXTERNAL_OES:
4513 if (!context->getExtensions().eglImageExternal)
4514 {
4515 context->handleError(Error(
4516 GL_INVALID_ENUM,
4517 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
4518 }
Geoff Langa8406172015-07-21 16:53:39 -04004519 break;
4520
4521 default:
Jamie Madill437fa652016-05-03 15:13:24 -04004522 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04004523 return false;
4524 }
4525
4526 if (!display->isValidImage(image))
4527 {
Jamie Madill437fa652016-05-03 15:13:24 -04004528 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04004529 return false;
4530 }
4531
4532 if (image->getSamples() > 0)
4533 {
Jamie Madill437fa652016-05-03 15:13:24 -04004534 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04004535 "cannot create a 2D texture from a multisampled EGL image."));
4536 return false;
4537 }
4538
Geoff Langca271392017-04-05 12:30:00 -04004539 const TextureCaps &textureCaps =
4540 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04004541 if (!textureCaps.texturable)
4542 {
Jamie Madill437fa652016-05-03 15:13:24 -04004543 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04004544 "EGL image internal format is not supported as a texture."));
4545 return false;
4546 }
4547
Geoff Langdcab33b2015-07-21 13:03:16 -04004548 return true;
4549}
4550
4551bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
4552 egl::Display *display,
4553 GLenum target,
4554 egl::Image *image)
4555{
Geoff Langa8406172015-07-21 16:53:39 -04004556 if (!context->getExtensions().eglImage)
4557 {
Jamie Madill437fa652016-05-03 15:13:24 -04004558 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04004559 return false;
4560 }
4561
4562 switch (target)
4563 {
4564 case GL_RENDERBUFFER:
4565 break;
4566
4567 default:
Jamie Madill437fa652016-05-03 15:13:24 -04004568 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04004569 return false;
4570 }
4571
4572 if (!display->isValidImage(image))
4573 {
Jamie Madill437fa652016-05-03 15:13:24 -04004574 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04004575 return false;
4576 }
4577
Geoff Langca271392017-04-05 12:30:00 -04004578 const TextureCaps &textureCaps =
4579 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04004580 if (!textureCaps.renderable)
4581 {
Jamie Madill437fa652016-05-03 15:13:24 -04004582 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04004583 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
4584 return false;
4585 }
4586
Geoff Langdcab33b2015-07-21 13:03:16 -04004587 return true;
4588}
Austin Kinrossbc781f32015-10-26 09:27:38 -07004589
4590bool ValidateBindVertexArrayBase(Context *context, GLuint array)
4591{
Geoff Lang36167ab2015-12-07 10:27:14 -05004592 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07004593 {
4594 // The default VAO should always exist
4595 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04004596 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07004597 return false;
4598 }
4599
4600 return true;
4601}
4602
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004603bool ValidateLinkProgram(Context *context, GLuint program)
4604{
4605 if (context->hasActiveTransformFeedback(program))
4606 {
4607 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004608 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004609 "Cannot link program while program is associated with an active "
4610 "transform feedback object."));
4611 return false;
4612 }
Jamie Madillc1d770e2017-04-13 17:31:24 -04004613
4614 Program *programObject = GetValidProgram(context, program);
4615 if (!programObject)
4616 {
4617 return false;
4618 }
4619
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004620 return true;
4621}
4622
Geoff Langc5629752015-12-07 16:29:04 -05004623bool ValidateProgramBinaryBase(Context *context,
4624 GLuint program,
4625 GLenum binaryFormat,
4626 const void *binary,
4627 GLint length)
4628{
4629 Program *programObject = GetValidProgram(context, program);
4630 if (programObject == nullptr)
4631 {
4632 return false;
4633 }
4634
4635 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
4636 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
4637 programBinaryFormats.end())
4638 {
Jamie Madill437fa652016-05-03 15:13:24 -04004639 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05004640 return false;
4641 }
4642
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004643 if (context->hasActiveTransformFeedback(program))
4644 {
4645 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004646 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004647 "Cannot change program binary while program is associated with "
4648 "an active transform feedback object."));
4649 return false;
4650 }
4651
Geoff Langc5629752015-12-07 16:29:04 -05004652 return true;
4653}
4654
4655bool ValidateGetProgramBinaryBase(Context *context,
4656 GLuint program,
4657 GLsizei bufSize,
4658 GLsizei *length,
4659 GLenum *binaryFormat,
4660 void *binary)
4661{
4662 Program *programObject = GetValidProgram(context, program);
4663 if (programObject == nullptr)
4664 {
4665 return false;
4666 }
4667
4668 if (!programObject->isLinked())
4669 {
Jamie Madill437fa652016-05-03 15:13:24 -04004670 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05004671 return false;
4672 }
4673
Jamie Madilla7d12dc2016-12-13 15:08:19 -05004674 if (context->getCaps().programBinaryFormats.empty())
4675 {
4676 context->handleError(Error(GL_INVALID_OPERATION, "No program binary formats supported."));
4677 return false;
4678 }
4679
Geoff Langc5629752015-12-07 16:29:04 -05004680 return true;
4681}
Jamie Madillc29968b2016-01-20 11:17:23 -05004682
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004683bool ValidateUseProgram(Context *context, GLuint program)
4684{
4685 if (program != 0)
4686 {
4687 Program *programObject = context->getProgram(program);
4688 if (!programObject)
4689 {
4690 // ES 3.1.0 section 7.3 page 72
4691 if (context->getShader(program))
4692 {
Jamie Madill437fa652016-05-03 15:13:24 -04004693 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004694 Error(GL_INVALID_OPERATION,
4695 "Attempted to use a single shader instead of a shader program."));
4696 return false;
4697 }
4698 else
4699 {
Jamie Madill437fa652016-05-03 15:13:24 -04004700 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004701 return false;
4702 }
4703 }
4704 if (!programObject->isLinked())
4705 {
Jamie Madill437fa652016-05-03 15:13:24 -04004706 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004707 return false;
4708 }
4709 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004710 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004711 {
4712 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004713 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004714 Error(GL_INVALID_OPERATION,
4715 "Cannot change active program while transform feedback is unpaused."));
4716 return false;
4717 }
4718
4719 return true;
4720}
4721
Jamie Madillc29968b2016-01-20 11:17:23 -05004722bool ValidateCopyTexImage2D(ValidationContext *context,
4723 GLenum target,
4724 GLint level,
4725 GLenum internalformat,
4726 GLint x,
4727 GLint y,
4728 GLsizei width,
4729 GLsizei height,
4730 GLint border)
4731{
Martin Radev1be913c2016-07-11 17:59:16 +03004732 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05004733 {
4734 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
4735 0, x, y, width, height, border);
4736 }
4737
Martin Radev1be913c2016-07-11 17:59:16 +03004738 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05004739 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
4740 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004741}
Jamie Madillc29968b2016-01-20 11:17:23 -05004742
4743bool ValidateFramebufferRenderbuffer(Context *context,
4744 GLenum target,
4745 GLenum attachment,
4746 GLenum renderbuffertarget,
4747 GLuint renderbuffer)
4748{
4749 if (!ValidFramebufferTarget(target) ||
4750 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
4751 {
Jamie Madill437fa652016-05-03 15:13:24 -04004752 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05004753 return false;
4754 }
4755
4756 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
4757 renderbuffertarget, renderbuffer);
4758}
4759
4760bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
4761{
4762 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
4763 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
4764 {
Jamie Madill437fa652016-05-03 15:13:24 -04004765 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05004766 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
4767 return false;
4768 }
4769
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004770 ASSERT(context->getGLState().getDrawFramebuffer());
4771 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05004772 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
4773
4774 // This should come first before the check for the default frame buffer
4775 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
4776 // rather than INVALID_OPERATION
4777 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
4778 {
4779 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
4780
4781 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02004782 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
4783 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05004784 {
4785 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02004786 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
4787 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
4788 // 3.1 is still a bit ambiguous about the error, but future specs are
4789 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04004790 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02004791 return false;
4792 }
4793 else if (bufs[colorAttachment] >= maxColorAttachment)
4794 {
Jamie Madill437fa652016-05-03 15:13:24 -04004795 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02004796 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05004797 return false;
4798 }
4799 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
4800 frameBufferId != 0)
4801 {
4802 // INVALID_OPERATION-GL is bound to buffer and ith argument
4803 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04004804 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05004805 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
4806 return false;
4807 }
4808 }
4809
4810 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
4811 // and n is not 1 or bufs is bound to value other than BACK and NONE
4812 if (frameBufferId == 0)
4813 {
4814 if (n != 1)
4815 {
Jamie Madill437fa652016-05-03 15:13:24 -04004816 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05004817 "n must be 1 when GL is bound to the default framebuffer"));
4818 return false;
4819 }
4820
4821 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
4822 {
Jamie Madill437fa652016-05-03 15:13:24 -04004823 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05004824 GL_INVALID_OPERATION,
4825 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
4826 return false;
4827 }
4828 }
4829
4830 return true;
4831}
4832
4833bool ValidateCopyTexSubImage2D(Context *context,
4834 GLenum target,
4835 GLint level,
4836 GLint xoffset,
4837 GLint yoffset,
4838 GLint x,
4839 GLint y,
4840 GLsizei width,
4841 GLsizei height)
4842{
Martin Radev1be913c2016-07-11 17:59:16 +03004843 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05004844 {
4845 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
4846 yoffset, x, y, width, height, 0);
4847 }
4848
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05004849 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
4850 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05004851}
4852
Geoff Lang496c02d2016-10-20 11:38:11 -07004853bool ValidateGetBufferPointervBase(Context *context,
4854 GLenum target,
4855 GLenum pname,
4856 GLsizei *length,
4857 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03004858{
Geoff Lang496c02d2016-10-20 11:38:11 -07004859 if (length)
4860 {
4861 *length = 0;
4862 }
4863
4864 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
4865 {
4866 context->handleError(
4867 Error(GL_INVALID_OPERATION,
Jamie Madillcc6ac252017-01-25 12:57:21 -08004868 "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
Geoff Lang496c02d2016-10-20 11:38:11 -07004869 return false;
4870 }
4871
Olli Etuaho4f667482016-03-30 15:56:35 +03004872 if (!ValidBufferTarget(context, target))
4873 {
Jamie Madill437fa652016-05-03 15:13:24 -04004874 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03004875 return false;
4876 }
4877
Geoff Lang496c02d2016-10-20 11:38:11 -07004878 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03004879 {
Geoff Lang496c02d2016-10-20 11:38:11 -07004880 case GL_BUFFER_MAP_POINTER:
4881 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03004882
Geoff Lang496c02d2016-10-20 11:38:11 -07004883 default:
4884 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4885 return false;
4886 }
Olli Etuaho4f667482016-03-30 15:56:35 +03004887
4888 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
4889 // target bound to zero generate an INVALID_OPERATION error."
4890 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07004891 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03004892 {
Jamie Madill437fa652016-05-03 15:13:24 -04004893 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004894 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
4895 return false;
4896 }
4897
Geoff Lang496c02d2016-10-20 11:38:11 -07004898 if (length)
4899 {
4900 *length = 1;
4901 }
4902
Olli Etuaho4f667482016-03-30 15:56:35 +03004903 return true;
4904}
4905
4906bool ValidateUnmapBufferBase(Context *context, GLenum target)
4907{
4908 if (!ValidBufferTarget(context, target))
4909 {
Jamie Madill437fa652016-05-03 15:13:24 -04004910 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004911 return false;
4912 }
4913
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004914 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03004915
4916 if (buffer == nullptr || !buffer->isMapped())
4917 {
Jamie Madill437fa652016-05-03 15:13:24 -04004918 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004919 return false;
4920 }
4921
4922 return true;
4923}
4924
4925bool ValidateMapBufferRangeBase(Context *context,
4926 GLenum target,
4927 GLintptr offset,
4928 GLsizeiptr length,
4929 GLbitfield access)
4930{
4931 if (!ValidBufferTarget(context, target))
4932 {
Jamie Madill437fa652016-05-03 15:13:24 -04004933 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004934 return false;
4935 }
4936
4937 if (offset < 0 || length < 0)
4938 {
Jamie Madill437fa652016-05-03 15:13:24 -04004939 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004940 return false;
4941 }
4942
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004943 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03004944
4945 if (!buffer)
4946 {
Jamie Madill437fa652016-05-03 15:13:24 -04004947 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004948 return false;
4949 }
4950
4951 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04004952 CheckedNumeric<size_t> checkedOffset(offset);
4953 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03004954
Jamie Madille2e406c2016-06-02 13:04:10 -04004955 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03004956 {
Jamie Madill437fa652016-05-03 15:13:24 -04004957 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004958 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
4959 return false;
4960 }
4961
4962 // Check for invalid bits in the mask
4963 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
4964 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
4965 GL_MAP_UNSYNCHRONIZED_BIT;
4966
4967 if (access & ~(allAccessBits))
4968 {
Jamie Madill437fa652016-05-03 15:13:24 -04004969 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03004970 return false;
4971 }
4972
4973 if (length == 0)
4974 {
Jamie Madill437fa652016-05-03 15:13:24 -04004975 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004976 return false;
4977 }
4978
4979 if (buffer->isMapped())
4980 {
Jamie Madill437fa652016-05-03 15:13:24 -04004981 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004982 return false;
4983 }
4984
4985 // Check for invalid bit combinations
4986 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
4987 {
Jamie Madill437fa652016-05-03 15:13:24 -04004988 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004989 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
4990 return false;
4991 }
4992
4993 GLbitfield writeOnlyBits =
4994 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
4995
4996 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
4997 {
Jamie Madill437fa652016-05-03 15:13:24 -04004998 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03004999 "Invalid access bits when mapping buffer for reading: 0x%X.",
5000 access));
5001 return false;
5002 }
5003
5004 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
5005 {
Jamie Madill437fa652016-05-03 15:13:24 -04005006 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03005007 GL_INVALID_OPERATION,
5008 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
5009 return false;
5010 }
5011 return true;
5012}
5013
5014bool ValidateFlushMappedBufferRangeBase(Context *context,
5015 GLenum target,
5016 GLintptr offset,
5017 GLsizeiptr length)
5018{
5019 if (offset < 0 || length < 0)
5020 {
Jamie Madill437fa652016-05-03 15:13:24 -04005021 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03005022 return false;
5023 }
5024
5025 if (!ValidBufferTarget(context, target))
5026 {
Jamie Madill437fa652016-05-03 15:13:24 -04005027 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03005028 return false;
5029 }
5030
Jamie Madilldfde6ab2016-06-09 07:07:18 -07005031 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03005032
5033 if (buffer == nullptr)
5034 {
Jamie Madill437fa652016-05-03 15:13:24 -04005035 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03005036 return false;
5037 }
5038
5039 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
5040 {
Jamie Madill437fa652016-05-03 15:13:24 -04005041 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03005042 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
5043 return false;
5044 }
5045
5046 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04005047 CheckedNumeric<size_t> checkedOffset(offset);
5048 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03005049
Jamie Madille2e406c2016-06-02 13:04:10 -04005050 if (!checkedSize.IsValid() ||
5051 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03005052 {
Jamie Madill437fa652016-05-03 15:13:24 -04005053 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03005054 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
5055 return false;
5056 }
5057
5058 return true;
5059}
5060
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005061bool ValidateGenerateMipmap(Context *context, GLenum target)
5062{
5063 if (!ValidTextureTarget(context, target))
5064 {
5065 context->handleError(Error(GL_INVALID_ENUM));
5066 return false;
5067 }
5068
5069 Texture *texture = context->getTargetTexture(target);
5070
5071 if (texture == nullptr)
5072 {
5073 context->handleError(Error(GL_INVALID_OPERATION));
5074 return false;
5075 }
5076
5077 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
5078
5079 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
5080 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
5081 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
5082 {
5083 context->handleError(Error(GL_INVALID_OPERATION));
5084 return false;
5085 }
5086
Jamie Madilla3944d42016-07-22 22:13:26 -04005087 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
5088 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
Geoff Langca271392017-04-05 12:30:00 -04005089 const TextureCaps &formatCaps = context->getTextureCaps().get(format.info->sizedInternalFormat);
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005090
5091 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
5092 // unsized formats or that are color renderable and filterable. Since we do not track if
5093 // the texture was created with sized or unsized format (only sized formats are stored),
5094 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
5095 // be able to) because they aren't color renderable. Simply do a special case for LUMA
5096 // textures since they're the only texture format that can be created with unsized formats
5097 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
5098 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04005099 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
5100 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005101 {
5102 context->handleError(Error(GL_INVALID_OPERATION));
5103 return false;
5104 }
5105
5106 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04005107 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005108 {
5109 context->handleError(Error(GL_INVALID_OPERATION));
5110 return false;
5111 }
5112
5113 // Non-power of 2 ES2 check
Geoff Lang55482a12016-11-21 16:54:01 -05005114 if (context->getClientVersion() < Version(3, 0) && !context->getExtensions().textureNPOT &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005115 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
5116 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
5117 {
Geoff Lang55482a12016-11-21 16:54:01 -05005118 ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005119 context->handleError(Error(GL_INVALID_OPERATION));
5120 return false;
5121 }
5122
5123 // Cube completeness check
5124 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
5125 {
5126 context->handleError(Error(GL_INVALID_OPERATION));
5127 return false;
5128 }
5129
5130 return true;
5131}
5132
Olli Etuaho41997e72016-03-10 13:38:39 +02005133bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
5134{
5135 return ValidateGenOrDelete(context, n);
5136}
5137
5138bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
5139{
5140 return ValidateGenOrDelete(context, n);
5141}
5142
5143bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
5144{
5145 return ValidateGenOrDelete(context, n);
5146}
5147
5148bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
5149{
5150 return ValidateGenOrDelete(context, n);
5151}
5152
5153bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
5154{
5155 return ValidateGenOrDelete(context, n);
5156}
5157
5158bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
5159{
5160 return ValidateGenOrDelete(context, n);
5161}
5162
5163bool ValidateGenTextures(Context *context, GLint n, GLuint *)
5164{
5165 return ValidateGenOrDelete(context, n);
5166}
5167
5168bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
5169{
5170 return ValidateGenOrDelete(context, n);
5171}
5172
5173bool ValidateGenOrDelete(Context *context, GLint n)
5174{
5175 if (n < 0)
5176 {
Jamie Madill437fa652016-05-03 15:13:24 -04005177 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02005178 return false;
5179 }
5180 return true;
5181}
5182
Geoff Langf41a7152016-09-19 15:11:17 -04005183bool ValidateEnable(Context *context, GLenum cap)
5184{
5185 if (!ValidCap(context, cap, false))
5186 {
5187 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5188 return false;
5189 }
5190
5191 if (context->getLimitations().noSampleAlphaToCoverageSupport &&
5192 cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
5193 {
5194 const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
5195 context->handleError(Error(GL_INVALID_OPERATION, errorMessage));
5196
5197 // We also output an error message to the debugger window if tracing is active, so that
5198 // developers can see the error message.
Yuly Novikovd73f8522017-01-13 17:48:57 -05005199 ERR() << errorMessage;
Geoff Langf41a7152016-09-19 15:11:17 -04005200 return false;
5201 }
5202
5203 return true;
5204}
5205
5206bool ValidateDisable(Context *context, GLenum cap)
5207{
5208 if (!ValidCap(context, cap, false))
5209 {
5210 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5211 return false;
5212 }
5213
5214 return true;
5215}
5216
5217bool ValidateIsEnabled(Context *context, GLenum cap)
5218{
5219 if (!ValidCap(context, cap, true))
5220 {
5221 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5222 return false;
5223 }
5224
5225 return true;
5226}
5227
Geoff Langff5b2d52016-09-07 11:32:23 -04005228bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
5229{
5230 if (!context->getExtensions().robustClientMemory)
5231 {
5232 context->handleError(
5233 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
5234 return false;
5235 }
5236
5237 if (bufSize < 0)
5238 {
5239 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
5240 return false;
5241 }
5242
5243 return true;
5244}
5245
Geoff Lang2e43dbb2016-10-14 12:27:35 -04005246bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
5247{
5248 if (bufSize < numParams)
5249 {
5250 context->handleError(Error(GL_INVALID_OPERATION,
5251 "%u parameters are required but %i were provided.", numParams,
5252 bufSize));
5253 return false;
5254 }
5255
5256 return true;
5257}
5258
Geoff Langff5b2d52016-09-07 11:32:23 -04005259bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context,
5260 GLenum target,
5261 GLenum attachment,
5262 GLenum pname,
5263 GLsizei *numParams)
5264{
5265 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08005266 if (numParams)
5267 {
5268 *numParams = 1;
5269 }
Geoff Langff5b2d52016-09-07 11:32:23 -04005270
5271 if (!ValidFramebufferTarget(target))
5272 {
5273 context->handleError(Error(GL_INVALID_ENUM));
5274 return false;
5275 }
5276
5277 int clientVersion = context->getClientMajorVersion();
5278
5279 switch (pname)
5280 {
5281 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5282 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5283 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5284 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5285 break;
5286
5287 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
5288 if (clientVersion < 3 && !context->getExtensions().sRGB)
5289 {
5290 context->handleError(Error(GL_INVALID_ENUM));
5291 return false;
5292 }
5293 break;
5294
5295 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
5296 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
5297 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
5298 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
5299 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
5300 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
5301 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5302 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5303 if (clientVersion < 3)
5304 {
5305 context->handleError(Error(GL_INVALID_ENUM));
5306 return false;
5307 }
5308 break;
5309
5310 default:
5311 context->handleError(Error(GL_INVALID_ENUM));
5312 return false;
5313 }
5314
5315 // Determine if the attachment is a valid enum
5316 switch (attachment)
5317 {
5318 case GL_BACK:
5319 case GL_FRONT:
5320 case GL_DEPTH:
5321 case GL_STENCIL:
5322 case GL_DEPTH_STENCIL_ATTACHMENT:
5323 if (clientVersion < 3)
5324 {
5325 context->handleError(Error(GL_INVALID_ENUM));
5326 return false;
5327 }
5328 break;
5329
5330 case GL_DEPTH_ATTACHMENT:
5331 case GL_STENCIL_ATTACHMENT:
5332 break;
5333
5334 default:
5335 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
5336 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
5337 {
5338 context->handleError(Error(GL_INVALID_ENUM));
5339 return false;
5340 }
5341 break;
5342 }
5343
5344 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
5345 ASSERT(framebuffer);
5346
5347 if (framebuffer->id() == 0)
5348 {
5349 if (clientVersion < 3)
5350 {
5351 context->handleError(Error(GL_INVALID_OPERATION));
5352 return false;
5353 }
5354
5355 switch (attachment)
5356 {
5357 case GL_BACK:
5358 case GL_DEPTH:
5359 case GL_STENCIL:
5360 break;
5361
5362 default:
5363 context->handleError(Error(GL_INVALID_OPERATION));
5364 return false;
5365 }
5366 }
5367 else
5368 {
5369 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
5370 {
5371 // Valid attachment query
5372 }
5373 else
5374 {
5375 switch (attachment)
5376 {
5377 case GL_DEPTH_ATTACHMENT:
5378 case GL_STENCIL_ATTACHMENT:
5379 break;
5380
5381 case GL_DEPTH_STENCIL_ATTACHMENT:
5382 if (!framebuffer->hasValidDepthStencil())
5383 {
5384 context->handleError(Error(GL_INVALID_OPERATION));
5385 return false;
5386 }
5387 break;
5388
5389 default:
5390 context->handleError(Error(GL_INVALID_OPERATION));
5391 return false;
5392 }
5393 }
5394 }
5395
5396 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
5397 if (attachmentObject)
5398 {
5399 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
5400 attachmentObject->type() == GL_TEXTURE ||
5401 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
5402
5403 switch (pname)
5404 {
5405 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5406 if (attachmentObject->type() != GL_RENDERBUFFER &&
5407 attachmentObject->type() != GL_TEXTURE)
5408 {
5409 context->handleError(Error(GL_INVALID_ENUM));
5410 return false;
5411 }
5412 break;
5413
5414 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5415 if (attachmentObject->type() != GL_TEXTURE)
5416 {
5417 context->handleError(Error(GL_INVALID_ENUM));
5418 return false;
5419 }
5420 break;
5421
5422 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5423 if (attachmentObject->type() != GL_TEXTURE)
5424 {
5425 context->handleError(Error(GL_INVALID_ENUM));
5426 return false;
5427 }
5428 break;
5429
5430 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5431 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
5432 {
5433 context->handleError(Error(GL_INVALID_OPERATION));
5434 return false;
5435 }
5436 break;
5437
5438 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5439 if (attachmentObject->type() != GL_TEXTURE)
5440 {
5441 context->handleError(Error(GL_INVALID_ENUM));
5442 return false;
5443 }
5444 break;
5445
5446 default:
5447 break;
5448 }
5449 }
5450 else
5451 {
5452 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
5453 // is NONE, then querying any other pname will generate INVALID_ENUM.
5454
5455 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
5456 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
5457 // INVALID_OPERATION for all other pnames
5458
5459 switch (pname)
5460 {
5461 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5462 break;
5463
5464 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5465 if (clientVersion < 3)
5466 {
5467 context->handleError(Error(GL_INVALID_ENUM));
5468 return false;
5469 }
5470 break;
5471
5472 default:
5473 if (clientVersion < 3)
5474 {
5475 context->handleError(Error(GL_INVALID_ENUM));
5476 return false;
5477 }
5478 else
5479 {
5480 context->handleError(Error(GL_INVALID_OPERATION));
5481 return false;
5482 }
5483 }
5484 }
5485
5486 return true;
5487}
5488
5489bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
5490 GLenum target,
5491 GLenum attachment,
5492 GLenum pname,
5493 GLsizei bufSize,
5494 GLsizei *numParams)
5495{
5496 if (!ValidateRobustEntryPoint(context, bufSize))
5497 {
5498 return false;
5499 }
5500
5501 if (!ValidateGetFramebufferAttachmentParameteriv(context, target, attachment, pname, numParams))
5502 {
5503 return false;
5504 }
5505
5506 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
5507 {
5508 return false;
5509 }
5510
5511 return true;
5512}
5513
5514bool ValidateGetBufferParameteriv(ValidationContext *context,
5515 GLenum target,
5516 GLenum pname,
Geoff Langebebe1c2016-10-14 12:01:31 -04005517 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04005518{
Geoff Langebebe1c2016-10-14 12:01:31 -04005519 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
Geoff Langff5b2d52016-09-07 11:32:23 -04005520}
5521
5522bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
5523 GLenum target,
5524 GLenum pname,
5525 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04005526 GLsizei *length,
5527 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04005528{
5529 if (!ValidateRobustEntryPoint(context, bufSize))
5530 {
5531 return false;
5532 }
5533
Geoff Langebebe1c2016-10-14 12:01:31 -04005534 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04005535 {
5536 return false;
5537 }
5538
Geoff Langebebe1c2016-10-14 12:01:31 -04005539 if (!ValidateRobustBufferSize(context, bufSize, *length))
5540 {
5541 return false;
5542 }
5543
5544 return true;
5545}
5546
5547bool ValidateGetBufferParameteri64v(ValidationContext *context,
5548 GLenum target,
5549 GLenum pname,
5550 GLint64 *params)
5551{
5552 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
5553}
5554
5555bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
5556 GLenum target,
5557 GLenum pname,
5558 GLsizei bufSize,
5559 GLsizei *length,
5560 GLint64 *params)
5561{
5562 if (!ValidateRobustEntryPoint(context, bufSize))
5563 {
5564 return false;
5565 }
5566
5567 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
5568 {
5569 return false;
5570 }
5571
5572 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04005573 {
5574 return false;
5575 }
5576
5577 return true;
5578}
5579
5580bool ValidateGetProgramiv(Context *context, GLuint program, GLenum pname, GLsizei *numParams)
5581{
5582 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08005583 if (numParams)
5584 {
5585 *numParams = 1;
5586 }
Geoff Langff5b2d52016-09-07 11:32:23 -04005587
5588 Program *programObject = GetValidProgram(context, program);
5589 if (!programObject)
5590 {
5591 return false;
5592 }
5593
5594 switch (pname)
5595 {
5596 case GL_DELETE_STATUS:
5597 case GL_LINK_STATUS:
5598 case GL_VALIDATE_STATUS:
5599 case GL_INFO_LOG_LENGTH:
5600 case GL_ATTACHED_SHADERS:
5601 case GL_ACTIVE_ATTRIBUTES:
5602 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
5603 case GL_ACTIVE_UNIFORMS:
5604 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
5605 break;
5606
5607 case GL_PROGRAM_BINARY_LENGTH:
5608 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
5609 {
5610 context->handleError(Error(GL_INVALID_ENUM,
5611 "Querying GL_PROGRAM_BINARY_LENGTH requires "
5612 "GL_OES_get_program_binary or ES 3.0."));
5613 return false;
5614 }
5615 break;
5616
5617 case GL_ACTIVE_UNIFORM_BLOCKS:
5618 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
5619 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
5620 case GL_TRANSFORM_FEEDBACK_VARYINGS:
5621 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
5622 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
5623 if (context->getClientMajorVersion() < 3)
5624 {
5625 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
5626 return false;
5627 }
5628 break;
5629
Yunchao He61afff12017-03-14 15:34:03 +08005630 case GL_PROGRAM_SEPARABLE:
5631 if (context->getClientVersion() < Version(3, 1))
5632 {
5633 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.1."));
5634 return false;
5635 }
5636 break;
5637
Geoff Langff5b2d52016-09-07 11:32:23 -04005638 default:
5639 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
5640 return false;
5641 }
5642
5643 return true;
5644}
5645
5646bool ValidateGetProgramivRobustANGLE(Context *context,
5647 GLuint program,
5648 GLenum pname,
5649 GLsizei bufSize,
5650 GLsizei *numParams)
5651{
5652 if (!ValidateRobustEntryPoint(context, bufSize))
5653 {
5654 return false;
5655 }
5656
5657 if (!ValidateGetProgramiv(context, program, pname, numParams))
5658 {
5659 return false;
5660 }
5661
5662 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
5663 {
5664 return false;
5665 }
5666
5667 return true;
5668}
5669
Geoff Lang740d9022016-10-07 11:20:52 -04005670bool ValidateGetRenderbufferParameteriv(Context *context,
5671 GLenum target,
5672 GLenum pname,
5673 GLint *params)
5674{
5675 return ValidateGetRenderbufferParameterivBase(context, target, pname, nullptr);
5676}
5677
5678bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
5679 GLenum target,
5680 GLenum pname,
5681 GLsizei bufSize,
5682 GLsizei *length,
5683 GLint *params)
5684{
5685 if (!ValidateRobustEntryPoint(context, bufSize))
5686 {
5687 return false;
5688 }
5689
5690 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
5691 {
5692 return false;
5693 }
5694
5695 if (!ValidateRobustBufferSize(context, bufSize, *length))
5696 {
5697 return false;
5698 }
5699
5700 return true;
5701}
5702
Geoff Langd7d0ed32016-10-07 11:33:51 -04005703bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params)
5704{
5705 return ValidateGetShaderivBase(context, shader, pname, nullptr);
5706}
5707
5708bool ValidateGetShaderivRobustANGLE(Context *context,
5709 GLuint shader,
5710 GLenum pname,
5711 GLsizei bufSize,
5712 GLsizei *length,
5713 GLint *params)
5714{
5715 if (!ValidateRobustEntryPoint(context, bufSize))
5716 {
5717 return false;
5718 }
5719
5720 if (!ValidateGetShaderivBase(context, shader, pname, length))
5721 {
5722 return false;
5723 }
5724
5725 if (!ValidateRobustBufferSize(context, bufSize, *length))
5726 {
5727 return false;
5728 }
5729
5730 return true;
5731}
5732
Geoff Langc1984ed2016-10-07 12:41:00 -04005733bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params)
5734{
5735 return ValidateGetTexParameterBase(context, target, pname, nullptr);
5736}
5737
5738bool ValidateGetTexParameterfvRobustANGLE(Context *context,
5739 GLenum target,
5740 GLenum pname,
5741 GLsizei bufSize,
5742 GLsizei *length,
5743 GLfloat *params)
5744{
5745 if (!ValidateRobustEntryPoint(context, bufSize))
5746 {
5747 return false;
5748 }
5749
5750 if (!ValidateGetTexParameterBase(context, target, pname, length))
5751 {
5752 return false;
5753 }
5754
5755 if (!ValidateRobustBufferSize(context, bufSize, *length))
5756 {
5757 return false;
5758 }
5759
5760 return true;
5761}
5762
5763bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params)
5764{
5765 return ValidateGetTexParameterBase(context, target, pname, nullptr);
5766}
5767
5768bool ValidateGetTexParameterivRobustANGLE(Context *context,
5769 GLenum target,
5770 GLenum pname,
5771 GLsizei bufSize,
5772 GLsizei *length,
5773 GLint *params)
5774{
5775 if (!ValidateRobustEntryPoint(context, bufSize))
5776 {
5777 return false;
5778 }
5779
5780 if (!ValidateGetTexParameterBase(context, target, pname, length))
5781 {
5782 return false;
5783 }
5784
5785 if (!ValidateRobustBufferSize(context, bufSize, *length))
5786 {
5787 return false;
5788 }
5789
5790 return true;
5791}
5792
5793bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param)
5794{
5795 return ValidateTexParameterBase(context, target, pname, -1, &param);
5796}
5797
5798bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params)
5799{
5800 return ValidateTexParameterBase(context, target, pname, -1, params);
5801}
5802
5803bool ValidateTexParameterfvRobustANGLE(Context *context,
5804 GLenum target,
5805 GLenum pname,
5806 GLsizei bufSize,
5807 const GLfloat *params)
5808{
5809 if (!ValidateRobustEntryPoint(context, bufSize))
5810 {
5811 return false;
5812 }
5813
5814 return ValidateTexParameterBase(context, target, pname, bufSize, params);
5815}
5816
5817bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param)
5818{
5819 return ValidateTexParameterBase(context, target, pname, -1, &param);
5820}
5821
5822bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params)
5823{
5824 return ValidateTexParameterBase(context, target, pname, -1, params);
5825}
5826
5827bool ValidateTexParameterivRobustANGLE(Context *context,
5828 GLenum target,
5829 GLenum pname,
5830 GLsizei bufSize,
5831 const GLint *params)
5832{
5833 if (!ValidateRobustEntryPoint(context, bufSize))
5834 {
5835 return false;
5836 }
5837
5838 return ValidateTexParameterBase(context, target, pname, bufSize, params);
5839}
5840
5841bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
5842{
5843 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
5844}
5845
5846bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
5847 GLuint sampler,
5848 GLenum pname,
5849 GLuint bufSize,
5850 GLsizei *length,
5851 GLfloat *params)
5852{
5853 if (!ValidateRobustEntryPoint(context, bufSize))
5854 {
5855 return false;
5856 }
5857
5858 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
5859 {
5860 return false;
5861 }
5862
5863 if (!ValidateRobustBufferSize(context, bufSize, *length))
5864 {
5865 return false;
5866 }
5867
5868 return true;
5869}
5870
5871bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
5872{
5873 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
5874}
5875
5876bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
5877 GLuint sampler,
5878 GLenum pname,
5879 GLuint bufSize,
5880 GLsizei *length,
5881 GLint *params)
5882{
5883 if (!ValidateRobustEntryPoint(context, bufSize))
5884 {
5885 return false;
5886 }
5887
5888 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
5889 {
5890 return false;
5891 }
5892
5893 if (!ValidateRobustBufferSize(context, bufSize, *length))
5894 {
5895 return false;
5896 }
5897
5898 return true;
5899}
5900
5901bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
5902{
5903 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
5904}
5905
5906bool ValidateSamplerParameterfv(Context *context,
5907 GLuint sampler,
5908 GLenum pname,
5909 const GLfloat *params)
5910{
5911 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
5912}
5913
5914bool ValidateSamplerParameterfvRobustANGLE(Context *context,
5915 GLuint sampler,
5916 GLenum pname,
5917 GLsizei bufSize,
5918 const GLfloat *params)
5919{
5920 if (!ValidateRobustEntryPoint(context, bufSize))
5921 {
5922 return false;
5923 }
5924
5925 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
5926}
5927
5928bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
5929{
5930 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
5931}
5932
5933bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
5934{
5935 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
5936}
5937
5938bool ValidateSamplerParameterivRobustANGLE(Context *context,
5939 GLuint sampler,
5940 GLenum pname,
5941 GLsizei bufSize,
5942 const GLint *params)
5943{
5944 if (!ValidateRobustEntryPoint(context, bufSize))
5945 {
5946 return false;
5947 }
5948
5949 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
5950}
5951
Geoff Lang0b031062016-10-13 14:30:04 -04005952bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params)
5953{
5954 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false);
5955}
5956
5957bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
5958 GLuint index,
5959 GLenum pname,
5960 GLsizei bufSize,
5961 GLsizei *length,
5962 GLfloat *params)
5963{
5964 if (!ValidateRobustEntryPoint(context, bufSize))
5965 {
5966 return false;
5967 }
5968
5969 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
5970 {
5971 return false;
5972 }
5973
5974 if (!ValidateRobustBufferSize(context, bufSize, *length))
5975 {
5976 return false;
5977 }
5978
5979 return true;
5980}
5981
5982bool ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params)
5983{
5984 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false);
5985}
5986
5987bool ValidateGetVertexAttribivRobustANGLE(Context *context,
5988 GLuint index,
5989 GLenum pname,
5990 GLsizei bufSize,
5991 GLsizei *length,
5992 GLint *params)
5993{
5994 if (!ValidateRobustEntryPoint(context, bufSize))
5995 {
5996 return false;
5997 }
5998
5999 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
6000 {
6001 return false;
6002 }
6003
6004 if (!ValidateRobustBufferSize(context, bufSize, *length))
6005 {
6006 return false;
6007 }
6008
6009 return true;
6010}
6011
6012bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer)
6013{
6014 return ValidateGetVertexAttribBase(context, index, pname, nullptr, true, false);
6015}
6016
6017bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
6018 GLuint index,
6019 GLenum pname,
6020 GLsizei bufSize,
6021 GLsizei *length,
6022 void **pointer)
6023{
6024 if (!ValidateRobustEntryPoint(context, bufSize))
6025 {
6026 return false;
6027 }
6028
6029 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
6030 {
6031 return false;
6032 }
6033
6034 if (!ValidateRobustBufferSize(context, bufSize, *length))
6035 {
6036 return false;
6037 }
6038
6039 return true;
6040}
6041
6042bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
6043{
6044 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
6045}
6046
6047bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
6048 GLuint index,
6049 GLenum pname,
6050 GLsizei bufSize,
6051 GLsizei *length,
6052 GLint *params)
6053{
6054 if (!ValidateRobustEntryPoint(context, bufSize))
6055 {
6056 return false;
6057 }
6058
6059 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
6060 {
6061 return false;
6062 }
6063
6064 if (!ValidateRobustBufferSize(context, bufSize, *length))
6065 {
6066 return false;
6067 }
6068
6069 return true;
6070}
6071
6072bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
6073{
6074 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
6075}
6076
6077bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
6078 GLuint index,
6079 GLenum pname,
6080 GLsizei bufSize,
6081 GLsizei *length,
6082 GLuint *params)
6083{
6084 if (!ValidateRobustEntryPoint(context, bufSize))
6085 {
6086 return false;
6087 }
6088
6089 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
6090 {
6091 return false;
6092 }
6093
6094 if (!ValidateRobustBufferSize(context, bufSize, *length))
6095 {
6096 return false;
6097 }
6098
6099 return true;
6100}
6101
Geoff Lang6899b872016-10-14 11:30:13 -04006102bool ValidateGetActiveUniformBlockiv(Context *context,
6103 GLuint program,
6104 GLuint uniformBlockIndex,
6105 GLenum pname,
6106 GLint *params)
6107{
6108 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
6109}
6110
6111bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
6112 GLuint program,
6113 GLuint uniformBlockIndex,
6114 GLenum pname,
6115 GLsizei bufSize,
6116 GLsizei *length,
6117 GLint *params)
6118{
6119 if (!ValidateRobustEntryPoint(context, bufSize))
6120 {
6121 return false;
6122 }
6123
6124 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
6125 {
6126 return false;
6127 }
6128
6129 if (!ValidateRobustBufferSize(context, bufSize, *length))
6130 {
6131 return false;
6132 }
6133
6134 return true;
6135}
6136
Geoff Lang0a9661f2016-10-20 10:59:20 -07006137bool ValidateGetInternalFormativ(Context *context,
6138 GLenum target,
6139 GLenum internalformat,
6140 GLenum pname,
6141 GLsizei bufSize,
6142 GLint *params)
6143{
6144 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
6145 nullptr);
6146}
6147
6148bool ValidateGetInternalFormativRobustANGLE(Context *context,
6149 GLenum target,
6150 GLenum internalformat,
6151 GLenum pname,
6152 GLsizei bufSize,
6153 GLsizei *length,
6154 GLint *params)
6155{
6156 if (!ValidateRobustEntryPoint(context, bufSize))
6157 {
6158 return false;
6159 }
6160
6161 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
6162 {
6163 return false;
6164 }
6165
6166 if (!ValidateRobustBufferSize(context, bufSize, *length))
6167 {
6168 return false;
6169 }
6170
6171 return true;
6172}
6173
Shao80957d92017-02-20 21:25:59 +08006174bool ValidateVertexFormatBase(ValidationContext *context,
6175 GLuint attribIndex,
6176 GLint size,
6177 GLenum type,
6178 GLboolean pureInteger)
6179{
6180 const Caps &caps = context->getCaps();
6181 if (attribIndex >= caps.maxVertexAttributes)
6182 {
6183 context->handleError(
6184 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
6185 return false;
6186 }
6187
6188 if (size < 1 || size > 4)
6189 {
6190 context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
6191 }
6192
6193 switch (type)
6194 {
6195 case GL_BYTE:
6196 case GL_UNSIGNED_BYTE:
6197 case GL_SHORT:
6198 case GL_UNSIGNED_SHORT:
6199 break;
6200
6201 case GL_INT:
6202 case GL_UNSIGNED_INT:
6203 if (context->getClientMajorVersion() < 3)
6204 {
6205 context->handleError(
6206 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6207 return false;
6208 }
6209 break;
6210
6211 case GL_FIXED:
6212 case GL_FLOAT:
6213 if (pureInteger)
6214 {
6215 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6216 return false;
6217 }
6218 break;
6219
6220 case GL_HALF_FLOAT:
6221 if (context->getClientMajorVersion() < 3)
6222 {
6223 context->handleError(
6224 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6225 return false;
6226 }
6227 if (pureInteger)
6228 {
6229 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6230 return false;
6231 }
6232 break;
6233
6234 case GL_INT_2_10_10_10_REV:
6235 case GL_UNSIGNED_INT_2_10_10_10_REV:
6236 if (context->getClientMajorVersion() < 3)
6237 {
6238 context->handleError(
6239 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6240 return false;
6241 }
6242 if (pureInteger)
6243 {
6244 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6245 return false;
6246 }
6247 if (size != 4)
6248 {
6249 context->handleError(Error(GL_INVALID_OPERATION,
6250 "Type is INT_2_10_10_10_REV or "
6251 "UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
6252 return false;
6253 }
6254 break;
6255
6256 default:
6257 context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
6258 return false;
6259 }
6260
6261 return true;
6262}
6263
Geoff Lang76e65652017-03-27 14:58:02 -04006264// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
6265// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
6266// specified clear value and the type of a buffer that is being cleared generates an
6267// INVALID_OPERATION error instead of producing undefined results
6268bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
6269 GLint drawbuffer,
6270 const GLenum *validComponentTypes,
6271 size_t validComponentTypeCount)
6272{
6273 const FramebufferAttachment *attachment =
6274 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
6275 if (attachment)
6276 {
6277 GLenum componentType = attachment->getFormat().info->componentType;
6278 const GLenum *end = validComponentTypes + validComponentTypeCount;
6279 if (std::find(validComponentTypes, end, componentType) == end)
6280 {
6281 context->handleError(
6282 Error(GL_INVALID_OPERATION,
6283 "No defined conversion between clear value and attachment format."));
6284 return false;
6285 }
6286 }
6287
6288 return true;
6289}
6290
Corentin Wallezb2931602017-04-11 15:58:57 -04006291bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
6292 GLsizei imageSize,
6293 GLsizei dataSize)
6294{
6295 if (!ValidateRobustEntryPoint(context, dataSize))
6296 {
6297 return false;
6298 }
6299
6300 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
6301 if (pixelUnpackBuffer == nullptr)
6302 {
6303 if (dataSize < imageSize)
6304 {
6305 context->handleError(
6306 Error(GL_INVALID_OPERATION, "dataSize must be at least %i.", imageSize));
6307 }
6308 }
6309 return true;
6310}
6311
Jamie Madillc29968b2016-01-20 11:17:23 -05006312} // namespace gl