blob: a4609a56e5025455c7de4262ccc742aac634dcb0 [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();
295 GLenum currentInternalFormat = readBuffer->getFormat().asSized();
296
297 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(currentInternalFormat);
298 bool validFormatTypeCombination =
299 ValidReadPixelsFormatType(context, internalFormatInfo.componentType, format, type);
300
301 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
302 {
303 context->handleError(Error(GL_INVALID_OPERATION));
304 return false;
305 }
306
307 // Check for pixel pack buffer related API errors
308 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
309 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
310 {
311 // ...the buffer object's data store is currently mapped.
312 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
313 return false;
314 }
315
316 // .. the data would be packed to the buffer object such that the memory writes required
317 // would exceed the data store size.
318 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
319 const InternalFormat &formatInfo = GetInternalFormatInfo(sizedInternalFormat);
320 const gl::Extents size(width, height, 1);
321 const auto &pack = context->getGLState().getPackState();
322
323 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
324 if (endByteOrErr.isError())
325 {
326 context->handleError(endByteOrErr.getError());
327 return false;
328 }
329
330 size_t endByte = endByteOrErr.getResult();
331 if (bufSize >= 0)
332 {
Geoff Lange93daba2017-03-30 13:54:40 -0400333 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400334 {
335 context->handleError(
336 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
337 return false;
338 }
339 }
340
341 if (pixelPackBuffer != nullptr)
342 {
343 CheckedNumeric<size_t> checkedEndByte(endByte);
344 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
345 checkedEndByte += checkedOffset;
346
347 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
348 {
349 // Overflow past the end of the buffer
350 context->handleError(
351 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
352 return false;
353 }
354 }
355
Geoff Lange93daba2017-03-30 13:54:40 -0400356 if (pixelPackBuffer == nullptr && length != nullptr)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400357 {
358 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
359 {
360 context->handleError(
361 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
362 return false;
363 }
364
365 *length = static_cast<GLsizei>(endByte);
366 }
367
Geoff Lange93daba2017-03-30 13:54:40 -0400368 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
369 angle::CheckedNumeric<int> clippedExtent(length);
370 if (start < 0)
371 {
372 // "subtract" the area that is less than 0
373 clippedExtent += start;
374 }
375
376 const int readExtent = start + length;
377 if (readExtent > bufferSize)
378 {
379 // Subtract the region to the right of the read buffer
380 clippedExtent -= (readExtent - bufferSize);
381 }
382
383 if (!clippedExtent.IsValid())
384 {
385 return 0;
386 }
387
388 return std::max(clippedExtent.ValueOrDie(), 0);
389 };
390
391 if (columns != nullptr)
392 {
393 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
394 }
395
396 if (rows != nullptr)
397 {
398 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
399 }
400
Geoff Lang62fce5b2016-09-30 10:46:35 -0400401 return true;
402}
403
Geoff Lang740d9022016-10-07 11:20:52 -0400404bool ValidateGetRenderbufferParameterivBase(Context *context,
405 GLenum target,
406 GLenum pname,
407 GLsizei *length)
408{
409 if (length)
410 {
411 *length = 0;
412 }
413
414 if (target != GL_RENDERBUFFER)
415 {
416 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
417 return false;
418 }
419
420 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
421 if (renderbuffer == nullptr)
422 {
423 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
424 return false;
425 }
426
427 switch (pname)
428 {
429 case GL_RENDERBUFFER_WIDTH:
430 case GL_RENDERBUFFER_HEIGHT:
431 case GL_RENDERBUFFER_INTERNAL_FORMAT:
432 case GL_RENDERBUFFER_RED_SIZE:
433 case GL_RENDERBUFFER_GREEN_SIZE:
434 case GL_RENDERBUFFER_BLUE_SIZE:
435 case GL_RENDERBUFFER_ALPHA_SIZE:
436 case GL_RENDERBUFFER_DEPTH_SIZE:
437 case GL_RENDERBUFFER_STENCIL_SIZE:
438 break;
439
440 case GL_RENDERBUFFER_SAMPLES_ANGLE:
441 if (!context->getExtensions().framebufferMultisample)
442 {
443 context->handleError(
444 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
445 return false;
446 }
447 break;
448
449 default:
450 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
451 return false;
452 }
453
454 if (length)
455 {
456 *length = 1;
457 }
458 return true;
459}
460
Geoff Langd7d0ed32016-10-07 11:33:51 -0400461bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
462{
463 if (length)
464 {
465 *length = 0;
466 }
467
468 if (GetValidShader(context, shader) == nullptr)
469 {
470 return false;
471 }
472
473 switch (pname)
474 {
475 case GL_SHADER_TYPE:
476 case GL_DELETE_STATUS:
477 case GL_COMPILE_STATUS:
478 case GL_INFO_LOG_LENGTH:
479 case GL_SHADER_SOURCE_LENGTH:
480 break;
481
482 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
483 if (!context->getExtensions().translatedShaderSource)
484 {
485 context->handleError(
486 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
487 return false;
488 }
489 break;
490
491 default:
492 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
493 return false;
494 }
495
496 if (length)
497 {
498 *length = 1;
499 }
500 return true;
501}
502
Geoff Langc1984ed2016-10-07 12:41:00 -0400503bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
504{
505 if (length)
506 {
507 *length = 0;
508 }
509
510 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
511 {
512 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
513 return false;
514 }
515
516 if (context->getTargetTexture(target) == nullptr)
517 {
518 // Should only be possible for external textures
519 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
520 return false;
521 }
522
523 switch (pname)
524 {
525 case GL_TEXTURE_MAG_FILTER:
526 case GL_TEXTURE_MIN_FILTER:
527 case GL_TEXTURE_WRAP_S:
528 case GL_TEXTURE_WRAP_T:
529 break;
530
531 case GL_TEXTURE_USAGE_ANGLE:
532 if (!context->getExtensions().textureUsage)
533 {
534 context->handleError(
535 Error(GL_INVALID_ENUM, "GL_ANGLE_texture_usage is not enabled."));
536 return false;
537 }
538 break;
539
540 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
541 if (!context->getExtensions().textureFilterAnisotropic)
542 {
543 context->handleError(
544 Error(GL_INVALID_ENUM, "GL_EXT_texture_filter_anisotropic is not enabled."));
545 return false;
546 }
547 break;
548
549 case GL_TEXTURE_IMMUTABLE_FORMAT:
550 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
551 {
552 context->handleError(
553 Error(GL_INVALID_ENUM, "GL_EXT_texture_storage is not enabled."));
554 return false;
555 }
556 break;
557
558 case GL_TEXTURE_WRAP_R:
559 case GL_TEXTURE_IMMUTABLE_LEVELS:
560 case GL_TEXTURE_SWIZZLE_R:
561 case GL_TEXTURE_SWIZZLE_G:
562 case GL_TEXTURE_SWIZZLE_B:
563 case GL_TEXTURE_SWIZZLE_A:
564 case GL_TEXTURE_BASE_LEVEL:
565 case GL_TEXTURE_MAX_LEVEL:
566 case GL_TEXTURE_MIN_LOD:
567 case GL_TEXTURE_MAX_LOD:
568 case GL_TEXTURE_COMPARE_MODE:
569 case GL_TEXTURE_COMPARE_FUNC:
570 if (context->getClientMajorVersion() < 3)
571 {
572 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
573 return false;
574 }
575 break;
576
Geoff Lang81c6b572016-10-19 14:07:52 -0700577 case GL_TEXTURE_SRGB_DECODE_EXT:
578 if (!context->getExtensions().textureSRGBDecode)
579 {
580 context->handleError(
581 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
582 return false;
583 }
584 break;
585
Geoff Langc1984ed2016-10-07 12:41:00 -0400586 default:
587 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
588 return false;
589 }
590
591 if (length)
592 {
593 *length = 1;
594 }
595 return true;
596}
597
598template <typename ParamType>
599bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isExternalTextureTarget)
600{
601 switch (ConvertToGLenum(params[0]))
602 {
603 case GL_CLAMP_TO_EDGE:
604 break;
605
606 case GL_REPEAT:
607 case GL_MIRRORED_REPEAT:
608 if (isExternalTextureTarget)
609 {
610 // OES_EGL_image_external specifies this error.
611 context->handleError(Error(
612 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
613 return false;
614 }
615 break;
616
617 default:
618 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
619 return false;
620 }
621
622 return true;
623}
624
625template <typename ParamType>
626bool ValidateTextureMinFilterValue(Context *context,
627 ParamType *params,
628 bool isExternalTextureTarget)
629{
630 switch (ConvertToGLenum(params[0]))
631 {
632 case GL_NEAREST:
633 case GL_LINEAR:
634 break;
635
636 case GL_NEAREST_MIPMAP_NEAREST:
637 case GL_LINEAR_MIPMAP_NEAREST:
638 case GL_NEAREST_MIPMAP_LINEAR:
639 case GL_LINEAR_MIPMAP_LINEAR:
640 if (isExternalTextureTarget)
641 {
642 // OES_EGL_image_external specifies this error.
643 context->handleError(
644 Error(GL_INVALID_ENUM,
645 "external textures only support NEAREST and LINEAR filtering"));
646 return false;
647 }
648 break;
649
650 default:
651 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
652 return false;
653 }
654
655 return true;
656}
657
658template <typename ParamType>
659bool ValidateTextureMagFilterValue(Context *context, ParamType *params)
660{
661 switch (ConvertToGLenum(params[0]))
662 {
663 case GL_NEAREST:
664 case GL_LINEAR:
665 break;
666
667 default:
668 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
669 return false;
670 }
671
672 return true;
673}
674
675template <typename ParamType>
676bool ValidateTextureCompareModeValue(Context *context, ParamType *params)
677{
678 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
679 switch (ConvertToGLenum(params[0]))
680 {
681 case GL_NONE:
682 case GL_COMPARE_REF_TO_TEXTURE:
683 break;
684
685 default:
686 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
687 return false;
688 }
689
690 return true;
691}
692
693template <typename ParamType>
694bool ValidateTextureCompareFuncValue(Context *context, ParamType *params)
695{
696 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
697 switch (ConvertToGLenum(params[0]))
698 {
699 case GL_LEQUAL:
700 case GL_GEQUAL:
701 case GL_LESS:
702 case GL_GREATER:
703 case GL_EQUAL:
704 case GL_NOTEQUAL:
705 case GL_ALWAYS:
706 case GL_NEVER:
707 break;
708
709 default:
710 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
711 return false;
712 }
713
714 return true;
715}
716
717template <typename ParamType>
Geoff Lang81c6b572016-10-19 14:07:52 -0700718bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params)
719{
720 if (!context->getExtensions().textureSRGBDecode)
721 {
722 context->handleError(Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
723 return false;
724 }
725
726 switch (ConvertToGLenum(params[0]))
727 {
728 case GL_DECODE_EXT:
729 case GL_SKIP_DECODE_EXT:
730 break;
731
732 default:
733 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
734 return false;
735 }
736
737 return true;
738}
739
740template <typename ParamType>
Geoff Langc1984ed2016-10-07 12:41:00 -0400741bool ValidateTexParameterBase(Context *context,
742 GLenum target,
743 GLenum pname,
744 GLsizei bufSize,
745 ParamType *params)
746{
747 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
748 {
749 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
750 return false;
751 }
752
753 if (context->getTargetTexture(target) == nullptr)
754 {
755 // Should only be possible for external textures
756 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
757 return false;
758 }
759
760 const GLsizei minBufSize = 1;
761 if (bufSize >= 0 && bufSize < minBufSize)
762 {
763 context->handleError(
764 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
765 return false;
766 }
767
768 switch (pname)
769 {
770 case GL_TEXTURE_WRAP_R:
771 case GL_TEXTURE_SWIZZLE_R:
772 case GL_TEXTURE_SWIZZLE_G:
773 case GL_TEXTURE_SWIZZLE_B:
774 case GL_TEXTURE_SWIZZLE_A:
775 case GL_TEXTURE_BASE_LEVEL:
776 case GL_TEXTURE_MAX_LEVEL:
777 case GL_TEXTURE_COMPARE_MODE:
778 case GL_TEXTURE_COMPARE_FUNC:
779 case GL_TEXTURE_MIN_LOD:
780 case GL_TEXTURE_MAX_LOD:
781 if (context->getClientMajorVersion() < 3)
782 {
783 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
784 return false;
785 }
786 if (target == GL_TEXTURE_EXTERNAL_OES &&
787 !context->getExtensions().eglImageExternalEssl3)
788 {
789 context->handleError(Error(GL_INVALID_ENUM,
790 "ES3 texture parameters are not available without "
791 "GL_OES_EGL_image_external_essl3."));
792 return false;
793 }
794 break;
795
796 default:
797 break;
798 }
799
800 switch (pname)
801 {
802 case GL_TEXTURE_WRAP_S:
803 case GL_TEXTURE_WRAP_T:
804 case GL_TEXTURE_WRAP_R:
805 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
806 {
807 return false;
808 }
809 break;
810
811 case GL_TEXTURE_MIN_FILTER:
812 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
813 {
814 return false;
815 }
816 break;
817
818 case GL_TEXTURE_MAG_FILTER:
819 if (!ValidateTextureMagFilterValue(context, params))
820 {
821 return false;
822 }
823 break;
824
825 case GL_TEXTURE_USAGE_ANGLE:
826 switch (ConvertToGLenum(params[0]))
827 {
828 case GL_NONE:
829 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
830 break;
831
832 default:
833 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
834 return false;
835 }
836 break;
837
838 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
839 if (!context->getExtensions().textureFilterAnisotropic)
840 {
841 context->handleError(
842 Error(GL_INVALID_ENUM, "GL_EXT_texture_anisotropic is not enabled."));
843 return false;
844 }
845
846 // we assume the parameter passed to this validation method is truncated, not rounded
847 if (params[0] < 1)
848 {
849 context->handleError(Error(GL_INVALID_VALUE, "Max anisotropy must be at least 1."));
850 return false;
851 }
852 break;
853
854 case GL_TEXTURE_MIN_LOD:
855 case GL_TEXTURE_MAX_LOD:
856 // any value is permissible
857 break;
858
859 case GL_TEXTURE_COMPARE_MODE:
860 if (!ValidateTextureCompareModeValue(context, params))
861 {
862 return false;
863 }
864 break;
865
866 case GL_TEXTURE_COMPARE_FUNC:
867 if (!ValidateTextureCompareFuncValue(context, params))
868 {
869 return false;
870 }
871 break;
872
873 case GL_TEXTURE_SWIZZLE_R:
874 case GL_TEXTURE_SWIZZLE_G:
875 case GL_TEXTURE_SWIZZLE_B:
876 case GL_TEXTURE_SWIZZLE_A:
877 switch (ConvertToGLenum(params[0]))
878 {
879 case GL_RED:
880 case GL_GREEN:
881 case GL_BLUE:
882 case GL_ALPHA:
883 case GL_ZERO:
884 case GL_ONE:
885 break;
886
887 default:
888 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
889 return false;
890 }
891 break;
892
893 case GL_TEXTURE_BASE_LEVEL:
894 if (params[0] < 0)
895 {
896 context->handleError(Error(GL_INVALID_VALUE, "Base level must be at least 0."));
897 return false;
898 }
899 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
900 {
901 context->handleError(
902 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
903 return false;
904 }
905 break;
906
907 case GL_TEXTURE_MAX_LEVEL:
908 if (params[0] < 0)
909 {
910 context->handleError(Error(GL_INVALID_VALUE, "Max level must be at least 0."));
911 return false;
912 }
913 break;
914
Geoff Lang3b573612016-10-31 14:08:10 -0400915 case GL_DEPTH_STENCIL_TEXTURE_MODE:
916 if (context->getClientVersion() < Version(3, 1))
917 {
918 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.1."));
919 return false;
920 }
Geoff Lang9f090372016-12-02 10:20:43 -0500921 switch (ConvertToGLenum(params[0]))
922 {
923 case GL_DEPTH_COMPONENT:
924 case GL_STENCIL_INDEX:
925 break;
926
927 default:
928 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
929 return false;
930 }
Geoff Lang3b573612016-10-31 14:08:10 -0400931 break;
932
Geoff Lang81c6b572016-10-19 14:07:52 -0700933 case GL_TEXTURE_SRGB_DECODE_EXT:
934 if (!ValidateTextureSRGBDecodeValue(context, params))
935 {
936 return false;
937 }
938 break;
939
Geoff Langc1984ed2016-10-07 12:41:00 -0400940 default:
941 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
942 return false;
943 }
944
945 return true;
946}
947
948template <typename ParamType>
949bool ValidateSamplerParameterBase(Context *context,
950 GLuint sampler,
951 GLenum pname,
952 GLsizei bufSize,
953 ParamType *params)
954{
955 if (context->getClientMajorVersion() < 3)
956 {
957 context->handleError(
958 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
959 return false;
960 }
961
962 if (!context->isSampler(sampler))
963 {
964 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
965 return false;
966 }
967
968 const GLsizei minBufSize = 1;
969 if (bufSize >= 0 && bufSize < minBufSize)
970 {
971 context->handleError(
972 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
973 return false;
974 }
975
976 switch (pname)
977 {
978 case GL_TEXTURE_WRAP_S:
979 case GL_TEXTURE_WRAP_T:
980 case GL_TEXTURE_WRAP_R:
981 if (!ValidateTextureWrapModeValue(context, params, false))
982 {
983 return false;
984 }
985 break;
986
987 case GL_TEXTURE_MIN_FILTER:
988 if (!ValidateTextureMinFilterValue(context, params, false))
989 {
990 return false;
991 }
992 break;
993
994 case GL_TEXTURE_MAG_FILTER:
995 if (!ValidateTextureMagFilterValue(context, params))
996 {
997 return false;
998 }
999 break;
1000
1001 case GL_TEXTURE_MIN_LOD:
1002 case GL_TEXTURE_MAX_LOD:
1003 // any value is permissible
1004 break;
1005
1006 case GL_TEXTURE_COMPARE_MODE:
1007 if (!ValidateTextureCompareModeValue(context, params))
1008 {
1009 return false;
1010 }
1011 break;
1012
1013 case GL_TEXTURE_COMPARE_FUNC:
1014 if (!ValidateTextureCompareFuncValue(context, params))
1015 {
1016 return false;
1017 }
1018 break;
1019
Geoff Lang81c6b572016-10-19 14:07:52 -07001020 case GL_TEXTURE_SRGB_DECODE_EXT:
1021 if (!ValidateTextureSRGBDecodeValue(context, params))
1022 {
1023 return false;
1024 }
1025 break;
1026
Geoff Langc1984ed2016-10-07 12:41:00 -04001027 default:
1028 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1029 return false;
1030 }
1031
1032 return true;
1033}
1034
1035bool ValidateGetSamplerParameterBase(Context *context,
1036 GLuint sampler,
1037 GLenum pname,
1038 GLsizei *length)
1039{
1040 if (length)
1041 {
1042 *length = 0;
1043 }
1044
1045 if (context->getClientMajorVersion() < 3)
1046 {
1047 context->handleError(
1048 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1049 return false;
1050 }
1051
1052 if (!context->isSampler(sampler))
1053 {
1054 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
1055 return false;
1056 }
1057
1058 switch (pname)
1059 {
1060 case GL_TEXTURE_WRAP_S:
1061 case GL_TEXTURE_WRAP_T:
1062 case GL_TEXTURE_WRAP_R:
1063 case GL_TEXTURE_MIN_FILTER:
1064 case GL_TEXTURE_MAG_FILTER:
1065 case GL_TEXTURE_MIN_LOD:
1066 case GL_TEXTURE_MAX_LOD:
1067 case GL_TEXTURE_COMPARE_MODE:
1068 case GL_TEXTURE_COMPARE_FUNC:
1069 break;
1070
Geoff Lang81c6b572016-10-19 14:07:52 -07001071 case GL_TEXTURE_SRGB_DECODE_EXT:
1072 if (!context->getExtensions().textureSRGBDecode)
1073 {
1074 context->handleError(
1075 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
1076 return false;
1077 }
1078 break;
1079
Geoff Langc1984ed2016-10-07 12:41:00 -04001080 default:
1081 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1082 return false;
1083 }
1084
1085 if (length)
1086 {
1087 *length = 1;
1088 }
1089 return true;
1090}
1091
Geoff Lang0b031062016-10-13 14:30:04 -04001092bool ValidateGetVertexAttribBase(Context *context,
1093 GLuint index,
1094 GLenum pname,
1095 GLsizei *length,
1096 bool pointer,
1097 bool pureIntegerEntryPoint)
1098{
1099 if (length)
1100 {
1101 *length = 0;
1102 }
1103
1104 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
1105 {
1106 context->handleError(
1107 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1108 return false;
1109 }
1110
1111 if (index >= context->getCaps().maxVertexAttributes)
1112 {
1113 context->handleError(Error(
1114 GL_INVALID_VALUE, "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES."));
1115 return false;
1116 }
1117
1118 if (pointer)
1119 {
1120 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
1121 {
1122 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1123 return false;
1124 }
1125 }
1126 else
1127 {
1128 switch (pname)
1129 {
1130 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1131 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1132 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1133 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1134 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1135 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1136 case GL_CURRENT_VERTEX_ATTRIB:
1137 break;
1138
1139 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1140 static_assert(
1141 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
1142 "ANGLE extension enums not equal to GL enums.");
1143 if (context->getClientMajorVersion() < 3 &&
1144 !context->getExtensions().instancedArrays)
1145 {
1146 context->handleError(Error(GL_INVALID_ENUM,
1147 "GL_VERTEX_ATTRIB_ARRAY_DIVISOR requires OpenGL ES "
1148 "3.0 or GL_ANGLE_instanced_arrays."));
1149 return false;
1150 }
1151 break;
1152
1153 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
1154 if (context->getClientMajorVersion() < 3)
1155 {
Shao80957d92017-02-20 21:25:59 +08001156 context->handleError(Error(
1157 GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
1158 return false;
1159 }
1160 break;
1161
1162 case GL_VERTEX_ATTRIB_BINDING:
1163 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
1164 if (context->getClientVersion() < ES_3_1)
1165 {
1166 context->handleError(
1167 Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
Geoff Lang0b031062016-10-13 14:30:04 -04001168 return false;
1169 }
1170 break;
1171
1172 default:
1173 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1174 return false;
1175 }
1176 }
1177
1178 if (length)
1179 {
1180 if (pname == GL_CURRENT_VERTEX_ATTRIB)
1181 {
1182 *length = 4;
1183 }
1184 else
1185 {
1186 *length = 1;
1187 }
1188 }
1189
1190 return true;
1191}
1192
Geoff Lang6899b872016-10-14 11:30:13 -04001193bool ValidateGetActiveUniformBlockivBase(Context *context,
1194 GLuint program,
1195 GLuint uniformBlockIndex,
1196 GLenum pname,
1197 GLsizei *length)
1198{
1199 if (length)
1200 {
1201 *length = 0;
1202 }
1203
1204 if (context->getClientMajorVersion() < 3)
1205 {
1206 context->handleError(
1207 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1208 return false;
1209 }
1210
1211 Program *programObject = GetValidProgram(context, program);
1212 if (!programObject)
1213 {
1214 return false;
1215 }
1216
1217 if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
1218 {
1219 context->handleError(
1220 Error(GL_INVALID_VALUE, "uniformBlockIndex exceeds active uniform block count."));
1221 return false;
1222 }
1223
1224 switch (pname)
1225 {
1226 case GL_UNIFORM_BLOCK_BINDING:
1227 case GL_UNIFORM_BLOCK_DATA_SIZE:
1228 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1229 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1230 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1231 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1232 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1233 break;
1234
1235 default:
1236 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1237 return false;
1238 }
1239
1240 if (length)
1241 {
1242 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
1243 {
1244 const UniformBlock &uniformBlock =
1245 programObject->getUniformBlockByIndex(uniformBlockIndex);
1246 *length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
1247 }
1248 else
1249 {
1250 *length = 1;
1251 }
1252 }
1253
1254 return true;
1255}
1256
Geoff Langebebe1c2016-10-14 12:01:31 -04001257bool ValidateGetBufferParameterBase(ValidationContext *context,
1258 GLenum target,
1259 GLenum pname,
1260 bool pointerVersion,
1261 GLsizei *numParams)
1262{
1263 if (numParams)
1264 {
1265 *numParams = 0;
1266 }
1267
1268 if (!ValidBufferTarget(context, target))
1269 {
1270 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
1271 return false;
1272 }
1273
1274 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
1275 if (!buffer)
1276 {
1277 // A null buffer means that "0" is bound to the requested buffer target
1278 context->handleError(Error(GL_INVALID_OPERATION, "No buffer bound."));
1279 return false;
1280 }
1281
1282 const Extensions &extensions = context->getExtensions();
1283
1284 switch (pname)
1285 {
1286 case GL_BUFFER_USAGE:
1287 case GL_BUFFER_SIZE:
1288 break;
1289
1290 case GL_BUFFER_ACCESS_OES:
1291 if (!extensions.mapBuffer)
1292 {
1293 context->handleError(
Jamie Madillcc6ac252017-01-25 12:57:21 -08001294 Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
Geoff Langebebe1c2016-10-14 12:01:31 -04001295 return false;
1296 }
1297 break;
1298
1299 case GL_BUFFER_MAPPED:
1300 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
1301 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
1302 !extensions.mapBufferRange)
1303 {
1304 context->handleError(Error(
1305 GL_INVALID_ENUM,
Jamie Madillcc6ac252017-01-25 12:57:21 -08001306 "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
Geoff Langebebe1c2016-10-14 12:01:31 -04001307 return false;
1308 }
1309 break;
1310
1311 case GL_BUFFER_MAP_POINTER:
1312 if (!pointerVersion)
1313 {
1314 context->handleError(
1315 Error(GL_INVALID_ENUM,
1316 "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."));
1317 return false;
1318 }
1319 break;
1320
1321 case GL_BUFFER_ACCESS_FLAGS:
1322 case GL_BUFFER_MAP_OFFSET:
1323 case GL_BUFFER_MAP_LENGTH:
1324 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
1325 {
1326 context->handleError(Error(
1327 GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."));
1328 return false;
1329 }
1330 break;
1331
1332 default:
1333 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1334 return false;
1335 }
1336
1337 // All buffer parameter queries return one value.
1338 if (numParams)
1339 {
1340 *numParams = 1;
1341 }
1342
1343 return true;
1344}
1345
Geoff Lang0a9661f2016-10-20 10:59:20 -07001346bool ValidateGetInternalFormativBase(Context *context,
1347 GLenum target,
1348 GLenum internalformat,
1349 GLenum pname,
1350 GLsizei bufSize,
1351 GLsizei *numParams)
1352{
1353 if (numParams)
1354 {
1355 *numParams = 0;
1356 }
1357
1358 if (context->getClientMajorVersion() < 3)
1359 {
1360 context->handleError(
1361 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1362 return false;
1363 }
1364
1365 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
1366 if (!formatCaps.renderable)
1367 {
1368 context->handleError(Error(GL_INVALID_ENUM, "Internal format is not renderable."));
1369 return false;
1370 }
1371
1372 switch (target)
1373 {
1374 case GL_RENDERBUFFER:
1375 break;
1376
JiangYizhoubddc46b2016-12-09 09:50:51 +08001377 case GL_TEXTURE_2D_MULTISAMPLE:
1378 if (context->getClientVersion() < ES_3_1)
1379 {
1380 context->handleError(
1381 Error(GL_INVALID_OPERATION, "Texture target requires at least OpenGL ES 3.1."));
1382 return false;
1383 }
1384 break;
1385
Geoff Lang0a9661f2016-10-20 10:59:20 -07001386 default:
1387 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
1388 return false;
1389 }
1390
1391 if (bufSize < 0)
1392 {
1393 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
1394 return false;
1395 }
1396
1397 GLsizei maxWriteParams = 0;
1398 switch (pname)
1399 {
1400 case GL_NUM_SAMPLE_COUNTS:
1401 maxWriteParams = 1;
1402 break;
1403
1404 case GL_SAMPLES:
1405 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
1406 break;
1407
1408 default:
1409 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1410 return false;
1411 }
1412
1413 if (numParams)
1414 {
1415 // glGetInternalFormativ will not overflow bufSize
1416 *numParams = std::min(bufSize, maxWriteParams);
1417 }
1418
1419 return true;
1420}
1421
Jamie Madillc1d770e2017-04-13 17:31:24 -04001422bool ValidateUniformCommonBase(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001423 gl::Program *program,
1424 GLint location,
1425 GLsizei count,
1426 const LinkedUniform **uniformOut)
1427{
1428 // TODO(Jiajia): Add image uniform check in future.
1429 if (count < 0)
1430 {
1431 context->handleError(Error(GL_INVALID_VALUE));
1432 return false;
1433 }
1434
1435 if (!program || !program->isLinked())
1436 {
1437 context->handleError(Error(GL_INVALID_OPERATION));
1438 return false;
1439 }
1440
1441 if (location == -1)
1442 {
1443 // Silently ignore the uniform command
1444 return false;
1445 }
1446
1447 const auto &uniformLocations = program->getUniformLocations();
1448 size_t castedLocation = static_cast<size_t>(location);
1449 if (castedLocation >= uniformLocations.size())
1450 {
1451 context->handleError(Error(GL_INVALID_OPERATION, "Invalid uniform location"));
1452 return false;
1453 }
1454
1455 const auto &uniformLocation = uniformLocations[castedLocation];
1456 if (uniformLocation.ignored)
1457 {
1458 // Silently ignore the uniform command
1459 return false;
1460 }
1461
1462 if (!uniformLocation.used)
1463 {
1464 context->handleError(Error(GL_INVALID_OPERATION));
1465 return false;
1466 }
1467
1468 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
1469
1470 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1471 if (!uniform.isArray() && count > 1)
1472 {
1473 context->handleError(Error(GL_INVALID_OPERATION));
1474 return false;
1475 }
1476
1477 *uniformOut = &uniform;
1478 return true;
1479}
1480
Frank Henigman999b0fd2017-02-02 21:45:55 -05001481bool ValidateUniform1ivValue(ValidationContext *context,
Frank Henigmana98a6472017-02-02 21:38:32 -05001482 GLenum uniformType,
1483 GLsizei count,
1484 const GLint *value)
1485{
1486 // Value type is GL_INT, because we only get here from glUniform1i{v}.
1487 // It is compatible with INT or BOOL.
1488 // Do these cheap tests first, for a little extra speed.
1489 if (GL_INT == uniformType || GL_BOOL == uniformType)
1490 {
1491 return true;
1492 }
1493
1494 if (IsSamplerType(uniformType))
1495 {
Frank Henigman999b0fd2017-02-02 21:45:55 -05001496 // Check that the values are in range.
1497 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
1498 for (GLsizei i = 0; i < count; ++i)
1499 {
1500 if (value[i] < 0 || value[i] >= max)
1501 {
1502 context->handleError(Error(GL_INVALID_VALUE, "sampler uniform value out of range"));
1503 return false;
1504 }
1505 }
Frank Henigmana98a6472017-02-02 21:38:32 -05001506 return true;
1507 }
1508
1509 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1510 return false;
1511}
1512
Jamie Madillc1d770e2017-04-13 17:31:24 -04001513bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001514{
1515 // Check that the value type is compatible with uniform type.
Frank Henigmana98a6472017-02-02 21:38:32 -05001516 // Do the cheaper test first, for a little extra speed.
1517 if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001518 {
1519 return true;
1520 }
1521
1522 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1523 return false;
1524}
1525
Jamie Madillc1d770e2017-04-13 17:31:24 -04001526bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001527{
1528 // Check that the value type is compatible with uniform type.
1529 if (valueType == uniformType)
1530 {
1531 return true;
1532 }
1533
1534 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1535 return false;
1536}
1537
Jamie Madillc1d770e2017-04-13 17:31:24 -04001538bool ValidateES2CopyTexImageParameters(ValidationContext *context,
1539 GLenum target,
1540 GLint level,
1541 GLenum internalformat,
1542 bool isSubImage,
1543 GLint xoffset,
1544 GLint yoffset,
1545 GLint x,
1546 GLint y,
1547 GLsizei width,
1548 GLsizei height,
1549 GLint border)
1550{
1551 if (!ValidTexture2DDestinationTarget(context, target))
1552 {
1553 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
1554 return false;
1555 }
1556
1557 if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage))
1558 {
1559 context->handleError(Error(GL_INVALID_VALUE, "Invalid texture dimensions."));
1560 return false;
1561 }
1562
1563 Format textureFormat = Format::Invalid();
1564 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
1565 xoffset, yoffset, 0, x, y, width, height, border,
1566 &textureFormat))
1567 {
1568 return false;
1569 }
1570
1571 const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
1572 GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getFormat().asSized();
1573 const auto &formatInfo = *textureFormat.info;
1574
1575 // [OpenGL ES 2.0.24] table 3.9
1576 if (isSubImage)
1577 {
1578 switch (formatInfo.format)
1579 {
1580 case GL_ALPHA:
1581 if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
1582 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES)
1583 {
1584 context->handleError(Error(GL_INVALID_OPERATION));
1585 return false;
1586 }
1587 break;
1588 case GL_LUMINANCE:
1589 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1590 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1591 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1592 colorbufferFormat != GL_RGBA8_OES)
1593 {
1594 context->handleError(Error(GL_INVALID_OPERATION));
1595 return false;
1596 }
1597 break;
1598 case GL_RED_EXT:
1599 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1600 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1601 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1602 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_R32F &&
1603 colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
1604 colorbufferFormat != GL_RGBA32F)
1605 {
1606 context->handleError(Error(GL_INVALID_OPERATION));
1607 return false;
1608 }
1609 break;
1610 case GL_RG_EXT:
1611 if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
1612 colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
1613 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES &&
1614 colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
1615 colorbufferFormat != GL_RGBA32F)
1616 {
1617 context->handleError(Error(GL_INVALID_OPERATION));
1618 return false;
1619 }
1620 break;
1621 case GL_RGB:
1622 if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1623 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1624 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGB32F &&
1625 colorbufferFormat != GL_RGBA32F)
1626 {
1627 context->handleError(Error(GL_INVALID_OPERATION));
1628 return false;
1629 }
1630 break;
1631 case GL_LUMINANCE_ALPHA:
1632 case GL_RGBA:
1633 if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1634 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGBA32F)
1635 {
1636 context->handleError(Error(GL_INVALID_OPERATION));
1637 return false;
1638 }
1639 break;
1640 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1641 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1642 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1643 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1644 case GL_ETC1_RGB8_OES:
1645 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
1646 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1647 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1648 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1649 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1650 context->handleError(Error(GL_INVALID_OPERATION));
1651 return false;
1652 case GL_DEPTH_COMPONENT:
1653 case GL_DEPTH_STENCIL_OES:
1654 context->handleError(Error(GL_INVALID_OPERATION));
1655 return false;
1656 default:
1657 context->handleError(Error(GL_INVALID_OPERATION));
1658 return false;
1659 }
1660
1661 if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat)
1662 {
1663 context->handleError(Error(GL_INVALID_OPERATION));
1664 return false;
1665 }
1666 }
1667 else
1668 {
1669 switch (internalformat)
1670 {
1671 case GL_ALPHA:
1672 if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
1673 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
1674 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX)
1675 {
1676 context->handleError(Error(GL_INVALID_OPERATION));
1677 return false;
1678 }
1679 break;
1680 case GL_LUMINANCE:
1681 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1682 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1683 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1684 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1685 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1686 {
1687 context->handleError(Error(GL_INVALID_OPERATION));
1688 return false;
1689 }
1690 break;
1691 case GL_RED_EXT:
1692 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1693 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1694 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1695 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1696 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1697 {
1698 context->handleError(Error(GL_INVALID_OPERATION));
1699 return false;
1700 }
1701 break;
1702 case GL_RG_EXT:
1703 if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
1704 colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
1705 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
1706 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX)
1707 {
1708 context->handleError(Error(GL_INVALID_OPERATION));
1709 return false;
1710 }
1711 break;
1712 case GL_RGB:
1713 if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1714 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1715 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1716 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1717 {
1718 context->handleError(Error(GL_INVALID_OPERATION));
1719 return false;
1720 }
1721 break;
1722 case GL_LUMINANCE_ALPHA:
1723 case GL_RGBA:
1724 if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1725 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1726 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1727 {
1728 context->handleError(Error(GL_INVALID_OPERATION));
1729 return false;
1730 }
1731 break;
1732 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1733 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1734 if (context->getExtensions().textureCompressionDXT1)
1735 {
1736 context->handleError(Error(GL_INVALID_OPERATION));
1737 return false;
1738 }
1739 else
1740 {
1741 context->handleError(Error(GL_INVALID_ENUM));
1742 return false;
1743 }
1744 break;
1745 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1746 if (context->getExtensions().textureCompressionDXT3)
1747 {
1748 context->handleError(Error(GL_INVALID_OPERATION));
1749 return false;
1750 }
1751 else
1752 {
1753 context->handleError(Error(GL_INVALID_ENUM));
1754 return false;
1755 }
1756 break;
1757 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1758 if (context->getExtensions().textureCompressionDXT5)
1759 {
1760 context->handleError(Error(GL_INVALID_OPERATION));
1761 return false;
1762 }
1763 else
1764 {
1765 context->handleError(Error(GL_INVALID_ENUM));
1766 return false;
1767 }
1768 break;
1769 case GL_ETC1_RGB8_OES:
1770 if (context->getExtensions().compressedETC1RGB8Texture)
1771 {
1772 context->handleError(Error(GL_INVALID_OPERATION));
1773 return false;
1774 }
1775 else
1776 {
1777 context->handleError(Error(GL_INVALID_ENUM));
1778 return false;
1779 }
1780 break;
1781 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
1782 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1783 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1784 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1785 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1786 if (context->getExtensions().lossyETCDecode)
1787 {
1788 context->handleError(Error(GL_INVALID_OPERATION,
1789 "ETC lossy decode formats can't be copied to."));
1790 return false;
1791 }
1792 else
1793 {
1794 context->handleError(Error(
1795 GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported."));
1796 return false;
1797 }
1798 break;
1799 case GL_DEPTH_COMPONENT:
1800 case GL_DEPTH_COMPONENT16:
1801 case GL_DEPTH_COMPONENT32_OES:
1802 case GL_DEPTH_STENCIL_OES:
1803 case GL_DEPTH24_STENCIL8_OES:
1804 if (context->getExtensions().depthTextures)
1805 {
1806 context->handleError(Error(GL_INVALID_OPERATION));
1807 return false;
1808 }
1809 else
1810 {
1811 context->handleError(Error(GL_INVALID_ENUM));
1812 return false;
1813 }
1814 default:
1815 context->handleError(Error(GL_INVALID_ENUM));
1816 return false;
1817 }
1818 }
1819
1820 // If width or height is zero, it is a no-op. Return false without setting an error.
1821 return (width > 0 && height > 0);
1822}
1823
Geoff Langf41a7152016-09-19 15:11:17 -04001824} // anonymous namespace
1825
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001826bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -04001827{
Jamie Madilld7460c72014-01-21 16:38:14 -05001828 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -04001829 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001830 case GL_TEXTURE_2D:
1831 case GL_TEXTURE_CUBE_MAP:
1832 return true;
Jamie Madill35d15012013-10-07 10:46:37 -04001833
He Yunchaoced53ae2016-11-29 15:00:51 +08001834 case GL_TEXTURE_3D:
1835 case GL_TEXTURE_2D_ARRAY:
1836 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -05001837
He Yunchaoced53ae2016-11-29 15:00:51 +08001838 case GL_TEXTURE_2D_MULTISAMPLE:
He Yunchaoced53ae2016-11-29 15:00:51 +08001839 return (context->getClientVersion() >= Version(3, 1));
Geoff Lang3b573612016-10-31 14:08:10 -04001840
He Yunchaoced53ae2016-11-29 15:00:51 +08001841 default:
1842 return false;
Jamie Madilld7460c72014-01-21 16:38:14 -05001843 }
Jamie Madill35d15012013-10-07 10:46:37 -04001844}
1845
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001846bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
1847{
1848 switch (target)
1849 {
1850 case GL_TEXTURE_2D:
1851 case GL_TEXTURE_CUBE_MAP:
1852 return true;
1853
1854 default:
1855 return false;
1856 }
1857}
1858
1859bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
1860{
1861 switch (target)
1862 {
1863 case GL_TEXTURE_3D:
1864 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +03001865 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001866
1867 default:
1868 return false;
1869 }
1870}
1871
Ian Ewellbda75592016-04-18 17:25:54 -04001872// Most texture GL calls are not compatible with external textures, so we have a separate validation
1873// function for use in the GL calls that do
1874bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
1875{
1876 return (target == GL_TEXTURE_EXTERNAL_OES) &&
1877 (context->getExtensions().eglImageExternal ||
1878 context->getExtensions().eglStreamConsumerExternal);
1879}
1880
Shannon Woods4dfed832014-03-17 20:03:39 -04001881// This function differs from ValidTextureTarget in that the target must be
1882// usable as the destination of a 2D operation-- so a cube face is valid, but
1883// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -04001884// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -05001885bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -04001886{
1887 switch (target)
1888 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001889 case GL_TEXTURE_2D:
1890 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1891 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1892 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1893 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1894 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1895 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1896 return true;
1897 default:
1898 return false;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001899 }
1900}
1901
1902bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
1903{
1904 switch (target)
1905 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001906 case GL_TEXTURE_3D:
1907 case GL_TEXTURE_2D_ARRAY:
1908 return true;
1909 default:
1910 return false;
Shannon Woods4dfed832014-03-17 20:03:39 -04001911 }
1912}
1913
He Yunchao11b038b2016-11-22 21:24:04 +08001914bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target)
1915{
1916 switch (target)
1917 {
1918 case GL_TEXTURE_2D:
1919 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1920 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1921 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1922 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1923 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1924 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1925 case GL_TEXTURE_3D:
1926 case GL_TEXTURE_2D_ARRAY:
1927 case GL_TEXTURE_2D_MULTISAMPLE:
1928 return true;
1929 default:
1930 return false;
1931 }
1932}
1933
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001934bool ValidFramebufferTarget(GLenum target)
1935{
He Yunchaoced53ae2016-11-29 15:00:51 +08001936 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
1937 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
Geoff Langd4475812015-03-18 10:53:05 -04001938 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001939
1940 switch (target)
1941 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001942 case GL_FRAMEBUFFER:
1943 return true;
1944 case GL_READ_FRAMEBUFFER:
1945 return true;
1946 case GL_DRAW_FRAMEBUFFER:
1947 return true;
1948 default:
1949 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001950 }
1951}
1952
Jamie Madill29639852016-09-02 15:00:09 -04001953bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -05001954{
1955 switch (target)
1956 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001957 case GL_ARRAY_BUFFER:
1958 case GL_ELEMENT_ARRAY_BUFFER:
1959 return true;
Jamie Madill8c96d582014-03-05 15:01:23 -05001960
He Yunchaoced53ae2016-11-29 15:00:51 +08001961 case GL_PIXEL_PACK_BUFFER:
1962 case GL_PIXEL_UNPACK_BUFFER:
1963 return (context->getExtensions().pixelBufferObject ||
1964 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -04001965
He Yunchaoced53ae2016-11-29 15:00:51 +08001966 case GL_COPY_READ_BUFFER:
1967 case GL_COPY_WRITE_BUFFER:
1968 case GL_TRANSFORM_FEEDBACK_BUFFER:
1969 case GL_UNIFORM_BUFFER:
1970 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -05001971
He Yunchaoced53ae2016-11-29 15:00:51 +08001972 case GL_ATOMIC_COUNTER_BUFFER:
1973 case GL_SHADER_STORAGE_BUFFER:
1974 case GL_DRAW_INDIRECT_BUFFER:
1975 case GL_DISPATCH_INDIRECT_BUFFER:
He Yunchaoced53ae2016-11-29 15:00:51 +08001976 return context->getClientVersion() >= Version(3, 1);
Geoff Lang3b573612016-10-31 14:08:10 -04001977
He Yunchaoced53ae2016-11-29 15:00:51 +08001978 default:
1979 return false;
Jamie Madill8c96d582014-03-05 15:01:23 -05001980 }
1981}
1982
Jamie Madillc29968b2016-01-20 11:17:23 -05001983bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -04001984{
Jamie Madillc29968b2016-01-20 11:17:23 -05001985 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -04001986 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -04001987 switch (target)
1988 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001989 case GL_TEXTURE_2D:
1990 maxDimension = caps.max2DTextureSize;
1991 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08001992 case GL_TEXTURE_CUBE_MAP:
1993 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1994 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1995 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1996 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1997 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1998 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1999 maxDimension = caps.maxCubeMapTextureSize;
2000 break;
2001 case GL_TEXTURE_3D:
2002 maxDimension = caps.max3DTextureSize;
2003 break;
2004 case GL_TEXTURE_2D_ARRAY:
2005 maxDimension = caps.max2DTextureSize;
2006 break;
He Yunchao11b038b2016-11-22 21:24:04 +08002007 case GL_TEXTURE_2D_MULTISAMPLE:
2008 maxDimension = caps.max2DTextureSize;
2009 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08002010 default:
2011 UNREACHABLE();
Geoff Langce635692013-09-24 13:56:32 -04002012 }
2013
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002014 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -04002015}
2016
Geoff Langcc507aa2016-12-12 10:09:52 -05002017bool ValidImageSizeParameters(const ValidationContext *context,
Austin Kinross08528e12015-10-07 16:24:40 -07002018 GLenum target,
2019 GLint level,
2020 GLsizei width,
2021 GLsizei height,
2022 GLsizei depth,
2023 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -04002024{
2025 if (level < 0 || width < 0 || height < 0 || depth < 0)
2026 {
2027 return false;
2028 }
2029
Austin Kinross08528e12015-10-07 16:24:40 -07002030 // TexSubImage parameters can be NPOT without textureNPOT extension,
2031 // as long as the destination texture is POT.
Geoff Langcc507aa2016-12-12 10:09:52 -05002032 bool hasNPOTSupport =
Geoff Lang5f319a42017-01-09 16:49:19 -05002033 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
Geoff Langcc507aa2016-12-12 10:09:52 -05002034 if (!isSubImage && !hasNPOTSupport &&
Jamie Madill4fd75c12014-06-23 10:53:54 -04002035 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -04002036 {
2037 return false;
2038 }
2039
2040 if (!ValidMipLevel(context, target, level))
2041 {
2042 return false;
2043 }
2044
2045 return true;
2046}
2047
Geoff Lang0d8b7242015-09-09 14:56:53 -04002048bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
2049{
2050 // List of compressed format that require that the texture size is smaller than or a multiple of
2051 // the compressed block size.
2052 switch (internalFormat)
2053 {
2054 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2055 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
2056 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
2057 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -08002058 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08002059 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
2060 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
2061 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
2062 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
2063 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
2064 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04002065 return true;
2066
2067 default:
2068 return false;
2069 }
2070}
2071
Jamie Madillc29968b2016-01-20 11:17:23 -05002072bool ValidCompressedImageSize(const ValidationContext *context,
2073 GLenum internalFormat,
Geoff Lang44ff5a72017-02-03 15:15:43 -05002074 GLint xoffset,
2075 GLint yoffset,
Jamie Madillc29968b2016-01-20 11:17:23 -05002076 GLsizei width,
2077 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04002078{
Geoff Lang5d601382014-07-22 15:14:06 -04002079 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
2080 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04002081 {
2082 return false;
2083 }
2084
Geoff Lang44ff5a72017-02-03 15:15:43 -05002085 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04002086 {
2087 return false;
2088 }
2089
Geoff Lang0d8b7242015-09-09 14:56:53 -04002090 if (CompressedTextureFormatRequiresExactSize(internalFormat))
2091 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05002092 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
2093 yoffset % formatInfo.compressedBlockHeight != 0 ||
2094 (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
Geoff Lang0d8b7242015-09-09 14:56:53 -04002095 width % formatInfo.compressedBlockWidth != 0) ||
2096 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
2097 height % formatInfo.compressedBlockHeight != 0))
2098 {
2099 return false;
2100 }
2101 }
2102
Geoff Langd4f180b2013-09-24 13:57:44 -04002103 return true;
2104}
2105
Geoff Langff5b2d52016-09-07 11:32:23 -04002106bool ValidImageDataSize(ValidationContext *context,
2107 GLenum textureTarget,
2108 GLsizei width,
2109 GLsizei height,
2110 GLsizei depth,
2111 GLenum internalFormat,
2112 GLenum type,
2113 const GLvoid *pixels,
2114 GLsizei imageSize)
2115{
2116 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
2117 if (pixelUnpackBuffer == nullptr && imageSize < 0)
2118 {
2119 // Checks are not required
2120 return true;
2121 }
2122
2123 // ...the data would be unpacked from the buffer object such that the memory reads required
2124 // would exceed the data store size.
2125 GLenum sizedFormat = GetSizedInternalFormat(internalFormat, type);
2126 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat);
2127 const gl::Extents size(width, height, depth);
2128 const auto &unpack = context->getGLState().getUnpackState();
2129
2130 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
2131 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
2132 if (endByteOrErr.isError())
2133 {
2134 context->handleError(endByteOrErr.getError());
2135 return false;
2136 }
2137
2138 GLuint endByte = endByteOrErr.getResult();
2139
2140 if (pixelUnpackBuffer)
2141 {
2142 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
2143 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
2144 checkedEndByte += checkedOffset;
2145
2146 if (!checkedEndByte.IsValid() ||
2147 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
2148 {
2149 // Overflow past the end of the buffer
2150 context->handleError(Error(GL_INVALID_OPERATION));
2151 return false;
2152 }
2153 }
2154 else
2155 {
2156 ASSERT(imageSize >= 0);
2157 if (pixels == nullptr && imageSize != 0)
2158 {
2159 context->handleError(
2160 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
Geoff Lang3feb3ff2016-10-26 10:57:45 -04002161 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04002162 }
2163
Geoff Lang3feb3ff2016-10-26 10:57:45 -04002164 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04002165 {
2166 context->handleError(
2167 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
2168 return false;
2169 }
2170 }
2171
2172 return true;
2173}
2174
Geoff Lang37dde692014-01-31 16:34:54 -05002175bool ValidQueryType(const Context *context, GLenum queryType)
2176{
He Yunchaoced53ae2016-11-29 15:00:51 +08002177 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
2178 "GL extension enums not equal.");
2179 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2180 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05002181
2182 switch (queryType)
2183 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002184 case GL_ANY_SAMPLES_PASSED:
2185 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
2186 return true;
2187 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
2188 return (context->getClientMajorVersion() >= 3);
2189 case GL_TIME_ELAPSED_EXT:
2190 return context->getExtensions().disjointTimerQuery;
2191 case GL_COMMANDS_COMPLETED_CHROMIUM:
2192 return context->getExtensions().syncQuery;
2193 default:
2194 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05002195 }
2196}
2197
Geoff Lang2d62ab72017-03-23 16:54:40 -04002198bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
2199 GLenum type,
2200 GLboolean normalized,
2201 GLsizei stride,
2202 const GLvoid *ptr,
2203 bool pureInteger)
2204{
2205 ASSERT(context->getExtensions().webglCompatibility);
2206
2207 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
2208 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
2209 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
2210 // parameter exceeds 255.
2211 constexpr GLsizei kMaxWebGLStride = 255;
2212 if (stride > kMaxWebGLStride)
2213 {
2214 context->handleError(
2215 Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
2216 return false;
2217 }
2218
2219 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
2220 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
2221 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
2222 // or an INVALID_OPERATION error is generated.
2223 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
2224 size_t typeSize = GetVertexFormatTypeSize(internalType);
2225
2226 ASSERT(isPow2(typeSize) && typeSize > 0);
2227 size_t sizeMask = (typeSize - 1);
2228 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
2229 {
2230 context->handleError(
2231 Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
2232 return false;
2233 }
2234
2235 if ((stride & sizeMask) != 0)
2236 {
2237 context->handleError(
2238 Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
2239 return false;
2240 }
2241
2242 return true;
2243}
2244
Jamie Madillef300b12016-10-07 15:12:09 -04002245Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05002246{
He Yunchaoced53ae2016-11-29 15:00:51 +08002247 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
2248 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
2249 // or program object and INVALID_OPERATION if the provided name identifies an object
2250 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05002251
Dian Xiang769769a2015-09-09 15:20:08 -07002252 Program *validProgram = context->getProgram(id);
2253
2254 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05002255 {
Dian Xiang769769a2015-09-09 15:20:08 -07002256 if (context->getShader(id))
2257 {
Jamie Madill437fa652016-05-03 15:13:24 -04002258 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07002259 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
2260 }
2261 else
2262 {
Jamie Madill437fa652016-05-03 15:13:24 -04002263 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -07002264 }
Geoff Lang48dcae72014-02-05 16:28:24 -05002265 }
Dian Xiang769769a2015-09-09 15:20:08 -07002266
2267 return validProgram;
2268}
2269
Jamie Madillef300b12016-10-07 15:12:09 -04002270Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07002271{
2272 // See ValidProgram for spec details.
2273
2274 Shader *validShader = context->getShader(id);
2275
2276 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05002277 {
Dian Xiang769769a2015-09-09 15:20:08 -07002278 if (context->getProgram(id))
2279 {
Jamie Madill437fa652016-05-03 15:13:24 -04002280 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07002281 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
2282 }
2283 else
2284 {
Jamie Madill437fa652016-05-03 15:13:24 -04002285 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -07002286 }
Geoff Lang48dcae72014-02-05 16:28:24 -05002287 }
Dian Xiang769769a2015-09-09 15:20:08 -07002288
2289 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05002290}
2291
Geoff Langb1196682014-07-23 13:47:29 -04002292bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04002293{
2294 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
2295 {
2296 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
2297
Geoff Langaae65a42014-05-26 12:43:44 -04002298 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04002299 {
Jamie Madill437fa652016-05-03 15:13:24 -04002300 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002301 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04002302 }
2303 }
2304 else
2305 {
2306 switch (attachment)
2307 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002308 case GL_DEPTH_ATTACHMENT:
2309 case GL_STENCIL_ATTACHMENT:
2310 break;
Jamie Madillb4472272014-07-03 10:38:55 -04002311
He Yunchaoced53ae2016-11-29 15:00:51 +08002312 case GL_DEPTH_STENCIL_ATTACHMENT:
2313 if (!context->getExtensions().webglCompatibility &&
2314 context->getClientMajorVersion() < 3)
2315 {
2316 context->handleError(Error(GL_INVALID_ENUM));
2317 return false;
2318 }
2319 break;
Jamie Madillb4472272014-07-03 10:38:55 -04002320
He Yunchaoced53ae2016-11-29 15:00:51 +08002321 default:
2322 context->handleError(Error(GL_INVALID_ENUM));
2323 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04002324 }
2325 }
2326
2327 return true;
2328}
2329
Jamie Madille8fb6402017-02-14 17:56:40 -05002330bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08002331 GLenum target,
2332 GLsizei samples,
2333 GLenum internalformat,
2334 GLsizei width,
2335 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002336{
2337 switch (target)
2338 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002339 case GL_RENDERBUFFER:
2340 break;
2341 default:
2342 context->handleError(Error(GL_INVALID_ENUM));
2343 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002344 }
2345
2346 if (width < 0 || height < 0 || samples < 0)
2347 {
Jamie Madill437fa652016-05-03 15:13:24 -04002348 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002349 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002350 }
2351
Jamie Madill4e0e6f82017-02-17 11:06:03 -05002352 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
2353 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
2354
2355 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04002356 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002357 {
Jamie Madill437fa652016-05-03 15:13:24 -04002358 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002359 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002360 }
2361
2362 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
2363 // 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 -08002364 // only sized internal formats.
Jamie Madill4e0e6f82017-02-17 11:06:03 -05002365 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(convertedInternalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04002366 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002367 {
Jamie Madill437fa652016-05-03 15:13:24 -04002368 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002369 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002370 }
2371
Geoff Langaae65a42014-05-26 12:43:44 -04002372 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002373 {
Jamie Madill437fa652016-05-03 15:13:24 -04002374 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002375 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002376 }
2377
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002378 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002379 if (handle == 0)
2380 {
Jamie Madill437fa652016-05-03 15:13:24 -04002381 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002382 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002383 }
2384
2385 return true;
2386}
2387
He Yunchaoced53ae2016-11-29 15:00:51 +08002388bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
2389 GLenum target,
2390 GLenum attachment,
2391 GLenum renderbuffertarget,
2392 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002393{
Shannon Woods1da3cf62014-06-27 15:32:23 -04002394 if (!ValidFramebufferTarget(target))
2395 {
Jamie Madill437fa652016-05-03 15:13:24 -04002396 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002397 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04002398 }
2399
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002400 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002401
Jamie Madill84115c92015-04-23 15:00:07 -04002402 ASSERT(framebuffer);
2403 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002404 {
Jamie Madill437fa652016-05-03 15:13:24 -04002405 context->handleError(
2406 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002407 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002408 }
2409
Jamie Madillb4472272014-07-03 10:38:55 -04002410 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002411 {
Jamie Madillb4472272014-07-03 10:38:55 -04002412 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002413 }
2414
Jamie Madillab9d82c2014-01-21 16:38:14 -05002415 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
2416 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
2417 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
2418 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
2419 if (renderbuffer != 0)
2420 {
2421 if (!context->getRenderbuffer(renderbuffer))
2422 {
Jamie Madill437fa652016-05-03 15:13:24 -04002423 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002424 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05002425 }
2426 }
2427
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002428 return true;
2429}
2430
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002431bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05002432 GLint srcX0,
2433 GLint srcY0,
2434 GLint srcX1,
2435 GLint srcY1,
2436 GLint dstX0,
2437 GLint dstY0,
2438 GLint dstX1,
2439 GLint dstY1,
2440 GLbitfield mask,
2441 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002442{
2443 switch (filter)
2444 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002445 case GL_NEAREST:
2446 break;
2447 case GL_LINEAR:
2448 break;
2449 default:
2450 context->handleError(Error(GL_INVALID_ENUM));
2451 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002452 }
2453
2454 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
2455 {
Jamie Madill437fa652016-05-03 15:13:24 -04002456 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002457 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002458 }
2459
2460 if (mask == 0)
2461 {
2462 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
2463 // buffers are copied.
2464 return false;
2465 }
2466
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002467 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
2468 // color buffer, leaving only nearest being unfiltered from above
2469 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
2470 {
Jamie Madill437fa652016-05-03 15:13:24 -04002471 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002472 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002473 }
2474
Jamie Madill51f40ec2016-06-15 14:06:00 -04002475 const auto &glState = context->getGLState();
2476 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
2477 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05002478
2479 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002480 {
Jamie Madill437fa652016-05-03 15:13:24 -04002481 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002482 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002483 }
2484
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002485 if (readFramebuffer->id() == drawFramebuffer->id())
2486 {
2487 context->handleError(Error(GL_INVALID_OPERATION));
2488 return false;
2489 }
2490
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002491 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05002492 {
Jamie Madill437fa652016-05-03 15:13:24 -04002493 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05002494 return false;
2495 }
2496
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002497 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05002498 {
Jamie Madill437fa652016-05-03 15:13:24 -04002499 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05002500 return false;
2501 }
2502
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002503 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002504 {
Jamie Madill437fa652016-05-03 15:13:24 -04002505 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002506 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002507 }
2508
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002509 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
2510
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002511 if (mask & GL_COLOR_BUFFER_BIT)
2512 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002513 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05002514 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002515
He Yunchao66a41a22016-12-15 16:45:05 +08002516 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002517 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002518 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002519
Geoff Langa15472a2015-08-11 11:48:03 -04002520 for (size_t drawbufferIdx = 0;
2521 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002522 {
Geoff Langa15472a2015-08-11 11:48:03 -04002523 const FramebufferAttachment *attachment =
2524 drawFramebuffer->getDrawBuffer(drawbufferIdx);
2525 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002526 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002527 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002528
Geoff Langb2f3d052013-08-13 12:49:27 -04002529 // The GL ES 3.0.2 spec (pg 193) states that:
2530 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08002531 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
2532 // as well
2533 // 3) If the read buffer is a signed integer format, the draw buffer must be as
2534 // well
Jamie Madill6163c752015-12-07 16:32:59 -05002535 // Changes with EXT_color_buffer_float:
2536 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04002537 GLenum readComponentType = readFormat.info->componentType;
2538 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08002539 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05002540 readComponentType == GL_SIGNED_NORMALIZED);
2541 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
2542 drawComponentType == GL_SIGNED_NORMALIZED);
2543
2544 if (extensions.colorBufferFloat)
2545 {
2546 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
2547 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
2548
2549 if (readFixedOrFloat != drawFixedOrFloat)
2550 {
Jamie Madill437fa652016-05-03 15:13:24 -04002551 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05002552 "If the read buffer contains fixed-point or "
2553 "floating-point values, the draw buffer "
2554 "must as well."));
2555 return false;
2556 }
2557 }
2558 else if (readFixedPoint != drawFixedPoint)
2559 {
Jamie Madill437fa652016-05-03 15:13:24 -04002560 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05002561 "If the read buffer contains fixed-point "
2562 "values, the draw buffer must as well."));
2563 return false;
2564 }
2565
2566 if (readComponentType == GL_UNSIGNED_INT &&
2567 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002568 {
Jamie Madill437fa652016-05-03 15:13:24 -04002569 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002570 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002571 }
2572
Jamie Madill6163c752015-12-07 16:32:59 -05002573 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002574 {
Jamie Madill437fa652016-05-03 15:13:24 -04002575 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002576 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002577 }
2578
Jamie Madilla3944d42016-07-22 22:13:26 -04002579 if (readColorBuffer->getSamples() > 0 &&
2580 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002581 {
Jamie Madill437fa652016-05-03 15:13:24 -04002582 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002583 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002584 }
2585 }
2586 }
2587
Jamie Madilla3944d42016-07-22 22:13:26 -04002588 if ((readFormat.info->componentType == GL_INT ||
2589 readFormat.info->componentType == GL_UNSIGNED_INT) &&
2590 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002591 {
Jamie Madill437fa652016-05-03 15:13:24 -04002592 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002593 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002594 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002595 }
He Yunchao66a41a22016-12-15 16:45:05 +08002596 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
2597 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
2598 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
2599 // situation is an application error that would lead to a crash in ANGLE.
2600 else if (drawFramebuffer->hasEnabledDrawBuffer())
2601 {
2602 context->handleError(Error(
2603 GL_INVALID_OPERATION,
2604 "Attempt to read from a missing color attachment of a complete framebuffer."));
2605 return false;
2606 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002607 }
2608
He Yunchaoced53ae2016-11-29 15:00:51 +08002609 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002610 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
2611 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002612 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002613 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002614 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002615 const gl::FramebufferAttachment *readBuffer =
2616 readFramebuffer->getAttachment(attachments[i]);
2617 const gl::FramebufferAttachment *drawBuffer =
2618 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002619
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002620 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002621 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002622 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002623 {
Jamie Madill437fa652016-05-03 15:13:24 -04002624 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002625 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002626 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002627
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002628 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002629 {
Jamie Madill437fa652016-05-03 15:13:24 -04002630 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002631 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002632 }
2633 }
He Yunchao66a41a22016-12-15 16:45:05 +08002634 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
2635 else if (drawBuffer)
2636 {
2637 context->handleError(Error(GL_INVALID_OPERATION,
2638 "Attempt to read from a missing depth/stencil "
2639 "attachment of a complete framebuffer."));
2640 return false;
2641 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002642 }
2643 }
2644
2645 return true;
2646}
2647
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002648bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05002649 GLint x,
2650 GLint y,
2651 GLsizei width,
2652 GLsizei height,
2653 GLenum format,
2654 GLenum type,
2655 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05002656{
Geoff Lange93daba2017-03-30 13:54:40 -04002657 return ValidateReadPixelsBase(context, x, y, width, height, format, type, -1, nullptr, nullptr,
2658 nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04002659}
2660
2661bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
2662 GLint x,
2663 GLint y,
2664 GLsizei width,
2665 GLsizei height,
2666 GLenum format,
2667 GLenum type,
2668 GLsizei bufSize,
2669 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04002670 GLsizei *columns,
2671 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -04002672 GLvoid *pixels)
2673{
2674 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05002675 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002676 return false;
2677 }
2678
Geoff Lang62fce5b2016-09-30 10:46:35 -04002679 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04002680 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05002681 {
Geoff Langb1196682014-07-23 13:47:29 -04002682 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002683 }
2684
Geoff Lang62fce5b2016-09-30 10:46:35 -04002685 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05002686 {
Geoff Langb1196682014-07-23 13:47:29 -04002687 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002688 }
2689
Jamie Madillc29968b2016-01-20 11:17:23 -05002690 return true;
2691}
2692
2693bool ValidateReadnPixelsEXT(Context *context,
2694 GLint x,
2695 GLint y,
2696 GLsizei width,
2697 GLsizei height,
2698 GLenum format,
2699 GLenum type,
2700 GLsizei bufSize,
2701 GLvoid *pixels)
2702{
2703 if (bufSize < 0)
2704 {
Jamie Madill437fa652016-05-03 15:13:24 -04002705 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002706 return false;
2707 }
2708
Geoff Lang62fce5b2016-09-30 10:46:35 -04002709 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04002710 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04002711}
Jamie Madill26e91952014-03-05 15:01:27 -05002712
Geoff Lang62fce5b2016-09-30 10:46:35 -04002713bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
2714 GLint x,
2715 GLint y,
2716 GLsizei width,
2717 GLsizei height,
2718 GLenum format,
2719 GLenum type,
2720 GLsizei bufSize,
2721 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04002722 GLsizei *columns,
2723 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -04002724 GLvoid *data)
2725{
2726 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04002727 {
Jamie Madille2e406c2016-06-02 13:04:10 -04002728 return false;
2729 }
2730
Geoff Lange93daba2017-03-30 13:54:40 -04002731 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
2732 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04002733 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002734 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002735 }
2736
Geoff Lang62fce5b2016-09-30 10:46:35 -04002737 if (!ValidateRobustBufferSize(context, bufSize, *length))
2738 {
2739 return false;
2740 }
2741
2742 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05002743}
2744
Olli Etuaho41997e72016-03-10 13:38:39 +02002745bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002746{
2747 if (!context->getExtensions().occlusionQueryBoolean &&
2748 !context->getExtensions().disjointTimerQuery)
2749 {
Jamie Madill437fa652016-05-03 15:13:24 -04002750 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002751 return false;
2752 }
2753
Olli Etuaho41997e72016-03-10 13:38:39 +02002754 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002755}
2756
Olli Etuaho41997e72016-03-10 13:38:39 +02002757bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002758{
2759 if (!context->getExtensions().occlusionQueryBoolean &&
2760 !context->getExtensions().disjointTimerQuery)
2761 {
Jamie Madill437fa652016-05-03 15:13:24 -04002762 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002763 return false;
2764 }
2765
Olli Etuaho41997e72016-03-10 13:38:39 +02002766 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002767}
2768
2769bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002770{
2771 if (!ValidQueryType(context, target))
2772 {
Jamie Madill437fa652016-05-03 15:13:24 -04002773 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04002774 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002775 }
2776
2777 if (id == 0)
2778 {
Jamie Madill437fa652016-05-03 15:13:24 -04002779 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04002780 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002781 }
2782
2783 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
2784 // of zero, if the active query object name for <target> is non-zero (for the
2785 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
2786 // the active query for either target is non-zero), if <id> is the name of an
2787 // existing query object whose type does not match <target>, or if <id> is the
2788 // active query object name for any query type, the error INVALID_OPERATION is
2789 // generated.
2790
2791 // Ensure no other queries are active
2792 // NOTE: If other queries than occlusion are supported, we will need to check
2793 // separately that:
2794 // a) The query ID passed is not the current active query for any target/type
2795 // b) There are no active queries for the requested target (and in the case
2796 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2797 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002798
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002799 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04002802 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002803 }
2804
2805 Query *queryObject = context->getQuery(id, true, target);
2806
2807 // check that name was obtained with glGenQueries
2808 if (!queryObject)
2809 {
Jamie Madill437fa652016-05-03 15:13:24 -04002810 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04002811 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002812 }
2813
2814 // check for type mismatch
2815 if (queryObject->getType() != target)
2816 {
Jamie Madill437fa652016-05-03 15:13:24 -04002817 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04002818 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002819 }
2820
2821 return true;
2822}
2823
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002824bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
2825{
2826 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002827 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002828 {
Jamie Madill437fa652016-05-03 15:13:24 -04002829 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002830 return false;
2831 }
2832
2833 return ValidateBeginQueryBase(context, target, id);
2834}
2835
2836bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04002837{
2838 if (!ValidQueryType(context, target))
2839 {
Jamie Madill437fa652016-05-03 15:13:24 -04002840 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04002841 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04002842 }
2843
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002844 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04002845
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002846 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04002847 {
Jamie Madill437fa652016-05-03 15:13:24 -04002848 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04002849 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04002850 }
2851
Jamie Madill45c785d2014-05-13 14:09:34 -04002852 return true;
2853}
2854
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002855bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
2856{
2857 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002858 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002859 {
Jamie Madill437fa652016-05-03 15:13:24 -04002860 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002861 return false;
2862 }
2863
2864 return ValidateEndQueryBase(context, target);
2865}
2866
2867bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
2868{
2869 if (!context->getExtensions().disjointTimerQuery)
2870 {
Jamie Madill437fa652016-05-03 15:13:24 -04002871 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002872 return false;
2873 }
2874
2875 if (target != GL_TIMESTAMP_EXT)
2876 {
Jamie Madill437fa652016-05-03 15:13:24 -04002877 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002878 return false;
2879 }
2880
2881 Query *queryObject = context->getQuery(id, true, target);
2882 if (queryObject == nullptr)
2883 {
Jamie Madill437fa652016-05-03 15:13:24 -04002884 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002885 return false;
2886 }
2887
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002888 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002889 {
Jamie Madill437fa652016-05-03 15:13:24 -04002890 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002891 return false;
2892 }
2893
2894 return true;
2895}
2896
Geoff Lang2186c382016-10-14 10:54:54 -04002897bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002898{
Geoff Lang2186c382016-10-14 10:54:54 -04002899 if (numParams)
2900 {
2901 *numParams = 0;
2902 }
2903
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002904 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
2905 {
Jamie Madill437fa652016-05-03 15:13:24 -04002906 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002907 return false;
2908 }
2909
2910 switch (pname)
2911 {
2912 case GL_CURRENT_QUERY_EXT:
2913 if (target == GL_TIMESTAMP_EXT)
2914 {
Jamie Madill437fa652016-05-03 15:13:24 -04002915 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002916 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
2917 return false;
2918 }
2919 break;
2920 case GL_QUERY_COUNTER_BITS_EXT:
2921 if (!context->getExtensions().disjointTimerQuery ||
2922 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
2923 {
Jamie Madill437fa652016-05-03 15:13:24 -04002924 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002925 return false;
2926 }
2927 break;
2928 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002929 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002930 return false;
2931 }
2932
Geoff Lang2186c382016-10-14 10:54:54 -04002933 if (numParams)
2934 {
2935 // All queries return only one value
2936 *numParams = 1;
2937 }
2938
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002939 return true;
2940}
2941
2942bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
2943{
2944 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002945 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002946 {
Jamie Madill437fa652016-05-03 15:13:24 -04002947 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002948 return false;
2949 }
2950
Geoff Lang2186c382016-10-14 10:54:54 -04002951 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002952}
2953
Geoff Lang2186c382016-10-14 10:54:54 -04002954bool ValidateGetQueryivRobustANGLE(Context *context,
2955 GLenum target,
2956 GLenum pname,
2957 GLsizei bufSize,
2958 GLsizei *length,
2959 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002960{
Geoff Lang2186c382016-10-14 10:54:54 -04002961 if (!ValidateRobustEntryPoint(context, bufSize))
2962 {
2963 return false;
2964 }
2965
2966 if (!ValidateGetQueryivBase(context, target, pname, length))
2967 {
2968 return false;
2969 }
2970
2971 if (!ValidateRobustBufferSize(context, bufSize, *length))
2972 {
2973 return false;
2974 }
2975
2976 return true;
2977}
2978
2979bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
2980{
2981 if (numParams)
2982 {
2983 *numParams = 0;
2984 }
2985
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002986 Query *queryObject = context->getQuery(id, false, GL_NONE);
2987
2988 if (!queryObject)
2989 {
Jamie Madill437fa652016-05-03 15:13:24 -04002990 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002991 return false;
2992 }
2993
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002994 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002995 {
Jamie Madill437fa652016-05-03 15:13:24 -04002996 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002997 return false;
2998 }
2999
3000 switch (pname)
3001 {
3002 case GL_QUERY_RESULT_EXT:
3003 case GL_QUERY_RESULT_AVAILABLE_EXT:
3004 break;
3005
3006 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003007 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003008 return false;
3009 }
3010
Geoff Lang2186c382016-10-14 10:54:54 -04003011 if (numParams)
3012 {
3013 *numParams = 1;
3014 }
3015
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003016 return true;
3017}
3018
3019bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
3020{
3021 if (!context->getExtensions().disjointTimerQuery)
3022 {
Jamie Madill437fa652016-05-03 15:13:24 -04003023 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003024 return false;
3025 }
Geoff Lang2186c382016-10-14 10:54:54 -04003026 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3027}
3028
3029bool ValidateGetQueryObjectivRobustANGLE(Context *context,
3030 GLuint id,
3031 GLenum pname,
3032 GLsizei bufSize,
3033 GLsizei *length,
3034 GLint *params)
3035{
3036 if (!context->getExtensions().disjointTimerQuery)
3037 {
3038 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3039 return false;
3040 }
3041
3042 if (!ValidateRobustEntryPoint(context, bufSize))
3043 {
3044 return false;
3045 }
3046
3047 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3048 {
3049 return false;
3050 }
3051
3052 if (!ValidateRobustBufferSize(context, bufSize, *length))
3053 {
3054 return false;
3055 }
3056
3057 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003058}
3059
3060bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
3061{
3062 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04003063 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003064 {
Jamie Madill437fa652016-05-03 15:13:24 -04003065 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003066 return false;
3067 }
Geoff Lang2186c382016-10-14 10:54:54 -04003068 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3069}
3070
3071bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
3072 GLuint id,
3073 GLenum pname,
3074 GLsizei bufSize,
3075 GLsizei *length,
3076 GLuint *params)
3077{
3078 if (!context->getExtensions().disjointTimerQuery &&
3079 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
3080 {
3081 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
3082 return false;
3083 }
3084
3085 if (!ValidateRobustEntryPoint(context, bufSize))
3086 {
3087 return false;
3088 }
3089
3090 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3091 {
3092 return false;
3093 }
3094
3095 if (!ValidateRobustBufferSize(context, bufSize, *length))
3096 {
3097 return false;
3098 }
3099
3100 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003101}
3102
3103bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
3104{
3105 if (!context->getExtensions().disjointTimerQuery)
3106 {
Jamie Madill437fa652016-05-03 15:13:24 -04003107 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003108 return false;
3109 }
Geoff Lang2186c382016-10-14 10:54:54 -04003110 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3111}
3112
3113bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
3114 GLuint id,
3115 GLenum pname,
3116 GLsizei bufSize,
3117 GLsizei *length,
3118 GLint64 *params)
3119{
3120 if (!context->getExtensions().disjointTimerQuery)
3121 {
3122 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3123 return false;
3124 }
3125
3126 if (!ValidateRobustEntryPoint(context, bufSize))
3127 {
3128 return false;
3129 }
3130
3131 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3132 {
3133 return false;
3134 }
3135
3136 if (!ValidateRobustBufferSize(context, bufSize, *length))
3137 {
3138 return false;
3139 }
3140
3141 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003142}
3143
3144bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
3145{
3146 if (!context->getExtensions().disjointTimerQuery)
3147 {
Jamie Madill437fa652016-05-03 15:13:24 -04003148 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003149 return false;
3150 }
Geoff Lang2186c382016-10-14 10:54:54 -04003151 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3152}
3153
3154bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
3155 GLuint id,
3156 GLenum pname,
3157 GLsizei bufSize,
3158 GLsizei *length,
3159 GLuint64 *params)
3160{
3161 if (!context->getExtensions().disjointTimerQuery)
3162 {
3163 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3164 return false;
3165 }
3166
3167 if (!ValidateRobustEntryPoint(context, bufSize))
3168 {
3169 return false;
3170 }
3171
3172 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3173 {
3174 return false;
3175 }
3176
3177 if (!ValidateRobustBufferSize(context, bufSize, *length))
3178 {
3179 return false;
3180 }
3181
3182 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003183}
3184
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003185bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003186 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003187 GLuint program,
3188 GLint location,
3189 GLsizei count)
3190{
3191 // Check for ES31 program uniform entry points
3192 if (context->getClientVersion() < Version(3, 1))
3193 {
3194 context->handleError(Error(GL_INVALID_OPERATION));
3195 return false;
3196 }
3197
3198 const LinkedUniform *uniform = nullptr;
3199 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003200 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3201 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003202}
3203
Frank Henigmana98a6472017-02-02 21:38:32 -05003204bool ValidateProgramUniform1iv(gl::Context *context,
3205 GLuint program,
3206 GLint location,
3207 GLsizei count,
3208 const GLint *value)
3209{
3210 // Check for ES31 program uniform entry points
3211 if (context->getClientVersion() < Version(3, 1))
3212 {
3213 context->handleError(Error(GL_INVALID_OPERATION));
3214 return false;
3215 }
3216
3217 const LinkedUniform *uniform = nullptr;
3218 gl::Program *programObject = GetValidProgram(context, program);
3219 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3220 ValidateUniform1ivValue(context, uniform->type, count, value);
3221}
3222
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003223bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003224 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003225 GLuint program,
3226 GLint location,
3227 GLsizei count,
3228 GLboolean transpose)
3229{
3230 // Check for ES31 program uniform entry points
3231 if (context->getClientVersion() < Version(3, 1))
3232 {
3233 context->handleError(Error(GL_INVALID_OPERATION));
3234 return false;
3235 }
3236
3237 const LinkedUniform *uniform = nullptr;
3238 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003239 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3240 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003241}
3242
Jamie Madillc1d770e2017-04-13 17:31:24 -04003243bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003244{
3245 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003246 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003247 {
Jamie Madill437fa652016-05-03 15:13:24 -04003248 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003249 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003250 }
3251
Jamie Madill62d31cb2015-09-11 13:25:51 -04003252 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003253 gl::Program *programObject = context->getGLState().getProgram();
3254 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3255 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04003256}
3257
Frank Henigmana98a6472017-02-02 21:38:32 -05003258bool ValidateUniform1iv(gl::Context *context, GLint location, GLsizei count, const GLint *value)
3259{
3260 const LinkedUniform *uniform = nullptr;
3261 gl::Program *programObject = context->getGLState().getProgram();
3262 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3263 ValidateUniform1ivValue(context, uniform->type, count, value);
3264}
3265
Jamie Madillc1d770e2017-04-13 17:31:24 -04003266bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003267 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08003268 GLint location,
3269 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04003270 GLboolean transpose)
3271{
3272 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003273 int rows = VariableRowCount(valueType);
3274 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03003275 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003276 {
Jamie Madill437fa652016-05-03 15:13:24 -04003277 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003278 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003279 }
3280
Martin Radev1be913c2016-07-11 17:59:16 +03003281 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003282 {
Jamie Madill437fa652016-05-03 15:13:24 -04003283 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003284 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003285 }
3286
Jamie Madill62d31cb2015-09-11 13:25:51 -04003287 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003288 gl::Program *programObject = context->getGLState().getProgram();
3289 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3290 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04003291}
3292
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003293bool ValidateStateQuery(ValidationContext *context,
3294 GLenum pname,
3295 GLenum *nativeType,
3296 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04003297{
3298 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
3299 {
Jamie Madill437fa652016-05-03 15:13:24 -04003300 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003301 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003302 }
3303
Jamie Madill0af26e12015-03-05 19:54:33 -05003304 const Caps &caps = context->getCaps();
3305
Jamie Madill893ab082014-05-16 16:56:10 -04003306 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
3307 {
3308 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
3309
Jamie Madill0af26e12015-03-05 19:54:33 -05003310 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04003311 {
Jamie Madill437fa652016-05-03 15:13:24 -04003312 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003313 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003314 }
3315 }
3316
3317 switch (pname)
3318 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003319 case GL_TEXTURE_BINDING_2D:
3320 case GL_TEXTURE_BINDING_CUBE_MAP:
3321 case GL_TEXTURE_BINDING_3D:
3322 case GL_TEXTURE_BINDING_2D_ARRAY:
3323 break;
3324 case GL_TEXTURE_BINDING_EXTERNAL_OES:
3325 if (!context->getExtensions().eglStreamConsumerExternal &&
3326 !context->getExtensions().eglImageExternal)
3327 {
3328 context->handleError(Error(GL_INVALID_ENUM,
3329 "Neither NV_EGL_stream_consumer_external nor "
3330 "GL_OES_EGL_image_external extensions enabled"));
3331 return false;
3332 }
3333 break;
Jamie Madill893ab082014-05-16 16:56:10 -04003334
He Yunchaoced53ae2016-11-29 15:00:51 +08003335 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
3336 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04003337 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003338 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
3339 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04003340 {
Jamie Madill437fa652016-05-03 15:13:24 -04003341 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003342 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003343 }
3344
Jamie Madill51f40ec2016-06-15 14:06:00 -04003345 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
3346 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03003347
3348 if (framebuffer->getReadBufferState() == GL_NONE)
3349 {
3350 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
3351 return false;
3352 }
3353
Jamie Madillb6bda4a2015-04-20 12:53:26 -04003354 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04003355 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04003356 {
Jamie Madill437fa652016-05-03 15:13:24 -04003357 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003358 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003359 }
3360 }
3361 break;
3362
He Yunchaoced53ae2016-11-29 15:00:51 +08003363 default:
3364 break;
Jamie Madill893ab082014-05-16 16:56:10 -04003365 }
3366
3367 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04003368 if (*numParams == 0)
3369 {
3370 return false;
3371 }
3372
3373 return true;
3374}
3375
3376bool ValidateRobustStateQuery(ValidationContext *context,
3377 GLenum pname,
3378 GLsizei bufSize,
3379 GLenum *nativeType,
3380 unsigned int *numParams)
3381{
3382 if (!ValidateRobustEntryPoint(context, bufSize))
3383 {
3384 return false;
3385 }
3386
3387 if (!ValidateStateQuery(context, pname, nativeType, numParams))
3388 {
3389 return false;
3390 }
3391
3392 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04003393 {
3394 return false;
3395 }
3396
3397 return true;
3398}
3399
Jamie Madillc29968b2016-01-20 11:17:23 -05003400bool ValidateCopyTexImageParametersBase(ValidationContext *context,
3401 GLenum target,
3402 GLint level,
3403 GLenum internalformat,
3404 bool isSubImage,
3405 GLint xoffset,
3406 GLint yoffset,
3407 GLint zoffset,
3408 GLint x,
3409 GLint y,
3410 GLsizei width,
3411 GLsizei height,
3412 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04003413 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04003414{
Jamie Madill560a8d82014-05-21 13:06:20 -04003415 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
3416 {
Jamie Madill437fa652016-05-03 15:13:24 -04003417 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003418 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003419 }
3420
He Yunchaoced53ae2016-11-29 15:00:51 +08003421 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
3422 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04003423 {
Jamie Madill437fa652016-05-03 15:13:24 -04003424 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003425 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003426 }
3427
3428 if (border != 0)
3429 {
Jamie Madill437fa652016-05-03 15:13:24 -04003430 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003431 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003432 }
3433
3434 if (!ValidMipLevel(context, target, level))
3435 {
Jamie Madill437fa652016-05-03 15:13:24 -04003436 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003437 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003438 }
3439
Jamie Madill51f40ec2016-06-15 14:06:00 -04003440 const auto &state = context->getGLState();
3441 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003442 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04003443 {
Jamie Madill437fa652016-05-03 15:13:24 -04003444 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003445 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003446 }
3447
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003448 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04003449 {
Jamie Madill437fa652016-05-03 15:13:24 -04003450 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003451 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003452 }
3453
Martin Radev138064f2016-07-15 12:03:41 +03003454 if (readFramebuffer->getReadBufferState() == GL_NONE)
3455 {
3456 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
3457 return false;
3458 }
3459
Corentin Wallez3c90ed62016-12-16 16:19:28 -05003460 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
3461 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08003462 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05003463 // situation is an application error that would lead to a crash in ANGLE.
3464 if (readFramebuffer->getReadColorbuffer() == nullptr)
3465 {
3466 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
3467 return false;
3468 }
3469
Geoff Langaae65a42014-05-26 12:43:44 -04003470 const gl::Caps &caps = context->getCaps();
3471
Geoff Langaae65a42014-05-26 12:43:44 -04003472 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04003473 switch (target)
3474 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003475 case GL_TEXTURE_2D:
3476 maxDimension = caps.max2DTextureSize;
3477 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003478
He Yunchaoced53ae2016-11-29 15:00:51 +08003479 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
3480 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
3481 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
3482 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
3483 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
3484 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
3485 maxDimension = caps.maxCubeMapTextureSize;
3486 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003487
He Yunchaoced53ae2016-11-29 15:00:51 +08003488 case GL_TEXTURE_2D_ARRAY:
3489 maxDimension = caps.max2DTextureSize;
3490 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003491
He Yunchaoced53ae2016-11-29 15:00:51 +08003492 case GL_TEXTURE_3D:
3493 maxDimension = caps.max3DTextureSize;
3494 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003495
He Yunchaoced53ae2016-11-29 15:00:51 +08003496 default:
3497 context->handleError(Error(GL_INVALID_ENUM));
3498 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003499 }
3500
Jamie Madillc29968b2016-01-20 11:17:23 -05003501 gl::Texture *texture =
3502 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04003503 if (!texture)
3504 {
Jamie Madill437fa652016-05-03 15:13:24 -04003505 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003506 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003507 }
3508
Geoff Lang69cce582015-09-17 13:20:36 -04003509 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04003510 {
Jamie Madill437fa652016-05-03 15:13:24 -04003511 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003512 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003513 }
3514
Geoff Lang5d601382014-07-22 15:14:06 -04003515 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
3516
3517 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04003518 {
Jamie Madill437fa652016-05-03 15:13:24 -04003519 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003520 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003521 }
3522
Geoff Lang44ff5a72017-02-03 15:15:43 -05003523 if (formatInfo.compressed &&
3524 !ValidCompressedImageSize(context, internalformat, xoffset, yoffset, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04003525 {
Jamie Madill437fa652016-05-03 15:13:24 -04003526 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05003527 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003528 }
3529
3530 if (isSubImage)
3531 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05003532 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
3533 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
3534 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04003535 {
Jamie Madill437fa652016-05-03 15:13:24 -04003536 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003537 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003538 }
3539 }
Jamie Madill6f38f822014-06-06 17:12:20 -04003540 else
3541 {
Geoff Lang691e58c2014-12-19 17:03:25 -05003542 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04003543 {
Jamie Madill437fa652016-05-03 15:13:24 -04003544 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003545 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003546 }
3547
Geoff Langeb66a6e2016-10-31 13:06:12 -04003548 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04003549 {
Jamie Madill437fa652016-05-03 15:13:24 -04003550 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003551 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003552 }
3553
3554 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08003555 if (static_cast<int>(width) > maxLevelDimension ||
3556 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04003557 {
Jamie Madill437fa652016-05-03 15:13:24 -04003558 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003559 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003560 }
3561 }
Jamie Madill560a8d82014-05-21 13:06:20 -04003562
Jamie Madill0c8abca2016-07-22 20:21:26 -04003563 if (textureFormatOut)
3564 {
3565 *textureFormatOut = texture->getFormat(target, level);
3566 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05003567
3568 // Detect texture copying feedback loops for WebGL.
3569 if (context->getExtensions().webglCompatibility)
3570 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05003571 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05003572 {
3573 context->handleError(Error(GL_INVALID_OPERATION,
3574 "Texture copying feedback loop formed between Framebuffer "
3575 "and specified Texture level."));
3576 return false;
3577 }
3578 }
3579
Jamie Madill560a8d82014-05-21 13:06:20 -04003580 return true;
3581}
3582
Jiajia Qind9671222016-11-29 16:30:31 +08003583bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04003584{
Jamie Madill1aeb1312014-06-20 13:21:25 -04003585 switch (mode)
3586 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003587 case GL_POINTS:
3588 case GL_LINES:
3589 case GL_LINE_LOOP:
3590 case GL_LINE_STRIP:
3591 case GL_TRIANGLES:
3592 case GL_TRIANGLE_STRIP:
3593 case GL_TRIANGLE_FAN:
3594 break;
3595 default:
3596 context->handleError(Error(GL_INVALID_ENUM));
3597 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04003598 }
3599
Jamie Madill250d33f2014-06-06 17:09:03 -04003600 if (count < 0)
3601 {
Jamie Madill437fa652016-05-03 15:13:24 -04003602 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003603 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003604 }
3605
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003606 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04003607
Jamie Madill250d33f2014-06-06 17:09:03 -04003608 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003609 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04003610 {
Jamie Madill437fa652016-05-03 15:13:24 -04003611 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003612 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003613 }
3614
Jamie Madillcbcde722017-01-06 14:50:00 -05003615 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
3616 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04003617 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003618 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
3619 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04003620 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003621 const FramebufferAttachment *dsAttachment =
3622 framebuffer->getStencilOrDepthStencilAttachment();
3623 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08003624 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04003625 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003626
3627 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
3628 bool differentWritemasks =
3629 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
3630 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
3631 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
3632 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
3633
3634 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04003635 {
Jamie Madillcbcde722017-01-06 14:50:00 -05003636 if (!context->getExtensions().webglCompatibility)
3637 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05003638 ERR() << "This ANGLE implementation does not support separate front/back stencil "
3639 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05003640 }
Jamie Madill437fa652016-05-03 15:13:24 -04003641 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04003642 return false;
3643 }
Jamie Madillac528012014-06-20 13:21:23 -04003644 }
3645
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003646 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04003647 {
Jamie Madill437fa652016-05-03 15:13:24 -04003648 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003649 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04003650 }
3651
Geoff Lang7dd2e102014-11-10 15:19:26 -05003652 gl::Program *program = state.getProgram();
3653 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04003654 {
Jamie Madill437fa652016-05-03 15:13:24 -04003655 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003656 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04003657 }
3658
Geoff Lang7dd2e102014-11-10 15:19:26 -05003659 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04003660 {
Jamie Madill437fa652016-05-03 15:13:24 -04003661 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003662 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04003663 }
3664
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003665 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08003666 for (unsigned int uniformBlockIndex = 0;
3667 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003668 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003669 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08003670 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04003671 const OffsetBindingPointer<Buffer> &uniformBuffer =
3672 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003673
Geoff Lang5d124a62015-09-15 13:03:27 -04003674 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003675 {
3676 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04003677 context->handleError(
3678 Error(GL_INVALID_OPERATION,
3679 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003680 return false;
3681 }
3682
Geoff Lang5d124a62015-09-15 13:03:27 -04003683 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003684 if (uniformBufferSize == 0)
3685 {
3686 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07003687 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003688 }
3689
Jamie Madill62d31cb2015-09-11 13:25:51 -04003690 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003691 {
3692 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04003693 context->handleError(
3694 Error(GL_INVALID_OPERATION,
3695 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003696 return false;
3697 }
3698 }
3699
Jamie Madilla4595b82017-01-11 17:36:34 -05003700 // Detect rendering feedback loops for WebGL.
3701 if (context->getExtensions().webglCompatibility)
3702 {
3703 if (framebuffer->formsRenderingFeedbackLoopWith(state))
3704 {
3705 context->handleError(
3706 Error(GL_INVALID_OPERATION,
3707 "Rendering feedback loop formed between Framebuffer and active Texture."));
3708 return false;
3709 }
3710 }
3711
Jamie Madill250d33f2014-06-06 17:09:03 -04003712 // No-op if zero count
3713 return (count > 0);
3714}
3715
Jamie Madillc1d770e2017-04-13 17:31:24 -04003716bool ValidateDrawArraysCommon(ValidationContext *context,
3717 GLenum mode,
3718 GLint first,
3719 GLsizei count,
3720 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04003721{
Jamie Madillfd716582014-06-06 17:09:04 -04003722 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04003723 {
Jamie Madill437fa652016-05-03 15:13:24 -04003724 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003725 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003726 }
3727
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003728 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003729 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08003730 if (curTransformFeedback && curTransformFeedback->isActive() &&
3731 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04003732 {
3733 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08003734 // that does not match the current transform feedback object's draw mode (if transform
3735 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04003736 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04003737 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003738 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04003739 }
3740
Jiajia Qind9671222016-11-29 16:30:31 +08003741 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07003742 {
3743 return false;
3744 }
3745
Corentin Wallez71168a02016-12-19 15:11:18 -08003746 // Check the computation of maxVertex doesn't overflow.
3747 // - first < 0 or count < 0 have been checked as an error condition
3748 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
3749 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
3750 ASSERT(count > 0 && first >= 0);
3751 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
3752 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05003753 {
3754 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
3755 return false;
3756 }
3757
Corentin Wallez71168a02016-12-19 15:11:18 -08003758 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04003759 {
3760 return false;
3761 }
3762
3763 return true;
3764}
3765
He Yunchaoced53ae2016-11-29 15:00:51 +08003766bool ValidateDrawArraysInstanced(Context *context,
3767 GLenum mode,
3768 GLint first,
3769 GLsizei count,
3770 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003771{
3772 if (primcount < 0)
3773 {
Jamie Madill437fa652016-05-03 15:13:24 -04003774 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003775 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04003776 }
3777
Jamie Madillc1d770e2017-04-13 17:31:24 -04003778 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04003779 {
3780 return false;
3781 }
3782
3783 // No-op if zero primitive count
3784 return (primcount > 0);
3785}
3786
Geoff Lang87a93302014-09-16 13:29:43 -04003787static bool ValidateDrawInstancedANGLE(Context *context)
3788{
3789 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003790 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04003791
Geoff Lang7dd2e102014-11-10 15:19:26 -05003792 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04003793
Jiawei-Shao2597fb62016-12-09 16:38:02 +08003794 const auto &attribs = state.getVertexArray()->getVertexAttributes();
3795 const auto &bindings = state.getVertexArray()->getVertexBindings();
Jamie Madill63805b42015-08-25 13:17:39 -04003796 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04003797 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +08003798 const VertexAttribute &attrib = attribs[attributeIndex];
3799 const VertexBinding &binding = bindings[attrib.bindingIndex];
3800 if (program->isAttribLocationActive(attributeIndex) && binding.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04003801 {
3802 return true;
3803 }
3804 }
3805
Jamie Madill437fa652016-05-03 15:13:24 -04003806 context->handleError(Error(GL_INVALID_OPERATION,
3807 "ANGLE_instanced_arrays requires that at least one active attribute"
3808 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04003809 return false;
3810}
3811
He Yunchaoced53ae2016-11-29 15:00:51 +08003812bool ValidateDrawArraysInstancedANGLE(Context *context,
3813 GLenum mode,
3814 GLint first,
3815 GLsizei count,
3816 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003817{
3818 if (!ValidateDrawInstancedANGLE(context))
3819 {
3820 return false;
3821 }
3822
3823 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
3824}
3825
Jiajia Qind9671222016-11-29 16:30:31 +08003826bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04003827{
Jamie Madill250d33f2014-06-06 17:09:03 -04003828 switch (type)
3829 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003830 case GL_UNSIGNED_BYTE:
3831 case GL_UNSIGNED_SHORT:
3832 break;
3833 case GL_UNSIGNED_INT:
3834 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
3835 {
3836 context->handleError(Error(GL_INVALID_ENUM));
3837 return false;
3838 }
3839 break;
3840 default:
3841 context->handleError(Error(GL_INVALID_ENUM));
3842 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003843 }
3844
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003845 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003846
3847 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08003848 if (curTransformFeedback && curTransformFeedback->isActive() &&
3849 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04003850 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003851 // It is an invalid operation to call DrawElements, DrawRangeElements or
3852 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04003853 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04003854 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003855 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003856 }
3857
Jiajia Qind9671222016-11-29 16:30:31 +08003858 return true;
3859}
3860
3861bool ValidateDrawElements(ValidationContext *context,
3862 GLenum mode,
3863 GLsizei count,
3864 GLenum type,
3865 const GLvoid *indices,
3866 GLsizei primcount,
3867 IndexRange *indexRangeOut)
3868{
3869 if (!ValidateDrawElementsBase(context, type))
3870 return false;
3871
3872 const State &state = context->getGLState();
3873
Jamie Madill250d33f2014-06-06 17:09:03 -04003874 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003875 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04003876 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003877 context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
Geoff Langb1196682014-07-23 13:47:29 -04003878 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003879 }
3880
He Yunchaoced53ae2016-11-29 15:00:51 +08003881 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04003882 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04003883
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05003884 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
3885
3886 if (context->getExtensions().webglCompatibility)
3887 {
3888 ASSERT(isPow2(typeBytes) && typeBytes > 0);
3889 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
3890 {
3891 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
3892 // The offset arguments to drawElements and [...], must be a multiple of the size of the
3893 // data type passed to the call, or an INVALID_OPERATION error is generated.
3894 context->handleError(Error(GL_INVALID_OPERATION,
3895 "indices must be a multiple of the element type size."));
3896 return false;
3897 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003898
3899 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
3900 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
3901 // error is generated.
3902 if (reinterpret_cast<intptr_t>(indices) < 0)
3903 {
3904 context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
3905 return false;
3906 }
Geoff Langfeb8c682017-02-13 16:07:35 -05003907 }
3908
3909 if (context->getExtensions().webglCompatibility ||
3910 !context->getGLState().areClientArraysEnabled())
3911 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05003912 if (!elementArrayBuffer && count > 0)
3913 {
3914 // [WebGL 1.0] Section 6.2 No Client Side Arrays
3915 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
3916 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
3917 context->handleError(Error(GL_INVALID_OPERATION,
3918 "There is no element array buffer bound and count > 0."));
3919 return false;
3920 }
3921 }
3922
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003923 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04003924 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003925 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04003926 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003927 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
3928 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
3929 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
3930 constexpr uint64_t kMaxTypeSize = 8;
3931 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
3932 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
3933 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003934
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003935 uint64_t typeSize = typeBytes;
3936 uint64_t elementCount = static_cast<uint64_t>(count);
3937 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
3938
3939 // Doing the multiplication here is overflow-safe
3940 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
3941
3942 // The offset can be any value, check for overflows
3943 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
3944 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003945 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003946 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003947 return false;
3948 }
3949
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003950 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
3951 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003952 {
3953 context->handleError(
3954 Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
3955 return false;
3956 }
3957 }
3958 else if (!indices)
3959 {
3960 // This is an application error that would normally result in a crash,
3961 // but we catch it and return an error
3962 context->handleError(
3963 Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
Geoff Langb1196682014-07-23 13:47:29 -04003964 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04003965 }
Jamie Madillae3000b2014-08-25 15:47:51 -04003966 }
3967
Jiajia Qind9671222016-11-29 16:30:31 +08003968 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07003969 {
3970 return false;
3971 }
3972
Jamie Madill2b976812014-08-25 15:47:49 -04003973 // Use max index to validate if our vertex buffers are large enough for the pull.
3974 // TODO: offer fast path, with disabled index validation.
3975 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
3976 if (elementArrayBuffer)
3977 {
Jacek Cabana5521de2014-10-01 17:23:46 +02003978 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04003979 Error error =
3980 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
3981 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04003982 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04003983 {
Jamie Madill437fa652016-05-03 15:13:24 -04003984 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04003985 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04003986 }
3987 }
3988 else
3989 {
Geoff Lang3edfe032015-09-04 16:38:24 -04003990 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04003991 }
3992
Jamie Madille79b1e12015-11-04 16:36:37 -05003993 // If we use an index greater than our maximum supported index range, return an error.
3994 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
3995 // return an error if possible here.
3996 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
3997 {
Jamie Madill437fa652016-05-03 15:13:24 -04003998 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05003999 return false;
4000 }
4001
Corentin Wallez92db6942016-12-09 13:10:36 -05004002 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->end),
4003 static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04004004 {
4005 return false;
4006 }
4007
Geoff Lang3edfe032015-09-04 16:38:24 -04004008 // No op if there are no real indices in the index data (all are primitive restart).
4009 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04004010}
4011
Geoff Langb1196682014-07-23 13:47:29 -04004012bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04004013 GLenum mode,
4014 GLsizei count,
4015 GLenum type,
4016 const GLvoid *indices,
4017 GLsizei primcount,
4018 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04004019{
4020 if (primcount < 0)
4021 {
Jamie Madill437fa652016-05-03 15:13:24 -04004022 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004023 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04004024 }
4025
Jamie Madill2b976812014-08-25 15:47:49 -04004026 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04004027 {
4028 return false;
4029 }
4030
4031 // No-op zero primitive count
4032 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04004033}
4034
Geoff Lang3edfe032015-09-04 16:38:24 -04004035bool ValidateDrawElementsInstancedANGLE(Context *context,
4036 GLenum mode,
4037 GLsizei count,
4038 GLenum type,
4039 const GLvoid *indices,
4040 GLsizei primcount,
4041 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04004042{
4043 if (!ValidateDrawInstancedANGLE(context))
4044 {
4045 return false;
4046 }
4047
He Yunchaoced53ae2016-11-29 15:00:51 +08004048 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount,
4049 indexRangeOut);
Geoff Lang87a93302014-09-16 13:29:43 -04004050}
4051
He Yunchaoced53ae2016-11-29 15:00:51 +08004052bool ValidateFramebufferTextureBase(Context *context,
4053 GLenum target,
4054 GLenum attachment,
4055 GLuint texture,
4056 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04004057{
Jamie Madill55ec3b12014-07-03 10:38:57 -04004058 if (!ValidFramebufferTarget(target))
4059 {
Jamie Madill437fa652016-05-03 15:13:24 -04004060 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04004061 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004062 }
4063
4064 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04004065 {
4066 return false;
4067 }
4068
Jamie Madill55ec3b12014-07-03 10:38:57 -04004069 if (texture != 0)
4070 {
4071 gl::Texture *tex = context->getTexture(texture);
4072
4073 if (tex == NULL)
4074 {
Jamie Madill437fa652016-05-03 15:13:24 -04004075 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004076 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004077 }
4078
4079 if (level < 0)
4080 {
Jamie Madill437fa652016-05-03 15:13:24 -04004081 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004082 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004083 }
4084 }
4085
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004086 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04004087 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04004088
Jamie Madill84115c92015-04-23 15:00:07 -04004089 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004090 {
Jamie Madill437fa652016-05-03 15:13:24 -04004091 context->handleError(
4092 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04004093 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004094 }
4095
4096 return true;
4097}
4098
He Yunchaoced53ae2016-11-29 15:00:51 +08004099bool ValidateFramebufferTexture2D(Context *context,
4100 GLenum target,
4101 GLenum attachment,
4102 GLenum textarget,
4103 GLuint texture,
4104 GLint level)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004105{
He Yunchaoced53ae2016-11-29 15:00:51 +08004106 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap
4107 // extension
Martin Radev1be913c2016-07-11 17:59:16 +03004108 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
4109 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004110 {
Jamie Madill437fa652016-05-03 15:13:24 -04004111 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004112 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004113 }
4114
4115 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04004116 {
4117 return false;
4118 }
4119
Jamie Madill55ec3b12014-07-03 10:38:57 -04004120 if (texture != 0)
4121 {
4122 gl::Texture *tex = context->getTexture(texture);
4123 ASSERT(tex);
4124
Jamie Madill2a6564e2014-07-11 09:53:19 -04004125 const gl::Caps &caps = context->getCaps();
4126
Jamie Madill55ec3b12014-07-03 10:38:57 -04004127 switch (textarget)
4128 {
He Yunchaoced53ae2016-11-29 15:00:51 +08004129 case GL_TEXTURE_2D:
Jamie Madill55ec3b12014-07-03 10:38:57 -04004130 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04004131 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04004132 {
Jamie Madill437fa652016-05-03 15:13:24 -04004133 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004134 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004135 }
4136 if (tex->getTarget() != GL_TEXTURE_2D)
4137 {
JiangYizhoubddc46b2016-12-09 09:50:51 +08004138 context->handleError(Error(GL_INVALID_OPERATION,
4139 "Textarget must match the texture target type."));
Geoff Langb1196682014-07-23 13:47:29 -04004140 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004141 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004142 }
4143 break;
4144
He Yunchaoced53ae2016-11-29 15:00:51 +08004145 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4146 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4147 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4148 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4149 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4150 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Jamie Madill55ec3b12014-07-03 10:38:57 -04004151 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04004152 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04004153 {
Jamie Madill437fa652016-05-03 15:13:24 -04004154 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004155 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004156 }
4157 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
4158 {
JiangYizhoubddc46b2016-12-09 09:50:51 +08004159 context->handleError(Error(GL_INVALID_OPERATION,
4160 "Textarget must match the texture target type."));
4161 return false;
4162 }
4163 }
4164 break;
4165
4166 case GL_TEXTURE_2D_MULTISAMPLE:
4167 {
4168 if (context->getClientVersion() < ES_3_1)
4169 {
4170 context->handleError(Error(GL_INVALID_OPERATION,
4171 "Texture target requires at least OpenGL ES 3.1."));
4172 return false;
4173 }
4174
4175 if (level != 0)
4176 {
4177 context->handleError(
4178 Error(GL_INVALID_VALUE, "Level must be 0 for TEXTURE_2D_MULTISAMPLE."));
4179 return false;
4180 }
4181 if (tex->getTarget() != GL_TEXTURE_2D_MULTISAMPLE)
4182 {
4183 context->handleError(Error(GL_INVALID_OPERATION,
4184 "Textarget must match the texture target type."));
Geoff Langb1196682014-07-23 13:47:29 -04004185 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004186 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004187 }
4188 break;
4189
He Yunchaoced53ae2016-11-29 15:00:51 +08004190 default:
4191 context->handleError(Error(GL_INVALID_ENUM));
4192 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004193 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05004194
Jamie Madilla3944d42016-07-22 22:13:26 -04004195 const Format &format = tex->getFormat(textarget, level);
4196 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05004197 {
Jamie Madill437fa652016-05-03 15:13:24 -04004198 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05004199 return false;
4200 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004201 }
4202
Jamie Madill570f7c82014-07-03 10:38:54 -04004203 return true;
4204}
4205
Geoff Langb1196682014-07-23 13:47:29 -04004206bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04004207{
4208 if (program == 0)
4209 {
Jamie Madill437fa652016-05-03 15:13:24 -04004210 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004211 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004212 }
4213
Dian Xiang769769a2015-09-09 15:20:08 -07004214 gl::Program *programObject = GetValidProgram(context, program);
4215 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05004216 {
4217 return false;
4218 }
4219
Jamie Madill0063c512014-08-25 15:47:53 -04004220 if (!programObject || !programObject->isLinked())
4221 {
Jamie Madill437fa652016-05-03 15:13:24 -04004222 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004223 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004224 }
4225
Geoff Lang7dd2e102014-11-10 15:19:26 -05004226 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04004227 {
Jamie Madill437fa652016-05-03 15:13:24 -04004228 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004229 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04004230 }
4231
Jamie Madill0063c512014-08-25 15:47:53 -04004232 return true;
4233}
4234
He Yunchaoced53ae2016-11-29 15:00:51 +08004235bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params)
Jamie Madill78f41802014-08-25 15:47:55 -04004236{
4237 return ValidateGetUniformBase(context, program, location);
4238}
4239
He Yunchaoced53ae2016-11-29 15:00:51 +08004240bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004241{
Jamie Madill78f41802014-08-25 15:47:55 -04004242 return ValidateGetUniformBase(context, program, location);
4243}
4244
Geoff Langf41d0ee2016-10-07 13:04:23 -04004245static bool ValidateSizedGetUniform(Context *context,
4246 GLuint program,
4247 GLint location,
4248 GLsizei bufSize,
4249 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04004250{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004251 if (length)
4252 {
4253 *length = 0;
4254 }
4255
Jamie Madill78f41802014-08-25 15:47:55 -04004256 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04004257 {
Jamie Madill78f41802014-08-25 15:47:55 -04004258 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004259 }
4260
Geoff Langf41d0ee2016-10-07 13:04:23 -04004261 if (bufSize < 0)
4262 {
4263 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
4264 return false;
4265 }
4266
Jamie Madilla502c742014-08-28 17:19:13 -04004267 gl::Program *programObject = context->getProgram(program);
4268 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04004269
Jamie Madill78f41802014-08-25 15:47:55 -04004270 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04004271 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08004272 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04004273 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04004274 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04004275 context->handleError(
4276 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04004277 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004278 }
4279
Geoff Langf41d0ee2016-10-07 13:04:23 -04004280 if (length)
4281 {
Geoff Lang94177fb2016-11-14 16:12:26 -05004282 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04004283 }
4284
Jamie Madill0063c512014-08-25 15:47:53 -04004285 return true;
4286}
4287
He Yunchaoced53ae2016-11-29 15:00:51 +08004288bool ValidateGetnUniformfvEXT(Context *context,
4289 GLuint program,
4290 GLint location,
4291 GLsizei bufSize,
4292 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004293{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004294 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04004295}
4296
He Yunchaoced53ae2016-11-29 15:00:51 +08004297bool ValidateGetnUniformivEXT(Context *context,
4298 GLuint program,
4299 GLint location,
4300 GLsizei bufSize,
4301 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004302{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004303 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
4304}
4305
4306bool ValidateGetUniformfvRobustANGLE(Context *context,
4307 GLuint program,
4308 GLint location,
4309 GLsizei bufSize,
4310 GLsizei *length,
4311 GLfloat *params)
4312{
4313 if (!ValidateRobustEntryPoint(context, bufSize))
4314 {
4315 return false;
4316 }
4317
4318 // bufSize is validated in ValidateSizedGetUniform
4319 return ValidateSizedGetUniform(context, program, location, bufSize, length);
4320}
4321
4322bool ValidateGetUniformivRobustANGLE(Context *context,
4323 GLuint program,
4324 GLint location,
4325 GLsizei bufSize,
4326 GLsizei *length,
4327 GLint *params)
4328{
4329 if (!ValidateRobustEntryPoint(context, bufSize))
4330 {
4331 return false;
4332 }
4333
4334 // bufSize is validated in ValidateSizedGetUniform
4335 return ValidateSizedGetUniform(context, program, location, bufSize, length);
4336}
4337
4338bool ValidateGetUniformuivRobustANGLE(Context *context,
4339 GLuint program,
4340 GLint location,
4341 GLsizei bufSize,
4342 GLsizei *length,
4343 GLuint *params)
4344{
4345 if (!ValidateRobustEntryPoint(context, bufSize))
4346 {
4347 return false;
4348 }
4349
4350 if (context->getClientMajorVersion() < 3)
4351 {
4352 context->handleError(
4353 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
4354 return false;
4355 }
4356
4357 // bufSize is validated in ValidateSizedGetUniform
4358 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04004359}
4360
He Yunchaoced53ae2016-11-29 15:00:51 +08004361bool ValidateDiscardFramebufferBase(Context *context,
4362 GLenum target,
4363 GLsizei numAttachments,
4364 const GLenum *attachments,
4365 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07004366{
4367 if (numAttachments < 0)
4368 {
Jamie Madill437fa652016-05-03 15:13:24 -04004369 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07004370 return false;
4371 }
4372
4373 for (GLsizei i = 0; i < numAttachments; ++i)
4374 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02004375 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07004376 {
4377 if (defaultFramebuffer)
4378 {
Jamie Madill437fa652016-05-03 15:13:24 -04004379 context->handleError(Error(
4380 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07004381 return false;
4382 }
4383
4384 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
4385 {
Jamie Madill437fa652016-05-03 15:13:24 -04004386 context->handleError(Error(GL_INVALID_OPERATION,
4387 "Requested color attachment is greater than the maximum "
4388 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07004389 return false;
4390 }
4391 }
4392 else
4393 {
4394 switch (attachments[i])
4395 {
He Yunchaoced53ae2016-11-29 15:00:51 +08004396 case GL_DEPTH_ATTACHMENT:
4397 case GL_STENCIL_ATTACHMENT:
4398 case GL_DEPTH_STENCIL_ATTACHMENT:
4399 if (defaultFramebuffer)
4400 {
4401 context->handleError(
4402 Error(GL_INVALID_ENUM,
4403 "Invalid attachment when the default framebuffer is bound"));
4404 return false;
4405 }
4406 break;
4407 case GL_COLOR:
4408 case GL_DEPTH:
4409 case GL_STENCIL:
4410 if (!defaultFramebuffer)
4411 {
4412 context->handleError(
4413 Error(GL_INVALID_ENUM,
4414 "Invalid attachment when the default framebuffer is not bound"));
4415 return false;
4416 }
4417 break;
4418 default:
4419 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07004420 return false;
Austin Kinross08332632015-05-05 13:35:47 -07004421 }
4422 }
4423 }
4424
4425 return true;
4426}
4427
Austin Kinross6ee1e782015-05-29 17:05:37 -07004428bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
4429{
4430 // Note that debug marker calls must not set error state
4431
4432 if (length < 0)
4433 {
4434 return false;
4435 }
4436
4437 if (marker == nullptr)
4438 {
4439 return false;
4440 }
4441
4442 return true;
4443}
4444
4445bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
4446{
4447 // Note that debug marker calls must not set error state
4448
4449 if (length < 0)
4450 {
4451 return false;
4452 }
4453
4454 if (length > 0 && marker == nullptr)
4455 {
4456 return false;
4457 }
4458
4459 return true;
4460}
4461
Geoff Langdcab33b2015-07-21 13:03:16 -04004462bool ValidateEGLImageTargetTexture2DOES(Context *context,
4463 egl::Display *display,
4464 GLenum target,
4465 egl::Image *image)
4466{
Geoff Langa8406172015-07-21 16:53:39 -04004467 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
4468 {
Jamie Madill437fa652016-05-03 15:13:24 -04004469 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04004470 return false;
4471 }
4472
4473 switch (target)
4474 {
4475 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04004476 if (!context->getExtensions().eglImage)
4477 {
4478 context->handleError(Error(
4479 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
4480 }
4481 break;
4482
4483 case GL_TEXTURE_EXTERNAL_OES:
4484 if (!context->getExtensions().eglImageExternal)
4485 {
4486 context->handleError(Error(
4487 GL_INVALID_ENUM,
4488 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
4489 }
Geoff Langa8406172015-07-21 16:53:39 -04004490 break;
4491
4492 default:
Jamie Madill437fa652016-05-03 15:13:24 -04004493 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04004494 return false;
4495 }
4496
4497 if (!display->isValidImage(image))
4498 {
Jamie Madill437fa652016-05-03 15:13:24 -04004499 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04004500 return false;
4501 }
4502
4503 if (image->getSamples() > 0)
4504 {
Jamie Madill437fa652016-05-03 15:13:24 -04004505 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04004506 "cannot create a 2D texture from a multisampled EGL image."));
4507 return false;
4508 }
4509
Jamie Madilla3944d42016-07-22 22:13:26 -04004510 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04004511 if (!textureCaps.texturable)
4512 {
Jamie Madill437fa652016-05-03 15:13:24 -04004513 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04004514 "EGL image internal format is not supported as a texture."));
4515 return false;
4516 }
4517
Geoff Langdcab33b2015-07-21 13:03:16 -04004518 return true;
4519}
4520
4521bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
4522 egl::Display *display,
4523 GLenum target,
4524 egl::Image *image)
4525{
Geoff Langa8406172015-07-21 16:53:39 -04004526 if (!context->getExtensions().eglImage)
4527 {
Jamie Madill437fa652016-05-03 15:13:24 -04004528 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04004529 return false;
4530 }
4531
4532 switch (target)
4533 {
4534 case GL_RENDERBUFFER:
4535 break;
4536
4537 default:
Jamie Madill437fa652016-05-03 15:13:24 -04004538 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04004539 return false;
4540 }
4541
4542 if (!display->isValidImage(image))
4543 {
Jamie Madill437fa652016-05-03 15:13:24 -04004544 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04004545 return false;
4546 }
4547
Jamie Madilla3944d42016-07-22 22:13:26 -04004548 const TextureCaps &textureCaps = context->getTextureCaps().get(image->getFormat().asSized());
Geoff Langa8406172015-07-21 16:53:39 -04004549 if (!textureCaps.renderable)
4550 {
Jamie Madill437fa652016-05-03 15:13:24 -04004551 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04004552 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
4553 return false;
4554 }
4555
Geoff Langdcab33b2015-07-21 13:03:16 -04004556 return true;
4557}
Austin Kinrossbc781f32015-10-26 09:27:38 -07004558
4559bool ValidateBindVertexArrayBase(Context *context, GLuint array)
4560{
Geoff Lang36167ab2015-12-07 10:27:14 -05004561 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07004562 {
4563 // The default VAO should always exist
4564 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04004565 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07004566 return false;
4567 }
4568
4569 return true;
4570}
4571
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004572bool ValidateLinkProgram(Context *context, GLuint program)
4573{
4574 if (context->hasActiveTransformFeedback(program))
4575 {
4576 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004577 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004578 "Cannot link program while program is associated with an active "
4579 "transform feedback object."));
4580 return false;
4581 }
Jamie Madillc1d770e2017-04-13 17:31:24 -04004582
4583 Program *programObject = GetValidProgram(context, program);
4584 if (!programObject)
4585 {
4586 return false;
4587 }
4588
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004589 return true;
4590}
4591
Geoff Langc5629752015-12-07 16:29:04 -05004592bool ValidateProgramBinaryBase(Context *context,
4593 GLuint program,
4594 GLenum binaryFormat,
4595 const void *binary,
4596 GLint length)
4597{
4598 Program *programObject = GetValidProgram(context, program);
4599 if (programObject == nullptr)
4600 {
4601 return false;
4602 }
4603
4604 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
4605 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
4606 programBinaryFormats.end())
4607 {
Jamie Madill437fa652016-05-03 15:13:24 -04004608 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05004609 return false;
4610 }
4611
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004612 if (context->hasActiveTransformFeedback(program))
4613 {
4614 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004615 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004616 "Cannot change program binary while program is associated with "
4617 "an active transform feedback object."));
4618 return false;
4619 }
4620
Geoff Langc5629752015-12-07 16:29:04 -05004621 return true;
4622}
4623
4624bool ValidateGetProgramBinaryBase(Context *context,
4625 GLuint program,
4626 GLsizei bufSize,
4627 GLsizei *length,
4628 GLenum *binaryFormat,
4629 void *binary)
4630{
4631 Program *programObject = GetValidProgram(context, program);
4632 if (programObject == nullptr)
4633 {
4634 return false;
4635 }
4636
4637 if (!programObject->isLinked())
4638 {
Jamie Madill437fa652016-05-03 15:13:24 -04004639 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05004640 return false;
4641 }
4642
Jamie Madilla7d12dc2016-12-13 15:08:19 -05004643 if (context->getCaps().programBinaryFormats.empty())
4644 {
4645 context->handleError(Error(GL_INVALID_OPERATION, "No program binary formats supported."));
4646 return false;
4647 }
4648
Geoff Langc5629752015-12-07 16:29:04 -05004649 return true;
4650}
Jamie Madillc29968b2016-01-20 11:17:23 -05004651
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004652bool ValidateUseProgram(Context *context, GLuint program)
4653{
4654 if (program != 0)
4655 {
4656 Program *programObject = context->getProgram(program);
4657 if (!programObject)
4658 {
4659 // ES 3.1.0 section 7.3 page 72
4660 if (context->getShader(program))
4661 {
Jamie Madill437fa652016-05-03 15:13:24 -04004662 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004663 Error(GL_INVALID_OPERATION,
4664 "Attempted to use a single shader instead of a shader program."));
4665 return false;
4666 }
4667 else
4668 {
Jamie Madill437fa652016-05-03 15:13:24 -04004669 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004670 return false;
4671 }
4672 }
4673 if (!programObject->isLinked())
4674 {
Jamie Madill437fa652016-05-03 15:13:24 -04004675 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004676 return false;
4677 }
4678 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004679 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004680 {
4681 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004682 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004683 Error(GL_INVALID_OPERATION,
4684 "Cannot change active program while transform feedback is unpaused."));
4685 return false;
4686 }
4687
4688 return true;
4689}
4690
Jamie Madillc29968b2016-01-20 11:17:23 -05004691bool ValidateCopyTexImage2D(ValidationContext *context,
4692 GLenum target,
4693 GLint level,
4694 GLenum internalformat,
4695 GLint x,
4696 GLint y,
4697 GLsizei width,
4698 GLsizei height,
4699 GLint border)
4700{
Martin Radev1be913c2016-07-11 17:59:16 +03004701 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05004702 {
4703 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
4704 0, x, y, width, height, border);
4705 }
4706
Martin Radev1be913c2016-07-11 17:59:16 +03004707 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05004708 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
4709 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004710}
Jamie Madillc29968b2016-01-20 11:17:23 -05004711
4712bool ValidateFramebufferRenderbuffer(Context *context,
4713 GLenum target,
4714 GLenum attachment,
4715 GLenum renderbuffertarget,
4716 GLuint renderbuffer)
4717{
4718 if (!ValidFramebufferTarget(target) ||
4719 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
4720 {
Jamie Madill437fa652016-05-03 15:13:24 -04004721 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05004722 return false;
4723 }
4724
4725 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
4726 renderbuffertarget, renderbuffer);
4727}
4728
4729bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
4730{
4731 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
4732 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
4733 {
Jamie Madill437fa652016-05-03 15:13:24 -04004734 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05004735 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
4736 return false;
4737 }
4738
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004739 ASSERT(context->getGLState().getDrawFramebuffer());
4740 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05004741 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
4742
4743 // This should come first before the check for the default frame buffer
4744 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
4745 // rather than INVALID_OPERATION
4746 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
4747 {
4748 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
4749
4750 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02004751 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
4752 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05004753 {
4754 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02004755 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
4756 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
4757 // 3.1 is still a bit ambiguous about the error, but future specs are
4758 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04004759 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02004760 return false;
4761 }
4762 else if (bufs[colorAttachment] >= maxColorAttachment)
4763 {
Jamie Madill437fa652016-05-03 15:13:24 -04004764 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02004765 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05004766 return false;
4767 }
4768 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
4769 frameBufferId != 0)
4770 {
4771 // INVALID_OPERATION-GL is bound to buffer and ith argument
4772 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04004773 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05004774 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
4775 return false;
4776 }
4777 }
4778
4779 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
4780 // and n is not 1 or bufs is bound to value other than BACK and NONE
4781 if (frameBufferId == 0)
4782 {
4783 if (n != 1)
4784 {
Jamie Madill437fa652016-05-03 15:13:24 -04004785 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05004786 "n must be 1 when GL is bound to the default framebuffer"));
4787 return false;
4788 }
4789
4790 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
4791 {
Jamie Madill437fa652016-05-03 15:13:24 -04004792 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05004793 GL_INVALID_OPERATION,
4794 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
4795 return false;
4796 }
4797 }
4798
4799 return true;
4800}
4801
4802bool ValidateCopyTexSubImage2D(Context *context,
4803 GLenum target,
4804 GLint level,
4805 GLint xoffset,
4806 GLint yoffset,
4807 GLint x,
4808 GLint y,
4809 GLsizei width,
4810 GLsizei height)
4811{
Martin Radev1be913c2016-07-11 17:59:16 +03004812 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05004813 {
4814 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
4815 yoffset, x, y, width, height, 0);
4816 }
4817
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05004818 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
4819 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05004820}
4821
Geoff Lang496c02d2016-10-20 11:38:11 -07004822bool ValidateGetBufferPointervBase(Context *context,
4823 GLenum target,
4824 GLenum pname,
4825 GLsizei *length,
4826 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03004827{
Geoff Lang496c02d2016-10-20 11:38:11 -07004828 if (length)
4829 {
4830 *length = 0;
4831 }
4832
4833 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
4834 {
4835 context->handleError(
4836 Error(GL_INVALID_OPERATION,
Jamie Madillcc6ac252017-01-25 12:57:21 -08004837 "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
Geoff Lang496c02d2016-10-20 11:38:11 -07004838 return false;
4839 }
4840
Olli Etuaho4f667482016-03-30 15:56:35 +03004841 if (!ValidBufferTarget(context, target))
4842 {
Jamie Madill437fa652016-05-03 15:13:24 -04004843 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03004844 return false;
4845 }
4846
Geoff Lang496c02d2016-10-20 11:38:11 -07004847 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03004848 {
Geoff Lang496c02d2016-10-20 11:38:11 -07004849 case GL_BUFFER_MAP_POINTER:
4850 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03004851
Geoff Lang496c02d2016-10-20 11:38:11 -07004852 default:
4853 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4854 return false;
4855 }
Olli Etuaho4f667482016-03-30 15:56:35 +03004856
4857 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
4858 // target bound to zero generate an INVALID_OPERATION error."
4859 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07004860 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03004861 {
Jamie Madill437fa652016-05-03 15:13:24 -04004862 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004863 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
4864 return false;
4865 }
4866
Geoff Lang496c02d2016-10-20 11:38:11 -07004867 if (length)
4868 {
4869 *length = 1;
4870 }
4871
Olli Etuaho4f667482016-03-30 15:56:35 +03004872 return true;
4873}
4874
4875bool ValidateUnmapBufferBase(Context *context, GLenum target)
4876{
4877 if (!ValidBufferTarget(context, target))
4878 {
Jamie Madill437fa652016-05-03 15:13:24 -04004879 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004880 return false;
4881 }
4882
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004883 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03004884
4885 if (buffer == nullptr || !buffer->isMapped())
4886 {
Jamie Madill437fa652016-05-03 15:13:24 -04004887 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004888 return false;
4889 }
4890
4891 return true;
4892}
4893
4894bool ValidateMapBufferRangeBase(Context *context,
4895 GLenum target,
4896 GLintptr offset,
4897 GLsizeiptr length,
4898 GLbitfield access)
4899{
4900 if (!ValidBufferTarget(context, target))
4901 {
Jamie Madill437fa652016-05-03 15:13:24 -04004902 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004903 return false;
4904 }
4905
4906 if (offset < 0 || length < 0)
4907 {
Jamie Madill437fa652016-05-03 15:13:24 -04004908 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004909 return false;
4910 }
4911
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004912 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03004913
4914 if (!buffer)
4915 {
Jamie Madill437fa652016-05-03 15:13:24 -04004916 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004917 return false;
4918 }
4919
4920 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04004921 CheckedNumeric<size_t> checkedOffset(offset);
4922 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03004923
Jamie Madille2e406c2016-06-02 13:04:10 -04004924 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03004925 {
Jamie Madill437fa652016-05-03 15:13:24 -04004926 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004927 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
4928 return false;
4929 }
4930
4931 // Check for invalid bits in the mask
4932 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
4933 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
4934 GL_MAP_UNSYNCHRONIZED_BIT;
4935
4936 if (access & ~(allAccessBits))
4937 {
Jamie Madill437fa652016-05-03 15:13:24 -04004938 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03004939 return false;
4940 }
4941
4942 if (length == 0)
4943 {
Jamie Madill437fa652016-05-03 15:13:24 -04004944 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004945 return false;
4946 }
4947
4948 if (buffer->isMapped())
4949 {
Jamie Madill437fa652016-05-03 15:13:24 -04004950 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004951 return false;
4952 }
4953
4954 // Check for invalid bit combinations
4955 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
4956 {
Jamie Madill437fa652016-05-03 15:13:24 -04004957 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004958 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
4959 return false;
4960 }
4961
4962 GLbitfield writeOnlyBits =
4963 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
4964
4965 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
4966 {
Jamie Madill437fa652016-05-03 15:13:24 -04004967 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03004968 "Invalid access bits when mapping buffer for reading: 0x%X.",
4969 access));
4970 return false;
4971 }
4972
4973 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
4974 {
Jamie Madill437fa652016-05-03 15:13:24 -04004975 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03004976 GL_INVALID_OPERATION,
4977 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
4978 return false;
4979 }
4980 return true;
4981}
4982
4983bool ValidateFlushMappedBufferRangeBase(Context *context,
4984 GLenum target,
4985 GLintptr offset,
4986 GLsizeiptr length)
4987{
4988 if (offset < 0 || length < 0)
4989 {
Jamie Madill437fa652016-05-03 15:13:24 -04004990 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004991 return false;
4992 }
4993
4994 if (!ValidBufferTarget(context, target))
4995 {
Jamie Madill437fa652016-05-03 15:13:24 -04004996 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004997 return false;
4998 }
4999
Jamie Madilldfde6ab2016-06-09 07:07:18 -07005000 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03005001
5002 if (buffer == nullptr)
5003 {
Jamie Madill437fa652016-05-03 15:13:24 -04005004 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03005005 return false;
5006 }
5007
5008 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
5009 {
Jamie Madill437fa652016-05-03 15:13:24 -04005010 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03005011 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
5012 return false;
5013 }
5014
5015 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04005016 CheckedNumeric<size_t> checkedOffset(offset);
5017 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03005018
Jamie Madille2e406c2016-06-02 13:04:10 -04005019 if (!checkedSize.IsValid() ||
5020 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03005021 {
Jamie Madill437fa652016-05-03 15:13:24 -04005022 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03005023 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
5024 return false;
5025 }
5026
5027 return true;
5028}
5029
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005030bool ValidateGenerateMipmap(Context *context, GLenum target)
5031{
5032 if (!ValidTextureTarget(context, target))
5033 {
5034 context->handleError(Error(GL_INVALID_ENUM));
5035 return false;
5036 }
5037
5038 Texture *texture = context->getTargetTexture(target);
5039
5040 if (texture == nullptr)
5041 {
5042 context->handleError(Error(GL_INVALID_OPERATION));
5043 return false;
5044 }
5045
5046 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
5047
5048 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
5049 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
5050 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
5051 {
5052 context->handleError(Error(GL_INVALID_OPERATION));
5053 return false;
5054 }
5055
Jamie Madilla3944d42016-07-22 22:13:26 -04005056 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
5057 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
5058 const TextureCaps &formatCaps = context->getTextureCaps().get(format.asSized());
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005059
5060 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
5061 // unsized formats or that are color renderable and filterable. Since we do not track if
5062 // the texture was created with sized or unsized format (only sized formats are stored),
5063 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
5064 // be able to) because they aren't color renderable. Simply do a special case for LUMA
5065 // textures since they're the only texture format that can be created with unsized formats
5066 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
5067 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04005068 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
5069 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005070 {
5071 context->handleError(Error(GL_INVALID_OPERATION));
5072 return false;
5073 }
5074
5075 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04005076 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005077 {
5078 context->handleError(Error(GL_INVALID_OPERATION));
5079 return false;
5080 }
5081
5082 // Non-power of 2 ES2 check
Geoff Lang55482a12016-11-21 16:54:01 -05005083 if (context->getClientVersion() < Version(3, 0) && !context->getExtensions().textureNPOT &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005084 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
5085 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
5086 {
Geoff Lang55482a12016-11-21 16:54:01 -05005087 ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005088 context->handleError(Error(GL_INVALID_OPERATION));
5089 return false;
5090 }
5091
5092 // Cube completeness check
5093 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
5094 {
5095 context->handleError(Error(GL_INVALID_OPERATION));
5096 return false;
5097 }
5098
5099 return true;
5100}
5101
Olli Etuaho41997e72016-03-10 13:38:39 +02005102bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
5103{
5104 return ValidateGenOrDelete(context, n);
5105}
5106
5107bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
5108{
5109 return ValidateGenOrDelete(context, n);
5110}
5111
5112bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
5113{
5114 return ValidateGenOrDelete(context, n);
5115}
5116
5117bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
5118{
5119 return ValidateGenOrDelete(context, n);
5120}
5121
5122bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
5123{
5124 return ValidateGenOrDelete(context, n);
5125}
5126
5127bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
5128{
5129 return ValidateGenOrDelete(context, n);
5130}
5131
5132bool ValidateGenTextures(Context *context, GLint n, GLuint *)
5133{
5134 return ValidateGenOrDelete(context, n);
5135}
5136
5137bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
5138{
5139 return ValidateGenOrDelete(context, n);
5140}
5141
5142bool ValidateGenOrDelete(Context *context, GLint n)
5143{
5144 if (n < 0)
5145 {
Jamie Madill437fa652016-05-03 15:13:24 -04005146 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02005147 return false;
5148 }
5149 return true;
5150}
5151
Geoff Langf41a7152016-09-19 15:11:17 -04005152bool ValidateEnable(Context *context, GLenum cap)
5153{
5154 if (!ValidCap(context, cap, false))
5155 {
5156 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5157 return false;
5158 }
5159
5160 if (context->getLimitations().noSampleAlphaToCoverageSupport &&
5161 cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
5162 {
5163 const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
5164 context->handleError(Error(GL_INVALID_OPERATION, errorMessage));
5165
5166 // We also output an error message to the debugger window if tracing is active, so that
5167 // developers can see the error message.
Yuly Novikovd73f8522017-01-13 17:48:57 -05005168 ERR() << errorMessage;
Geoff Langf41a7152016-09-19 15:11:17 -04005169 return false;
5170 }
5171
5172 return true;
5173}
5174
5175bool ValidateDisable(Context *context, GLenum cap)
5176{
5177 if (!ValidCap(context, cap, false))
5178 {
5179 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5180 return false;
5181 }
5182
5183 return true;
5184}
5185
5186bool ValidateIsEnabled(Context *context, GLenum cap)
5187{
5188 if (!ValidCap(context, cap, true))
5189 {
5190 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5191 return false;
5192 }
5193
5194 return true;
5195}
5196
Geoff Langff5b2d52016-09-07 11:32:23 -04005197bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
5198{
5199 if (!context->getExtensions().robustClientMemory)
5200 {
5201 context->handleError(
5202 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
5203 return false;
5204 }
5205
5206 if (bufSize < 0)
5207 {
5208 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
5209 return false;
5210 }
5211
5212 return true;
5213}
5214
Geoff Lang2e43dbb2016-10-14 12:27:35 -04005215bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
5216{
5217 if (bufSize < numParams)
5218 {
5219 context->handleError(Error(GL_INVALID_OPERATION,
5220 "%u parameters are required but %i were provided.", numParams,
5221 bufSize));
5222 return false;
5223 }
5224
5225 return true;
5226}
5227
Geoff Langff5b2d52016-09-07 11:32:23 -04005228bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context,
5229 GLenum target,
5230 GLenum attachment,
5231 GLenum pname,
5232 GLsizei *numParams)
5233{
5234 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08005235 if (numParams)
5236 {
5237 *numParams = 1;
5238 }
Geoff Langff5b2d52016-09-07 11:32:23 -04005239
5240 if (!ValidFramebufferTarget(target))
5241 {
5242 context->handleError(Error(GL_INVALID_ENUM));
5243 return false;
5244 }
5245
5246 int clientVersion = context->getClientMajorVersion();
5247
5248 switch (pname)
5249 {
5250 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5251 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5252 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5253 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5254 break;
5255
5256 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
5257 if (clientVersion < 3 && !context->getExtensions().sRGB)
5258 {
5259 context->handleError(Error(GL_INVALID_ENUM));
5260 return false;
5261 }
5262 break;
5263
5264 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
5265 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
5266 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
5267 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
5268 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
5269 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
5270 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5271 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5272 if (clientVersion < 3)
5273 {
5274 context->handleError(Error(GL_INVALID_ENUM));
5275 return false;
5276 }
5277 break;
5278
5279 default:
5280 context->handleError(Error(GL_INVALID_ENUM));
5281 return false;
5282 }
5283
5284 // Determine if the attachment is a valid enum
5285 switch (attachment)
5286 {
5287 case GL_BACK:
5288 case GL_FRONT:
5289 case GL_DEPTH:
5290 case GL_STENCIL:
5291 case GL_DEPTH_STENCIL_ATTACHMENT:
5292 if (clientVersion < 3)
5293 {
5294 context->handleError(Error(GL_INVALID_ENUM));
5295 return false;
5296 }
5297 break;
5298
5299 case GL_DEPTH_ATTACHMENT:
5300 case GL_STENCIL_ATTACHMENT:
5301 break;
5302
5303 default:
5304 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
5305 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
5306 {
5307 context->handleError(Error(GL_INVALID_ENUM));
5308 return false;
5309 }
5310 break;
5311 }
5312
5313 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
5314 ASSERT(framebuffer);
5315
5316 if (framebuffer->id() == 0)
5317 {
5318 if (clientVersion < 3)
5319 {
5320 context->handleError(Error(GL_INVALID_OPERATION));
5321 return false;
5322 }
5323
5324 switch (attachment)
5325 {
5326 case GL_BACK:
5327 case GL_DEPTH:
5328 case GL_STENCIL:
5329 break;
5330
5331 default:
5332 context->handleError(Error(GL_INVALID_OPERATION));
5333 return false;
5334 }
5335 }
5336 else
5337 {
5338 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
5339 {
5340 // Valid attachment query
5341 }
5342 else
5343 {
5344 switch (attachment)
5345 {
5346 case GL_DEPTH_ATTACHMENT:
5347 case GL_STENCIL_ATTACHMENT:
5348 break;
5349
5350 case GL_DEPTH_STENCIL_ATTACHMENT:
5351 if (!framebuffer->hasValidDepthStencil())
5352 {
5353 context->handleError(Error(GL_INVALID_OPERATION));
5354 return false;
5355 }
5356 break;
5357
5358 default:
5359 context->handleError(Error(GL_INVALID_OPERATION));
5360 return false;
5361 }
5362 }
5363 }
5364
5365 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
5366 if (attachmentObject)
5367 {
5368 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
5369 attachmentObject->type() == GL_TEXTURE ||
5370 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
5371
5372 switch (pname)
5373 {
5374 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5375 if (attachmentObject->type() != GL_RENDERBUFFER &&
5376 attachmentObject->type() != GL_TEXTURE)
5377 {
5378 context->handleError(Error(GL_INVALID_ENUM));
5379 return false;
5380 }
5381 break;
5382
5383 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5384 if (attachmentObject->type() != GL_TEXTURE)
5385 {
5386 context->handleError(Error(GL_INVALID_ENUM));
5387 return false;
5388 }
5389 break;
5390
5391 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5392 if (attachmentObject->type() != GL_TEXTURE)
5393 {
5394 context->handleError(Error(GL_INVALID_ENUM));
5395 return false;
5396 }
5397 break;
5398
5399 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5400 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
5401 {
5402 context->handleError(Error(GL_INVALID_OPERATION));
5403 return false;
5404 }
5405 break;
5406
5407 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5408 if (attachmentObject->type() != GL_TEXTURE)
5409 {
5410 context->handleError(Error(GL_INVALID_ENUM));
5411 return false;
5412 }
5413 break;
5414
5415 default:
5416 break;
5417 }
5418 }
5419 else
5420 {
5421 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
5422 // is NONE, then querying any other pname will generate INVALID_ENUM.
5423
5424 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
5425 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
5426 // INVALID_OPERATION for all other pnames
5427
5428 switch (pname)
5429 {
5430 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5431 break;
5432
5433 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5434 if (clientVersion < 3)
5435 {
5436 context->handleError(Error(GL_INVALID_ENUM));
5437 return false;
5438 }
5439 break;
5440
5441 default:
5442 if (clientVersion < 3)
5443 {
5444 context->handleError(Error(GL_INVALID_ENUM));
5445 return false;
5446 }
5447 else
5448 {
5449 context->handleError(Error(GL_INVALID_OPERATION));
5450 return false;
5451 }
5452 }
5453 }
5454
5455 return true;
5456}
5457
5458bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
5459 GLenum target,
5460 GLenum attachment,
5461 GLenum pname,
5462 GLsizei bufSize,
5463 GLsizei *numParams)
5464{
5465 if (!ValidateRobustEntryPoint(context, bufSize))
5466 {
5467 return false;
5468 }
5469
5470 if (!ValidateGetFramebufferAttachmentParameteriv(context, target, attachment, pname, numParams))
5471 {
5472 return false;
5473 }
5474
5475 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
5476 {
5477 return false;
5478 }
5479
5480 return true;
5481}
5482
5483bool ValidateGetBufferParameteriv(ValidationContext *context,
5484 GLenum target,
5485 GLenum pname,
Geoff Langebebe1c2016-10-14 12:01:31 -04005486 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04005487{
Geoff Langebebe1c2016-10-14 12:01:31 -04005488 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
Geoff Langff5b2d52016-09-07 11:32:23 -04005489}
5490
5491bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
5492 GLenum target,
5493 GLenum pname,
5494 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04005495 GLsizei *length,
5496 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04005497{
5498 if (!ValidateRobustEntryPoint(context, bufSize))
5499 {
5500 return false;
5501 }
5502
Geoff Langebebe1c2016-10-14 12:01:31 -04005503 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04005504 {
5505 return false;
5506 }
5507
Geoff Langebebe1c2016-10-14 12:01:31 -04005508 if (!ValidateRobustBufferSize(context, bufSize, *length))
5509 {
5510 return false;
5511 }
5512
5513 return true;
5514}
5515
5516bool ValidateGetBufferParameteri64v(ValidationContext *context,
5517 GLenum target,
5518 GLenum pname,
5519 GLint64 *params)
5520{
5521 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
5522}
5523
5524bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
5525 GLenum target,
5526 GLenum pname,
5527 GLsizei bufSize,
5528 GLsizei *length,
5529 GLint64 *params)
5530{
5531 if (!ValidateRobustEntryPoint(context, bufSize))
5532 {
5533 return false;
5534 }
5535
5536 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
5537 {
5538 return false;
5539 }
5540
5541 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04005542 {
5543 return false;
5544 }
5545
5546 return true;
5547}
5548
5549bool ValidateGetProgramiv(Context *context, GLuint program, GLenum pname, GLsizei *numParams)
5550{
5551 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08005552 if (numParams)
5553 {
5554 *numParams = 1;
5555 }
Geoff Langff5b2d52016-09-07 11:32:23 -04005556
5557 Program *programObject = GetValidProgram(context, program);
5558 if (!programObject)
5559 {
5560 return false;
5561 }
5562
5563 switch (pname)
5564 {
5565 case GL_DELETE_STATUS:
5566 case GL_LINK_STATUS:
5567 case GL_VALIDATE_STATUS:
5568 case GL_INFO_LOG_LENGTH:
5569 case GL_ATTACHED_SHADERS:
5570 case GL_ACTIVE_ATTRIBUTES:
5571 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
5572 case GL_ACTIVE_UNIFORMS:
5573 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
5574 break;
5575
5576 case GL_PROGRAM_BINARY_LENGTH:
5577 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
5578 {
5579 context->handleError(Error(GL_INVALID_ENUM,
5580 "Querying GL_PROGRAM_BINARY_LENGTH requires "
5581 "GL_OES_get_program_binary or ES 3.0."));
5582 return false;
5583 }
5584 break;
5585
5586 case GL_ACTIVE_UNIFORM_BLOCKS:
5587 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
5588 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
5589 case GL_TRANSFORM_FEEDBACK_VARYINGS:
5590 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
5591 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
5592 if (context->getClientMajorVersion() < 3)
5593 {
5594 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
5595 return false;
5596 }
5597 break;
5598
Yunchao He61afff12017-03-14 15:34:03 +08005599 case GL_PROGRAM_SEPARABLE:
5600 if (context->getClientVersion() < Version(3, 1))
5601 {
5602 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.1."));
5603 return false;
5604 }
5605 break;
5606
Geoff Langff5b2d52016-09-07 11:32:23 -04005607 default:
5608 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
5609 return false;
5610 }
5611
5612 return true;
5613}
5614
5615bool ValidateGetProgramivRobustANGLE(Context *context,
5616 GLuint program,
5617 GLenum pname,
5618 GLsizei bufSize,
5619 GLsizei *numParams)
5620{
5621 if (!ValidateRobustEntryPoint(context, bufSize))
5622 {
5623 return false;
5624 }
5625
5626 if (!ValidateGetProgramiv(context, program, pname, numParams))
5627 {
5628 return false;
5629 }
5630
5631 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
5632 {
5633 return false;
5634 }
5635
5636 return true;
5637}
5638
Geoff Lang740d9022016-10-07 11:20:52 -04005639bool ValidateGetRenderbufferParameteriv(Context *context,
5640 GLenum target,
5641 GLenum pname,
5642 GLint *params)
5643{
5644 return ValidateGetRenderbufferParameterivBase(context, target, pname, nullptr);
5645}
5646
5647bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
5648 GLenum target,
5649 GLenum pname,
5650 GLsizei bufSize,
5651 GLsizei *length,
5652 GLint *params)
5653{
5654 if (!ValidateRobustEntryPoint(context, bufSize))
5655 {
5656 return false;
5657 }
5658
5659 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
5660 {
5661 return false;
5662 }
5663
5664 if (!ValidateRobustBufferSize(context, bufSize, *length))
5665 {
5666 return false;
5667 }
5668
5669 return true;
5670}
5671
Geoff Langd7d0ed32016-10-07 11:33:51 -04005672bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params)
5673{
5674 return ValidateGetShaderivBase(context, shader, pname, nullptr);
5675}
5676
5677bool ValidateGetShaderivRobustANGLE(Context *context,
5678 GLuint shader,
5679 GLenum pname,
5680 GLsizei bufSize,
5681 GLsizei *length,
5682 GLint *params)
5683{
5684 if (!ValidateRobustEntryPoint(context, bufSize))
5685 {
5686 return false;
5687 }
5688
5689 if (!ValidateGetShaderivBase(context, shader, pname, length))
5690 {
5691 return false;
5692 }
5693
5694 if (!ValidateRobustBufferSize(context, bufSize, *length))
5695 {
5696 return false;
5697 }
5698
5699 return true;
5700}
5701
Geoff Langc1984ed2016-10-07 12:41:00 -04005702bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params)
5703{
5704 return ValidateGetTexParameterBase(context, target, pname, nullptr);
5705}
5706
5707bool ValidateGetTexParameterfvRobustANGLE(Context *context,
5708 GLenum target,
5709 GLenum pname,
5710 GLsizei bufSize,
5711 GLsizei *length,
5712 GLfloat *params)
5713{
5714 if (!ValidateRobustEntryPoint(context, bufSize))
5715 {
5716 return false;
5717 }
5718
5719 if (!ValidateGetTexParameterBase(context, target, pname, length))
5720 {
5721 return false;
5722 }
5723
5724 if (!ValidateRobustBufferSize(context, bufSize, *length))
5725 {
5726 return false;
5727 }
5728
5729 return true;
5730}
5731
5732bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params)
5733{
5734 return ValidateGetTexParameterBase(context, target, pname, nullptr);
5735}
5736
5737bool ValidateGetTexParameterivRobustANGLE(Context *context,
5738 GLenum target,
5739 GLenum pname,
5740 GLsizei bufSize,
5741 GLsizei *length,
5742 GLint *params)
5743{
5744 if (!ValidateRobustEntryPoint(context, bufSize))
5745 {
5746 return false;
5747 }
5748
5749 if (!ValidateGetTexParameterBase(context, target, pname, length))
5750 {
5751 return false;
5752 }
5753
5754 if (!ValidateRobustBufferSize(context, bufSize, *length))
5755 {
5756 return false;
5757 }
5758
5759 return true;
5760}
5761
5762bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param)
5763{
5764 return ValidateTexParameterBase(context, target, pname, -1, &param);
5765}
5766
5767bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params)
5768{
5769 return ValidateTexParameterBase(context, target, pname, -1, params);
5770}
5771
5772bool ValidateTexParameterfvRobustANGLE(Context *context,
5773 GLenum target,
5774 GLenum pname,
5775 GLsizei bufSize,
5776 const GLfloat *params)
5777{
5778 if (!ValidateRobustEntryPoint(context, bufSize))
5779 {
5780 return false;
5781 }
5782
5783 return ValidateTexParameterBase(context, target, pname, bufSize, params);
5784}
5785
5786bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param)
5787{
5788 return ValidateTexParameterBase(context, target, pname, -1, &param);
5789}
5790
5791bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params)
5792{
5793 return ValidateTexParameterBase(context, target, pname, -1, params);
5794}
5795
5796bool ValidateTexParameterivRobustANGLE(Context *context,
5797 GLenum target,
5798 GLenum pname,
5799 GLsizei bufSize,
5800 const GLint *params)
5801{
5802 if (!ValidateRobustEntryPoint(context, bufSize))
5803 {
5804 return false;
5805 }
5806
5807 return ValidateTexParameterBase(context, target, pname, bufSize, params);
5808}
5809
5810bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
5811{
5812 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
5813}
5814
5815bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
5816 GLuint sampler,
5817 GLenum pname,
5818 GLuint bufSize,
5819 GLsizei *length,
5820 GLfloat *params)
5821{
5822 if (!ValidateRobustEntryPoint(context, bufSize))
5823 {
5824 return false;
5825 }
5826
5827 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
5828 {
5829 return false;
5830 }
5831
5832 if (!ValidateRobustBufferSize(context, bufSize, *length))
5833 {
5834 return false;
5835 }
5836
5837 return true;
5838}
5839
5840bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
5841{
5842 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
5843}
5844
5845bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
5846 GLuint sampler,
5847 GLenum pname,
5848 GLuint bufSize,
5849 GLsizei *length,
5850 GLint *params)
5851{
5852 if (!ValidateRobustEntryPoint(context, bufSize))
5853 {
5854 return false;
5855 }
5856
5857 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
5858 {
5859 return false;
5860 }
5861
5862 if (!ValidateRobustBufferSize(context, bufSize, *length))
5863 {
5864 return false;
5865 }
5866
5867 return true;
5868}
5869
5870bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
5871{
5872 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
5873}
5874
5875bool ValidateSamplerParameterfv(Context *context,
5876 GLuint sampler,
5877 GLenum pname,
5878 const GLfloat *params)
5879{
5880 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
5881}
5882
5883bool ValidateSamplerParameterfvRobustANGLE(Context *context,
5884 GLuint sampler,
5885 GLenum pname,
5886 GLsizei bufSize,
5887 const GLfloat *params)
5888{
5889 if (!ValidateRobustEntryPoint(context, bufSize))
5890 {
5891 return false;
5892 }
5893
5894 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
5895}
5896
5897bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
5898{
5899 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
5900}
5901
5902bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
5903{
5904 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
5905}
5906
5907bool ValidateSamplerParameterivRobustANGLE(Context *context,
5908 GLuint sampler,
5909 GLenum pname,
5910 GLsizei bufSize,
5911 const GLint *params)
5912{
5913 if (!ValidateRobustEntryPoint(context, bufSize))
5914 {
5915 return false;
5916 }
5917
5918 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
5919}
5920
Geoff Lang0b031062016-10-13 14:30:04 -04005921bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params)
5922{
5923 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false);
5924}
5925
5926bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
5927 GLuint index,
5928 GLenum pname,
5929 GLsizei bufSize,
5930 GLsizei *length,
5931 GLfloat *params)
5932{
5933 if (!ValidateRobustEntryPoint(context, bufSize))
5934 {
5935 return false;
5936 }
5937
5938 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
5939 {
5940 return false;
5941 }
5942
5943 if (!ValidateRobustBufferSize(context, bufSize, *length))
5944 {
5945 return false;
5946 }
5947
5948 return true;
5949}
5950
5951bool ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params)
5952{
5953 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false);
5954}
5955
5956bool ValidateGetVertexAttribivRobustANGLE(Context *context,
5957 GLuint index,
5958 GLenum pname,
5959 GLsizei bufSize,
5960 GLsizei *length,
5961 GLint *params)
5962{
5963 if (!ValidateRobustEntryPoint(context, bufSize))
5964 {
5965 return false;
5966 }
5967
5968 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
5969 {
5970 return false;
5971 }
5972
5973 if (!ValidateRobustBufferSize(context, bufSize, *length))
5974 {
5975 return false;
5976 }
5977
5978 return true;
5979}
5980
5981bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer)
5982{
5983 return ValidateGetVertexAttribBase(context, index, pname, nullptr, true, false);
5984}
5985
5986bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
5987 GLuint index,
5988 GLenum pname,
5989 GLsizei bufSize,
5990 GLsizei *length,
5991 void **pointer)
5992{
5993 if (!ValidateRobustEntryPoint(context, bufSize))
5994 {
5995 return false;
5996 }
5997
5998 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
5999 {
6000 return false;
6001 }
6002
6003 if (!ValidateRobustBufferSize(context, bufSize, *length))
6004 {
6005 return false;
6006 }
6007
6008 return true;
6009}
6010
6011bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
6012{
6013 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
6014}
6015
6016bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
6017 GLuint index,
6018 GLenum pname,
6019 GLsizei bufSize,
6020 GLsizei *length,
6021 GLint *params)
6022{
6023 if (!ValidateRobustEntryPoint(context, bufSize))
6024 {
6025 return false;
6026 }
6027
6028 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
6029 {
6030 return false;
6031 }
6032
6033 if (!ValidateRobustBufferSize(context, bufSize, *length))
6034 {
6035 return false;
6036 }
6037
6038 return true;
6039}
6040
6041bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
6042{
6043 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
6044}
6045
6046bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
6047 GLuint index,
6048 GLenum pname,
6049 GLsizei bufSize,
6050 GLsizei *length,
6051 GLuint *params)
6052{
6053 if (!ValidateRobustEntryPoint(context, bufSize))
6054 {
6055 return false;
6056 }
6057
6058 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
6059 {
6060 return false;
6061 }
6062
6063 if (!ValidateRobustBufferSize(context, bufSize, *length))
6064 {
6065 return false;
6066 }
6067
6068 return true;
6069}
6070
Geoff Lang6899b872016-10-14 11:30:13 -04006071bool ValidateGetActiveUniformBlockiv(Context *context,
6072 GLuint program,
6073 GLuint uniformBlockIndex,
6074 GLenum pname,
6075 GLint *params)
6076{
6077 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
6078}
6079
6080bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
6081 GLuint program,
6082 GLuint uniformBlockIndex,
6083 GLenum pname,
6084 GLsizei bufSize,
6085 GLsizei *length,
6086 GLint *params)
6087{
6088 if (!ValidateRobustEntryPoint(context, bufSize))
6089 {
6090 return false;
6091 }
6092
6093 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
6094 {
6095 return false;
6096 }
6097
6098 if (!ValidateRobustBufferSize(context, bufSize, *length))
6099 {
6100 return false;
6101 }
6102
6103 return true;
6104}
6105
Geoff Lang0a9661f2016-10-20 10:59:20 -07006106bool ValidateGetInternalFormativ(Context *context,
6107 GLenum target,
6108 GLenum internalformat,
6109 GLenum pname,
6110 GLsizei bufSize,
6111 GLint *params)
6112{
6113 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
6114 nullptr);
6115}
6116
6117bool ValidateGetInternalFormativRobustANGLE(Context *context,
6118 GLenum target,
6119 GLenum internalformat,
6120 GLenum pname,
6121 GLsizei bufSize,
6122 GLsizei *length,
6123 GLint *params)
6124{
6125 if (!ValidateRobustEntryPoint(context, bufSize))
6126 {
6127 return false;
6128 }
6129
6130 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
6131 {
6132 return false;
6133 }
6134
6135 if (!ValidateRobustBufferSize(context, bufSize, *length))
6136 {
6137 return false;
6138 }
6139
6140 return true;
6141}
6142
Shao80957d92017-02-20 21:25:59 +08006143bool ValidateVertexFormatBase(ValidationContext *context,
6144 GLuint attribIndex,
6145 GLint size,
6146 GLenum type,
6147 GLboolean pureInteger)
6148{
6149 const Caps &caps = context->getCaps();
6150 if (attribIndex >= caps.maxVertexAttributes)
6151 {
6152 context->handleError(
6153 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
6154 return false;
6155 }
6156
6157 if (size < 1 || size > 4)
6158 {
6159 context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
6160 }
6161
6162 switch (type)
6163 {
6164 case GL_BYTE:
6165 case GL_UNSIGNED_BYTE:
6166 case GL_SHORT:
6167 case GL_UNSIGNED_SHORT:
6168 break;
6169
6170 case GL_INT:
6171 case GL_UNSIGNED_INT:
6172 if (context->getClientMajorVersion() < 3)
6173 {
6174 context->handleError(
6175 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6176 return false;
6177 }
6178 break;
6179
6180 case GL_FIXED:
6181 case GL_FLOAT:
6182 if (pureInteger)
6183 {
6184 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6185 return false;
6186 }
6187 break;
6188
6189 case GL_HALF_FLOAT:
6190 if (context->getClientMajorVersion() < 3)
6191 {
6192 context->handleError(
6193 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6194 return false;
6195 }
6196 if (pureInteger)
6197 {
6198 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6199 return false;
6200 }
6201 break;
6202
6203 case GL_INT_2_10_10_10_REV:
6204 case GL_UNSIGNED_INT_2_10_10_10_REV:
6205 if (context->getClientMajorVersion() < 3)
6206 {
6207 context->handleError(
6208 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6209 return false;
6210 }
6211 if (pureInteger)
6212 {
6213 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6214 return false;
6215 }
6216 if (size != 4)
6217 {
6218 context->handleError(Error(GL_INVALID_OPERATION,
6219 "Type is INT_2_10_10_10_REV or "
6220 "UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
6221 return false;
6222 }
6223 break;
6224
6225 default:
6226 context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
6227 return false;
6228 }
6229
6230 return true;
6231}
6232
Geoff Lang76e65652017-03-27 14:58:02 -04006233// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
6234// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
6235// specified clear value and the type of a buffer that is being cleared generates an
6236// INVALID_OPERATION error instead of producing undefined results
6237bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
6238 GLint drawbuffer,
6239 const GLenum *validComponentTypes,
6240 size_t validComponentTypeCount)
6241{
6242 const FramebufferAttachment *attachment =
6243 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
6244 if (attachment)
6245 {
6246 GLenum componentType = attachment->getFormat().info->componentType;
6247 const GLenum *end = validComponentTypes + validComponentTypeCount;
6248 if (std::find(validComponentTypes, end, componentType) == end)
6249 {
6250 context->handleError(
6251 Error(GL_INVALID_OPERATION,
6252 "No defined conversion between clear value and attachment format."));
6253 return false;
6254 }
6255 }
6256
6257 return true;
6258}
6259
Jamie Madillc29968b2016-01-20 11:17:23 -05006260} // namespace gl