blob: b0ffad2ce71fd017849510ce3c6beed04bfffccd [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
Jamie Madille2e406c2016-06-02 13:04:10 -040010
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/validationES2.h"
12#include "libANGLE/validationES3.h"
13#include "libANGLE/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040014#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050015#include "libANGLE/Texture.h"
16#include "libANGLE/Framebuffer.h"
17#include "libANGLE/FramebufferAttachment.h"
18#include "libANGLE/formatutils.h"
Geoff Langa8406172015-07-21 16:53:39 -040019#include "libANGLE/Image.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050021#include "libANGLE/Program.h"
22#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050023#include "libANGLE/TransformFeedback.h"
24#include "libANGLE/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025
26#include "common/mathutil.h"
27#include "common/utilities.h"
28
Jamie Madille2e406c2016-06-02 13:04:10 -040029using namespace angle;
30
Geoff Lange8ebe7f2013-08-05 15:03:13 -040031namespace gl
32{
Jamie Madille79b1e12015-11-04 16:36:37 -050033const char *g_ExceedsMaxElementErrorMessage = "Element value exceeds maximum element index.";
34
Jamie Madill1ca74672015-07-21 15:14:11 -040035namespace
36{
Corentin Wallez92db6942016-12-09 13:10:36 -050037bool ValidateDrawAttribs(ValidationContext *context,
38 GLint primcount,
39 GLint maxVertex,
40 GLint vertexCount)
Jamie Madill1ca74672015-07-21 15:14:11 -040041{
Jamie Madilldfde6ab2016-06-09 07:07:18 -070042 const gl::State &state = context->getGLState();
Jamie Madill1ca74672015-07-21 15:14:11 -040043 const gl::Program *program = state.getProgram();
44
Corentin Wallez327411e2016-12-09 11:09:17 -050045 bool webglCompatibility = context->getExtensions().webglCompatibility;
46
He Yunchaoced53ae2016-11-29 15:00:51 +080047 const VertexArray *vao = state.getVertexArray();
48 const auto &vertexAttribs = vao->getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +080049 const auto &vertexBindings = vao->getVertexBindings();
He Yunchaoced53ae2016-11-29 15:00:51 +080050 size_t maxEnabledAttrib = vao->getMaxEnabledAttribute();
Jamie Madill1ca74672015-07-21 15:14:11 -040051 for (size_t attributeIndex = 0; attributeIndex < maxEnabledAttrib; ++attributeIndex)
52 {
53 const VertexAttribute &attrib = vertexAttribs[attributeIndex];
Corentin Wallezfd456442016-12-21 17:57:00 -050054 if (!program->isAttribLocationActive(attributeIndex) || !attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040055 {
Corentin Wallezfd456442016-12-21 17:57:00 -050056 continue;
57 }
Jamie Madill1ca74672015-07-21 15:14:11 -040058
Jiawei-Shao2597fb62016-12-09 16:38:02 +080059 const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
Corentin Wallezfd456442016-12-21 17:57:00 -050060 // If we have no buffer, then we either get an error, or there are no more checks to be done.
Jiawei-Shao2597fb62016-12-09 16:38:02 +080061 gl::Buffer *buffer = binding.buffer.get();
Corentin Wallezfd456442016-12-21 17:57:00 -050062 if (!buffer)
63 {
Geoff Langfeb8c682017-02-13 16:07:35 -050064 if (webglCompatibility || !state.areClientArraysEnabled())
Corentin Wallez327411e2016-12-09 11:09:17 -050065 {
66 // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
Corentin Wallezfd456442016-12-21 17:57:00 -050067 // If a vertex attribute is enabled as an array via enableVertexAttribArray but
68 // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer,
69 // then calls to drawArrays or drawElements will generate an INVALID_OPERATION
70 // error.
Corentin Wallez327411e2016-12-09 11:09:17 -050071 context->handleError(
72 Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer."));
Corentin Wallezfd456442016-12-21 17:57:00 -050073 return false;
Corentin Wallez327411e2016-12-09 11:09:17 -050074 }
Corentin Wallezfd456442016-12-21 17:57:00 -050075 else if (attrib.pointer == nullptr)
Jamie Madill1ca74672015-07-21 15:14:11 -040076 {
77 // This is an application error that would normally result in a crash,
78 // but we catch it and return an error
Corentin Wallezfd456442016-12-21 17:57:00 -050079 context->handleError(
80 Error(GL_INVALID_OPERATION,
81 "An enabled vertex array has no buffer and no pointer."));
Jamie Madill1ca74672015-07-21 15:14:11 -040082 return false;
83 }
Corentin Wallezfd456442016-12-21 17:57:00 -050084 continue;
85 }
86
87 // If we're drawing zero vertices, we have enough data.
88 if (vertexCount <= 0 || primcount <= 0)
89 {
90 continue;
91 }
92
93 GLint maxVertexElement = 0;
Jiawei-Shao2597fb62016-12-09 16:38:02 +080094 if (binding.divisor == 0)
Corentin Wallezfd456442016-12-21 17:57:00 -050095 {
96 maxVertexElement = maxVertex;
97 }
98 else
99 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800100 maxVertexElement = (primcount - 1) / binding.divisor;
Corentin Wallezfd456442016-12-21 17:57:00 -0500101 }
102
103 // We do manual overflow checks here instead of using safe_math.h because it was
104 // a bottleneck. Thanks to some properties of GL we know inequalities that can
105 // help us make the overflow checks faster.
106
107 // The max possible attribSize is 16 for a vector of 4 32 bit values.
108 constexpr uint64_t kMaxAttribSize = 16;
109 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
110 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
111
112 // We know attribStride is given as a GLsizei which is typedefed to int.
113 // We also know an upper bound for attribSize.
114 static_assert(std::is_same<int, GLsizei>::value, "");
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800115 uint64_t attribStride = ComputeVertexAttributeStride(attrib, binding);
Corentin Wallezfd456442016-12-21 17:57:00 -0500116 uint64_t attribSize = ComputeVertexAttributeTypeSize(attrib);
117 ASSERT(attribStride <= kIntMax && attribSize <= kMaxAttribSize);
118
119 // Computing the max offset using uint64_t without attrib.offset is overflow
120 // safe. Note: Last vertex element does not take the full stride!
121 static_assert(kIntMax * kIntMax < kUint64Max - kMaxAttribSize, "");
122 uint64_t attribDataSizeNoOffset = maxVertexElement * attribStride + attribSize;
123
124 // An overflow can happen when adding the offset, check for it.
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800125 uint64_t attribOffset = ComputeVertexAttributeOffset(attrib, binding);
126 if (attribDataSizeNoOffset > kUint64Max - attribOffset)
Corentin Wallezfd456442016-12-21 17:57:00 -0500127 {
128 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
129 return false;
130 }
131 uint64_t attribDataSizeWithOffset = attribDataSizeNoOffset + attribOffset;
132
133 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
134 // We can return INVALID_OPERATION if our vertex attribute does not have
135 // enough backing data.
136 if (attribDataSizeWithOffset > static_cast<uint64_t>(buffer->getSize()))
137 {
138 context->handleError(Error(GL_INVALID_OPERATION,
139 "Vertex buffer is not big enough for the draw call"));
140 return false;
Jamie Madill1ca74672015-07-21 15:14:11 -0400141 }
142 }
143
144 return true;
145}
146
Geoff Langf607c602016-09-21 11:46:48 -0400147bool ValidReadPixelsFormatType(ValidationContext *context,
148 GLenum framebufferComponentType,
149 GLenum format,
150 GLenum type)
151{
152 switch (framebufferComponentType)
153 {
154 case GL_UNSIGNED_NORMALIZED:
155 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
156 // ReadPixels with BGRA even if the extension is not present
157 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
158 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
159 type == GL_UNSIGNED_BYTE);
160
161 case GL_SIGNED_NORMALIZED:
162 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
163
164 case GL_INT:
165 return (format == GL_RGBA_INTEGER && type == GL_INT);
166
167 case GL_UNSIGNED_INT:
168 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
169
170 case GL_FLOAT:
171 return (format == GL_RGBA && type == GL_FLOAT);
172
173 default:
174 UNREACHABLE();
175 return false;
176 }
177}
178
Geoff Langf41a7152016-09-19 15:11:17 -0400179bool ValidCap(const Context *context, GLenum cap, bool queryOnly)
Geoff Lang0550d032014-01-30 11:29:07 -0500180{
181 switch (cap)
182 {
Geoff Langf41a7152016-09-19 15:11:17 -0400183 // EXT_multisample_compatibility
184 case GL_MULTISAMPLE_EXT:
185 case GL_SAMPLE_ALPHA_TO_ONE_EXT:
186 return context->getExtensions().multisampleCompatibility;
Sami Väisänen74c23472016-05-09 17:30:30 +0300187
Geoff Langf41a7152016-09-19 15:11:17 -0400188 case GL_CULL_FACE:
189 case GL_POLYGON_OFFSET_FILL:
190 case GL_SAMPLE_ALPHA_TO_COVERAGE:
191 case GL_SAMPLE_COVERAGE:
192 case GL_SCISSOR_TEST:
193 case GL_STENCIL_TEST:
194 case GL_DEPTH_TEST:
195 case GL_BLEND:
196 case GL_DITHER:
197 return true;
Geoff Lang70d0f492015-12-10 17:45:46 -0500198
Geoff Langf41a7152016-09-19 15:11:17 -0400199 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
200 case GL_RASTERIZER_DISCARD:
201 return (context->getClientMajorVersion() >= 3);
Geoff Lang70d0f492015-12-10 17:45:46 -0500202
Geoff Langf41a7152016-09-19 15:11:17 -0400203 case GL_DEBUG_OUTPUT_SYNCHRONOUS:
204 case GL_DEBUG_OUTPUT:
205 return context->getExtensions().debug;
Geoff Lang70d0f492015-12-10 17:45:46 -0500206
Geoff Langf41a7152016-09-19 15:11:17 -0400207 case GL_BIND_GENERATES_RESOURCE_CHROMIUM:
208 return queryOnly && context->getExtensions().bindGeneratesResource;
209
Geoff Langfeb8c682017-02-13 16:07:35 -0500210 case GL_CLIENT_ARRAYS_ANGLE:
211 return queryOnly && context->getExtensions().clientArrays;
212
Geoff Lang1d2c41d2016-10-19 16:14:46 -0700213 case GL_FRAMEBUFFER_SRGB_EXT:
214 return context->getExtensions().sRGBWriteControl;
215
Geoff Lang3b573612016-10-31 14:08:10 -0400216 case GL_SAMPLE_MASK:
Geoff Lang3b573612016-10-31 14:08:10 -0400217 return context->getClientVersion() >= Version(3, 1);
218
Jamie Madille08a1d32017-03-07 17:24:06 -0500219 case GL_CONTEXT_ROBUST_RESOURCE_INITIALIZATION_ANGLE:
220 return queryOnly && context->getExtensions().robustResourceInitialization;
221
Geoff Langf41a7152016-09-19 15:11:17 -0400222 default:
223 return false;
Geoff Lang0550d032014-01-30 11:29:07 -0500224 }
225}
226
Geoff Lang62fce5b2016-09-30 10:46:35 -0400227bool ValidateReadPixelsBase(ValidationContext *context,
228 GLint x,
229 GLint y,
230 GLsizei width,
231 GLsizei height,
232 GLenum format,
233 GLenum type,
234 GLsizei bufSize,
235 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -0400236 GLsizei *columns,
237 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -0400238 GLvoid *pixels)
239{
240 if (length != nullptr)
241 {
242 *length = 0;
243 }
Geoff Lange93daba2017-03-30 13:54:40 -0400244 if (rows != nullptr)
245 {
246 *rows = 0;
247 }
248 if (columns != nullptr)
249 {
250 *columns = 0;
251 }
Geoff Lang62fce5b2016-09-30 10:46:35 -0400252
253 if (width < 0 || height < 0)
254 {
255 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
256 return false;
257 }
258
259 auto readFramebuffer = context->getGLState().getReadFramebuffer();
260
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400261 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400262 {
263 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
264 return false;
265 }
266
Jamie Madilldd43e6c2017-03-24 14:18:49 -0400267 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400268 {
269 context->handleError(Error(GL_INVALID_OPERATION));
270 return false;
271 }
272
273 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
274 ASSERT(framebuffer);
275
276 if (framebuffer->getReadBufferState() == GL_NONE)
277 {
278 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
279 return false;
280 }
281
282 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
Corentin Wallez3c90ed62016-12-16 16:19:28 -0500283 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
284 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
285 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
286 // situation is an application error that would lead to a crash in ANGLE.
287 if (readBuffer == nullptr)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400288 {
Corentin Wallez3c90ed62016-12-16 16:19:28 -0500289 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
Geoff Lang62fce5b2016-09-30 10:46:35 -0400290 return false;
291 }
292
293 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
294 GLenum currentType = framebuffer->getImplementationColorReadType();
Geoff Langca271392017-04-05 12:30:00 -0400295 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
Geoff Lang62fce5b2016-09-30 10:46:35 -0400296
Geoff Lang62fce5b2016-09-30 10:46:35 -0400297 bool validFormatTypeCombination =
Geoff Langca271392017-04-05 12:30:00 -0400298 ValidReadPixelsFormatType(context, currentComponentType, format, type);
Geoff Lang62fce5b2016-09-30 10:46:35 -0400299
300 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
301 {
302 context->handleError(Error(GL_INVALID_OPERATION));
303 return false;
304 }
305
306 // Check for pixel pack buffer related API errors
307 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
308 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
309 {
310 // ...the buffer object's data store is currently mapped.
311 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
312 return false;
313 }
314
315 // .. the data would be packed to the buffer object such that the memory writes required
316 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -0400317 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
Geoff Lang62fce5b2016-09-30 10:46:35 -0400318 const gl::Extents size(width, height, 1);
319 const auto &pack = context->getGLState().getPackState();
320
321 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
322 if (endByteOrErr.isError())
323 {
324 context->handleError(endByteOrErr.getError());
325 return false;
326 }
327
328 size_t endByte = endByteOrErr.getResult();
329 if (bufSize >= 0)
330 {
Geoff Lange93daba2017-03-30 13:54:40 -0400331 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400332 {
333 context->handleError(
334 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
335 return false;
336 }
337 }
338
339 if (pixelPackBuffer != nullptr)
340 {
341 CheckedNumeric<size_t> checkedEndByte(endByte);
342 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
343 checkedEndByte += checkedOffset;
344
345 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
346 {
347 // Overflow past the end of the buffer
348 context->handleError(
349 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
350 return false;
351 }
352 }
353
Geoff Lange93daba2017-03-30 13:54:40 -0400354 if (pixelPackBuffer == nullptr && length != nullptr)
Geoff Lang62fce5b2016-09-30 10:46:35 -0400355 {
356 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
357 {
358 context->handleError(
359 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
360 return false;
361 }
362
363 *length = static_cast<GLsizei>(endByte);
364 }
365
Geoff Lange93daba2017-03-30 13:54:40 -0400366 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
367 angle::CheckedNumeric<int> clippedExtent(length);
368 if (start < 0)
369 {
370 // "subtract" the area that is less than 0
371 clippedExtent += start;
372 }
373
374 const int readExtent = start + length;
375 if (readExtent > bufferSize)
376 {
377 // Subtract the region to the right of the read buffer
378 clippedExtent -= (readExtent - bufferSize);
379 }
380
381 if (!clippedExtent.IsValid())
382 {
383 return 0;
384 }
385
386 return std::max(clippedExtent.ValueOrDie(), 0);
387 };
388
389 if (columns != nullptr)
390 {
391 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
392 }
393
394 if (rows != nullptr)
395 {
396 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
397 }
398
Geoff Lang62fce5b2016-09-30 10:46:35 -0400399 return true;
400}
401
Geoff Lang740d9022016-10-07 11:20:52 -0400402bool ValidateGetRenderbufferParameterivBase(Context *context,
403 GLenum target,
404 GLenum pname,
405 GLsizei *length)
406{
407 if (length)
408 {
409 *length = 0;
410 }
411
412 if (target != GL_RENDERBUFFER)
413 {
414 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
415 return false;
416 }
417
418 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
419 if (renderbuffer == nullptr)
420 {
421 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
422 return false;
423 }
424
425 switch (pname)
426 {
427 case GL_RENDERBUFFER_WIDTH:
428 case GL_RENDERBUFFER_HEIGHT:
429 case GL_RENDERBUFFER_INTERNAL_FORMAT:
430 case GL_RENDERBUFFER_RED_SIZE:
431 case GL_RENDERBUFFER_GREEN_SIZE:
432 case GL_RENDERBUFFER_BLUE_SIZE:
433 case GL_RENDERBUFFER_ALPHA_SIZE:
434 case GL_RENDERBUFFER_DEPTH_SIZE:
435 case GL_RENDERBUFFER_STENCIL_SIZE:
436 break;
437
438 case GL_RENDERBUFFER_SAMPLES_ANGLE:
439 if (!context->getExtensions().framebufferMultisample)
440 {
441 context->handleError(
442 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
443 return false;
444 }
445 break;
446
447 default:
448 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
449 return false;
450 }
451
452 if (length)
453 {
454 *length = 1;
455 }
456 return true;
457}
458
Geoff Langd7d0ed32016-10-07 11:33:51 -0400459bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
460{
461 if (length)
462 {
463 *length = 0;
464 }
465
466 if (GetValidShader(context, shader) == nullptr)
467 {
468 return false;
469 }
470
471 switch (pname)
472 {
473 case GL_SHADER_TYPE:
474 case GL_DELETE_STATUS:
475 case GL_COMPILE_STATUS:
476 case GL_INFO_LOG_LENGTH:
477 case GL_SHADER_SOURCE_LENGTH:
478 break;
479
480 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
481 if (!context->getExtensions().translatedShaderSource)
482 {
483 context->handleError(
484 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
485 return false;
486 }
487 break;
488
489 default:
490 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
491 return false;
492 }
493
494 if (length)
495 {
496 *length = 1;
497 }
498 return true;
499}
500
Geoff Langc1984ed2016-10-07 12:41:00 -0400501bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
502{
503 if (length)
504 {
505 *length = 0;
506 }
507
508 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
509 {
510 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
511 return false;
512 }
513
514 if (context->getTargetTexture(target) == nullptr)
515 {
516 // Should only be possible for external textures
517 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
518 return false;
519 }
520
521 switch (pname)
522 {
523 case GL_TEXTURE_MAG_FILTER:
524 case GL_TEXTURE_MIN_FILTER:
525 case GL_TEXTURE_WRAP_S:
526 case GL_TEXTURE_WRAP_T:
527 break;
528
529 case GL_TEXTURE_USAGE_ANGLE:
530 if (!context->getExtensions().textureUsage)
531 {
532 context->handleError(
533 Error(GL_INVALID_ENUM, "GL_ANGLE_texture_usage is not enabled."));
534 return false;
535 }
536 break;
537
538 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
539 if (!context->getExtensions().textureFilterAnisotropic)
540 {
541 context->handleError(
542 Error(GL_INVALID_ENUM, "GL_EXT_texture_filter_anisotropic is not enabled."));
543 return false;
544 }
545 break;
546
547 case GL_TEXTURE_IMMUTABLE_FORMAT:
548 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
549 {
550 context->handleError(
551 Error(GL_INVALID_ENUM, "GL_EXT_texture_storage is not enabled."));
552 return false;
553 }
554 break;
555
556 case GL_TEXTURE_WRAP_R:
557 case GL_TEXTURE_IMMUTABLE_LEVELS:
558 case GL_TEXTURE_SWIZZLE_R:
559 case GL_TEXTURE_SWIZZLE_G:
560 case GL_TEXTURE_SWIZZLE_B:
561 case GL_TEXTURE_SWIZZLE_A:
562 case GL_TEXTURE_BASE_LEVEL:
563 case GL_TEXTURE_MAX_LEVEL:
564 case GL_TEXTURE_MIN_LOD:
565 case GL_TEXTURE_MAX_LOD:
566 case GL_TEXTURE_COMPARE_MODE:
567 case GL_TEXTURE_COMPARE_FUNC:
568 if (context->getClientMajorVersion() < 3)
569 {
570 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
571 return false;
572 }
573 break;
574
Geoff Lang81c6b572016-10-19 14:07:52 -0700575 case GL_TEXTURE_SRGB_DECODE_EXT:
576 if (!context->getExtensions().textureSRGBDecode)
577 {
578 context->handleError(
579 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
580 return false;
581 }
582 break;
583
Geoff Langc1984ed2016-10-07 12:41:00 -0400584 default:
585 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
586 return false;
587 }
588
589 if (length)
590 {
591 *length = 1;
592 }
593 return true;
594}
595
596template <typename ParamType>
597bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isExternalTextureTarget)
598{
599 switch (ConvertToGLenum(params[0]))
600 {
601 case GL_CLAMP_TO_EDGE:
602 break;
603
604 case GL_REPEAT:
605 case GL_MIRRORED_REPEAT:
606 if (isExternalTextureTarget)
607 {
608 // OES_EGL_image_external specifies this error.
609 context->handleError(Error(
610 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
611 return false;
612 }
613 break;
614
615 default:
616 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
617 return false;
618 }
619
620 return true;
621}
622
623template <typename ParamType>
624bool ValidateTextureMinFilterValue(Context *context,
625 ParamType *params,
626 bool isExternalTextureTarget)
627{
628 switch (ConvertToGLenum(params[0]))
629 {
630 case GL_NEAREST:
631 case GL_LINEAR:
632 break;
633
634 case GL_NEAREST_MIPMAP_NEAREST:
635 case GL_LINEAR_MIPMAP_NEAREST:
636 case GL_NEAREST_MIPMAP_LINEAR:
637 case GL_LINEAR_MIPMAP_LINEAR:
638 if (isExternalTextureTarget)
639 {
640 // OES_EGL_image_external specifies this error.
641 context->handleError(
642 Error(GL_INVALID_ENUM,
643 "external textures only support NEAREST and LINEAR filtering"));
644 return false;
645 }
646 break;
647
648 default:
649 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
650 return false;
651 }
652
653 return true;
654}
655
656template <typename ParamType>
657bool ValidateTextureMagFilterValue(Context *context, ParamType *params)
658{
659 switch (ConvertToGLenum(params[0]))
660 {
661 case GL_NEAREST:
662 case GL_LINEAR:
663 break;
664
665 default:
666 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
667 return false;
668 }
669
670 return true;
671}
672
673template <typename ParamType>
674bool ValidateTextureCompareModeValue(Context *context, ParamType *params)
675{
676 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
677 switch (ConvertToGLenum(params[0]))
678 {
679 case GL_NONE:
680 case GL_COMPARE_REF_TO_TEXTURE:
681 break;
682
683 default:
684 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
685 return false;
686 }
687
688 return true;
689}
690
691template <typename ParamType>
692bool ValidateTextureCompareFuncValue(Context *context, ParamType *params)
693{
694 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
695 switch (ConvertToGLenum(params[0]))
696 {
697 case GL_LEQUAL:
698 case GL_GEQUAL:
699 case GL_LESS:
700 case GL_GREATER:
701 case GL_EQUAL:
702 case GL_NOTEQUAL:
703 case GL_ALWAYS:
704 case GL_NEVER:
705 break;
706
707 default:
708 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
709 return false;
710 }
711
712 return true;
713}
714
715template <typename ParamType>
Geoff Lang81c6b572016-10-19 14:07:52 -0700716bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params)
717{
718 if (!context->getExtensions().textureSRGBDecode)
719 {
720 context->handleError(Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
721 return false;
722 }
723
724 switch (ConvertToGLenum(params[0]))
725 {
726 case GL_DECODE_EXT:
727 case GL_SKIP_DECODE_EXT:
728 break;
729
730 default:
731 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
732 return false;
733 }
734
735 return true;
736}
737
738template <typename ParamType>
Geoff Langc1984ed2016-10-07 12:41:00 -0400739bool ValidateTexParameterBase(Context *context,
740 GLenum target,
741 GLenum pname,
742 GLsizei bufSize,
743 ParamType *params)
744{
745 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
746 {
747 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
748 return false;
749 }
750
751 if (context->getTargetTexture(target) == nullptr)
752 {
753 // Should only be possible for external textures
754 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
755 return false;
756 }
757
758 const GLsizei minBufSize = 1;
759 if (bufSize >= 0 && bufSize < minBufSize)
760 {
761 context->handleError(
762 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
763 return false;
764 }
765
766 switch (pname)
767 {
768 case GL_TEXTURE_WRAP_R:
769 case GL_TEXTURE_SWIZZLE_R:
770 case GL_TEXTURE_SWIZZLE_G:
771 case GL_TEXTURE_SWIZZLE_B:
772 case GL_TEXTURE_SWIZZLE_A:
773 case GL_TEXTURE_BASE_LEVEL:
774 case GL_TEXTURE_MAX_LEVEL:
775 case GL_TEXTURE_COMPARE_MODE:
776 case GL_TEXTURE_COMPARE_FUNC:
777 case GL_TEXTURE_MIN_LOD:
778 case GL_TEXTURE_MAX_LOD:
779 if (context->getClientMajorVersion() < 3)
780 {
781 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
782 return false;
783 }
784 if (target == GL_TEXTURE_EXTERNAL_OES &&
785 !context->getExtensions().eglImageExternalEssl3)
786 {
787 context->handleError(Error(GL_INVALID_ENUM,
788 "ES3 texture parameters are not available without "
789 "GL_OES_EGL_image_external_essl3."));
790 return false;
791 }
792 break;
793
794 default:
795 break;
796 }
797
798 switch (pname)
799 {
800 case GL_TEXTURE_WRAP_S:
801 case GL_TEXTURE_WRAP_T:
802 case GL_TEXTURE_WRAP_R:
803 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
804 {
805 return false;
806 }
807 break;
808
809 case GL_TEXTURE_MIN_FILTER:
810 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
811 {
812 return false;
813 }
814 break;
815
816 case GL_TEXTURE_MAG_FILTER:
817 if (!ValidateTextureMagFilterValue(context, params))
818 {
819 return false;
820 }
821 break;
822
823 case GL_TEXTURE_USAGE_ANGLE:
824 switch (ConvertToGLenum(params[0]))
825 {
826 case GL_NONE:
827 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
828 break;
829
830 default:
831 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
832 return false;
833 }
834 break;
835
836 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
837 if (!context->getExtensions().textureFilterAnisotropic)
838 {
839 context->handleError(
840 Error(GL_INVALID_ENUM, "GL_EXT_texture_anisotropic is not enabled."));
841 return false;
842 }
843
844 // we assume the parameter passed to this validation method is truncated, not rounded
845 if (params[0] < 1)
846 {
847 context->handleError(Error(GL_INVALID_VALUE, "Max anisotropy must be at least 1."));
848 return false;
849 }
850 break;
851
852 case GL_TEXTURE_MIN_LOD:
853 case GL_TEXTURE_MAX_LOD:
854 // any value is permissible
855 break;
856
857 case GL_TEXTURE_COMPARE_MODE:
858 if (!ValidateTextureCompareModeValue(context, params))
859 {
860 return false;
861 }
862 break;
863
864 case GL_TEXTURE_COMPARE_FUNC:
865 if (!ValidateTextureCompareFuncValue(context, params))
866 {
867 return false;
868 }
869 break;
870
871 case GL_TEXTURE_SWIZZLE_R:
872 case GL_TEXTURE_SWIZZLE_G:
873 case GL_TEXTURE_SWIZZLE_B:
874 case GL_TEXTURE_SWIZZLE_A:
875 switch (ConvertToGLenum(params[0]))
876 {
877 case GL_RED:
878 case GL_GREEN:
879 case GL_BLUE:
880 case GL_ALPHA:
881 case GL_ZERO:
882 case GL_ONE:
883 break;
884
885 default:
886 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
887 return false;
888 }
889 break;
890
891 case GL_TEXTURE_BASE_LEVEL:
892 if (params[0] < 0)
893 {
894 context->handleError(Error(GL_INVALID_VALUE, "Base level must be at least 0."));
895 return false;
896 }
897 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
898 {
899 context->handleError(
900 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
901 return false;
902 }
903 break;
904
905 case GL_TEXTURE_MAX_LEVEL:
906 if (params[0] < 0)
907 {
908 context->handleError(Error(GL_INVALID_VALUE, "Max level must be at least 0."));
909 return false;
910 }
911 break;
912
Geoff Lang3b573612016-10-31 14:08:10 -0400913 case GL_DEPTH_STENCIL_TEXTURE_MODE:
914 if (context->getClientVersion() < Version(3, 1))
915 {
916 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.1."));
917 return false;
918 }
Geoff Lang9f090372016-12-02 10:20:43 -0500919 switch (ConvertToGLenum(params[0]))
920 {
921 case GL_DEPTH_COMPONENT:
922 case GL_STENCIL_INDEX:
923 break;
924
925 default:
926 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
927 return false;
928 }
Geoff Lang3b573612016-10-31 14:08:10 -0400929 break;
930
Geoff Lang81c6b572016-10-19 14:07:52 -0700931 case GL_TEXTURE_SRGB_DECODE_EXT:
932 if (!ValidateTextureSRGBDecodeValue(context, params))
933 {
934 return false;
935 }
936 break;
937
Geoff Langc1984ed2016-10-07 12:41:00 -0400938 default:
939 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
940 return false;
941 }
942
943 return true;
944}
945
946template <typename ParamType>
947bool ValidateSamplerParameterBase(Context *context,
948 GLuint sampler,
949 GLenum pname,
950 GLsizei bufSize,
951 ParamType *params)
952{
953 if (context->getClientMajorVersion() < 3)
954 {
955 context->handleError(
956 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
957 return false;
958 }
959
960 if (!context->isSampler(sampler))
961 {
962 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
963 return false;
964 }
965
966 const GLsizei minBufSize = 1;
967 if (bufSize >= 0 && bufSize < minBufSize)
968 {
969 context->handleError(
970 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
971 return false;
972 }
973
974 switch (pname)
975 {
976 case GL_TEXTURE_WRAP_S:
977 case GL_TEXTURE_WRAP_T:
978 case GL_TEXTURE_WRAP_R:
979 if (!ValidateTextureWrapModeValue(context, params, false))
980 {
981 return false;
982 }
983 break;
984
985 case GL_TEXTURE_MIN_FILTER:
986 if (!ValidateTextureMinFilterValue(context, params, false))
987 {
988 return false;
989 }
990 break;
991
992 case GL_TEXTURE_MAG_FILTER:
993 if (!ValidateTextureMagFilterValue(context, params))
994 {
995 return false;
996 }
997 break;
998
999 case GL_TEXTURE_MIN_LOD:
1000 case GL_TEXTURE_MAX_LOD:
1001 // any value is permissible
1002 break;
1003
1004 case GL_TEXTURE_COMPARE_MODE:
1005 if (!ValidateTextureCompareModeValue(context, params))
1006 {
1007 return false;
1008 }
1009 break;
1010
1011 case GL_TEXTURE_COMPARE_FUNC:
1012 if (!ValidateTextureCompareFuncValue(context, params))
1013 {
1014 return false;
1015 }
1016 break;
1017
Geoff Lang81c6b572016-10-19 14:07:52 -07001018 case GL_TEXTURE_SRGB_DECODE_EXT:
1019 if (!ValidateTextureSRGBDecodeValue(context, params))
1020 {
1021 return false;
1022 }
1023 break;
1024
Geoff Langc1984ed2016-10-07 12:41:00 -04001025 default:
1026 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1027 return false;
1028 }
1029
1030 return true;
1031}
1032
1033bool ValidateGetSamplerParameterBase(Context *context,
1034 GLuint sampler,
1035 GLenum pname,
1036 GLsizei *length)
1037{
1038 if (length)
1039 {
1040 *length = 0;
1041 }
1042
1043 if (context->getClientMajorVersion() < 3)
1044 {
1045 context->handleError(
1046 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1047 return false;
1048 }
1049
1050 if (!context->isSampler(sampler))
1051 {
1052 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
1053 return false;
1054 }
1055
1056 switch (pname)
1057 {
1058 case GL_TEXTURE_WRAP_S:
1059 case GL_TEXTURE_WRAP_T:
1060 case GL_TEXTURE_WRAP_R:
1061 case GL_TEXTURE_MIN_FILTER:
1062 case GL_TEXTURE_MAG_FILTER:
1063 case GL_TEXTURE_MIN_LOD:
1064 case GL_TEXTURE_MAX_LOD:
1065 case GL_TEXTURE_COMPARE_MODE:
1066 case GL_TEXTURE_COMPARE_FUNC:
1067 break;
1068
Geoff Lang81c6b572016-10-19 14:07:52 -07001069 case GL_TEXTURE_SRGB_DECODE_EXT:
1070 if (!context->getExtensions().textureSRGBDecode)
1071 {
1072 context->handleError(
1073 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
1074 return false;
1075 }
1076 break;
1077
Geoff Langc1984ed2016-10-07 12:41:00 -04001078 default:
1079 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1080 return false;
1081 }
1082
1083 if (length)
1084 {
1085 *length = 1;
1086 }
1087 return true;
1088}
1089
Geoff Lang0b031062016-10-13 14:30:04 -04001090bool ValidateGetVertexAttribBase(Context *context,
1091 GLuint index,
1092 GLenum pname,
1093 GLsizei *length,
1094 bool pointer,
1095 bool pureIntegerEntryPoint)
1096{
1097 if (length)
1098 {
1099 *length = 0;
1100 }
1101
1102 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
1103 {
1104 context->handleError(
1105 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1106 return false;
1107 }
1108
1109 if (index >= context->getCaps().maxVertexAttributes)
1110 {
1111 context->handleError(Error(
1112 GL_INVALID_VALUE, "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES."));
1113 return false;
1114 }
1115
1116 if (pointer)
1117 {
1118 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
1119 {
1120 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1121 return false;
1122 }
1123 }
1124 else
1125 {
1126 switch (pname)
1127 {
1128 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1129 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1130 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1131 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1132 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1133 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1134 case GL_CURRENT_VERTEX_ATTRIB:
1135 break;
1136
1137 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1138 static_assert(
1139 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
1140 "ANGLE extension enums not equal to GL enums.");
1141 if (context->getClientMajorVersion() < 3 &&
1142 !context->getExtensions().instancedArrays)
1143 {
1144 context->handleError(Error(GL_INVALID_ENUM,
1145 "GL_VERTEX_ATTRIB_ARRAY_DIVISOR requires OpenGL ES "
1146 "3.0 or GL_ANGLE_instanced_arrays."));
1147 return false;
1148 }
1149 break;
1150
1151 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
1152 if (context->getClientMajorVersion() < 3)
1153 {
Shao80957d92017-02-20 21:25:59 +08001154 context->handleError(Error(
1155 GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
1156 return false;
1157 }
1158 break;
1159
1160 case GL_VERTEX_ATTRIB_BINDING:
1161 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
1162 if (context->getClientVersion() < ES_3_1)
1163 {
1164 context->handleError(
1165 Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
Geoff Lang0b031062016-10-13 14:30:04 -04001166 return false;
1167 }
1168 break;
1169
1170 default:
1171 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1172 return false;
1173 }
1174 }
1175
1176 if (length)
1177 {
1178 if (pname == GL_CURRENT_VERTEX_ATTRIB)
1179 {
1180 *length = 4;
1181 }
1182 else
1183 {
1184 *length = 1;
1185 }
1186 }
1187
1188 return true;
1189}
1190
Geoff Lang6899b872016-10-14 11:30:13 -04001191bool ValidateGetActiveUniformBlockivBase(Context *context,
1192 GLuint program,
1193 GLuint uniformBlockIndex,
1194 GLenum pname,
1195 GLsizei *length)
1196{
1197 if (length)
1198 {
1199 *length = 0;
1200 }
1201
1202 if (context->getClientMajorVersion() < 3)
1203 {
1204 context->handleError(
1205 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1206 return false;
1207 }
1208
1209 Program *programObject = GetValidProgram(context, program);
1210 if (!programObject)
1211 {
1212 return false;
1213 }
1214
1215 if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
1216 {
1217 context->handleError(
1218 Error(GL_INVALID_VALUE, "uniformBlockIndex exceeds active uniform block count."));
1219 return false;
1220 }
1221
1222 switch (pname)
1223 {
1224 case GL_UNIFORM_BLOCK_BINDING:
1225 case GL_UNIFORM_BLOCK_DATA_SIZE:
1226 case GL_UNIFORM_BLOCK_NAME_LENGTH:
1227 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
1228 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
1229 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
1230 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
1231 break;
1232
1233 default:
1234 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1235 return false;
1236 }
1237
1238 if (length)
1239 {
1240 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
1241 {
1242 const UniformBlock &uniformBlock =
1243 programObject->getUniformBlockByIndex(uniformBlockIndex);
1244 *length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
1245 }
1246 else
1247 {
1248 *length = 1;
1249 }
1250 }
1251
1252 return true;
1253}
1254
Geoff Langebebe1c2016-10-14 12:01:31 -04001255bool ValidateGetBufferParameterBase(ValidationContext *context,
1256 GLenum target,
1257 GLenum pname,
1258 bool pointerVersion,
1259 GLsizei *numParams)
1260{
1261 if (numParams)
1262 {
1263 *numParams = 0;
1264 }
1265
1266 if (!ValidBufferTarget(context, target))
1267 {
1268 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
1269 return false;
1270 }
1271
1272 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
1273 if (!buffer)
1274 {
1275 // A null buffer means that "0" is bound to the requested buffer target
1276 context->handleError(Error(GL_INVALID_OPERATION, "No buffer bound."));
1277 return false;
1278 }
1279
1280 const Extensions &extensions = context->getExtensions();
1281
1282 switch (pname)
1283 {
1284 case GL_BUFFER_USAGE:
1285 case GL_BUFFER_SIZE:
1286 break;
1287
1288 case GL_BUFFER_ACCESS_OES:
1289 if (!extensions.mapBuffer)
1290 {
1291 context->handleError(
Jamie Madillcc6ac252017-01-25 12:57:21 -08001292 Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
Geoff Langebebe1c2016-10-14 12:01:31 -04001293 return false;
1294 }
1295 break;
1296
1297 case GL_BUFFER_MAPPED:
1298 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
1299 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
1300 !extensions.mapBufferRange)
1301 {
1302 context->handleError(Error(
1303 GL_INVALID_ENUM,
Jamie Madillcc6ac252017-01-25 12:57:21 -08001304 "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
Geoff Langebebe1c2016-10-14 12:01:31 -04001305 return false;
1306 }
1307 break;
1308
1309 case GL_BUFFER_MAP_POINTER:
1310 if (!pointerVersion)
1311 {
1312 context->handleError(
1313 Error(GL_INVALID_ENUM,
1314 "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."));
1315 return false;
1316 }
1317 break;
1318
1319 case GL_BUFFER_ACCESS_FLAGS:
1320 case GL_BUFFER_MAP_OFFSET:
1321 case GL_BUFFER_MAP_LENGTH:
1322 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
1323 {
1324 context->handleError(Error(
1325 GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."));
1326 return false;
1327 }
1328 break;
1329
1330 default:
1331 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1332 return false;
1333 }
1334
1335 // All buffer parameter queries return one value.
1336 if (numParams)
1337 {
1338 *numParams = 1;
1339 }
1340
1341 return true;
1342}
1343
Geoff Lang0a9661f2016-10-20 10:59:20 -07001344bool ValidateGetInternalFormativBase(Context *context,
1345 GLenum target,
1346 GLenum internalformat,
1347 GLenum pname,
1348 GLsizei bufSize,
1349 GLsizei *numParams)
1350{
1351 if (numParams)
1352 {
1353 *numParams = 0;
1354 }
1355
1356 if (context->getClientMajorVersion() < 3)
1357 {
1358 context->handleError(
1359 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
1360 return false;
1361 }
1362
1363 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
1364 if (!formatCaps.renderable)
1365 {
1366 context->handleError(Error(GL_INVALID_ENUM, "Internal format is not renderable."));
1367 return false;
1368 }
1369
1370 switch (target)
1371 {
1372 case GL_RENDERBUFFER:
1373 break;
1374
JiangYizhoubddc46b2016-12-09 09:50:51 +08001375 case GL_TEXTURE_2D_MULTISAMPLE:
1376 if (context->getClientVersion() < ES_3_1)
1377 {
1378 context->handleError(
1379 Error(GL_INVALID_OPERATION, "Texture target requires at least OpenGL ES 3.1."));
1380 return false;
1381 }
1382 break;
1383
Geoff Lang0a9661f2016-10-20 10:59:20 -07001384 default:
1385 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
1386 return false;
1387 }
1388
1389 if (bufSize < 0)
1390 {
1391 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
1392 return false;
1393 }
1394
1395 GLsizei maxWriteParams = 0;
1396 switch (pname)
1397 {
1398 case GL_NUM_SAMPLE_COUNTS:
1399 maxWriteParams = 1;
1400 break;
1401
1402 case GL_SAMPLES:
1403 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
1404 break;
1405
1406 default:
1407 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
1408 return false;
1409 }
1410
1411 if (numParams)
1412 {
1413 // glGetInternalFormativ will not overflow bufSize
1414 *numParams = std::min(bufSize, maxWriteParams);
1415 }
1416
1417 return true;
1418}
1419
Jamie Madillc1d770e2017-04-13 17:31:24 -04001420bool ValidateUniformCommonBase(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001421 gl::Program *program,
1422 GLint location,
1423 GLsizei count,
1424 const LinkedUniform **uniformOut)
1425{
1426 // TODO(Jiajia): Add image uniform check in future.
1427 if (count < 0)
1428 {
1429 context->handleError(Error(GL_INVALID_VALUE));
1430 return false;
1431 }
1432
1433 if (!program || !program->isLinked())
1434 {
1435 context->handleError(Error(GL_INVALID_OPERATION));
1436 return false;
1437 }
1438
1439 if (location == -1)
1440 {
1441 // Silently ignore the uniform command
1442 return false;
1443 }
1444
1445 const auto &uniformLocations = program->getUniformLocations();
1446 size_t castedLocation = static_cast<size_t>(location);
1447 if (castedLocation >= uniformLocations.size())
1448 {
1449 context->handleError(Error(GL_INVALID_OPERATION, "Invalid uniform location"));
1450 return false;
1451 }
1452
1453 const auto &uniformLocation = uniformLocations[castedLocation];
1454 if (uniformLocation.ignored)
1455 {
1456 // Silently ignore the uniform command
1457 return false;
1458 }
1459
1460 if (!uniformLocation.used)
1461 {
1462 context->handleError(Error(GL_INVALID_OPERATION));
1463 return false;
1464 }
1465
1466 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
1467
1468 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1469 if (!uniform.isArray() && count > 1)
1470 {
1471 context->handleError(Error(GL_INVALID_OPERATION));
1472 return false;
1473 }
1474
1475 *uniformOut = &uniform;
1476 return true;
1477}
1478
Frank Henigman999b0fd2017-02-02 21:45:55 -05001479bool ValidateUniform1ivValue(ValidationContext *context,
Frank Henigmana98a6472017-02-02 21:38:32 -05001480 GLenum uniformType,
1481 GLsizei count,
1482 const GLint *value)
1483{
1484 // Value type is GL_INT, because we only get here from glUniform1i{v}.
1485 // It is compatible with INT or BOOL.
1486 // Do these cheap tests first, for a little extra speed.
1487 if (GL_INT == uniformType || GL_BOOL == uniformType)
1488 {
1489 return true;
1490 }
1491
1492 if (IsSamplerType(uniformType))
1493 {
Frank Henigman999b0fd2017-02-02 21:45:55 -05001494 // Check that the values are in range.
1495 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
1496 for (GLsizei i = 0; i < count; ++i)
1497 {
1498 if (value[i] < 0 || value[i] >= max)
1499 {
1500 context->handleError(Error(GL_INVALID_VALUE, "sampler uniform value out of range"));
1501 return false;
1502 }
1503 }
Frank Henigmana98a6472017-02-02 21:38:32 -05001504 return true;
1505 }
1506
1507 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1508 return false;
1509}
1510
Jamie Madillc1d770e2017-04-13 17:31:24 -04001511bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001512{
1513 // Check that the value type is compatible with uniform type.
Frank Henigmana98a6472017-02-02 21:38:32 -05001514 // Do the cheaper test first, for a little extra speed.
1515 if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001516 {
1517 return true;
1518 }
1519
1520 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1521 return false;
1522}
1523
Jamie Madillc1d770e2017-04-13 17:31:24 -04001524bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05001525{
1526 // Check that the value type is compatible with uniform type.
1527 if (valueType == uniformType)
1528 {
1529 return true;
1530 }
1531
1532 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
1533 return false;
1534}
1535
Jamie Madillc1d770e2017-04-13 17:31:24 -04001536bool ValidateES2CopyTexImageParameters(ValidationContext *context,
1537 GLenum target,
1538 GLint level,
1539 GLenum internalformat,
1540 bool isSubImage,
1541 GLint xoffset,
1542 GLint yoffset,
1543 GLint x,
1544 GLint y,
1545 GLsizei width,
1546 GLsizei height,
1547 GLint border)
1548{
1549 if (!ValidTexture2DDestinationTarget(context, target))
1550 {
1551 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
1552 return false;
1553 }
1554
1555 if (!ValidImageSizeParameters(context, target, level, width, height, 1, isSubImage))
1556 {
1557 context->handleError(Error(GL_INVALID_VALUE, "Invalid texture dimensions."));
1558 return false;
1559 }
1560
1561 Format textureFormat = Format::Invalid();
1562 if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
1563 xoffset, yoffset, 0, x, y, width, height, border,
1564 &textureFormat))
1565 {
1566 return false;
1567 }
1568
1569 const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
Geoff Langca271392017-04-05 12:30:00 -04001570 GLenum colorbufferFormat =
1571 framebuffer->getReadColorbuffer()->getFormat().info->sizedInternalFormat;
Jamie Madillc1d770e2017-04-13 17:31:24 -04001572 const auto &formatInfo = *textureFormat.info;
1573
1574 // [OpenGL ES 2.0.24] table 3.9
1575 if (isSubImage)
1576 {
1577 switch (formatInfo.format)
1578 {
1579 case GL_ALPHA:
1580 if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
1581 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES)
1582 {
1583 context->handleError(Error(GL_INVALID_OPERATION));
1584 return false;
1585 }
1586 break;
1587 case GL_LUMINANCE:
1588 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1589 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1590 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1591 colorbufferFormat != GL_RGBA8_OES)
1592 {
1593 context->handleError(Error(GL_INVALID_OPERATION));
1594 return false;
1595 }
1596 break;
1597 case GL_RED_EXT:
1598 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1599 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1600 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1601 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_R32F &&
1602 colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
1603 colorbufferFormat != GL_RGBA32F)
1604 {
1605 context->handleError(Error(GL_INVALID_OPERATION));
1606 return false;
1607 }
1608 break;
1609 case GL_RG_EXT:
1610 if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
1611 colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
1612 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_RGBA8_OES &&
1613 colorbufferFormat != GL_RG32F && colorbufferFormat != GL_RGB32F &&
1614 colorbufferFormat != GL_RGBA32F)
1615 {
1616 context->handleError(Error(GL_INVALID_OPERATION));
1617 return false;
1618 }
1619 break;
1620 case GL_RGB:
1621 if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1622 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1623 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGB32F &&
1624 colorbufferFormat != GL_RGBA32F)
1625 {
1626 context->handleError(Error(GL_INVALID_OPERATION));
1627 return false;
1628 }
1629 break;
1630 case GL_LUMINANCE_ALPHA:
1631 case GL_RGBA:
1632 if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1633 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_RGBA32F)
1634 {
1635 context->handleError(Error(GL_INVALID_OPERATION));
1636 return false;
1637 }
1638 break;
1639 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1640 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1641 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1642 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1643 case GL_ETC1_RGB8_OES:
1644 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
1645 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1646 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1647 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1648 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1649 context->handleError(Error(GL_INVALID_OPERATION));
1650 return false;
1651 case GL_DEPTH_COMPONENT:
1652 case GL_DEPTH_STENCIL_OES:
1653 context->handleError(Error(GL_INVALID_OPERATION));
1654 return false;
1655 default:
1656 context->handleError(Error(GL_INVALID_OPERATION));
1657 return false;
1658 }
1659
1660 if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat)
1661 {
1662 context->handleError(Error(GL_INVALID_OPERATION));
1663 return false;
1664 }
1665 }
1666 else
1667 {
1668 switch (internalformat)
1669 {
1670 case GL_ALPHA:
1671 if (colorbufferFormat != GL_ALPHA8_EXT && colorbufferFormat != GL_RGBA4 &&
1672 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
1673 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX)
1674 {
1675 context->handleError(Error(GL_INVALID_OPERATION));
1676 return false;
1677 }
1678 break;
1679 case GL_LUMINANCE:
1680 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1681 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1682 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1683 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1684 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1685 {
1686 context->handleError(Error(GL_INVALID_OPERATION));
1687 return false;
1688 }
1689 break;
1690 case GL_RED_EXT:
1691 if (colorbufferFormat != GL_R8_EXT && colorbufferFormat != GL_RG8_EXT &&
1692 colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1693 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1694 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1695 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1696 {
1697 context->handleError(Error(GL_INVALID_OPERATION));
1698 return false;
1699 }
1700 break;
1701 case GL_RG_EXT:
1702 if (colorbufferFormat != GL_RG8_EXT && colorbufferFormat != GL_RGB565 &&
1703 colorbufferFormat != GL_RGB8_OES && colorbufferFormat != GL_RGBA4 &&
1704 colorbufferFormat != GL_RGB5_A1 && colorbufferFormat != GL_BGRA8_EXT &&
1705 colorbufferFormat != GL_RGBA8_OES && colorbufferFormat != GL_BGR5_A1_ANGLEX)
1706 {
1707 context->handleError(Error(GL_INVALID_OPERATION));
1708 return false;
1709 }
1710 break;
1711 case GL_RGB:
1712 if (colorbufferFormat != GL_RGB565 && colorbufferFormat != GL_RGB8_OES &&
1713 colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1714 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1715 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1716 {
1717 context->handleError(Error(GL_INVALID_OPERATION));
1718 return false;
1719 }
1720 break;
1721 case GL_LUMINANCE_ALPHA:
1722 case GL_RGBA:
1723 if (colorbufferFormat != GL_RGBA4 && colorbufferFormat != GL_RGB5_A1 &&
1724 colorbufferFormat != GL_BGRA8_EXT && colorbufferFormat != GL_RGBA8_OES &&
1725 colorbufferFormat != GL_BGR5_A1_ANGLEX)
1726 {
1727 context->handleError(Error(GL_INVALID_OPERATION));
1728 return false;
1729 }
1730 break;
1731 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1732 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1733 if (context->getExtensions().textureCompressionDXT1)
1734 {
1735 context->handleError(Error(GL_INVALID_OPERATION));
1736 return false;
1737 }
1738 else
1739 {
1740 context->handleError(Error(GL_INVALID_ENUM));
1741 return false;
1742 }
1743 break;
1744 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1745 if (context->getExtensions().textureCompressionDXT3)
1746 {
1747 context->handleError(Error(GL_INVALID_OPERATION));
1748 return false;
1749 }
1750 else
1751 {
1752 context->handleError(Error(GL_INVALID_ENUM));
1753 return false;
1754 }
1755 break;
1756 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
1757 if (context->getExtensions().textureCompressionDXT5)
1758 {
1759 context->handleError(Error(GL_INVALID_OPERATION));
1760 return false;
1761 }
1762 else
1763 {
1764 context->handleError(Error(GL_INVALID_ENUM));
1765 return false;
1766 }
1767 break;
1768 case GL_ETC1_RGB8_OES:
1769 if (context->getExtensions().compressedETC1RGB8Texture)
1770 {
1771 context->handleError(Error(GL_INVALID_OPERATION));
1772 return false;
1773 }
1774 else
1775 {
1776 context->handleError(Error(GL_INVALID_ENUM));
1777 return false;
1778 }
1779 break;
1780 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
1781 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1782 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1783 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1784 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1785 if (context->getExtensions().lossyETCDecode)
1786 {
1787 context->handleError(Error(GL_INVALID_OPERATION,
1788 "ETC lossy decode formats can't be copied to."));
1789 return false;
1790 }
1791 else
1792 {
1793 context->handleError(Error(
1794 GL_INVALID_ENUM, "ANGLE_lossy_etc_decode extension is not supported."));
1795 return false;
1796 }
1797 break;
1798 case GL_DEPTH_COMPONENT:
1799 case GL_DEPTH_COMPONENT16:
1800 case GL_DEPTH_COMPONENT32_OES:
1801 case GL_DEPTH_STENCIL_OES:
1802 case GL_DEPTH24_STENCIL8_OES:
1803 if (context->getExtensions().depthTextures)
1804 {
1805 context->handleError(Error(GL_INVALID_OPERATION));
1806 return false;
1807 }
1808 else
1809 {
1810 context->handleError(Error(GL_INVALID_ENUM));
1811 return false;
1812 }
1813 default:
1814 context->handleError(Error(GL_INVALID_ENUM));
1815 return false;
1816 }
1817 }
1818
1819 // If width or height is zero, it is a no-op. Return false without setting an error.
1820 return (width > 0 && height > 0);
1821}
1822
Geoff Langf41a7152016-09-19 15:11:17 -04001823} // anonymous namespace
1824
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001825bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -04001826{
Jamie Madilld7460c72014-01-21 16:38:14 -05001827 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -04001828 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001829 case GL_TEXTURE_2D:
1830 case GL_TEXTURE_CUBE_MAP:
1831 return true;
Jamie Madill35d15012013-10-07 10:46:37 -04001832
He Yunchaoced53ae2016-11-29 15:00:51 +08001833 case GL_TEXTURE_3D:
1834 case GL_TEXTURE_2D_ARRAY:
1835 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -05001836
He Yunchaoced53ae2016-11-29 15:00:51 +08001837 case GL_TEXTURE_2D_MULTISAMPLE:
He Yunchaoced53ae2016-11-29 15:00:51 +08001838 return (context->getClientVersion() >= Version(3, 1));
Geoff Lang3b573612016-10-31 14:08:10 -04001839
He Yunchaoced53ae2016-11-29 15:00:51 +08001840 default:
1841 return false;
Jamie Madilld7460c72014-01-21 16:38:14 -05001842 }
Jamie Madill35d15012013-10-07 10:46:37 -04001843}
1844
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001845bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
1846{
1847 switch (target)
1848 {
1849 case GL_TEXTURE_2D:
1850 case GL_TEXTURE_CUBE_MAP:
1851 return true;
1852
1853 default:
1854 return false;
1855 }
1856}
1857
1858bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
1859{
1860 switch (target)
1861 {
1862 case GL_TEXTURE_3D:
1863 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +03001864 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001865
1866 default:
1867 return false;
1868 }
1869}
1870
Ian Ewellbda75592016-04-18 17:25:54 -04001871// Most texture GL calls are not compatible with external textures, so we have a separate validation
1872// function for use in the GL calls that do
1873bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
1874{
1875 return (target == GL_TEXTURE_EXTERNAL_OES) &&
1876 (context->getExtensions().eglImageExternal ||
1877 context->getExtensions().eglStreamConsumerExternal);
1878}
1879
Shannon Woods4dfed832014-03-17 20:03:39 -04001880// This function differs from ValidTextureTarget in that the target must be
1881// usable as the destination of a 2D operation-- so a cube face is valid, but
1882// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -04001883// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -05001884bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -04001885{
1886 switch (target)
1887 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001888 case GL_TEXTURE_2D:
1889 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1890 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1891 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1892 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1893 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1894 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1895 return true;
1896 default:
1897 return false;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05001898 }
1899}
1900
1901bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
1902{
1903 switch (target)
1904 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001905 case GL_TEXTURE_3D:
1906 case GL_TEXTURE_2D_ARRAY:
1907 return true;
1908 default:
1909 return false;
Shannon Woods4dfed832014-03-17 20:03:39 -04001910 }
1911}
1912
He Yunchao11b038b2016-11-22 21:24:04 +08001913bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target)
1914{
1915 switch (target)
1916 {
1917 case GL_TEXTURE_2D:
1918 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1919 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1920 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1921 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1922 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1923 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1924 case GL_TEXTURE_3D:
1925 case GL_TEXTURE_2D_ARRAY:
1926 case GL_TEXTURE_2D_MULTISAMPLE:
1927 return true;
1928 default:
1929 return false;
1930 }
1931}
1932
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001933bool ValidFramebufferTarget(GLenum target)
1934{
He Yunchaoced53ae2016-11-29 15:00:51 +08001935 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
1936 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
Geoff Langd4475812015-03-18 10:53:05 -04001937 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001938
1939 switch (target)
1940 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001941 case GL_FRAMEBUFFER:
1942 return true;
1943 case GL_READ_FRAMEBUFFER:
1944 return true;
1945 case GL_DRAW_FRAMEBUFFER:
1946 return true;
1947 default:
1948 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001949 }
1950}
1951
Jamie Madill29639852016-09-02 15:00:09 -04001952bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -05001953{
1954 switch (target)
1955 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001956 case GL_ARRAY_BUFFER:
1957 case GL_ELEMENT_ARRAY_BUFFER:
1958 return true;
Jamie Madill8c96d582014-03-05 15:01:23 -05001959
He Yunchaoced53ae2016-11-29 15:00:51 +08001960 case GL_PIXEL_PACK_BUFFER:
1961 case GL_PIXEL_UNPACK_BUFFER:
1962 return (context->getExtensions().pixelBufferObject ||
1963 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -04001964
He Yunchaoced53ae2016-11-29 15:00:51 +08001965 case GL_COPY_READ_BUFFER:
1966 case GL_COPY_WRITE_BUFFER:
1967 case GL_TRANSFORM_FEEDBACK_BUFFER:
1968 case GL_UNIFORM_BUFFER:
1969 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -05001970
He Yunchaoced53ae2016-11-29 15:00:51 +08001971 case GL_ATOMIC_COUNTER_BUFFER:
1972 case GL_SHADER_STORAGE_BUFFER:
1973 case GL_DRAW_INDIRECT_BUFFER:
1974 case GL_DISPATCH_INDIRECT_BUFFER:
He Yunchaoced53ae2016-11-29 15:00:51 +08001975 return context->getClientVersion() >= Version(3, 1);
Geoff Lang3b573612016-10-31 14:08:10 -04001976
He Yunchaoced53ae2016-11-29 15:00:51 +08001977 default:
1978 return false;
Jamie Madill8c96d582014-03-05 15:01:23 -05001979 }
1980}
1981
Jamie Madillc29968b2016-01-20 11:17:23 -05001982bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -04001983{
Jamie Madillc29968b2016-01-20 11:17:23 -05001984 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -04001985 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -04001986 switch (target)
1987 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001988 case GL_TEXTURE_2D:
1989 maxDimension = caps.max2DTextureSize;
1990 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08001991 case GL_TEXTURE_CUBE_MAP:
1992 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1993 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1994 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1995 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1996 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1997 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1998 maxDimension = caps.maxCubeMapTextureSize;
1999 break;
2000 case GL_TEXTURE_3D:
2001 maxDimension = caps.max3DTextureSize;
2002 break;
2003 case GL_TEXTURE_2D_ARRAY:
2004 maxDimension = caps.max2DTextureSize;
2005 break;
He Yunchao11b038b2016-11-22 21:24:04 +08002006 case GL_TEXTURE_2D_MULTISAMPLE:
2007 maxDimension = caps.max2DTextureSize;
2008 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08002009 default:
2010 UNREACHABLE();
Geoff Langce635692013-09-24 13:56:32 -04002011 }
2012
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002013 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -04002014}
2015
Geoff Langcc507aa2016-12-12 10:09:52 -05002016bool ValidImageSizeParameters(const ValidationContext *context,
Austin Kinross08528e12015-10-07 16:24:40 -07002017 GLenum target,
2018 GLint level,
2019 GLsizei width,
2020 GLsizei height,
2021 GLsizei depth,
2022 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -04002023{
2024 if (level < 0 || width < 0 || height < 0 || depth < 0)
2025 {
2026 return false;
2027 }
2028
Austin Kinross08528e12015-10-07 16:24:40 -07002029 // TexSubImage parameters can be NPOT without textureNPOT extension,
2030 // as long as the destination texture is POT.
Geoff Langcc507aa2016-12-12 10:09:52 -05002031 bool hasNPOTSupport =
Geoff Lang5f319a42017-01-09 16:49:19 -05002032 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
Geoff Langcc507aa2016-12-12 10:09:52 -05002033 if (!isSubImage && !hasNPOTSupport &&
Jamie Madill4fd75c12014-06-23 10:53:54 -04002034 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -04002035 {
2036 return false;
2037 }
2038
2039 if (!ValidMipLevel(context, target, level))
2040 {
2041 return false;
2042 }
2043
2044 return true;
2045}
2046
Geoff Lang0d8b7242015-09-09 14:56:53 -04002047bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
2048{
2049 // List of compressed format that require that the texture size is smaller than or a multiple of
2050 // the compressed block size.
2051 switch (internalFormat)
2052 {
2053 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2054 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
2055 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
2056 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -08002057 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08002058 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
2059 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
2060 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
2061 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
2062 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
2063 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04002064 return true;
2065
2066 default:
2067 return false;
2068 }
2069}
2070
Jamie Madillc29968b2016-01-20 11:17:23 -05002071bool ValidCompressedImageSize(const ValidationContext *context,
2072 GLenum internalFormat,
Geoff Lang44ff5a72017-02-03 15:15:43 -05002073 GLint xoffset,
2074 GLint yoffset,
Jamie Madillc29968b2016-01-20 11:17:23 -05002075 GLsizei width,
2076 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04002077{
Geoff Langca271392017-04-05 12:30:00 -04002078 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04002079 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04002080 {
2081 return false;
2082 }
2083
Geoff Lang44ff5a72017-02-03 15:15:43 -05002084 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04002085 {
2086 return false;
2087 }
2088
Geoff Lang0d8b7242015-09-09 14:56:53 -04002089 if (CompressedTextureFormatRequiresExactSize(internalFormat))
2090 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05002091 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
2092 yoffset % formatInfo.compressedBlockHeight != 0 ||
2093 (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
Geoff Lang0d8b7242015-09-09 14:56:53 -04002094 width % formatInfo.compressedBlockWidth != 0) ||
2095 (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
2096 height % formatInfo.compressedBlockHeight != 0))
2097 {
2098 return false;
2099 }
2100 }
2101
Geoff Langd4f180b2013-09-24 13:57:44 -04002102 return true;
2103}
2104
Geoff Langff5b2d52016-09-07 11:32:23 -04002105bool ValidImageDataSize(ValidationContext *context,
2106 GLenum textureTarget,
2107 GLsizei width,
2108 GLsizei height,
2109 GLsizei depth,
2110 GLenum internalFormat,
2111 GLenum type,
2112 const GLvoid *pixels,
2113 GLsizei imageSize)
2114{
2115 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
2116 if (pixelUnpackBuffer == nullptr && imageSize < 0)
2117 {
2118 // Checks are not required
2119 return true;
2120 }
2121
2122 // ...the data would be unpacked from the buffer object such that the memory reads required
2123 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -04002124 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
Geoff Langff5b2d52016-09-07 11:32:23 -04002125 const gl::Extents size(width, height, depth);
2126 const auto &unpack = context->getGLState().getUnpackState();
2127
2128 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
2129 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
2130 if (endByteOrErr.isError())
2131 {
2132 context->handleError(endByteOrErr.getError());
2133 return false;
2134 }
2135
2136 GLuint endByte = endByteOrErr.getResult();
2137
2138 if (pixelUnpackBuffer)
2139 {
2140 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
2141 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
2142 checkedEndByte += checkedOffset;
2143
2144 if (!checkedEndByte.IsValid() ||
2145 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
2146 {
2147 // Overflow past the end of the buffer
2148 context->handleError(Error(GL_INVALID_OPERATION));
2149 return false;
2150 }
2151 }
2152 else
2153 {
2154 ASSERT(imageSize >= 0);
2155 if (pixels == nullptr && imageSize != 0)
2156 {
2157 context->handleError(
2158 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
Geoff Lang3feb3ff2016-10-26 10:57:45 -04002159 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04002160 }
2161
Geoff Lang3feb3ff2016-10-26 10:57:45 -04002162 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04002163 {
2164 context->handleError(
2165 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
2166 return false;
2167 }
2168 }
2169
2170 return true;
2171}
2172
Geoff Lang37dde692014-01-31 16:34:54 -05002173bool ValidQueryType(const Context *context, GLenum queryType)
2174{
He Yunchaoced53ae2016-11-29 15:00:51 +08002175 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
2176 "GL extension enums not equal.");
2177 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2178 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05002179
2180 switch (queryType)
2181 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002182 case GL_ANY_SAMPLES_PASSED:
2183 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
2184 return true;
2185 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
2186 return (context->getClientMajorVersion() >= 3);
2187 case GL_TIME_ELAPSED_EXT:
2188 return context->getExtensions().disjointTimerQuery;
2189 case GL_COMMANDS_COMPLETED_CHROMIUM:
2190 return context->getExtensions().syncQuery;
2191 default:
2192 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05002193 }
2194}
2195
Geoff Lang2d62ab72017-03-23 16:54:40 -04002196bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
2197 GLenum type,
2198 GLboolean normalized,
2199 GLsizei stride,
2200 const GLvoid *ptr,
2201 bool pureInteger)
2202{
2203 ASSERT(context->getExtensions().webglCompatibility);
2204
2205 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
2206 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
2207 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
2208 // parameter exceeds 255.
2209 constexpr GLsizei kMaxWebGLStride = 255;
2210 if (stride > kMaxWebGLStride)
2211 {
2212 context->handleError(
2213 Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
2214 return false;
2215 }
2216
2217 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
2218 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
2219 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
2220 // or an INVALID_OPERATION error is generated.
2221 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
2222 size_t typeSize = GetVertexFormatTypeSize(internalType);
2223
2224 ASSERT(isPow2(typeSize) && typeSize > 0);
2225 size_t sizeMask = (typeSize - 1);
2226 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
2227 {
2228 context->handleError(
2229 Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
2230 return false;
2231 }
2232
2233 if ((stride & sizeMask) != 0)
2234 {
2235 context->handleError(
2236 Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
2237 return false;
2238 }
2239
2240 return true;
2241}
2242
Jamie Madillef300b12016-10-07 15:12:09 -04002243Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05002244{
He Yunchaoced53ae2016-11-29 15:00:51 +08002245 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
2246 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
2247 // or program object and INVALID_OPERATION if the provided name identifies an object
2248 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05002249
Dian Xiang769769a2015-09-09 15:20:08 -07002250 Program *validProgram = context->getProgram(id);
2251
2252 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05002253 {
Dian Xiang769769a2015-09-09 15:20:08 -07002254 if (context->getShader(id))
2255 {
Jamie Madill437fa652016-05-03 15:13:24 -04002256 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07002257 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
2258 }
2259 else
2260 {
Jamie Madill437fa652016-05-03 15:13:24 -04002261 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -07002262 }
Geoff Lang48dcae72014-02-05 16:28:24 -05002263 }
Dian Xiang769769a2015-09-09 15:20:08 -07002264
2265 return validProgram;
2266}
2267
Jamie Madillef300b12016-10-07 15:12:09 -04002268Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07002269{
2270 // See ValidProgram for spec details.
2271
2272 Shader *validShader = context->getShader(id);
2273
2274 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05002275 {
Dian Xiang769769a2015-09-09 15:20:08 -07002276 if (context->getProgram(id))
2277 {
Jamie Madill437fa652016-05-03 15:13:24 -04002278 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07002279 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
2280 }
2281 else
2282 {
Jamie Madill437fa652016-05-03 15:13:24 -04002283 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -07002284 }
Geoff Lang48dcae72014-02-05 16:28:24 -05002285 }
Dian Xiang769769a2015-09-09 15:20:08 -07002286
2287 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05002288}
2289
Geoff Langb1196682014-07-23 13:47:29 -04002290bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04002291{
2292 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
2293 {
2294 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
2295
Geoff Langaae65a42014-05-26 12:43:44 -04002296 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04002297 {
Jamie Madill437fa652016-05-03 15:13:24 -04002298 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002299 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04002300 }
2301 }
2302 else
2303 {
2304 switch (attachment)
2305 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002306 case GL_DEPTH_ATTACHMENT:
2307 case GL_STENCIL_ATTACHMENT:
2308 break;
Jamie Madillb4472272014-07-03 10:38:55 -04002309
He Yunchaoced53ae2016-11-29 15:00:51 +08002310 case GL_DEPTH_STENCIL_ATTACHMENT:
2311 if (!context->getExtensions().webglCompatibility &&
2312 context->getClientMajorVersion() < 3)
2313 {
2314 context->handleError(Error(GL_INVALID_ENUM));
2315 return false;
2316 }
2317 break;
Jamie Madillb4472272014-07-03 10:38:55 -04002318
He Yunchaoced53ae2016-11-29 15:00:51 +08002319 default:
2320 context->handleError(Error(GL_INVALID_ENUM));
2321 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04002322 }
2323 }
2324
2325 return true;
2326}
2327
Jamie Madille8fb6402017-02-14 17:56:40 -05002328bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08002329 GLenum target,
2330 GLsizei samples,
2331 GLenum internalformat,
2332 GLsizei width,
2333 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002334{
2335 switch (target)
2336 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002337 case GL_RENDERBUFFER:
2338 break;
2339 default:
2340 context->handleError(Error(GL_INVALID_ENUM));
2341 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002342 }
2343
2344 if (width < 0 || height < 0 || samples < 0)
2345 {
Jamie Madill437fa652016-05-03 15:13:24 -04002346 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002347 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002348 }
2349
Jamie Madill4e0e6f82017-02-17 11:06:03 -05002350 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
2351 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
2352
2353 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04002354 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002355 {
Jamie Madill437fa652016-05-03 15:13:24 -04002356 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002357 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002358 }
2359
2360 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
2361 // 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 -08002362 // only sized internal formats.
Geoff Langca271392017-04-05 12:30:00 -04002363 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat);
2364 if (formatInfo.internalFormat == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002365 {
Jamie Madill437fa652016-05-03 15:13:24 -04002366 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002367 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002368 }
2369
Geoff Langaae65a42014-05-26 12:43:44 -04002370 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002371 {
Jamie Madill437fa652016-05-03 15:13:24 -04002372 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002373 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002374 }
2375
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002376 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002377 if (handle == 0)
2378 {
Jamie Madill437fa652016-05-03 15:13:24 -04002379 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002380 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002381 }
2382
2383 return true;
2384}
2385
He Yunchaoced53ae2016-11-29 15:00:51 +08002386bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
2387 GLenum target,
2388 GLenum attachment,
2389 GLenum renderbuffertarget,
2390 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002391{
Shannon Woods1da3cf62014-06-27 15:32:23 -04002392 if (!ValidFramebufferTarget(target))
2393 {
Jamie Madill437fa652016-05-03 15:13:24 -04002394 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002395 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04002396 }
2397
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002398 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002399
Jamie Madill84115c92015-04-23 15:00:07 -04002400 ASSERT(framebuffer);
2401 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002402 {
Jamie Madill437fa652016-05-03 15:13:24 -04002403 context->handleError(
2404 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04002405 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002406 }
2407
Jamie Madillb4472272014-07-03 10:38:55 -04002408 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002409 {
Jamie Madillb4472272014-07-03 10:38:55 -04002410 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002411 }
2412
Jamie Madillab9d82c2014-01-21 16:38:14 -05002413 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
2414 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
2415 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
2416 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
2417 if (renderbuffer != 0)
2418 {
2419 if (!context->getRenderbuffer(renderbuffer))
2420 {
Jamie Madill437fa652016-05-03 15:13:24 -04002421 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002422 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05002423 }
2424 }
2425
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05002426 return true;
2427}
2428
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002429bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05002430 GLint srcX0,
2431 GLint srcY0,
2432 GLint srcX1,
2433 GLint srcY1,
2434 GLint dstX0,
2435 GLint dstY0,
2436 GLint dstX1,
2437 GLint dstY1,
2438 GLbitfield mask,
2439 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002440{
2441 switch (filter)
2442 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002443 case GL_NEAREST:
2444 break;
2445 case GL_LINEAR:
2446 break;
2447 default:
2448 context->handleError(Error(GL_INVALID_ENUM));
2449 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002450 }
2451
2452 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
2453 {
Jamie Madill437fa652016-05-03 15:13:24 -04002454 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002455 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002456 }
2457
2458 if (mask == 0)
2459 {
2460 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
2461 // buffers are copied.
2462 return false;
2463 }
2464
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002465 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
2466 // color buffer, leaving only nearest being unfiltered from above
2467 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
2468 {
Jamie Madill437fa652016-05-03 15:13:24 -04002469 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002470 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002471 }
2472
Jamie Madill51f40ec2016-06-15 14:06:00 -04002473 const auto &glState = context->getGLState();
2474 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
2475 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05002476
2477 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002478 {
Jamie Madill437fa652016-05-03 15:13:24 -04002479 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002480 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002481 }
2482
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002483 if (readFramebuffer->id() == drawFramebuffer->id())
2484 {
2485 context->handleError(Error(GL_INVALID_OPERATION));
2486 return false;
2487 }
2488
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002489 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05002490 {
Jamie Madill437fa652016-05-03 15:13:24 -04002491 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05002492 return false;
2493 }
2494
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002495 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05002496 {
Jamie Madill437fa652016-05-03 15:13:24 -04002497 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05002498 return false;
2499 }
2500
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002501 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002502 {
Jamie Madill437fa652016-05-03 15:13:24 -04002503 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002504 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002505 }
2506
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002507 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
2508
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002509 if (mask & GL_COLOR_BUFFER_BIT)
2510 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002511 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05002512 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002513
He Yunchao66a41a22016-12-15 16:45:05 +08002514 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002515 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002516 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002517
Geoff Langa15472a2015-08-11 11:48:03 -04002518 for (size_t drawbufferIdx = 0;
2519 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002520 {
Geoff Langa15472a2015-08-11 11:48:03 -04002521 const FramebufferAttachment *attachment =
2522 drawFramebuffer->getDrawBuffer(drawbufferIdx);
2523 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002524 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002525 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002526
Geoff Langb2f3d052013-08-13 12:49:27 -04002527 // The GL ES 3.0.2 spec (pg 193) states that:
2528 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08002529 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
2530 // as well
2531 // 3) If the read buffer is a signed integer format, the draw buffer must be as
2532 // well
Jamie Madill6163c752015-12-07 16:32:59 -05002533 // Changes with EXT_color_buffer_float:
2534 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04002535 GLenum readComponentType = readFormat.info->componentType;
2536 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08002537 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05002538 readComponentType == GL_SIGNED_NORMALIZED);
2539 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
2540 drawComponentType == GL_SIGNED_NORMALIZED);
2541
2542 if (extensions.colorBufferFloat)
2543 {
2544 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
2545 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
2546
2547 if (readFixedOrFloat != drawFixedOrFloat)
2548 {
Jamie Madill437fa652016-05-03 15:13:24 -04002549 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05002550 "If the read buffer contains fixed-point or "
2551 "floating-point values, the draw buffer "
2552 "must as well."));
2553 return false;
2554 }
2555 }
2556 else if (readFixedPoint != drawFixedPoint)
2557 {
Jamie Madill437fa652016-05-03 15:13:24 -04002558 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05002559 "If the read buffer contains fixed-point "
2560 "values, the draw buffer must as well."));
2561 return false;
2562 }
2563
2564 if (readComponentType == GL_UNSIGNED_INT &&
2565 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002566 {
Jamie Madill437fa652016-05-03 15:13:24 -04002567 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002568 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002569 }
2570
Jamie Madill6163c752015-12-07 16:32:59 -05002571 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002572 {
Jamie Madill437fa652016-05-03 15:13:24 -04002573 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002574 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002575 }
2576
Jamie Madilla3944d42016-07-22 22:13:26 -04002577 if (readColorBuffer->getSamples() > 0 &&
2578 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002579 {
Jamie Madill437fa652016-05-03 15:13:24 -04002580 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002581 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002582 }
2583 }
2584 }
2585
Jamie Madilla3944d42016-07-22 22:13:26 -04002586 if ((readFormat.info->componentType == GL_INT ||
2587 readFormat.info->componentType == GL_UNSIGNED_INT) &&
2588 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002589 {
Jamie Madill437fa652016-05-03 15:13:24 -04002590 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002591 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002592 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002593 }
He Yunchao66a41a22016-12-15 16:45:05 +08002594 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
2595 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
2596 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
2597 // situation is an application error that would lead to a crash in ANGLE.
2598 else if (drawFramebuffer->hasEnabledDrawBuffer())
2599 {
2600 context->handleError(Error(
2601 GL_INVALID_OPERATION,
2602 "Attempt to read from a missing color attachment of a complete framebuffer."));
2603 return false;
2604 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002605 }
2606
He Yunchaoced53ae2016-11-29 15:00:51 +08002607 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002608 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
2609 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002610 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002611 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002612 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002613 const gl::FramebufferAttachment *readBuffer =
2614 readFramebuffer->getAttachment(attachments[i]);
2615 const gl::FramebufferAttachment *drawBuffer =
2616 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002617
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002618 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002619 {
Jamie Madilla3944d42016-07-22 22:13:26 -04002620 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002621 {
Jamie Madill437fa652016-05-03 15:13:24 -04002622 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002623 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002624 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002625
Dongseong Hwang44b422c2014-12-09 15:42:01 +02002626 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002627 {
Jamie Madill437fa652016-05-03 15:13:24 -04002628 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002629 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002630 }
2631 }
He Yunchao66a41a22016-12-15 16:45:05 +08002632 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
2633 else if (drawBuffer)
2634 {
2635 context->handleError(Error(GL_INVALID_OPERATION,
2636 "Attempt to read from a missing depth/stencil "
2637 "attachment of a complete framebuffer."));
2638 return false;
2639 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04002640 }
2641 }
2642
2643 return true;
2644}
2645
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002646bool ValidateReadPixels(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05002647 GLint x,
2648 GLint y,
2649 GLsizei width,
2650 GLsizei height,
2651 GLenum format,
2652 GLenum type,
2653 GLvoid *pixels)
Jamie Madill26e91952014-03-05 15:01:27 -05002654{
Geoff Lange93daba2017-03-30 13:54:40 -04002655 return ValidateReadPixelsBase(context, x, y, width, height, format, type, -1, nullptr, nullptr,
2656 nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04002657}
2658
2659bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
2660 GLint x,
2661 GLint y,
2662 GLsizei width,
2663 GLsizei height,
2664 GLenum format,
2665 GLenum type,
2666 GLsizei bufSize,
2667 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04002668 GLsizei *columns,
2669 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -04002670 GLvoid *pixels)
2671{
2672 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05002673 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002674 return false;
2675 }
2676
Geoff Lang62fce5b2016-09-30 10:46:35 -04002677 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04002678 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05002679 {
Geoff Langb1196682014-07-23 13:47:29 -04002680 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002681 }
2682
Geoff Lang62fce5b2016-09-30 10:46:35 -04002683 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05002684 {
Geoff Langb1196682014-07-23 13:47:29 -04002685 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002686 }
2687
Jamie Madillc29968b2016-01-20 11:17:23 -05002688 return true;
2689}
2690
2691bool ValidateReadnPixelsEXT(Context *context,
2692 GLint x,
2693 GLint y,
2694 GLsizei width,
2695 GLsizei height,
2696 GLenum format,
2697 GLenum type,
2698 GLsizei bufSize,
2699 GLvoid *pixels)
2700{
2701 if (bufSize < 0)
2702 {
Jamie Madill437fa652016-05-03 15:13:24 -04002703 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05002704 return false;
2705 }
2706
Geoff Lang62fce5b2016-09-30 10:46:35 -04002707 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04002708 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04002709}
Jamie Madill26e91952014-03-05 15:01:27 -05002710
Geoff Lang62fce5b2016-09-30 10:46:35 -04002711bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
2712 GLint x,
2713 GLint y,
2714 GLsizei width,
2715 GLsizei height,
2716 GLenum format,
2717 GLenum type,
2718 GLsizei bufSize,
2719 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04002720 GLsizei *columns,
2721 GLsizei *rows,
Geoff Lang62fce5b2016-09-30 10:46:35 -04002722 GLvoid *data)
2723{
2724 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04002725 {
Jamie Madille2e406c2016-06-02 13:04:10 -04002726 return false;
2727 }
2728
Geoff Lange93daba2017-03-30 13:54:40 -04002729 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
2730 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04002731 {
Jamie Madillc29968b2016-01-20 11:17:23 -05002732 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05002733 }
2734
Geoff Lang62fce5b2016-09-30 10:46:35 -04002735 if (!ValidateRobustBufferSize(context, bufSize, *length))
2736 {
2737 return false;
2738 }
2739
2740 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05002741}
2742
Olli Etuaho41997e72016-03-10 13:38:39 +02002743bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002744{
2745 if (!context->getExtensions().occlusionQueryBoolean &&
2746 !context->getExtensions().disjointTimerQuery)
2747 {
Jamie Madill437fa652016-05-03 15:13:24 -04002748 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002749 return false;
2750 }
2751
Olli Etuaho41997e72016-03-10 13:38:39 +02002752 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002753}
2754
Olli Etuaho41997e72016-03-10 13:38:39 +02002755bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002756{
2757 if (!context->getExtensions().occlusionQueryBoolean &&
2758 !context->getExtensions().disjointTimerQuery)
2759 {
Jamie Madill437fa652016-05-03 15:13:24 -04002760 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002761 return false;
2762 }
2763
Olli Etuaho41997e72016-03-10 13:38:39 +02002764 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002765}
2766
2767bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002768{
2769 if (!ValidQueryType(context, target))
2770 {
Jamie Madill437fa652016-05-03 15:13:24 -04002771 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04002772 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002773 }
2774
2775 if (id == 0)
2776 {
Jamie Madill437fa652016-05-03 15:13:24 -04002777 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04002778 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002779 }
2780
2781 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
2782 // of zero, if the active query object name for <target> is non-zero (for the
2783 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
2784 // the active query for either target is non-zero), if <id> is the name of an
2785 // existing query object whose type does not match <target>, or if <id> is the
2786 // active query object name for any query type, the error INVALID_OPERATION is
2787 // generated.
2788
2789 // Ensure no other queries are active
2790 // NOTE: If other queries than occlusion are supported, we will need to check
2791 // separately that:
2792 // a) The query ID passed is not the current active query for any target/type
2793 // b) There are no active queries for the requested target (and in the case
2794 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
2795 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002796
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002797 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002798 {
Jamie Madill437fa652016-05-03 15:13:24 -04002799 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04002800 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002801 }
2802
2803 Query *queryObject = context->getQuery(id, true, target);
2804
2805 // check that name was obtained with glGenQueries
2806 if (!queryObject)
2807 {
Jamie Madill437fa652016-05-03 15:13:24 -04002808 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04002809 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002810 }
2811
2812 // check for type mismatch
2813 if (queryObject->getType() != target)
2814 {
Jamie Madill437fa652016-05-03 15:13:24 -04002815 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04002816 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04002817 }
2818
2819 return true;
2820}
2821
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002822bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
2823{
2824 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002825 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002826 {
Jamie Madill437fa652016-05-03 15:13:24 -04002827 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002828 return false;
2829 }
2830
2831 return ValidateBeginQueryBase(context, target, id);
2832}
2833
2834bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04002835{
2836 if (!ValidQueryType(context, target))
2837 {
Jamie Madill437fa652016-05-03 15:13:24 -04002838 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04002839 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04002840 }
2841
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002842 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04002843
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002844 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04002845 {
Jamie Madill437fa652016-05-03 15:13:24 -04002846 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04002847 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04002848 }
2849
Jamie Madill45c785d2014-05-13 14:09:34 -04002850 return true;
2851}
2852
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002853bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
2854{
2855 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002856 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002857 {
Jamie Madill437fa652016-05-03 15:13:24 -04002858 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002859 return false;
2860 }
2861
2862 return ValidateEndQueryBase(context, target);
2863}
2864
2865bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
2866{
2867 if (!context->getExtensions().disjointTimerQuery)
2868 {
Jamie Madill437fa652016-05-03 15:13:24 -04002869 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002870 return false;
2871 }
2872
2873 if (target != GL_TIMESTAMP_EXT)
2874 {
Jamie Madill437fa652016-05-03 15:13:24 -04002875 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002876 return false;
2877 }
2878
2879 Query *queryObject = context->getQuery(id, true, target);
2880 if (queryObject == nullptr)
2881 {
Jamie Madill437fa652016-05-03 15:13:24 -04002882 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002883 return false;
2884 }
2885
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002886 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002887 {
Jamie Madill437fa652016-05-03 15:13:24 -04002888 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002889 return false;
2890 }
2891
2892 return true;
2893}
2894
Geoff Lang2186c382016-10-14 10:54:54 -04002895bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002896{
Geoff Lang2186c382016-10-14 10:54:54 -04002897 if (numParams)
2898 {
2899 *numParams = 0;
2900 }
2901
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002902 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
2903 {
Jamie Madill437fa652016-05-03 15:13:24 -04002904 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002905 return false;
2906 }
2907
2908 switch (pname)
2909 {
2910 case GL_CURRENT_QUERY_EXT:
2911 if (target == GL_TIMESTAMP_EXT)
2912 {
Jamie Madill437fa652016-05-03 15:13:24 -04002913 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002914 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
2915 return false;
2916 }
2917 break;
2918 case GL_QUERY_COUNTER_BITS_EXT:
2919 if (!context->getExtensions().disjointTimerQuery ||
2920 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
2921 {
Jamie Madill437fa652016-05-03 15:13:24 -04002922 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002923 return false;
2924 }
2925 break;
2926 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002927 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002928 return false;
2929 }
2930
Geoff Lang2186c382016-10-14 10:54:54 -04002931 if (numParams)
2932 {
2933 // All queries return only one value
2934 *numParams = 1;
2935 }
2936
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002937 return true;
2938}
2939
2940bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
2941{
2942 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002943 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002944 {
Jamie Madill437fa652016-05-03 15:13:24 -04002945 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002946 return false;
2947 }
2948
Geoff Lang2186c382016-10-14 10:54:54 -04002949 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002950}
2951
Geoff Lang2186c382016-10-14 10:54:54 -04002952bool ValidateGetQueryivRobustANGLE(Context *context,
2953 GLenum target,
2954 GLenum pname,
2955 GLsizei bufSize,
2956 GLsizei *length,
2957 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002958{
Geoff Lang2186c382016-10-14 10:54:54 -04002959 if (!ValidateRobustEntryPoint(context, bufSize))
2960 {
2961 return false;
2962 }
2963
2964 if (!ValidateGetQueryivBase(context, target, pname, length))
2965 {
2966 return false;
2967 }
2968
2969 if (!ValidateRobustBufferSize(context, bufSize, *length))
2970 {
2971 return false;
2972 }
2973
2974 return true;
2975}
2976
2977bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
2978{
2979 if (numParams)
2980 {
2981 *numParams = 0;
2982 }
2983
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002984 Query *queryObject = context->getQuery(id, false, GL_NONE);
2985
2986 if (!queryObject)
2987 {
Jamie Madill437fa652016-05-03 15:13:24 -04002988 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002989 return false;
2990 }
2991
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002992 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002993 {
Jamie Madill437fa652016-05-03 15:13:24 -04002994 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002995 return false;
2996 }
2997
2998 switch (pname)
2999 {
3000 case GL_QUERY_RESULT_EXT:
3001 case GL_QUERY_RESULT_AVAILABLE_EXT:
3002 break;
3003
3004 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003005 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003006 return false;
3007 }
3008
Geoff Lang2186c382016-10-14 10:54:54 -04003009 if (numParams)
3010 {
3011 *numParams = 1;
3012 }
3013
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003014 return true;
3015}
3016
3017bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
3018{
3019 if (!context->getExtensions().disjointTimerQuery)
3020 {
Jamie Madill437fa652016-05-03 15:13:24 -04003021 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003022 return false;
3023 }
Geoff Lang2186c382016-10-14 10:54:54 -04003024 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3025}
3026
3027bool ValidateGetQueryObjectivRobustANGLE(Context *context,
3028 GLuint id,
3029 GLenum pname,
3030 GLsizei bufSize,
3031 GLsizei *length,
3032 GLint *params)
3033{
3034 if (!context->getExtensions().disjointTimerQuery)
3035 {
3036 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3037 return false;
3038 }
3039
3040 if (!ValidateRobustEntryPoint(context, bufSize))
3041 {
3042 return false;
3043 }
3044
3045 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3046 {
3047 return false;
3048 }
3049
3050 if (!ValidateRobustBufferSize(context, bufSize, *length))
3051 {
3052 return false;
3053 }
3054
3055 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003056}
3057
3058bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
3059{
3060 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04003061 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003062 {
Jamie Madill437fa652016-05-03 15:13:24 -04003063 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003064 return false;
3065 }
Geoff Lang2186c382016-10-14 10:54:54 -04003066 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3067}
3068
3069bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
3070 GLuint id,
3071 GLenum pname,
3072 GLsizei bufSize,
3073 GLsizei *length,
3074 GLuint *params)
3075{
3076 if (!context->getExtensions().disjointTimerQuery &&
3077 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
3078 {
3079 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
3080 return false;
3081 }
3082
3083 if (!ValidateRobustEntryPoint(context, bufSize))
3084 {
3085 return false;
3086 }
3087
3088 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3089 {
3090 return false;
3091 }
3092
3093 if (!ValidateRobustBufferSize(context, bufSize, *length))
3094 {
3095 return false;
3096 }
3097
3098 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003099}
3100
3101bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
3102{
3103 if (!context->getExtensions().disjointTimerQuery)
3104 {
Jamie Madill437fa652016-05-03 15:13:24 -04003105 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003106 return false;
3107 }
Geoff Lang2186c382016-10-14 10:54:54 -04003108 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3109}
3110
3111bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
3112 GLuint id,
3113 GLenum pname,
3114 GLsizei bufSize,
3115 GLsizei *length,
3116 GLint64 *params)
3117{
3118 if (!context->getExtensions().disjointTimerQuery)
3119 {
3120 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3121 return false;
3122 }
3123
3124 if (!ValidateRobustEntryPoint(context, bufSize))
3125 {
3126 return false;
3127 }
3128
3129 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3130 {
3131 return false;
3132 }
3133
3134 if (!ValidateRobustBufferSize(context, bufSize, *length))
3135 {
3136 return false;
3137 }
3138
3139 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003140}
3141
3142bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
3143{
3144 if (!context->getExtensions().disjointTimerQuery)
3145 {
Jamie Madill437fa652016-05-03 15:13:24 -04003146 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003147 return false;
3148 }
Geoff Lang2186c382016-10-14 10:54:54 -04003149 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
3150}
3151
3152bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
3153 GLuint id,
3154 GLenum pname,
3155 GLsizei bufSize,
3156 GLsizei *length,
3157 GLuint64 *params)
3158{
3159 if (!context->getExtensions().disjointTimerQuery)
3160 {
3161 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
3162 return false;
3163 }
3164
3165 if (!ValidateRobustEntryPoint(context, bufSize))
3166 {
3167 return false;
3168 }
3169
3170 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
3171 {
3172 return false;
3173 }
3174
3175 if (!ValidateRobustBufferSize(context, bufSize, *length))
3176 {
3177 return false;
3178 }
3179
3180 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05003181}
3182
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003183bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003184 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003185 GLuint program,
3186 GLint location,
3187 GLsizei count)
3188{
3189 // Check for ES31 program uniform entry points
3190 if (context->getClientVersion() < Version(3, 1))
3191 {
3192 context->handleError(Error(GL_INVALID_OPERATION));
3193 return false;
3194 }
3195
3196 const LinkedUniform *uniform = nullptr;
3197 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003198 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3199 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003200}
3201
Frank Henigmana98a6472017-02-02 21:38:32 -05003202bool ValidateProgramUniform1iv(gl::Context *context,
3203 GLuint program,
3204 GLint location,
3205 GLsizei count,
3206 const GLint *value)
3207{
3208 // Check for ES31 program uniform entry points
3209 if (context->getClientVersion() < Version(3, 1))
3210 {
3211 context->handleError(Error(GL_INVALID_OPERATION));
3212 return false;
3213 }
3214
3215 const LinkedUniform *uniform = nullptr;
3216 gl::Program *programObject = GetValidProgram(context, program);
3217 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3218 ValidateUniform1ivValue(context, uniform->type, count, value);
3219}
3220
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003221bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003222 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003223 GLuint program,
3224 GLint location,
3225 GLsizei count,
3226 GLboolean transpose)
3227{
3228 // Check for ES31 program uniform entry points
3229 if (context->getClientVersion() < Version(3, 1))
3230 {
3231 context->handleError(Error(GL_INVALID_OPERATION));
3232 return false;
3233 }
3234
3235 const LinkedUniform *uniform = nullptr;
3236 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003237 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3238 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08003239}
3240
Jamie Madillc1d770e2017-04-13 17:31:24 -04003241bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003242{
3243 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003244 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003245 {
Jamie Madill437fa652016-05-03 15:13:24 -04003246 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003247 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003248 }
3249
Jamie Madill62d31cb2015-09-11 13:25:51 -04003250 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003251 gl::Program *programObject = context->getGLState().getProgram();
3252 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3253 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04003254}
3255
Frank Henigmana98a6472017-02-02 21:38:32 -05003256bool ValidateUniform1iv(gl::Context *context, GLint location, GLsizei count, const GLint *value)
3257{
3258 const LinkedUniform *uniform = nullptr;
3259 gl::Program *programObject = context->getGLState().getProgram();
3260 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3261 ValidateUniform1ivValue(context, uniform->type, count, value);
3262}
3263
Jamie Madillc1d770e2017-04-13 17:31:24 -04003264bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003265 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08003266 GLint location,
3267 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04003268 GLboolean transpose)
3269{
3270 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003271 int rows = VariableRowCount(valueType);
3272 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03003273 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003274 {
Jamie Madill437fa652016-05-03 15:13:24 -04003275 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003276 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003277 }
3278
Martin Radev1be913c2016-07-11 17:59:16 +03003279 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04003280 {
Jamie Madill437fa652016-05-03 15:13:24 -04003281 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003282 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04003283 }
3284
Jamie Madill62d31cb2015-09-11 13:25:51 -04003285 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05003286 gl::Program *programObject = context->getGLState().getProgram();
3287 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
3288 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04003289}
3290
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003291bool ValidateStateQuery(ValidationContext *context,
3292 GLenum pname,
3293 GLenum *nativeType,
3294 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04003295{
3296 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
3297 {
Jamie Madill437fa652016-05-03 15:13:24 -04003298 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003299 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003300 }
3301
Jamie Madill0af26e12015-03-05 19:54:33 -05003302 const Caps &caps = context->getCaps();
3303
Jamie Madill893ab082014-05-16 16:56:10 -04003304 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
3305 {
3306 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
3307
Jamie Madill0af26e12015-03-05 19:54:33 -05003308 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04003309 {
Jamie Madill437fa652016-05-03 15:13:24 -04003310 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003311 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003312 }
3313 }
3314
3315 switch (pname)
3316 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003317 case GL_TEXTURE_BINDING_2D:
3318 case GL_TEXTURE_BINDING_CUBE_MAP:
3319 case GL_TEXTURE_BINDING_3D:
3320 case GL_TEXTURE_BINDING_2D_ARRAY:
3321 break;
3322 case GL_TEXTURE_BINDING_EXTERNAL_OES:
3323 if (!context->getExtensions().eglStreamConsumerExternal &&
3324 !context->getExtensions().eglImageExternal)
3325 {
3326 context->handleError(Error(GL_INVALID_ENUM,
3327 "Neither NV_EGL_stream_consumer_external nor "
3328 "GL_OES_EGL_image_external extensions enabled"));
3329 return false;
3330 }
3331 break;
Jamie Madill893ab082014-05-16 16:56:10 -04003332
He Yunchaoced53ae2016-11-29 15:00:51 +08003333 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
3334 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04003335 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003336 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
3337 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04003338 {
Jamie Madill437fa652016-05-03 15:13:24 -04003339 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003340 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003341 }
3342
Jamie Madill51f40ec2016-06-15 14:06:00 -04003343 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
3344 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03003345
3346 if (framebuffer->getReadBufferState() == GL_NONE)
3347 {
3348 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
3349 return false;
3350 }
3351
Jamie Madillb6bda4a2015-04-20 12:53:26 -04003352 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04003353 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04003354 {
Jamie Madill437fa652016-05-03 15:13:24 -04003355 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003356 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04003357 }
3358 }
3359 break;
3360
He Yunchaoced53ae2016-11-29 15:00:51 +08003361 default:
3362 break;
Jamie Madill893ab082014-05-16 16:56:10 -04003363 }
3364
3365 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04003366 if (*numParams == 0)
3367 {
3368 return false;
3369 }
3370
3371 return true;
3372}
3373
3374bool ValidateRobustStateQuery(ValidationContext *context,
3375 GLenum pname,
3376 GLsizei bufSize,
3377 GLenum *nativeType,
3378 unsigned int *numParams)
3379{
3380 if (!ValidateRobustEntryPoint(context, bufSize))
3381 {
3382 return false;
3383 }
3384
3385 if (!ValidateStateQuery(context, pname, nativeType, numParams))
3386 {
3387 return false;
3388 }
3389
3390 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04003391 {
3392 return false;
3393 }
3394
3395 return true;
3396}
3397
Jamie Madillc29968b2016-01-20 11:17:23 -05003398bool ValidateCopyTexImageParametersBase(ValidationContext *context,
3399 GLenum target,
3400 GLint level,
3401 GLenum internalformat,
3402 bool isSubImage,
3403 GLint xoffset,
3404 GLint yoffset,
3405 GLint zoffset,
3406 GLint x,
3407 GLint y,
3408 GLsizei width,
3409 GLsizei height,
3410 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04003411 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04003412{
Jamie Madill560a8d82014-05-21 13:06:20 -04003413 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
3414 {
Jamie Madill437fa652016-05-03 15:13:24 -04003415 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003416 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003417 }
3418
He Yunchaoced53ae2016-11-29 15:00:51 +08003419 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
3420 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04003421 {
Jamie Madill437fa652016-05-03 15:13:24 -04003422 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003423 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003424 }
3425
3426 if (border != 0)
3427 {
Jamie Madill437fa652016-05-03 15:13:24 -04003428 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003429 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003430 }
3431
3432 if (!ValidMipLevel(context, target, level))
3433 {
Jamie Madill437fa652016-05-03 15:13:24 -04003434 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003435 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003436 }
3437
Jamie Madill51f40ec2016-06-15 14:06:00 -04003438 const auto &state = context->getGLState();
3439 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003440 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04003441 {
Jamie Madill437fa652016-05-03 15:13:24 -04003442 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003443 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003444 }
3445
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003446 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04003447 {
Jamie Madill437fa652016-05-03 15:13:24 -04003448 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003449 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003450 }
3451
Martin Radev138064f2016-07-15 12:03:41 +03003452 if (readFramebuffer->getReadBufferState() == GL_NONE)
3453 {
3454 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
3455 return false;
3456 }
3457
Corentin Wallez3c90ed62016-12-16 16:19:28 -05003458 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
3459 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08003460 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05003461 // situation is an application error that would lead to a crash in ANGLE.
3462 if (readFramebuffer->getReadColorbuffer() == nullptr)
3463 {
3464 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
3465 return false;
3466 }
3467
Geoff Langaae65a42014-05-26 12:43:44 -04003468 const gl::Caps &caps = context->getCaps();
3469
Geoff Langaae65a42014-05-26 12:43:44 -04003470 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04003471 switch (target)
3472 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003473 case GL_TEXTURE_2D:
3474 maxDimension = caps.max2DTextureSize;
3475 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003476
He Yunchaoced53ae2016-11-29 15:00:51 +08003477 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
3478 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
3479 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
3480 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
3481 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
3482 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
3483 maxDimension = caps.maxCubeMapTextureSize;
3484 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003485
He Yunchaoced53ae2016-11-29 15:00:51 +08003486 case GL_TEXTURE_2D_ARRAY:
3487 maxDimension = caps.max2DTextureSize;
3488 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003489
He Yunchaoced53ae2016-11-29 15:00:51 +08003490 case GL_TEXTURE_3D:
3491 maxDimension = caps.max3DTextureSize;
3492 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04003493
He Yunchaoced53ae2016-11-29 15:00:51 +08003494 default:
3495 context->handleError(Error(GL_INVALID_ENUM));
3496 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003497 }
3498
Jamie Madillc29968b2016-01-20 11:17:23 -05003499 gl::Texture *texture =
3500 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04003501 if (!texture)
3502 {
Jamie Madill437fa652016-05-03 15:13:24 -04003503 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003504 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003505 }
3506
Geoff Lang69cce582015-09-17 13:20:36 -04003507 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04003508 {
Jamie Madill437fa652016-05-03 15:13:24 -04003509 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003510 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003511 }
3512
Geoff Langca271392017-04-05 12:30:00 -04003513 const gl::InternalFormat &formatInfo =
3514 gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04003515
3516 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04003517 {
Jamie Madill437fa652016-05-03 15:13:24 -04003518 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003519 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003520 }
3521
Geoff Lang44ff5a72017-02-03 15:15:43 -05003522 if (formatInfo.compressed &&
3523 !ValidCompressedImageSize(context, internalformat, xoffset, yoffset, width, height))
Jamie Madill560a8d82014-05-21 13:06:20 -04003524 {
Jamie Madill437fa652016-05-03 15:13:24 -04003525 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05003526 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003527 }
3528
3529 if (isSubImage)
3530 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05003531 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
3532 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
3533 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04003534 {
Jamie Madill437fa652016-05-03 15:13:24 -04003535 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003536 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04003537 }
3538 }
Jamie Madill6f38f822014-06-06 17:12:20 -04003539 else
3540 {
Geoff Lang691e58c2014-12-19 17:03:25 -05003541 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04003542 {
Jamie Madill437fa652016-05-03 15:13:24 -04003543 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003544 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003545 }
3546
Geoff Langeb66a6e2016-10-31 13:06:12 -04003547 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04003548 {
Jamie Madill437fa652016-05-03 15:13:24 -04003549 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003550 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003551 }
3552
3553 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08003554 if (static_cast<int>(width) > maxLevelDimension ||
3555 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04003556 {
Jamie Madill437fa652016-05-03 15:13:24 -04003557 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003558 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04003559 }
3560 }
Jamie Madill560a8d82014-05-21 13:06:20 -04003561
Jamie Madill0c8abca2016-07-22 20:21:26 -04003562 if (textureFormatOut)
3563 {
3564 *textureFormatOut = texture->getFormat(target, level);
3565 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05003566
3567 // Detect texture copying feedback loops for WebGL.
3568 if (context->getExtensions().webglCompatibility)
3569 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05003570 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05003571 {
3572 context->handleError(Error(GL_INVALID_OPERATION,
3573 "Texture copying feedback loop formed between Framebuffer "
3574 "and specified Texture level."));
3575 return false;
3576 }
3577 }
3578
Jamie Madill560a8d82014-05-21 13:06:20 -04003579 return true;
3580}
3581
Jiajia Qind9671222016-11-29 16:30:31 +08003582bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04003583{
Jamie Madill1aeb1312014-06-20 13:21:25 -04003584 switch (mode)
3585 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003586 case GL_POINTS:
3587 case GL_LINES:
3588 case GL_LINE_LOOP:
3589 case GL_LINE_STRIP:
3590 case GL_TRIANGLES:
3591 case GL_TRIANGLE_STRIP:
3592 case GL_TRIANGLE_FAN:
3593 break;
3594 default:
3595 context->handleError(Error(GL_INVALID_ENUM));
3596 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04003597 }
3598
Jamie Madill250d33f2014-06-06 17:09:03 -04003599 if (count < 0)
3600 {
Jamie Madill437fa652016-05-03 15:13:24 -04003601 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003602 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003603 }
3604
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003605 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04003606
Jamie Madill250d33f2014-06-06 17:09:03 -04003607 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003608 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04003609 {
Jamie Madill437fa652016-05-03 15:13:24 -04003610 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003611 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003612 }
3613
Jamie Madillcbcde722017-01-06 14:50:00 -05003614 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
3615 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04003616 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003617 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
3618 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04003619 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003620 const FramebufferAttachment *dsAttachment =
3621 framebuffer->getStencilOrDepthStencilAttachment();
3622 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08003623 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04003624 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05003625
3626 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
3627 bool differentWritemasks =
3628 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
3629 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
3630 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
3631 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
3632
3633 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04003634 {
Jamie Madillcbcde722017-01-06 14:50:00 -05003635 if (!context->getExtensions().webglCompatibility)
3636 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05003637 ERR() << "This ANGLE implementation does not support separate front/back stencil "
3638 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05003639 }
Jamie Madill437fa652016-05-03 15:13:24 -04003640 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04003641 return false;
3642 }
Jamie Madillac528012014-06-20 13:21:23 -04003643 }
3644
Jamie Madilldd43e6c2017-03-24 14:18:49 -04003645 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04003646 {
Jamie Madill437fa652016-05-03 15:13:24 -04003647 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003648 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04003649 }
3650
Geoff Lang7dd2e102014-11-10 15:19:26 -05003651 gl::Program *program = state.getProgram();
3652 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04003653 {
Jamie Madill437fa652016-05-03 15:13:24 -04003654 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003655 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04003656 }
3657
Geoff Lang7dd2e102014-11-10 15:19:26 -05003658 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04003659 {
Jamie Madill437fa652016-05-03 15:13:24 -04003660 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003661 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04003662 }
3663
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003664 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08003665 for (unsigned int uniformBlockIndex = 0;
3666 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003667 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04003668 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08003669 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04003670 const OffsetBindingPointer<Buffer> &uniformBuffer =
3671 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003672
Geoff Lang5d124a62015-09-15 13:03:27 -04003673 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003674 {
3675 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04003676 context->handleError(
3677 Error(GL_INVALID_OPERATION,
3678 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003679 return false;
3680 }
3681
Geoff Lang5d124a62015-09-15 13:03:27 -04003682 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003683 if (uniformBufferSize == 0)
3684 {
3685 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07003686 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003687 }
3688
Jamie Madill62d31cb2015-09-11 13:25:51 -04003689 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003690 {
3691 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04003692 context->handleError(
3693 Error(GL_INVALID_OPERATION,
3694 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00003695 return false;
3696 }
3697 }
3698
Jamie Madilla4595b82017-01-11 17:36:34 -05003699 // Detect rendering feedback loops for WebGL.
3700 if (context->getExtensions().webglCompatibility)
3701 {
3702 if (framebuffer->formsRenderingFeedbackLoopWith(state))
3703 {
3704 context->handleError(
3705 Error(GL_INVALID_OPERATION,
3706 "Rendering feedback loop formed between Framebuffer and active Texture."));
3707 return false;
3708 }
3709 }
3710
Jamie Madill250d33f2014-06-06 17:09:03 -04003711 // No-op if zero count
3712 return (count > 0);
3713}
3714
Jamie Madillc1d770e2017-04-13 17:31:24 -04003715bool ValidateDrawArraysCommon(ValidationContext *context,
3716 GLenum mode,
3717 GLint first,
3718 GLsizei count,
3719 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04003720{
Jamie Madillfd716582014-06-06 17:09:04 -04003721 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04003722 {
Jamie Madill437fa652016-05-03 15:13:24 -04003723 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003724 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003725 }
3726
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003727 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003728 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08003729 if (curTransformFeedback && curTransformFeedback->isActive() &&
3730 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04003731 {
3732 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08003733 // that does not match the current transform feedback object's draw mode (if transform
3734 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04003735 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04003736 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003737 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04003738 }
3739
Jiajia Qind9671222016-11-29 16:30:31 +08003740 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07003741 {
3742 return false;
3743 }
3744
Corentin Wallez71168a02016-12-19 15:11:18 -08003745 // Check the computation of maxVertex doesn't overflow.
3746 // - first < 0 or count < 0 have been checked as an error condition
3747 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
3748 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
3749 ASSERT(count > 0 && first >= 0);
3750 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
3751 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05003752 {
3753 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
3754 return false;
3755 }
3756
Corentin Wallez71168a02016-12-19 15:11:18 -08003757 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04003758 {
3759 return false;
3760 }
3761
3762 return true;
3763}
3764
He Yunchaoced53ae2016-11-29 15:00:51 +08003765bool ValidateDrawArraysInstanced(Context *context,
3766 GLenum mode,
3767 GLint first,
3768 GLsizei count,
3769 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003770{
3771 if (primcount < 0)
3772 {
Jamie Madill437fa652016-05-03 15:13:24 -04003773 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003774 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04003775 }
3776
Jamie Madillc1d770e2017-04-13 17:31:24 -04003777 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04003778 {
3779 return false;
3780 }
3781
3782 // No-op if zero primitive count
3783 return (primcount > 0);
3784}
3785
Geoff Lang87a93302014-09-16 13:29:43 -04003786static bool ValidateDrawInstancedANGLE(Context *context)
3787{
3788 // Verify there is at least one active attribute with a divisor of zero
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003789 const gl::State &state = context->getGLState();
Geoff Lang87a93302014-09-16 13:29:43 -04003790
Geoff Lang7dd2e102014-11-10 15:19:26 -05003791 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04003792
Jiawei-Shao2597fb62016-12-09 16:38:02 +08003793 const auto &attribs = state.getVertexArray()->getVertexAttributes();
3794 const auto &bindings = state.getVertexArray()->getVertexBindings();
Jamie Madill63805b42015-08-25 13:17:39 -04003795 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Geoff Lang87a93302014-09-16 13:29:43 -04003796 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +08003797 const VertexAttribute &attrib = attribs[attributeIndex];
3798 const VertexBinding &binding = bindings[attrib.bindingIndex];
3799 if (program->isAttribLocationActive(attributeIndex) && binding.divisor == 0)
Geoff Lang87a93302014-09-16 13:29:43 -04003800 {
3801 return true;
3802 }
3803 }
3804
Jamie Madill437fa652016-05-03 15:13:24 -04003805 context->handleError(Error(GL_INVALID_OPERATION,
3806 "ANGLE_instanced_arrays requires that at least one active attribute"
3807 "has a divisor of zero."));
Geoff Lang87a93302014-09-16 13:29:43 -04003808 return false;
3809}
3810
He Yunchaoced53ae2016-11-29 15:00:51 +08003811bool ValidateDrawArraysInstancedANGLE(Context *context,
3812 GLenum mode,
3813 GLint first,
3814 GLsizei count,
3815 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003816{
3817 if (!ValidateDrawInstancedANGLE(context))
3818 {
3819 return false;
3820 }
3821
3822 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
3823}
3824
Jiajia Qind9671222016-11-29 16:30:31 +08003825bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04003826{
Jamie Madill250d33f2014-06-06 17:09:03 -04003827 switch (type)
3828 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003829 case GL_UNSIGNED_BYTE:
3830 case GL_UNSIGNED_SHORT:
3831 break;
3832 case GL_UNSIGNED_INT:
3833 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
3834 {
3835 context->handleError(Error(GL_INVALID_ENUM));
3836 return false;
3837 }
3838 break;
3839 default:
3840 context->handleError(Error(GL_INVALID_ENUM));
3841 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003842 }
3843
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003844 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003845
3846 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08003847 if (curTransformFeedback && curTransformFeedback->isActive() &&
3848 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04003849 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003850 // It is an invalid operation to call DrawElements, DrawRangeElements or
3851 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04003852 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04003853 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003854 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003855 }
3856
Jiajia Qind9671222016-11-29 16:30:31 +08003857 return true;
3858}
3859
3860bool ValidateDrawElements(ValidationContext *context,
3861 GLenum mode,
3862 GLsizei count,
3863 GLenum type,
3864 const GLvoid *indices,
3865 GLsizei primcount,
3866 IndexRange *indexRangeOut)
3867{
3868 if (!ValidateDrawElementsBase(context, type))
3869 return false;
3870
3871 const State &state = context->getGLState();
3872
Jamie Madill250d33f2014-06-06 17:09:03 -04003873 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04003874 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04003875 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003876 context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
Geoff Langb1196682014-07-23 13:47:29 -04003877 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04003878 }
3879
He Yunchaoced53ae2016-11-29 15:00:51 +08003880 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04003881 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04003882
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05003883 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
3884
3885 if (context->getExtensions().webglCompatibility)
3886 {
3887 ASSERT(isPow2(typeBytes) && typeBytes > 0);
3888 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
3889 {
3890 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
3891 // The offset arguments to drawElements and [...], must be a multiple of the size of the
3892 // data type passed to the call, or an INVALID_OPERATION error is generated.
3893 context->handleError(Error(GL_INVALID_OPERATION,
3894 "indices must be a multiple of the element type size."));
3895 return false;
3896 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003897
3898 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
3899 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
3900 // error is generated.
3901 if (reinterpret_cast<intptr_t>(indices) < 0)
3902 {
3903 context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
3904 return false;
3905 }
Geoff Langfeb8c682017-02-13 16:07:35 -05003906 }
3907
3908 if (context->getExtensions().webglCompatibility ||
3909 !context->getGLState().areClientArraysEnabled())
3910 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05003911 if (!elementArrayBuffer && count > 0)
3912 {
3913 // [WebGL 1.0] Section 6.2 No Client Side Arrays
3914 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
3915 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
3916 context->handleError(Error(GL_INVALID_OPERATION,
3917 "There is no element array buffer bound and count > 0."));
3918 return false;
3919 }
3920 }
3921
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003922 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04003923 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003924 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04003925 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003926 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
3927 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
3928 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
3929 constexpr uint64_t kMaxTypeSize = 8;
3930 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
3931 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
3932 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003933
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003934 uint64_t typeSize = typeBytes;
3935 uint64_t elementCount = static_cast<uint64_t>(count);
3936 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
3937
3938 // Doing the multiplication here is overflow-safe
3939 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
3940
3941 // The offset can be any value, check for overflows
3942 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
3943 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003944 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003945 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003946 return false;
3947 }
3948
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003949 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
3950 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003951 {
3952 context->handleError(
3953 Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
3954 return false;
3955 }
3956 }
3957 else if (!indices)
3958 {
3959 // This is an application error that would normally result in a crash,
3960 // but we catch it and return an error
3961 context->handleError(
3962 Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
Geoff Langb1196682014-07-23 13:47:29 -04003963 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04003964 }
Jamie Madillae3000b2014-08-25 15:47:51 -04003965 }
3966
Jiajia Qind9671222016-11-29 16:30:31 +08003967 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07003968 {
3969 return false;
3970 }
3971
Jamie Madill2b976812014-08-25 15:47:49 -04003972 // Use max index to validate if our vertex buffers are large enough for the pull.
3973 // TODO: offer fast path, with disabled index validation.
3974 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
3975 if (elementArrayBuffer)
3976 {
Jacek Cabana5521de2014-10-01 17:23:46 +02003977 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Geoff Lang3edfe032015-09-04 16:38:24 -04003978 Error error =
3979 elementArrayBuffer->getIndexRange(type, static_cast<size_t>(offset), count,
3980 state.isPrimitiveRestartEnabled(), indexRangeOut);
Geoff Lang520c4ae2015-05-05 13:12:36 -04003981 if (error.isError())
Jamie Madill2b976812014-08-25 15:47:49 -04003982 {
Jamie Madill437fa652016-05-03 15:13:24 -04003983 context->handleError(error);
Geoff Lang520c4ae2015-05-05 13:12:36 -04003984 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04003985 }
3986 }
3987 else
3988 {
Geoff Lang3edfe032015-09-04 16:38:24 -04003989 *indexRangeOut = ComputeIndexRange(type, indices, count, state.isPrimitiveRestartEnabled());
Jamie Madill2b976812014-08-25 15:47:49 -04003990 }
3991
Jamie Madille79b1e12015-11-04 16:36:37 -05003992 // If we use an index greater than our maximum supported index range, return an error.
3993 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
3994 // return an error if possible here.
3995 if (static_cast<GLuint64>(indexRangeOut->end) >= context->getCaps().maxElementIndex)
3996 {
Jamie Madill437fa652016-05-03 15:13:24 -04003997 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05003998 return false;
3999 }
4000
Corentin Wallez92db6942016-12-09 13:10:36 -05004001 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->end),
4002 static_cast<GLint>(indexRangeOut->vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04004003 {
4004 return false;
4005 }
4006
Geoff Lang3edfe032015-09-04 16:38:24 -04004007 // No op if there are no real indices in the index data (all are primitive restart).
4008 return (indexRangeOut->vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04004009}
4010
Geoff Langb1196682014-07-23 13:47:29 -04004011bool ValidateDrawElementsInstanced(Context *context,
Geoff Lang3edfe032015-09-04 16:38:24 -04004012 GLenum mode,
4013 GLsizei count,
4014 GLenum type,
4015 const GLvoid *indices,
4016 GLsizei primcount,
4017 IndexRange *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04004018{
4019 if (primcount < 0)
4020 {
Jamie Madill437fa652016-05-03 15:13:24 -04004021 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004022 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04004023 }
4024
Jamie Madill2b976812014-08-25 15:47:49 -04004025 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04004026 {
4027 return false;
4028 }
4029
4030 // No-op zero primitive count
4031 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04004032}
4033
Geoff Lang3edfe032015-09-04 16:38:24 -04004034bool ValidateDrawElementsInstancedANGLE(Context *context,
4035 GLenum mode,
4036 GLsizei count,
4037 GLenum type,
4038 const GLvoid *indices,
4039 GLsizei primcount,
4040 IndexRange *indexRangeOut)
Geoff Lang87a93302014-09-16 13:29:43 -04004041{
4042 if (!ValidateDrawInstancedANGLE(context))
4043 {
4044 return false;
4045 }
4046
He Yunchaoced53ae2016-11-29 15:00:51 +08004047 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount,
4048 indexRangeOut);
Geoff Lang87a93302014-09-16 13:29:43 -04004049}
4050
He Yunchaoced53ae2016-11-29 15:00:51 +08004051bool ValidateFramebufferTextureBase(Context *context,
4052 GLenum target,
4053 GLenum attachment,
4054 GLuint texture,
4055 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04004056{
Jamie Madill55ec3b12014-07-03 10:38:57 -04004057 if (!ValidFramebufferTarget(target))
4058 {
Jamie Madill437fa652016-05-03 15:13:24 -04004059 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04004060 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004061 }
4062
4063 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04004064 {
4065 return false;
4066 }
4067
Jamie Madill55ec3b12014-07-03 10:38:57 -04004068 if (texture != 0)
4069 {
4070 gl::Texture *tex = context->getTexture(texture);
4071
4072 if (tex == NULL)
4073 {
Jamie Madill437fa652016-05-03 15:13:24 -04004074 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004075 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004076 }
4077
4078 if (level < 0)
4079 {
Jamie Madill437fa652016-05-03 15:13:24 -04004080 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004081 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004082 }
4083 }
4084
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004085 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04004086 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04004087
Jamie Madill84115c92015-04-23 15:00:07 -04004088 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004089 {
Jamie Madill437fa652016-05-03 15:13:24 -04004090 context->handleError(
4091 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04004092 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004093 }
4094
4095 return true;
4096}
4097
He Yunchaoced53ae2016-11-29 15:00:51 +08004098bool ValidateFramebufferTexture2D(Context *context,
4099 GLenum target,
4100 GLenum attachment,
4101 GLenum textarget,
4102 GLuint texture,
4103 GLint level)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004104{
He Yunchaoced53ae2016-11-29 15:00:51 +08004105 // Attachments are required to be bound to level 0 without ES3 or the GL_OES_fbo_render_mipmap
4106 // extension
Martin Radev1be913c2016-07-11 17:59:16 +03004107 if (context->getClientMajorVersion() < 3 && !context->getExtensions().fboRenderMipmap &&
4108 level != 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04004109 {
Jamie Madill437fa652016-05-03 15:13:24 -04004110 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004111 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004112 }
4113
4114 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04004115 {
4116 return false;
4117 }
4118
Jamie Madill55ec3b12014-07-03 10:38:57 -04004119 if (texture != 0)
4120 {
4121 gl::Texture *tex = context->getTexture(texture);
4122 ASSERT(tex);
4123
Jamie Madill2a6564e2014-07-11 09:53:19 -04004124 const gl::Caps &caps = context->getCaps();
4125
Jamie Madill55ec3b12014-07-03 10:38:57 -04004126 switch (textarget)
4127 {
He Yunchaoced53ae2016-11-29 15:00:51 +08004128 case GL_TEXTURE_2D:
Jamie Madill55ec3b12014-07-03 10:38:57 -04004129 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04004130 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04004131 {
Jamie Madill437fa652016-05-03 15:13:24 -04004132 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004133 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004134 }
4135 if (tex->getTarget() != GL_TEXTURE_2D)
4136 {
JiangYizhoubddc46b2016-12-09 09:50:51 +08004137 context->handleError(Error(GL_INVALID_OPERATION,
4138 "Textarget must match the texture target type."));
Geoff Langb1196682014-07-23 13:47:29 -04004139 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004140 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004141 }
4142 break;
4143
He Yunchaoced53ae2016-11-29 15:00:51 +08004144 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4145 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4146 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4147 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4148 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4149 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
Jamie Madill55ec3b12014-07-03 10:38:57 -04004150 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04004151 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04004152 {
Jamie Madill437fa652016-05-03 15:13:24 -04004153 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004154 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004155 }
4156 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
4157 {
JiangYizhoubddc46b2016-12-09 09:50:51 +08004158 context->handleError(Error(GL_INVALID_OPERATION,
4159 "Textarget must match the texture target type."));
4160 return false;
4161 }
4162 }
4163 break;
4164
4165 case GL_TEXTURE_2D_MULTISAMPLE:
4166 {
4167 if (context->getClientVersion() < ES_3_1)
4168 {
4169 context->handleError(Error(GL_INVALID_OPERATION,
4170 "Texture target requires at least OpenGL ES 3.1."));
4171 return false;
4172 }
4173
4174 if (level != 0)
4175 {
4176 context->handleError(
4177 Error(GL_INVALID_VALUE, "Level must be 0 for TEXTURE_2D_MULTISAMPLE."));
4178 return false;
4179 }
4180 if (tex->getTarget() != GL_TEXTURE_2D_MULTISAMPLE)
4181 {
4182 context->handleError(Error(GL_INVALID_OPERATION,
4183 "Textarget must match the texture target type."));
Geoff Langb1196682014-07-23 13:47:29 -04004184 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004185 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004186 }
4187 break;
4188
He Yunchaoced53ae2016-11-29 15:00:51 +08004189 default:
4190 context->handleError(Error(GL_INVALID_ENUM));
4191 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04004192 }
Geoff Langa9be0dc2014-12-17 12:34:40 -05004193
Jamie Madilla3944d42016-07-22 22:13:26 -04004194 const Format &format = tex->getFormat(textarget, level);
4195 if (format.info->compressed)
Geoff Langa9be0dc2014-12-17 12:34:40 -05004196 {
Jamie Madill437fa652016-05-03 15:13:24 -04004197 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05004198 return false;
4199 }
Jamie Madill55ec3b12014-07-03 10:38:57 -04004200 }
4201
Jamie Madill570f7c82014-07-03 10:38:54 -04004202 return true;
4203}
4204
Geoff Langb1196682014-07-23 13:47:29 -04004205bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04004206{
4207 if (program == 0)
4208 {
Jamie Madill437fa652016-05-03 15:13:24 -04004209 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04004210 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004211 }
4212
Dian Xiang769769a2015-09-09 15:20:08 -07004213 gl::Program *programObject = GetValidProgram(context, program);
4214 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05004215 {
4216 return false;
4217 }
4218
Jamie Madill0063c512014-08-25 15:47:53 -04004219 if (!programObject || !programObject->isLinked())
4220 {
Jamie Madill437fa652016-05-03 15:13:24 -04004221 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004222 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004223 }
4224
Geoff Lang7dd2e102014-11-10 15:19:26 -05004225 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04004226 {
Jamie Madill437fa652016-05-03 15:13:24 -04004227 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04004228 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04004229 }
4230
Jamie Madill0063c512014-08-25 15:47:53 -04004231 return true;
4232}
4233
He Yunchaoced53ae2016-11-29 15:00:51 +08004234bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat *params)
Jamie Madill78f41802014-08-25 15:47:55 -04004235{
4236 return ValidateGetUniformBase(context, program, location);
4237}
4238
He Yunchaoced53ae2016-11-29 15:00:51 +08004239bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004240{
Jamie Madill78f41802014-08-25 15:47:55 -04004241 return ValidateGetUniformBase(context, program, location);
4242}
4243
Geoff Langf41d0ee2016-10-07 13:04:23 -04004244static bool ValidateSizedGetUniform(Context *context,
4245 GLuint program,
4246 GLint location,
4247 GLsizei bufSize,
4248 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04004249{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004250 if (length)
4251 {
4252 *length = 0;
4253 }
4254
Jamie Madill78f41802014-08-25 15:47:55 -04004255 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04004256 {
Jamie Madill78f41802014-08-25 15:47:55 -04004257 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004258 }
4259
Geoff Langf41d0ee2016-10-07 13:04:23 -04004260 if (bufSize < 0)
4261 {
4262 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
4263 return false;
4264 }
4265
Jamie Madilla502c742014-08-28 17:19:13 -04004266 gl::Program *programObject = context->getProgram(program);
4267 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04004268
Jamie Madill78f41802014-08-25 15:47:55 -04004269 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04004270 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08004271 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04004272 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04004273 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04004274 context->handleError(
4275 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04004276 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04004277 }
4278
Geoff Langf41d0ee2016-10-07 13:04:23 -04004279 if (length)
4280 {
Geoff Lang94177fb2016-11-14 16:12:26 -05004281 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04004282 }
4283
Jamie Madill0063c512014-08-25 15:47:53 -04004284 return true;
4285}
4286
He Yunchaoced53ae2016-11-29 15:00:51 +08004287bool ValidateGetnUniformfvEXT(Context *context,
4288 GLuint program,
4289 GLint location,
4290 GLsizei bufSize,
4291 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004292{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004293 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04004294}
4295
He Yunchaoced53ae2016-11-29 15:00:51 +08004296bool ValidateGetnUniformivEXT(Context *context,
4297 GLuint program,
4298 GLint location,
4299 GLsizei bufSize,
4300 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04004301{
Geoff Langf41d0ee2016-10-07 13:04:23 -04004302 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
4303}
4304
4305bool ValidateGetUniformfvRobustANGLE(Context *context,
4306 GLuint program,
4307 GLint location,
4308 GLsizei bufSize,
4309 GLsizei *length,
4310 GLfloat *params)
4311{
4312 if (!ValidateRobustEntryPoint(context, bufSize))
4313 {
4314 return false;
4315 }
4316
4317 // bufSize is validated in ValidateSizedGetUniform
4318 return ValidateSizedGetUniform(context, program, location, bufSize, length);
4319}
4320
4321bool ValidateGetUniformivRobustANGLE(Context *context,
4322 GLuint program,
4323 GLint location,
4324 GLsizei bufSize,
4325 GLsizei *length,
4326 GLint *params)
4327{
4328 if (!ValidateRobustEntryPoint(context, bufSize))
4329 {
4330 return false;
4331 }
4332
4333 // bufSize is validated in ValidateSizedGetUniform
4334 return ValidateSizedGetUniform(context, program, location, bufSize, length);
4335}
4336
4337bool ValidateGetUniformuivRobustANGLE(Context *context,
4338 GLuint program,
4339 GLint location,
4340 GLsizei bufSize,
4341 GLsizei *length,
4342 GLuint *params)
4343{
4344 if (!ValidateRobustEntryPoint(context, bufSize))
4345 {
4346 return false;
4347 }
4348
4349 if (context->getClientMajorVersion() < 3)
4350 {
4351 context->handleError(
4352 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
4353 return false;
4354 }
4355
4356 // bufSize is validated in ValidateSizedGetUniform
4357 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04004358}
4359
He Yunchaoced53ae2016-11-29 15:00:51 +08004360bool ValidateDiscardFramebufferBase(Context *context,
4361 GLenum target,
4362 GLsizei numAttachments,
4363 const GLenum *attachments,
4364 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07004365{
4366 if (numAttachments < 0)
4367 {
Jamie Madill437fa652016-05-03 15:13:24 -04004368 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07004369 return false;
4370 }
4371
4372 for (GLsizei i = 0; i < numAttachments; ++i)
4373 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02004374 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07004375 {
4376 if (defaultFramebuffer)
4377 {
Jamie Madill437fa652016-05-03 15:13:24 -04004378 context->handleError(Error(
4379 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07004380 return false;
4381 }
4382
4383 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
4384 {
Jamie Madill437fa652016-05-03 15:13:24 -04004385 context->handleError(Error(GL_INVALID_OPERATION,
4386 "Requested color attachment is greater than the maximum "
4387 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07004388 return false;
4389 }
4390 }
4391 else
4392 {
4393 switch (attachments[i])
4394 {
He Yunchaoced53ae2016-11-29 15:00:51 +08004395 case GL_DEPTH_ATTACHMENT:
4396 case GL_STENCIL_ATTACHMENT:
4397 case GL_DEPTH_STENCIL_ATTACHMENT:
4398 if (defaultFramebuffer)
4399 {
4400 context->handleError(
4401 Error(GL_INVALID_ENUM,
4402 "Invalid attachment when the default framebuffer is bound"));
4403 return false;
4404 }
4405 break;
4406 case GL_COLOR:
4407 case GL_DEPTH:
4408 case GL_STENCIL:
4409 if (!defaultFramebuffer)
4410 {
4411 context->handleError(
4412 Error(GL_INVALID_ENUM,
4413 "Invalid attachment when the default framebuffer is not bound"));
4414 return false;
4415 }
4416 break;
4417 default:
4418 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07004419 return false;
Austin Kinross08332632015-05-05 13:35:47 -07004420 }
4421 }
4422 }
4423
4424 return true;
4425}
4426
Austin Kinross6ee1e782015-05-29 17:05:37 -07004427bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
4428{
4429 // Note that debug marker calls must not set error state
4430
4431 if (length < 0)
4432 {
4433 return false;
4434 }
4435
4436 if (marker == nullptr)
4437 {
4438 return false;
4439 }
4440
4441 return true;
4442}
4443
4444bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
4445{
4446 // Note that debug marker calls must not set error state
4447
4448 if (length < 0)
4449 {
4450 return false;
4451 }
4452
4453 if (length > 0 && marker == nullptr)
4454 {
4455 return false;
4456 }
4457
4458 return true;
4459}
4460
Geoff Langdcab33b2015-07-21 13:03:16 -04004461bool ValidateEGLImageTargetTexture2DOES(Context *context,
4462 egl::Display *display,
4463 GLenum target,
4464 egl::Image *image)
4465{
Geoff Langa8406172015-07-21 16:53:39 -04004466 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
4467 {
Jamie Madill437fa652016-05-03 15:13:24 -04004468 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04004469 return false;
4470 }
4471
4472 switch (target)
4473 {
4474 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04004475 if (!context->getExtensions().eglImage)
4476 {
4477 context->handleError(Error(
4478 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
4479 }
4480 break;
4481
4482 case GL_TEXTURE_EXTERNAL_OES:
4483 if (!context->getExtensions().eglImageExternal)
4484 {
4485 context->handleError(Error(
4486 GL_INVALID_ENUM,
4487 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
4488 }
Geoff Langa8406172015-07-21 16:53:39 -04004489 break;
4490
4491 default:
Jamie Madill437fa652016-05-03 15:13:24 -04004492 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04004493 return false;
4494 }
4495
4496 if (!display->isValidImage(image))
4497 {
Jamie Madill437fa652016-05-03 15:13:24 -04004498 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04004499 return false;
4500 }
4501
4502 if (image->getSamples() > 0)
4503 {
Jamie Madill437fa652016-05-03 15:13:24 -04004504 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04004505 "cannot create a 2D texture from a multisampled EGL image."));
4506 return false;
4507 }
4508
Geoff Langca271392017-04-05 12:30:00 -04004509 const TextureCaps &textureCaps =
4510 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
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
Geoff Langca271392017-04-05 12:30:00 -04004548 const TextureCaps &textureCaps =
4549 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04004550 if (!textureCaps.renderable)
4551 {
Jamie Madill437fa652016-05-03 15:13:24 -04004552 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04004553 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
4554 return false;
4555 }
4556
Geoff Langdcab33b2015-07-21 13:03:16 -04004557 return true;
4558}
Austin Kinrossbc781f32015-10-26 09:27:38 -07004559
4560bool ValidateBindVertexArrayBase(Context *context, GLuint array)
4561{
Geoff Lang36167ab2015-12-07 10:27:14 -05004562 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07004563 {
4564 // The default VAO should always exist
4565 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04004566 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07004567 return false;
4568 }
4569
4570 return true;
4571}
4572
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004573bool ValidateLinkProgram(Context *context, GLuint program)
4574{
4575 if (context->hasActiveTransformFeedback(program))
4576 {
4577 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004578 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004579 "Cannot link program while program is associated with an active "
4580 "transform feedback object."));
4581 return false;
4582 }
Jamie Madillc1d770e2017-04-13 17:31:24 -04004583
4584 Program *programObject = GetValidProgram(context, program);
4585 if (!programObject)
4586 {
4587 return false;
4588 }
4589
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004590 return true;
4591}
4592
Geoff Langc5629752015-12-07 16:29:04 -05004593bool ValidateProgramBinaryBase(Context *context,
4594 GLuint program,
4595 GLenum binaryFormat,
4596 const void *binary,
4597 GLint length)
4598{
4599 Program *programObject = GetValidProgram(context, program);
4600 if (programObject == nullptr)
4601 {
4602 return false;
4603 }
4604
4605 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
4606 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
4607 programBinaryFormats.end())
4608 {
Jamie Madill437fa652016-05-03 15:13:24 -04004609 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05004610 return false;
4611 }
4612
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004613 if (context->hasActiveTransformFeedback(program))
4614 {
4615 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004616 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004617 "Cannot change program binary while program is associated with "
4618 "an active transform feedback object."));
4619 return false;
4620 }
4621
Geoff Langc5629752015-12-07 16:29:04 -05004622 return true;
4623}
4624
4625bool ValidateGetProgramBinaryBase(Context *context,
4626 GLuint program,
4627 GLsizei bufSize,
4628 GLsizei *length,
4629 GLenum *binaryFormat,
4630 void *binary)
4631{
4632 Program *programObject = GetValidProgram(context, program);
4633 if (programObject == nullptr)
4634 {
4635 return false;
4636 }
4637
4638 if (!programObject->isLinked())
4639 {
Jamie Madill437fa652016-05-03 15:13:24 -04004640 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05004641 return false;
4642 }
4643
Jamie Madilla7d12dc2016-12-13 15:08:19 -05004644 if (context->getCaps().programBinaryFormats.empty())
4645 {
4646 context->handleError(Error(GL_INVALID_OPERATION, "No program binary formats supported."));
4647 return false;
4648 }
4649
Geoff Langc5629752015-12-07 16:29:04 -05004650 return true;
4651}
Jamie Madillc29968b2016-01-20 11:17:23 -05004652
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004653bool ValidateUseProgram(Context *context, GLuint program)
4654{
4655 if (program != 0)
4656 {
4657 Program *programObject = context->getProgram(program);
4658 if (!programObject)
4659 {
4660 // ES 3.1.0 section 7.3 page 72
4661 if (context->getShader(program))
4662 {
Jamie Madill437fa652016-05-03 15:13:24 -04004663 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004664 Error(GL_INVALID_OPERATION,
4665 "Attempted to use a single shader instead of a shader program."));
4666 return false;
4667 }
4668 else
4669 {
Jamie Madill437fa652016-05-03 15:13:24 -04004670 context->handleError(Error(GL_INVALID_VALUE, "Program invalid."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004671 return false;
4672 }
4673 }
4674 if (!programObject->isLinked())
4675 {
Jamie Madill437fa652016-05-03 15:13:24 -04004676 context->handleError(Error(GL_INVALID_OPERATION, "Program not linked."));
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004677 return false;
4678 }
4679 }
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004680 if (context->getGLState().isTransformFeedbackActiveUnpaused())
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004681 {
4682 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04004683 context->handleError(
Olli Etuahoc3e55a42016-03-09 16:29:18 +02004684 Error(GL_INVALID_OPERATION,
4685 "Cannot change active program while transform feedback is unpaused."));
4686 return false;
4687 }
4688
4689 return true;
4690}
4691
Jamie Madillc29968b2016-01-20 11:17:23 -05004692bool ValidateCopyTexImage2D(ValidationContext *context,
4693 GLenum target,
4694 GLint level,
4695 GLenum internalformat,
4696 GLint x,
4697 GLint y,
4698 GLsizei width,
4699 GLsizei height,
4700 GLint border)
4701{
Martin Radev1be913c2016-07-11 17:59:16 +03004702 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05004703 {
4704 return ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, 0,
4705 0, x, y, width, height, border);
4706 }
4707
Martin Radev1be913c2016-07-11 17:59:16 +03004708 ASSERT(context->getClientMajorVersion() == 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05004709 return ValidateES3CopyTexImage2DParameters(context, target, level, internalformat, false, 0, 0,
4710 0, x, y, width, height, border);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004711}
Jamie Madillc29968b2016-01-20 11:17:23 -05004712
4713bool ValidateFramebufferRenderbuffer(Context *context,
4714 GLenum target,
4715 GLenum attachment,
4716 GLenum renderbuffertarget,
4717 GLuint renderbuffer)
4718{
4719 if (!ValidFramebufferTarget(target) ||
4720 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
4721 {
Jamie Madill437fa652016-05-03 15:13:24 -04004722 context->handleError(Error(GL_INVALID_ENUM));
Jamie Madillc29968b2016-01-20 11:17:23 -05004723 return false;
4724 }
4725
4726 return ValidateFramebufferRenderbufferParameters(context, target, attachment,
4727 renderbuffertarget, renderbuffer);
4728}
4729
4730bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
4731{
4732 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
4733 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
4734 {
Jamie Madill437fa652016-05-03 15:13:24 -04004735 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05004736 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
4737 return false;
4738 }
4739
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004740 ASSERT(context->getGLState().getDrawFramebuffer());
4741 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05004742 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
4743
4744 // This should come first before the check for the default frame buffer
4745 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
4746 // rather than INVALID_OPERATION
4747 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
4748 {
4749 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
4750
4751 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02004752 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
4753 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05004754 {
4755 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02004756 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
4757 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
4758 // 3.1 is still a bit ambiguous about the error, but future specs are
4759 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04004760 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02004761 return false;
4762 }
4763 else if (bufs[colorAttachment] >= maxColorAttachment)
4764 {
Jamie Madill437fa652016-05-03 15:13:24 -04004765 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02004766 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05004767 return false;
4768 }
4769 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
4770 frameBufferId != 0)
4771 {
4772 // INVALID_OPERATION-GL is bound to buffer and ith argument
4773 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04004774 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05004775 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
4776 return false;
4777 }
4778 }
4779
4780 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
4781 // and n is not 1 or bufs is bound to value other than BACK and NONE
4782 if (frameBufferId == 0)
4783 {
4784 if (n != 1)
4785 {
Jamie Madill437fa652016-05-03 15:13:24 -04004786 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05004787 "n must be 1 when GL is bound to the default framebuffer"));
4788 return false;
4789 }
4790
4791 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
4792 {
Jamie Madill437fa652016-05-03 15:13:24 -04004793 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05004794 GL_INVALID_OPERATION,
4795 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
4796 return false;
4797 }
4798 }
4799
4800 return true;
4801}
4802
4803bool ValidateCopyTexSubImage2D(Context *context,
4804 GLenum target,
4805 GLint level,
4806 GLint xoffset,
4807 GLint yoffset,
4808 GLint x,
4809 GLint y,
4810 GLsizei width,
4811 GLsizei height)
4812{
Martin Radev1be913c2016-07-11 17:59:16 +03004813 if (context->getClientMajorVersion() < 3)
Jamie Madillc29968b2016-01-20 11:17:23 -05004814 {
4815 return ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset,
4816 yoffset, x, y, width, height, 0);
4817 }
4818
Ian Ewellfc7cf8e2016-01-20 15:57:46 -05004819 return ValidateES3CopyTexImage2DParameters(context, target, level, GL_NONE, true, xoffset,
4820 yoffset, 0, x, y, width, height, 0);
Jamie Madillc29968b2016-01-20 11:17:23 -05004821}
4822
Geoff Lang496c02d2016-10-20 11:38:11 -07004823bool ValidateGetBufferPointervBase(Context *context,
4824 GLenum target,
4825 GLenum pname,
4826 GLsizei *length,
4827 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03004828{
Geoff Lang496c02d2016-10-20 11:38:11 -07004829 if (length)
4830 {
4831 *length = 0;
4832 }
4833
4834 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
4835 {
4836 context->handleError(
4837 Error(GL_INVALID_OPERATION,
Jamie Madillcc6ac252017-01-25 12:57:21 -08004838 "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
Geoff Lang496c02d2016-10-20 11:38:11 -07004839 return false;
4840 }
4841
Olli Etuaho4f667482016-03-30 15:56:35 +03004842 if (!ValidBufferTarget(context, target))
4843 {
Jamie Madill437fa652016-05-03 15:13:24 -04004844 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03004845 return false;
4846 }
4847
Geoff Lang496c02d2016-10-20 11:38:11 -07004848 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03004849 {
Geoff Lang496c02d2016-10-20 11:38:11 -07004850 case GL_BUFFER_MAP_POINTER:
4851 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03004852
Geoff Lang496c02d2016-10-20 11:38:11 -07004853 default:
4854 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4855 return false;
4856 }
Olli Etuaho4f667482016-03-30 15:56:35 +03004857
4858 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
4859 // target bound to zero generate an INVALID_OPERATION error."
4860 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07004861 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03004862 {
Jamie Madill437fa652016-05-03 15:13:24 -04004863 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004864 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
4865 return false;
4866 }
4867
Geoff Lang496c02d2016-10-20 11:38:11 -07004868 if (length)
4869 {
4870 *length = 1;
4871 }
4872
Olli Etuaho4f667482016-03-30 15:56:35 +03004873 return true;
4874}
4875
4876bool ValidateUnmapBufferBase(Context *context, GLenum target)
4877{
4878 if (!ValidBufferTarget(context, target))
4879 {
Jamie Madill437fa652016-05-03 15:13:24 -04004880 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004881 return false;
4882 }
4883
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004884 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03004885
4886 if (buffer == nullptr || !buffer->isMapped())
4887 {
Jamie Madill437fa652016-05-03 15:13:24 -04004888 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004889 return false;
4890 }
4891
4892 return true;
4893}
4894
4895bool ValidateMapBufferRangeBase(Context *context,
4896 GLenum target,
4897 GLintptr offset,
4898 GLsizeiptr length,
4899 GLbitfield access)
4900{
4901 if (!ValidBufferTarget(context, target))
4902 {
Jamie Madill437fa652016-05-03 15:13:24 -04004903 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004904 return false;
4905 }
4906
4907 if (offset < 0 || length < 0)
4908 {
Jamie Madill437fa652016-05-03 15:13:24 -04004909 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004910 return false;
4911 }
4912
Jamie Madilldfde6ab2016-06-09 07:07:18 -07004913 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03004914
4915 if (!buffer)
4916 {
Jamie Madill437fa652016-05-03 15:13:24 -04004917 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004918 return false;
4919 }
4920
4921 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04004922 CheckedNumeric<size_t> checkedOffset(offset);
4923 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03004924
Jamie Madille2e406c2016-06-02 13:04:10 -04004925 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03004926 {
Jamie Madill437fa652016-05-03 15:13:24 -04004927 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004928 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
4929 return false;
4930 }
4931
4932 // Check for invalid bits in the mask
4933 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
4934 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
4935 GL_MAP_UNSYNCHRONIZED_BIT;
4936
4937 if (access & ~(allAccessBits))
4938 {
Jamie Madill437fa652016-05-03 15:13:24 -04004939 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03004940 return false;
4941 }
4942
4943 if (length == 0)
4944 {
Jamie Madill437fa652016-05-03 15:13:24 -04004945 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004946 return false;
4947 }
4948
4949 if (buffer->isMapped())
4950 {
Jamie Madill437fa652016-05-03 15:13:24 -04004951 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004952 return false;
4953 }
4954
4955 // Check for invalid bit combinations
4956 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
4957 {
Jamie Madill437fa652016-05-03 15:13:24 -04004958 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03004959 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
4960 return false;
4961 }
4962
4963 GLbitfield writeOnlyBits =
4964 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
4965
4966 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
4967 {
Jamie Madill437fa652016-05-03 15:13:24 -04004968 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03004969 "Invalid access bits when mapping buffer for reading: 0x%X.",
4970 access));
4971 return false;
4972 }
4973
4974 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
4975 {
Jamie Madill437fa652016-05-03 15:13:24 -04004976 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03004977 GL_INVALID_OPERATION,
4978 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
4979 return false;
4980 }
4981 return true;
4982}
4983
4984bool ValidateFlushMappedBufferRangeBase(Context *context,
4985 GLenum target,
4986 GLintptr offset,
4987 GLsizeiptr length)
4988{
4989 if (offset < 0 || length < 0)
4990 {
Jamie Madill437fa652016-05-03 15:13:24 -04004991 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004992 return false;
4993 }
4994
4995 if (!ValidBufferTarget(context, target))
4996 {
Jamie Madill437fa652016-05-03 15:13:24 -04004997 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03004998 return false;
4999 }
5000
Jamie Madilldfde6ab2016-06-09 07:07:18 -07005001 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03005002
5003 if (buffer == nullptr)
5004 {
Jamie Madill437fa652016-05-03 15:13:24 -04005005 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03005006 return false;
5007 }
5008
5009 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
5010 {
Jamie Madill437fa652016-05-03 15:13:24 -04005011 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03005012 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
5013 return false;
5014 }
5015
5016 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04005017 CheckedNumeric<size_t> checkedOffset(offset);
5018 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03005019
Jamie Madille2e406c2016-06-02 13:04:10 -04005020 if (!checkedSize.IsValid() ||
5021 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03005022 {
Jamie Madill437fa652016-05-03 15:13:24 -04005023 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03005024 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
5025 return false;
5026 }
5027
5028 return true;
5029}
5030
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005031bool ValidateGenerateMipmap(Context *context, GLenum target)
5032{
5033 if (!ValidTextureTarget(context, target))
5034 {
5035 context->handleError(Error(GL_INVALID_ENUM));
5036 return false;
5037 }
5038
5039 Texture *texture = context->getTargetTexture(target);
5040
5041 if (texture == nullptr)
5042 {
5043 context->handleError(Error(GL_INVALID_OPERATION));
5044 return false;
5045 }
5046
5047 const GLuint effectiveBaseLevel = texture->getTextureState().getEffectiveBaseLevel();
5048
5049 // This error isn't spelled out in the spec in a very explicit way, but we interpret the spec so
5050 // that out-of-range base level has a non-color-renderable / non-texture-filterable format.
5051 if (effectiveBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
5052 {
5053 context->handleError(Error(GL_INVALID_OPERATION));
5054 return false;
5055 }
5056
Jamie Madilla3944d42016-07-22 22:13:26 -04005057 GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
5058 const auto &format = texture->getFormat(baseTarget, effectiveBaseLevel);
Geoff Langca271392017-04-05 12:30:00 -04005059 const TextureCaps &formatCaps = context->getTextureCaps().get(format.info->sizedInternalFormat);
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005060
5061 // GenerateMipmap should not generate an INVALID_OPERATION for textures created with
5062 // unsized formats or that are color renderable and filterable. Since we do not track if
5063 // the texture was created with sized or unsized format (only sized formats are stored),
5064 // it is not possible to make sure the the LUMA formats can generate mipmaps (they should
5065 // be able to) because they aren't color renderable. Simply do a special case for LUMA
5066 // textures since they're the only texture format that can be created with unsized formats
5067 // that is not color renderable. New unsized formats are unlikely to be added, since ES2
5068 // was the last version to use add them.
Jamie Madilla3944d42016-07-22 22:13:26 -04005069 if (format.info->depthBits > 0 || format.info->stencilBits > 0 || !formatCaps.filterable ||
5070 (!formatCaps.renderable && !format.info->isLUMA()) || format.info->compressed)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005071 {
5072 context->handleError(Error(GL_INVALID_OPERATION));
5073 return false;
5074 }
5075
5076 // GL_EXT_sRGB does not support mipmap generation on sRGB textures
Jamie Madilla3944d42016-07-22 22:13:26 -04005077 if (context->getClientMajorVersion() == 2 && format.info->colorEncoding == GL_SRGB)
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005078 {
5079 context->handleError(Error(GL_INVALID_OPERATION));
5080 return false;
5081 }
5082
5083 // Non-power of 2 ES2 check
Geoff Lang55482a12016-11-21 16:54:01 -05005084 if (context->getClientVersion() < Version(3, 0) && !context->getExtensions().textureNPOT &&
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005085 (!isPow2(static_cast<int>(texture->getWidth(baseTarget, 0))) ||
5086 !isPow2(static_cast<int>(texture->getHeight(baseTarget, 0)))))
5087 {
Geoff Lang55482a12016-11-21 16:54:01 -05005088 ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
Olli Etuaho0f2b1562016-05-13 16:15:35 +03005089 context->handleError(Error(GL_INVALID_OPERATION));
5090 return false;
5091 }
5092
5093 // Cube completeness check
5094 if (target == GL_TEXTURE_CUBE_MAP && !texture->getTextureState().isCubeComplete())
5095 {
5096 context->handleError(Error(GL_INVALID_OPERATION));
5097 return false;
5098 }
5099
5100 return true;
5101}
5102
Olli Etuaho41997e72016-03-10 13:38:39 +02005103bool ValidateGenBuffers(Context *context, GLint n, GLuint *)
5104{
5105 return ValidateGenOrDelete(context, n);
5106}
5107
5108bool ValidateDeleteBuffers(Context *context, GLint n, const GLuint *)
5109{
5110 return ValidateGenOrDelete(context, n);
5111}
5112
5113bool ValidateGenFramebuffers(Context *context, GLint n, GLuint *)
5114{
5115 return ValidateGenOrDelete(context, n);
5116}
5117
5118bool ValidateDeleteFramebuffers(Context *context, GLint n, const GLuint *)
5119{
5120 return ValidateGenOrDelete(context, n);
5121}
5122
5123bool ValidateGenRenderbuffers(Context *context, GLint n, GLuint *)
5124{
5125 return ValidateGenOrDelete(context, n);
5126}
5127
5128bool ValidateDeleteRenderbuffers(Context *context, GLint n, const GLuint *)
5129{
5130 return ValidateGenOrDelete(context, n);
5131}
5132
5133bool ValidateGenTextures(Context *context, GLint n, GLuint *)
5134{
5135 return ValidateGenOrDelete(context, n);
5136}
5137
5138bool ValidateDeleteTextures(Context *context, GLint n, const GLuint *)
5139{
5140 return ValidateGenOrDelete(context, n);
5141}
5142
5143bool ValidateGenOrDelete(Context *context, GLint n)
5144{
5145 if (n < 0)
5146 {
Jamie Madill437fa652016-05-03 15:13:24 -04005147 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02005148 return false;
5149 }
5150 return true;
5151}
5152
Geoff Langf41a7152016-09-19 15:11:17 -04005153bool ValidateEnable(Context *context, GLenum cap)
5154{
5155 if (!ValidCap(context, cap, false))
5156 {
5157 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5158 return false;
5159 }
5160
5161 if (context->getLimitations().noSampleAlphaToCoverageSupport &&
5162 cap == GL_SAMPLE_ALPHA_TO_COVERAGE)
5163 {
5164 const char *errorMessage = "Current renderer doesn't support alpha-to-coverage";
5165 context->handleError(Error(GL_INVALID_OPERATION, errorMessage));
5166
5167 // We also output an error message to the debugger window if tracing is active, so that
5168 // developers can see the error message.
Yuly Novikovd73f8522017-01-13 17:48:57 -05005169 ERR() << errorMessage;
Geoff Langf41a7152016-09-19 15:11:17 -04005170 return false;
5171 }
5172
5173 return true;
5174}
5175
5176bool ValidateDisable(Context *context, GLenum cap)
5177{
5178 if (!ValidCap(context, cap, false))
5179 {
5180 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5181 return false;
5182 }
5183
5184 return true;
5185}
5186
5187bool ValidateIsEnabled(Context *context, GLenum cap)
5188{
5189 if (!ValidCap(context, cap, true))
5190 {
5191 context->handleError(Error(GL_INVALID_ENUM, "Invalid cap."));
5192 return false;
5193 }
5194
5195 return true;
5196}
5197
Geoff Langff5b2d52016-09-07 11:32:23 -04005198bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
5199{
5200 if (!context->getExtensions().robustClientMemory)
5201 {
5202 context->handleError(
5203 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
5204 return false;
5205 }
5206
5207 if (bufSize < 0)
5208 {
5209 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
5210 return false;
5211 }
5212
5213 return true;
5214}
5215
Geoff Lang2e43dbb2016-10-14 12:27:35 -04005216bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
5217{
5218 if (bufSize < numParams)
5219 {
5220 context->handleError(Error(GL_INVALID_OPERATION,
5221 "%u parameters are required but %i were provided.", numParams,
5222 bufSize));
5223 return false;
5224 }
5225
5226 return true;
5227}
5228
Geoff Langff5b2d52016-09-07 11:32:23 -04005229bool ValidateGetFramebufferAttachmentParameteriv(ValidationContext *context,
5230 GLenum target,
5231 GLenum attachment,
5232 GLenum pname,
5233 GLsizei *numParams)
5234{
5235 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08005236 if (numParams)
5237 {
5238 *numParams = 1;
5239 }
Geoff Langff5b2d52016-09-07 11:32:23 -04005240
5241 if (!ValidFramebufferTarget(target))
5242 {
5243 context->handleError(Error(GL_INVALID_ENUM));
5244 return false;
5245 }
5246
5247 int clientVersion = context->getClientMajorVersion();
5248
5249 switch (pname)
5250 {
5251 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5252 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5253 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5254 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5255 break;
5256
5257 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
5258 if (clientVersion < 3 && !context->getExtensions().sRGB)
5259 {
5260 context->handleError(Error(GL_INVALID_ENUM));
5261 return false;
5262 }
5263 break;
5264
5265 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
5266 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
5267 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
5268 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
5269 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
5270 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
5271 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5272 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5273 if (clientVersion < 3)
5274 {
5275 context->handleError(Error(GL_INVALID_ENUM));
5276 return false;
5277 }
5278 break;
5279
5280 default:
5281 context->handleError(Error(GL_INVALID_ENUM));
5282 return false;
5283 }
5284
5285 // Determine if the attachment is a valid enum
5286 switch (attachment)
5287 {
5288 case GL_BACK:
5289 case GL_FRONT:
5290 case GL_DEPTH:
5291 case GL_STENCIL:
5292 case GL_DEPTH_STENCIL_ATTACHMENT:
5293 if (clientVersion < 3)
5294 {
5295 context->handleError(Error(GL_INVALID_ENUM));
5296 return false;
5297 }
5298 break;
5299
5300 case GL_DEPTH_ATTACHMENT:
5301 case GL_STENCIL_ATTACHMENT:
5302 break;
5303
5304 default:
5305 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
5306 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
5307 {
5308 context->handleError(Error(GL_INVALID_ENUM));
5309 return false;
5310 }
5311 break;
5312 }
5313
5314 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
5315 ASSERT(framebuffer);
5316
5317 if (framebuffer->id() == 0)
5318 {
5319 if (clientVersion < 3)
5320 {
5321 context->handleError(Error(GL_INVALID_OPERATION));
5322 return false;
5323 }
5324
5325 switch (attachment)
5326 {
5327 case GL_BACK:
5328 case GL_DEPTH:
5329 case GL_STENCIL:
5330 break;
5331
5332 default:
5333 context->handleError(Error(GL_INVALID_OPERATION));
5334 return false;
5335 }
5336 }
5337 else
5338 {
5339 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
5340 {
5341 // Valid attachment query
5342 }
5343 else
5344 {
5345 switch (attachment)
5346 {
5347 case GL_DEPTH_ATTACHMENT:
5348 case GL_STENCIL_ATTACHMENT:
5349 break;
5350
5351 case GL_DEPTH_STENCIL_ATTACHMENT:
5352 if (!framebuffer->hasValidDepthStencil())
5353 {
5354 context->handleError(Error(GL_INVALID_OPERATION));
5355 return false;
5356 }
5357 break;
5358
5359 default:
5360 context->handleError(Error(GL_INVALID_OPERATION));
5361 return false;
5362 }
5363 }
5364 }
5365
5366 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
5367 if (attachmentObject)
5368 {
5369 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
5370 attachmentObject->type() == GL_TEXTURE ||
5371 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
5372
5373 switch (pname)
5374 {
5375 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5376 if (attachmentObject->type() != GL_RENDERBUFFER &&
5377 attachmentObject->type() != GL_TEXTURE)
5378 {
5379 context->handleError(Error(GL_INVALID_ENUM));
5380 return false;
5381 }
5382 break;
5383
5384 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
5385 if (attachmentObject->type() != GL_TEXTURE)
5386 {
5387 context->handleError(Error(GL_INVALID_ENUM));
5388 return false;
5389 }
5390 break;
5391
5392 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
5393 if (attachmentObject->type() != GL_TEXTURE)
5394 {
5395 context->handleError(Error(GL_INVALID_ENUM));
5396 return false;
5397 }
5398 break;
5399
5400 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
5401 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
5402 {
5403 context->handleError(Error(GL_INVALID_OPERATION));
5404 return false;
5405 }
5406 break;
5407
5408 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
5409 if (attachmentObject->type() != GL_TEXTURE)
5410 {
5411 context->handleError(Error(GL_INVALID_ENUM));
5412 return false;
5413 }
5414 break;
5415
5416 default:
5417 break;
5418 }
5419 }
5420 else
5421 {
5422 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
5423 // is NONE, then querying any other pname will generate INVALID_ENUM.
5424
5425 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
5426 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
5427 // INVALID_OPERATION for all other pnames
5428
5429 switch (pname)
5430 {
5431 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
5432 break;
5433
5434 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
5435 if (clientVersion < 3)
5436 {
5437 context->handleError(Error(GL_INVALID_ENUM));
5438 return false;
5439 }
5440 break;
5441
5442 default:
5443 if (clientVersion < 3)
5444 {
5445 context->handleError(Error(GL_INVALID_ENUM));
5446 return false;
5447 }
5448 else
5449 {
5450 context->handleError(Error(GL_INVALID_OPERATION));
5451 return false;
5452 }
5453 }
5454 }
5455
5456 return true;
5457}
5458
5459bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
5460 GLenum target,
5461 GLenum attachment,
5462 GLenum pname,
5463 GLsizei bufSize,
5464 GLsizei *numParams)
5465{
5466 if (!ValidateRobustEntryPoint(context, bufSize))
5467 {
5468 return false;
5469 }
5470
5471 if (!ValidateGetFramebufferAttachmentParameteriv(context, target, attachment, pname, numParams))
5472 {
5473 return false;
5474 }
5475
5476 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
5477 {
5478 return false;
5479 }
5480
5481 return true;
5482}
5483
5484bool ValidateGetBufferParameteriv(ValidationContext *context,
5485 GLenum target,
5486 GLenum pname,
Geoff Langebebe1c2016-10-14 12:01:31 -04005487 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04005488{
Geoff Langebebe1c2016-10-14 12:01:31 -04005489 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
Geoff Langff5b2d52016-09-07 11:32:23 -04005490}
5491
5492bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
5493 GLenum target,
5494 GLenum pname,
5495 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04005496 GLsizei *length,
5497 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04005498{
5499 if (!ValidateRobustEntryPoint(context, bufSize))
5500 {
5501 return false;
5502 }
5503
Geoff Langebebe1c2016-10-14 12:01:31 -04005504 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04005505 {
5506 return false;
5507 }
5508
Geoff Langebebe1c2016-10-14 12:01:31 -04005509 if (!ValidateRobustBufferSize(context, bufSize, *length))
5510 {
5511 return false;
5512 }
5513
5514 return true;
5515}
5516
5517bool ValidateGetBufferParameteri64v(ValidationContext *context,
5518 GLenum target,
5519 GLenum pname,
5520 GLint64 *params)
5521{
5522 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
5523}
5524
5525bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
5526 GLenum target,
5527 GLenum pname,
5528 GLsizei bufSize,
5529 GLsizei *length,
5530 GLint64 *params)
5531{
5532 if (!ValidateRobustEntryPoint(context, bufSize))
5533 {
5534 return false;
5535 }
5536
5537 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
5538 {
5539 return false;
5540 }
5541
5542 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04005543 {
5544 return false;
5545 }
5546
5547 return true;
5548}
5549
5550bool ValidateGetProgramiv(Context *context, GLuint program, GLenum pname, GLsizei *numParams)
5551{
5552 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08005553 if (numParams)
5554 {
5555 *numParams = 1;
5556 }
Geoff Langff5b2d52016-09-07 11:32:23 -04005557
5558 Program *programObject = GetValidProgram(context, program);
5559 if (!programObject)
5560 {
5561 return false;
5562 }
5563
5564 switch (pname)
5565 {
5566 case GL_DELETE_STATUS:
5567 case GL_LINK_STATUS:
5568 case GL_VALIDATE_STATUS:
5569 case GL_INFO_LOG_LENGTH:
5570 case GL_ATTACHED_SHADERS:
5571 case GL_ACTIVE_ATTRIBUTES:
5572 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
5573 case GL_ACTIVE_UNIFORMS:
5574 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
5575 break;
5576
5577 case GL_PROGRAM_BINARY_LENGTH:
5578 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
5579 {
5580 context->handleError(Error(GL_INVALID_ENUM,
5581 "Querying GL_PROGRAM_BINARY_LENGTH requires "
5582 "GL_OES_get_program_binary or ES 3.0."));
5583 return false;
5584 }
5585 break;
5586
5587 case GL_ACTIVE_UNIFORM_BLOCKS:
5588 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
5589 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
5590 case GL_TRANSFORM_FEEDBACK_VARYINGS:
5591 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
5592 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
5593 if (context->getClientMajorVersion() < 3)
5594 {
5595 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
5596 return false;
5597 }
5598 break;
5599
Yunchao He61afff12017-03-14 15:34:03 +08005600 case GL_PROGRAM_SEPARABLE:
5601 if (context->getClientVersion() < Version(3, 1))
5602 {
5603 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.1."));
5604 return false;
5605 }
5606 break;
5607
Geoff Langff5b2d52016-09-07 11:32:23 -04005608 default:
5609 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
5610 return false;
5611 }
5612
5613 return true;
5614}
5615
5616bool ValidateGetProgramivRobustANGLE(Context *context,
5617 GLuint program,
5618 GLenum pname,
5619 GLsizei bufSize,
5620 GLsizei *numParams)
5621{
5622 if (!ValidateRobustEntryPoint(context, bufSize))
5623 {
5624 return false;
5625 }
5626
5627 if (!ValidateGetProgramiv(context, program, pname, numParams))
5628 {
5629 return false;
5630 }
5631
5632 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
5633 {
5634 return false;
5635 }
5636
5637 return true;
5638}
5639
Geoff Lang740d9022016-10-07 11:20:52 -04005640bool ValidateGetRenderbufferParameteriv(Context *context,
5641 GLenum target,
5642 GLenum pname,
5643 GLint *params)
5644{
5645 return ValidateGetRenderbufferParameterivBase(context, target, pname, nullptr);
5646}
5647
5648bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
5649 GLenum target,
5650 GLenum pname,
5651 GLsizei bufSize,
5652 GLsizei *length,
5653 GLint *params)
5654{
5655 if (!ValidateRobustEntryPoint(context, bufSize))
5656 {
5657 return false;
5658 }
5659
5660 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
5661 {
5662 return false;
5663 }
5664
5665 if (!ValidateRobustBufferSize(context, bufSize, *length))
5666 {
5667 return false;
5668 }
5669
5670 return true;
5671}
5672
Geoff Langd7d0ed32016-10-07 11:33:51 -04005673bool ValidateGetShaderiv(Context *context, GLuint shader, GLenum pname, GLint *params)
5674{
5675 return ValidateGetShaderivBase(context, shader, pname, nullptr);
5676}
5677
5678bool ValidateGetShaderivRobustANGLE(Context *context,
5679 GLuint shader,
5680 GLenum pname,
5681 GLsizei bufSize,
5682 GLsizei *length,
5683 GLint *params)
5684{
5685 if (!ValidateRobustEntryPoint(context, bufSize))
5686 {
5687 return false;
5688 }
5689
5690 if (!ValidateGetShaderivBase(context, shader, pname, length))
5691 {
5692 return false;
5693 }
5694
5695 if (!ValidateRobustBufferSize(context, bufSize, *length))
5696 {
5697 return false;
5698 }
5699
5700 return true;
5701}
5702
Geoff Langc1984ed2016-10-07 12:41:00 -04005703bool ValidateGetTexParameterfv(Context *context, GLenum target, GLenum pname, GLfloat *params)
5704{
5705 return ValidateGetTexParameterBase(context, target, pname, nullptr);
5706}
5707
5708bool ValidateGetTexParameterfvRobustANGLE(Context *context,
5709 GLenum target,
5710 GLenum pname,
5711 GLsizei bufSize,
5712 GLsizei *length,
5713 GLfloat *params)
5714{
5715 if (!ValidateRobustEntryPoint(context, bufSize))
5716 {
5717 return false;
5718 }
5719
5720 if (!ValidateGetTexParameterBase(context, target, pname, length))
5721 {
5722 return false;
5723 }
5724
5725 if (!ValidateRobustBufferSize(context, bufSize, *length))
5726 {
5727 return false;
5728 }
5729
5730 return true;
5731}
5732
5733bool ValidateGetTexParameteriv(Context *context, GLenum target, GLenum pname, GLint *params)
5734{
5735 return ValidateGetTexParameterBase(context, target, pname, nullptr);
5736}
5737
5738bool ValidateGetTexParameterivRobustANGLE(Context *context,
5739 GLenum target,
5740 GLenum pname,
5741 GLsizei bufSize,
5742 GLsizei *length,
5743 GLint *params)
5744{
5745 if (!ValidateRobustEntryPoint(context, bufSize))
5746 {
5747 return false;
5748 }
5749
5750 if (!ValidateGetTexParameterBase(context, target, pname, length))
5751 {
5752 return false;
5753 }
5754
5755 if (!ValidateRobustBufferSize(context, bufSize, *length))
5756 {
5757 return false;
5758 }
5759
5760 return true;
5761}
5762
5763bool ValidateTexParameterf(Context *context, GLenum target, GLenum pname, GLfloat param)
5764{
5765 return ValidateTexParameterBase(context, target, pname, -1, &param);
5766}
5767
5768bool ValidateTexParameterfv(Context *context, GLenum target, GLenum pname, const GLfloat *params)
5769{
5770 return ValidateTexParameterBase(context, target, pname, -1, params);
5771}
5772
5773bool ValidateTexParameterfvRobustANGLE(Context *context,
5774 GLenum target,
5775 GLenum pname,
5776 GLsizei bufSize,
5777 const GLfloat *params)
5778{
5779 if (!ValidateRobustEntryPoint(context, bufSize))
5780 {
5781 return false;
5782 }
5783
5784 return ValidateTexParameterBase(context, target, pname, bufSize, params);
5785}
5786
5787bool ValidateTexParameteri(Context *context, GLenum target, GLenum pname, GLint param)
5788{
5789 return ValidateTexParameterBase(context, target, pname, -1, &param);
5790}
5791
5792bool ValidateTexParameteriv(Context *context, GLenum target, GLenum pname, const GLint *params)
5793{
5794 return ValidateTexParameterBase(context, target, pname, -1, params);
5795}
5796
5797bool ValidateTexParameterivRobustANGLE(Context *context,
5798 GLenum target,
5799 GLenum pname,
5800 GLsizei bufSize,
5801 const GLint *params)
5802{
5803 if (!ValidateRobustEntryPoint(context, bufSize))
5804 {
5805 return false;
5806 }
5807
5808 return ValidateTexParameterBase(context, target, pname, bufSize, params);
5809}
5810
5811bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
5812{
5813 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
5814}
5815
5816bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
5817 GLuint sampler,
5818 GLenum pname,
5819 GLuint bufSize,
5820 GLsizei *length,
5821 GLfloat *params)
5822{
5823 if (!ValidateRobustEntryPoint(context, bufSize))
5824 {
5825 return false;
5826 }
5827
5828 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
5829 {
5830 return false;
5831 }
5832
5833 if (!ValidateRobustBufferSize(context, bufSize, *length))
5834 {
5835 return false;
5836 }
5837
5838 return true;
5839}
5840
5841bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
5842{
5843 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
5844}
5845
5846bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
5847 GLuint sampler,
5848 GLenum pname,
5849 GLuint bufSize,
5850 GLsizei *length,
5851 GLint *params)
5852{
5853 if (!ValidateRobustEntryPoint(context, bufSize))
5854 {
5855 return false;
5856 }
5857
5858 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
5859 {
5860 return false;
5861 }
5862
5863 if (!ValidateRobustBufferSize(context, bufSize, *length))
5864 {
5865 return false;
5866 }
5867
5868 return true;
5869}
5870
5871bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
5872{
5873 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
5874}
5875
5876bool ValidateSamplerParameterfv(Context *context,
5877 GLuint sampler,
5878 GLenum pname,
5879 const GLfloat *params)
5880{
5881 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
5882}
5883
5884bool ValidateSamplerParameterfvRobustANGLE(Context *context,
5885 GLuint sampler,
5886 GLenum pname,
5887 GLsizei bufSize,
5888 const GLfloat *params)
5889{
5890 if (!ValidateRobustEntryPoint(context, bufSize))
5891 {
5892 return false;
5893 }
5894
5895 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
5896}
5897
5898bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
5899{
5900 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
5901}
5902
5903bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
5904{
5905 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
5906}
5907
5908bool ValidateSamplerParameterivRobustANGLE(Context *context,
5909 GLuint sampler,
5910 GLenum pname,
5911 GLsizei bufSize,
5912 const GLint *params)
5913{
5914 if (!ValidateRobustEntryPoint(context, bufSize))
5915 {
5916 return false;
5917 }
5918
5919 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
5920}
5921
Geoff Lang0b031062016-10-13 14:30:04 -04005922bool ValidateGetVertexAttribfv(Context *context, GLuint index, GLenum pname, GLfloat *params)
5923{
5924 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false);
5925}
5926
5927bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
5928 GLuint index,
5929 GLenum pname,
5930 GLsizei bufSize,
5931 GLsizei *length,
5932 GLfloat *params)
5933{
5934 if (!ValidateRobustEntryPoint(context, bufSize))
5935 {
5936 return false;
5937 }
5938
5939 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
5940 {
5941 return false;
5942 }
5943
5944 if (!ValidateRobustBufferSize(context, bufSize, *length))
5945 {
5946 return false;
5947 }
5948
5949 return true;
5950}
5951
5952bool ValidateGetVertexAttribiv(Context *context, GLuint index, GLenum pname, GLint *params)
5953{
5954 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, false);
5955}
5956
5957bool ValidateGetVertexAttribivRobustANGLE(Context *context,
5958 GLuint index,
5959 GLenum pname,
5960 GLsizei bufSize,
5961 GLsizei *length,
5962 GLint *params)
5963{
5964 if (!ValidateRobustEntryPoint(context, bufSize))
5965 {
5966 return false;
5967 }
5968
5969 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
5970 {
5971 return false;
5972 }
5973
5974 if (!ValidateRobustBufferSize(context, bufSize, *length))
5975 {
5976 return false;
5977 }
5978
5979 return true;
5980}
5981
5982bool ValidateGetVertexAttribPointerv(Context *context, GLuint index, GLenum pname, void **pointer)
5983{
5984 return ValidateGetVertexAttribBase(context, index, pname, nullptr, true, false);
5985}
5986
5987bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
5988 GLuint index,
5989 GLenum pname,
5990 GLsizei bufSize,
5991 GLsizei *length,
5992 void **pointer)
5993{
5994 if (!ValidateRobustEntryPoint(context, bufSize))
5995 {
5996 return false;
5997 }
5998
5999 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
6000 {
6001 return false;
6002 }
6003
6004 if (!ValidateRobustBufferSize(context, bufSize, *length))
6005 {
6006 return false;
6007 }
6008
6009 return true;
6010}
6011
6012bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
6013{
6014 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
6015}
6016
6017bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
6018 GLuint index,
6019 GLenum pname,
6020 GLsizei bufSize,
6021 GLsizei *length,
6022 GLint *params)
6023{
6024 if (!ValidateRobustEntryPoint(context, bufSize))
6025 {
6026 return false;
6027 }
6028
6029 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
6030 {
6031 return false;
6032 }
6033
6034 if (!ValidateRobustBufferSize(context, bufSize, *length))
6035 {
6036 return false;
6037 }
6038
6039 return true;
6040}
6041
6042bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
6043{
6044 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
6045}
6046
6047bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
6048 GLuint index,
6049 GLenum pname,
6050 GLsizei bufSize,
6051 GLsizei *length,
6052 GLuint *params)
6053{
6054 if (!ValidateRobustEntryPoint(context, bufSize))
6055 {
6056 return false;
6057 }
6058
6059 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
6060 {
6061 return false;
6062 }
6063
6064 if (!ValidateRobustBufferSize(context, bufSize, *length))
6065 {
6066 return false;
6067 }
6068
6069 return true;
6070}
6071
Geoff Lang6899b872016-10-14 11:30:13 -04006072bool ValidateGetActiveUniformBlockiv(Context *context,
6073 GLuint program,
6074 GLuint uniformBlockIndex,
6075 GLenum pname,
6076 GLint *params)
6077{
6078 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
6079}
6080
6081bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
6082 GLuint program,
6083 GLuint uniformBlockIndex,
6084 GLenum pname,
6085 GLsizei bufSize,
6086 GLsizei *length,
6087 GLint *params)
6088{
6089 if (!ValidateRobustEntryPoint(context, bufSize))
6090 {
6091 return false;
6092 }
6093
6094 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
6095 {
6096 return false;
6097 }
6098
6099 if (!ValidateRobustBufferSize(context, bufSize, *length))
6100 {
6101 return false;
6102 }
6103
6104 return true;
6105}
6106
Geoff Lang0a9661f2016-10-20 10:59:20 -07006107bool ValidateGetInternalFormativ(Context *context,
6108 GLenum target,
6109 GLenum internalformat,
6110 GLenum pname,
6111 GLsizei bufSize,
6112 GLint *params)
6113{
6114 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
6115 nullptr);
6116}
6117
6118bool ValidateGetInternalFormativRobustANGLE(Context *context,
6119 GLenum target,
6120 GLenum internalformat,
6121 GLenum pname,
6122 GLsizei bufSize,
6123 GLsizei *length,
6124 GLint *params)
6125{
6126 if (!ValidateRobustEntryPoint(context, bufSize))
6127 {
6128 return false;
6129 }
6130
6131 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
6132 {
6133 return false;
6134 }
6135
6136 if (!ValidateRobustBufferSize(context, bufSize, *length))
6137 {
6138 return false;
6139 }
6140
6141 return true;
6142}
6143
Shao80957d92017-02-20 21:25:59 +08006144bool ValidateVertexFormatBase(ValidationContext *context,
6145 GLuint attribIndex,
6146 GLint size,
6147 GLenum type,
6148 GLboolean pureInteger)
6149{
6150 const Caps &caps = context->getCaps();
6151 if (attribIndex >= caps.maxVertexAttributes)
6152 {
6153 context->handleError(
6154 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
6155 return false;
6156 }
6157
6158 if (size < 1 || size > 4)
6159 {
6160 context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
6161 }
6162
6163 switch (type)
6164 {
6165 case GL_BYTE:
6166 case GL_UNSIGNED_BYTE:
6167 case GL_SHORT:
6168 case GL_UNSIGNED_SHORT:
6169 break;
6170
6171 case GL_INT:
6172 case GL_UNSIGNED_INT:
6173 if (context->getClientMajorVersion() < 3)
6174 {
6175 context->handleError(
6176 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6177 return false;
6178 }
6179 break;
6180
6181 case GL_FIXED:
6182 case GL_FLOAT:
6183 if (pureInteger)
6184 {
6185 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6186 return false;
6187 }
6188 break;
6189
6190 case GL_HALF_FLOAT:
6191 if (context->getClientMajorVersion() < 3)
6192 {
6193 context->handleError(
6194 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6195 return false;
6196 }
6197 if (pureInteger)
6198 {
6199 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6200 return false;
6201 }
6202 break;
6203
6204 case GL_INT_2_10_10_10_REV:
6205 case GL_UNSIGNED_INT_2_10_10_10_REV:
6206 if (context->getClientMajorVersion() < 3)
6207 {
6208 context->handleError(
6209 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
6210 return false;
6211 }
6212 if (pureInteger)
6213 {
6214 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
6215 return false;
6216 }
6217 if (size != 4)
6218 {
6219 context->handleError(Error(GL_INVALID_OPERATION,
6220 "Type is INT_2_10_10_10_REV or "
6221 "UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
6222 return false;
6223 }
6224 break;
6225
6226 default:
6227 context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
6228 return false;
6229 }
6230
6231 return true;
6232}
6233
Geoff Lang76e65652017-03-27 14:58:02 -04006234// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
6235// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
6236// specified clear value and the type of a buffer that is being cleared generates an
6237// INVALID_OPERATION error instead of producing undefined results
6238bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
6239 GLint drawbuffer,
6240 const GLenum *validComponentTypes,
6241 size_t validComponentTypeCount)
6242{
6243 const FramebufferAttachment *attachment =
6244 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
6245 if (attachment)
6246 {
6247 GLenum componentType = attachment->getFormat().info->componentType;
6248 const GLenum *end = validComponentTypes + validComponentTypeCount;
6249 if (std::find(validComponentTypes, end, componentType) == end)
6250 {
6251 context->handleError(
6252 Error(GL_INVALID_OPERATION,
6253 "No defined conversion between clear value and attachment format."));
6254 return false;
6255 }
6256 }
6257
6258 return true;
6259}
6260
Corentin Wallezb2931602017-04-11 15:58:57 -04006261bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
6262 GLsizei imageSize,
6263 GLsizei dataSize)
6264{
6265 if (!ValidateRobustEntryPoint(context, dataSize))
6266 {
6267 return false;
6268 }
6269
6270 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
6271 if (pixelUnpackBuffer == nullptr)
6272 {
6273 if (dataSize < imageSize)
6274 {
6275 context->handleError(
6276 Error(GL_INVALID_OPERATION, "dataSize must be at least %i.", imageSize));
6277 }
6278 }
6279 return true;
6280}
6281
Jamie Madillc29968b2016-01-20 11:17:23 -05006282} // namespace gl