blob: 30044f50e4b7e06aee8a2ec04118d9248a5d6c7e [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/Context.h"
Geoff Langa8406172015-07-21 16:53:39 -040012#include "libANGLE/Display.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050013#include "libANGLE/Framebuffer.h"
14#include "libANGLE/FramebufferAttachment.h"
Geoff Langa8406172015-07-21 16:53:39 -040015#include "libANGLE/Image.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050016#include "libANGLE/Program.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040017#include "libANGLE/Query.h"
18#include "libANGLE/Texture.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/TransformFeedback.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040020#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050021#include "libANGLE/VertexArray.h"
Jamie Madill231c7f52017-04-26 13:45:37 -040022#include "libANGLE/formatutils.h"
23#include "libANGLE/validationES2.h"
24#include "libANGLE/validationES3.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
Jamie Madill231c7f52017-04-26 13:45:37 -040047 const VertexArray *vao = state.getVertexArray();
48 const auto &vertexAttribs = vao->getVertexAttributes();
Jiawei-Shao2597fb62016-12-09 16:38:02 +080049 const auto &vertexBindings = vao->getVertexBindings();
Jamie Madill231c7f52017-04-26 13:45:37 -040050 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 Wallez672f7f32017-06-15 17:42:17 -040054
55 // No need to range check for disabled attribs.
56 if (!attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040057 {
Corentin Wallezfd456442016-12-21 17:57:00 -050058 continue;
59 }
Jamie Madill1ca74672015-07-21 15:14:11 -040060
Jamie Madill231c7f52017-04-26 13:45:37 -040061 // If we have no buffer, then we either get an error, or there are no more checks to be
62 // done.
Corentin Wallez672f7f32017-06-15 17:42:17 -040063 const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
64 gl::Buffer *buffer = binding.getBuffer().get();
Corentin Wallezfd456442016-12-21 17:57:00 -050065 if (!buffer)
66 {
Geoff Langfeb8c682017-02-13 16:07:35 -050067 if (webglCompatibility || !state.areClientArraysEnabled())
Corentin Wallez327411e2016-12-09 11:09:17 -050068 {
69 // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
Corentin Wallezfd456442016-12-21 17:57:00 -050070 // If a vertex attribute is enabled as an array via enableVertexAttribArray but
71 // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer,
72 // then calls to drawArrays or drawElements will generate an INVALID_OPERATION
73 // error.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -050074 context->handleError(InvalidOperation()
75 << "An enabled vertex array has no buffer.");
Corentin Wallezfd456442016-12-21 17:57:00 -050076 return false;
Corentin Wallez327411e2016-12-09 11:09:17 -050077 }
Corentin Wallezfd456442016-12-21 17:57:00 -050078 else if (attrib.pointer == nullptr)
Jamie Madill1ca74672015-07-21 15:14:11 -040079 {
80 // This is an application error that would normally result in a crash,
81 // but we catch it and return an error
Yuly Novikovc4d18aa2017-03-09 18:45:02 -050082 context->handleError(InvalidOperation()
83 << "An enabled vertex array has no buffer and no pointer.");
Jamie Madill1ca74672015-07-21 15:14:11 -040084 return false;
85 }
Corentin Wallezfd456442016-12-21 17:57:00 -050086 continue;
87 }
88
Corentin Wallez672f7f32017-06-15 17:42:17 -040089 // This needs to come after the check for client arrays as even unused attributes cannot use
90 // client-side arrays
91 if (!program->isAttribLocationActive(attributeIndex))
92 {
93 continue;
94 }
95
Corentin Wallezfd456442016-12-21 17:57:00 -050096 // If we're drawing zero vertices, we have enough data.
97 if (vertexCount <= 0 || primcount <= 0)
98 {
99 continue;
100 }
101
102 GLint maxVertexElement = 0;
Martin Radevdd5f27e2017-06-07 10:17:09 +0300103 GLuint divisor = binding.getDivisor();
104 if (divisor == 0)
Corentin Wallezfd456442016-12-21 17:57:00 -0500105 {
106 maxVertexElement = maxVertex;
107 }
108 else
109 {
Martin Radevdd5f27e2017-06-07 10:17:09 +0300110 maxVertexElement = (primcount - 1) / divisor;
Corentin Wallezfd456442016-12-21 17:57:00 -0500111 }
112
113 // We do manual overflow checks here instead of using safe_math.h because it was
114 // a bottleneck. Thanks to some properties of GL we know inequalities that can
115 // help us make the overflow checks faster.
116
117 // The max possible attribSize is 16 for a vector of 4 32 bit values.
118 constexpr uint64_t kMaxAttribSize = 16;
119 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
120 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
121
122 // We know attribStride is given as a GLsizei which is typedefed to int.
123 // We also know an upper bound for attribSize.
124 static_assert(std::is_same<int, GLsizei>::value, "");
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800125 uint64_t attribStride = ComputeVertexAttributeStride(attrib, binding);
Corentin Wallezfd456442016-12-21 17:57:00 -0500126 uint64_t attribSize = ComputeVertexAttributeTypeSize(attrib);
127 ASSERT(attribStride <= kIntMax && attribSize <= kMaxAttribSize);
128
129 // Computing the max offset using uint64_t without attrib.offset is overflow
130 // safe. Note: Last vertex element does not take the full stride!
131 static_assert(kIntMax * kIntMax < kUint64Max - kMaxAttribSize, "");
132 uint64_t attribDataSizeNoOffset = maxVertexElement * attribStride + attribSize;
133
134 // An overflow can happen when adding the offset, check for it.
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800135 uint64_t attribOffset = ComputeVertexAttributeOffset(attrib, binding);
136 if (attribDataSizeNoOffset > kUint64Max - attribOffset)
Corentin Wallezfd456442016-12-21 17:57:00 -0500137 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500138 context->handleError(InvalidOperation() << "Integer overflow.");
Corentin Wallezfd456442016-12-21 17:57:00 -0500139 return false;
140 }
141 uint64_t attribDataSizeWithOffset = attribDataSizeNoOffset + attribOffset;
142
143 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
144 // We can return INVALID_OPERATION if our vertex attribute does not have
145 // enough backing data.
146 if (attribDataSizeWithOffset > static_cast<uint64_t>(buffer->getSize()))
147 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500148 context->handleError(InvalidOperation()
149 << "Vertex buffer is not big enough for the draw call");
Corentin Wallezfd456442016-12-21 17:57:00 -0500150 return false;
Jamie Madill1ca74672015-07-21 15:14:11 -0400151 }
152 }
153
154 return true;
155}
156
Geoff Langf607c602016-09-21 11:46:48 -0400157bool ValidReadPixelsFormatType(ValidationContext *context,
158 GLenum framebufferComponentType,
159 GLenum format,
160 GLenum type)
161{
162 switch (framebufferComponentType)
163 {
164 case GL_UNSIGNED_NORMALIZED:
165 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
166 // ReadPixels with BGRA even if the extension is not present
167 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
168 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
169 type == GL_UNSIGNED_BYTE);
170
171 case GL_SIGNED_NORMALIZED:
172 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
173
174 case GL_INT:
175 return (format == GL_RGBA_INTEGER && type == GL_INT);
176
177 case GL_UNSIGNED_INT:
178 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
179
180 case GL_FLOAT:
181 return (format == GL_RGBA && type == GL_FLOAT);
182
183 default:
184 UNREACHABLE();
185 return false;
186 }
187}
188
Geoff Langc1984ed2016-10-07 12:41:00 -0400189template <typename ParamType>
190bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isExternalTextureTarget)
191{
192 switch (ConvertToGLenum(params[0]))
193 {
194 case GL_CLAMP_TO_EDGE:
195 break;
196
197 case GL_REPEAT:
198 case GL_MIRRORED_REPEAT:
199 if (isExternalTextureTarget)
200 {
201 // OES_EGL_image_external specifies this error.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500202 context->handleError(InvalidEnum()
203 << "external textures only support CLAMP_TO_EDGE wrap mode");
Geoff Langc1984ed2016-10-07 12:41:00 -0400204 return false;
205 }
206 break;
207
208 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500209 context->handleError(InvalidEnum() << "Unknown param value.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400210 return false;
211 }
212
213 return true;
214}
215
216template <typename ParamType>
217bool ValidateTextureMinFilterValue(Context *context,
218 ParamType *params,
219 bool isExternalTextureTarget)
220{
221 switch (ConvertToGLenum(params[0]))
222 {
223 case GL_NEAREST:
224 case GL_LINEAR:
225 break;
226
227 case GL_NEAREST_MIPMAP_NEAREST:
228 case GL_LINEAR_MIPMAP_NEAREST:
229 case GL_NEAREST_MIPMAP_LINEAR:
230 case GL_LINEAR_MIPMAP_LINEAR:
231 if (isExternalTextureTarget)
232 {
233 // OES_EGL_image_external specifies this error.
234 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500235 InvalidEnum() << "external textures only support NEAREST and LINEAR filtering");
Geoff Langc1984ed2016-10-07 12:41:00 -0400236 return false;
237 }
238 break;
239
240 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500241 context->handleError(InvalidEnum() << "Unknown param value.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400242 return false;
243 }
244
245 return true;
246}
247
248template <typename ParamType>
249bool ValidateTextureMagFilterValue(Context *context, ParamType *params)
250{
251 switch (ConvertToGLenum(params[0]))
252 {
253 case GL_NEAREST:
254 case GL_LINEAR:
255 break;
256
257 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500258 context->handleError(InvalidEnum() << "Unknown param value.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400259 return false;
260 }
261
262 return true;
263}
264
265template <typename ParamType>
266bool ValidateTextureCompareModeValue(Context *context, ParamType *params)
267{
268 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
269 switch (ConvertToGLenum(params[0]))
270 {
271 case GL_NONE:
272 case GL_COMPARE_REF_TO_TEXTURE:
273 break;
274
275 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500276 context->handleError(InvalidEnum() << "Unknown param value.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400277 return false;
278 }
279
280 return true;
281}
282
283template <typename ParamType>
284bool ValidateTextureCompareFuncValue(Context *context, ParamType *params)
285{
286 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
287 switch (ConvertToGLenum(params[0]))
288 {
289 case GL_LEQUAL:
290 case GL_GEQUAL:
291 case GL_LESS:
292 case GL_GREATER:
293 case GL_EQUAL:
294 case GL_NOTEQUAL:
295 case GL_ALWAYS:
296 case GL_NEVER:
297 break;
298
299 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500300 context->handleError(InvalidEnum() << "Unknown param value.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400301 return false;
302 }
303
304 return true;
305}
306
307template <typename ParamType>
Geoff Lang81c6b572016-10-19 14:07:52 -0700308bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params)
309{
310 if (!context->getExtensions().textureSRGBDecode)
311 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500312 context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled.");
Geoff Lang81c6b572016-10-19 14:07:52 -0700313 return false;
314 }
315
316 switch (ConvertToGLenum(params[0]))
317 {
318 case GL_DECODE_EXT:
319 case GL_SKIP_DECODE_EXT:
320 break;
321
322 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500323 context->handleError(InvalidEnum() << "Unknown param value.");
Geoff Lang81c6b572016-10-19 14:07:52 -0700324 return false;
325 }
326
327 return true;
328}
329
330template <typename ParamType>
Geoff Langc1984ed2016-10-07 12:41:00 -0400331bool ValidateSamplerParameterBase(Context *context,
332 GLuint sampler,
333 GLenum pname,
334 GLsizei bufSize,
335 ParamType *params)
336{
337 if (context->getClientMajorVersion() < 3)
338 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500339 context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400340 return false;
341 }
342
343 if (!context->isSampler(sampler))
344 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500345 context->handleError(InvalidOperation() << "Sampler is not valid.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400346 return false;
347 }
348
349 const GLsizei minBufSize = 1;
350 if (bufSize >= 0 && bufSize < minBufSize)
351 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500352 context->handleError(InvalidOperation() << "bufSize must be at least " << minBufSize);
Geoff Langc1984ed2016-10-07 12:41:00 -0400353 return false;
354 }
355
356 switch (pname)
357 {
358 case GL_TEXTURE_WRAP_S:
359 case GL_TEXTURE_WRAP_T:
360 case GL_TEXTURE_WRAP_R:
361 if (!ValidateTextureWrapModeValue(context, params, false))
362 {
363 return false;
364 }
365 break;
366
367 case GL_TEXTURE_MIN_FILTER:
368 if (!ValidateTextureMinFilterValue(context, params, false))
369 {
370 return false;
371 }
372 break;
373
374 case GL_TEXTURE_MAG_FILTER:
375 if (!ValidateTextureMagFilterValue(context, params))
376 {
377 return false;
378 }
379 break;
380
381 case GL_TEXTURE_MIN_LOD:
382 case GL_TEXTURE_MAX_LOD:
383 // any value is permissible
384 break;
385
386 case GL_TEXTURE_COMPARE_MODE:
387 if (!ValidateTextureCompareModeValue(context, params))
388 {
389 return false;
390 }
391 break;
392
393 case GL_TEXTURE_COMPARE_FUNC:
394 if (!ValidateTextureCompareFuncValue(context, params))
395 {
396 return false;
397 }
398 break;
399
Geoff Lang81c6b572016-10-19 14:07:52 -0700400 case GL_TEXTURE_SRGB_DECODE_EXT:
401 if (!ValidateTextureSRGBDecodeValue(context, params))
402 {
403 return false;
404 }
405 break;
406
Geoff Langc1984ed2016-10-07 12:41:00 -0400407 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500408 context->handleError(InvalidEnum() << "Unknown pname.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400409 return false;
410 }
411
412 return true;
413}
414
415bool ValidateGetSamplerParameterBase(Context *context,
416 GLuint sampler,
417 GLenum pname,
418 GLsizei *length)
419{
420 if (length)
421 {
422 *length = 0;
423 }
424
425 if (context->getClientMajorVersion() < 3)
426 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500427 context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400428 return false;
429 }
430
431 if (!context->isSampler(sampler))
432 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500433 context->handleError(InvalidOperation() << "Sampler is not valid.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400434 return false;
435 }
436
437 switch (pname)
438 {
439 case GL_TEXTURE_WRAP_S:
440 case GL_TEXTURE_WRAP_T:
441 case GL_TEXTURE_WRAP_R:
442 case GL_TEXTURE_MIN_FILTER:
443 case GL_TEXTURE_MAG_FILTER:
444 case GL_TEXTURE_MIN_LOD:
445 case GL_TEXTURE_MAX_LOD:
446 case GL_TEXTURE_COMPARE_MODE:
447 case GL_TEXTURE_COMPARE_FUNC:
448 break;
449
Geoff Lang81c6b572016-10-19 14:07:52 -0700450 case GL_TEXTURE_SRGB_DECODE_EXT:
451 if (!context->getExtensions().textureSRGBDecode)
452 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500453 context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled.");
Geoff Lang81c6b572016-10-19 14:07:52 -0700454 return false;
455 }
456 break;
457
Geoff Langc1984ed2016-10-07 12:41:00 -0400458 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500459 context->handleError(InvalidEnum() << "Unknown pname.");
Geoff Langc1984ed2016-10-07 12:41:00 -0400460 return false;
461 }
462
463 if (length)
464 {
465 *length = 1;
466 }
467 return true;
468}
469
Geoff Lang6899b872016-10-14 11:30:13 -0400470bool ValidateGetActiveUniformBlockivBase(Context *context,
471 GLuint program,
472 GLuint uniformBlockIndex,
473 GLenum pname,
474 GLsizei *length)
475{
476 if (length)
477 {
478 *length = 0;
479 }
480
481 if (context->getClientMajorVersion() < 3)
482 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500483 context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0.");
Geoff Lang6899b872016-10-14 11:30:13 -0400484 return false;
485 }
486
487 Program *programObject = GetValidProgram(context, program);
488 if (!programObject)
489 {
490 return false;
491 }
492
493 if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
494 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500495 context->handleError(InvalidValue()
496 << "uniformBlockIndex exceeds active uniform block count.");
Geoff Lang6899b872016-10-14 11:30:13 -0400497 return false;
498 }
499
500 switch (pname)
501 {
502 case GL_UNIFORM_BLOCK_BINDING:
503 case GL_UNIFORM_BLOCK_DATA_SIZE:
504 case GL_UNIFORM_BLOCK_NAME_LENGTH:
505 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
506 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
507 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
508 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
509 break;
510
511 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500512 context->handleError(InvalidEnum() << "Unknown pname.");
Geoff Lang6899b872016-10-14 11:30:13 -0400513 return false;
514 }
515
516 if (length)
517 {
518 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
519 {
520 const UniformBlock &uniformBlock =
521 programObject->getUniformBlockByIndex(uniformBlockIndex);
522 *length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
523 }
524 else
525 {
526 *length = 1;
527 }
528 }
529
530 return true;
531}
532
Geoff Lang0a9661f2016-10-20 10:59:20 -0700533bool ValidateGetInternalFormativBase(Context *context,
534 GLenum target,
535 GLenum internalformat,
536 GLenum pname,
537 GLsizei bufSize,
538 GLsizei *numParams)
539{
540 if (numParams)
541 {
542 *numParams = 0;
543 }
544
545 if (context->getClientMajorVersion() < 3)
546 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500547 context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0.");
Geoff Lang0a9661f2016-10-20 10:59:20 -0700548 return false;
549 }
550
551 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
552 if (!formatCaps.renderable)
553 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500554 context->handleError(InvalidEnum() << "Internal format is not renderable.");
Geoff Lang0a9661f2016-10-20 10:59:20 -0700555 return false;
556 }
557
558 switch (target)
559 {
560 case GL_RENDERBUFFER:
561 break;
562
JiangYizhoubddc46b2016-12-09 09:50:51 +0800563 case GL_TEXTURE_2D_MULTISAMPLE:
564 if (context->getClientVersion() < ES_3_1)
565 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500566 context->handleError(InvalidOperation()
567 << "Texture target requires at least OpenGL ES 3.1.");
JiangYizhoubddc46b2016-12-09 09:50:51 +0800568 return false;
569 }
570 break;
571
Geoff Lang0a9661f2016-10-20 10:59:20 -0700572 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500573 context->handleError(InvalidEnum() << "Invalid target.");
Geoff Lang0a9661f2016-10-20 10:59:20 -0700574 return false;
575 }
576
577 if (bufSize < 0)
578 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500579 context->handleError(InvalidValue() << "bufSize cannot be negative.");
Geoff Lang0a9661f2016-10-20 10:59:20 -0700580 return false;
581 }
582
583 GLsizei maxWriteParams = 0;
584 switch (pname)
585 {
586 case GL_NUM_SAMPLE_COUNTS:
587 maxWriteParams = 1;
588 break;
589
590 case GL_SAMPLES:
591 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
592 break;
593
594 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500595 context->handleError(InvalidEnum() << "Unknown pname.");
Geoff Lang0a9661f2016-10-20 10:59:20 -0700596 return false;
597 }
598
599 if (numParams)
600 {
601 // glGetInternalFormativ will not overflow bufSize
602 *numParams = std::min(bufSize, maxWriteParams);
603 }
604
605 return true;
606}
607
Jamie Madillc1d770e2017-04-13 17:31:24 -0400608bool ValidateUniformCommonBase(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500609 gl::Program *program,
610 GLint location,
611 GLsizei count,
612 const LinkedUniform **uniformOut)
613{
614 // TODO(Jiajia): Add image uniform check in future.
615 if (count < 0)
616 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500617 context->handleError(InvalidValue());
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500618 return false;
619 }
620
621 if (!program || !program->isLinked())
622 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500623 context->handleError(InvalidOperation());
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500624 return false;
625 }
626
627 if (location == -1)
628 {
629 // Silently ignore the uniform command
630 return false;
631 }
632
633 const auto &uniformLocations = program->getUniformLocations();
Jamie Madillbe849e42017-05-02 15:49:00 -0400634 size_t castedLocation = static_cast<size_t>(location);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500635 if (castedLocation >= uniformLocations.size())
636 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500637 context->handleError(InvalidOperation() << "Invalid uniform location");
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500638 return false;
639 }
640
641 const auto &uniformLocation = uniformLocations[castedLocation];
642 if (uniformLocation.ignored)
643 {
644 // Silently ignore the uniform command
645 return false;
646 }
647
648 if (!uniformLocation.used)
649 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500650 context->handleError(InvalidOperation());
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500651 return false;
652 }
653
654 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
655
656 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
657 if (!uniform.isArray() && count > 1)
658 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500659 context->handleError(InvalidOperation());
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500660 return false;
661 }
662
663 *uniformOut = &uniform;
664 return true;
665}
666
Frank Henigman999b0fd2017-02-02 21:45:55 -0500667bool ValidateUniform1ivValue(ValidationContext *context,
Frank Henigmana98a6472017-02-02 21:38:32 -0500668 GLenum uniformType,
669 GLsizei count,
670 const GLint *value)
671{
672 // Value type is GL_INT, because we only get here from glUniform1i{v}.
673 // It is compatible with INT or BOOL.
674 // Do these cheap tests first, for a little extra speed.
675 if (GL_INT == uniformType || GL_BOOL == uniformType)
676 {
677 return true;
678 }
679
680 if (IsSamplerType(uniformType))
681 {
Frank Henigman999b0fd2017-02-02 21:45:55 -0500682 // Check that the values are in range.
683 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
684 for (GLsizei i = 0; i < count; ++i)
685 {
686 if (value[i] < 0 || value[i] >= max)
687 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500688 context->handleError(InvalidValue() << "sampler uniform value out of range");
Frank Henigman999b0fd2017-02-02 21:45:55 -0500689 return false;
690 }
691 }
Frank Henigmana98a6472017-02-02 21:38:32 -0500692 return true;
693 }
694
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500695 context->handleError(InvalidOperation() << "wrong type of value for uniform");
Frank Henigmana98a6472017-02-02 21:38:32 -0500696 return false;
697}
698
Jamie Madillc1d770e2017-04-13 17:31:24 -0400699bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500700{
701 // Check that the value type is compatible with uniform type.
Frank Henigmana98a6472017-02-02 21:38:32 -0500702 // Do the cheaper test first, for a little extra speed.
703 if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500704 {
705 return true;
706 }
707
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500708 context->handleError(InvalidOperation() << "wrong type of value for uniform");
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500709 return false;
710}
711
Jamie Madillc1d770e2017-04-13 17:31:24 -0400712bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500713{
714 // Check that the value type is compatible with uniform type.
715 if (valueType == uniformType)
716 {
717 return true;
718 }
719
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500720 context->handleError(InvalidOperation() << "wrong type of value for uniform");
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500721 return false;
722}
723
Geoff Lange0cff192017-05-30 13:04:56 -0400724bool ValidateFragmentShaderColorBufferTypeMatch(ValidationContext *context)
725{
726 const Program *program = context->getGLState().getProgram();
727 const Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer();
728
729 const auto &programOutputTypes = program->getOutputVariableTypes();
730 for (size_t drawBufferIdx = 0; drawBufferIdx < programOutputTypes.size(); drawBufferIdx++)
731 {
732 GLenum outputType = programOutputTypes[drawBufferIdx];
733 GLenum inputType = framebuffer->getDrawbufferWriteType(drawBufferIdx);
734 if (outputType != GL_NONE && inputType != GL_NONE && inputType != outputType)
735 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500736 context->handleError(InvalidOperation() << "Fragment shader output type does not "
737 "match the bound framebuffer attachment "
738 "type.");
Geoff Lange0cff192017-05-30 13:04:56 -0400739 return false;
740 }
741 }
742
743 return true;
744}
745
Geoff Lang9ab5b822017-05-30 16:19:23 -0400746bool ValidateVertexShaderAttributeTypeMatch(ValidationContext *context)
747{
748 const Program *program = context->getGLState().getProgram();
749 const VertexArray *vao = context->getGLState().getVertexArray();
750
751 for (const auto &shaderAttribute : program->getAttributes())
752 {
753 GLenum shaderInputType = VariableComponentType(shaderAttribute.type);
754
755 const auto &attrib = vao->getVertexAttribute(shaderAttribute.location);
756 const auto &currentValue =
757 context->getGLState().getVertexAttribCurrentValue(shaderAttribute.location);
758 GLenum vertexType = attrib.enabled ? GetVertexAttributeBaseType(attrib) : currentValue.Type;
759
760 if (shaderInputType != GL_NONE && vertexType != GL_NONE && shaderInputType != vertexType)
761 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500762 context->handleError(InvalidOperation() << "Vertex shader input type does not "
763 "match the type of the bound vertex "
764 "attribute.");
Geoff Lang9ab5b822017-05-30 16:19:23 -0400765 return false;
766 }
767 }
768
769 return true;
770}
771
Geoff Langf41a7152016-09-19 15:11:17 -0400772} // anonymous namespace
773
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500774bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400775{
Jamie Madilld7460c72014-01-21 16:38:14 -0500776 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400777 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800778 case GL_TEXTURE_2D:
779 case GL_TEXTURE_CUBE_MAP:
780 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400781
He Yunchaoced53ae2016-11-29 15:00:51 +0800782 case GL_TEXTURE_3D:
783 case GL_TEXTURE_2D_ARRAY:
784 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500785
He Yunchaoced53ae2016-11-29 15:00:51 +0800786 case GL_TEXTURE_2D_MULTISAMPLE:
He Yunchaoced53ae2016-11-29 15:00:51 +0800787 return (context->getClientVersion() >= Version(3, 1));
Geoff Lang3b573612016-10-31 14:08:10 -0400788
He Yunchaoced53ae2016-11-29 15:00:51 +0800789 default:
790 return false;
Jamie Madilld7460c72014-01-21 16:38:14 -0500791 }
Jamie Madill35d15012013-10-07 10:46:37 -0400792}
793
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500794bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
795{
796 switch (target)
797 {
798 case GL_TEXTURE_2D:
799 case GL_TEXTURE_CUBE_MAP:
800 return true;
801
802 default:
803 return false;
804 }
805}
806
807bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
808{
809 switch (target)
810 {
811 case GL_TEXTURE_3D:
812 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300813 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500814
815 default:
816 return false;
817 }
818}
819
Ian Ewellbda75592016-04-18 17:25:54 -0400820// Most texture GL calls are not compatible with external textures, so we have a separate validation
821// function for use in the GL calls that do
822bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
823{
824 return (target == GL_TEXTURE_EXTERNAL_OES) &&
825 (context->getExtensions().eglImageExternal ||
826 context->getExtensions().eglStreamConsumerExternal);
827}
828
Shannon Woods4dfed832014-03-17 20:03:39 -0400829// This function differs from ValidTextureTarget in that the target must be
830// usable as the destination of a 2D operation-- so a cube face is valid, but
831// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400832// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500833bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400834{
835 switch (target)
836 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800837 case GL_TEXTURE_2D:
838 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
839 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
840 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
841 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
842 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
843 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
844 return true;
845 default:
846 return false;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500847 }
848}
849
Jamie Madillbe849e42017-05-02 15:49:00 -0400850bool ValidateDrawElementsInstancedBase(ValidationContext *context,
851 GLenum mode,
852 GLsizei count,
853 GLenum type,
854 const GLvoid *indices,
855 GLsizei primcount)
856{
857 if (primcount < 0)
858 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500859 context->handleError(InvalidValue() << "primcount cannot be negative.");
Jamie Madillbe849e42017-05-02 15:49:00 -0400860 return false;
861 }
862
863 if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount))
864 {
865 return false;
866 }
867
868 // No-op zero primitive count
869 return (primcount > 0);
870}
871
872bool ValidateDrawArraysInstancedBase(Context *context,
873 GLenum mode,
874 GLint first,
875 GLsizei count,
876 GLsizei primcount)
877{
878 if (primcount < 0)
879 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500880 context->handleError(InvalidValue() << "primcount cannot be negative.");
Jamie Madillbe849e42017-05-02 15:49:00 -0400881 return false;
882 }
883
884 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
885 {
886 return false;
887 }
888
889 // No-op if zero primitive count
890 return (primcount > 0);
891}
892
893bool ValidateDrawInstancedANGLEAndWebGL(ValidationContext *context)
894{
895 // Verify there is at least one active attribute with a divisor of zero
896 const State &state = context->getGLState();
897
898 Program *program = state.getProgram();
899
900 const auto &attribs = state.getVertexArray()->getVertexAttributes();
901 const auto &bindings = state.getVertexArray()->getVertexBindings();
902 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
903 {
904 const VertexAttribute &attrib = attribs[attributeIndex];
905 const VertexBinding &binding = bindings[attrib.bindingIndex];
Martin Radevdd5f27e2017-06-07 10:17:09 +0300906 if (program->isAttribLocationActive(attributeIndex) && binding.getDivisor() == 0)
Jamie Madillbe849e42017-05-02 15:49:00 -0400907 {
908 return true;
909 }
910 }
911
Yuly Novikovc4d18aa2017-03-09 18:45:02 -0500912 context->handleError(InvalidOperation()
913 << "At least one attribute must have a divisor of zero.");
Jamie Madillbe849e42017-05-02 15:49:00 -0400914 return false;
915}
916
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500917bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
918{
919 switch (target)
920 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800921 case GL_TEXTURE_3D:
922 case GL_TEXTURE_2D_ARRAY:
923 return true;
924 default:
925 return false;
Shannon Woods4dfed832014-03-17 20:03:39 -0400926 }
927}
928
He Yunchao11b038b2016-11-22 21:24:04 +0800929bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target)
930{
931 switch (target)
932 {
933 case GL_TEXTURE_2D:
934 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
935 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
936 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
937 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
938 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
939 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
940 case GL_TEXTURE_3D:
941 case GL_TEXTURE_2D_ARRAY:
942 case GL_TEXTURE_2D_MULTISAMPLE:
943 return true;
944 default:
945 return false;
946 }
947}
948
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500949bool ValidFramebufferTarget(GLenum target)
950{
He Yunchaoced53ae2016-11-29 15:00:51 +0800951 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
952 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
Geoff Langd4475812015-03-18 10:53:05 -0400953 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500954
955 switch (target)
956 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800957 case GL_FRAMEBUFFER:
958 return true;
959 case GL_READ_FRAMEBUFFER:
960 return true;
961 case GL_DRAW_FRAMEBUFFER:
962 return true;
963 default:
964 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500965 }
966}
967
Jamie Madill29639852016-09-02 15:00:09 -0400968bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500969{
970 switch (target)
971 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800972 case GL_ARRAY_BUFFER:
973 case GL_ELEMENT_ARRAY_BUFFER:
974 return true;
Jamie Madill8c96d582014-03-05 15:01:23 -0500975
He Yunchaoced53ae2016-11-29 15:00:51 +0800976 case GL_PIXEL_PACK_BUFFER:
977 case GL_PIXEL_UNPACK_BUFFER:
978 return (context->getExtensions().pixelBufferObject ||
979 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400980
He Yunchaoced53ae2016-11-29 15:00:51 +0800981 case GL_COPY_READ_BUFFER:
982 case GL_COPY_WRITE_BUFFER:
983 case GL_TRANSFORM_FEEDBACK_BUFFER:
984 case GL_UNIFORM_BUFFER:
985 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500986
He Yunchaoced53ae2016-11-29 15:00:51 +0800987 case GL_ATOMIC_COUNTER_BUFFER:
988 case GL_SHADER_STORAGE_BUFFER:
989 case GL_DRAW_INDIRECT_BUFFER:
990 case GL_DISPATCH_INDIRECT_BUFFER:
He Yunchaoced53ae2016-11-29 15:00:51 +0800991 return context->getClientVersion() >= Version(3, 1);
Geoff Lang3b573612016-10-31 14:08:10 -0400992
He Yunchaoced53ae2016-11-29 15:00:51 +0800993 default:
994 return false;
Jamie Madill8c96d582014-03-05 15:01:23 -0500995 }
996}
997
Jamie Madillc29968b2016-01-20 11:17:23 -0500998bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400999{
Jamie Madillc29968b2016-01-20 11:17:23 -05001000 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -04001001 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -04001002 switch (target)
1003 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001004 case GL_TEXTURE_2D:
1005 maxDimension = caps.max2DTextureSize;
1006 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08001007 case GL_TEXTURE_CUBE_MAP:
1008 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1009 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1010 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1011 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1012 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1013 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1014 maxDimension = caps.maxCubeMapTextureSize;
1015 break;
1016 case GL_TEXTURE_3D:
1017 maxDimension = caps.max3DTextureSize;
1018 break;
1019 case GL_TEXTURE_2D_ARRAY:
1020 maxDimension = caps.max2DTextureSize;
1021 break;
He Yunchao11b038b2016-11-22 21:24:04 +08001022 case GL_TEXTURE_2D_MULTISAMPLE:
1023 maxDimension = caps.max2DTextureSize;
1024 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08001025 default:
1026 UNREACHABLE();
Geoff Langce635692013-09-24 13:56:32 -04001027 }
1028
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001029 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -04001030}
1031
Geoff Langcc507aa2016-12-12 10:09:52 -05001032bool ValidImageSizeParameters(const ValidationContext *context,
Austin Kinross08528e12015-10-07 16:24:40 -07001033 GLenum target,
1034 GLint level,
1035 GLsizei width,
1036 GLsizei height,
1037 GLsizei depth,
1038 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -04001039{
1040 if (level < 0 || width < 0 || height < 0 || depth < 0)
1041 {
1042 return false;
1043 }
1044
Austin Kinross08528e12015-10-07 16:24:40 -07001045 // TexSubImage parameters can be NPOT without textureNPOT extension,
1046 // as long as the destination texture is POT.
Geoff Langcc507aa2016-12-12 10:09:52 -05001047 bool hasNPOTSupport =
Geoff Lang5f319a42017-01-09 16:49:19 -05001048 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
Geoff Langcc507aa2016-12-12 10:09:52 -05001049 if (!isSubImage && !hasNPOTSupport &&
Jamie Madill4fd75c12014-06-23 10:53:54 -04001050 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -04001051 {
1052 return false;
1053 }
1054
1055 if (!ValidMipLevel(context, target, level))
1056 {
1057 return false;
1058 }
1059
1060 return true;
1061}
1062
Geoff Lang0d8b7242015-09-09 14:56:53 -04001063bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
1064{
1065 // List of compressed format that require that the texture size is smaller than or a multiple of
1066 // the compressed block size.
1067 switch (internalFormat)
1068 {
1069 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1070 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1071 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1072 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Geoff Langfff7a7d2017-06-02 10:39:17 -04001073 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
1074 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
1075 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
1076 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
Minmin Gonge3939b92015-12-01 15:36:51 -08001077 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08001078 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1079 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1080 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1081 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1082 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
1083 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04001084 return true;
1085
1086 default:
1087 return false;
1088 }
1089}
1090
Geoff Lang966c9402017-04-18 12:38:27 -04001091bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed)
1092{
1093 return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) ||
1094 (size % blockSize == 0);
1095}
1096
Jamie Madillc29968b2016-01-20 11:17:23 -05001097bool ValidCompressedImageSize(const ValidationContext *context,
1098 GLenum internalFormat,
Geoff Lang966c9402017-04-18 12:38:27 -04001099 GLint level,
Jamie Madillc29968b2016-01-20 11:17:23 -05001100 GLsizei width,
1101 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04001102{
Geoff Langca271392017-04-05 12:30:00 -04001103 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04001104 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04001105 {
1106 return false;
1107 }
1108
Geoff Lang966c9402017-04-18 12:38:27 -04001109 if (width < 0 || height < 0)
1110 {
1111 return false;
1112 }
1113
1114 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1115 {
1116 // The ANGLE extensions allow specifying compressed textures with sizes smaller than the
1117 // block size for level 0 but WebGL disallows this.
1118 bool smallerThanBlockSizeAllowed =
1119 level > 0 || !context->getExtensions().webglCompatibility;
1120
1121 if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth,
1122 smallerThanBlockSizeAllowed) ||
1123 !ValidCompressedDimension(height, formatInfo.compressedBlockHeight,
1124 smallerThanBlockSizeAllowed))
1125 {
1126 return false;
1127 }
1128 }
1129
1130 return true;
1131}
1132
1133bool ValidCompressedSubImageSize(const ValidationContext *context,
1134 GLenum internalFormat,
1135 GLint xoffset,
1136 GLint yoffset,
1137 GLsizei width,
1138 GLsizei height,
1139 size_t textureWidth,
1140 size_t textureHeight)
1141{
1142 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1143 if (!formatInfo.compressed)
1144 {
1145 return false;
1146 }
1147
Geoff Lang44ff5a72017-02-03 15:15:43 -05001148 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04001149 {
1150 return false;
1151 }
1152
Geoff Lang0d8b7242015-09-09 14:56:53 -04001153 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1154 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05001155 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
Geoff Lang966c9402017-04-18 12:38:27 -04001156 yoffset % formatInfo.compressedBlockHeight != 0)
1157 {
1158 return false;
1159 }
1160
1161 // Allowed to either have data that is a multiple of block size or is smaller than the block
1162 // size but fills the entire mip
1163 bool fillsEntireMip = xoffset == 0 && yoffset == 0 &&
1164 static_cast<size_t>(width) == textureWidth &&
1165 static_cast<size_t>(height) == textureHeight;
1166 bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
1167 (height % formatInfo.compressedBlockHeight) == 0;
1168 if (!sizeMultipleOfBlockSize && !fillsEntireMip)
Geoff Lang0d8b7242015-09-09 14:56:53 -04001169 {
1170 return false;
1171 }
1172 }
1173
Geoff Langd4f180b2013-09-24 13:57:44 -04001174 return true;
1175}
1176
Geoff Langff5b2d52016-09-07 11:32:23 -04001177bool ValidImageDataSize(ValidationContext *context,
1178 GLenum textureTarget,
1179 GLsizei width,
1180 GLsizei height,
1181 GLsizei depth,
Geoff Langdbcced82017-06-06 15:55:54 -04001182 GLenum format,
Geoff Langff5b2d52016-09-07 11:32:23 -04001183 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001184 const void *pixels,
Geoff Langff5b2d52016-09-07 11:32:23 -04001185 GLsizei imageSize)
1186{
1187 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
1188 if (pixelUnpackBuffer == nullptr && imageSize < 0)
1189 {
1190 // Checks are not required
1191 return true;
1192 }
1193
1194 // ...the data would be unpacked from the buffer object such that the memory reads required
1195 // would exceed the data store size.
Geoff Langdbcced82017-06-06 15:55:54 -04001196 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
1197 ASSERT(formatInfo.internalFormat != GL_NONE);
Geoff Langff5b2d52016-09-07 11:32:23 -04001198 const gl::Extents size(width, height, depth);
1199 const auto &unpack = context->getGLState().getUnpackState();
1200
1201 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
1202 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
1203 if (endByteOrErr.isError())
1204 {
1205 context->handleError(endByteOrErr.getError());
1206 return false;
1207 }
1208
1209 GLuint endByte = endByteOrErr.getResult();
1210
1211 if (pixelUnpackBuffer)
1212 {
1213 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
1214 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
1215 checkedEndByte += checkedOffset;
1216
1217 if (!checkedEndByte.IsValid() ||
1218 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
1219 {
1220 // Overflow past the end of the buffer
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001221 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04001222 return false;
1223 }
1224 }
1225 else
1226 {
1227 ASSERT(imageSize >= 0);
1228 if (pixels == nullptr && imageSize != 0)
1229 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001230 context->handleError(InvalidOperation()
1231 << "imageSize must be 0 if no texture data is provided.");
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001232 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04001233 }
1234
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001235 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04001236 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001237 context->handleError(InvalidOperation() << "imageSize must be at least " << endByte);
Geoff Langff5b2d52016-09-07 11:32:23 -04001238 return false;
1239 }
1240 }
1241
1242 return true;
1243}
1244
Geoff Lang37dde692014-01-31 16:34:54 -05001245bool ValidQueryType(const Context *context, GLenum queryType)
1246{
He Yunchaoced53ae2016-11-29 15:00:51 +08001247 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
1248 "GL extension enums not equal.");
1249 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1250 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05001251
1252 switch (queryType)
1253 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001254 case GL_ANY_SAMPLES_PASSED:
1255 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
1256 return true;
1257 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1258 return (context->getClientMajorVersion() >= 3);
1259 case GL_TIME_ELAPSED_EXT:
1260 return context->getExtensions().disjointTimerQuery;
1261 case GL_COMMANDS_COMPLETED_CHROMIUM:
1262 return context->getExtensions().syncQuery;
1263 default:
1264 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05001265 }
1266}
1267
Geoff Lang2d62ab72017-03-23 16:54:40 -04001268bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
1269 GLenum type,
1270 GLboolean normalized,
1271 GLsizei stride,
Jamie Madill876429b2017-04-20 15:46:24 -04001272 const void *ptr,
Geoff Lang2d62ab72017-03-23 16:54:40 -04001273 bool pureInteger)
1274{
1275 ASSERT(context->getExtensions().webglCompatibility);
1276
1277 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
1278 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
1279 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
1280 // parameter exceeds 255.
1281 constexpr GLsizei kMaxWebGLStride = 255;
1282 if (stride > kMaxWebGLStride)
1283 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001284 context->handleError(InvalidValue()
1285 << "Stride is over the maximum stride allowed by WebGL.");
Geoff Lang2d62ab72017-03-23 16:54:40 -04001286 return false;
1287 }
1288
1289 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
1290 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
1291 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
1292 // or an INVALID_OPERATION error is generated.
1293 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
1294 size_t typeSize = GetVertexFormatTypeSize(internalType);
1295
1296 ASSERT(isPow2(typeSize) && typeSize > 0);
1297 size_t sizeMask = (typeSize - 1);
1298 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
1299 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001300 context->handleError(InvalidOperation() << "Offset is not a multiple of the type size.");
Geoff Lang2d62ab72017-03-23 16:54:40 -04001301 return false;
1302 }
1303
1304 if ((stride & sizeMask) != 0)
1305 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001306 context->handleError(InvalidOperation() << "Stride is not a multiple of the type size.");
Geoff Lang2d62ab72017-03-23 16:54:40 -04001307 return false;
1308 }
1309
1310 return true;
1311}
1312
Jamie Madillef300b12016-10-07 15:12:09 -04001313Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05001314{
He Yunchaoced53ae2016-11-29 15:00:51 +08001315 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
1316 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
1317 // or program object and INVALID_OPERATION if the provided name identifies an object
1318 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05001319
Dian Xiang769769a2015-09-09 15:20:08 -07001320 Program *validProgram = context->getProgram(id);
1321
1322 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05001323 {
Dian Xiang769769a2015-09-09 15:20:08 -07001324 if (context->getShader(id))
1325 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001326 context->handleError(InvalidOperation()
1327 << "Expected a program name, but found a shader name");
Dian Xiang769769a2015-09-09 15:20:08 -07001328 }
1329 else
1330 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001331 context->handleError(InvalidValue() << "Program name is not valid");
Dian Xiang769769a2015-09-09 15:20:08 -07001332 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001333 }
Dian Xiang769769a2015-09-09 15:20:08 -07001334
1335 return validProgram;
1336}
1337
Jamie Madillef300b12016-10-07 15:12:09 -04001338Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07001339{
1340 // See ValidProgram for spec details.
1341
1342 Shader *validShader = context->getShader(id);
1343
1344 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05001345 {
Dian Xiang769769a2015-09-09 15:20:08 -07001346 if (context->getProgram(id))
1347 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001348 context->handleError(InvalidOperation()
1349 << "Expected a shader name, but found a program name");
Dian Xiang769769a2015-09-09 15:20:08 -07001350 }
1351 else
1352 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001353 context->handleError(InvalidValue() << "Shader name is invalid");
Dian Xiang769769a2015-09-09 15:20:08 -07001354 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001355 }
Dian Xiang769769a2015-09-09 15:20:08 -07001356
1357 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05001358}
1359
Geoff Langb1196682014-07-23 13:47:29 -04001360bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04001361{
1362 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
1363 {
1364 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
1365
Geoff Langaae65a42014-05-26 12:43:44 -04001366 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04001367 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001368 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04001369 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001370 }
1371 }
1372 else
1373 {
1374 switch (attachment)
1375 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001376 case GL_DEPTH_ATTACHMENT:
1377 case GL_STENCIL_ATTACHMENT:
1378 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001379
He Yunchaoced53ae2016-11-29 15:00:51 +08001380 case GL_DEPTH_STENCIL_ATTACHMENT:
1381 if (!context->getExtensions().webglCompatibility &&
1382 context->getClientMajorVersion() < 3)
1383 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001384 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08001385 return false;
1386 }
1387 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001388
He Yunchaoced53ae2016-11-29 15:00:51 +08001389 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001390 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08001391 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001392 }
1393 }
1394
1395 return true;
1396}
1397
Jamie Madille8fb6402017-02-14 17:56:40 -05001398bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08001399 GLenum target,
1400 GLsizei samples,
1401 GLenum internalformat,
1402 GLsizei width,
1403 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001404{
1405 switch (target)
1406 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001407 case GL_RENDERBUFFER:
1408 break;
1409 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001410 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08001411 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001412 }
1413
1414 if (width < 0 || height < 0 || samples < 0)
1415 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001416 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04001417 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001418 }
1419
Jamie Madill4e0e6f82017-02-17 11:06:03 -05001420 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
1421 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
1422
1423 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04001424 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001425 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001426 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04001427 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001428 }
1429
1430 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
1431 // 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 -08001432 // only sized internal formats.
Geoff Langca271392017-04-05 12:30:00 -04001433 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat);
1434 if (formatInfo.internalFormat == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001435 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001436 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04001437 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001438 }
1439
Geoff Langaae65a42014-05-26 12:43:44 -04001440 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001441 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001442 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04001443 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001444 }
1445
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001446 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001447 if (handle == 0)
1448 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001449 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001450 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001451 }
1452
1453 return true;
1454}
1455
He Yunchaoced53ae2016-11-29 15:00:51 +08001456bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
1457 GLenum target,
1458 GLenum attachment,
1459 GLenum renderbuffertarget,
1460 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001461{
Shannon Woods1da3cf62014-06-27 15:32:23 -04001462 if (!ValidFramebufferTarget(target))
1463 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001464 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04001465 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04001466 }
1467
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001468 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001469
Jamie Madill84115c92015-04-23 15:00:07 -04001470 ASSERT(framebuffer);
1471 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001472 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001473 context->handleError(InvalidOperation() << "Cannot change default FBO's attachments");
Geoff Langb1196682014-07-23 13:47:29 -04001474 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001475 }
1476
Jamie Madillb4472272014-07-03 10:38:55 -04001477 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001478 {
Jamie Madillb4472272014-07-03 10:38:55 -04001479 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001480 }
1481
Jamie Madillab9d82c2014-01-21 16:38:14 -05001482 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1483 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1484 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1485 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1486 if (renderbuffer != 0)
1487 {
1488 if (!context->getRenderbuffer(renderbuffer))
1489 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001490 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001491 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05001492 }
1493 }
1494
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001495 return true;
1496}
1497
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001498bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001499 GLint srcX0,
1500 GLint srcY0,
1501 GLint srcX1,
1502 GLint srcY1,
1503 GLint dstX0,
1504 GLint dstY0,
1505 GLint dstX1,
1506 GLint dstY1,
1507 GLbitfield mask,
1508 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001509{
1510 switch (filter)
1511 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001512 case GL_NEAREST:
1513 break;
1514 case GL_LINEAR:
1515 break;
1516 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001517 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08001518 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001519 }
1520
1521 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1522 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001523 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04001524 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001525 }
1526
1527 if (mask == 0)
1528 {
1529 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
1530 // buffers are copied.
1531 return false;
1532 }
1533
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001534 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1535 // color buffer, leaving only nearest being unfiltered from above
1536 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1537 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001538 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001539 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001540 }
1541
Jamie Madill51f40ec2016-06-15 14:06:00 -04001542 const auto &glState = context->getGLState();
1543 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1544 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001545
1546 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001547 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001548 context->handleError(InvalidFramebufferOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001549 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001550 }
1551
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001552 if (readFramebuffer->id() == drawFramebuffer->id())
1553 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001554 context->handleError(InvalidOperation());
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001555 return false;
1556 }
1557
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001558 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001559 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001560 context->handleError(InvalidFramebufferOperation());
Jamie Madill48faf802014-11-06 15:27:22 -05001561 return false;
1562 }
1563
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001564 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001565 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001566 context->handleError(InvalidFramebufferOperation());
Jamie Madill48faf802014-11-06 15:27:22 -05001567 return false;
1568 }
1569
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001570 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001571 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001572 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001573 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001574 }
1575
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001576 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1577
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001578 if (mask & GL_COLOR_BUFFER_BIT)
1579 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001580 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05001581 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001582
He Yunchao66a41a22016-12-15 16:45:05 +08001583 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001584 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001585 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001586
Geoff Langa15472a2015-08-11 11:48:03 -04001587 for (size_t drawbufferIdx = 0;
1588 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001589 {
Geoff Langa15472a2015-08-11 11:48:03 -04001590 const FramebufferAttachment *attachment =
1591 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1592 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001593 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001594 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001595
Geoff Langb2f3d052013-08-13 12:49:27 -04001596 // The GL ES 3.0.2 spec (pg 193) states that:
1597 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08001598 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
1599 // as well
1600 // 3) If the read buffer is a signed integer format, the draw buffer must be as
1601 // well
Jamie Madill6163c752015-12-07 16:32:59 -05001602 // Changes with EXT_color_buffer_float:
1603 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04001604 GLenum readComponentType = readFormat.info->componentType;
1605 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08001606 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05001607 readComponentType == GL_SIGNED_NORMALIZED);
1608 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1609 drawComponentType == GL_SIGNED_NORMALIZED);
1610
1611 if (extensions.colorBufferFloat)
1612 {
1613 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1614 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1615
1616 if (readFixedOrFloat != drawFixedOrFloat)
1617 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001618 context->handleError(InvalidOperation()
1619 << "If the read buffer contains fixed-point or "
1620 "floating-point values, the draw buffer must "
1621 "as well.");
Jamie Madill6163c752015-12-07 16:32:59 -05001622 return false;
1623 }
1624 }
1625 else if (readFixedPoint != drawFixedPoint)
1626 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001627 context->handleError(InvalidOperation()
1628 << "If the read buffer contains fixed-point values, "
1629 "the draw buffer must as well.");
Jamie Madill6163c752015-12-07 16:32:59 -05001630 return false;
1631 }
1632
1633 if (readComponentType == GL_UNSIGNED_INT &&
1634 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001635 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001636 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001637 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001638 }
1639
Jamie Madill6163c752015-12-07 16:32:59 -05001640 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001641 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001642 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001643 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001644 }
1645
Jamie Madilla3944d42016-07-22 22:13:26 -04001646 if (readColorBuffer->getSamples() > 0 &&
1647 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001648 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001649 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001650 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001651 }
Geoff Lange4915782017-04-12 15:19:07 -04001652
1653 if (context->getExtensions().webglCompatibility &&
1654 *readColorBuffer == *attachment)
1655 {
1656 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001657 InvalidOperation()
1658 << "Read and write color attachments cannot be the same image.");
Geoff Lange4915782017-04-12 15:19:07 -04001659 return false;
1660 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001661 }
1662 }
1663
Jamie Madilla3944d42016-07-22 22:13:26 -04001664 if ((readFormat.info->componentType == GL_INT ||
1665 readFormat.info->componentType == GL_UNSIGNED_INT) &&
1666 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001667 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001668 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001669 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001670 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001671 }
He Yunchao66a41a22016-12-15 16:45:05 +08001672 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1673 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
1674 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
1675 // situation is an application error that would lead to a crash in ANGLE.
1676 else if (drawFramebuffer->hasEnabledDrawBuffer())
1677 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001678 context->handleError(
1679 InvalidOperation()
1680 << "Attempt to read from a missing color attachment of a complete framebuffer.");
He Yunchao66a41a22016-12-15 16:45:05 +08001681 return false;
1682 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001683 }
1684
He Yunchaoced53ae2016-11-29 15:00:51 +08001685 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001686 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1687 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001688 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001689 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001690 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001691 const gl::FramebufferAttachment *readBuffer =
1692 readFramebuffer->getAttachment(attachments[i]);
1693 const gl::FramebufferAttachment *drawBuffer =
1694 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001695
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001696 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001697 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001698 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001699 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001700 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001701 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001702 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001703
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001704 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001705 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001706 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04001707 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001708 }
Geoff Lange4915782017-04-12 15:19:07 -04001709
1710 if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer)
1711 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001712 context->handleError(
1713 InvalidOperation()
1714 << "Read and write depth stencil attachments cannot be the same image.");
Geoff Lange4915782017-04-12 15:19:07 -04001715 return false;
1716 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001717 }
He Yunchao66a41a22016-12-15 16:45:05 +08001718 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1719 else if (drawBuffer)
1720 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001721 context->handleError(InvalidOperation() << "Attempt to read from a missing "
1722 "depth/stencil attachment of a "
1723 "complete framebuffer.");
He Yunchao66a41a22016-12-15 16:45:05 +08001724 return false;
1725 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001726 }
1727 }
1728
1729 return true;
1730}
1731
Jamie Madill4928b7c2017-06-20 12:57:39 -04001732bool ValidateReadPixelsRobustANGLE(Context *context,
Geoff Lang62fce5b2016-09-30 10:46:35 -04001733 GLint x,
1734 GLint y,
1735 GLsizei width,
1736 GLsizei height,
1737 GLenum format,
1738 GLenum type,
1739 GLsizei bufSize,
1740 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001741 GLsizei *columns,
1742 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001743 void *pixels)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001744{
1745 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05001746 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001747 return false;
1748 }
1749
Geoff Lang62fce5b2016-09-30 10:46:35 -04001750 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04001751 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05001752 {
Geoff Langb1196682014-07-23 13:47:29 -04001753 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001754 }
1755
Geoff Lang62fce5b2016-09-30 10:46:35 -04001756 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05001757 {
Geoff Langb1196682014-07-23 13:47:29 -04001758 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001759 }
1760
Jamie Madillc29968b2016-01-20 11:17:23 -05001761 return true;
1762}
1763
1764bool ValidateReadnPixelsEXT(Context *context,
1765 GLint x,
1766 GLint y,
1767 GLsizei width,
1768 GLsizei height,
1769 GLenum format,
1770 GLenum type,
1771 GLsizei bufSize,
Jamie Madill876429b2017-04-20 15:46:24 -04001772 void *pixels)
Jamie Madillc29968b2016-01-20 11:17:23 -05001773{
1774 if (bufSize < 0)
1775 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001776 context->handleError(InvalidValue() << "bufSize must be a positive number");
Jamie Madillc29968b2016-01-20 11:17:23 -05001777 return false;
1778 }
1779
Geoff Lang62fce5b2016-09-30 10:46:35 -04001780 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04001781 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04001782}
Jamie Madill26e91952014-03-05 15:01:27 -05001783
Jamie Madill4928b7c2017-06-20 12:57:39 -04001784bool ValidateReadnPixelsRobustANGLE(Context *context,
Geoff Lang62fce5b2016-09-30 10:46:35 -04001785 GLint x,
1786 GLint y,
1787 GLsizei width,
1788 GLsizei height,
1789 GLenum format,
1790 GLenum type,
1791 GLsizei bufSize,
1792 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001793 GLsizei *columns,
1794 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001795 void *data)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001796{
1797 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04001798 {
Jamie Madille2e406c2016-06-02 13:04:10 -04001799 return false;
1800 }
1801
Geoff Lange93daba2017-03-30 13:54:40 -04001802 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
1803 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04001804 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001805 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001806 }
1807
Geoff Lang62fce5b2016-09-30 10:46:35 -04001808 if (!ValidateRobustBufferSize(context, bufSize, *length))
1809 {
1810 return false;
1811 }
1812
1813 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05001814}
1815
Olli Etuaho41997e72016-03-10 13:38:39 +02001816bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001817{
1818 if (!context->getExtensions().occlusionQueryBoolean &&
1819 !context->getExtensions().disjointTimerQuery)
1820 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001821 context->handleError(InvalidOperation() << "Query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001822 return false;
1823 }
1824
Olli Etuaho41997e72016-03-10 13:38:39 +02001825 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001826}
1827
Olli Etuaho41997e72016-03-10 13:38:39 +02001828bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001829{
1830 if (!context->getExtensions().occlusionQueryBoolean &&
1831 !context->getExtensions().disjointTimerQuery)
1832 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001833 context->handleError(InvalidOperation() << "Query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001834 return false;
1835 }
1836
Olli Etuaho41997e72016-03-10 13:38:39 +02001837 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001838}
1839
1840bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001841{
1842 if (!ValidQueryType(context, target))
1843 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001844 context->handleError(InvalidEnum() << "Invalid query target");
Geoff Langb1196682014-07-23 13:47:29 -04001845 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001846 }
1847
1848 if (id == 0)
1849 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001850 context->handleError(InvalidOperation() << "Query id is 0");
Geoff Langb1196682014-07-23 13:47:29 -04001851 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001852 }
1853
1854 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1855 // of zero, if the active query object name for <target> is non-zero (for the
1856 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1857 // the active query for either target is non-zero), if <id> is the name of an
1858 // existing query object whose type does not match <target>, or if <id> is the
1859 // active query object name for any query type, the error INVALID_OPERATION is
1860 // generated.
1861
1862 // Ensure no other queries are active
1863 // NOTE: If other queries than occlusion are supported, we will need to check
1864 // separately that:
1865 // a) The query ID passed is not the current active query for any target/type
1866 // b) There are no active queries for the requested target (and in the case
1867 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1868 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001869
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001870 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001871 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001872 context->handleError(InvalidOperation() << "Other query is active");
Geoff Langb1196682014-07-23 13:47:29 -04001873 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001874 }
1875
1876 Query *queryObject = context->getQuery(id, true, target);
1877
1878 // check that name was obtained with glGenQueries
1879 if (!queryObject)
1880 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001881 context->handleError(InvalidOperation() << "Invalid query id");
Geoff Langb1196682014-07-23 13:47:29 -04001882 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001883 }
1884
1885 // check for type mismatch
1886 if (queryObject->getType() != target)
1887 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001888 context->handleError(InvalidOperation() << "Query type does not match target");
Geoff Langb1196682014-07-23 13:47:29 -04001889 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001890 }
1891
1892 return true;
1893}
1894
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001895bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1896{
1897 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001898 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001899 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001900 context->handleError(InvalidOperation() << "Query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001901 return false;
1902 }
1903
1904 return ValidateBeginQueryBase(context, target, id);
1905}
1906
1907bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001908{
1909 if (!ValidQueryType(context, target))
1910 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001911 context->handleError(InvalidEnum() << "Invalid query target");
Geoff Langb1196682014-07-23 13:47:29 -04001912 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001913 }
1914
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001915 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001916
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001917 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001918 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001919 context->handleError(InvalidOperation() << "Query target not active");
Geoff Langb1196682014-07-23 13:47:29 -04001920 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001921 }
1922
Jamie Madill45c785d2014-05-13 14:09:34 -04001923 return true;
1924}
1925
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001926bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1927{
1928 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001929 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001930 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001931 context->handleError(InvalidOperation() << "Query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001932 return false;
1933 }
1934
1935 return ValidateEndQueryBase(context, target);
1936}
1937
1938bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1939{
1940 if (!context->getExtensions().disjointTimerQuery)
1941 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001942 context->handleError(InvalidOperation() << "Disjoint timer query not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001943 return false;
1944 }
1945
1946 if (target != GL_TIMESTAMP_EXT)
1947 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001948 context->handleError(InvalidEnum() << "Invalid query target");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001949 return false;
1950 }
1951
1952 Query *queryObject = context->getQuery(id, true, target);
1953 if (queryObject == nullptr)
1954 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001955 context->handleError(InvalidOperation() << "Invalid query id");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001956 return false;
1957 }
1958
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001959 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001960 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001961 context->handleError(InvalidOperation() << "Query is active");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001962 return false;
1963 }
1964
1965 return true;
1966}
1967
Geoff Lang2186c382016-10-14 10:54:54 -04001968bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001969{
Geoff Lang2186c382016-10-14 10:54:54 -04001970 if (numParams)
1971 {
1972 *numParams = 0;
1973 }
1974
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001975 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1976 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001977 context->handleError(InvalidEnum() << "Invalid query type");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001978 return false;
1979 }
1980
1981 switch (pname)
1982 {
1983 case GL_CURRENT_QUERY_EXT:
1984 if (target == GL_TIMESTAMP_EXT)
1985 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001986 context->handleError(InvalidEnum() << "Cannot use current query for timestamp");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001987 return false;
1988 }
1989 break;
1990 case GL_QUERY_COUNTER_BITS_EXT:
1991 if (!context->getExtensions().disjointTimerQuery ||
1992 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1993 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001994 context->handleError(InvalidEnum() << "Invalid pname");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001995 return false;
1996 }
1997 break;
1998 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05001999 context->handleError(InvalidEnum() << "Invalid pname");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002000 return false;
2001 }
2002
Geoff Lang2186c382016-10-14 10:54:54 -04002003 if (numParams)
2004 {
2005 // All queries return only one value
2006 *numParams = 1;
2007 }
2008
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002009 return true;
2010}
2011
2012bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
2013{
2014 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002015 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002016 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002017 context->handleError(InvalidOperation() << "Query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002018 return false;
2019 }
2020
Geoff Lang2186c382016-10-14 10:54:54 -04002021 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002022}
2023
Geoff Lang2186c382016-10-14 10:54:54 -04002024bool ValidateGetQueryivRobustANGLE(Context *context,
2025 GLenum target,
2026 GLenum pname,
2027 GLsizei bufSize,
2028 GLsizei *length,
2029 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002030{
Geoff Lang2186c382016-10-14 10:54:54 -04002031 if (!ValidateRobustEntryPoint(context, bufSize))
2032 {
2033 return false;
2034 }
2035
2036 if (!ValidateGetQueryivBase(context, target, pname, length))
2037 {
2038 return false;
2039 }
2040
2041 if (!ValidateRobustBufferSize(context, bufSize, *length))
2042 {
2043 return false;
2044 }
2045
2046 return true;
2047}
2048
2049bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
2050{
2051 if (numParams)
2052 {
2053 *numParams = 0;
2054 }
2055
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002056 Query *queryObject = context->getQuery(id, false, GL_NONE);
2057
2058 if (!queryObject)
2059 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002060 context->handleError(InvalidOperation() << "Query does not exist");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002061 return false;
2062 }
2063
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002064 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002065 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002066 context->handleError(InvalidOperation() << "Query currently active");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002067 return false;
2068 }
2069
2070 switch (pname)
2071 {
2072 case GL_QUERY_RESULT_EXT:
2073 case GL_QUERY_RESULT_AVAILABLE_EXT:
2074 break;
2075
2076 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002077 context->handleError(InvalidEnum() << "Invalid pname enum");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002078 return false;
2079 }
2080
Geoff Lang2186c382016-10-14 10:54:54 -04002081 if (numParams)
2082 {
2083 *numParams = 1;
2084 }
2085
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002086 return true;
2087}
2088
2089bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
2090{
2091 if (!context->getExtensions().disjointTimerQuery)
2092 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002093 context->handleError(InvalidOperation() << "Timer query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002094 return false;
2095 }
Geoff Lang2186c382016-10-14 10:54:54 -04002096 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2097}
2098
2099bool ValidateGetQueryObjectivRobustANGLE(Context *context,
2100 GLuint id,
2101 GLenum pname,
2102 GLsizei bufSize,
2103 GLsizei *length,
2104 GLint *params)
2105{
2106 if (!context->getExtensions().disjointTimerQuery)
2107 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002108 context->handleError(InvalidOperation() << "Timer query extension not enabled");
Geoff Lang2186c382016-10-14 10:54:54 -04002109 return false;
2110 }
2111
2112 if (!ValidateRobustEntryPoint(context, bufSize))
2113 {
2114 return false;
2115 }
2116
2117 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2118 {
2119 return false;
2120 }
2121
2122 if (!ValidateRobustBufferSize(context, bufSize, *length))
2123 {
2124 return false;
2125 }
2126
2127 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002128}
2129
2130bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
2131{
2132 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002133 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002134 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002135 context->handleError(InvalidOperation() << "Query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002136 return false;
2137 }
Geoff Lang2186c382016-10-14 10:54:54 -04002138 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2139}
2140
2141bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
2142 GLuint id,
2143 GLenum pname,
2144 GLsizei bufSize,
2145 GLsizei *length,
2146 GLuint *params)
2147{
2148 if (!context->getExtensions().disjointTimerQuery &&
2149 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
2150 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002151 context->handleError(InvalidOperation() << "Query extension not enabled");
Geoff Lang2186c382016-10-14 10:54:54 -04002152 return false;
2153 }
2154
2155 if (!ValidateRobustEntryPoint(context, bufSize))
2156 {
2157 return false;
2158 }
2159
2160 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2161 {
2162 return false;
2163 }
2164
2165 if (!ValidateRobustBufferSize(context, bufSize, *length))
2166 {
2167 return false;
2168 }
2169
2170 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002171}
2172
2173bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
2174{
2175 if (!context->getExtensions().disjointTimerQuery)
2176 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002177 context->handleError(InvalidOperation() << "Timer query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002178 return false;
2179 }
Geoff Lang2186c382016-10-14 10:54:54 -04002180 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2181}
2182
2183bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
2184 GLuint id,
2185 GLenum pname,
2186 GLsizei bufSize,
2187 GLsizei *length,
2188 GLint64 *params)
2189{
2190 if (!context->getExtensions().disjointTimerQuery)
2191 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002192 context->handleError(InvalidOperation() << "Timer query extension not enabled");
Geoff Lang2186c382016-10-14 10:54:54 -04002193 return false;
2194 }
2195
2196 if (!ValidateRobustEntryPoint(context, bufSize))
2197 {
2198 return false;
2199 }
2200
2201 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2202 {
2203 return false;
2204 }
2205
2206 if (!ValidateRobustBufferSize(context, bufSize, *length))
2207 {
2208 return false;
2209 }
2210
2211 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002212}
2213
2214bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
2215{
2216 if (!context->getExtensions().disjointTimerQuery)
2217 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002218 context->handleError(InvalidOperation() << "Timer query extension not enabled");
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002219 return false;
2220 }
Geoff Lang2186c382016-10-14 10:54:54 -04002221 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2222}
2223
2224bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
2225 GLuint id,
2226 GLenum pname,
2227 GLsizei bufSize,
2228 GLsizei *length,
2229 GLuint64 *params)
2230{
2231 if (!context->getExtensions().disjointTimerQuery)
2232 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002233 context->handleError(InvalidOperation() << "Timer query extension not enabled");
Geoff Lang2186c382016-10-14 10:54:54 -04002234 return false;
2235 }
2236
2237 if (!ValidateRobustEntryPoint(context, bufSize))
2238 {
2239 return false;
2240 }
2241
2242 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2243 {
2244 return false;
2245 }
2246
2247 if (!ValidateRobustBufferSize(context, bufSize, *length))
2248 {
2249 return false;
2250 }
2251
2252 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002253}
2254
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002255bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002256 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002257 GLuint program,
2258 GLint location,
2259 GLsizei count)
2260{
2261 // Check for ES31 program uniform entry points
2262 if (context->getClientVersion() < Version(3, 1))
2263 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002264 context->handleError(InvalidOperation());
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002265 return false;
2266 }
2267
2268 const LinkedUniform *uniform = nullptr;
2269 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002270 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2271 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002272}
2273
Frank Henigmana98a6472017-02-02 21:38:32 -05002274bool ValidateProgramUniform1iv(gl::Context *context,
2275 GLuint program,
2276 GLint location,
2277 GLsizei count,
2278 const GLint *value)
2279{
2280 // Check for ES31 program uniform entry points
2281 if (context->getClientVersion() < Version(3, 1))
2282 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002283 context->handleError(InvalidOperation());
Frank Henigmana98a6472017-02-02 21:38:32 -05002284 return false;
2285 }
2286
2287 const LinkedUniform *uniform = nullptr;
2288 gl::Program *programObject = GetValidProgram(context, program);
2289 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2290 ValidateUniform1ivValue(context, uniform->type, count, value);
2291}
2292
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002293bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002294 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002295 GLuint program,
2296 GLint location,
2297 GLsizei count,
2298 GLboolean transpose)
2299{
2300 // Check for ES31 program uniform entry points
2301 if (context->getClientVersion() < Version(3, 1))
2302 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002303 context->handleError(InvalidOperation());
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002304 return false;
2305 }
2306
2307 const LinkedUniform *uniform = nullptr;
2308 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002309 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2310 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002311}
2312
Jamie Madillc1d770e2017-04-13 17:31:24 -04002313bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002314{
2315 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002316 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002317 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002318 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002319 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002320 }
2321
Jamie Madill62d31cb2015-09-11 13:25:51 -04002322 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002323 gl::Program *programObject = context->getGLState().getProgram();
2324 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2325 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002326}
2327
Jamie Madillbe849e42017-05-02 15:49:00 -04002328bool ValidateUniform1iv(ValidationContext *context,
2329 GLint location,
2330 GLsizei count,
2331 const GLint *value)
Frank Henigmana98a6472017-02-02 21:38:32 -05002332{
2333 const LinkedUniform *uniform = nullptr;
2334 gl::Program *programObject = context->getGLState().getProgram();
2335 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2336 ValidateUniform1ivValue(context, uniform->type, count, value);
2337}
2338
Jamie Madillc1d770e2017-04-13 17:31:24 -04002339bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002340 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08002341 GLint location,
2342 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04002343 GLboolean transpose)
2344{
2345 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002346 int rows = VariableRowCount(valueType);
2347 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03002348 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002349 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002350 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002351 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002352 }
2353
Martin Radev1be913c2016-07-11 17:59:16 +03002354 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002355 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002356 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002357 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002358 }
2359
Jamie Madill62d31cb2015-09-11 13:25:51 -04002360 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002361 gl::Program *programObject = context->getGLState().getProgram();
2362 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2363 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002364}
2365
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002366bool ValidateStateQuery(ValidationContext *context,
2367 GLenum pname,
2368 GLenum *nativeType,
2369 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04002370{
2371 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
2372 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002373 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04002374 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002375 }
2376
Jamie Madill0af26e12015-03-05 19:54:33 -05002377 const Caps &caps = context->getCaps();
2378
Jamie Madill893ab082014-05-16 16:56:10 -04002379 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
2380 {
2381 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
2382
Jamie Madill0af26e12015-03-05 19:54:33 -05002383 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04002384 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002385 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002386 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002387 }
2388 }
2389
2390 switch (pname)
2391 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002392 case GL_TEXTURE_BINDING_2D:
2393 case GL_TEXTURE_BINDING_CUBE_MAP:
2394 case GL_TEXTURE_BINDING_3D:
2395 case GL_TEXTURE_BINDING_2D_ARRAY:
2396 break;
2397 case GL_TEXTURE_BINDING_EXTERNAL_OES:
2398 if (!context->getExtensions().eglStreamConsumerExternal &&
2399 !context->getExtensions().eglImageExternal)
2400 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002401 context->handleError(InvalidEnum() << "Neither NV_EGL_stream_consumer_external "
2402 "nor GL_OES_EGL_image_external "
2403 "extensions enabled");
He Yunchaoced53ae2016-11-29 15:00:51 +08002404 return false;
2405 }
2406 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002407
He Yunchaoced53ae2016-11-29 15:00:51 +08002408 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2409 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04002410 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002411 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
2412 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04002413 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002414 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002415 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002416 }
2417
Jamie Madill51f40ec2016-06-15 14:06:00 -04002418 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
2419 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03002420
2421 if (framebuffer->getReadBufferState() == GL_NONE)
2422 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002423 context->handleError(InvalidOperation() << "Read buffer is GL_NONE");
Martin Radev138064f2016-07-15 12:03:41 +03002424 return false;
2425 }
2426
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002427 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04002428 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04002429 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002430 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002431 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002432 }
2433 }
2434 break;
2435
He Yunchaoced53ae2016-11-29 15:00:51 +08002436 default:
2437 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002438 }
2439
2440 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04002441 if (*numParams == 0)
2442 {
2443 return false;
2444 }
2445
2446 return true;
2447}
2448
2449bool ValidateRobustStateQuery(ValidationContext *context,
2450 GLenum pname,
2451 GLsizei bufSize,
2452 GLenum *nativeType,
2453 unsigned int *numParams)
2454{
2455 if (!ValidateRobustEntryPoint(context, bufSize))
2456 {
2457 return false;
2458 }
2459
2460 if (!ValidateStateQuery(context, pname, nativeType, numParams))
2461 {
2462 return false;
2463 }
2464
2465 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04002466 {
2467 return false;
2468 }
2469
2470 return true;
2471}
2472
Jamie Madillc29968b2016-01-20 11:17:23 -05002473bool ValidateCopyTexImageParametersBase(ValidationContext *context,
2474 GLenum target,
2475 GLint level,
2476 GLenum internalformat,
2477 bool isSubImage,
2478 GLint xoffset,
2479 GLint yoffset,
2480 GLint zoffset,
2481 GLint x,
2482 GLint y,
2483 GLsizei width,
2484 GLsizei height,
2485 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04002486 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04002487{
Jamie Madill560a8d82014-05-21 13:06:20 -04002488 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
2489 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002490 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002491 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002492 }
2493
He Yunchaoced53ae2016-11-29 15:00:51 +08002494 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
2495 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04002496 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002497 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002498 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002499 }
2500
2501 if (border != 0)
2502 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002503 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002504 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002505 }
2506
2507 if (!ValidMipLevel(context, target, level))
2508 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002509 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002510 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002511 }
2512
Jamie Madill51f40ec2016-06-15 14:06:00 -04002513 const auto &state = context->getGLState();
2514 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002515 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04002516 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002517 context->handleError(InvalidFramebufferOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002518 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002519 }
2520
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002521 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04002522 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002523 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002524 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002525 }
2526
Martin Radev138064f2016-07-15 12:03:41 +03002527 if (readFramebuffer->getReadBufferState() == GL_NONE)
2528 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002529 context->handleError(InvalidOperation() << "Read buffer is GL_NONE");
Martin Radev138064f2016-07-15 12:03:41 +03002530 return false;
2531 }
2532
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002533 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
2534 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08002535 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002536 // situation is an application error that would lead to a crash in ANGLE.
2537 if (readFramebuffer->getReadColorbuffer() == nullptr)
2538 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002539 context->handleError(InvalidOperation() << "Missing read attachment");
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002540 return false;
2541 }
2542
Geoff Langaae65a42014-05-26 12:43:44 -04002543 const gl::Caps &caps = context->getCaps();
2544
Geoff Langaae65a42014-05-26 12:43:44 -04002545 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04002546 switch (target)
2547 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002548 case GL_TEXTURE_2D:
2549 maxDimension = caps.max2DTextureSize;
2550 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002551
He Yunchaoced53ae2016-11-29 15:00:51 +08002552 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2553 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2554 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2555 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2556 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2557 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2558 maxDimension = caps.maxCubeMapTextureSize;
2559 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002560
He Yunchaoced53ae2016-11-29 15:00:51 +08002561 case GL_TEXTURE_2D_ARRAY:
2562 maxDimension = caps.max2DTextureSize;
2563 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002564
He Yunchaoced53ae2016-11-29 15:00:51 +08002565 case GL_TEXTURE_3D:
2566 maxDimension = caps.max3DTextureSize;
2567 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002568
He Yunchaoced53ae2016-11-29 15:00:51 +08002569 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002570 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08002571 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002572 }
2573
Jamie Madillc29968b2016-01-20 11:17:23 -05002574 gl::Texture *texture =
2575 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04002576 if (!texture)
2577 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002578 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002579 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002580 }
2581
Geoff Lang69cce582015-09-17 13:20:36 -04002582 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04002583 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002584 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002585 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002586 }
2587
Geoff Langca271392017-04-05 12:30:00 -04002588 const gl::InternalFormat &formatInfo =
2589 gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04002590
Geoff Lang966c9402017-04-18 12:38:27 -04002591 if (formatInfo.depthBits > 0 || formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04002592 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002593 context->handleError(InvalidOperation());
Geoff Langa9be0dc2014-12-17 12:34:40 -05002594 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002595 }
2596
2597 if (isSubImage)
2598 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05002599 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
2600 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
2601 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04002602 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002603 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002604 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002605 }
2606 }
Jamie Madill6f38f822014-06-06 17:12:20 -04002607 else
2608 {
Geoff Lang691e58c2014-12-19 17:03:25 -05002609 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04002610 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002611 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002612 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002613 }
2614
Geoff Langeb66a6e2016-10-31 13:06:12 -04002615 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04002616 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002617 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04002618 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002619 }
2620
2621 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08002622 if (static_cast<int>(width) > maxLevelDimension ||
2623 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04002624 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002625 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002626 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002627 }
2628 }
Jamie Madill560a8d82014-05-21 13:06:20 -04002629
Jamie Madill0c8abca2016-07-22 20:21:26 -04002630 if (textureFormatOut)
2631 {
2632 *textureFormatOut = texture->getFormat(target, level);
2633 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05002634
2635 // Detect texture copying feedback loops for WebGL.
2636 if (context->getExtensions().webglCompatibility)
2637 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05002638 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05002639 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002640 context->handleError(InvalidOperation() << "Texture copying feedback loop formed "
2641 "between Framebuffer and specified "
2642 "Texture level.");
Jamie Madillf695a3a2017-01-11 17:36:35 -05002643 return false;
2644 }
2645 }
2646
Jamie Madill560a8d82014-05-21 13:06:20 -04002647 return true;
2648}
2649
Jiajia Qind9671222016-11-29 16:30:31 +08002650bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04002651{
Jamie Madill1aeb1312014-06-20 13:21:25 -04002652 switch (mode)
2653 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002654 case GL_POINTS:
2655 case GL_LINES:
2656 case GL_LINE_LOOP:
2657 case GL_LINE_STRIP:
2658 case GL_TRIANGLES:
2659 case GL_TRIANGLE_STRIP:
2660 case GL_TRIANGLE_FAN:
2661 break;
2662 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002663 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08002664 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04002665 }
2666
Jamie Madill250d33f2014-06-06 17:09:03 -04002667 if (count < 0)
2668 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002669 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002670 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002671 }
2672
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002673 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04002674
Jamie Madill250d33f2014-06-06 17:09:03 -04002675 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002676 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002677 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002678 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002679 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002680 }
2681
Jamie Madillcbcde722017-01-06 14:50:00 -05002682 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
2683 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04002684 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002685 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
2686 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04002687 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002688 const FramebufferAttachment *dsAttachment =
2689 framebuffer->getStencilOrDepthStencilAttachment();
2690 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08002691 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04002692 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002693
2694 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
2695 bool differentWritemasks =
2696 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
2697 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
2698 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
2699 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
2700
2701 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04002702 {
Jamie Madillcbcde722017-01-06 14:50:00 -05002703 if (!context->getExtensions().webglCompatibility)
2704 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05002705 ERR() << "This ANGLE implementation does not support separate front/back stencil "
2706 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05002707 }
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002708 context->handleError(InvalidOperation());
Geoff Lang3a86ad32015-09-01 11:47:05 -04002709 return false;
2710 }
Jamie Madillac528012014-06-20 13:21:23 -04002711 }
2712
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002713 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002714 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002715 context->handleError(InvalidFramebufferOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002716 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002717 }
2718
Geoff Lang7dd2e102014-11-10 15:19:26 -05002719 gl::Program *program = state.getProgram();
2720 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002721 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002722 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002723 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002724 }
2725
Yunchao Hef81ce4a2017-04-24 10:49:17 +08002726 if (!program->validateSamplers(nullptr, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04002727 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002728 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002729 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002730 }
2731
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002732 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08002733 for (unsigned int uniformBlockIndex = 0;
2734 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002735 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04002736 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08002737 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04002738 const OffsetBindingPointer<Buffer> &uniformBuffer =
2739 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002740
Geoff Lang5d124a62015-09-15 13:03:27 -04002741 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002742 {
2743 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002744 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002745 InvalidOperation()
2746 << "It is undefined behaviour to have a used but unbound uniform buffer.");
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002747 return false;
2748 }
2749
Geoff Lang5d124a62015-09-15 13:03:27 -04002750 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002751 if (uniformBufferSize == 0)
2752 {
2753 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07002754 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002755 }
2756
Jamie Madill62d31cb2015-09-11 13:25:51 -04002757 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002758 {
2759 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002760 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002761 InvalidOperation()
2762 << "It is undefined behaviour to use a uniform buffer that is too small.");
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002763 return false;
2764 }
2765 }
2766
Geoff Lange0cff192017-05-30 13:04:56 -04002767 // Do some additonal WebGL-specific validation
Jamie Madilla4595b82017-01-11 17:36:34 -05002768 if (context->getExtensions().webglCompatibility)
2769 {
Geoff Lange0cff192017-05-30 13:04:56 -04002770 // Detect rendering feedback loops for WebGL.
Jamie Madilla4595b82017-01-11 17:36:34 -05002771 if (framebuffer->formsRenderingFeedbackLoopWith(state))
2772 {
2773 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002774 InvalidOperation()
2775 << "Rendering feedback loop formed between Framebuffer and active Texture.");
Jamie Madilla4595b82017-01-11 17:36:34 -05002776 return false;
2777 }
Geoff Lange0cff192017-05-30 13:04:56 -04002778
Geoff Lang9ab5b822017-05-30 16:19:23 -04002779 // Detect that the vertex shader input types match the attribute types
2780 if (!ValidateVertexShaderAttributeTypeMatch(context))
2781 {
2782 return false;
2783 }
2784
Geoff Lange0cff192017-05-30 13:04:56 -04002785 // Detect that the color buffer types match the fragment shader output types
2786 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
2787 {
2788 return false;
2789 }
Jamie Madilla4595b82017-01-11 17:36:34 -05002790 }
2791
Jamie Madill250d33f2014-06-06 17:09:03 -04002792 // No-op if zero count
2793 return (count > 0);
2794}
2795
Jamie Madillc1d770e2017-04-13 17:31:24 -04002796bool ValidateDrawArraysCommon(ValidationContext *context,
2797 GLenum mode,
2798 GLint first,
2799 GLsizei count,
2800 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04002801{
Jamie Madillfd716582014-06-06 17:09:04 -04002802 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04002803 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002804 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04002805 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002806 }
2807
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002808 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002809 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002810 if (curTransformFeedback && curTransformFeedback->isActive() &&
2811 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04002812 {
2813 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08002814 // that does not match the current transform feedback object's draw mode (if transform
2815 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04002816 // is active), (3.0.2, section 2.14, pg 86)
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002817 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002818 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002819 }
2820
Jiajia Qind9671222016-11-29 16:30:31 +08002821 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002822 {
2823 return false;
2824 }
2825
Corentin Wallez71168a02016-12-19 15:11:18 -08002826 // Check the computation of maxVertex doesn't overflow.
2827 // - first < 0 or count < 0 have been checked as an error condition
2828 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
2829 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
2830 ASSERT(count > 0 && first >= 0);
2831 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
2832 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05002833 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002834 context->handleError(InvalidOperation() << "Integer overflow.");
Corentin Wallez92db6942016-12-09 13:10:36 -05002835 return false;
2836 }
2837
Corentin Wallez71168a02016-12-19 15:11:18 -08002838 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04002839 {
2840 return false;
2841 }
2842
2843 return true;
2844}
2845
He Yunchaoced53ae2016-11-29 15:00:51 +08002846bool ValidateDrawArraysInstanced(Context *context,
2847 GLenum mode,
2848 GLint first,
2849 GLsizei count,
2850 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04002851{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002852 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04002853 {
2854 return false;
2855 }
2856
Corentin Wallez170efbf2017-05-02 13:45:01 -04002857 return !context->getExtensions().webglCompatibility ||
2858 ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002859}
2860
He Yunchaoced53ae2016-11-29 15:00:51 +08002861bool ValidateDrawArraysInstancedANGLE(Context *context,
2862 GLenum mode,
2863 GLint first,
2864 GLsizei count,
2865 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04002866{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002867 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04002868 {
2869 return false;
2870 }
2871
Corentin Wallez170efbf2017-05-02 13:45:01 -04002872 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002873}
2874
Jiajia Qind9671222016-11-29 16:30:31 +08002875bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04002876{
Jamie Madill250d33f2014-06-06 17:09:03 -04002877 switch (type)
2878 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002879 case GL_UNSIGNED_BYTE:
2880 case GL_UNSIGNED_SHORT:
2881 break;
2882 case GL_UNSIGNED_INT:
2883 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2884 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002885 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08002886 return false;
2887 }
2888 break;
2889 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002890 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08002891 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002892 }
2893
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002894 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002895
2896 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002897 if (curTransformFeedback && curTransformFeedback->isActive() &&
2898 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002899 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002900 // It is an invalid operation to call DrawElements, DrawRangeElements or
2901 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04002902 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002903 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002904 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002905 }
2906
Jiajia Qind9671222016-11-29 16:30:31 +08002907 return true;
2908}
2909
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002910bool ValidateDrawElementsCommon(ValidationContext *context,
2911 GLenum mode,
2912 GLsizei count,
2913 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04002914 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002915 GLsizei primcount)
Jiajia Qind9671222016-11-29 16:30:31 +08002916{
2917 if (!ValidateDrawElementsBase(context, type))
2918 return false;
2919
2920 const State &state = context->getGLState();
2921
Corentin Wallez170efbf2017-05-02 13:45:01 -04002922 if (!ValidateDrawBase(context, mode, count))
2923 {
2924 return false;
2925 }
2926
Jamie Madill250d33f2014-06-06 17:09:03 -04002927 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002928 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002929 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002930 context->handleError(InvalidOperation() << "Index buffer is mapped.");
Geoff Langb1196682014-07-23 13:47:29 -04002931 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002932 }
2933
He Yunchaoced53ae2016-11-29 15:00:51 +08002934 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002935 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04002936
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002937 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
2938
2939 if (context->getExtensions().webglCompatibility)
2940 {
2941 ASSERT(isPow2(typeBytes) && typeBytes > 0);
2942 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
2943 {
2944 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2945 // The offset arguments to drawElements and [...], must be a multiple of the size of the
2946 // data type passed to the call, or an INVALID_OPERATION error is generated.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002947 context->handleError(InvalidOperation()
2948 << "indices must be a multiple of the element type size.");
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002949 return false;
2950 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002951
2952 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2953 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
2954 // error is generated.
2955 if (reinterpret_cast<intptr_t>(indices) < 0)
2956 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002957 context->handleError(InvalidValue() << "Offset < 0.");
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002958 return false;
2959 }
Geoff Langfeb8c682017-02-13 16:07:35 -05002960 }
2961
2962 if (context->getExtensions().webglCompatibility ||
2963 !context->getGLState().areClientArraysEnabled())
2964 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002965 if (!elementArrayBuffer && count > 0)
2966 {
2967 // [WebGL 1.0] Section 6.2 No Client Side Arrays
2968 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
2969 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002970 context->handleError(InvalidOperation()
2971 << "There is no element array buffer bound and count > 0.");
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002972 return false;
2973 }
2974 }
2975
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002976 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04002977 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002978 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04002979 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002980 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
2981 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
2982 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
2983 constexpr uint64_t kMaxTypeSize = 8;
2984 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
2985 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
2986 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002987
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002988 uint64_t typeSize = typeBytes;
2989 uint64_t elementCount = static_cast<uint64_t>(count);
2990 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
2991
2992 // Doing the multiplication here is overflow-safe
2993 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
2994
2995 // The offset can be any value, check for overflows
2996 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
2997 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002998 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002999 context->handleError(InvalidOperation() << "Integer overflow.");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003000 return false;
3001 }
3002
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003003 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
3004 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003005 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003006 context->handleError(InvalidOperation()
3007 << "Index buffer is not big enough for the draw.");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003008 return false;
3009 }
3010 }
3011 else if (!indices)
3012 {
3013 // This is an application error that would normally result in a crash,
3014 // but we catch it and return an error
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003015 context->handleError(InvalidOperation() << "No element array buffer and no pointer.");
Geoff Langb1196682014-07-23 13:47:29 -04003016 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04003017 }
Jamie Madillae3000b2014-08-25 15:47:51 -04003018 }
3019
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003020 // Use the parameter buffer to retrieve and cache the index range.
Jamie Madill2b976812014-08-25 15:47:49 -04003021 // TODO: offer fast path, with disabled index validation.
3022 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003023 const auto &params = context->getParams<HasIndexRange>();
3024 const auto &indexRangeOpt = params.getIndexRange();
3025 if (!indexRangeOpt.valid())
Jamie Madill2b976812014-08-25 15:47:49 -04003026 {
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003027 // Unexpected error.
3028 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04003029 }
3030
Jamie Madille79b1e12015-11-04 16:36:37 -05003031 // If we use an index greater than our maximum supported index range, return an error.
3032 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
3033 // return an error if possible here.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003034 if (static_cast<GLuint64>(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex)
Jamie Madille79b1e12015-11-04 16:36:37 -05003035 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003036 context->handleError(InvalidOperation() << g_ExceedsMaxElementErrorMessage);
Jamie Madille79b1e12015-11-04 16:36:37 -05003037 return false;
3038 }
3039
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003040 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOpt.value().end),
3041 static_cast<GLint>(indexRangeOpt.value().vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04003042 {
3043 return false;
3044 }
3045
Geoff Lang3edfe032015-09-04 16:38:24 -04003046 // No op if there are no real indices in the index data (all are primitive restart).
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003047 return (indexRangeOpt.value().vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04003048}
3049
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003050bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
3051 GLenum mode,
3052 GLsizei count,
3053 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003054 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003055 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003056{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003057 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04003058 {
3059 return false;
3060 }
3061
Corentin Wallez170efbf2017-05-02 13:45:01 -04003062 return !context->getExtensions().webglCompatibility ||
3063 ValidateDrawInstancedANGLEAndWebGL(context);
Jamie Madill250d33f2014-06-06 17:09:03 -04003064}
3065
Geoff Lang3edfe032015-09-04 16:38:24 -04003066bool ValidateDrawElementsInstancedANGLE(Context *context,
3067 GLenum mode,
3068 GLsizei count,
3069 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003070 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003071 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003072{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003073 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04003074 {
3075 return false;
3076 }
3077
Corentin Wallez170efbf2017-05-02 13:45:01 -04003078 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04003079}
3080
He Yunchaoced53ae2016-11-29 15:00:51 +08003081bool ValidateFramebufferTextureBase(Context *context,
3082 GLenum target,
3083 GLenum attachment,
3084 GLuint texture,
3085 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04003086{
Jamie Madill55ec3b12014-07-03 10:38:57 -04003087 if (!ValidFramebufferTarget(target))
3088 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003089 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04003090 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003091 }
3092
3093 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04003094 {
3095 return false;
3096 }
3097
Jamie Madill55ec3b12014-07-03 10:38:57 -04003098 if (texture != 0)
3099 {
3100 gl::Texture *tex = context->getTexture(texture);
3101
Jamie Madillbe849e42017-05-02 15:49:00 -04003102 if (tex == NULL)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003103 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003104 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04003105 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003106 }
3107
3108 if (level < 0)
3109 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003110 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04003111 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003112 }
3113 }
3114
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003115 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04003116 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04003117
Jamie Madill84115c92015-04-23 15:00:07 -04003118 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003119 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003120 context->handleError(InvalidOperation() << "Cannot change default FBO's attachments");
Geoff Langb1196682014-07-23 13:47:29 -04003121 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003122 }
3123
3124 return true;
3125}
3126
Geoff Langb1196682014-07-23 13:47:29 -04003127bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04003128{
3129 if (program == 0)
3130 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003131 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04003132 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003133 }
3134
Dian Xiang769769a2015-09-09 15:20:08 -07003135 gl::Program *programObject = GetValidProgram(context, program);
3136 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05003137 {
3138 return false;
3139 }
3140
Jamie Madill0063c512014-08-25 15:47:53 -04003141 if (!programObject || !programObject->isLinked())
3142 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003143 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04003144 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003145 }
3146
Geoff Lang7dd2e102014-11-10 15:19:26 -05003147 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04003148 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003149 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04003150 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04003151 }
3152
Jamie Madill0063c512014-08-25 15:47:53 -04003153 return true;
3154}
3155
Geoff Langf41d0ee2016-10-07 13:04:23 -04003156static bool ValidateSizedGetUniform(Context *context,
3157 GLuint program,
3158 GLint location,
3159 GLsizei bufSize,
3160 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04003161{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003162 if (length)
3163 {
3164 *length = 0;
3165 }
3166
Jamie Madill78f41802014-08-25 15:47:55 -04003167 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04003168 {
Jamie Madill78f41802014-08-25 15:47:55 -04003169 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003170 }
3171
Geoff Langf41d0ee2016-10-07 13:04:23 -04003172 if (bufSize < 0)
3173 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003174 context->handleError(InvalidValue() << "bufSize cannot be negative.");
Geoff Langf41d0ee2016-10-07 13:04:23 -04003175 return false;
3176 }
3177
Jamie Madilla502c742014-08-28 17:19:13 -04003178 gl::Program *programObject = context->getProgram(program);
3179 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04003180
Jamie Madill78f41802014-08-25 15:47:55 -04003181 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04003182 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08003183 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04003184 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04003185 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003186 context->handleError(InvalidOperation()
3187 << "bufSize of at least " << requiredBytes << " is required.");
Geoff Langb1196682014-07-23 13:47:29 -04003188 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003189 }
3190
Geoff Langf41d0ee2016-10-07 13:04:23 -04003191 if (length)
3192 {
Geoff Lang94177fb2016-11-14 16:12:26 -05003193 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04003194 }
3195
Jamie Madill0063c512014-08-25 15:47:53 -04003196 return true;
3197}
3198
He Yunchaoced53ae2016-11-29 15:00:51 +08003199bool ValidateGetnUniformfvEXT(Context *context,
3200 GLuint program,
3201 GLint location,
3202 GLsizei bufSize,
3203 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003204{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003205 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04003206}
3207
He Yunchaoced53ae2016-11-29 15:00:51 +08003208bool ValidateGetnUniformivEXT(Context *context,
3209 GLuint program,
3210 GLint location,
3211 GLsizei bufSize,
3212 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003213{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003214 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3215}
3216
3217bool ValidateGetUniformfvRobustANGLE(Context *context,
3218 GLuint program,
3219 GLint location,
3220 GLsizei bufSize,
3221 GLsizei *length,
3222 GLfloat *params)
3223{
3224 if (!ValidateRobustEntryPoint(context, bufSize))
3225 {
3226 return false;
3227 }
3228
3229 // bufSize is validated in ValidateSizedGetUniform
3230 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3231}
3232
3233bool ValidateGetUniformivRobustANGLE(Context *context,
3234 GLuint program,
3235 GLint location,
3236 GLsizei bufSize,
3237 GLsizei *length,
3238 GLint *params)
3239{
3240 if (!ValidateRobustEntryPoint(context, bufSize))
3241 {
3242 return false;
3243 }
3244
3245 // bufSize is validated in ValidateSizedGetUniform
3246 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3247}
3248
3249bool ValidateGetUniformuivRobustANGLE(Context *context,
3250 GLuint program,
3251 GLint location,
3252 GLsizei bufSize,
3253 GLsizei *length,
3254 GLuint *params)
3255{
3256 if (!ValidateRobustEntryPoint(context, bufSize))
3257 {
3258 return false;
3259 }
3260
3261 if (context->getClientMajorVersion() < 3)
3262 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003263 context->handleError(InvalidOperation() << "Entry point requires at least OpenGL ES 3.0.");
Geoff Langf41d0ee2016-10-07 13:04:23 -04003264 return false;
3265 }
3266
3267 // bufSize is validated in ValidateSizedGetUniform
3268 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04003269}
3270
He Yunchaoced53ae2016-11-29 15:00:51 +08003271bool ValidateDiscardFramebufferBase(Context *context,
3272 GLenum target,
3273 GLsizei numAttachments,
3274 const GLenum *attachments,
3275 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07003276{
3277 if (numAttachments < 0)
3278 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003279 context->handleError(InvalidValue() << "numAttachments must not be less than zero");
Austin Kinross08332632015-05-05 13:35:47 -07003280 return false;
3281 }
3282
3283 for (GLsizei i = 0; i < numAttachments; ++i)
3284 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02003285 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07003286 {
3287 if (defaultFramebuffer)
3288 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003289 context->handleError(InvalidEnum()
3290 << "Invalid attachment when the default framebuffer is bound");
Austin Kinross08332632015-05-05 13:35:47 -07003291 return false;
3292 }
3293
3294 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
3295 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003296 context->handleError(InvalidOperation() << "Requested color attachment is "
3297 "greater than the maximum supported "
3298 "color attachments");
Austin Kinross08332632015-05-05 13:35:47 -07003299 return false;
3300 }
3301 }
3302 else
3303 {
3304 switch (attachments[i])
3305 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003306 case GL_DEPTH_ATTACHMENT:
3307 case GL_STENCIL_ATTACHMENT:
3308 case GL_DEPTH_STENCIL_ATTACHMENT:
3309 if (defaultFramebuffer)
3310 {
3311 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003312 InvalidEnum()
3313 << "Invalid attachment when the default framebuffer is bound");
He Yunchaoced53ae2016-11-29 15:00:51 +08003314 return false;
3315 }
3316 break;
3317 case GL_COLOR:
3318 case GL_DEPTH:
3319 case GL_STENCIL:
3320 if (!defaultFramebuffer)
3321 {
3322 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003323 InvalidEnum()
3324 << "Invalid attachment when the default framebuffer is not bound");
He Yunchaoced53ae2016-11-29 15:00:51 +08003325 return false;
3326 }
3327 break;
3328 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003329 context->handleError(InvalidEnum() << "Invalid attachment");
Austin Kinross08332632015-05-05 13:35:47 -07003330 return false;
Austin Kinross08332632015-05-05 13:35:47 -07003331 }
3332 }
3333 }
3334
3335 return true;
3336}
3337
Austin Kinross6ee1e782015-05-29 17:05:37 -07003338bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
3339{
3340 // Note that debug marker calls must not set error state
3341
3342 if (length < 0)
3343 {
3344 return false;
3345 }
3346
3347 if (marker == nullptr)
3348 {
3349 return false;
3350 }
3351
3352 return true;
3353}
3354
3355bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
3356{
3357 // Note that debug marker calls must not set error state
3358
3359 if (length < 0)
3360 {
3361 return false;
3362 }
3363
3364 if (length > 0 && marker == nullptr)
3365 {
3366 return false;
3367 }
3368
3369 return true;
3370}
3371
Geoff Langdcab33b2015-07-21 13:03:16 -04003372bool ValidateEGLImageTargetTexture2DOES(Context *context,
Geoff Langdcab33b2015-07-21 13:03:16 -04003373 GLenum target,
3374 egl::Image *image)
3375{
Geoff Langa8406172015-07-21 16:53:39 -04003376 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
3377 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003378 context->handleError(InvalidOperation());
Geoff Langa8406172015-07-21 16:53:39 -04003379 return false;
3380 }
3381
3382 switch (target)
3383 {
3384 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04003385 if (!context->getExtensions().eglImage)
3386 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003387 context->handleError(InvalidEnum()
3388 << "GL_TEXTURE_2D texture target requires GL_OES_EGL_image.");
Geoff Langb66a9092016-05-16 15:59:14 -04003389 }
3390 break;
3391
3392 case GL_TEXTURE_EXTERNAL_OES:
3393 if (!context->getExtensions().eglImageExternal)
3394 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003395 context->handleError(InvalidEnum() << "GL_TEXTURE_EXTERNAL_OES texture target "
3396 "requires GL_OES_EGL_image_external.");
Geoff Langb66a9092016-05-16 15:59:14 -04003397 }
Geoff Langa8406172015-07-21 16:53:39 -04003398 break;
3399
3400 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003401 context->handleError(InvalidEnum() << "invalid texture target.");
Geoff Langa8406172015-07-21 16:53:39 -04003402 return false;
3403 }
3404
Jamie Madill61e16b42017-06-19 11:13:23 -04003405 ASSERT(context->getCurrentDisplay());
3406 if (!context->getCurrentDisplay()->isValidImage(image))
Geoff Langa8406172015-07-21 16:53:39 -04003407 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003408 context->handleError(InvalidValue() << "EGL image is not valid.");
Geoff Langa8406172015-07-21 16:53:39 -04003409 return false;
3410 }
3411
3412 if (image->getSamples() > 0)
3413 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003414 context->handleError(InvalidOperation()
3415 << "cannot create a 2D texture from a multisampled EGL image.");
Geoff Langa8406172015-07-21 16:53:39 -04003416 return false;
3417 }
3418
Geoff Langca271392017-04-05 12:30:00 -04003419 const TextureCaps &textureCaps =
3420 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003421 if (!textureCaps.texturable)
3422 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003423 context->handleError(InvalidOperation()
3424 << "EGL image internal format is not supported as a texture.");
Geoff Langa8406172015-07-21 16:53:39 -04003425 return false;
3426 }
3427
Geoff Langdcab33b2015-07-21 13:03:16 -04003428 return true;
3429}
3430
3431bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
Geoff Langdcab33b2015-07-21 13:03:16 -04003432 GLenum target,
3433 egl::Image *image)
3434{
Geoff Langa8406172015-07-21 16:53:39 -04003435 if (!context->getExtensions().eglImage)
3436 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003437 context->handleError(InvalidOperation());
Geoff Langa8406172015-07-21 16:53:39 -04003438 return false;
3439 }
3440
3441 switch (target)
3442 {
3443 case GL_RENDERBUFFER:
3444 break;
3445
3446 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003447 context->handleError(InvalidEnum() << "invalid renderbuffer target.");
Geoff Langa8406172015-07-21 16:53:39 -04003448 return false;
3449 }
3450
Jamie Madill61e16b42017-06-19 11:13:23 -04003451 ASSERT(context->getCurrentDisplay());
3452 if (!context->getCurrentDisplay()->isValidImage(image))
Geoff Langa8406172015-07-21 16:53:39 -04003453 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003454 context->handleError(InvalidValue() << "EGL image is not valid.");
Geoff Langa8406172015-07-21 16:53:39 -04003455 return false;
3456 }
3457
Geoff Langca271392017-04-05 12:30:00 -04003458 const TextureCaps &textureCaps =
3459 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003460 if (!textureCaps.renderable)
3461 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003462 context->handleError(InvalidOperation()
3463 << "EGL image internal format is not supported as a renderbuffer.");
Geoff Langa8406172015-07-21 16:53:39 -04003464 return false;
3465 }
3466
Geoff Langdcab33b2015-07-21 13:03:16 -04003467 return true;
3468}
Austin Kinrossbc781f32015-10-26 09:27:38 -07003469
3470bool ValidateBindVertexArrayBase(Context *context, GLuint array)
3471{
Geoff Lang36167ab2015-12-07 10:27:14 -05003472 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07003473 {
3474 // The default VAO should always exist
3475 ASSERT(array != 0);
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003476 context->handleError(InvalidOperation());
Austin Kinrossbc781f32015-10-26 09:27:38 -07003477 return false;
3478 }
3479
3480 return true;
3481}
3482
Geoff Langc5629752015-12-07 16:29:04 -05003483bool ValidateProgramBinaryBase(Context *context,
3484 GLuint program,
3485 GLenum binaryFormat,
3486 const void *binary,
3487 GLint length)
3488{
3489 Program *programObject = GetValidProgram(context, program);
3490 if (programObject == nullptr)
3491 {
3492 return false;
3493 }
3494
3495 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3496 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3497 programBinaryFormats.end())
3498 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003499 context->handleError(InvalidEnum() << "Program binary format is not valid.");
Geoff Langc5629752015-12-07 16:29:04 -05003500 return false;
3501 }
3502
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003503 if (context->hasActiveTransformFeedback(program))
3504 {
3505 // ES 3.0.4 section 2.15 page 91
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003506 context->handleError(InvalidOperation() << "Cannot change program binary while program "
3507 "is associated with an active transform "
3508 "feedback object.");
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003509 return false;
3510 }
3511
Geoff Langc5629752015-12-07 16:29:04 -05003512 return true;
3513}
3514
3515bool ValidateGetProgramBinaryBase(Context *context,
3516 GLuint program,
3517 GLsizei bufSize,
3518 GLsizei *length,
3519 GLenum *binaryFormat,
3520 void *binary)
3521{
3522 Program *programObject = GetValidProgram(context, program);
3523 if (programObject == nullptr)
3524 {
3525 return false;
3526 }
3527
3528 if (!programObject->isLinked())
3529 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003530 context->handleError(InvalidOperation() << "Program is not linked.");
Geoff Langc5629752015-12-07 16:29:04 -05003531 return false;
3532 }
3533
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003534 if (context->getCaps().programBinaryFormats.empty())
3535 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003536 context->handleError(InvalidOperation() << "No program binary formats supported.");
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003537 return false;
3538 }
3539
Geoff Langc5629752015-12-07 16:29:04 -05003540 return true;
3541}
Jamie Madillc29968b2016-01-20 11:17:23 -05003542
Jamie Madillc29968b2016-01-20 11:17:23 -05003543bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
3544{
3545 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3546 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3547 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003548 context->handleError(InvalidValue()
3549 << "n must be non-negative and no greater than MAX_DRAW_BUFFERS");
Jamie Madillc29968b2016-01-20 11:17:23 -05003550 return false;
3551 }
3552
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003553 ASSERT(context->getGLState().getDrawFramebuffer());
3554 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05003555 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3556
3557 // This should come first before the check for the default frame buffer
3558 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3559 // rather than INVALID_OPERATION
3560 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3561 {
3562 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3563
3564 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02003565 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3566 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05003567 {
3568 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02003569 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3570 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3571 // 3.1 is still a bit ambiguous about the error, but future specs are
3572 // expected to clarify that GL_INVALID_ENUM is the correct error.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003573 context->handleError(InvalidEnum() << "Invalid buffer value");
Olli Etuaho84c9f592016-03-09 14:37:25 +02003574 return false;
3575 }
3576 else if (bufs[colorAttachment] >= maxColorAttachment)
3577 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003578 context->handleError(InvalidOperation()
3579 << "Buffer value is greater than MAX_DRAW_BUFFERS");
Jamie Madillc29968b2016-01-20 11:17:23 -05003580 return false;
3581 }
3582 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3583 frameBufferId != 0)
3584 {
3585 // INVALID_OPERATION-GL is bound to buffer and ith argument
3586 // is not COLOR_ATTACHMENTi or NONE
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003587 context->handleError(InvalidOperation()
3588 << "Ith value does not match COLOR_ATTACHMENTi or NONE");
Jamie Madillc29968b2016-01-20 11:17:23 -05003589 return false;
3590 }
3591 }
3592
3593 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3594 // and n is not 1 or bufs is bound to value other than BACK and NONE
3595 if (frameBufferId == 0)
3596 {
3597 if (n != 1)
3598 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003599 context->handleError(InvalidOperation()
3600 << "n must be 1 when GL is bound to the default framebuffer");
Jamie Madillc29968b2016-01-20 11:17:23 -05003601 return false;
3602 }
3603
3604 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3605 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003606 context->handleError(
3607 InvalidOperation()
3608 << "Only NONE or BACK are valid values when drawing to the default framebuffer");
Jamie Madillc29968b2016-01-20 11:17:23 -05003609 return false;
3610 }
3611 }
3612
3613 return true;
3614}
3615
Geoff Lang496c02d2016-10-20 11:38:11 -07003616bool ValidateGetBufferPointervBase(Context *context,
3617 GLenum target,
3618 GLenum pname,
3619 GLsizei *length,
3620 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03003621{
Geoff Lang496c02d2016-10-20 11:38:11 -07003622 if (length)
3623 {
3624 *length = 0;
3625 }
3626
3627 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
3628 {
3629 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003630 InvalidOperation()
3631 << "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled.");
Geoff Lang496c02d2016-10-20 11:38:11 -07003632 return false;
3633 }
3634
Olli Etuaho4f667482016-03-30 15:56:35 +03003635 if (!ValidBufferTarget(context, target))
3636 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003637 context->handleError(InvalidEnum() << "Buffer target not valid: 0x" << std::hex
3638 << std::uppercase << target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003639 return false;
3640 }
3641
Geoff Lang496c02d2016-10-20 11:38:11 -07003642 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03003643 {
Geoff Lang496c02d2016-10-20 11:38:11 -07003644 case GL_BUFFER_MAP_POINTER:
3645 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03003646
Geoff Lang496c02d2016-10-20 11:38:11 -07003647 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003648 context->handleError(InvalidEnum() << "Unknown pname.");
Geoff Lang496c02d2016-10-20 11:38:11 -07003649 return false;
3650 }
Olli Etuaho4f667482016-03-30 15:56:35 +03003651
3652 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3653 // target bound to zero generate an INVALID_OPERATION error."
3654 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07003655 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03003656 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003657 context->handleError(InvalidOperation()
3658 << "Can not get pointer for reserved buffer name zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003659 return false;
3660 }
3661
Geoff Lang496c02d2016-10-20 11:38:11 -07003662 if (length)
3663 {
3664 *length = 1;
3665 }
3666
Olli Etuaho4f667482016-03-30 15:56:35 +03003667 return true;
3668}
3669
3670bool ValidateUnmapBufferBase(Context *context, GLenum target)
3671{
3672 if (!ValidBufferTarget(context, target))
3673 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003674 context->handleError(InvalidEnum() << "Invalid buffer target.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003675 return false;
3676 }
3677
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003678 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003679
3680 if (buffer == nullptr || !buffer->isMapped())
3681 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003682 context->handleError(InvalidOperation() << "Buffer not mapped.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003683 return false;
3684 }
3685
3686 return true;
3687}
3688
3689bool ValidateMapBufferRangeBase(Context *context,
3690 GLenum target,
3691 GLintptr offset,
3692 GLsizeiptr length,
3693 GLbitfield access)
3694{
3695 if (!ValidBufferTarget(context, target))
3696 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003697 context->handleError(InvalidEnum() << "Invalid buffer target.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003698 return false;
3699 }
3700
3701 if (offset < 0 || length < 0)
3702 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003703 context->handleError(InvalidValue() << "Invalid offset or length.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003704 return false;
3705 }
3706
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003707 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003708
3709 if (!buffer)
3710 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003711 context->handleError(InvalidOperation() << "Attempted to map buffer object zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003712 return false;
3713 }
3714
3715 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003716 CheckedNumeric<size_t> checkedOffset(offset);
3717 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003718
Jamie Madille2e406c2016-06-02 13:04:10 -04003719 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003720 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003721 context->handleError(InvalidValue() << "Mapped range does not fit into buffer dimensions.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003722 return false;
3723 }
3724
3725 // Check for invalid bits in the mask
3726 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3727 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3728 GL_MAP_UNSYNCHRONIZED_BIT;
3729
3730 if (access & ~(allAccessBits))
3731 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003732 context->handleError(InvalidValue()
3733 << "Invalid access bits: 0x" << std::hex << std::uppercase << access);
Olli Etuaho4f667482016-03-30 15:56:35 +03003734 return false;
3735 }
3736
3737 if (length == 0)
3738 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003739 context->handleError(InvalidOperation() << "Buffer mapping length is zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003740 return false;
3741 }
3742
3743 if (buffer->isMapped())
3744 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003745 context->handleError(InvalidOperation() << "Buffer is already mapped.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003746 return false;
3747 }
3748
3749 // Check for invalid bit combinations
3750 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3751 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003752 context->handleError(InvalidOperation()
3753 << "Need to map buffer for either reading or writing.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003754 return false;
3755 }
3756
3757 GLbitfield writeOnlyBits =
3758 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3759
3760 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3761 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003762 context->handleError(InvalidOperation()
3763 << "Invalid access bits when mapping buffer for reading: 0x"
3764 << std::hex << std::uppercase << access);
Olli Etuaho4f667482016-03-30 15:56:35 +03003765 return false;
3766 }
3767
3768 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3769 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003770 context->handleError(
3771 InvalidOperation()
3772 << "The explicit flushing bit may only be set if the buffer is mapped for writing.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003773 return false;
3774 }
3775 return true;
3776}
3777
3778bool ValidateFlushMappedBufferRangeBase(Context *context,
3779 GLenum target,
3780 GLintptr offset,
3781 GLsizeiptr length)
3782{
3783 if (offset < 0 || length < 0)
3784 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003785 context->handleError(InvalidValue() << "Invalid offset/length parameters.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003786 return false;
3787 }
3788
3789 if (!ValidBufferTarget(context, target))
3790 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003791 context->handleError(InvalidEnum() << "Invalid buffer target.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003792 return false;
3793 }
3794
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003795 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003796
3797 if (buffer == nullptr)
3798 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003799 context->handleError(InvalidOperation() << "Attempted to flush buffer object zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003800 return false;
3801 }
3802
3803 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3804 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003805 context->handleError(InvalidOperation()
3806 << "Attempted to flush a buffer not mapped for explicit flushing.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003807 return false;
3808 }
3809
3810 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003811 CheckedNumeric<size_t> checkedOffset(offset);
3812 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003813
Jamie Madille2e406c2016-06-02 13:04:10 -04003814 if (!checkedSize.IsValid() ||
3815 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003816 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003817 context->handleError(InvalidValue()
3818 << "Flushed range does not fit into buffer mapping dimensions.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003819 return false;
3820 }
3821
3822 return true;
3823}
3824
Olli Etuaho41997e72016-03-10 13:38:39 +02003825bool ValidateGenOrDelete(Context *context, GLint n)
3826{
3827 if (n < 0)
3828 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003829 context->handleError(InvalidValue() << "n < 0");
Olli Etuaho41997e72016-03-10 13:38:39 +02003830 return false;
3831 }
3832 return true;
3833}
3834
Geoff Langff5b2d52016-09-07 11:32:23 -04003835bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
3836{
3837 if (!context->getExtensions().robustClientMemory)
3838 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003839 context->handleError(InvalidOperation()
3840 << "GL_ANGLE_robust_client_memory is not available.");
Geoff Langff5b2d52016-09-07 11:32:23 -04003841 return false;
3842 }
3843
3844 if (bufSize < 0)
3845 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003846 context->handleError(InvalidValue() << "bufSize cannot be negative.");
Geoff Langff5b2d52016-09-07 11:32:23 -04003847 return false;
3848 }
3849
3850 return true;
3851}
3852
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003853bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
3854{
3855 if (bufSize < numParams)
3856 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003857 context->handleError(InvalidOperation() << numParams << " parameters are required but "
3858 << bufSize << " were provided.");
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003859 return false;
3860 }
3861
3862 return true;
3863}
3864
Jamie Madillbe849e42017-05-02 15:49:00 -04003865bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context,
3866 GLenum target,
3867 GLenum attachment,
3868 GLenum pname,
3869 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04003870{
3871 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08003872 if (numParams)
3873 {
3874 *numParams = 1;
3875 }
Geoff Langff5b2d52016-09-07 11:32:23 -04003876
3877 if (!ValidFramebufferTarget(target))
3878 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003879 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003880 return false;
3881 }
3882
3883 int clientVersion = context->getClientMajorVersion();
3884
3885 switch (pname)
3886 {
3887 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3888 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3889 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3890 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3891 break;
3892
3893 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3894 if (clientVersion < 3 && !context->getExtensions().sRGB)
3895 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003896 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003897 return false;
3898 }
3899 break;
3900
3901 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3902 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3903 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3904 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3905 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3906 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3907 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3908 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3909 if (clientVersion < 3)
3910 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003911 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003912 return false;
3913 }
3914 break;
3915
3916 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003917 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003918 return false;
3919 }
3920
3921 // Determine if the attachment is a valid enum
3922 switch (attachment)
3923 {
3924 case GL_BACK:
3925 case GL_FRONT:
3926 case GL_DEPTH:
3927 case GL_STENCIL:
3928 case GL_DEPTH_STENCIL_ATTACHMENT:
3929 if (clientVersion < 3)
3930 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003931 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003932 return false;
3933 }
3934 break;
3935
3936 case GL_DEPTH_ATTACHMENT:
3937 case GL_STENCIL_ATTACHMENT:
3938 break;
3939
3940 default:
3941 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
3942 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3943 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003944 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003945 return false;
3946 }
3947 break;
3948 }
3949
3950 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
3951 ASSERT(framebuffer);
3952
3953 if (framebuffer->id() == 0)
3954 {
3955 if (clientVersion < 3)
3956 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003957 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003958 return false;
3959 }
3960
3961 switch (attachment)
3962 {
3963 case GL_BACK:
3964 case GL_DEPTH:
3965 case GL_STENCIL:
3966 break;
3967
3968 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003969 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003970 return false;
3971 }
3972 }
3973 else
3974 {
3975 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3976 {
3977 // Valid attachment query
3978 }
3979 else
3980 {
3981 switch (attachment)
3982 {
3983 case GL_DEPTH_ATTACHMENT:
3984 case GL_STENCIL_ATTACHMENT:
3985 break;
3986
3987 case GL_DEPTH_STENCIL_ATTACHMENT:
3988 if (!framebuffer->hasValidDepthStencil())
3989 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003990 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003991 return false;
3992 }
3993 break;
3994
3995 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003996 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003997 return false;
3998 }
3999 }
4000 }
4001
4002 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
4003 if (attachmentObject)
4004 {
4005 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
4006 attachmentObject->type() == GL_TEXTURE ||
4007 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
4008
4009 switch (pname)
4010 {
4011 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4012 if (attachmentObject->type() != GL_RENDERBUFFER &&
4013 attachmentObject->type() != GL_TEXTURE)
4014 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004015 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004016 return false;
4017 }
4018 break;
4019
4020 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
4021 if (attachmentObject->type() != GL_TEXTURE)
4022 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004023 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004024 return false;
4025 }
4026 break;
4027
4028 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
4029 if (attachmentObject->type() != GL_TEXTURE)
4030 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004031 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004032 return false;
4033 }
4034 break;
4035
4036 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4037 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
4038 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004039 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04004040 return false;
4041 }
4042 break;
4043
4044 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
4045 if (attachmentObject->type() != GL_TEXTURE)
4046 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004047 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004048 return false;
4049 }
4050 break;
4051
4052 default:
4053 break;
4054 }
4055 }
4056 else
4057 {
4058 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
4059 // is NONE, then querying any other pname will generate INVALID_ENUM.
4060
4061 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
4062 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
4063 // INVALID_OPERATION for all other pnames
4064
4065 switch (pname)
4066 {
4067 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
4068 break;
4069
4070 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4071 if (clientVersion < 3)
4072 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004073 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004074 return false;
4075 }
4076 break;
4077
4078 default:
4079 if (clientVersion < 3)
4080 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004081 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004082 return false;
4083 }
4084 else
4085 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004086 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04004087 return false;
4088 }
4089 }
4090 }
4091
4092 return true;
4093}
4094
4095bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
4096 GLenum target,
4097 GLenum attachment,
4098 GLenum pname,
4099 GLsizei bufSize,
4100 GLsizei *numParams)
4101{
4102 if (!ValidateRobustEntryPoint(context, bufSize))
4103 {
4104 return false;
4105 }
4106
Jamie Madillbe849e42017-05-02 15:49:00 -04004107 if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname,
4108 numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004109 {
4110 return false;
4111 }
4112
4113 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4114 {
4115 return false;
4116 }
4117
4118 return true;
4119}
4120
Geoff Langff5b2d52016-09-07 11:32:23 -04004121bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
4122 GLenum target,
4123 GLenum pname,
4124 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04004125 GLsizei *length,
4126 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04004127{
4128 if (!ValidateRobustEntryPoint(context, bufSize))
4129 {
4130 return false;
4131 }
4132
Geoff Langebebe1c2016-10-14 12:01:31 -04004133 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004134 {
4135 return false;
4136 }
4137
Geoff Langebebe1c2016-10-14 12:01:31 -04004138 if (!ValidateRobustBufferSize(context, bufSize, *length))
4139 {
4140 return false;
4141 }
4142
4143 return true;
4144}
4145
4146bool ValidateGetBufferParameteri64v(ValidationContext *context,
4147 GLenum target,
4148 GLenum pname,
4149 GLint64 *params)
4150{
4151 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
4152}
4153
4154bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
4155 GLenum target,
4156 GLenum pname,
4157 GLsizei bufSize,
4158 GLsizei *length,
4159 GLint64 *params)
4160{
4161 if (!ValidateRobustEntryPoint(context, bufSize))
4162 {
4163 return false;
4164 }
4165
4166 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
4167 {
4168 return false;
4169 }
4170
4171 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004172 {
4173 return false;
4174 }
4175
4176 return true;
4177}
4178
Jamie Madillbe849e42017-05-02 15:49:00 -04004179bool ValidateGetProgramivBase(ValidationContext *context,
4180 GLuint program,
4181 GLenum pname,
4182 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04004183{
4184 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08004185 if (numParams)
4186 {
4187 *numParams = 1;
4188 }
Geoff Langff5b2d52016-09-07 11:32:23 -04004189
4190 Program *programObject = GetValidProgram(context, program);
4191 if (!programObject)
4192 {
4193 return false;
4194 }
4195
4196 switch (pname)
4197 {
4198 case GL_DELETE_STATUS:
4199 case GL_LINK_STATUS:
4200 case GL_VALIDATE_STATUS:
4201 case GL_INFO_LOG_LENGTH:
4202 case GL_ATTACHED_SHADERS:
4203 case GL_ACTIVE_ATTRIBUTES:
4204 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
4205 case GL_ACTIVE_UNIFORMS:
4206 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
4207 break;
4208
4209 case GL_PROGRAM_BINARY_LENGTH:
4210 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
4211 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004212 context->handleError(InvalidEnum() << "Querying GL_PROGRAM_BINARY_LENGTH "
4213 "requires GL_OES_get_program_binary or "
4214 "ES 3.0.");
Geoff Langff5b2d52016-09-07 11:32:23 -04004215 return false;
4216 }
4217 break;
4218
4219 case GL_ACTIVE_UNIFORM_BLOCKS:
4220 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
4221 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
4222 case GL_TRANSFORM_FEEDBACK_VARYINGS:
4223 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
4224 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
4225 if (context->getClientMajorVersion() < 3)
4226 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004227 context->handleError(InvalidEnum() << "Querying requires at least ES 3.0.");
Geoff Langff5b2d52016-09-07 11:32:23 -04004228 return false;
4229 }
4230 break;
4231
Yunchao He61afff12017-03-14 15:34:03 +08004232 case GL_PROGRAM_SEPARABLE:
4233 if (context->getClientVersion() < Version(3, 1))
4234 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004235 context->handleError(InvalidEnum() << "Querying requires at least ES 3.1.");
Yunchao He61afff12017-03-14 15:34:03 +08004236 return false;
4237 }
4238 break;
4239
Geoff Langff5b2d52016-09-07 11:32:23 -04004240 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004241 context->handleError(InvalidEnum() << "Unknown parameter name.");
Geoff Langff5b2d52016-09-07 11:32:23 -04004242 return false;
4243 }
4244
4245 return true;
4246}
4247
4248bool ValidateGetProgramivRobustANGLE(Context *context,
4249 GLuint program,
4250 GLenum pname,
4251 GLsizei bufSize,
4252 GLsizei *numParams)
4253{
4254 if (!ValidateRobustEntryPoint(context, bufSize))
4255 {
4256 return false;
4257 }
4258
Jamie Madillbe849e42017-05-02 15:49:00 -04004259 if (!ValidateGetProgramivBase(context, program, pname, numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004260 {
4261 return false;
4262 }
4263
4264 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4265 {
4266 return false;
4267 }
4268
4269 return true;
4270}
4271
Geoff Lang740d9022016-10-07 11:20:52 -04004272bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
4273 GLenum target,
4274 GLenum pname,
4275 GLsizei bufSize,
4276 GLsizei *length,
4277 GLint *params)
4278{
4279 if (!ValidateRobustEntryPoint(context, bufSize))
4280 {
4281 return false;
4282 }
4283
4284 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
4285 {
4286 return false;
4287 }
4288
4289 if (!ValidateRobustBufferSize(context, bufSize, *length))
4290 {
4291 return false;
4292 }
4293
4294 return true;
4295}
4296
Geoff Langd7d0ed32016-10-07 11:33:51 -04004297bool ValidateGetShaderivRobustANGLE(Context *context,
4298 GLuint shader,
4299 GLenum pname,
4300 GLsizei bufSize,
4301 GLsizei *length,
4302 GLint *params)
4303{
4304 if (!ValidateRobustEntryPoint(context, bufSize))
4305 {
4306 return false;
4307 }
4308
4309 if (!ValidateGetShaderivBase(context, shader, pname, length))
4310 {
4311 return false;
4312 }
4313
4314 if (!ValidateRobustBufferSize(context, bufSize, *length))
4315 {
4316 return false;
4317 }
4318
4319 return true;
4320}
4321
Geoff Langc1984ed2016-10-07 12:41:00 -04004322bool ValidateGetTexParameterfvRobustANGLE(Context *context,
4323 GLenum target,
4324 GLenum pname,
4325 GLsizei bufSize,
4326 GLsizei *length,
4327 GLfloat *params)
4328{
4329 if (!ValidateRobustEntryPoint(context, bufSize))
4330 {
4331 return false;
4332 }
4333
4334 if (!ValidateGetTexParameterBase(context, target, pname, length))
4335 {
4336 return false;
4337 }
4338
4339 if (!ValidateRobustBufferSize(context, bufSize, *length))
4340 {
4341 return false;
4342 }
4343
4344 return true;
4345}
4346
Geoff Langc1984ed2016-10-07 12:41:00 -04004347bool ValidateGetTexParameterivRobustANGLE(Context *context,
4348 GLenum target,
4349 GLenum pname,
4350 GLsizei bufSize,
4351 GLsizei *length,
4352 GLint *params)
4353{
4354 if (!ValidateRobustEntryPoint(context, bufSize))
4355 {
4356 return false;
4357 }
4358
4359 if (!ValidateGetTexParameterBase(context, target, pname, length))
4360 {
4361 return false;
4362 }
4363
4364 if (!ValidateRobustBufferSize(context, bufSize, *length))
4365 {
4366 return false;
4367 }
4368
4369 return true;
4370}
4371
Geoff Langc1984ed2016-10-07 12:41:00 -04004372bool ValidateTexParameterfvRobustANGLE(Context *context,
4373 GLenum target,
4374 GLenum pname,
4375 GLsizei bufSize,
4376 const GLfloat *params)
4377{
4378 if (!ValidateRobustEntryPoint(context, bufSize))
4379 {
4380 return false;
4381 }
4382
4383 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4384}
4385
Geoff Langc1984ed2016-10-07 12:41:00 -04004386bool ValidateTexParameterivRobustANGLE(Context *context,
4387 GLenum target,
4388 GLenum pname,
4389 GLsizei bufSize,
4390 const GLint *params)
4391{
4392 if (!ValidateRobustEntryPoint(context, bufSize))
4393 {
4394 return false;
4395 }
4396
4397 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4398}
4399
4400bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
4401{
4402 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4403}
4404
4405bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
4406 GLuint sampler,
4407 GLenum pname,
4408 GLuint bufSize,
4409 GLsizei *length,
4410 GLfloat *params)
4411{
4412 if (!ValidateRobustEntryPoint(context, bufSize))
4413 {
4414 return false;
4415 }
4416
4417 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4418 {
4419 return false;
4420 }
4421
4422 if (!ValidateRobustBufferSize(context, bufSize, *length))
4423 {
4424 return false;
4425 }
4426
4427 return true;
4428}
4429
4430bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
4431{
4432 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4433}
4434
4435bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
4436 GLuint sampler,
4437 GLenum pname,
4438 GLuint bufSize,
4439 GLsizei *length,
4440 GLint *params)
4441{
4442 if (!ValidateRobustEntryPoint(context, bufSize))
4443 {
4444 return false;
4445 }
4446
4447 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4448 {
4449 return false;
4450 }
4451
4452 if (!ValidateRobustBufferSize(context, bufSize, *length))
4453 {
4454 return false;
4455 }
4456
4457 return true;
4458}
4459
4460bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
4461{
4462 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4463}
4464
4465bool ValidateSamplerParameterfv(Context *context,
4466 GLuint sampler,
4467 GLenum pname,
4468 const GLfloat *params)
4469{
4470 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4471}
4472
4473bool ValidateSamplerParameterfvRobustANGLE(Context *context,
4474 GLuint sampler,
4475 GLenum pname,
4476 GLsizei bufSize,
4477 const GLfloat *params)
4478{
4479 if (!ValidateRobustEntryPoint(context, bufSize))
4480 {
4481 return false;
4482 }
4483
4484 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4485}
4486
4487bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
4488{
4489 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4490}
4491
4492bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
4493{
4494 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4495}
4496
4497bool ValidateSamplerParameterivRobustANGLE(Context *context,
4498 GLuint sampler,
4499 GLenum pname,
4500 GLsizei bufSize,
4501 const GLint *params)
4502{
4503 if (!ValidateRobustEntryPoint(context, bufSize))
4504 {
4505 return false;
4506 }
4507
4508 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4509}
4510
Geoff Lang0b031062016-10-13 14:30:04 -04004511bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
4512 GLuint index,
4513 GLenum pname,
4514 GLsizei bufSize,
4515 GLsizei *length,
4516 GLfloat *params)
4517{
4518 if (!ValidateRobustEntryPoint(context, bufSize))
4519 {
4520 return false;
4521 }
4522
4523 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4524 {
4525 return false;
4526 }
4527
4528 if (!ValidateRobustBufferSize(context, bufSize, *length))
4529 {
4530 return false;
4531 }
4532
4533 return true;
4534}
4535
Geoff Lang0b031062016-10-13 14:30:04 -04004536bool ValidateGetVertexAttribivRobustANGLE(Context *context,
4537 GLuint index,
4538 GLenum pname,
4539 GLsizei bufSize,
4540 GLsizei *length,
4541 GLint *params)
4542{
4543 if (!ValidateRobustEntryPoint(context, bufSize))
4544 {
4545 return false;
4546 }
4547
4548 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4549 {
4550 return false;
4551 }
4552
4553 if (!ValidateRobustBufferSize(context, bufSize, *length))
4554 {
4555 return false;
4556 }
4557
4558 return true;
4559}
4560
Geoff Lang0b031062016-10-13 14:30:04 -04004561bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
4562 GLuint index,
4563 GLenum pname,
4564 GLsizei bufSize,
4565 GLsizei *length,
4566 void **pointer)
4567{
4568 if (!ValidateRobustEntryPoint(context, bufSize))
4569 {
4570 return false;
4571 }
4572
4573 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
4574 {
4575 return false;
4576 }
4577
4578 if (!ValidateRobustBufferSize(context, bufSize, *length))
4579 {
4580 return false;
4581 }
4582
4583 return true;
4584}
4585
4586bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
4587{
4588 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4589}
4590
4591bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
4592 GLuint index,
4593 GLenum pname,
4594 GLsizei bufSize,
4595 GLsizei *length,
4596 GLint *params)
4597{
4598 if (!ValidateRobustEntryPoint(context, bufSize))
4599 {
4600 return false;
4601 }
4602
4603 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4604 {
4605 return false;
4606 }
4607
4608 if (!ValidateRobustBufferSize(context, bufSize, *length))
4609 {
4610 return false;
4611 }
4612
4613 return true;
4614}
4615
4616bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
4617{
4618 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4619}
4620
4621bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
4622 GLuint index,
4623 GLenum pname,
4624 GLsizei bufSize,
4625 GLsizei *length,
4626 GLuint *params)
4627{
4628 if (!ValidateRobustEntryPoint(context, bufSize))
4629 {
4630 return false;
4631 }
4632
4633 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4634 {
4635 return false;
4636 }
4637
4638 if (!ValidateRobustBufferSize(context, bufSize, *length))
4639 {
4640 return false;
4641 }
4642
4643 return true;
4644}
4645
Geoff Lang6899b872016-10-14 11:30:13 -04004646bool ValidateGetActiveUniformBlockiv(Context *context,
4647 GLuint program,
4648 GLuint uniformBlockIndex,
4649 GLenum pname,
4650 GLint *params)
4651{
4652 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
4653}
4654
4655bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
4656 GLuint program,
4657 GLuint uniformBlockIndex,
4658 GLenum pname,
4659 GLsizei bufSize,
4660 GLsizei *length,
4661 GLint *params)
4662{
4663 if (!ValidateRobustEntryPoint(context, bufSize))
4664 {
4665 return false;
4666 }
4667
4668 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
4669 {
4670 return false;
4671 }
4672
4673 if (!ValidateRobustBufferSize(context, bufSize, *length))
4674 {
4675 return false;
4676 }
4677
4678 return true;
4679}
4680
Geoff Lang0a9661f2016-10-20 10:59:20 -07004681bool ValidateGetInternalFormativ(Context *context,
4682 GLenum target,
4683 GLenum internalformat,
4684 GLenum pname,
4685 GLsizei bufSize,
4686 GLint *params)
4687{
4688 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
4689 nullptr);
4690}
4691
4692bool ValidateGetInternalFormativRobustANGLE(Context *context,
4693 GLenum target,
4694 GLenum internalformat,
4695 GLenum pname,
4696 GLsizei bufSize,
4697 GLsizei *length,
4698 GLint *params)
4699{
4700 if (!ValidateRobustEntryPoint(context, bufSize))
4701 {
4702 return false;
4703 }
4704
4705 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
4706 {
4707 return false;
4708 }
4709
4710 if (!ValidateRobustBufferSize(context, bufSize, *length))
4711 {
4712 return false;
4713 }
4714
4715 return true;
4716}
4717
Shao80957d92017-02-20 21:25:59 +08004718bool ValidateVertexFormatBase(ValidationContext *context,
4719 GLuint attribIndex,
4720 GLint size,
4721 GLenum type,
4722 GLboolean pureInteger)
4723{
4724 const Caps &caps = context->getCaps();
4725 if (attribIndex >= caps.maxVertexAttributes)
4726 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004727 context->handleError(InvalidValue()
4728 << "attribindex must be smaller than MAX_VERTEX_ATTRIBS.");
Shao80957d92017-02-20 21:25:59 +08004729 return false;
4730 }
4731
4732 if (size < 1 || size > 4)
4733 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004734 context->handleError(InvalidValue() << "size must be between one and four.");
Shao80957d92017-02-20 21:25:59 +08004735 }
4736
4737 switch (type)
4738 {
4739 case GL_BYTE:
4740 case GL_UNSIGNED_BYTE:
4741 case GL_SHORT:
4742 case GL_UNSIGNED_SHORT:
4743 break;
4744
4745 case GL_INT:
4746 case GL_UNSIGNED_INT:
4747 if (context->getClientMajorVersion() < 3)
4748 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004749 context->handleError(InvalidEnum()
4750 << "Vertex type not supported before OpenGL ES 3.0.");
Shao80957d92017-02-20 21:25:59 +08004751 return false;
4752 }
4753 break;
4754
4755 case GL_FIXED:
4756 case GL_FLOAT:
4757 if (pureInteger)
4758 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004759 context->handleError(InvalidEnum() << "Type is not integer.");
Shao80957d92017-02-20 21:25:59 +08004760 return false;
4761 }
4762 break;
4763
4764 case GL_HALF_FLOAT:
4765 if (context->getClientMajorVersion() < 3)
4766 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004767 context->handleError(InvalidEnum()
4768 << "Vertex type not supported before OpenGL ES 3.0.");
Shao80957d92017-02-20 21:25:59 +08004769 return false;
4770 }
4771 if (pureInteger)
4772 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004773 context->handleError(InvalidEnum() << "Type is not integer.");
Shao80957d92017-02-20 21:25:59 +08004774 return false;
4775 }
4776 break;
4777
4778 case GL_INT_2_10_10_10_REV:
4779 case GL_UNSIGNED_INT_2_10_10_10_REV:
4780 if (context->getClientMajorVersion() < 3)
4781 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004782 context->handleError(InvalidEnum()
4783 << "Vertex type not supported before OpenGL ES 3.0.");
Shao80957d92017-02-20 21:25:59 +08004784 return false;
4785 }
4786 if (pureInteger)
4787 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004788 context->handleError(InvalidEnum() << "Type is not integer.");
Shao80957d92017-02-20 21:25:59 +08004789 return false;
4790 }
4791 if (size != 4)
4792 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004793 context->handleError(InvalidOperation() << "Type is INT_2_10_10_10_REV or "
4794 "UNSIGNED_INT_2_10_10_10_REV and "
4795 "size is not 4.");
Shao80957d92017-02-20 21:25:59 +08004796 return false;
4797 }
4798 break;
4799
4800 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004801 context->handleError(InvalidEnum() << "Invalid vertex type.");
Shao80957d92017-02-20 21:25:59 +08004802 return false;
4803 }
4804
4805 return true;
4806}
4807
Geoff Lang76e65652017-03-27 14:58:02 -04004808// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
4809// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
4810// specified clear value and the type of a buffer that is being cleared generates an
4811// INVALID_OPERATION error instead of producing undefined results
4812bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
4813 GLint drawbuffer,
4814 const GLenum *validComponentTypes,
4815 size_t validComponentTypeCount)
4816{
4817 const FramebufferAttachment *attachment =
4818 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
4819 if (attachment)
4820 {
4821 GLenum componentType = attachment->getFormat().info->componentType;
4822 const GLenum *end = validComponentTypes + validComponentTypeCount;
4823 if (std::find(validComponentTypes, end, componentType) == end)
4824 {
4825 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004826 InvalidOperation()
4827 << "No defined conversion between clear value and attachment format.");
Geoff Lang76e65652017-03-27 14:58:02 -04004828 return false;
4829 }
4830 }
4831
4832 return true;
4833}
4834
Corentin Wallezb2931602017-04-11 15:58:57 -04004835bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
4836 GLsizei imageSize,
4837 GLsizei dataSize)
4838{
4839 if (!ValidateRobustEntryPoint(context, dataSize))
4840 {
4841 return false;
4842 }
4843
4844 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
4845 if (pixelUnpackBuffer == nullptr)
4846 {
4847 if (dataSize < imageSize)
4848 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004849 context->handleError(InvalidOperation() << "dataSize must be at least " << imageSize);
Corentin Wallezb2931602017-04-11 15:58:57 -04004850 }
4851 }
4852 return true;
4853}
4854
Jamie Madillbe849e42017-05-02 15:49:00 -04004855bool ValidateGetBufferParameterBase(ValidationContext *context,
4856 GLenum target,
4857 GLenum pname,
4858 bool pointerVersion,
4859 GLsizei *numParams)
4860{
4861 if (numParams)
4862 {
4863 *numParams = 0;
4864 }
4865
4866 if (!ValidBufferTarget(context, target))
4867 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004868 context->handleError(InvalidEnum() << "Invalid buffer target.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004869 return false;
4870 }
4871
4872 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
4873 if (!buffer)
4874 {
4875 // A null buffer means that "0" is bound to the requested buffer target
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004876 context->handleError(InvalidOperation() << "No buffer bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004877 return false;
4878 }
4879
4880 const Extensions &extensions = context->getExtensions();
4881
4882 switch (pname)
4883 {
4884 case GL_BUFFER_USAGE:
4885 case GL_BUFFER_SIZE:
4886 break;
4887
4888 case GL_BUFFER_ACCESS_OES:
4889 if (!extensions.mapBuffer)
4890 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004891 context->handleError(InvalidEnum()
4892 << "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004893 return false;
4894 }
4895 break;
4896
4897 case GL_BUFFER_MAPPED:
4898 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
4899 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
4900 !extensions.mapBufferRange)
4901 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004902 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0, "
4903 "GL_OES_mapbuffer or "
4904 "GL_EXT_map_buffer_range.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004905 return false;
4906 }
4907 break;
4908
4909 case GL_BUFFER_MAP_POINTER:
4910 if (!pointerVersion)
4911 {
4912 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004913 InvalidEnum()
4914 << "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004915 return false;
4916 }
4917 break;
4918
4919 case GL_BUFFER_ACCESS_FLAGS:
4920 case GL_BUFFER_MAP_OFFSET:
4921 case GL_BUFFER_MAP_LENGTH:
4922 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
4923 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004924 context->handleError(InvalidEnum()
4925 << "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004926 return false;
4927 }
4928 break;
4929
4930 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004931 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004932 return false;
4933 }
4934
4935 // All buffer parameter queries return one value.
4936 if (numParams)
4937 {
4938 *numParams = 1;
4939 }
4940
4941 return true;
4942}
4943
4944bool ValidateGetRenderbufferParameterivBase(Context *context,
4945 GLenum target,
4946 GLenum pname,
4947 GLsizei *length)
4948{
4949 if (length)
4950 {
4951 *length = 0;
4952 }
4953
4954 if (target != GL_RENDERBUFFER)
4955 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004956 context->handleError(InvalidEnum() << "Invalid target.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004957 return false;
4958 }
4959
4960 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
4961 if (renderbuffer == nullptr)
4962 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004963 context->handleError(InvalidOperation() << "No renderbuffer bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004964 return false;
4965 }
4966
4967 switch (pname)
4968 {
4969 case GL_RENDERBUFFER_WIDTH:
4970 case GL_RENDERBUFFER_HEIGHT:
4971 case GL_RENDERBUFFER_INTERNAL_FORMAT:
4972 case GL_RENDERBUFFER_RED_SIZE:
4973 case GL_RENDERBUFFER_GREEN_SIZE:
4974 case GL_RENDERBUFFER_BLUE_SIZE:
4975 case GL_RENDERBUFFER_ALPHA_SIZE:
4976 case GL_RENDERBUFFER_DEPTH_SIZE:
4977 case GL_RENDERBUFFER_STENCIL_SIZE:
4978 break;
4979
4980 case GL_RENDERBUFFER_SAMPLES_ANGLE:
4981 if (!context->getExtensions().framebufferMultisample)
4982 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004983 context->handleError(InvalidEnum()
4984 << "GL_ANGLE_framebuffer_multisample is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004985 return false;
4986 }
4987 break;
4988
4989 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004990 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004991 return false;
4992 }
4993
4994 if (length)
4995 {
4996 *length = 1;
4997 }
4998 return true;
4999}
5000
5001bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
5002{
5003 if (length)
5004 {
5005 *length = 0;
5006 }
5007
5008 if (GetValidShader(context, shader) == nullptr)
5009 {
5010 return false;
5011 }
5012
5013 switch (pname)
5014 {
5015 case GL_SHADER_TYPE:
5016 case GL_DELETE_STATUS:
5017 case GL_COMPILE_STATUS:
5018 case GL_INFO_LOG_LENGTH:
5019 case GL_SHADER_SOURCE_LENGTH:
5020 break;
5021
5022 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
5023 if (!context->getExtensions().translatedShaderSource)
5024 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005025 context->handleError(InvalidEnum()
5026 << "GL_ANGLE_translated_shader_source is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005027 return false;
5028 }
5029 break;
5030
5031 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005032 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005033 return false;
5034 }
5035
5036 if (length)
5037 {
5038 *length = 1;
5039 }
5040 return true;
5041}
5042
5043bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
5044{
5045 if (length)
5046 {
5047 *length = 0;
5048 }
5049
5050 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5051 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005052 context->handleError(InvalidEnum() << "Invalid texture target");
Jamie Madillbe849e42017-05-02 15:49:00 -04005053 return false;
5054 }
5055
5056 if (context->getTargetTexture(target) == nullptr)
5057 {
5058 // Should only be possible for external textures
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005059 context->handleError(InvalidEnum() << "No texture bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005060 return false;
5061 }
5062
5063 switch (pname)
5064 {
5065 case GL_TEXTURE_MAG_FILTER:
5066 case GL_TEXTURE_MIN_FILTER:
5067 case GL_TEXTURE_WRAP_S:
5068 case GL_TEXTURE_WRAP_T:
5069 break;
5070
5071 case GL_TEXTURE_USAGE_ANGLE:
5072 if (!context->getExtensions().textureUsage)
5073 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005074 context->handleError(InvalidEnum() << "GL_ANGLE_texture_usage is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005075 return false;
5076 }
5077 break;
5078
5079 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5080 if (!context->getExtensions().textureFilterAnisotropic)
5081 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005082 context->handleError(InvalidEnum()
5083 << "GL_EXT_texture_filter_anisotropic is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005084 return false;
5085 }
5086 break;
5087
5088 case GL_TEXTURE_IMMUTABLE_FORMAT:
5089 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
5090 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005091 context->handleError(InvalidEnum() << "GL_EXT_texture_storage is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005092 return false;
5093 }
5094 break;
5095
5096 case GL_TEXTURE_WRAP_R:
5097 case GL_TEXTURE_IMMUTABLE_LEVELS:
5098 case GL_TEXTURE_SWIZZLE_R:
5099 case GL_TEXTURE_SWIZZLE_G:
5100 case GL_TEXTURE_SWIZZLE_B:
5101 case GL_TEXTURE_SWIZZLE_A:
5102 case GL_TEXTURE_BASE_LEVEL:
5103 case GL_TEXTURE_MAX_LEVEL:
5104 case GL_TEXTURE_MIN_LOD:
5105 case GL_TEXTURE_MAX_LOD:
5106 case GL_TEXTURE_COMPARE_MODE:
5107 case GL_TEXTURE_COMPARE_FUNC:
5108 if (context->getClientMajorVersion() < 3)
5109 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005110 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005111 return false;
5112 }
5113 break;
5114
5115 case GL_TEXTURE_SRGB_DECODE_EXT:
5116 if (!context->getExtensions().textureSRGBDecode)
5117 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005118 context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005119 return false;
5120 }
5121 break;
5122
5123 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005124 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005125 return false;
5126 }
5127
5128 if (length)
5129 {
5130 *length = 1;
5131 }
5132 return true;
5133}
5134
5135bool ValidateGetVertexAttribBase(Context *context,
5136 GLuint index,
5137 GLenum pname,
5138 GLsizei *length,
5139 bool pointer,
5140 bool pureIntegerEntryPoint)
5141{
5142 if (length)
5143 {
5144 *length = 0;
5145 }
5146
5147 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
5148 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005149 context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005150 return false;
5151 }
5152
5153 if (index >= context->getCaps().maxVertexAttributes)
5154 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005155 context->handleError(InvalidValue()
5156 << "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005157 return false;
5158 }
5159
5160 if (pointer)
5161 {
5162 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
5163 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005164 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005165 return false;
5166 }
5167 }
5168 else
5169 {
5170 switch (pname)
5171 {
5172 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
5173 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
5174 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
5175 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
5176 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
5177 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
5178 case GL_CURRENT_VERTEX_ATTRIB:
5179 break;
5180
5181 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
5182 static_assert(
5183 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
5184 "ANGLE extension enums not equal to GL enums.");
5185 if (context->getClientMajorVersion() < 3 &&
5186 !context->getExtensions().instancedArrays)
5187 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005188 context->handleError(InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_DIVISOR "
5189 "requires OpenGL ES 3.0 or "
5190 "GL_ANGLE_instanced_arrays.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005191 return false;
5192 }
5193 break;
5194
5195 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
5196 if (context->getClientMajorVersion() < 3)
5197 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005198 context->handleError(
5199 InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005200 return false;
5201 }
5202 break;
5203
5204 case GL_VERTEX_ATTRIB_BINDING:
5205 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
5206 if (context->getClientVersion() < ES_3_1)
5207 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005208 context->handleError(InvalidEnum()
5209 << "Vertex Attrib Bindings require OpenGL ES 3.1.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005210 return false;
5211 }
5212 break;
5213
5214 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005215 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005216 return false;
5217 }
5218 }
5219
5220 if (length)
5221 {
5222 if (pname == GL_CURRENT_VERTEX_ATTRIB)
5223 {
5224 *length = 4;
5225 }
5226 else
5227 {
5228 *length = 1;
5229 }
5230 }
5231
5232 return true;
5233}
5234
Jamie Madill4928b7c2017-06-20 12:57:39 -04005235bool ValidateReadPixelsBase(Context *context,
Jamie Madillbe849e42017-05-02 15:49:00 -04005236 GLint x,
5237 GLint y,
5238 GLsizei width,
5239 GLsizei height,
5240 GLenum format,
5241 GLenum type,
5242 GLsizei bufSize,
5243 GLsizei *length,
5244 GLsizei *columns,
5245 GLsizei *rows,
5246 void *pixels)
5247{
5248 if (length != nullptr)
5249 {
5250 *length = 0;
5251 }
5252 if (rows != nullptr)
5253 {
5254 *rows = 0;
5255 }
5256 if (columns != nullptr)
5257 {
5258 *columns = 0;
5259 }
5260
5261 if (width < 0 || height < 0)
5262 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005263 context->handleError(InvalidValue() << "width and height must be positive");
Jamie Madillbe849e42017-05-02 15:49:00 -04005264 return false;
5265 }
5266
5267 auto readFramebuffer = context->getGLState().getReadFramebuffer();
5268
5269 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
5270 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005271 context->handleError(InvalidFramebufferOperation());
Jamie Madillbe849e42017-05-02 15:49:00 -04005272 return false;
5273 }
5274
5275 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
5276 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005277 context->handleError(InvalidOperation());
Jamie Madillbe849e42017-05-02 15:49:00 -04005278 return false;
5279 }
5280
5281 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
5282 ASSERT(framebuffer);
5283
5284 if (framebuffer->getReadBufferState() == GL_NONE)
5285 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005286 context->handleError(InvalidOperation() << "Read buffer is GL_NONE");
Jamie Madillbe849e42017-05-02 15:49:00 -04005287 return false;
5288 }
5289
5290 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
5291 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
5292 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
5293 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
5294 // situation is an application error that would lead to a crash in ANGLE.
5295 if (readBuffer == nullptr)
5296 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005297 context->handleError(InvalidOperation() << "Missing read attachment");
Jamie Madillbe849e42017-05-02 15:49:00 -04005298 return false;
5299 }
5300
Jamie Madill4928b7c2017-06-20 12:57:39 -04005301 GLenum currentFormat = framebuffer->getImplementationColorReadFormat(context);
5302 GLenum currentType = framebuffer->getImplementationColorReadType(context);
Jamie Madillbe849e42017-05-02 15:49:00 -04005303 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
5304
5305 bool validFormatTypeCombination =
5306 ValidReadPixelsFormatType(context, currentComponentType, format, type);
5307
5308 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
5309 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005310 context->handleError(InvalidOperation());
Jamie Madillbe849e42017-05-02 15:49:00 -04005311 return false;
5312 }
5313
5314 // Check for pixel pack buffer related API errors
5315 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
5316 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
5317 {
5318 // ...the buffer object's data store is currently mapped.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005319 context->handleError(InvalidOperation() << "Pixel pack buffer is mapped.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005320 return false;
5321 }
5322
5323 // .. the data would be packed to the buffer object such that the memory writes required
5324 // would exceed the data store size.
5325 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
5326 const gl::Extents size(width, height, 1);
5327 const auto &pack = context->getGLState().getPackState();
5328
5329 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
5330 if (endByteOrErr.isError())
5331 {
5332 context->handleError(endByteOrErr.getError());
5333 return false;
5334 }
5335
5336 size_t endByte = endByteOrErr.getResult();
5337 if (bufSize >= 0)
5338 {
5339 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
5340 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005341 context->handleError(InvalidOperation()
5342 << "bufSize must be at least " << endByte << " bytes.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005343 return false;
5344 }
5345 }
5346
5347 if (pixelPackBuffer != nullptr)
5348 {
5349 CheckedNumeric<size_t> checkedEndByte(endByte);
5350 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
5351 checkedEndByte += checkedOffset;
5352
5353 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
5354 {
5355 // Overflow past the end of the buffer
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005356 context->handleError(InvalidOperation()
5357 << "Writes would overflow the pixel pack buffer.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005358 return false;
5359 }
5360 }
5361
5362 if (pixelPackBuffer == nullptr && length != nullptr)
5363 {
5364 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
5365 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005366 context->handleError(InvalidOperation() << "length would overflow GLsizei.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005367 return false;
5368 }
5369
5370 *length = static_cast<GLsizei>(endByte);
5371 }
5372
5373 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
5374 angle::CheckedNumeric<int> clippedExtent(length);
5375 if (start < 0)
5376 {
5377 // "subtract" the area that is less than 0
5378 clippedExtent += start;
5379 }
5380
5381 const int readExtent = start + length;
5382 if (readExtent > bufferSize)
5383 {
5384 // Subtract the region to the right of the read buffer
5385 clippedExtent -= (readExtent - bufferSize);
5386 }
5387
5388 if (!clippedExtent.IsValid())
5389 {
5390 return 0;
5391 }
5392
5393 return std::max(clippedExtent.ValueOrDie(), 0);
5394 };
5395
5396 if (columns != nullptr)
5397 {
5398 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
5399 }
5400
5401 if (rows != nullptr)
5402 {
5403 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
5404 }
5405
5406 return true;
5407}
5408
5409template <typename ParamType>
5410bool ValidateTexParameterBase(Context *context,
5411 GLenum target,
5412 GLenum pname,
5413 GLsizei bufSize,
5414 const ParamType *params)
5415{
5416 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5417 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005418 context->handleError(InvalidEnum() << "Invalid texture target");
Jamie Madillbe849e42017-05-02 15:49:00 -04005419 return false;
5420 }
5421
5422 if (context->getTargetTexture(target) == nullptr)
5423 {
5424 // Should only be possible for external textures
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005425 context->handleError(InvalidEnum() << "No texture bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005426 return false;
5427 }
5428
5429 const GLsizei minBufSize = 1;
5430 if (bufSize >= 0 && bufSize < minBufSize)
5431 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005432 context->handleError(InvalidOperation() << "bufSize must be at least " << minBufSize);
Jamie Madillbe849e42017-05-02 15:49:00 -04005433 return false;
5434 }
5435
5436 switch (pname)
5437 {
5438 case GL_TEXTURE_WRAP_R:
5439 case GL_TEXTURE_SWIZZLE_R:
5440 case GL_TEXTURE_SWIZZLE_G:
5441 case GL_TEXTURE_SWIZZLE_B:
5442 case GL_TEXTURE_SWIZZLE_A:
5443 case GL_TEXTURE_BASE_LEVEL:
5444 case GL_TEXTURE_MAX_LEVEL:
5445 case GL_TEXTURE_COMPARE_MODE:
5446 case GL_TEXTURE_COMPARE_FUNC:
5447 case GL_TEXTURE_MIN_LOD:
5448 case GL_TEXTURE_MAX_LOD:
5449 if (context->getClientMajorVersion() < 3)
5450 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005451 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005452 return false;
5453 }
5454 if (target == GL_TEXTURE_EXTERNAL_OES &&
5455 !context->getExtensions().eglImageExternalEssl3)
5456 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005457 context->handleError(InvalidEnum() << "ES3 texture parameters are not "
5458 "available without "
5459 "GL_OES_EGL_image_external_essl3.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005460 return false;
5461 }
5462 break;
5463
5464 default:
5465 break;
5466 }
5467
5468 switch (pname)
5469 {
5470 case GL_TEXTURE_WRAP_S:
5471 case GL_TEXTURE_WRAP_T:
5472 case GL_TEXTURE_WRAP_R:
5473 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5474 {
5475 return false;
5476 }
5477 break;
5478
5479 case GL_TEXTURE_MIN_FILTER:
5480 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5481 {
5482 return false;
5483 }
5484 break;
5485
5486 case GL_TEXTURE_MAG_FILTER:
5487 if (!ValidateTextureMagFilterValue(context, params))
5488 {
5489 return false;
5490 }
5491 break;
5492
5493 case GL_TEXTURE_USAGE_ANGLE:
5494 switch (ConvertToGLenum(params[0]))
5495 {
5496 case GL_NONE:
5497 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
5498 break;
5499
5500 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005501 context->handleError(InvalidEnum() << "Unknown param value.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005502 return false;
5503 }
5504 break;
5505
5506 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5507 if (!context->getExtensions().textureFilterAnisotropic)
5508 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005509 context->handleError(InvalidEnum() << "GL_EXT_texture_anisotropic is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005510 return false;
5511 }
5512
5513 // we assume the parameter passed to this validation method is truncated, not rounded
5514 if (params[0] < 1)
5515 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005516 context->handleError(InvalidValue() << "Max anisotropy must be at least 1.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005517 return false;
5518 }
5519 break;
5520
5521 case GL_TEXTURE_MIN_LOD:
5522 case GL_TEXTURE_MAX_LOD:
5523 // any value is permissible
5524 break;
5525
5526 case GL_TEXTURE_COMPARE_MODE:
5527 if (!ValidateTextureCompareModeValue(context, params))
5528 {
5529 return false;
5530 }
5531 break;
5532
5533 case GL_TEXTURE_COMPARE_FUNC:
5534 if (!ValidateTextureCompareFuncValue(context, params))
5535 {
5536 return false;
5537 }
5538 break;
5539
5540 case GL_TEXTURE_SWIZZLE_R:
5541 case GL_TEXTURE_SWIZZLE_G:
5542 case GL_TEXTURE_SWIZZLE_B:
5543 case GL_TEXTURE_SWIZZLE_A:
5544 switch (ConvertToGLenum(params[0]))
5545 {
5546 case GL_RED:
5547 case GL_GREEN:
5548 case GL_BLUE:
5549 case GL_ALPHA:
5550 case GL_ZERO:
5551 case GL_ONE:
5552 break;
5553
5554 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005555 context->handleError(InvalidEnum() << "Unknown param value.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005556 return false;
5557 }
5558 break;
5559
5560 case GL_TEXTURE_BASE_LEVEL:
5561 if (params[0] < 0)
5562 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005563 context->handleError(InvalidValue() << "Base level must be at least 0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005564 return false;
5565 }
5566 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
5567 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005568 context->handleError(InvalidOperation()
5569 << "Base level must be 0 for external textures.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005570 return false;
5571 }
5572 break;
5573
5574 case GL_TEXTURE_MAX_LEVEL:
5575 if (params[0] < 0)
5576 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005577 context->handleError(InvalidValue() << "Max level must be at least 0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005578 return false;
5579 }
5580 break;
5581
5582 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5583 if (context->getClientVersion() < Version(3, 1))
5584 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005585 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.1.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005586 return false;
5587 }
5588 switch (ConvertToGLenum(params[0]))
5589 {
5590 case GL_DEPTH_COMPONENT:
5591 case GL_STENCIL_INDEX:
5592 break;
5593
5594 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005595 context->handleError(InvalidEnum() << "Unknown param value.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005596 return false;
5597 }
5598 break;
5599
5600 case GL_TEXTURE_SRGB_DECODE_EXT:
5601 if (!ValidateTextureSRGBDecodeValue(context, params))
5602 {
5603 return false;
5604 }
5605 break;
5606
5607 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005608 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005609 return false;
5610 }
5611
5612 return true;
5613}
5614
5615template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *);
5616template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *);
5617
Jamie Madillc29968b2016-01-20 11:17:23 -05005618} // namespace gl