blob: 5fa59c1d0a91b09690a22df1cf6d2f231d7613be [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
Corentin Wallez0dc97812017-06-22 14:38:44 -0400893bool ValidateDrawInstancedANGLE(ValidationContext *context)
Jamie Madillbe849e42017-05-02 15:49:00 -0400894{
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 Wallez0dc97812017-06-22 14:38:44 -04002852 return ValidateDrawArraysInstancedBase(context, mode, first, count, primcount);
Geoff Lang87a93302014-09-16 13:29:43 -04002853}
2854
He Yunchaoced53ae2016-11-29 15:00:51 +08002855bool ValidateDrawArraysInstancedANGLE(Context *context,
2856 GLenum mode,
2857 GLint first,
2858 GLsizei count,
2859 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04002860{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002861 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04002862 {
2863 return false;
2864 }
2865
Corentin Wallez0dc97812017-06-22 14:38:44 -04002866 return ValidateDrawInstancedANGLE(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002867}
2868
Jiajia Qind9671222016-11-29 16:30:31 +08002869bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04002870{
Jamie Madill250d33f2014-06-06 17:09:03 -04002871 switch (type)
2872 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002873 case GL_UNSIGNED_BYTE:
2874 case GL_UNSIGNED_SHORT:
2875 break;
2876 case GL_UNSIGNED_INT:
2877 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2878 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002879 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08002880 return false;
2881 }
2882 break;
2883 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002884 context->handleError(InvalidEnum());
He Yunchaoced53ae2016-11-29 15:00:51 +08002885 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002886 }
2887
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002888 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002889
2890 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002891 if (curTransformFeedback && curTransformFeedback->isActive() &&
2892 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002893 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002894 // It is an invalid operation to call DrawElements, DrawRangeElements or
2895 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04002896 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002897 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04002898 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002899 }
2900
Jiajia Qind9671222016-11-29 16:30:31 +08002901 return true;
2902}
2903
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002904bool ValidateDrawElementsCommon(ValidationContext *context,
2905 GLenum mode,
2906 GLsizei count,
2907 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04002908 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002909 GLsizei primcount)
Jiajia Qind9671222016-11-29 16:30:31 +08002910{
2911 if (!ValidateDrawElementsBase(context, type))
2912 return false;
2913
2914 const State &state = context->getGLState();
2915
Corentin Wallez170efbf2017-05-02 13:45:01 -04002916 if (!ValidateDrawBase(context, mode, count))
2917 {
2918 return false;
2919 }
2920
Jamie Madill250d33f2014-06-06 17:09:03 -04002921 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002922 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002923 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002924 context->handleError(InvalidOperation() << "Index buffer is mapped.");
Geoff Langb1196682014-07-23 13:47:29 -04002925 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002926 }
2927
He Yunchaoced53ae2016-11-29 15:00:51 +08002928 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002929 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04002930
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002931 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
2932
2933 if (context->getExtensions().webglCompatibility)
2934 {
2935 ASSERT(isPow2(typeBytes) && typeBytes > 0);
2936 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
2937 {
2938 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2939 // The offset arguments to drawElements and [...], must be a multiple of the size of the
2940 // data type passed to the call, or an INVALID_OPERATION error is generated.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002941 context->handleError(InvalidOperation()
2942 << "indices must be a multiple of the element type size.");
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002943 return false;
2944 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002945
2946 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2947 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
2948 // error is generated.
2949 if (reinterpret_cast<intptr_t>(indices) < 0)
2950 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002951 context->handleError(InvalidValue() << "Offset < 0.");
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002952 return false;
2953 }
Geoff Langfeb8c682017-02-13 16:07:35 -05002954 }
2955
2956 if (context->getExtensions().webglCompatibility ||
2957 !context->getGLState().areClientArraysEnabled())
2958 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002959 if (!elementArrayBuffer && count > 0)
2960 {
2961 // [WebGL 1.0] Section 6.2 No Client Side Arrays
2962 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
2963 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002964 context->handleError(InvalidOperation()
2965 << "There is no element array buffer bound and count > 0.");
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002966 return false;
2967 }
2968 }
2969
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002970 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04002971 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002972 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04002973 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002974 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
2975 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
2976 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
2977 constexpr uint64_t kMaxTypeSize = 8;
2978 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
2979 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
2980 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002981
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002982 uint64_t typeSize = typeBytes;
2983 uint64_t elementCount = static_cast<uint64_t>(count);
2984 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
2985
2986 // Doing the multiplication here is overflow-safe
2987 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
2988
2989 // The offset can be any value, check for overflows
2990 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
2991 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002992 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05002993 context->handleError(InvalidOperation() << "Integer overflow.");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002994 return false;
2995 }
2996
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002997 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
2998 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002999 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003000 context->handleError(InvalidOperation()
3001 << "Index buffer is not big enough for the draw.");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003002 return false;
3003 }
3004 }
3005 else if (!indices)
3006 {
3007 // This is an application error that would normally result in a crash,
3008 // but we catch it and return an error
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003009 context->handleError(InvalidOperation() << "No element array buffer and no pointer.");
Geoff Langb1196682014-07-23 13:47:29 -04003010 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04003011 }
Jamie Madillae3000b2014-08-25 15:47:51 -04003012 }
3013
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003014 // Use the parameter buffer to retrieve and cache the index range.
Jamie Madill2b976812014-08-25 15:47:49 -04003015 // TODO: offer fast path, with disabled index validation.
3016 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003017 const auto &params = context->getParams<HasIndexRange>();
3018 const auto &indexRangeOpt = params.getIndexRange();
3019 if (!indexRangeOpt.valid())
Jamie Madill2b976812014-08-25 15:47:49 -04003020 {
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003021 // Unexpected error.
3022 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04003023 }
3024
Jamie Madille79b1e12015-11-04 16:36:37 -05003025 // If we use an index greater than our maximum supported index range, return an error.
3026 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
3027 // return an error if possible here.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003028 if (static_cast<GLuint64>(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex)
Jamie Madille79b1e12015-11-04 16:36:37 -05003029 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003030 context->handleError(InvalidOperation() << g_ExceedsMaxElementErrorMessage);
Jamie Madille79b1e12015-11-04 16:36:37 -05003031 return false;
3032 }
3033
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003034 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOpt.value().end),
3035 static_cast<GLint>(indexRangeOpt.value().vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04003036 {
3037 return false;
3038 }
3039
Geoff Lang3edfe032015-09-04 16:38:24 -04003040 // No op if there are no real indices in the index data (all are primitive restart).
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003041 return (indexRangeOpt.value().vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04003042}
3043
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003044bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
3045 GLenum mode,
3046 GLsizei count,
3047 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003048 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003049 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003050{
Corentin Wallez0dc97812017-06-22 14:38:44 -04003051 return ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount);
Jamie Madill250d33f2014-06-06 17:09:03 -04003052}
3053
Geoff Lang3edfe032015-09-04 16:38:24 -04003054bool ValidateDrawElementsInstancedANGLE(Context *context,
3055 GLenum mode,
3056 GLsizei count,
3057 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003058 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003059 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003060{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003061 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04003062 {
3063 return false;
3064 }
3065
Corentin Wallez0dc97812017-06-22 14:38:44 -04003066 return ValidateDrawInstancedANGLE(context);
Geoff Lang87a93302014-09-16 13:29:43 -04003067}
3068
He Yunchaoced53ae2016-11-29 15:00:51 +08003069bool ValidateFramebufferTextureBase(Context *context,
3070 GLenum target,
3071 GLenum attachment,
3072 GLuint texture,
3073 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04003074{
Jamie Madill55ec3b12014-07-03 10:38:57 -04003075 if (!ValidFramebufferTarget(target))
3076 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003077 context->handleError(InvalidEnum());
Geoff Langb1196682014-07-23 13:47:29 -04003078 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003079 }
3080
3081 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04003082 {
3083 return false;
3084 }
3085
Jamie Madill55ec3b12014-07-03 10:38:57 -04003086 if (texture != 0)
3087 {
3088 gl::Texture *tex = context->getTexture(texture);
3089
Jamie Madillbe849e42017-05-02 15:49:00 -04003090 if (tex == NULL)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003091 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003092 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04003093 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003094 }
3095
3096 if (level < 0)
3097 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003098 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04003099 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003100 }
3101 }
3102
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003103 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04003104 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04003105
Jamie Madill84115c92015-04-23 15:00:07 -04003106 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003107 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003108 context->handleError(InvalidOperation() << "Cannot change default FBO's attachments");
Geoff Langb1196682014-07-23 13:47:29 -04003109 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003110 }
3111
3112 return true;
3113}
3114
Geoff Langb1196682014-07-23 13:47:29 -04003115bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04003116{
3117 if (program == 0)
3118 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003119 context->handleError(InvalidValue());
Geoff Langb1196682014-07-23 13:47:29 -04003120 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003121 }
3122
Dian Xiang769769a2015-09-09 15:20:08 -07003123 gl::Program *programObject = GetValidProgram(context, program);
3124 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05003125 {
3126 return false;
3127 }
3128
Jamie Madill0063c512014-08-25 15:47:53 -04003129 if (!programObject || !programObject->isLinked())
3130 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003131 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04003132 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003133 }
3134
Geoff Lang7dd2e102014-11-10 15:19:26 -05003135 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04003136 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003137 context->handleError(InvalidOperation());
Geoff Langb1196682014-07-23 13:47:29 -04003138 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04003139 }
3140
Jamie Madill0063c512014-08-25 15:47:53 -04003141 return true;
3142}
3143
Geoff Langf41d0ee2016-10-07 13:04:23 -04003144static bool ValidateSizedGetUniform(Context *context,
3145 GLuint program,
3146 GLint location,
3147 GLsizei bufSize,
3148 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04003149{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003150 if (length)
3151 {
3152 *length = 0;
3153 }
3154
Jamie Madill78f41802014-08-25 15:47:55 -04003155 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04003156 {
Jamie Madill78f41802014-08-25 15:47:55 -04003157 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003158 }
3159
Geoff Langf41d0ee2016-10-07 13:04:23 -04003160 if (bufSize < 0)
3161 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003162 context->handleError(InvalidValue() << "bufSize cannot be negative.");
Geoff Langf41d0ee2016-10-07 13:04:23 -04003163 return false;
3164 }
3165
Jamie Madilla502c742014-08-28 17:19:13 -04003166 gl::Program *programObject = context->getProgram(program);
3167 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04003168
Jamie Madill78f41802014-08-25 15:47:55 -04003169 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04003170 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08003171 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04003172 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04003173 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003174 context->handleError(InvalidOperation()
3175 << "bufSize of at least " << requiredBytes << " is required.");
Geoff Langb1196682014-07-23 13:47:29 -04003176 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003177 }
3178
Geoff Langf41d0ee2016-10-07 13:04:23 -04003179 if (length)
3180 {
Geoff Lang94177fb2016-11-14 16:12:26 -05003181 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04003182 }
3183
Jamie Madill0063c512014-08-25 15:47:53 -04003184 return true;
3185}
3186
He Yunchaoced53ae2016-11-29 15:00:51 +08003187bool ValidateGetnUniformfvEXT(Context *context,
3188 GLuint program,
3189 GLint location,
3190 GLsizei bufSize,
3191 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003192{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003193 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04003194}
3195
He Yunchaoced53ae2016-11-29 15:00:51 +08003196bool ValidateGetnUniformivEXT(Context *context,
3197 GLuint program,
3198 GLint location,
3199 GLsizei bufSize,
3200 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003201{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003202 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3203}
3204
3205bool ValidateGetUniformfvRobustANGLE(Context *context,
3206 GLuint program,
3207 GLint location,
3208 GLsizei bufSize,
3209 GLsizei *length,
3210 GLfloat *params)
3211{
3212 if (!ValidateRobustEntryPoint(context, bufSize))
3213 {
3214 return false;
3215 }
3216
3217 // bufSize is validated in ValidateSizedGetUniform
3218 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3219}
3220
3221bool ValidateGetUniformivRobustANGLE(Context *context,
3222 GLuint program,
3223 GLint location,
3224 GLsizei bufSize,
3225 GLsizei *length,
3226 GLint *params)
3227{
3228 if (!ValidateRobustEntryPoint(context, bufSize))
3229 {
3230 return false;
3231 }
3232
3233 // bufSize is validated in ValidateSizedGetUniform
3234 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3235}
3236
3237bool ValidateGetUniformuivRobustANGLE(Context *context,
3238 GLuint program,
3239 GLint location,
3240 GLsizei bufSize,
3241 GLsizei *length,
3242 GLuint *params)
3243{
3244 if (!ValidateRobustEntryPoint(context, bufSize))
3245 {
3246 return false;
3247 }
3248
3249 if (context->getClientMajorVersion() < 3)
3250 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003251 context->handleError(InvalidOperation() << "Entry point requires at least OpenGL ES 3.0.");
Geoff Langf41d0ee2016-10-07 13:04:23 -04003252 return false;
3253 }
3254
3255 // bufSize is validated in ValidateSizedGetUniform
3256 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04003257}
3258
He Yunchaoced53ae2016-11-29 15:00:51 +08003259bool ValidateDiscardFramebufferBase(Context *context,
3260 GLenum target,
3261 GLsizei numAttachments,
3262 const GLenum *attachments,
3263 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07003264{
3265 if (numAttachments < 0)
3266 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003267 context->handleError(InvalidValue() << "numAttachments must not be less than zero");
Austin Kinross08332632015-05-05 13:35:47 -07003268 return false;
3269 }
3270
3271 for (GLsizei i = 0; i < numAttachments; ++i)
3272 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02003273 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07003274 {
3275 if (defaultFramebuffer)
3276 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003277 context->handleError(InvalidEnum()
3278 << "Invalid attachment when the default framebuffer is bound");
Austin Kinross08332632015-05-05 13:35:47 -07003279 return false;
3280 }
3281
3282 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
3283 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003284 context->handleError(InvalidOperation() << "Requested color attachment is "
3285 "greater than the maximum supported "
3286 "color attachments");
Austin Kinross08332632015-05-05 13:35:47 -07003287 return false;
3288 }
3289 }
3290 else
3291 {
3292 switch (attachments[i])
3293 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003294 case GL_DEPTH_ATTACHMENT:
3295 case GL_STENCIL_ATTACHMENT:
3296 case GL_DEPTH_STENCIL_ATTACHMENT:
3297 if (defaultFramebuffer)
3298 {
3299 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003300 InvalidEnum()
3301 << "Invalid attachment when the default framebuffer is bound");
He Yunchaoced53ae2016-11-29 15:00:51 +08003302 return false;
3303 }
3304 break;
3305 case GL_COLOR:
3306 case GL_DEPTH:
3307 case GL_STENCIL:
3308 if (!defaultFramebuffer)
3309 {
3310 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003311 InvalidEnum()
3312 << "Invalid attachment when the default framebuffer is not bound");
He Yunchaoced53ae2016-11-29 15:00:51 +08003313 return false;
3314 }
3315 break;
3316 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003317 context->handleError(InvalidEnum() << "Invalid attachment");
Austin Kinross08332632015-05-05 13:35:47 -07003318 return false;
Austin Kinross08332632015-05-05 13:35:47 -07003319 }
3320 }
3321 }
3322
3323 return true;
3324}
3325
Austin Kinross6ee1e782015-05-29 17:05:37 -07003326bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
3327{
3328 // Note that debug marker calls must not set error state
3329
3330 if (length < 0)
3331 {
3332 return false;
3333 }
3334
3335 if (marker == nullptr)
3336 {
3337 return false;
3338 }
3339
3340 return true;
3341}
3342
3343bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
3344{
3345 // Note that debug marker calls must not set error state
3346
3347 if (length < 0)
3348 {
3349 return false;
3350 }
3351
3352 if (length > 0 && marker == nullptr)
3353 {
3354 return false;
3355 }
3356
3357 return true;
3358}
3359
Geoff Langdcab33b2015-07-21 13:03:16 -04003360bool ValidateEGLImageTargetTexture2DOES(Context *context,
Geoff Langdcab33b2015-07-21 13:03:16 -04003361 GLenum target,
3362 egl::Image *image)
3363{
Geoff Langa8406172015-07-21 16:53:39 -04003364 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
3365 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003366 context->handleError(InvalidOperation());
Geoff Langa8406172015-07-21 16:53:39 -04003367 return false;
3368 }
3369
3370 switch (target)
3371 {
3372 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04003373 if (!context->getExtensions().eglImage)
3374 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003375 context->handleError(InvalidEnum()
3376 << "GL_TEXTURE_2D texture target requires GL_OES_EGL_image.");
Geoff Langb66a9092016-05-16 15:59:14 -04003377 }
3378 break;
3379
3380 case GL_TEXTURE_EXTERNAL_OES:
3381 if (!context->getExtensions().eglImageExternal)
3382 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003383 context->handleError(InvalidEnum() << "GL_TEXTURE_EXTERNAL_OES texture target "
3384 "requires GL_OES_EGL_image_external.");
Geoff Langb66a9092016-05-16 15:59:14 -04003385 }
Geoff Langa8406172015-07-21 16:53:39 -04003386 break;
3387
3388 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003389 context->handleError(InvalidEnum() << "invalid texture target.");
Geoff Langa8406172015-07-21 16:53:39 -04003390 return false;
3391 }
3392
Jamie Madill61e16b42017-06-19 11:13:23 -04003393 ASSERT(context->getCurrentDisplay());
3394 if (!context->getCurrentDisplay()->isValidImage(image))
Geoff Langa8406172015-07-21 16:53:39 -04003395 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003396 context->handleError(InvalidValue() << "EGL image is not valid.");
Geoff Langa8406172015-07-21 16:53:39 -04003397 return false;
3398 }
3399
3400 if (image->getSamples() > 0)
3401 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003402 context->handleError(InvalidOperation()
3403 << "cannot create a 2D texture from a multisampled EGL image.");
Geoff Langa8406172015-07-21 16:53:39 -04003404 return false;
3405 }
3406
Geoff Langca271392017-04-05 12:30:00 -04003407 const TextureCaps &textureCaps =
3408 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003409 if (!textureCaps.texturable)
3410 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003411 context->handleError(InvalidOperation()
3412 << "EGL image internal format is not supported as a texture.");
Geoff Langa8406172015-07-21 16:53:39 -04003413 return false;
3414 }
3415
Geoff Langdcab33b2015-07-21 13:03:16 -04003416 return true;
3417}
3418
3419bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
Geoff Langdcab33b2015-07-21 13:03:16 -04003420 GLenum target,
3421 egl::Image *image)
3422{
Geoff Langa8406172015-07-21 16:53:39 -04003423 if (!context->getExtensions().eglImage)
3424 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003425 context->handleError(InvalidOperation());
Geoff Langa8406172015-07-21 16:53:39 -04003426 return false;
3427 }
3428
3429 switch (target)
3430 {
3431 case GL_RENDERBUFFER:
3432 break;
3433
3434 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003435 context->handleError(InvalidEnum() << "invalid renderbuffer target.");
Geoff Langa8406172015-07-21 16:53:39 -04003436 return false;
3437 }
3438
Jamie Madill61e16b42017-06-19 11:13:23 -04003439 ASSERT(context->getCurrentDisplay());
3440 if (!context->getCurrentDisplay()->isValidImage(image))
Geoff Langa8406172015-07-21 16:53:39 -04003441 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003442 context->handleError(InvalidValue() << "EGL image is not valid.");
Geoff Langa8406172015-07-21 16:53:39 -04003443 return false;
3444 }
3445
Geoff Langca271392017-04-05 12:30:00 -04003446 const TextureCaps &textureCaps =
3447 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003448 if (!textureCaps.renderable)
3449 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003450 context->handleError(InvalidOperation()
3451 << "EGL image internal format is not supported as a renderbuffer.");
Geoff Langa8406172015-07-21 16:53:39 -04003452 return false;
3453 }
3454
Geoff Langdcab33b2015-07-21 13:03:16 -04003455 return true;
3456}
Austin Kinrossbc781f32015-10-26 09:27:38 -07003457
3458bool ValidateBindVertexArrayBase(Context *context, GLuint array)
3459{
Geoff Lang36167ab2015-12-07 10:27:14 -05003460 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07003461 {
3462 // The default VAO should always exist
3463 ASSERT(array != 0);
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003464 context->handleError(InvalidOperation());
Austin Kinrossbc781f32015-10-26 09:27:38 -07003465 return false;
3466 }
3467
3468 return true;
3469}
3470
Geoff Langc5629752015-12-07 16:29:04 -05003471bool ValidateProgramBinaryBase(Context *context,
3472 GLuint program,
3473 GLenum binaryFormat,
3474 const void *binary,
3475 GLint length)
3476{
3477 Program *programObject = GetValidProgram(context, program);
3478 if (programObject == nullptr)
3479 {
3480 return false;
3481 }
3482
3483 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3484 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3485 programBinaryFormats.end())
3486 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003487 context->handleError(InvalidEnum() << "Program binary format is not valid.");
Geoff Langc5629752015-12-07 16:29:04 -05003488 return false;
3489 }
3490
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003491 if (context->hasActiveTransformFeedback(program))
3492 {
3493 // ES 3.0.4 section 2.15 page 91
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003494 context->handleError(InvalidOperation() << "Cannot change program binary while program "
3495 "is associated with an active transform "
3496 "feedback object.");
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003497 return false;
3498 }
3499
Geoff Langc5629752015-12-07 16:29:04 -05003500 return true;
3501}
3502
3503bool ValidateGetProgramBinaryBase(Context *context,
3504 GLuint program,
3505 GLsizei bufSize,
3506 GLsizei *length,
3507 GLenum *binaryFormat,
3508 void *binary)
3509{
3510 Program *programObject = GetValidProgram(context, program);
3511 if (programObject == nullptr)
3512 {
3513 return false;
3514 }
3515
3516 if (!programObject->isLinked())
3517 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003518 context->handleError(InvalidOperation() << "Program is not linked.");
Geoff Langc5629752015-12-07 16:29:04 -05003519 return false;
3520 }
3521
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003522 if (context->getCaps().programBinaryFormats.empty())
3523 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003524 context->handleError(InvalidOperation() << "No program binary formats supported.");
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003525 return false;
3526 }
3527
Geoff Langc5629752015-12-07 16:29:04 -05003528 return true;
3529}
Jamie Madillc29968b2016-01-20 11:17:23 -05003530
Jamie Madillc29968b2016-01-20 11:17:23 -05003531bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
3532{
3533 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3534 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3535 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003536 context->handleError(InvalidValue()
3537 << "n must be non-negative and no greater than MAX_DRAW_BUFFERS");
Jamie Madillc29968b2016-01-20 11:17:23 -05003538 return false;
3539 }
3540
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003541 ASSERT(context->getGLState().getDrawFramebuffer());
3542 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05003543 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3544
3545 // This should come first before the check for the default frame buffer
3546 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3547 // rather than INVALID_OPERATION
3548 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3549 {
3550 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3551
3552 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02003553 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3554 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05003555 {
3556 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02003557 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3558 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3559 // 3.1 is still a bit ambiguous about the error, but future specs are
3560 // expected to clarify that GL_INVALID_ENUM is the correct error.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003561 context->handleError(InvalidEnum() << "Invalid buffer value");
Olli Etuaho84c9f592016-03-09 14:37:25 +02003562 return false;
3563 }
3564 else if (bufs[colorAttachment] >= maxColorAttachment)
3565 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003566 context->handleError(InvalidOperation()
3567 << "Buffer value is greater than MAX_DRAW_BUFFERS");
Jamie Madillc29968b2016-01-20 11:17:23 -05003568 return false;
3569 }
3570 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3571 frameBufferId != 0)
3572 {
3573 // INVALID_OPERATION-GL is bound to buffer and ith argument
3574 // is not COLOR_ATTACHMENTi or NONE
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003575 context->handleError(InvalidOperation()
3576 << "Ith value does not match COLOR_ATTACHMENTi or NONE");
Jamie Madillc29968b2016-01-20 11:17:23 -05003577 return false;
3578 }
3579 }
3580
3581 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3582 // and n is not 1 or bufs is bound to value other than BACK and NONE
3583 if (frameBufferId == 0)
3584 {
3585 if (n != 1)
3586 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003587 context->handleError(InvalidOperation()
3588 << "n must be 1 when GL is bound to the default framebuffer");
Jamie Madillc29968b2016-01-20 11:17:23 -05003589 return false;
3590 }
3591
3592 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3593 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003594 context->handleError(
3595 InvalidOperation()
3596 << "Only NONE or BACK are valid values when drawing to the default framebuffer");
Jamie Madillc29968b2016-01-20 11:17:23 -05003597 return false;
3598 }
3599 }
3600
3601 return true;
3602}
3603
Geoff Lang496c02d2016-10-20 11:38:11 -07003604bool ValidateGetBufferPointervBase(Context *context,
3605 GLenum target,
3606 GLenum pname,
3607 GLsizei *length,
3608 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03003609{
Geoff Lang496c02d2016-10-20 11:38:11 -07003610 if (length)
3611 {
3612 *length = 0;
3613 }
3614
3615 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
3616 {
3617 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003618 InvalidOperation()
3619 << "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled.");
Geoff Lang496c02d2016-10-20 11:38:11 -07003620 return false;
3621 }
3622
Olli Etuaho4f667482016-03-30 15:56:35 +03003623 if (!ValidBufferTarget(context, target))
3624 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003625 context->handleError(InvalidEnum() << "Buffer target not valid: 0x" << std::hex
3626 << std::uppercase << target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003627 return false;
3628 }
3629
Geoff Lang496c02d2016-10-20 11:38:11 -07003630 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03003631 {
Geoff Lang496c02d2016-10-20 11:38:11 -07003632 case GL_BUFFER_MAP_POINTER:
3633 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03003634
Geoff Lang496c02d2016-10-20 11:38:11 -07003635 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003636 context->handleError(InvalidEnum() << "Unknown pname.");
Geoff Lang496c02d2016-10-20 11:38:11 -07003637 return false;
3638 }
Olli Etuaho4f667482016-03-30 15:56:35 +03003639
3640 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3641 // target bound to zero generate an INVALID_OPERATION error."
3642 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07003643 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03003644 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003645 context->handleError(InvalidOperation()
3646 << "Can not get pointer for reserved buffer name zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003647 return false;
3648 }
3649
Geoff Lang496c02d2016-10-20 11:38:11 -07003650 if (length)
3651 {
3652 *length = 1;
3653 }
3654
Olli Etuaho4f667482016-03-30 15:56:35 +03003655 return true;
3656}
3657
3658bool ValidateUnmapBufferBase(Context *context, GLenum target)
3659{
3660 if (!ValidBufferTarget(context, target))
3661 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003662 context->handleError(InvalidEnum() << "Invalid buffer target.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003663 return false;
3664 }
3665
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003666 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003667
3668 if (buffer == nullptr || !buffer->isMapped())
3669 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003670 context->handleError(InvalidOperation() << "Buffer not mapped.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003671 return false;
3672 }
3673
3674 return true;
3675}
3676
3677bool ValidateMapBufferRangeBase(Context *context,
3678 GLenum target,
3679 GLintptr offset,
3680 GLsizeiptr length,
3681 GLbitfield access)
3682{
3683 if (!ValidBufferTarget(context, target))
3684 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003685 context->handleError(InvalidEnum() << "Invalid buffer target.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003686 return false;
3687 }
3688
3689 if (offset < 0 || length < 0)
3690 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003691 context->handleError(InvalidValue() << "Invalid offset or length.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003692 return false;
3693 }
3694
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003695 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003696
3697 if (!buffer)
3698 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003699 context->handleError(InvalidOperation() << "Attempted to map buffer object zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003700 return false;
3701 }
3702
3703 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003704 CheckedNumeric<size_t> checkedOffset(offset);
3705 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003706
Jamie Madille2e406c2016-06-02 13:04:10 -04003707 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003708 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003709 context->handleError(InvalidValue() << "Mapped range does not fit into buffer dimensions.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003710 return false;
3711 }
3712
3713 // Check for invalid bits in the mask
3714 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3715 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3716 GL_MAP_UNSYNCHRONIZED_BIT;
3717
3718 if (access & ~(allAccessBits))
3719 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003720 context->handleError(InvalidValue()
3721 << "Invalid access bits: 0x" << std::hex << std::uppercase << access);
Olli Etuaho4f667482016-03-30 15:56:35 +03003722 return false;
3723 }
3724
3725 if (length == 0)
3726 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003727 context->handleError(InvalidOperation() << "Buffer mapping length is zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003728 return false;
3729 }
3730
3731 if (buffer->isMapped())
3732 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003733 context->handleError(InvalidOperation() << "Buffer is already mapped.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003734 return false;
3735 }
3736
3737 // Check for invalid bit combinations
3738 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3739 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003740 context->handleError(InvalidOperation()
3741 << "Need to map buffer for either reading or writing.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003742 return false;
3743 }
3744
3745 GLbitfield writeOnlyBits =
3746 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3747
3748 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3749 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003750 context->handleError(InvalidOperation()
3751 << "Invalid access bits when mapping buffer for reading: 0x"
3752 << std::hex << std::uppercase << access);
Olli Etuaho4f667482016-03-30 15:56:35 +03003753 return false;
3754 }
3755
3756 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3757 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003758 context->handleError(
3759 InvalidOperation()
3760 << "The explicit flushing bit may only be set if the buffer is mapped for writing.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003761 return false;
3762 }
3763 return true;
3764}
3765
3766bool ValidateFlushMappedBufferRangeBase(Context *context,
3767 GLenum target,
3768 GLintptr offset,
3769 GLsizeiptr length)
3770{
3771 if (offset < 0 || length < 0)
3772 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003773 context->handleError(InvalidValue() << "Invalid offset/length parameters.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003774 return false;
3775 }
3776
3777 if (!ValidBufferTarget(context, target))
3778 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003779 context->handleError(InvalidEnum() << "Invalid buffer target.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003780 return false;
3781 }
3782
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003783 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003784
3785 if (buffer == nullptr)
3786 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003787 context->handleError(InvalidOperation() << "Attempted to flush buffer object zero.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003788 return false;
3789 }
3790
3791 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3792 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003793 context->handleError(InvalidOperation()
3794 << "Attempted to flush a buffer not mapped for explicit flushing.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003795 return false;
3796 }
3797
3798 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003799 CheckedNumeric<size_t> checkedOffset(offset);
3800 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003801
Jamie Madille2e406c2016-06-02 13:04:10 -04003802 if (!checkedSize.IsValid() ||
3803 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003804 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003805 context->handleError(InvalidValue()
3806 << "Flushed range does not fit into buffer mapping dimensions.");
Olli Etuaho4f667482016-03-30 15:56:35 +03003807 return false;
3808 }
3809
3810 return true;
3811}
3812
Olli Etuaho41997e72016-03-10 13:38:39 +02003813bool ValidateGenOrDelete(Context *context, GLint n)
3814{
3815 if (n < 0)
3816 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003817 context->handleError(InvalidValue() << "n < 0");
Olli Etuaho41997e72016-03-10 13:38:39 +02003818 return false;
3819 }
3820 return true;
3821}
3822
Geoff Langff5b2d52016-09-07 11:32:23 -04003823bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
3824{
3825 if (!context->getExtensions().robustClientMemory)
3826 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003827 context->handleError(InvalidOperation()
3828 << "GL_ANGLE_robust_client_memory is not available.");
Geoff Langff5b2d52016-09-07 11:32:23 -04003829 return false;
3830 }
3831
3832 if (bufSize < 0)
3833 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003834 context->handleError(InvalidValue() << "bufSize cannot be negative.");
Geoff Langff5b2d52016-09-07 11:32:23 -04003835 return false;
3836 }
3837
3838 return true;
3839}
3840
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003841bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
3842{
3843 if (bufSize < numParams)
3844 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003845 context->handleError(InvalidOperation() << numParams << " parameters are required but "
3846 << bufSize << " were provided.");
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003847 return false;
3848 }
3849
3850 return true;
3851}
3852
Jamie Madillbe849e42017-05-02 15:49:00 -04003853bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context,
3854 GLenum target,
3855 GLenum attachment,
3856 GLenum pname,
3857 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04003858{
3859 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08003860 if (numParams)
3861 {
3862 *numParams = 1;
3863 }
Geoff Langff5b2d52016-09-07 11:32:23 -04003864
3865 if (!ValidFramebufferTarget(target))
3866 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003867 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003868 return false;
3869 }
3870
3871 int clientVersion = context->getClientMajorVersion();
3872
3873 switch (pname)
3874 {
3875 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3876 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3877 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3878 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3879 break;
3880
3881 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3882 if (clientVersion < 3 && !context->getExtensions().sRGB)
3883 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003884 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003885 return false;
3886 }
3887 break;
3888
3889 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3890 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3891 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3892 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3893 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3894 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3895 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3896 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3897 if (clientVersion < 3)
3898 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003899 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003900 return false;
3901 }
3902 break;
3903
3904 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003905 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003906 return false;
3907 }
3908
3909 // Determine if the attachment is a valid enum
3910 switch (attachment)
3911 {
3912 case GL_BACK:
3913 case GL_FRONT:
3914 case GL_DEPTH:
3915 case GL_STENCIL:
3916 case GL_DEPTH_STENCIL_ATTACHMENT:
3917 if (clientVersion < 3)
3918 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003919 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003920 return false;
3921 }
3922 break;
3923
3924 case GL_DEPTH_ATTACHMENT:
3925 case GL_STENCIL_ATTACHMENT:
3926 break;
3927
3928 default:
3929 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
3930 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3931 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003932 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04003933 return false;
3934 }
3935 break;
3936 }
3937
3938 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
3939 ASSERT(framebuffer);
3940
3941 if (framebuffer->id() == 0)
3942 {
3943 if (clientVersion < 3)
3944 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003945 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003946 return false;
3947 }
3948
3949 switch (attachment)
3950 {
3951 case GL_BACK:
3952 case GL_DEPTH:
3953 case GL_STENCIL:
3954 break;
3955
3956 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003957 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003958 return false;
3959 }
3960 }
3961 else
3962 {
3963 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3964 {
3965 // Valid attachment query
3966 }
3967 else
3968 {
3969 switch (attachment)
3970 {
3971 case GL_DEPTH_ATTACHMENT:
3972 case GL_STENCIL_ATTACHMENT:
3973 break;
3974
3975 case GL_DEPTH_STENCIL_ATTACHMENT:
3976 if (!framebuffer->hasValidDepthStencil())
3977 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003978 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003979 return false;
3980 }
3981 break;
3982
3983 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05003984 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04003985 return false;
3986 }
3987 }
3988 }
3989
3990 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
3991 if (attachmentObject)
3992 {
3993 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
3994 attachmentObject->type() == GL_TEXTURE ||
3995 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
3996
3997 switch (pname)
3998 {
3999 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4000 if (attachmentObject->type() != GL_RENDERBUFFER &&
4001 attachmentObject->type() != GL_TEXTURE)
4002 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004003 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004004 return false;
4005 }
4006 break;
4007
4008 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
4009 if (attachmentObject->type() != GL_TEXTURE)
4010 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004011 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004012 return false;
4013 }
4014 break;
4015
4016 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
4017 if (attachmentObject->type() != GL_TEXTURE)
4018 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004019 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004020 return false;
4021 }
4022 break;
4023
4024 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4025 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
4026 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004027 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04004028 return false;
4029 }
4030 break;
4031
4032 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
4033 if (attachmentObject->type() != GL_TEXTURE)
4034 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004035 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004036 return false;
4037 }
4038 break;
4039
4040 default:
4041 break;
4042 }
4043 }
4044 else
4045 {
4046 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
4047 // is NONE, then querying any other pname will generate INVALID_ENUM.
4048
4049 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
4050 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
4051 // INVALID_OPERATION for all other pnames
4052
4053 switch (pname)
4054 {
4055 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
4056 break;
4057
4058 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4059 if (clientVersion < 3)
4060 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004061 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004062 return false;
4063 }
4064 break;
4065
4066 default:
4067 if (clientVersion < 3)
4068 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004069 context->handleError(InvalidEnum());
Geoff Langff5b2d52016-09-07 11:32:23 -04004070 return false;
4071 }
4072 else
4073 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004074 context->handleError(InvalidOperation());
Geoff Langff5b2d52016-09-07 11:32:23 -04004075 return false;
4076 }
4077 }
4078 }
4079
4080 return true;
4081}
4082
4083bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
4084 GLenum target,
4085 GLenum attachment,
4086 GLenum pname,
4087 GLsizei bufSize,
4088 GLsizei *numParams)
4089{
4090 if (!ValidateRobustEntryPoint(context, bufSize))
4091 {
4092 return false;
4093 }
4094
Jamie Madillbe849e42017-05-02 15:49:00 -04004095 if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname,
4096 numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004097 {
4098 return false;
4099 }
4100
4101 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4102 {
4103 return false;
4104 }
4105
4106 return true;
4107}
4108
Geoff Langff5b2d52016-09-07 11:32:23 -04004109bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
4110 GLenum target,
4111 GLenum pname,
4112 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04004113 GLsizei *length,
4114 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04004115{
4116 if (!ValidateRobustEntryPoint(context, bufSize))
4117 {
4118 return false;
4119 }
4120
Geoff Langebebe1c2016-10-14 12:01:31 -04004121 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004122 {
4123 return false;
4124 }
4125
Geoff Langebebe1c2016-10-14 12:01:31 -04004126 if (!ValidateRobustBufferSize(context, bufSize, *length))
4127 {
4128 return false;
4129 }
4130
4131 return true;
4132}
4133
4134bool ValidateGetBufferParameteri64v(ValidationContext *context,
4135 GLenum target,
4136 GLenum pname,
4137 GLint64 *params)
4138{
4139 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
4140}
4141
4142bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
4143 GLenum target,
4144 GLenum pname,
4145 GLsizei bufSize,
4146 GLsizei *length,
4147 GLint64 *params)
4148{
4149 if (!ValidateRobustEntryPoint(context, bufSize))
4150 {
4151 return false;
4152 }
4153
4154 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
4155 {
4156 return false;
4157 }
4158
4159 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004160 {
4161 return false;
4162 }
4163
4164 return true;
4165}
4166
Jamie Madillbe849e42017-05-02 15:49:00 -04004167bool ValidateGetProgramivBase(ValidationContext *context,
4168 GLuint program,
4169 GLenum pname,
4170 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04004171{
4172 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08004173 if (numParams)
4174 {
4175 *numParams = 1;
4176 }
Geoff Langff5b2d52016-09-07 11:32:23 -04004177
4178 Program *programObject = GetValidProgram(context, program);
4179 if (!programObject)
4180 {
4181 return false;
4182 }
4183
4184 switch (pname)
4185 {
4186 case GL_DELETE_STATUS:
4187 case GL_LINK_STATUS:
4188 case GL_VALIDATE_STATUS:
4189 case GL_INFO_LOG_LENGTH:
4190 case GL_ATTACHED_SHADERS:
4191 case GL_ACTIVE_ATTRIBUTES:
4192 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
4193 case GL_ACTIVE_UNIFORMS:
4194 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
4195 break;
4196
4197 case GL_PROGRAM_BINARY_LENGTH:
4198 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
4199 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004200 context->handleError(InvalidEnum() << "Querying GL_PROGRAM_BINARY_LENGTH "
4201 "requires GL_OES_get_program_binary or "
4202 "ES 3.0.");
Geoff Langff5b2d52016-09-07 11:32:23 -04004203 return false;
4204 }
4205 break;
4206
4207 case GL_ACTIVE_UNIFORM_BLOCKS:
4208 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
4209 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
4210 case GL_TRANSFORM_FEEDBACK_VARYINGS:
4211 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
4212 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
4213 if (context->getClientMajorVersion() < 3)
4214 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004215 context->handleError(InvalidEnum() << "Querying requires at least ES 3.0.");
Geoff Langff5b2d52016-09-07 11:32:23 -04004216 return false;
4217 }
4218 break;
4219
Yunchao He61afff12017-03-14 15:34:03 +08004220 case GL_PROGRAM_SEPARABLE:
4221 if (context->getClientVersion() < Version(3, 1))
4222 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004223 context->handleError(InvalidEnum() << "Querying requires at least ES 3.1.");
Yunchao He61afff12017-03-14 15:34:03 +08004224 return false;
4225 }
4226 break;
4227
Geoff Langff5b2d52016-09-07 11:32:23 -04004228 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004229 context->handleError(InvalidEnum() << "Unknown parameter name.");
Geoff Langff5b2d52016-09-07 11:32:23 -04004230 return false;
4231 }
4232
4233 return true;
4234}
4235
4236bool ValidateGetProgramivRobustANGLE(Context *context,
4237 GLuint program,
4238 GLenum pname,
4239 GLsizei bufSize,
4240 GLsizei *numParams)
4241{
4242 if (!ValidateRobustEntryPoint(context, bufSize))
4243 {
4244 return false;
4245 }
4246
Jamie Madillbe849e42017-05-02 15:49:00 -04004247 if (!ValidateGetProgramivBase(context, program, pname, numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004248 {
4249 return false;
4250 }
4251
4252 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4253 {
4254 return false;
4255 }
4256
4257 return true;
4258}
4259
Geoff Lang740d9022016-10-07 11:20:52 -04004260bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
4261 GLenum target,
4262 GLenum pname,
4263 GLsizei bufSize,
4264 GLsizei *length,
4265 GLint *params)
4266{
4267 if (!ValidateRobustEntryPoint(context, bufSize))
4268 {
4269 return false;
4270 }
4271
4272 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
4273 {
4274 return false;
4275 }
4276
4277 if (!ValidateRobustBufferSize(context, bufSize, *length))
4278 {
4279 return false;
4280 }
4281
4282 return true;
4283}
4284
Geoff Langd7d0ed32016-10-07 11:33:51 -04004285bool ValidateGetShaderivRobustANGLE(Context *context,
4286 GLuint shader,
4287 GLenum pname,
4288 GLsizei bufSize,
4289 GLsizei *length,
4290 GLint *params)
4291{
4292 if (!ValidateRobustEntryPoint(context, bufSize))
4293 {
4294 return false;
4295 }
4296
4297 if (!ValidateGetShaderivBase(context, shader, pname, length))
4298 {
4299 return false;
4300 }
4301
4302 if (!ValidateRobustBufferSize(context, bufSize, *length))
4303 {
4304 return false;
4305 }
4306
4307 return true;
4308}
4309
Geoff Langc1984ed2016-10-07 12:41:00 -04004310bool ValidateGetTexParameterfvRobustANGLE(Context *context,
4311 GLenum target,
4312 GLenum pname,
4313 GLsizei bufSize,
4314 GLsizei *length,
4315 GLfloat *params)
4316{
4317 if (!ValidateRobustEntryPoint(context, bufSize))
4318 {
4319 return false;
4320 }
4321
4322 if (!ValidateGetTexParameterBase(context, target, pname, length))
4323 {
4324 return false;
4325 }
4326
4327 if (!ValidateRobustBufferSize(context, bufSize, *length))
4328 {
4329 return false;
4330 }
4331
4332 return true;
4333}
4334
Geoff Langc1984ed2016-10-07 12:41:00 -04004335bool ValidateGetTexParameterivRobustANGLE(Context *context,
4336 GLenum target,
4337 GLenum pname,
4338 GLsizei bufSize,
4339 GLsizei *length,
4340 GLint *params)
4341{
4342 if (!ValidateRobustEntryPoint(context, bufSize))
4343 {
4344 return false;
4345 }
4346
4347 if (!ValidateGetTexParameterBase(context, target, pname, length))
4348 {
4349 return false;
4350 }
4351
4352 if (!ValidateRobustBufferSize(context, bufSize, *length))
4353 {
4354 return false;
4355 }
4356
4357 return true;
4358}
4359
Geoff Langc1984ed2016-10-07 12:41:00 -04004360bool ValidateTexParameterfvRobustANGLE(Context *context,
4361 GLenum target,
4362 GLenum pname,
4363 GLsizei bufSize,
4364 const GLfloat *params)
4365{
4366 if (!ValidateRobustEntryPoint(context, bufSize))
4367 {
4368 return false;
4369 }
4370
4371 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4372}
4373
Geoff Langc1984ed2016-10-07 12:41:00 -04004374bool ValidateTexParameterivRobustANGLE(Context *context,
4375 GLenum target,
4376 GLenum pname,
4377 GLsizei bufSize,
4378 const GLint *params)
4379{
4380 if (!ValidateRobustEntryPoint(context, bufSize))
4381 {
4382 return false;
4383 }
4384
4385 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4386}
4387
4388bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
4389{
4390 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4391}
4392
4393bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
4394 GLuint sampler,
4395 GLenum pname,
4396 GLuint bufSize,
4397 GLsizei *length,
4398 GLfloat *params)
4399{
4400 if (!ValidateRobustEntryPoint(context, bufSize))
4401 {
4402 return false;
4403 }
4404
4405 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4406 {
4407 return false;
4408 }
4409
4410 if (!ValidateRobustBufferSize(context, bufSize, *length))
4411 {
4412 return false;
4413 }
4414
4415 return true;
4416}
4417
4418bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
4419{
4420 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4421}
4422
4423bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
4424 GLuint sampler,
4425 GLenum pname,
4426 GLuint bufSize,
4427 GLsizei *length,
4428 GLint *params)
4429{
4430 if (!ValidateRobustEntryPoint(context, bufSize))
4431 {
4432 return false;
4433 }
4434
4435 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4436 {
4437 return false;
4438 }
4439
4440 if (!ValidateRobustBufferSize(context, bufSize, *length))
4441 {
4442 return false;
4443 }
4444
4445 return true;
4446}
4447
4448bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
4449{
4450 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4451}
4452
4453bool ValidateSamplerParameterfv(Context *context,
4454 GLuint sampler,
4455 GLenum pname,
4456 const GLfloat *params)
4457{
4458 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4459}
4460
4461bool ValidateSamplerParameterfvRobustANGLE(Context *context,
4462 GLuint sampler,
4463 GLenum pname,
4464 GLsizei bufSize,
4465 const GLfloat *params)
4466{
4467 if (!ValidateRobustEntryPoint(context, bufSize))
4468 {
4469 return false;
4470 }
4471
4472 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4473}
4474
4475bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
4476{
4477 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4478}
4479
4480bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
4481{
4482 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4483}
4484
4485bool ValidateSamplerParameterivRobustANGLE(Context *context,
4486 GLuint sampler,
4487 GLenum pname,
4488 GLsizei bufSize,
4489 const GLint *params)
4490{
4491 if (!ValidateRobustEntryPoint(context, bufSize))
4492 {
4493 return false;
4494 }
4495
4496 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4497}
4498
Geoff Lang0b031062016-10-13 14:30:04 -04004499bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
4500 GLuint index,
4501 GLenum pname,
4502 GLsizei bufSize,
4503 GLsizei *length,
4504 GLfloat *params)
4505{
4506 if (!ValidateRobustEntryPoint(context, bufSize))
4507 {
4508 return false;
4509 }
4510
4511 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4512 {
4513 return false;
4514 }
4515
4516 if (!ValidateRobustBufferSize(context, bufSize, *length))
4517 {
4518 return false;
4519 }
4520
4521 return true;
4522}
4523
Geoff Lang0b031062016-10-13 14:30:04 -04004524bool ValidateGetVertexAttribivRobustANGLE(Context *context,
4525 GLuint index,
4526 GLenum pname,
4527 GLsizei bufSize,
4528 GLsizei *length,
4529 GLint *params)
4530{
4531 if (!ValidateRobustEntryPoint(context, bufSize))
4532 {
4533 return false;
4534 }
4535
4536 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4537 {
4538 return false;
4539 }
4540
4541 if (!ValidateRobustBufferSize(context, bufSize, *length))
4542 {
4543 return false;
4544 }
4545
4546 return true;
4547}
4548
Geoff Lang0b031062016-10-13 14:30:04 -04004549bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
4550 GLuint index,
4551 GLenum pname,
4552 GLsizei bufSize,
4553 GLsizei *length,
4554 void **pointer)
4555{
4556 if (!ValidateRobustEntryPoint(context, bufSize))
4557 {
4558 return false;
4559 }
4560
4561 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
4562 {
4563 return false;
4564 }
4565
4566 if (!ValidateRobustBufferSize(context, bufSize, *length))
4567 {
4568 return false;
4569 }
4570
4571 return true;
4572}
4573
4574bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
4575{
4576 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4577}
4578
4579bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
4580 GLuint index,
4581 GLenum pname,
4582 GLsizei bufSize,
4583 GLsizei *length,
4584 GLint *params)
4585{
4586 if (!ValidateRobustEntryPoint(context, bufSize))
4587 {
4588 return false;
4589 }
4590
4591 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4592 {
4593 return false;
4594 }
4595
4596 if (!ValidateRobustBufferSize(context, bufSize, *length))
4597 {
4598 return false;
4599 }
4600
4601 return true;
4602}
4603
4604bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
4605{
4606 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4607}
4608
4609bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
4610 GLuint index,
4611 GLenum pname,
4612 GLsizei bufSize,
4613 GLsizei *length,
4614 GLuint *params)
4615{
4616 if (!ValidateRobustEntryPoint(context, bufSize))
4617 {
4618 return false;
4619 }
4620
4621 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4622 {
4623 return false;
4624 }
4625
4626 if (!ValidateRobustBufferSize(context, bufSize, *length))
4627 {
4628 return false;
4629 }
4630
4631 return true;
4632}
4633
Geoff Lang6899b872016-10-14 11:30:13 -04004634bool ValidateGetActiveUniformBlockiv(Context *context,
4635 GLuint program,
4636 GLuint uniformBlockIndex,
4637 GLenum pname,
4638 GLint *params)
4639{
4640 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
4641}
4642
4643bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
4644 GLuint program,
4645 GLuint uniformBlockIndex,
4646 GLenum pname,
4647 GLsizei bufSize,
4648 GLsizei *length,
4649 GLint *params)
4650{
4651 if (!ValidateRobustEntryPoint(context, bufSize))
4652 {
4653 return false;
4654 }
4655
4656 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
4657 {
4658 return false;
4659 }
4660
4661 if (!ValidateRobustBufferSize(context, bufSize, *length))
4662 {
4663 return false;
4664 }
4665
4666 return true;
4667}
4668
Geoff Lang0a9661f2016-10-20 10:59:20 -07004669bool ValidateGetInternalFormativ(Context *context,
4670 GLenum target,
4671 GLenum internalformat,
4672 GLenum pname,
4673 GLsizei bufSize,
4674 GLint *params)
4675{
4676 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
4677 nullptr);
4678}
4679
4680bool ValidateGetInternalFormativRobustANGLE(Context *context,
4681 GLenum target,
4682 GLenum internalformat,
4683 GLenum pname,
4684 GLsizei bufSize,
4685 GLsizei *length,
4686 GLint *params)
4687{
4688 if (!ValidateRobustEntryPoint(context, bufSize))
4689 {
4690 return false;
4691 }
4692
4693 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
4694 {
4695 return false;
4696 }
4697
4698 if (!ValidateRobustBufferSize(context, bufSize, *length))
4699 {
4700 return false;
4701 }
4702
4703 return true;
4704}
4705
Shao80957d92017-02-20 21:25:59 +08004706bool ValidateVertexFormatBase(ValidationContext *context,
4707 GLuint attribIndex,
4708 GLint size,
4709 GLenum type,
4710 GLboolean pureInteger)
4711{
4712 const Caps &caps = context->getCaps();
4713 if (attribIndex >= caps.maxVertexAttributes)
4714 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004715 context->handleError(InvalidValue()
4716 << "attribindex must be smaller than MAX_VERTEX_ATTRIBS.");
Shao80957d92017-02-20 21:25:59 +08004717 return false;
4718 }
4719
4720 if (size < 1 || size > 4)
4721 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004722 context->handleError(InvalidValue() << "size must be between one and four.");
Geoff Lang8700a982017-06-13 10:15:13 -04004723 return false;
Shao80957d92017-02-20 21:25:59 +08004724 }
4725
4726 switch (type)
4727 {
4728 case GL_BYTE:
4729 case GL_UNSIGNED_BYTE:
4730 case GL_SHORT:
4731 case GL_UNSIGNED_SHORT:
4732 break;
4733
4734 case GL_INT:
4735 case GL_UNSIGNED_INT:
4736 if (context->getClientMajorVersion() < 3)
4737 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004738 context->handleError(InvalidEnum()
4739 << "Vertex type not supported before OpenGL ES 3.0.");
Shao80957d92017-02-20 21:25:59 +08004740 return false;
4741 }
4742 break;
4743
4744 case GL_FIXED:
4745 case GL_FLOAT:
4746 if (pureInteger)
4747 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004748 context->handleError(InvalidEnum() << "Type is not integer.");
Shao80957d92017-02-20 21:25:59 +08004749 return false;
4750 }
4751 break;
4752
4753 case GL_HALF_FLOAT:
4754 if (context->getClientMajorVersion() < 3)
4755 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004756 context->handleError(InvalidEnum()
4757 << "Vertex type not supported before OpenGL ES 3.0.");
Shao80957d92017-02-20 21:25:59 +08004758 return false;
4759 }
4760 if (pureInteger)
4761 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004762 context->handleError(InvalidEnum() << "Type is not integer.");
Shao80957d92017-02-20 21:25:59 +08004763 return false;
4764 }
4765 break;
4766
4767 case GL_INT_2_10_10_10_REV:
4768 case GL_UNSIGNED_INT_2_10_10_10_REV:
4769 if (context->getClientMajorVersion() < 3)
4770 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004771 context->handleError(InvalidEnum()
4772 << "Vertex type not supported before OpenGL ES 3.0.");
Shao80957d92017-02-20 21:25:59 +08004773 return false;
4774 }
4775 if (pureInteger)
4776 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004777 context->handleError(InvalidEnum() << "Type is not integer.");
Shao80957d92017-02-20 21:25:59 +08004778 return false;
4779 }
4780 if (size != 4)
4781 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004782 context->handleError(InvalidOperation() << "Type is INT_2_10_10_10_REV or "
4783 "UNSIGNED_INT_2_10_10_10_REV and "
4784 "size is not 4.");
Shao80957d92017-02-20 21:25:59 +08004785 return false;
4786 }
4787 break;
4788
4789 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004790 context->handleError(InvalidEnum() << "Invalid vertex type.");
Shao80957d92017-02-20 21:25:59 +08004791 return false;
4792 }
4793
4794 return true;
4795}
4796
Geoff Lang76e65652017-03-27 14:58:02 -04004797// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
4798// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
4799// specified clear value and the type of a buffer that is being cleared generates an
4800// INVALID_OPERATION error instead of producing undefined results
4801bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
4802 GLint drawbuffer,
4803 const GLenum *validComponentTypes,
4804 size_t validComponentTypeCount)
4805{
4806 const FramebufferAttachment *attachment =
4807 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
4808 if (attachment)
4809 {
4810 GLenum componentType = attachment->getFormat().info->componentType;
4811 const GLenum *end = validComponentTypes + validComponentTypeCount;
4812 if (std::find(validComponentTypes, end, componentType) == end)
4813 {
4814 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004815 InvalidOperation()
4816 << "No defined conversion between clear value and attachment format.");
Geoff Lang76e65652017-03-27 14:58:02 -04004817 return false;
4818 }
4819 }
4820
4821 return true;
4822}
4823
Corentin Wallezb2931602017-04-11 15:58:57 -04004824bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
4825 GLsizei imageSize,
4826 GLsizei dataSize)
4827{
4828 if (!ValidateRobustEntryPoint(context, dataSize))
4829 {
4830 return false;
4831 }
4832
4833 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
4834 if (pixelUnpackBuffer == nullptr)
4835 {
4836 if (dataSize < imageSize)
4837 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004838 context->handleError(InvalidOperation() << "dataSize must be at least " << imageSize);
Corentin Wallezb2931602017-04-11 15:58:57 -04004839 }
4840 }
4841 return true;
4842}
4843
Jamie Madillbe849e42017-05-02 15:49:00 -04004844bool ValidateGetBufferParameterBase(ValidationContext *context,
4845 GLenum target,
4846 GLenum pname,
4847 bool pointerVersion,
4848 GLsizei *numParams)
4849{
4850 if (numParams)
4851 {
4852 *numParams = 0;
4853 }
4854
4855 if (!ValidBufferTarget(context, target))
4856 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004857 context->handleError(InvalidEnum() << "Invalid buffer target.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004858 return false;
4859 }
4860
4861 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
4862 if (!buffer)
4863 {
4864 // A null buffer means that "0" is bound to the requested buffer target
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004865 context->handleError(InvalidOperation() << "No buffer bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004866 return false;
4867 }
4868
4869 const Extensions &extensions = context->getExtensions();
4870
4871 switch (pname)
4872 {
4873 case GL_BUFFER_USAGE:
4874 case GL_BUFFER_SIZE:
4875 break;
4876
4877 case GL_BUFFER_ACCESS_OES:
4878 if (!extensions.mapBuffer)
4879 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004880 context->handleError(InvalidEnum()
4881 << "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004882 return false;
4883 }
4884 break;
4885
4886 case GL_BUFFER_MAPPED:
4887 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
4888 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
4889 !extensions.mapBufferRange)
4890 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004891 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0, "
4892 "GL_OES_mapbuffer or "
4893 "GL_EXT_map_buffer_range.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004894 return false;
4895 }
4896 break;
4897
4898 case GL_BUFFER_MAP_POINTER:
4899 if (!pointerVersion)
4900 {
4901 context->handleError(
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004902 InvalidEnum()
4903 << "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004904 return false;
4905 }
4906 break;
4907
4908 case GL_BUFFER_ACCESS_FLAGS:
4909 case GL_BUFFER_MAP_OFFSET:
4910 case GL_BUFFER_MAP_LENGTH:
4911 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
4912 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004913 context->handleError(InvalidEnum()
4914 << "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004915 return false;
4916 }
4917 break;
4918
4919 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004920 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004921 return false;
4922 }
4923
4924 // All buffer parameter queries return one value.
4925 if (numParams)
4926 {
4927 *numParams = 1;
4928 }
4929
4930 return true;
4931}
4932
4933bool ValidateGetRenderbufferParameterivBase(Context *context,
4934 GLenum target,
4935 GLenum pname,
4936 GLsizei *length)
4937{
4938 if (length)
4939 {
4940 *length = 0;
4941 }
4942
4943 if (target != GL_RENDERBUFFER)
4944 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004945 context->handleError(InvalidEnum() << "Invalid target.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004946 return false;
4947 }
4948
4949 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
4950 if (renderbuffer == nullptr)
4951 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004952 context->handleError(InvalidOperation() << "No renderbuffer bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004953 return false;
4954 }
4955
4956 switch (pname)
4957 {
4958 case GL_RENDERBUFFER_WIDTH:
4959 case GL_RENDERBUFFER_HEIGHT:
4960 case GL_RENDERBUFFER_INTERNAL_FORMAT:
4961 case GL_RENDERBUFFER_RED_SIZE:
4962 case GL_RENDERBUFFER_GREEN_SIZE:
4963 case GL_RENDERBUFFER_BLUE_SIZE:
4964 case GL_RENDERBUFFER_ALPHA_SIZE:
4965 case GL_RENDERBUFFER_DEPTH_SIZE:
4966 case GL_RENDERBUFFER_STENCIL_SIZE:
4967 break;
4968
4969 case GL_RENDERBUFFER_SAMPLES_ANGLE:
4970 if (!context->getExtensions().framebufferMultisample)
4971 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004972 context->handleError(InvalidEnum()
4973 << "GL_ANGLE_framebuffer_multisample is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004974 return false;
4975 }
4976 break;
4977
4978 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05004979 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04004980 return false;
4981 }
4982
4983 if (length)
4984 {
4985 *length = 1;
4986 }
4987 return true;
4988}
4989
4990bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
4991{
4992 if (length)
4993 {
4994 *length = 0;
4995 }
4996
4997 if (GetValidShader(context, shader) == nullptr)
4998 {
4999 return false;
5000 }
5001
5002 switch (pname)
5003 {
5004 case GL_SHADER_TYPE:
5005 case GL_DELETE_STATUS:
5006 case GL_COMPILE_STATUS:
5007 case GL_INFO_LOG_LENGTH:
5008 case GL_SHADER_SOURCE_LENGTH:
5009 break;
5010
5011 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
5012 if (!context->getExtensions().translatedShaderSource)
5013 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005014 context->handleError(InvalidEnum()
5015 << "GL_ANGLE_translated_shader_source is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005016 return false;
5017 }
5018 break;
5019
5020 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005021 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005022 return false;
5023 }
5024
5025 if (length)
5026 {
5027 *length = 1;
5028 }
5029 return true;
5030}
5031
5032bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
5033{
5034 if (length)
5035 {
5036 *length = 0;
5037 }
5038
5039 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5040 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005041 context->handleError(InvalidEnum() << "Invalid texture target");
Jamie Madillbe849e42017-05-02 15:49:00 -04005042 return false;
5043 }
5044
5045 if (context->getTargetTexture(target) == nullptr)
5046 {
5047 // Should only be possible for external textures
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005048 context->handleError(InvalidEnum() << "No texture bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005049 return false;
5050 }
5051
5052 switch (pname)
5053 {
5054 case GL_TEXTURE_MAG_FILTER:
5055 case GL_TEXTURE_MIN_FILTER:
5056 case GL_TEXTURE_WRAP_S:
5057 case GL_TEXTURE_WRAP_T:
5058 break;
5059
5060 case GL_TEXTURE_USAGE_ANGLE:
5061 if (!context->getExtensions().textureUsage)
5062 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005063 context->handleError(InvalidEnum() << "GL_ANGLE_texture_usage is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005064 return false;
5065 }
5066 break;
5067
5068 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5069 if (!context->getExtensions().textureFilterAnisotropic)
5070 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005071 context->handleError(InvalidEnum()
5072 << "GL_EXT_texture_filter_anisotropic is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005073 return false;
5074 }
5075 break;
5076
5077 case GL_TEXTURE_IMMUTABLE_FORMAT:
5078 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
5079 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005080 context->handleError(InvalidEnum() << "GL_EXT_texture_storage is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005081 return false;
5082 }
5083 break;
5084
5085 case GL_TEXTURE_WRAP_R:
5086 case GL_TEXTURE_IMMUTABLE_LEVELS:
5087 case GL_TEXTURE_SWIZZLE_R:
5088 case GL_TEXTURE_SWIZZLE_G:
5089 case GL_TEXTURE_SWIZZLE_B:
5090 case GL_TEXTURE_SWIZZLE_A:
5091 case GL_TEXTURE_BASE_LEVEL:
5092 case GL_TEXTURE_MAX_LEVEL:
5093 case GL_TEXTURE_MIN_LOD:
5094 case GL_TEXTURE_MAX_LOD:
5095 case GL_TEXTURE_COMPARE_MODE:
5096 case GL_TEXTURE_COMPARE_FUNC:
5097 if (context->getClientMajorVersion() < 3)
5098 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005099 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005100 return false;
5101 }
5102 break;
5103
5104 case GL_TEXTURE_SRGB_DECODE_EXT:
5105 if (!context->getExtensions().textureSRGBDecode)
5106 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005107 context->handleError(InvalidEnum() << "GL_EXT_texture_sRGB_decode is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005108 return false;
5109 }
5110 break;
5111
5112 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005113 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005114 return false;
5115 }
5116
5117 if (length)
5118 {
5119 *length = 1;
5120 }
5121 return true;
5122}
5123
5124bool ValidateGetVertexAttribBase(Context *context,
5125 GLuint index,
5126 GLenum pname,
5127 GLsizei *length,
5128 bool pointer,
5129 bool pureIntegerEntryPoint)
5130{
5131 if (length)
5132 {
5133 *length = 0;
5134 }
5135
5136 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
5137 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005138 context->handleError(InvalidOperation() << "Context does not support OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005139 return false;
5140 }
5141
5142 if (index >= context->getCaps().maxVertexAttributes)
5143 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005144 context->handleError(InvalidValue()
5145 << "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005146 return false;
5147 }
5148
5149 if (pointer)
5150 {
5151 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
5152 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005153 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005154 return false;
5155 }
5156 }
5157 else
5158 {
5159 switch (pname)
5160 {
5161 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
5162 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
5163 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
5164 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
5165 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
5166 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
5167 case GL_CURRENT_VERTEX_ATTRIB:
5168 break;
5169
5170 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
5171 static_assert(
5172 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
5173 "ANGLE extension enums not equal to GL enums.");
5174 if (context->getClientMajorVersion() < 3 &&
5175 !context->getExtensions().instancedArrays)
5176 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005177 context->handleError(InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_DIVISOR "
5178 "requires OpenGL ES 3.0 or "
5179 "GL_ANGLE_instanced_arrays.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005180 return false;
5181 }
5182 break;
5183
5184 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
5185 if (context->getClientMajorVersion() < 3)
5186 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005187 context->handleError(
5188 InvalidEnum() << "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005189 return false;
5190 }
5191 break;
5192
5193 case GL_VERTEX_ATTRIB_BINDING:
5194 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
5195 if (context->getClientVersion() < ES_3_1)
5196 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005197 context->handleError(InvalidEnum()
5198 << "Vertex Attrib Bindings require OpenGL ES 3.1.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005199 return false;
5200 }
5201 break;
5202
5203 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005204 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005205 return false;
5206 }
5207 }
5208
5209 if (length)
5210 {
5211 if (pname == GL_CURRENT_VERTEX_ATTRIB)
5212 {
5213 *length = 4;
5214 }
5215 else
5216 {
5217 *length = 1;
5218 }
5219 }
5220
5221 return true;
5222}
5223
Jamie Madill4928b7c2017-06-20 12:57:39 -04005224bool ValidateReadPixelsBase(Context *context,
Jamie Madillbe849e42017-05-02 15:49:00 -04005225 GLint x,
5226 GLint y,
5227 GLsizei width,
5228 GLsizei height,
5229 GLenum format,
5230 GLenum type,
5231 GLsizei bufSize,
5232 GLsizei *length,
5233 GLsizei *columns,
5234 GLsizei *rows,
5235 void *pixels)
5236{
5237 if (length != nullptr)
5238 {
5239 *length = 0;
5240 }
5241 if (rows != nullptr)
5242 {
5243 *rows = 0;
5244 }
5245 if (columns != nullptr)
5246 {
5247 *columns = 0;
5248 }
5249
5250 if (width < 0 || height < 0)
5251 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005252 context->handleError(InvalidValue() << "width and height must be positive");
Jamie Madillbe849e42017-05-02 15:49:00 -04005253 return false;
5254 }
5255
5256 auto readFramebuffer = context->getGLState().getReadFramebuffer();
5257
5258 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
5259 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005260 context->handleError(InvalidFramebufferOperation());
Jamie Madillbe849e42017-05-02 15:49:00 -04005261 return false;
5262 }
5263
5264 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
5265 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005266 context->handleError(InvalidOperation());
Jamie Madillbe849e42017-05-02 15:49:00 -04005267 return false;
5268 }
5269
5270 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
5271 ASSERT(framebuffer);
5272
5273 if (framebuffer->getReadBufferState() == GL_NONE)
5274 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005275 context->handleError(InvalidOperation() << "Read buffer is GL_NONE");
Jamie Madillbe849e42017-05-02 15:49:00 -04005276 return false;
5277 }
5278
5279 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
5280 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
5281 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
5282 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
5283 // situation is an application error that would lead to a crash in ANGLE.
5284 if (readBuffer == nullptr)
5285 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005286 context->handleError(InvalidOperation() << "Missing read attachment");
Jamie Madillbe849e42017-05-02 15:49:00 -04005287 return false;
5288 }
5289
Jamie Madill4928b7c2017-06-20 12:57:39 -04005290 GLenum currentFormat = framebuffer->getImplementationColorReadFormat(context);
5291 GLenum currentType = framebuffer->getImplementationColorReadType(context);
Jamie Madillbe849e42017-05-02 15:49:00 -04005292 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
5293
5294 bool validFormatTypeCombination =
5295 ValidReadPixelsFormatType(context, currentComponentType, format, type);
5296
5297 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
5298 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005299 context->handleError(InvalidOperation());
Jamie Madillbe849e42017-05-02 15:49:00 -04005300 return false;
5301 }
5302
5303 // Check for pixel pack buffer related API errors
5304 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
5305 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
5306 {
5307 // ...the buffer object's data store is currently mapped.
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005308 context->handleError(InvalidOperation() << "Pixel pack buffer is mapped.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005309 return false;
5310 }
5311
5312 // .. the data would be packed to the buffer object such that the memory writes required
5313 // would exceed the data store size.
5314 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
5315 const gl::Extents size(width, height, 1);
5316 const auto &pack = context->getGLState().getPackState();
5317
5318 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
5319 if (endByteOrErr.isError())
5320 {
5321 context->handleError(endByteOrErr.getError());
5322 return false;
5323 }
5324
5325 size_t endByte = endByteOrErr.getResult();
5326 if (bufSize >= 0)
5327 {
5328 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
5329 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005330 context->handleError(InvalidOperation()
5331 << "bufSize must be at least " << endByte << " bytes.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005332 return false;
5333 }
5334 }
5335
5336 if (pixelPackBuffer != nullptr)
5337 {
5338 CheckedNumeric<size_t> checkedEndByte(endByte);
5339 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
5340 checkedEndByte += checkedOffset;
5341
5342 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
5343 {
5344 // Overflow past the end of the buffer
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005345 context->handleError(InvalidOperation()
5346 << "Writes would overflow the pixel pack buffer.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005347 return false;
5348 }
5349 }
5350
5351 if (pixelPackBuffer == nullptr && length != nullptr)
5352 {
5353 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
5354 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005355 context->handleError(InvalidOperation() << "length would overflow GLsizei.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005356 return false;
5357 }
5358
5359 *length = static_cast<GLsizei>(endByte);
5360 }
5361
5362 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
5363 angle::CheckedNumeric<int> clippedExtent(length);
5364 if (start < 0)
5365 {
5366 // "subtract" the area that is less than 0
5367 clippedExtent += start;
5368 }
5369
5370 const int readExtent = start + length;
5371 if (readExtent > bufferSize)
5372 {
5373 // Subtract the region to the right of the read buffer
5374 clippedExtent -= (readExtent - bufferSize);
5375 }
5376
5377 if (!clippedExtent.IsValid())
5378 {
5379 return 0;
5380 }
5381
5382 return std::max(clippedExtent.ValueOrDie(), 0);
5383 };
5384
5385 if (columns != nullptr)
5386 {
5387 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
5388 }
5389
5390 if (rows != nullptr)
5391 {
5392 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
5393 }
5394
5395 return true;
5396}
5397
5398template <typename ParamType>
5399bool ValidateTexParameterBase(Context *context,
5400 GLenum target,
5401 GLenum pname,
5402 GLsizei bufSize,
5403 const ParamType *params)
5404{
5405 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5406 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005407 context->handleError(InvalidEnum() << "Invalid texture target");
Jamie Madillbe849e42017-05-02 15:49:00 -04005408 return false;
5409 }
5410
5411 if (context->getTargetTexture(target) == nullptr)
5412 {
5413 // Should only be possible for external textures
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005414 context->handleError(InvalidEnum() << "No texture bound.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005415 return false;
5416 }
5417
5418 const GLsizei minBufSize = 1;
5419 if (bufSize >= 0 && bufSize < minBufSize)
5420 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005421 context->handleError(InvalidOperation() << "bufSize must be at least " << minBufSize);
Jamie Madillbe849e42017-05-02 15:49:00 -04005422 return false;
5423 }
5424
5425 switch (pname)
5426 {
5427 case GL_TEXTURE_WRAP_R:
5428 case GL_TEXTURE_SWIZZLE_R:
5429 case GL_TEXTURE_SWIZZLE_G:
5430 case GL_TEXTURE_SWIZZLE_B:
5431 case GL_TEXTURE_SWIZZLE_A:
5432 case GL_TEXTURE_BASE_LEVEL:
5433 case GL_TEXTURE_MAX_LEVEL:
5434 case GL_TEXTURE_COMPARE_MODE:
5435 case GL_TEXTURE_COMPARE_FUNC:
5436 case GL_TEXTURE_MIN_LOD:
5437 case GL_TEXTURE_MAX_LOD:
5438 if (context->getClientMajorVersion() < 3)
5439 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005440 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005441 return false;
5442 }
5443 if (target == GL_TEXTURE_EXTERNAL_OES &&
5444 !context->getExtensions().eglImageExternalEssl3)
5445 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005446 context->handleError(InvalidEnum() << "ES3 texture parameters are not "
5447 "available without "
5448 "GL_OES_EGL_image_external_essl3.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005449 return false;
5450 }
5451 break;
5452
5453 default:
5454 break;
5455 }
5456
5457 switch (pname)
5458 {
5459 case GL_TEXTURE_WRAP_S:
5460 case GL_TEXTURE_WRAP_T:
5461 case GL_TEXTURE_WRAP_R:
5462 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5463 {
5464 return false;
5465 }
5466 break;
5467
5468 case GL_TEXTURE_MIN_FILTER:
5469 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5470 {
5471 return false;
5472 }
5473 break;
5474
5475 case GL_TEXTURE_MAG_FILTER:
5476 if (!ValidateTextureMagFilterValue(context, params))
5477 {
5478 return false;
5479 }
5480 break;
5481
5482 case GL_TEXTURE_USAGE_ANGLE:
5483 switch (ConvertToGLenum(params[0]))
5484 {
5485 case GL_NONE:
5486 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
5487 break;
5488
5489 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005490 context->handleError(InvalidEnum() << "Unknown param value.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005491 return false;
5492 }
5493 break;
5494
5495 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5496 if (!context->getExtensions().textureFilterAnisotropic)
5497 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005498 context->handleError(InvalidEnum() << "GL_EXT_texture_anisotropic is not enabled.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005499 return false;
5500 }
5501
5502 // we assume the parameter passed to this validation method is truncated, not rounded
5503 if (params[0] < 1)
5504 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005505 context->handleError(InvalidValue() << "Max anisotropy must be at least 1.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005506 return false;
5507 }
5508 break;
5509
5510 case GL_TEXTURE_MIN_LOD:
5511 case GL_TEXTURE_MAX_LOD:
5512 // any value is permissible
5513 break;
5514
5515 case GL_TEXTURE_COMPARE_MODE:
5516 if (!ValidateTextureCompareModeValue(context, params))
5517 {
5518 return false;
5519 }
5520 break;
5521
5522 case GL_TEXTURE_COMPARE_FUNC:
5523 if (!ValidateTextureCompareFuncValue(context, params))
5524 {
5525 return false;
5526 }
5527 break;
5528
5529 case GL_TEXTURE_SWIZZLE_R:
5530 case GL_TEXTURE_SWIZZLE_G:
5531 case GL_TEXTURE_SWIZZLE_B:
5532 case GL_TEXTURE_SWIZZLE_A:
5533 switch (ConvertToGLenum(params[0]))
5534 {
5535 case GL_RED:
5536 case GL_GREEN:
5537 case GL_BLUE:
5538 case GL_ALPHA:
5539 case GL_ZERO:
5540 case GL_ONE:
5541 break;
5542
5543 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005544 context->handleError(InvalidEnum() << "Unknown param value.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005545 return false;
5546 }
5547 break;
5548
5549 case GL_TEXTURE_BASE_LEVEL:
5550 if (params[0] < 0)
5551 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005552 context->handleError(InvalidValue() << "Base level must be at least 0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005553 return false;
5554 }
5555 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
5556 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005557 context->handleError(InvalidOperation()
5558 << "Base level must be 0 for external textures.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005559 return false;
5560 }
5561 break;
5562
5563 case GL_TEXTURE_MAX_LEVEL:
5564 if (params[0] < 0)
5565 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005566 context->handleError(InvalidValue() << "Max level must be at least 0.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005567 return false;
5568 }
5569 break;
5570
5571 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5572 if (context->getClientVersion() < Version(3, 1))
5573 {
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005574 context->handleError(InvalidEnum() << "pname requires OpenGL ES 3.1.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005575 return false;
5576 }
5577 switch (ConvertToGLenum(params[0]))
5578 {
5579 case GL_DEPTH_COMPONENT:
5580 case GL_STENCIL_INDEX:
5581 break;
5582
5583 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005584 context->handleError(InvalidEnum() << "Unknown param value.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005585 return false;
5586 }
5587 break;
5588
5589 case GL_TEXTURE_SRGB_DECODE_EXT:
5590 if (!ValidateTextureSRGBDecodeValue(context, params))
5591 {
5592 return false;
5593 }
5594 break;
5595
5596 default:
Yuly Novikovc4d18aa2017-03-09 18:45:02 -05005597 context->handleError(InvalidEnum() << "Unknown pname.");
Jamie Madillbe849e42017-05-02 15:49:00 -04005598 return false;
5599 }
5600
5601 return true;
5602}
5603
5604template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *);
5605template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *);
5606
Jamie Madillc29968b2016-01-20 11:17:23 -05005607} // namespace gl