blob: 4e5b8fe57beca8079c97b4ba4b97f823ccf016e0 [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 Wallezfd456442016-12-21 17:57:00 -050054 if (!program->isAttribLocationActive(attributeIndex) || !attrib.enabled)
Jamie Madill1ca74672015-07-21 15:14:11 -040055 {
Corentin Wallezfd456442016-12-21 17:57:00 -050056 continue;
57 }
Jamie Madill1ca74672015-07-21 15:14:11 -040058
Jiawei-Shao2597fb62016-12-09 16:38:02 +080059 const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
Jamie Madill231c7f52017-04-26 13:45:37 -040060 // If we have no buffer, then we either get an error, or there are no more checks to be
61 // done.
Jiawei-Shao2597fb62016-12-09 16:38:02 +080062 gl::Buffer *buffer = binding.buffer.get();
Corentin Wallezfd456442016-12-21 17:57:00 -050063 if (!buffer)
64 {
Geoff Langfeb8c682017-02-13 16:07:35 -050065 if (webglCompatibility || !state.areClientArraysEnabled())
Corentin Wallez327411e2016-12-09 11:09:17 -050066 {
67 // [WebGL 1.0] Section 6.5 Enabled Vertex Attributes and Range Checking
Corentin Wallezfd456442016-12-21 17:57:00 -050068 // If a vertex attribute is enabled as an array via enableVertexAttribArray but
69 // no buffer is bound to that attribute via bindBuffer and vertexAttribPointer,
70 // then calls to drawArrays or drawElements will generate an INVALID_OPERATION
71 // error.
Corentin Wallez327411e2016-12-09 11:09:17 -050072 context->handleError(
73 Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer."));
Corentin Wallezfd456442016-12-21 17:57:00 -050074 return false;
Corentin Wallez327411e2016-12-09 11:09:17 -050075 }
Corentin Wallezfd456442016-12-21 17:57:00 -050076 else if (attrib.pointer == nullptr)
Jamie Madill1ca74672015-07-21 15:14:11 -040077 {
78 // This is an application error that would normally result in a crash,
79 // but we catch it and return an error
Jamie Madill231c7f52017-04-26 13:45:37 -040080 context->handleError(Error(
81 GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
Jamie Madill1ca74672015-07-21 15:14:11 -040082 return false;
83 }
Corentin Wallezfd456442016-12-21 17:57:00 -050084 continue;
85 }
86
87 // If we're drawing zero vertices, we have enough data.
88 if (vertexCount <= 0 || primcount <= 0)
89 {
90 continue;
91 }
92
93 GLint maxVertexElement = 0;
Jiawei-Shao2597fb62016-12-09 16:38:02 +080094 if (binding.divisor == 0)
Corentin Wallezfd456442016-12-21 17:57:00 -050095 {
96 maxVertexElement = maxVertex;
97 }
98 else
99 {
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800100 maxVertexElement = (primcount - 1) / binding.divisor;
Corentin Wallezfd456442016-12-21 17:57:00 -0500101 }
102
103 // We do manual overflow checks here instead of using safe_math.h because it was
104 // a bottleneck. Thanks to some properties of GL we know inequalities that can
105 // help us make the overflow checks faster.
106
107 // The max possible attribSize is 16 for a vector of 4 32 bit values.
108 constexpr uint64_t kMaxAttribSize = 16;
109 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
110 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
111
112 // We know attribStride is given as a GLsizei which is typedefed to int.
113 // We also know an upper bound for attribSize.
114 static_assert(std::is_same<int, GLsizei>::value, "");
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800115 uint64_t attribStride = ComputeVertexAttributeStride(attrib, binding);
Corentin Wallezfd456442016-12-21 17:57:00 -0500116 uint64_t attribSize = ComputeVertexAttributeTypeSize(attrib);
117 ASSERT(attribStride <= kIntMax && attribSize <= kMaxAttribSize);
118
119 // Computing the max offset using uint64_t without attrib.offset is overflow
120 // safe. Note: Last vertex element does not take the full stride!
121 static_assert(kIntMax * kIntMax < kUint64Max - kMaxAttribSize, "");
122 uint64_t attribDataSizeNoOffset = maxVertexElement * attribStride + attribSize;
123
124 // An overflow can happen when adding the offset, check for it.
Jiawei-Shao2597fb62016-12-09 16:38:02 +0800125 uint64_t attribOffset = ComputeVertexAttributeOffset(attrib, binding);
126 if (attribDataSizeNoOffset > kUint64Max - attribOffset)
Corentin Wallezfd456442016-12-21 17:57:00 -0500127 {
128 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
129 return false;
130 }
131 uint64_t attribDataSizeWithOffset = attribDataSizeNoOffset + attribOffset;
132
133 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
134 // We can return INVALID_OPERATION if our vertex attribute does not have
135 // enough backing data.
136 if (attribDataSizeWithOffset > static_cast<uint64_t>(buffer->getSize()))
137 {
Jamie Madill231c7f52017-04-26 13:45:37 -0400138 context->handleError(
139 Error(GL_INVALID_OPERATION, "Vertex buffer is not big enough for the draw call"));
Corentin Wallezfd456442016-12-21 17:57:00 -0500140 return false;
Jamie Madill1ca74672015-07-21 15:14:11 -0400141 }
142 }
143
144 return true;
145}
146
Geoff Langf607c602016-09-21 11:46:48 -0400147bool ValidReadPixelsFormatType(ValidationContext *context,
148 GLenum framebufferComponentType,
149 GLenum format,
150 GLenum type)
151{
152 switch (framebufferComponentType)
153 {
154 case GL_UNSIGNED_NORMALIZED:
155 // TODO(geofflang): Don't accept BGRA here. Some chrome internals appear to try to use
156 // ReadPixels with BGRA even if the extension is not present
157 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE) ||
158 (context->getExtensions().readFormatBGRA && format == GL_BGRA_EXT &&
159 type == GL_UNSIGNED_BYTE);
160
161 case GL_SIGNED_NORMALIZED:
162 return (format == GL_RGBA && type == GL_UNSIGNED_BYTE);
163
164 case GL_INT:
165 return (format == GL_RGBA_INTEGER && type == GL_INT);
166
167 case GL_UNSIGNED_INT:
168 return (format == GL_RGBA_INTEGER && type == GL_UNSIGNED_INT);
169
170 case GL_FLOAT:
171 return (format == GL_RGBA && type == GL_FLOAT);
172
173 default:
174 UNREACHABLE();
175 return false;
176 }
177}
178
Geoff Langc1984ed2016-10-07 12:41:00 -0400179template <typename ParamType>
180bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isExternalTextureTarget)
181{
182 switch (ConvertToGLenum(params[0]))
183 {
184 case GL_CLAMP_TO_EDGE:
185 break;
186
187 case GL_REPEAT:
188 case GL_MIRRORED_REPEAT:
189 if (isExternalTextureTarget)
190 {
191 // OES_EGL_image_external specifies this error.
192 context->handleError(Error(
193 GL_INVALID_ENUM, "external textures only support CLAMP_TO_EDGE wrap mode"));
194 return false;
195 }
196 break;
197
198 default:
199 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
200 return false;
201 }
202
203 return true;
204}
205
206template <typename ParamType>
207bool ValidateTextureMinFilterValue(Context *context,
208 ParamType *params,
209 bool isExternalTextureTarget)
210{
211 switch (ConvertToGLenum(params[0]))
212 {
213 case GL_NEAREST:
214 case GL_LINEAR:
215 break;
216
217 case GL_NEAREST_MIPMAP_NEAREST:
218 case GL_LINEAR_MIPMAP_NEAREST:
219 case GL_NEAREST_MIPMAP_LINEAR:
220 case GL_LINEAR_MIPMAP_LINEAR:
221 if (isExternalTextureTarget)
222 {
223 // OES_EGL_image_external specifies this error.
224 context->handleError(
225 Error(GL_INVALID_ENUM,
226 "external textures only support NEAREST and LINEAR filtering"));
227 return false;
228 }
229 break;
230
231 default:
232 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
233 return false;
234 }
235
236 return true;
237}
238
239template <typename ParamType>
240bool ValidateTextureMagFilterValue(Context *context, ParamType *params)
241{
242 switch (ConvertToGLenum(params[0]))
243 {
244 case GL_NEAREST:
245 case GL_LINEAR:
246 break;
247
248 default:
249 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
250 return false;
251 }
252
253 return true;
254}
255
256template <typename ParamType>
257bool ValidateTextureCompareModeValue(Context *context, ParamType *params)
258{
259 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
260 switch (ConvertToGLenum(params[0]))
261 {
262 case GL_NONE:
263 case GL_COMPARE_REF_TO_TEXTURE:
264 break;
265
266 default:
267 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
268 return false;
269 }
270
271 return true;
272}
273
274template <typename ParamType>
275bool ValidateTextureCompareFuncValue(Context *context, ParamType *params)
276{
277 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
278 switch (ConvertToGLenum(params[0]))
279 {
280 case GL_LEQUAL:
281 case GL_GEQUAL:
282 case GL_LESS:
283 case GL_GREATER:
284 case GL_EQUAL:
285 case GL_NOTEQUAL:
286 case GL_ALWAYS:
287 case GL_NEVER:
288 break;
289
290 default:
291 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
292 return false;
293 }
294
295 return true;
296}
297
298template <typename ParamType>
Geoff Lang81c6b572016-10-19 14:07:52 -0700299bool ValidateTextureSRGBDecodeValue(Context *context, ParamType *params)
300{
301 if (!context->getExtensions().textureSRGBDecode)
302 {
303 context->handleError(Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
304 return false;
305 }
306
307 switch (ConvertToGLenum(params[0]))
308 {
309 case GL_DECODE_EXT:
310 case GL_SKIP_DECODE_EXT:
311 break;
312
313 default:
314 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
315 return false;
316 }
317
318 return true;
319}
320
321template <typename ParamType>
Geoff Langc1984ed2016-10-07 12:41:00 -0400322bool ValidateSamplerParameterBase(Context *context,
323 GLuint sampler,
324 GLenum pname,
325 GLsizei bufSize,
326 ParamType *params)
327{
328 if (context->getClientMajorVersion() < 3)
329 {
330 context->handleError(
331 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
332 return false;
333 }
334
335 if (!context->isSampler(sampler))
336 {
337 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
338 return false;
339 }
340
341 const GLsizei minBufSize = 1;
342 if (bufSize >= 0 && bufSize < minBufSize)
343 {
344 context->handleError(
345 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
346 return false;
347 }
348
349 switch (pname)
350 {
351 case GL_TEXTURE_WRAP_S:
352 case GL_TEXTURE_WRAP_T:
353 case GL_TEXTURE_WRAP_R:
354 if (!ValidateTextureWrapModeValue(context, params, false))
355 {
356 return false;
357 }
358 break;
359
360 case GL_TEXTURE_MIN_FILTER:
361 if (!ValidateTextureMinFilterValue(context, params, false))
362 {
363 return false;
364 }
365 break;
366
367 case GL_TEXTURE_MAG_FILTER:
368 if (!ValidateTextureMagFilterValue(context, params))
369 {
370 return false;
371 }
372 break;
373
374 case GL_TEXTURE_MIN_LOD:
375 case GL_TEXTURE_MAX_LOD:
376 // any value is permissible
377 break;
378
379 case GL_TEXTURE_COMPARE_MODE:
380 if (!ValidateTextureCompareModeValue(context, params))
381 {
382 return false;
383 }
384 break;
385
386 case GL_TEXTURE_COMPARE_FUNC:
387 if (!ValidateTextureCompareFuncValue(context, params))
388 {
389 return false;
390 }
391 break;
392
Geoff Lang81c6b572016-10-19 14:07:52 -0700393 case GL_TEXTURE_SRGB_DECODE_EXT:
394 if (!ValidateTextureSRGBDecodeValue(context, params))
395 {
396 return false;
397 }
398 break;
399
Geoff Langc1984ed2016-10-07 12:41:00 -0400400 default:
401 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
402 return false;
403 }
404
405 return true;
406}
407
408bool ValidateGetSamplerParameterBase(Context *context,
409 GLuint sampler,
410 GLenum pname,
411 GLsizei *length)
412{
413 if (length)
414 {
415 *length = 0;
416 }
417
418 if (context->getClientMajorVersion() < 3)
419 {
420 context->handleError(
421 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
422 return false;
423 }
424
425 if (!context->isSampler(sampler))
426 {
427 context->handleError(Error(GL_INVALID_OPERATION, "Sampler is not valid."));
428 return false;
429 }
430
431 switch (pname)
432 {
433 case GL_TEXTURE_WRAP_S:
434 case GL_TEXTURE_WRAP_T:
435 case GL_TEXTURE_WRAP_R:
436 case GL_TEXTURE_MIN_FILTER:
437 case GL_TEXTURE_MAG_FILTER:
438 case GL_TEXTURE_MIN_LOD:
439 case GL_TEXTURE_MAX_LOD:
440 case GL_TEXTURE_COMPARE_MODE:
441 case GL_TEXTURE_COMPARE_FUNC:
442 break;
443
Geoff Lang81c6b572016-10-19 14:07:52 -0700444 case GL_TEXTURE_SRGB_DECODE_EXT:
445 if (!context->getExtensions().textureSRGBDecode)
446 {
447 context->handleError(
448 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
449 return false;
450 }
451 break;
452
Geoff Langc1984ed2016-10-07 12:41:00 -0400453 default:
454 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
455 return false;
456 }
457
458 if (length)
459 {
460 *length = 1;
461 }
462 return true;
463}
464
Geoff Lang6899b872016-10-14 11:30:13 -0400465bool ValidateGetActiveUniformBlockivBase(Context *context,
466 GLuint program,
467 GLuint uniformBlockIndex,
468 GLenum pname,
469 GLsizei *length)
470{
471 if (length)
472 {
473 *length = 0;
474 }
475
476 if (context->getClientMajorVersion() < 3)
477 {
478 context->handleError(
479 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
480 return false;
481 }
482
483 Program *programObject = GetValidProgram(context, program);
484 if (!programObject)
485 {
486 return false;
487 }
488
489 if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
490 {
491 context->handleError(
492 Error(GL_INVALID_VALUE, "uniformBlockIndex exceeds active uniform block count."));
493 return false;
494 }
495
496 switch (pname)
497 {
498 case GL_UNIFORM_BLOCK_BINDING:
499 case GL_UNIFORM_BLOCK_DATA_SIZE:
500 case GL_UNIFORM_BLOCK_NAME_LENGTH:
501 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
502 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
503 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
504 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
505 break;
506
507 default:
508 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
509 return false;
510 }
511
512 if (length)
513 {
514 if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
515 {
516 const UniformBlock &uniformBlock =
517 programObject->getUniformBlockByIndex(uniformBlockIndex);
518 *length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
519 }
520 else
521 {
522 *length = 1;
523 }
524 }
525
526 return true;
527}
528
Geoff Lang0a9661f2016-10-20 10:59:20 -0700529bool ValidateGetInternalFormativBase(Context *context,
530 GLenum target,
531 GLenum internalformat,
532 GLenum pname,
533 GLsizei bufSize,
534 GLsizei *numParams)
535{
536 if (numParams)
537 {
538 *numParams = 0;
539 }
540
541 if (context->getClientMajorVersion() < 3)
542 {
543 context->handleError(
544 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
545 return false;
546 }
547
548 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
549 if (!formatCaps.renderable)
550 {
551 context->handleError(Error(GL_INVALID_ENUM, "Internal format is not renderable."));
552 return false;
553 }
554
555 switch (target)
556 {
557 case GL_RENDERBUFFER:
558 break;
559
JiangYizhoubddc46b2016-12-09 09:50:51 +0800560 case GL_TEXTURE_2D_MULTISAMPLE:
561 if (context->getClientVersion() < ES_3_1)
562 {
563 context->handleError(
564 Error(GL_INVALID_OPERATION, "Texture target requires at least OpenGL ES 3.1."));
565 return false;
566 }
567 break;
568
Geoff Lang0a9661f2016-10-20 10:59:20 -0700569 default:
570 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
571 return false;
572 }
573
574 if (bufSize < 0)
575 {
576 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
577 return false;
578 }
579
580 GLsizei maxWriteParams = 0;
581 switch (pname)
582 {
583 case GL_NUM_SAMPLE_COUNTS:
584 maxWriteParams = 1;
585 break;
586
587 case GL_SAMPLES:
588 maxWriteParams = static_cast<GLsizei>(formatCaps.sampleCounts.size());
589 break;
590
591 default:
592 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
593 return false;
594 }
595
596 if (numParams)
597 {
598 // glGetInternalFormativ will not overflow bufSize
599 *numParams = std::min(bufSize, maxWriteParams);
600 }
601
602 return true;
603}
604
Jamie Madillc1d770e2017-04-13 17:31:24 -0400605bool ValidateUniformCommonBase(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500606 gl::Program *program,
607 GLint location,
608 GLsizei count,
609 const LinkedUniform **uniformOut)
610{
611 // TODO(Jiajia): Add image uniform check in future.
612 if (count < 0)
613 {
614 context->handleError(Error(GL_INVALID_VALUE));
615 return false;
616 }
617
618 if (!program || !program->isLinked())
619 {
620 context->handleError(Error(GL_INVALID_OPERATION));
621 return false;
622 }
623
624 if (location == -1)
625 {
626 // Silently ignore the uniform command
627 return false;
628 }
629
630 const auto &uniformLocations = program->getUniformLocations();
Jamie Madillbe849e42017-05-02 15:49:00 -0400631 size_t castedLocation = static_cast<size_t>(location);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500632 if (castedLocation >= uniformLocations.size())
633 {
634 context->handleError(Error(GL_INVALID_OPERATION, "Invalid uniform location"));
635 return false;
636 }
637
638 const auto &uniformLocation = uniformLocations[castedLocation];
639 if (uniformLocation.ignored)
640 {
641 // Silently ignore the uniform command
642 return false;
643 }
644
645 if (!uniformLocation.used)
646 {
647 context->handleError(Error(GL_INVALID_OPERATION));
648 return false;
649 }
650
651 const auto &uniform = program->getUniformByIndex(uniformLocation.index);
652
653 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
654 if (!uniform.isArray() && count > 1)
655 {
656 context->handleError(Error(GL_INVALID_OPERATION));
657 return false;
658 }
659
660 *uniformOut = &uniform;
661 return true;
662}
663
Frank Henigman999b0fd2017-02-02 21:45:55 -0500664bool ValidateUniform1ivValue(ValidationContext *context,
Frank Henigmana98a6472017-02-02 21:38:32 -0500665 GLenum uniformType,
666 GLsizei count,
667 const GLint *value)
668{
669 // Value type is GL_INT, because we only get here from glUniform1i{v}.
670 // It is compatible with INT or BOOL.
671 // Do these cheap tests first, for a little extra speed.
672 if (GL_INT == uniformType || GL_BOOL == uniformType)
673 {
674 return true;
675 }
676
677 if (IsSamplerType(uniformType))
678 {
Frank Henigman999b0fd2017-02-02 21:45:55 -0500679 // Check that the values are in range.
680 const GLint max = context->getCaps().maxCombinedTextureImageUnits;
681 for (GLsizei i = 0; i < count; ++i)
682 {
683 if (value[i] < 0 || value[i] >= max)
684 {
685 context->handleError(Error(GL_INVALID_VALUE, "sampler uniform value out of range"));
686 return false;
687 }
688 }
Frank Henigmana98a6472017-02-02 21:38:32 -0500689 return true;
690 }
691
692 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
693 return false;
694}
695
Jamie Madillc1d770e2017-04-13 17:31:24 -0400696bool ValidateUniformValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500697{
698 // Check that the value type is compatible with uniform type.
Frank Henigmana98a6472017-02-02 21:38:32 -0500699 // Do the cheaper test first, for a little extra speed.
700 if (valueType == uniformType || VariableBoolVectorType(valueType) == uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500701 {
702 return true;
703 }
704
705 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
706 return false;
707}
708
Jamie Madillc1d770e2017-04-13 17:31:24 -0400709bool ValidateUniformMatrixValue(ValidationContext *context, GLenum valueType, GLenum uniformType)
Frank Henigmanf5f74ae2017-02-02 21:14:23 -0500710{
711 // Check that the value type is compatible with uniform type.
712 if (valueType == uniformType)
713 {
714 return true;
715 }
716
717 context->handleError(Error(GL_INVALID_OPERATION, "wrong type of value for uniform"));
718 return false;
719}
720
Geoff Lange0cff192017-05-30 13:04:56 -0400721bool ValidateFragmentShaderColorBufferTypeMatch(ValidationContext *context)
722{
723 const Program *program = context->getGLState().getProgram();
724 const Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer();
725
726 const auto &programOutputTypes = program->getOutputVariableTypes();
727 for (size_t drawBufferIdx = 0; drawBufferIdx < programOutputTypes.size(); drawBufferIdx++)
728 {
729 GLenum outputType = programOutputTypes[drawBufferIdx];
730 GLenum inputType = framebuffer->getDrawbufferWriteType(drawBufferIdx);
731 if (outputType != GL_NONE && inputType != GL_NONE && inputType != outputType)
732 {
733 context->handleError(Error(GL_INVALID_OPERATION,
734 "Fragment shader output type does not match the bound "
735 "framebuffer attachment type."));
736 return false;
737 }
738 }
739
740 return true;
741}
742
Geoff Langf41a7152016-09-19 15:11:17 -0400743} // anonymous namespace
744
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500745bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400746{
Jamie Madilld7460c72014-01-21 16:38:14 -0500747 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400748 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800749 case GL_TEXTURE_2D:
750 case GL_TEXTURE_CUBE_MAP:
751 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400752
He Yunchaoced53ae2016-11-29 15:00:51 +0800753 case GL_TEXTURE_3D:
754 case GL_TEXTURE_2D_ARRAY:
755 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500756
He Yunchaoced53ae2016-11-29 15:00:51 +0800757 case GL_TEXTURE_2D_MULTISAMPLE:
He Yunchaoced53ae2016-11-29 15:00:51 +0800758 return (context->getClientVersion() >= Version(3, 1));
Geoff Lang3b573612016-10-31 14:08:10 -0400759
He Yunchaoced53ae2016-11-29 15:00:51 +0800760 default:
761 return false;
Jamie Madilld7460c72014-01-21 16:38:14 -0500762 }
Jamie Madill35d15012013-10-07 10:46:37 -0400763}
764
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500765bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
766{
767 switch (target)
768 {
769 case GL_TEXTURE_2D:
770 case GL_TEXTURE_CUBE_MAP:
771 return true;
772
773 default:
774 return false;
775 }
776}
777
778bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
779{
780 switch (target)
781 {
782 case GL_TEXTURE_3D:
783 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300784 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500785
786 default:
787 return false;
788 }
789}
790
Ian Ewellbda75592016-04-18 17:25:54 -0400791// Most texture GL calls are not compatible with external textures, so we have a separate validation
792// function for use in the GL calls that do
793bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
794{
795 return (target == GL_TEXTURE_EXTERNAL_OES) &&
796 (context->getExtensions().eglImageExternal ||
797 context->getExtensions().eglStreamConsumerExternal);
798}
799
Shannon Woods4dfed832014-03-17 20:03:39 -0400800// This function differs from ValidTextureTarget in that the target must be
801// usable as the destination of a 2D operation-- so a cube face is valid, but
802// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400803// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500804bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400805{
806 switch (target)
807 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800808 case GL_TEXTURE_2D:
809 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
810 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
811 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
812 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
813 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
814 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
815 return true;
816 default:
817 return false;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500818 }
819}
820
Jamie Madillbe849e42017-05-02 15:49:00 -0400821bool ValidateDrawElementsInstancedBase(ValidationContext *context,
822 GLenum mode,
823 GLsizei count,
824 GLenum type,
825 const GLvoid *indices,
826 GLsizei primcount)
827{
828 if (primcount < 0)
829 {
830 context->handleError(Error(GL_INVALID_VALUE, "primcount cannot be negative."));
831 return false;
832 }
833
834 if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount))
835 {
836 return false;
837 }
838
839 // No-op zero primitive count
840 return (primcount > 0);
841}
842
843bool ValidateDrawArraysInstancedBase(Context *context,
844 GLenum mode,
845 GLint first,
846 GLsizei count,
847 GLsizei primcount)
848{
849 if (primcount < 0)
850 {
851 context->handleError(Error(GL_INVALID_VALUE, "primcount cannot be negative."));
852 return false;
853 }
854
855 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
856 {
857 return false;
858 }
859
860 // No-op if zero primitive count
861 return (primcount > 0);
862}
863
864bool ValidateDrawInstancedANGLEAndWebGL(ValidationContext *context)
865{
866 // Verify there is at least one active attribute with a divisor of zero
867 const State &state = context->getGLState();
868
869 Program *program = state.getProgram();
870
871 const auto &attribs = state.getVertexArray()->getVertexAttributes();
872 const auto &bindings = state.getVertexArray()->getVertexBindings();
873 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
874 {
875 const VertexAttribute &attrib = attribs[attributeIndex];
876 const VertexBinding &binding = bindings[attrib.bindingIndex];
877 if (program->isAttribLocationActive(attributeIndex) && binding.divisor == 0)
878 {
879 return true;
880 }
881 }
882
883 context->handleError(
884 Error(GL_INVALID_OPERATION, "At least one attribute must have a divisor of zero."));
885 return false;
886}
887
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500888bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
889{
890 switch (target)
891 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800892 case GL_TEXTURE_3D:
893 case GL_TEXTURE_2D_ARRAY:
894 return true;
895 default:
896 return false;
Shannon Woods4dfed832014-03-17 20:03:39 -0400897 }
898}
899
He Yunchao11b038b2016-11-22 21:24:04 +0800900bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target)
901{
902 switch (target)
903 {
904 case GL_TEXTURE_2D:
905 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
906 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
907 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
908 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
909 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
910 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
911 case GL_TEXTURE_3D:
912 case GL_TEXTURE_2D_ARRAY:
913 case GL_TEXTURE_2D_MULTISAMPLE:
914 return true;
915 default:
916 return false;
917 }
918}
919
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500920bool ValidFramebufferTarget(GLenum target)
921{
He Yunchaoced53ae2016-11-29 15:00:51 +0800922 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
923 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
Geoff Langd4475812015-03-18 10:53:05 -0400924 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500925
926 switch (target)
927 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800928 case GL_FRAMEBUFFER:
929 return true;
930 case GL_READ_FRAMEBUFFER:
931 return true;
932 case GL_DRAW_FRAMEBUFFER:
933 return true;
934 default:
935 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500936 }
937}
938
Jamie Madill29639852016-09-02 15:00:09 -0400939bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500940{
941 switch (target)
942 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800943 case GL_ARRAY_BUFFER:
944 case GL_ELEMENT_ARRAY_BUFFER:
945 return true;
Jamie Madill8c96d582014-03-05 15:01:23 -0500946
He Yunchaoced53ae2016-11-29 15:00:51 +0800947 case GL_PIXEL_PACK_BUFFER:
948 case GL_PIXEL_UNPACK_BUFFER:
949 return (context->getExtensions().pixelBufferObject ||
950 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400951
He Yunchaoced53ae2016-11-29 15:00:51 +0800952 case GL_COPY_READ_BUFFER:
953 case GL_COPY_WRITE_BUFFER:
954 case GL_TRANSFORM_FEEDBACK_BUFFER:
955 case GL_UNIFORM_BUFFER:
956 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500957
He Yunchaoced53ae2016-11-29 15:00:51 +0800958 case GL_ATOMIC_COUNTER_BUFFER:
959 case GL_SHADER_STORAGE_BUFFER:
960 case GL_DRAW_INDIRECT_BUFFER:
961 case GL_DISPATCH_INDIRECT_BUFFER:
He Yunchaoced53ae2016-11-29 15:00:51 +0800962 return context->getClientVersion() >= Version(3, 1);
Geoff Lang3b573612016-10-31 14:08:10 -0400963
He Yunchaoced53ae2016-11-29 15:00:51 +0800964 default:
965 return false;
Jamie Madill8c96d582014-03-05 15:01:23 -0500966 }
967}
968
Jamie Madillc29968b2016-01-20 11:17:23 -0500969bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400970{
Jamie Madillc29968b2016-01-20 11:17:23 -0500971 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400972 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400973 switch (target)
974 {
Jamie Madillc29968b2016-01-20 11:17:23 -0500975 case GL_TEXTURE_2D:
976 maxDimension = caps.max2DTextureSize;
977 break;
He Yunchaoced53ae2016-11-29 15:00:51 +0800978 case GL_TEXTURE_CUBE_MAP:
979 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
980 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
981 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
982 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
983 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
984 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
985 maxDimension = caps.maxCubeMapTextureSize;
986 break;
987 case GL_TEXTURE_3D:
988 maxDimension = caps.max3DTextureSize;
989 break;
990 case GL_TEXTURE_2D_ARRAY:
991 maxDimension = caps.max2DTextureSize;
992 break;
He Yunchao11b038b2016-11-22 21:24:04 +0800993 case GL_TEXTURE_2D_MULTISAMPLE:
994 maxDimension = caps.max2DTextureSize;
995 break;
He Yunchaoced53ae2016-11-29 15:00:51 +0800996 default:
997 UNREACHABLE();
Geoff Langce635692013-09-24 13:56:32 -0400998 }
999
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001000 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -04001001}
1002
Geoff Langcc507aa2016-12-12 10:09:52 -05001003bool ValidImageSizeParameters(const ValidationContext *context,
Austin Kinross08528e12015-10-07 16:24:40 -07001004 GLenum target,
1005 GLint level,
1006 GLsizei width,
1007 GLsizei height,
1008 GLsizei depth,
1009 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -04001010{
1011 if (level < 0 || width < 0 || height < 0 || depth < 0)
1012 {
1013 return false;
1014 }
1015
Austin Kinross08528e12015-10-07 16:24:40 -07001016 // TexSubImage parameters can be NPOT without textureNPOT extension,
1017 // as long as the destination texture is POT.
Geoff Langcc507aa2016-12-12 10:09:52 -05001018 bool hasNPOTSupport =
Geoff Lang5f319a42017-01-09 16:49:19 -05001019 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
Geoff Langcc507aa2016-12-12 10:09:52 -05001020 if (!isSubImage && !hasNPOTSupport &&
Jamie Madill4fd75c12014-06-23 10:53:54 -04001021 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -04001022 {
1023 return false;
1024 }
1025
1026 if (!ValidMipLevel(context, target, level))
1027 {
1028 return false;
1029 }
1030
1031 return true;
1032}
1033
Geoff Lang0d8b7242015-09-09 14:56:53 -04001034bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
1035{
1036 // List of compressed format that require that the texture size is smaller than or a multiple of
1037 // the compressed block size.
1038 switch (internalFormat)
1039 {
1040 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1041 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1042 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1043 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -08001044 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08001045 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1046 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1047 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1048 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1049 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
1050 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04001051 return true;
1052
1053 default:
1054 return false;
1055 }
1056}
1057
Geoff Lang966c9402017-04-18 12:38:27 -04001058bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed)
1059{
1060 return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) ||
1061 (size % blockSize == 0);
1062}
1063
Jamie Madillc29968b2016-01-20 11:17:23 -05001064bool ValidCompressedImageSize(const ValidationContext *context,
1065 GLenum internalFormat,
Geoff Lang966c9402017-04-18 12:38:27 -04001066 GLint level,
Jamie Madillc29968b2016-01-20 11:17:23 -05001067 GLsizei width,
1068 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04001069{
Geoff Langca271392017-04-05 12:30:00 -04001070 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04001071 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04001072 {
1073 return false;
1074 }
1075
Geoff Lang966c9402017-04-18 12:38:27 -04001076 if (width < 0 || height < 0)
1077 {
1078 return false;
1079 }
1080
1081 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1082 {
1083 // The ANGLE extensions allow specifying compressed textures with sizes smaller than the
1084 // block size for level 0 but WebGL disallows this.
1085 bool smallerThanBlockSizeAllowed =
1086 level > 0 || !context->getExtensions().webglCompatibility;
1087
1088 if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth,
1089 smallerThanBlockSizeAllowed) ||
1090 !ValidCompressedDimension(height, formatInfo.compressedBlockHeight,
1091 smallerThanBlockSizeAllowed))
1092 {
1093 return false;
1094 }
1095 }
1096
1097 return true;
1098}
1099
1100bool ValidCompressedSubImageSize(const ValidationContext *context,
1101 GLenum internalFormat,
1102 GLint xoffset,
1103 GLint yoffset,
1104 GLsizei width,
1105 GLsizei height,
1106 size_t textureWidth,
1107 size_t textureHeight)
1108{
1109 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1110 if (!formatInfo.compressed)
1111 {
1112 return false;
1113 }
1114
Geoff Lang44ff5a72017-02-03 15:15:43 -05001115 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04001116 {
1117 return false;
1118 }
1119
Geoff Lang0d8b7242015-09-09 14:56:53 -04001120 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1121 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05001122 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
Geoff Lang966c9402017-04-18 12:38:27 -04001123 yoffset % formatInfo.compressedBlockHeight != 0)
1124 {
1125 return false;
1126 }
1127
1128 // Allowed to either have data that is a multiple of block size or is smaller than the block
1129 // size but fills the entire mip
1130 bool fillsEntireMip = xoffset == 0 && yoffset == 0 &&
1131 static_cast<size_t>(width) == textureWidth &&
1132 static_cast<size_t>(height) == textureHeight;
1133 bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
1134 (height % formatInfo.compressedBlockHeight) == 0;
1135 if (!sizeMultipleOfBlockSize && !fillsEntireMip)
Geoff Lang0d8b7242015-09-09 14:56:53 -04001136 {
1137 return false;
1138 }
1139 }
1140
Geoff Langd4f180b2013-09-24 13:57:44 -04001141 return true;
1142}
1143
Geoff Langff5b2d52016-09-07 11:32:23 -04001144bool ValidImageDataSize(ValidationContext *context,
1145 GLenum textureTarget,
1146 GLsizei width,
1147 GLsizei height,
1148 GLsizei depth,
1149 GLenum internalFormat,
1150 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001151 const void *pixels,
Geoff Langff5b2d52016-09-07 11:32:23 -04001152 GLsizei imageSize)
1153{
1154 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
1155 if (pixelUnpackBuffer == nullptr && imageSize < 0)
1156 {
1157 // Checks are not required
1158 return true;
1159 }
1160
1161 // ...the data would be unpacked from the buffer object such that the memory reads required
1162 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -04001163 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
Geoff Langff5b2d52016-09-07 11:32:23 -04001164 const gl::Extents size(width, height, depth);
1165 const auto &unpack = context->getGLState().getUnpackState();
1166
1167 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
1168 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
1169 if (endByteOrErr.isError())
1170 {
1171 context->handleError(endByteOrErr.getError());
1172 return false;
1173 }
1174
1175 GLuint endByte = endByteOrErr.getResult();
1176
1177 if (pixelUnpackBuffer)
1178 {
1179 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
1180 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
1181 checkedEndByte += checkedOffset;
1182
1183 if (!checkedEndByte.IsValid() ||
1184 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
1185 {
1186 // Overflow past the end of the buffer
1187 context->handleError(Error(GL_INVALID_OPERATION));
1188 return false;
1189 }
1190 }
1191 else
1192 {
1193 ASSERT(imageSize >= 0);
1194 if (pixels == nullptr && imageSize != 0)
1195 {
1196 context->handleError(
1197 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001198 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04001199 }
1200
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001201 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04001202 {
1203 context->handleError(
1204 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
1205 return false;
1206 }
1207 }
1208
1209 return true;
1210}
1211
Geoff Lang37dde692014-01-31 16:34:54 -05001212bool ValidQueryType(const Context *context, GLenum queryType)
1213{
He Yunchaoced53ae2016-11-29 15:00:51 +08001214 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
1215 "GL extension enums not equal.");
1216 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1217 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05001218
1219 switch (queryType)
1220 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001221 case GL_ANY_SAMPLES_PASSED:
1222 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
1223 return true;
1224 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1225 return (context->getClientMajorVersion() >= 3);
1226 case GL_TIME_ELAPSED_EXT:
1227 return context->getExtensions().disjointTimerQuery;
1228 case GL_COMMANDS_COMPLETED_CHROMIUM:
1229 return context->getExtensions().syncQuery;
1230 default:
1231 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05001232 }
1233}
1234
Geoff Lang2d62ab72017-03-23 16:54:40 -04001235bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
1236 GLenum type,
1237 GLboolean normalized,
1238 GLsizei stride,
Jamie Madill876429b2017-04-20 15:46:24 -04001239 const void *ptr,
Geoff Lang2d62ab72017-03-23 16:54:40 -04001240 bool pureInteger)
1241{
1242 ASSERT(context->getExtensions().webglCompatibility);
1243
1244 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
1245 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
1246 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
1247 // parameter exceeds 255.
1248 constexpr GLsizei kMaxWebGLStride = 255;
1249 if (stride > kMaxWebGLStride)
1250 {
1251 context->handleError(
1252 Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
1253 return false;
1254 }
1255
1256 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
1257 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
1258 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
1259 // or an INVALID_OPERATION error is generated.
1260 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
1261 size_t typeSize = GetVertexFormatTypeSize(internalType);
1262
1263 ASSERT(isPow2(typeSize) && typeSize > 0);
1264 size_t sizeMask = (typeSize - 1);
1265 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
1266 {
1267 context->handleError(
1268 Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
1269 return false;
1270 }
1271
1272 if ((stride & sizeMask) != 0)
1273 {
1274 context->handleError(
1275 Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
1276 return false;
1277 }
1278
1279 return true;
1280}
1281
Jamie Madillef300b12016-10-07 15:12:09 -04001282Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05001283{
He Yunchaoced53ae2016-11-29 15:00:51 +08001284 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
1285 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
1286 // or program object and INVALID_OPERATION if the provided name identifies an object
1287 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05001288
Dian Xiang769769a2015-09-09 15:20:08 -07001289 Program *validProgram = context->getProgram(id);
1290
1291 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05001292 {
Dian Xiang769769a2015-09-09 15:20:08 -07001293 if (context->getShader(id))
1294 {
Jamie Madill437fa652016-05-03 15:13:24 -04001295 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07001296 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
1297 }
1298 else
1299 {
Jamie Madill437fa652016-05-03 15:13:24 -04001300 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -07001301 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001302 }
Dian Xiang769769a2015-09-09 15:20:08 -07001303
1304 return validProgram;
1305}
1306
Jamie Madillef300b12016-10-07 15:12:09 -04001307Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07001308{
1309 // See ValidProgram for spec details.
1310
1311 Shader *validShader = context->getShader(id);
1312
1313 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05001314 {
Dian Xiang769769a2015-09-09 15:20:08 -07001315 if (context->getProgram(id))
1316 {
Jamie Madill437fa652016-05-03 15:13:24 -04001317 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07001318 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
1319 }
1320 else
1321 {
Jamie Madill437fa652016-05-03 15:13:24 -04001322 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -07001323 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001324 }
Dian Xiang769769a2015-09-09 15:20:08 -07001325
1326 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05001327}
1328
Geoff Langb1196682014-07-23 13:47:29 -04001329bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04001330{
1331 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
1332 {
1333 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
1334
Geoff Langaae65a42014-05-26 12:43:44 -04001335 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04001336 {
Jamie Madill437fa652016-05-03 15:13:24 -04001337 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001338 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001339 }
1340 }
1341 else
1342 {
1343 switch (attachment)
1344 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001345 case GL_DEPTH_ATTACHMENT:
1346 case GL_STENCIL_ATTACHMENT:
1347 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001348
He Yunchaoced53ae2016-11-29 15:00:51 +08001349 case GL_DEPTH_STENCIL_ATTACHMENT:
1350 if (!context->getExtensions().webglCompatibility &&
1351 context->getClientMajorVersion() < 3)
1352 {
1353 context->handleError(Error(GL_INVALID_ENUM));
1354 return false;
1355 }
1356 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001357
He Yunchaoced53ae2016-11-29 15:00:51 +08001358 default:
1359 context->handleError(Error(GL_INVALID_ENUM));
1360 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001361 }
1362 }
1363
1364 return true;
1365}
1366
Jamie Madille8fb6402017-02-14 17:56:40 -05001367bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08001368 GLenum target,
1369 GLsizei samples,
1370 GLenum internalformat,
1371 GLsizei width,
1372 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001373{
1374 switch (target)
1375 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001376 case GL_RENDERBUFFER:
1377 break;
1378 default:
1379 context->handleError(Error(GL_INVALID_ENUM));
1380 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001381 }
1382
1383 if (width < 0 || height < 0 || samples < 0)
1384 {
Jamie Madill437fa652016-05-03 15:13:24 -04001385 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001386 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001387 }
1388
Jamie Madill4e0e6f82017-02-17 11:06:03 -05001389 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
1390 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
1391
1392 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04001393 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001394 {
Jamie Madill437fa652016-05-03 15:13:24 -04001395 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001396 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001397 }
1398
1399 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
1400 // 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 -08001401 // only sized internal formats.
Geoff Langca271392017-04-05 12:30:00 -04001402 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat);
1403 if (formatInfo.internalFormat == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001404 {
Jamie Madill437fa652016-05-03 15:13:24 -04001405 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001406 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001407 }
1408
Geoff Langaae65a42014-05-26 12:43:44 -04001409 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001410 {
Jamie Madill437fa652016-05-03 15:13:24 -04001411 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001412 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001413 }
1414
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001415 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001416 if (handle == 0)
1417 {
Jamie Madill437fa652016-05-03 15:13:24 -04001418 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001419 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001420 }
1421
1422 return true;
1423}
1424
He Yunchaoced53ae2016-11-29 15:00:51 +08001425bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
1426 GLenum target,
1427 GLenum attachment,
1428 GLenum renderbuffertarget,
1429 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001430{
Shannon Woods1da3cf62014-06-27 15:32:23 -04001431 if (!ValidFramebufferTarget(target))
1432 {
Jamie Madill437fa652016-05-03 15:13:24 -04001433 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001434 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04001435 }
1436
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001437 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001438
Jamie Madill84115c92015-04-23 15:00:07 -04001439 ASSERT(framebuffer);
1440 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001441 {
Jamie Madill437fa652016-05-03 15:13:24 -04001442 context->handleError(
1443 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001444 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001445 }
1446
Jamie Madillb4472272014-07-03 10:38:55 -04001447 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001448 {
Jamie Madillb4472272014-07-03 10:38:55 -04001449 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001450 }
1451
Jamie Madillab9d82c2014-01-21 16:38:14 -05001452 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1453 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1454 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1455 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1456 if (renderbuffer != 0)
1457 {
1458 if (!context->getRenderbuffer(renderbuffer))
1459 {
Jamie Madill437fa652016-05-03 15:13:24 -04001460 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001461 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05001462 }
1463 }
1464
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001465 return true;
1466}
1467
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001468bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001469 GLint srcX0,
1470 GLint srcY0,
1471 GLint srcX1,
1472 GLint srcY1,
1473 GLint dstX0,
1474 GLint dstY0,
1475 GLint dstX1,
1476 GLint dstY1,
1477 GLbitfield mask,
1478 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001479{
1480 switch (filter)
1481 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001482 case GL_NEAREST:
1483 break;
1484 case GL_LINEAR:
1485 break;
1486 default:
1487 context->handleError(Error(GL_INVALID_ENUM));
1488 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001489 }
1490
1491 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1492 {
Jamie Madill437fa652016-05-03 15:13:24 -04001493 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001494 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001495 }
1496
1497 if (mask == 0)
1498 {
1499 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
1500 // buffers are copied.
1501 return false;
1502 }
1503
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001504 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1505 // color buffer, leaving only nearest being unfiltered from above
1506 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1507 {
Jamie Madill437fa652016-05-03 15:13:24 -04001508 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001509 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001510 }
1511
Jamie Madill51f40ec2016-06-15 14:06:00 -04001512 const auto &glState = context->getGLState();
1513 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1514 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001515
1516 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001517 {
Jamie Madill437fa652016-05-03 15:13:24 -04001518 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001519 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001520 }
1521
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001522 if (readFramebuffer->id() == drawFramebuffer->id())
1523 {
1524 context->handleError(Error(GL_INVALID_OPERATION));
1525 return false;
1526 }
1527
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001528 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001529 {
Jamie Madill437fa652016-05-03 15:13:24 -04001530 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001531 return false;
1532 }
1533
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001534 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001535 {
Jamie Madill437fa652016-05-03 15:13:24 -04001536 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001537 return false;
1538 }
1539
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001540 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001541 {
Jamie Madill437fa652016-05-03 15:13:24 -04001542 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001543 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001544 }
1545
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001546 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1547
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001548 if (mask & GL_COLOR_BUFFER_BIT)
1549 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001550 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05001551 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001552
He Yunchao66a41a22016-12-15 16:45:05 +08001553 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001554 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001555 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001556
Geoff Langa15472a2015-08-11 11:48:03 -04001557 for (size_t drawbufferIdx = 0;
1558 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001559 {
Geoff Langa15472a2015-08-11 11:48:03 -04001560 const FramebufferAttachment *attachment =
1561 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1562 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001563 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001564 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001565
Geoff Langb2f3d052013-08-13 12:49:27 -04001566 // The GL ES 3.0.2 spec (pg 193) states that:
1567 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08001568 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
1569 // as well
1570 // 3) If the read buffer is a signed integer format, the draw buffer must be as
1571 // well
Jamie Madill6163c752015-12-07 16:32:59 -05001572 // Changes with EXT_color_buffer_float:
1573 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04001574 GLenum readComponentType = readFormat.info->componentType;
1575 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08001576 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05001577 readComponentType == GL_SIGNED_NORMALIZED);
1578 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1579 drawComponentType == GL_SIGNED_NORMALIZED);
1580
1581 if (extensions.colorBufferFloat)
1582 {
1583 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1584 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1585
1586 if (readFixedOrFloat != drawFixedOrFloat)
1587 {
Jamie Madill437fa652016-05-03 15:13:24 -04001588 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001589 "If the read buffer contains fixed-point or "
1590 "floating-point values, the draw buffer "
1591 "must as well."));
1592 return false;
1593 }
1594 }
1595 else if (readFixedPoint != drawFixedPoint)
1596 {
Jamie Madill437fa652016-05-03 15:13:24 -04001597 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001598 "If the read buffer contains fixed-point "
1599 "values, the draw buffer must as well."));
1600 return false;
1601 }
1602
1603 if (readComponentType == GL_UNSIGNED_INT &&
1604 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001605 {
Jamie Madill437fa652016-05-03 15:13:24 -04001606 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001607 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001608 }
1609
Jamie Madill6163c752015-12-07 16:32:59 -05001610 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001611 {
Jamie Madill437fa652016-05-03 15:13:24 -04001612 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001613 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001614 }
1615
Jamie Madilla3944d42016-07-22 22:13:26 -04001616 if (readColorBuffer->getSamples() > 0 &&
1617 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001618 {
Jamie Madill437fa652016-05-03 15:13:24 -04001619 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001620 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001621 }
Geoff Lange4915782017-04-12 15:19:07 -04001622
1623 if (context->getExtensions().webglCompatibility &&
1624 *readColorBuffer == *attachment)
1625 {
1626 context->handleError(
1627 Error(GL_INVALID_OPERATION,
1628 "Read and write color attachments cannot be the same image."));
1629 return false;
1630 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001631 }
1632 }
1633
Jamie Madilla3944d42016-07-22 22:13:26 -04001634 if ((readFormat.info->componentType == GL_INT ||
1635 readFormat.info->componentType == GL_UNSIGNED_INT) &&
1636 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001637 {
Jamie Madill437fa652016-05-03 15:13:24 -04001638 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001639 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001640 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001641 }
He Yunchao66a41a22016-12-15 16:45:05 +08001642 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1643 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
1644 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
1645 // situation is an application error that would lead to a crash in ANGLE.
1646 else if (drawFramebuffer->hasEnabledDrawBuffer())
1647 {
1648 context->handleError(Error(
1649 GL_INVALID_OPERATION,
1650 "Attempt to read from a missing color attachment of a complete framebuffer."));
1651 return false;
1652 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001653 }
1654
He Yunchaoced53ae2016-11-29 15:00:51 +08001655 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001656 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1657 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001658 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001659 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001660 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001661 const gl::FramebufferAttachment *readBuffer =
1662 readFramebuffer->getAttachment(attachments[i]);
1663 const gl::FramebufferAttachment *drawBuffer =
1664 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001665
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001666 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001667 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001668 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001669 {
Jamie Madill437fa652016-05-03 15:13:24 -04001670 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001671 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001672 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001673
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001674 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001675 {
Jamie Madill437fa652016-05-03 15:13:24 -04001676 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001677 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001678 }
Geoff Lange4915782017-04-12 15:19:07 -04001679
1680 if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer)
1681 {
1682 context->handleError(Error(
1683 GL_INVALID_OPERATION,
1684 "Read and write depth stencil attachments cannot be the same image."));
1685 return false;
1686 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001687 }
He Yunchao66a41a22016-12-15 16:45:05 +08001688 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1689 else if (drawBuffer)
1690 {
1691 context->handleError(Error(GL_INVALID_OPERATION,
1692 "Attempt to read from a missing depth/stencil "
1693 "attachment of a complete framebuffer."));
1694 return false;
1695 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001696 }
1697 }
1698
1699 return true;
1700}
1701
Geoff Lang62fce5b2016-09-30 10:46:35 -04001702bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
1703 GLint x,
1704 GLint y,
1705 GLsizei width,
1706 GLsizei height,
1707 GLenum format,
1708 GLenum type,
1709 GLsizei bufSize,
1710 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001711 GLsizei *columns,
1712 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001713 void *pixels)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001714{
1715 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05001716 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001717 return false;
1718 }
1719
Geoff Lang62fce5b2016-09-30 10:46:35 -04001720 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04001721 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05001722 {
Geoff Langb1196682014-07-23 13:47:29 -04001723 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001724 }
1725
Geoff Lang62fce5b2016-09-30 10:46:35 -04001726 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05001727 {
Geoff Langb1196682014-07-23 13:47:29 -04001728 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001729 }
1730
Jamie Madillc29968b2016-01-20 11:17:23 -05001731 return true;
1732}
1733
1734bool ValidateReadnPixelsEXT(Context *context,
1735 GLint x,
1736 GLint y,
1737 GLsizei width,
1738 GLsizei height,
1739 GLenum format,
1740 GLenum type,
1741 GLsizei bufSize,
Jamie Madill876429b2017-04-20 15:46:24 -04001742 void *pixels)
Jamie Madillc29968b2016-01-20 11:17:23 -05001743{
1744 if (bufSize < 0)
1745 {
Jamie Madill437fa652016-05-03 15:13:24 -04001746 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001747 return false;
1748 }
1749
Geoff Lang62fce5b2016-09-30 10:46:35 -04001750 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04001751 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04001752}
Jamie Madill26e91952014-03-05 15:01:27 -05001753
Geoff Lang62fce5b2016-09-30 10:46:35 -04001754bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
1755 GLint x,
1756 GLint y,
1757 GLsizei width,
1758 GLsizei height,
1759 GLenum format,
1760 GLenum type,
1761 GLsizei bufSize,
1762 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001763 GLsizei *columns,
1764 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001765 void *data)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001766{
1767 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04001768 {
Jamie Madille2e406c2016-06-02 13:04:10 -04001769 return false;
1770 }
1771
Geoff Lange93daba2017-03-30 13:54:40 -04001772 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
1773 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04001774 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001775 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001776 }
1777
Geoff Lang62fce5b2016-09-30 10:46:35 -04001778 if (!ValidateRobustBufferSize(context, bufSize, *length))
1779 {
1780 return false;
1781 }
1782
1783 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05001784}
1785
Olli Etuaho41997e72016-03-10 13:38:39 +02001786bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001787{
1788 if (!context->getExtensions().occlusionQueryBoolean &&
1789 !context->getExtensions().disjointTimerQuery)
1790 {
Jamie Madill437fa652016-05-03 15:13:24 -04001791 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001792 return false;
1793 }
1794
Olli Etuaho41997e72016-03-10 13:38:39 +02001795 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001796}
1797
Olli Etuaho41997e72016-03-10 13:38:39 +02001798bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001799{
1800 if (!context->getExtensions().occlusionQueryBoolean &&
1801 !context->getExtensions().disjointTimerQuery)
1802 {
Jamie Madill437fa652016-05-03 15:13:24 -04001803 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001804 return false;
1805 }
1806
Olli Etuaho41997e72016-03-10 13:38:39 +02001807 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001808}
1809
1810bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001811{
1812 if (!ValidQueryType(context, target))
1813 {
Jamie Madill437fa652016-05-03 15:13:24 -04001814 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001815 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001816 }
1817
1818 if (id == 0)
1819 {
Jamie Madill437fa652016-05-03 15:13:24 -04001820 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001821 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001822 }
1823
1824 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1825 // of zero, if the active query object name for <target> is non-zero (for the
1826 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1827 // the active query for either target is non-zero), if <id> is the name of an
1828 // existing query object whose type does not match <target>, or if <id> is the
1829 // active query object name for any query type, the error INVALID_OPERATION is
1830 // generated.
1831
1832 // Ensure no other queries are active
1833 // NOTE: If other queries than occlusion are supported, we will need to check
1834 // separately that:
1835 // a) The query ID passed is not the current active query for any target/type
1836 // b) There are no active queries for the requested target (and in the case
1837 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1838 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001839
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001840 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001841 {
Jamie Madill437fa652016-05-03 15:13:24 -04001842 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001843 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001844 }
1845
1846 Query *queryObject = context->getQuery(id, true, target);
1847
1848 // check that name was obtained with glGenQueries
1849 if (!queryObject)
1850 {
Jamie Madill437fa652016-05-03 15:13:24 -04001851 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001852 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001853 }
1854
1855 // check for type mismatch
1856 if (queryObject->getType() != target)
1857 {
Jamie Madill437fa652016-05-03 15:13:24 -04001858 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001859 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001860 }
1861
1862 return true;
1863}
1864
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001865bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1866{
1867 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001868 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001869 {
Jamie Madill437fa652016-05-03 15:13:24 -04001870 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001871 return false;
1872 }
1873
1874 return ValidateBeginQueryBase(context, target, id);
1875}
1876
1877bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001878{
1879 if (!ValidQueryType(context, target))
1880 {
Jamie Madill437fa652016-05-03 15:13:24 -04001881 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001882 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001883 }
1884
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001885 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001886
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001887 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001888 {
Jamie Madill437fa652016-05-03 15:13:24 -04001889 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001890 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001891 }
1892
Jamie Madill45c785d2014-05-13 14:09:34 -04001893 return true;
1894}
1895
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001896bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1897{
1898 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001899 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001900 {
Jamie Madill437fa652016-05-03 15:13:24 -04001901 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001902 return false;
1903 }
1904
1905 return ValidateEndQueryBase(context, target);
1906}
1907
1908bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1909{
1910 if (!context->getExtensions().disjointTimerQuery)
1911 {
Jamie Madill437fa652016-05-03 15:13:24 -04001912 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001913 return false;
1914 }
1915
1916 if (target != GL_TIMESTAMP_EXT)
1917 {
Jamie Madill437fa652016-05-03 15:13:24 -04001918 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001919 return false;
1920 }
1921
1922 Query *queryObject = context->getQuery(id, true, target);
1923 if (queryObject == nullptr)
1924 {
Jamie Madill437fa652016-05-03 15:13:24 -04001925 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001926 return false;
1927 }
1928
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001929 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001930 {
Jamie Madill437fa652016-05-03 15:13:24 -04001931 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001932 return false;
1933 }
1934
1935 return true;
1936}
1937
Geoff Lang2186c382016-10-14 10:54:54 -04001938bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001939{
Geoff Lang2186c382016-10-14 10:54:54 -04001940 if (numParams)
1941 {
1942 *numParams = 0;
1943 }
1944
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001945 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1946 {
Jamie Madill437fa652016-05-03 15:13:24 -04001947 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001948 return false;
1949 }
1950
1951 switch (pname)
1952 {
1953 case GL_CURRENT_QUERY_EXT:
1954 if (target == GL_TIMESTAMP_EXT)
1955 {
Jamie Madill437fa652016-05-03 15:13:24 -04001956 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001957 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1958 return false;
1959 }
1960 break;
1961 case GL_QUERY_COUNTER_BITS_EXT:
1962 if (!context->getExtensions().disjointTimerQuery ||
1963 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1964 {
Jamie Madill437fa652016-05-03 15:13:24 -04001965 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001966 return false;
1967 }
1968 break;
1969 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001970 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001971 return false;
1972 }
1973
Geoff Lang2186c382016-10-14 10:54:54 -04001974 if (numParams)
1975 {
1976 // All queries return only one value
1977 *numParams = 1;
1978 }
1979
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001980 return true;
1981}
1982
1983bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
1984{
1985 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001986 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001987 {
Jamie Madill437fa652016-05-03 15:13:24 -04001988 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001989 return false;
1990 }
1991
Geoff Lang2186c382016-10-14 10:54:54 -04001992 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001993}
1994
Geoff Lang2186c382016-10-14 10:54:54 -04001995bool ValidateGetQueryivRobustANGLE(Context *context,
1996 GLenum target,
1997 GLenum pname,
1998 GLsizei bufSize,
1999 GLsizei *length,
2000 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002001{
Geoff Lang2186c382016-10-14 10:54:54 -04002002 if (!ValidateRobustEntryPoint(context, bufSize))
2003 {
2004 return false;
2005 }
2006
2007 if (!ValidateGetQueryivBase(context, target, pname, length))
2008 {
2009 return false;
2010 }
2011
2012 if (!ValidateRobustBufferSize(context, bufSize, *length))
2013 {
2014 return false;
2015 }
2016
2017 return true;
2018}
2019
2020bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
2021{
2022 if (numParams)
2023 {
2024 *numParams = 0;
2025 }
2026
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002027 Query *queryObject = context->getQuery(id, false, GL_NONE);
2028
2029 if (!queryObject)
2030 {
Jamie Madill437fa652016-05-03 15:13:24 -04002031 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002032 return false;
2033 }
2034
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002035 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002036 {
Jamie Madill437fa652016-05-03 15:13:24 -04002037 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002038 return false;
2039 }
2040
2041 switch (pname)
2042 {
2043 case GL_QUERY_RESULT_EXT:
2044 case GL_QUERY_RESULT_AVAILABLE_EXT:
2045 break;
2046
2047 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002048 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002049 return false;
2050 }
2051
Geoff Lang2186c382016-10-14 10:54:54 -04002052 if (numParams)
2053 {
2054 *numParams = 1;
2055 }
2056
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002057 return true;
2058}
2059
2060bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
2061{
2062 if (!context->getExtensions().disjointTimerQuery)
2063 {
Jamie Madill437fa652016-05-03 15:13:24 -04002064 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002065 return false;
2066 }
Geoff Lang2186c382016-10-14 10:54:54 -04002067 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2068}
2069
2070bool ValidateGetQueryObjectivRobustANGLE(Context *context,
2071 GLuint id,
2072 GLenum pname,
2073 GLsizei bufSize,
2074 GLsizei *length,
2075 GLint *params)
2076{
2077 if (!context->getExtensions().disjointTimerQuery)
2078 {
2079 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2080 return false;
2081 }
2082
2083 if (!ValidateRobustEntryPoint(context, bufSize))
2084 {
2085 return false;
2086 }
2087
2088 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2089 {
2090 return false;
2091 }
2092
2093 if (!ValidateRobustBufferSize(context, bufSize, *length))
2094 {
2095 return false;
2096 }
2097
2098 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002099}
2100
2101bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
2102{
2103 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002104 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002105 {
Jamie Madill437fa652016-05-03 15:13:24 -04002106 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002107 return false;
2108 }
Geoff Lang2186c382016-10-14 10:54:54 -04002109 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2110}
2111
2112bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
2113 GLuint id,
2114 GLenum pname,
2115 GLsizei bufSize,
2116 GLsizei *length,
2117 GLuint *params)
2118{
2119 if (!context->getExtensions().disjointTimerQuery &&
2120 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
2121 {
2122 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
2123 return false;
2124 }
2125
2126 if (!ValidateRobustEntryPoint(context, bufSize))
2127 {
2128 return false;
2129 }
2130
2131 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2132 {
2133 return false;
2134 }
2135
2136 if (!ValidateRobustBufferSize(context, bufSize, *length))
2137 {
2138 return false;
2139 }
2140
2141 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002142}
2143
2144bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
2145{
2146 if (!context->getExtensions().disjointTimerQuery)
2147 {
Jamie Madill437fa652016-05-03 15:13:24 -04002148 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002149 return false;
2150 }
Geoff Lang2186c382016-10-14 10:54:54 -04002151 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2152}
2153
2154bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
2155 GLuint id,
2156 GLenum pname,
2157 GLsizei bufSize,
2158 GLsizei *length,
2159 GLint64 *params)
2160{
2161 if (!context->getExtensions().disjointTimerQuery)
2162 {
2163 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2164 return false;
2165 }
2166
2167 if (!ValidateRobustEntryPoint(context, bufSize))
2168 {
2169 return false;
2170 }
2171
2172 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2173 {
2174 return false;
2175 }
2176
2177 if (!ValidateRobustBufferSize(context, bufSize, *length))
2178 {
2179 return false;
2180 }
2181
2182 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002183}
2184
2185bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
2186{
2187 if (!context->getExtensions().disjointTimerQuery)
2188 {
Jamie Madill437fa652016-05-03 15:13:24 -04002189 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002190 return false;
2191 }
Geoff Lang2186c382016-10-14 10:54:54 -04002192 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2193}
2194
2195bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
2196 GLuint id,
2197 GLenum pname,
2198 GLsizei bufSize,
2199 GLsizei *length,
2200 GLuint64 *params)
2201{
2202 if (!context->getExtensions().disjointTimerQuery)
2203 {
2204 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2205 return false;
2206 }
2207
2208 if (!ValidateRobustEntryPoint(context, bufSize))
2209 {
2210 return false;
2211 }
2212
2213 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2214 {
2215 return false;
2216 }
2217
2218 if (!ValidateRobustBufferSize(context, bufSize, *length))
2219 {
2220 return false;
2221 }
2222
2223 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002224}
2225
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002226bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002227 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002228 GLuint program,
2229 GLint location,
2230 GLsizei count)
2231{
2232 // Check for ES31 program uniform entry points
2233 if (context->getClientVersion() < Version(3, 1))
2234 {
2235 context->handleError(Error(GL_INVALID_OPERATION));
2236 return false;
2237 }
2238
2239 const LinkedUniform *uniform = nullptr;
2240 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002241 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2242 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002243}
2244
Frank Henigmana98a6472017-02-02 21:38:32 -05002245bool ValidateProgramUniform1iv(gl::Context *context,
2246 GLuint program,
2247 GLint location,
2248 GLsizei count,
2249 const GLint *value)
2250{
2251 // Check for ES31 program uniform entry points
2252 if (context->getClientVersion() < Version(3, 1))
2253 {
2254 context->handleError(Error(GL_INVALID_OPERATION));
2255 return false;
2256 }
2257
2258 const LinkedUniform *uniform = nullptr;
2259 gl::Program *programObject = GetValidProgram(context, program);
2260 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2261 ValidateUniform1ivValue(context, uniform->type, count, value);
2262}
2263
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002264bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002265 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002266 GLuint program,
2267 GLint location,
2268 GLsizei count,
2269 GLboolean transpose)
2270{
2271 // Check for ES31 program uniform entry points
2272 if (context->getClientVersion() < Version(3, 1))
2273 {
2274 context->handleError(Error(GL_INVALID_OPERATION));
2275 return false;
2276 }
2277
2278 const LinkedUniform *uniform = nullptr;
2279 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002280 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2281 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002282}
2283
Jamie Madillc1d770e2017-04-13 17:31:24 -04002284bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002285{
2286 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002287 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002288 {
Jamie Madill437fa652016-05-03 15:13:24 -04002289 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002290 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002291 }
2292
Jamie Madill62d31cb2015-09-11 13:25:51 -04002293 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002294 gl::Program *programObject = context->getGLState().getProgram();
2295 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2296 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002297}
2298
Jamie Madillbe849e42017-05-02 15:49:00 -04002299bool ValidateUniform1iv(ValidationContext *context,
2300 GLint location,
2301 GLsizei count,
2302 const GLint *value)
Frank Henigmana98a6472017-02-02 21:38:32 -05002303{
2304 const LinkedUniform *uniform = nullptr;
2305 gl::Program *programObject = context->getGLState().getProgram();
2306 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2307 ValidateUniform1ivValue(context, uniform->type, count, value);
2308}
2309
Jamie Madillc1d770e2017-04-13 17:31:24 -04002310bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002311 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08002312 GLint location,
2313 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04002314 GLboolean transpose)
2315{
2316 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002317 int rows = VariableRowCount(valueType);
2318 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03002319 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002320 {
Jamie Madill437fa652016-05-03 15:13:24 -04002321 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002322 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002323 }
2324
Martin Radev1be913c2016-07-11 17:59:16 +03002325 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002326 {
Jamie Madill437fa652016-05-03 15:13:24 -04002327 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002328 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002329 }
2330
Jamie Madill62d31cb2015-09-11 13:25:51 -04002331 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002332 gl::Program *programObject = context->getGLState().getProgram();
2333 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2334 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002335}
2336
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002337bool ValidateStateQuery(ValidationContext *context,
2338 GLenum pname,
2339 GLenum *nativeType,
2340 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04002341{
2342 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
2343 {
Jamie Madill437fa652016-05-03 15:13:24 -04002344 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002345 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002346 }
2347
Jamie Madill0af26e12015-03-05 19:54:33 -05002348 const Caps &caps = context->getCaps();
2349
Jamie Madill893ab082014-05-16 16:56:10 -04002350 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
2351 {
2352 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
2353
Jamie Madill0af26e12015-03-05 19:54:33 -05002354 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04002355 {
Jamie Madill437fa652016-05-03 15:13:24 -04002356 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002357 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002358 }
2359 }
2360
2361 switch (pname)
2362 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002363 case GL_TEXTURE_BINDING_2D:
2364 case GL_TEXTURE_BINDING_CUBE_MAP:
2365 case GL_TEXTURE_BINDING_3D:
2366 case GL_TEXTURE_BINDING_2D_ARRAY:
2367 break;
2368 case GL_TEXTURE_BINDING_EXTERNAL_OES:
2369 if (!context->getExtensions().eglStreamConsumerExternal &&
2370 !context->getExtensions().eglImageExternal)
2371 {
2372 context->handleError(Error(GL_INVALID_ENUM,
2373 "Neither NV_EGL_stream_consumer_external nor "
2374 "GL_OES_EGL_image_external extensions enabled"));
2375 return false;
2376 }
2377 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002378
He Yunchaoced53ae2016-11-29 15:00:51 +08002379 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2380 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04002381 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002382 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
2383 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04002384 {
Jamie Madill437fa652016-05-03 15:13:24 -04002385 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002386 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002387 }
2388
Jamie Madill51f40ec2016-06-15 14:06:00 -04002389 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
2390 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03002391
2392 if (framebuffer->getReadBufferState() == GL_NONE)
2393 {
2394 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2395 return false;
2396 }
2397
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002398 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04002399 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04002400 {
Jamie Madill437fa652016-05-03 15:13:24 -04002401 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002402 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002403 }
2404 }
2405 break;
2406
He Yunchaoced53ae2016-11-29 15:00:51 +08002407 default:
2408 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002409 }
2410
2411 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04002412 if (*numParams == 0)
2413 {
2414 return false;
2415 }
2416
2417 return true;
2418}
2419
2420bool ValidateRobustStateQuery(ValidationContext *context,
2421 GLenum pname,
2422 GLsizei bufSize,
2423 GLenum *nativeType,
2424 unsigned int *numParams)
2425{
2426 if (!ValidateRobustEntryPoint(context, bufSize))
2427 {
2428 return false;
2429 }
2430
2431 if (!ValidateStateQuery(context, pname, nativeType, numParams))
2432 {
2433 return false;
2434 }
2435
2436 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04002437 {
2438 return false;
2439 }
2440
2441 return true;
2442}
2443
Jamie Madillc29968b2016-01-20 11:17:23 -05002444bool ValidateCopyTexImageParametersBase(ValidationContext *context,
2445 GLenum target,
2446 GLint level,
2447 GLenum internalformat,
2448 bool isSubImage,
2449 GLint xoffset,
2450 GLint yoffset,
2451 GLint zoffset,
2452 GLint x,
2453 GLint y,
2454 GLsizei width,
2455 GLsizei height,
2456 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04002457 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04002458{
Jamie Madill560a8d82014-05-21 13:06:20 -04002459 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
2460 {
Jamie Madill437fa652016-05-03 15:13:24 -04002461 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002462 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002463 }
2464
He Yunchaoced53ae2016-11-29 15:00:51 +08002465 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
2466 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04002467 {
Jamie Madill437fa652016-05-03 15:13:24 -04002468 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002469 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002470 }
2471
2472 if (border != 0)
2473 {
Jamie Madill437fa652016-05-03 15:13:24 -04002474 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002475 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002476 }
2477
2478 if (!ValidMipLevel(context, target, level))
2479 {
Jamie Madill437fa652016-05-03 15:13:24 -04002480 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002481 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002482 }
2483
Jamie Madill51f40ec2016-06-15 14:06:00 -04002484 const auto &state = context->getGLState();
2485 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002486 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04002487 {
Jamie Madill437fa652016-05-03 15:13:24 -04002488 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002489 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002490 }
2491
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002492 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04002493 {
Jamie Madill437fa652016-05-03 15:13:24 -04002494 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002495 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002496 }
2497
Martin Radev138064f2016-07-15 12:03:41 +03002498 if (readFramebuffer->getReadBufferState() == GL_NONE)
2499 {
2500 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2501 return false;
2502 }
2503
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002504 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
2505 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08002506 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002507 // situation is an application error that would lead to a crash in ANGLE.
2508 if (readFramebuffer->getReadColorbuffer() == nullptr)
2509 {
2510 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
2511 return false;
2512 }
2513
Geoff Langaae65a42014-05-26 12:43:44 -04002514 const gl::Caps &caps = context->getCaps();
2515
Geoff Langaae65a42014-05-26 12:43:44 -04002516 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04002517 switch (target)
2518 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002519 case GL_TEXTURE_2D:
2520 maxDimension = caps.max2DTextureSize;
2521 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002522
He Yunchaoced53ae2016-11-29 15:00:51 +08002523 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2524 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2525 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2526 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2527 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2528 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2529 maxDimension = caps.maxCubeMapTextureSize;
2530 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002531
He Yunchaoced53ae2016-11-29 15:00:51 +08002532 case GL_TEXTURE_2D_ARRAY:
2533 maxDimension = caps.max2DTextureSize;
2534 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002535
He Yunchaoced53ae2016-11-29 15:00:51 +08002536 case GL_TEXTURE_3D:
2537 maxDimension = caps.max3DTextureSize;
2538 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002539
He Yunchaoced53ae2016-11-29 15:00:51 +08002540 default:
2541 context->handleError(Error(GL_INVALID_ENUM));
2542 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002543 }
2544
Jamie Madillc29968b2016-01-20 11:17:23 -05002545 gl::Texture *texture =
2546 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04002547 if (!texture)
2548 {
Jamie Madill437fa652016-05-03 15:13:24 -04002549 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002550 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002551 }
2552
Geoff Lang69cce582015-09-17 13:20:36 -04002553 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04002554 {
Jamie Madill437fa652016-05-03 15:13:24 -04002555 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002556 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002557 }
2558
Geoff Langca271392017-04-05 12:30:00 -04002559 const gl::InternalFormat &formatInfo =
2560 gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04002561
Geoff Lang966c9402017-04-18 12:38:27 -04002562 if (formatInfo.depthBits > 0 || formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04002563 {
Jamie Madill437fa652016-05-03 15:13:24 -04002564 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002565 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002566 }
2567
2568 if (isSubImage)
2569 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05002570 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
2571 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
2572 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04002573 {
Jamie Madill437fa652016-05-03 15:13:24 -04002574 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002575 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002576 }
2577 }
Jamie Madill6f38f822014-06-06 17:12:20 -04002578 else
2579 {
Geoff Lang691e58c2014-12-19 17:03:25 -05002580 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04002581 {
Jamie Madill437fa652016-05-03 15:13:24 -04002582 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002583 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002584 }
2585
Geoff Langeb66a6e2016-10-31 13:06:12 -04002586 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04002587 {
Jamie Madill437fa652016-05-03 15:13:24 -04002588 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002589 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002590 }
2591
2592 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08002593 if (static_cast<int>(width) > maxLevelDimension ||
2594 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04002595 {
Jamie Madill437fa652016-05-03 15:13:24 -04002596 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002597 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002598 }
2599 }
Jamie Madill560a8d82014-05-21 13:06:20 -04002600
Jamie Madill0c8abca2016-07-22 20:21:26 -04002601 if (textureFormatOut)
2602 {
2603 *textureFormatOut = texture->getFormat(target, level);
2604 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05002605
2606 // Detect texture copying feedback loops for WebGL.
2607 if (context->getExtensions().webglCompatibility)
2608 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05002609 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05002610 {
2611 context->handleError(Error(GL_INVALID_OPERATION,
2612 "Texture copying feedback loop formed between Framebuffer "
2613 "and specified Texture level."));
2614 return false;
2615 }
2616 }
2617
Jamie Madill560a8d82014-05-21 13:06:20 -04002618 return true;
2619}
2620
Jiajia Qind9671222016-11-29 16:30:31 +08002621bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04002622{
Jamie Madill1aeb1312014-06-20 13:21:25 -04002623 switch (mode)
2624 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002625 case GL_POINTS:
2626 case GL_LINES:
2627 case GL_LINE_LOOP:
2628 case GL_LINE_STRIP:
2629 case GL_TRIANGLES:
2630 case GL_TRIANGLE_STRIP:
2631 case GL_TRIANGLE_FAN:
2632 break;
2633 default:
2634 context->handleError(Error(GL_INVALID_ENUM));
2635 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04002636 }
2637
Jamie Madill250d33f2014-06-06 17:09:03 -04002638 if (count < 0)
2639 {
Jamie Madill437fa652016-05-03 15:13:24 -04002640 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002641 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002642 }
2643
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002644 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04002645
Jamie Madill250d33f2014-06-06 17:09:03 -04002646 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002647 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002648 {
Jamie Madill437fa652016-05-03 15:13:24 -04002649 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002650 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002651 }
2652
Jamie Madillcbcde722017-01-06 14:50:00 -05002653 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
2654 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04002655 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002656 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
2657 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04002658 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002659 const FramebufferAttachment *dsAttachment =
2660 framebuffer->getStencilOrDepthStencilAttachment();
2661 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08002662 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04002663 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002664
2665 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
2666 bool differentWritemasks =
2667 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
2668 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
2669 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
2670 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
2671
2672 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04002673 {
Jamie Madillcbcde722017-01-06 14:50:00 -05002674 if (!context->getExtensions().webglCompatibility)
2675 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05002676 ERR() << "This ANGLE implementation does not support separate front/back stencil "
2677 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05002678 }
Jamie Madill437fa652016-05-03 15:13:24 -04002679 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04002680 return false;
2681 }
Jamie Madillac528012014-06-20 13:21:23 -04002682 }
2683
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002684 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002685 {
Jamie Madill437fa652016-05-03 15:13:24 -04002686 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002687 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002688 }
2689
Geoff Lang7dd2e102014-11-10 15:19:26 -05002690 gl::Program *program = state.getProgram();
2691 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002692 {
Jamie Madill437fa652016-05-03 15:13:24 -04002693 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002694 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002695 }
2696
Yunchao Hef81ce4a2017-04-24 10:49:17 +08002697 if (!program->validateSamplers(nullptr, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04002698 {
Jamie Madill437fa652016-05-03 15:13:24 -04002699 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002700 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002701 }
2702
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002703 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08002704 for (unsigned int uniformBlockIndex = 0;
2705 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002706 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04002707 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08002708 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04002709 const OffsetBindingPointer<Buffer> &uniformBuffer =
2710 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002711
Geoff Lang5d124a62015-09-15 13:03:27 -04002712 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002713 {
2714 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002715 context->handleError(
2716 Error(GL_INVALID_OPERATION,
2717 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002718 return false;
2719 }
2720
Geoff Lang5d124a62015-09-15 13:03:27 -04002721 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002722 if (uniformBufferSize == 0)
2723 {
2724 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07002725 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002726 }
2727
Jamie Madill62d31cb2015-09-11 13:25:51 -04002728 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002729 {
2730 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002731 context->handleError(
2732 Error(GL_INVALID_OPERATION,
2733 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002734 return false;
2735 }
2736 }
2737
Geoff Lange0cff192017-05-30 13:04:56 -04002738 // Do some additonal WebGL-specific validation
Jamie Madilla4595b82017-01-11 17:36:34 -05002739 if (context->getExtensions().webglCompatibility)
2740 {
Geoff Lange0cff192017-05-30 13:04:56 -04002741 // Detect rendering feedback loops for WebGL.
Jamie Madilla4595b82017-01-11 17:36:34 -05002742 if (framebuffer->formsRenderingFeedbackLoopWith(state))
2743 {
2744 context->handleError(
2745 Error(GL_INVALID_OPERATION,
2746 "Rendering feedback loop formed between Framebuffer and active Texture."));
2747 return false;
2748 }
Geoff Lange0cff192017-05-30 13:04:56 -04002749
2750 // Detect that the color buffer types match the fragment shader output types
2751 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
2752 {
2753 return false;
2754 }
Jamie Madilla4595b82017-01-11 17:36:34 -05002755 }
2756
Jamie Madill250d33f2014-06-06 17:09:03 -04002757 // No-op if zero count
2758 return (count > 0);
2759}
2760
Jamie Madillc1d770e2017-04-13 17:31:24 -04002761bool ValidateDrawArraysCommon(ValidationContext *context,
2762 GLenum mode,
2763 GLint first,
2764 GLsizei count,
2765 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04002766{
Jamie Madillfd716582014-06-06 17:09:04 -04002767 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04002768 {
Jamie Madill437fa652016-05-03 15:13:24 -04002769 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002770 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002771 }
2772
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002773 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002774 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002775 if (curTransformFeedback && curTransformFeedback->isActive() &&
2776 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04002777 {
2778 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08002779 // that does not match the current transform feedback object's draw mode (if transform
2780 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04002781 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002782 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002783 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002784 }
2785
Jiajia Qind9671222016-11-29 16:30:31 +08002786 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002787 {
2788 return false;
2789 }
2790
Corentin Wallez71168a02016-12-19 15:11:18 -08002791 // Check the computation of maxVertex doesn't overflow.
2792 // - first < 0 or count < 0 have been checked as an error condition
2793 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
2794 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
2795 ASSERT(count > 0 && first >= 0);
2796 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
2797 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05002798 {
2799 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
2800 return false;
2801 }
2802
Corentin Wallez71168a02016-12-19 15:11:18 -08002803 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04002804 {
2805 return false;
2806 }
2807
2808 return true;
2809}
2810
He Yunchaoced53ae2016-11-29 15:00:51 +08002811bool ValidateDrawArraysInstanced(Context *context,
2812 GLenum mode,
2813 GLint first,
2814 GLsizei count,
2815 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04002816{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002817 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04002818 {
2819 return false;
2820 }
2821
Corentin Wallez170efbf2017-05-02 13:45:01 -04002822 return !context->getExtensions().webglCompatibility ||
2823 ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002824}
2825
He Yunchaoced53ae2016-11-29 15:00:51 +08002826bool ValidateDrawArraysInstancedANGLE(Context *context,
2827 GLenum mode,
2828 GLint first,
2829 GLsizei count,
2830 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04002831{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002832 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04002833 {
2834 return false;
2835 }
2836
Corentin Wallez170efbf2017-05-02 13:45:01 -04002837 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002838}
2839
Jiajia Qind9671222016-11-29 16:30:31 +08002840bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04002841{
Jamie Madill250d33f2014-06-06 17:09:03 -04002842 switch (type)
2843 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002844 case GL_UNSIGNED_BYTE:
2845 case GL_UNSIGNED_SHORT:
2846 break;
2847 case GL_UNSIGNED_INT:
2848 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2849 {
2850 context->handleError(Error(GL_INVALID_ENUM));
2851 return false;
2852 }
2853 break;
2854 default:
2855 context->handleError(Error(GL_INVALID_ENUM));
2856 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002857 }
2858
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002859 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002860
2861 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002862 if (curTransformFeedback && curTransformFeedback->isActive() &&
2863 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002864 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002865 // It is an invalid operation to call DrawElements, DrawRangeElements or
2866 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04002867 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002868 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002869 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002870 }
2871
Jiajia Qind9671222016-11-29 16:30:31 +08002872 return true;
2873}
2874
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002875bool ValidateDrawElementsCommon(ValidationContext *context,
2876 GLenum mode,
2877 GLsizei count,
2878 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04002879 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002880 GLsizei primcount)
Jiajia Qind9671222016-11-29 16:30:31 +08002881{
2882 if (!ValidateDrawElementsBase(context, type))
2883 return false;
2884
2885 const State &state = context->getGLState();
2886
Corentin Wallez170efbf2017-05-02 13:45:01 -04002887 if (!ValidateDrawBase(context, mode, count))
2888 {
2889 return false;
2890 }
2891
Jamie Madill250d33f2014-06-06 17:09:03 -04002892 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002893 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002894 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002895 context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
Geoff Langb1196682014-07-23 13:47:29 -04002896 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002897 }
2898
He Yunchaoced53ae2016-11-29 15:00:51 +08002899 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002900 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04002901
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002902 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
2903
2904 if (context->getExtensions().webglCompatibility)
2905 {
2906 ASSERT(isPow2(typeBytes) && typeBytes > 0);
2907 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
2908 {
2909 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2910 // The offset arguments to drawElements and [...], must be a multiple of the size of the
2911 // data type passed to the call, or an INVALID_OPERATION error is generated.
2912 context->handleError(Error(GL_INVALID_OPERATION,
2913 "indices must be a multiple of the element type size."));
2914 return false;
2915 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002916
2917 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2918 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
2919 // error is generated.
2920 if (reinterpret_cast<intptr_t>(indices) < 0)
2921 {
2922 context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
2923 return false;
2924 }
Geoff Langfeb8c682017-02-13 16:07:35 -05002925 }
2926
2927 if (context->getExtensions().webglCompatibility ||
2928 !context->getGLState().areClientArraysEnabled())
2929 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002930 if (!elementArrayBuffer && count > 0)
2931 {
2932 // [WebGL 1.0] Section 6.2 No Client Side Arrays
2933 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
2934 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
2935 context->handleError(Error(GL_INVALID_OPERATION,
2936 "There is no element array buffer bound and count > 0."));
2937 return false;
2938 }
2939 }
2940
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002941 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04002942 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002943 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04002944 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002945 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
2946 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
2947 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
2948 constexpr uint64_t kMaxTypeSize = 8;
2949 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
2950 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
2951 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002952
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002953 uint64_t typeSize = typeBytes;
2954 uint64_t elementCount = static_cast<uint64_t>(count);
2955 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
2956
2957 // Doing the multiplication here is overflow-safe
2958 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
2959
2960 // The offset can be any value, check for overflows
2961 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
2962 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002963 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002964 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002965 return false;
2966 }
2967
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002968 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
2969 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002970 {
2971 context->handleError(
2972 Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
2973 return false;
2974 }
2975 }
2976 else if (!indices)
2977 {
2978 // This is an application error that would normally result in a crash,
2979 // but we catch it and return an error
2980 context->handleError(
2981 Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
Geoff Langb1196682014-07-23 13:47:29 -04002982 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04002983 }
Jamie Madillae3000b2014-08-25 15:47:51 -04002984 }
2985
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002986 // Use the parameter buffer to retrieve and cache the index range.
Jamie Madill2b976812014-08-25 15:47:49 -04002987 // TODO: offer fast path, with disabled index validation.
2988 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002989 const auto &params = context->getParams<HasIndexRange>();
2990 const auto &indexRangeOpt = params.getIndexRange();
2991 if (!indexRangeOpt.valid())
Jamie Madill2b976812014-08-25 15:47:49 -04002992 {
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002993 // Unexpected error.
2994 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04002995 }
2996
Jamie Madille79b1e12015-11-04 16:36:37 -05002997 // If we use an index greater than our maximum supported index range, return an error.
2998 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
2999 // return an error if possible here.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003000 if (static_cast<GLuint64>(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex)
Jamie Madille79b1e12015-11-04 16:36:37 -05003001 {
Jamie Madill437fa652016-05-03 15:13:24 -04003002 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05003003 return false;
3004 }
3005
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003006 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOpt.value().end),
3007 static_cast<GLint>(indexRangeOpt.value().vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04003008 {
3009 return false;
3010 }
3011
Geoff Lang3edfe032015-09-04 16:38:24 -04003012 // No op if there are no real indices in the index data (all are primitive restart).
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003013 return (indexRangeOpt.value().vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04003014}
3015
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003016bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
3017 GLenum mode,
3018 GLsizei count,
3019 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003020 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003021 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003022{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003023 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04003024 {
3025 return false;
3026 }
3027
Corentin Wallez170efbf2017-05-02 13:45:01 -04003028 return !context->getExtensions().webglCompatibility ||
3029 ValidateDrawInstancedANGLEAndWebGL(context);
Jamie Madill250d33f2014-06-06 17:09:03 -04003030}
3031
Geoff Lang3edfe032015-09-04 16:38:24 -04003032bool ValidateDrawElementsInstancedANGLE(Context *context,
3033 GLenum mode,
3034 GLsizei count,
3035 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003036 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003037 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003038{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003039 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04003040 {
3041 return false;
3042 }
3043
Corentin Wallez170efbf2017-05-02 13:45:01 -04003044 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04003045}
3046
He Yunchaoced53ae2016-11-29 15:00:51 +08003047bool ValidateFramebufferTextureBase(Context *context,
3048 GLenum target,
3049 GLenum attachment,
3050 GLuint texture,
3051 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04003052{
Jamie Madill55ec3b12014-07-03 10:38:57 -04003053 if (!ValidFramebufferTarget(target))
3054 {
Jamie Madill437fa652016-05-03 15:13:24 -04003055 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003056 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003057 }
3058
3059 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04003060 {
3061 return false;
3062 }
3063
Jamie Madill55ec3b12014-07-03 10:38:57 -04003064 if (texture != 0)
3065 {
3066 gl::Texture *tex = context->getTexture(texture);
3067
Jamie Madillbe849e42017-05-02 15:49:00 -04003068 if (tex == NULL)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003069 {
Jamie Madill437fa652016-05-03 15:13:24 -04003070 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003071 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003072 }
3073
3074 if (level < 0)
3075 {
Jamie Madill437fa652016-05-03 15:13:24 -04003076 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003077 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003078 }
3079 }
3080
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003081 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04003082 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04003083
Jamie Madill84115c92015-04-23 15:00:07 -04003084 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003085 {
Jamie Madill437fa652016-05-03 15:13:24 -04003086 context->handleError(
3087 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04003088 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003089 }
3090
3091 return true;
3092}
3093
Geoff Langb1196682014-07-23 13:47:29 -04003094bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04003095{
3096 if (program == 0)
3097 {
Jamie Madill437fa652016-05-03 15:13:24 -04003098 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003099 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003100 }
3101
Dian Xiang769769a2015-09-09 15:20:08 -07003102 gl::Program *programObject = GetValidProgram(context, program);
3103 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05003104 {
3105 return false;
3106 }
3107
Jamie Madill0063c512014-08-25 15:47:53 -04003108 if (!programObject || !programObject->isLinked())
3109 {
Jamie Madill437fa652016-05-03 15:13:24 -04003110 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003111 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003112 }
3113
Geoff Lang7dd2e102014-11-10 15:19:26 -05003114 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04003115 {
Jamie Madill437fa652016-05-03 15:13:24 -04003116 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003117 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04003118 }
3119
Jamie Madill0063c512014-08-25 15:47:53 -04003120 return true;
3121}
3122
Geoff Langf41d0ee2016-10-07 13:04:23 -04003123static bool ValidateSizedGetUniform(Context *context,
3124 GLuint program,
3125 GLint location,
3126 GLsizei bufSize,
3127 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04003128{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003129 if (length)
3130 {
3131 *length = 0;
3132 }
3133
Jamie Madill78f41802014-08-25 15:47:55 -04003134 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04003135 {
Jamie Madill78f41802014-08-25 15:47:55 -04003136 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003137 }
3138
Geoff Langf41d0ee2016-10-07 13:04:23 -04003139 if (bufSize < 0)
3140 {
3141 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3142 return false;
3143 }
3144
Jamie Madilla502c742014-08-28 17:19:13 -04003145 gl::Program *programObject = context->getProgram(program);
3146 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04003147
Jamie Madill78f41802014-08-25 15:47:55 -04003148 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04003149 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08003150 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04003151 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04003152 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04003153 context->handleError(
3154 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04003155 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003156 }
3157
Geoff Langf41d0ee2016-10-07 13:04:23 -04003158 if (length)
3159 {
Geoff Lang94177fb2016-11-14 16:12:26 -05003160 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04003161 }
3162
Jamie Madill0063c512014-08-25 15:47:53 -04003163 return true;
3164}
3165
He Yunchaoced53ae2016-11-29 15:00:51 +08003166bool ValidateGetnUniformfvEXT(Context *context,
3167 GLuint program,
3168 GLint location,
3169 GLsizei bufSize,
3170 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003171{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003172 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04003173}
3174
He Yunchaoced53ae2016-11-29 15:00:51 +08003175bool ValidateGetnUniformivEXT(Context *context,
3176 GLuint program,
3177 GLint location,
3178 GLsizei bufSize,
3179 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003180{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003181 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3182}
3183
3184bool ValidateGetUniformfvRobustANGLE(Context *context,
3185 GLuint program,
3186 GLint location,
3187 GLsizei bufSize,
3188 GLsizei *length,
3189 GLfloat *params)
3190{
3191 if (!ValidateRobustEntryPoint(context, bufSize))
3192 {
3193 return false;
3194 }
3195
3196 // bufSize is validated in ValidateSizedGetUniform
3197 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3198}
3199
3200bool ValidateGetUniformivRobustANGLE(Context *context,
3201 GLuint program,
3202 GLint location,
3203 GLsizei bufSize,
3204 GLsizei *length,
3205 GLint *params)
3206{
3207 if (!ValidateRobustEntryPoint(context, bufSize))
3208 {
3209 return false;
3210 }
3211
3212 // bufSize is validated in ValidateSizedGetUniform
3213 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3214}
3215
3216bool ValidateGetUniformuivRobustANGLE(Context *context,
3217 GLuint program,
3218 GLint location,
3219 GLsizei bufSize,
3220 GLsizei *length,
3221 GLuint *params)
3222{
3223 if (!ValidateRobustEntryPoint(context, bufSize))
3224 {
3225 return false;
3226 }
3227
3228 if (context->getClientMajorVersion() < 3)
3229 {
3230 context->handleError(
3231 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
3232 return false;
3233 }
3234
3235 // bufSize is validated in ValidateSizedGetUniform
3236 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04003237}
3238
He Yunchaoced53ae2016-11-29 15:00:51 +08003239bool ValidateDiscardFramebufferBase(Context *context,
3240 GLenum target,
3241 GLsizei numAttachments,
3242 const GLenum *attachments,
3243 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07003244{
3245 if (numAttachments < 0)
3246 {
Jamie Madill437fa652016-05-03 15:13:24 -04003247 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07003248 return false;
3249 }
3250
3251 for (GLsizei i = 0; i < numAttachments; ++i)
3252 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02003253 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07003254 {
3255 if (defaultFramebuffer)
3256 {
Jamie Madill437fa652016-05-03 15:13:24 -04003257 context->handleError(Error(
3258 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07003259 return false;
3260 }
3261
3262 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
3263 {
Jamie Madill437fa652016-05-03 15:13:24 -04003264 context->handleError(Error(GL_INVALID_OPERATION,
3265 "Requested color attachment is greater than the maximum "
3266 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07003267 return false;
3268 }
3269 }
3270 else
3271 {
3272 switch (attachments[i])
3273 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003274 case GL_DEPTH_ATTACHMENT:
3275 case GL_STENCIL_ATTACHMENT:
3276 case GL_DEPTH_STENCIL_ATTACHMENT:
3277 if (defaultFramebuffer)
3278 {
3279 context->handleError(
3280 Error(GL_INVALID_ENUM,
3281 "Invalid attachment when the default framebuffer is bound"));
3282 return false;
3283 }
3284 break;
3285 case GL_COLOR:
3286 case GL_DEPTH:
3287 case GL_STENCIL:
3288 if (!defaultFramebuffer)
3289 {
3290 context->handleError(
3291 Error(GL_INVALID_ENUM,
3292 "Invalid attachment when the default framebuffer is not bound"));
3293 return false;
3294 }
3295 break;
3296 default:
3297 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07003298 return false;
Austin Kinross08332632015-05-05 13:35:47 -07003299 }
3300 }
3301 }
3302
3303 return true;
3304}
3305
Austin Kinross6ee1e782015-05-29 17:05:37 -07003306bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
3307{
3308 // Note that debug marker calls must not set error state
3309
3310 if (length < 0)
3311 {
3312 return false;
3313 }
3314
3315 if (marker == nullptr)
3316 {
3317 return false;
3318 }
3319
3320 return true;
3321}
3322
3323bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
3324{
3325 // Note that debug marker calls must not set error state
3326
3327 if (length < 0)
3328 {
3329 return false;
3330 }
3331
3332 if (length > 0 && marker == nullptr)
3333 {
3334 return false;
3335 }
3336
3337 return true;
3338}
3339
Geoff Langdcab33b2015-07-21 13:03:16 -04003340bool ValidateEGLImageTargetTexture2DOES(Context *context,
3341 egl::Display *display,
3342 GLenum target,
3343 egl::Image *image)
3344{
Geoff Langa8406172015-07-21 16:53:39 -04003345 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
3346 {
Jamie Madill437fa652016-05-03 15:13:24 -04003347 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04003348 return false;
3349 }
3350
3351 switch (target)
3352 {
3353 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04003354 if (!context->getExtensions().eglImage)
3355 {
3356 context->handleError(Error(
3357 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
3358 }
3359 break;
3360
3361 case GL_TEXTURE_EXTERNAL_OES:
3362 if (!context->getExtensions().eglImageExternal)
3363 {
3364 context->handleError(Error(
3365 GL_INVALID_ENUM,
3366 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
3367 }
Geoff Langa8406172015-07-21 16:53:39 -04003368 break;
3369
3370 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003371 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04003372 return false;
3373 }
3374
3375 if (!display->isValidImage(image))
3376 {
Jamie Madill437fa652016-05-03 15:13:24 -04003377 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04003378 return false;
3379 }
3380
3381 if (image->getSamples() > 0)
3382 {
Jamie Madill437fa652016-05-03 15:13:24 -04003383 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04003384 "cannot create a 2D texture from a multisampled EGL image."));
3385 return false;
3386 }
3387
Geoff Langca271392017-04-05 12:30:00 -04003388 const TextureCaps &textureCaps =
3389 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003390 if (!textureCaps.texturable)
3391 {
Jamie Madill437fa652016-05-03 15:13:24 -04003392 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04003393 "EGL image internal format is not supported as a texture."));
3394 return false;
3395 }
3396
Geoff Langdcab33b2015-07-21 13:03:16 -04003397 return true;
3398}
3399
3400bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
3401 egl::Display *display,
3402 GLenum target,
3403 egl::Image *image)
3404{
Geoff Langa8406172015-07-21 16:53:39 -04003405 if (!context->getExtensions().eglImage)
3406 {
Jamie Madill437fa652016-05-03 15:13:24 -04003407 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04003408 return false;
3409 }
3410
3411 switch (target)
3412 {
3413 case GL_RENDERBUFFER:
3414 break;
3415
3416 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003417 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04003418 return false;
3419 }
3420
3421 if (!display->isValidImage(image))
3422 {
Jamie Madill437fa652016-05-03 15:13:24 -04003423 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04003424 return false;
3425 }
3426
Geoff Langca271392017-04-05 12:30:00 -04003427 const TextureCaps &textureCaps =
3428 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003429 if (!textureCaps.renderable)
3430 {
Jamie Madill437fa652016-05-03 15:13:24 -04003431 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04003432 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
3433 return false;
3434 }
3435
Geoff Langdcab33b2015-07-21 13:03:16 -04003436 return true;
3437}
Austin Kinrossbc781f32015-10-26 09:27:38 -07003438
3439bool ValidateBindVertexArrayBase(Context *context, GLuint array)
3440{
Geoff Lang36167ab2015-12-07 10:27:14 -05003441 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07003442 {
3443 // The default VAO should always exist
3444 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04003445 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07003446 return false;
3447 }
3448
3449 return true;
3450}
3451
Geoff Langc5629752015-12-07 16:29:04 -05003452bool ValidateProgramBinaryBase(Context *context,
3453 GLuint program,
3454 GLenum binaryFormat,
3455 const void *binary,
3456 GLint length)
3457{
3458 Program *programObject = GetValidProgram(context, program);
3459 if (programObject == nullptr)
3460 {
3461 return false;
3462 }
3463
3464 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3465 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3466 programBinaryFormats.end())
3467 {
Jamie Madill437fa652016-05-03 15:13:24 -04003468 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05003469 return false;
3470 }
3471
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003472 if (context->hasActiveTransformFeedback(program))
3473 {
3474 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04003475 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003476 "Cannot change program binary while program is associated with "
3477 "an active transform feedback object."));
3478 return false;
3479 }
3480
Geoff Langc5629752015-12-07 16:29:04 -05003481 return true;
3482}
3483
3484bool ValidateGetProgramBinaryBase(Context *context,
3485 GLuint program,
3486 GLsizei bufSize,
3487 GLsizei *length,
3488 GLenum *binaryFormat,
3489 void *binary)
3490{
3491 Program *programObject = GetValidProgram(context, program);
3492 if (programObject == nullptr)
3493 {
3494 return false;
3495 }
3496
3497 if (!programObject->isLinked())
3498 {
Jamie Madill437fa652016-05-03 15:13:24 -04003499 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05003500 return false;
3501 }
3502
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003503 if (context->getCaps().programBinaryFormats.empty())
3504 {
3505 context->handleError(Error(GL_INVALID_OPERATION, "No program binary formats supported."));
3506 return false;
3507 }
3508
Geoff Langc5629752015-12-07 16:29:04 -05003509 return true;
3510}
Jamie Madillc29968b2016-01-20 11:17:23 -05003511
Jamie Madillc29968b2016-01-20 11:17:23 -05003512bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
3513{
3514 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3515 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3516 {
Jamie Madill437fa652016-05-03 15:13:24 -04003517 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003518 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
3519 return false;
3520 }
3521
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003522 ASSERT(context->getGLState().getDrawFramebuffer());
3523 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05003524 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3525
3526 // This should come first before the check for the default frame buffer
3527 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3528 // rather than INVALID_OPERATION
3529 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3530 {
3531 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3532
3533 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02003534 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3535 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05003536 {
3537 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02003538 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3539 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3540 // 3.1 is still a bit ambiguous about the error, but future specs are
3541 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04003542 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02003543 return false;
3544 }
3545 else if (bufs[colorAttachment] >= maxColorAttachment)
3546 {
Jamie Madill437fa652016-05-03 15:13:24 -04003547 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02003548 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05003549 return false;
3550 }
3551 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3552 frameBufferId != 0)
3553 {
3554 // INVALID_OPERATION-GL is bound to buffer and ith argument
3555 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04003556 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003557 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
3558 return false;
3559 }
3560 }
3561
3562 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3563 // and n is not 1 or bufs is bound to value other than BACK and NONE
3564 if (frameBufferId == 0)
3565 {
3566 if (n != 1)
3567 {
Jamie Madill437fa652016-05-03 15:13:24 -04003568 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05003569 "n must be 1 when GL is bound to the default framebuffer"));
3570 return false;
3571 }
3572
3573 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3574 {
Jamie Madill437fa652016-05-03 15:13:24 -04003575 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05003576 GL_INVALID_OPERATION,
3577 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
3578 return false;
3579 }
3580 }
3581
3582 return true;
3583}
3584
Geoff Lang496c02d2016-10-20 11:38:11 -07003585bool ValidateGetBufferPointervBase(Context *context,
3586 GLenum target,
3587 GLenum pname,
3588 GLsizei *length,
3589 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03003590{
Geoff Lang496c02d2016-10-20 11:38:11 -07003591 if (length)
3592 {
3593 *length = 0;
3594 }
3595
3596 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
3597 {
3598 context->handleError(
3599 Error(GL_INVALID_OPERATION,
Jamie Madillcc6ac252017-01-25 12:57:21 -08003600 "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
Geoff Lang496c02d2016-10-20 11:38:11 -07003601 return false;
3602 }
3603
Olli Etuaho4f667482016-03-30 15:56:35 +03003604 if (!ValidBufferTarget(context, target))
3605 {
Jamie Madill437fa652016-05-03 15:13:24 -04003606 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03003607 return false;
3608 }
3609
Geoff Lang496c02d2016-10-20 11:38:11 -07003610 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03003611 {
Geoff Lang496c02d2016-10-20 11:38:11 -07003612 case GL_BUFFER_MAP_POINTER:
3613 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03003614
Geoff Lang496c02d2016-10-20 11:38:11 -07003615 default:
3616 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
3617 return false;
3618 }
Olli Etuaho4f667482016-03-30 15:56:35 +03003619
3620 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3621 // target bound to zero generate an INVALID_OPERATION error."
3622 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07003623 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03003624 {
Jamie Madill437fa652016-05-03 15:13:24 -04003625 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003626 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
3627 return false;
3628 }
3629
Geoff Lang496c02d2016-10-20 11:38:11 -07003630 if (length)
3631 {
3632 *length = 1;
3633 }
3634
Olli Etuaho4f667482016-03-30 15:56:35 +03003635 return true;
3636}
3637
3638bool ValidateUnmapBufferBase(Context *context, GLenum target)
3639{
3640 if (!ValidBufferTarget(context, target))
3641 {
Jamie Madill437fa652016-05-03 15:13:24 -04003642 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003643 return false;
3644 }
3645
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003646 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003647
3648 if (buffer == nullptr || !buffer->isMapped())
3649 {
Jamie Madill437fa652016-05-03 15:13:24 -04003650 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003651 return false;
3652 }
3653
3654 return true;
3655}
3656
3657bool ValidateMapBufferRangeBase(Context *context,
3658 GLenum target,
3659 GLintptr offset,
3660 GLsizeiptr length,
3661 GLbitfield access)
3662{
3663 if (!ValidBufferTarget(context, target))
3664 {
Jamie Madill437fa652016-05-03 15:13:24 -04003665 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003666 return false;
3667 }
3668
3669 if (offset < 0 || length < 0)
3670 {
Jamie Madill437fa652016-05-03 15:13:24 -04003671 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003672 return false;
3673 }
3674
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003675 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003676
3677 if (!buffer)
3678 {
Jamie Madill437fa652016-05-03 15:13:24 -04003679 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003680 return false;
3681 }
3682
3683 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003684 CheckedNumeric<size_t> checkedOffset(offset);
3685 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003686
Jamie Madille2e406c2016-06-02 13:04:10 -04003687 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003688 {
Jamie Madill437fa652016-05-03 15:13:24 -04003689 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003690 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
3691 return false;
3692 }
3693
3694 // Check for invalid bits in the mask
3695 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3696 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3697 GL_MAP_UNSYNCHRONIZED_BIT;
3698
3699 if (access & ~(allAccessBits))
3700 {
Jamie Madill437fa652016-05-03 15:13:24 -04003701 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03003702 return false;
3703 }
3704
3705 if (length == 0)
3706 {
Jamie Madill437fa652016-05-03 15:13:24 -04003707 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003708 return false;
3709 }
3710
3711 if (buffer->isMapped())
3712 {
Jamie Madill437fa652016-05-03 15:13:24 -04003713 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003714 return false;
3715 }
3716
3717 // Check for invalid bit combinations
3718 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3719 {
Jamie Madill437fa652016-05-03 15:13:24 -04003720 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003721 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
3722 return false;
3723 }
3724
3725 GLbitfield writeOnlyBits =
3726 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3727
3728 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3729 {
Jamie Madill437fa652016-05-03 15:13:24 -04003730 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03003731 "Invalid access bits when mapping buffer for reading: 0x%X.",
3732 access));
3733 return false;
3734 }
3735
3736 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3737 {
Jamie Madill437fa652016-05-03 15:13:24 -04003738 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003739 GL_INVALID_OPERATION,
3740 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
3741 return false;
3742 }
3743 return true;
3744}
3745
3746bool ValidateFlushMappedBufferRangeBase(Context *context,
3747 GLenum target,
3748 GLintptr offset,
3749 GLsizeiptr length)
3750{
3751 if (offset < 0 || length < 0)
3752 {
Jamie Madill437fa652016-05-03 15:13:24 -04003753 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003754 return false;
3755 }
3756
3757 if (!ValidBufferTarget(context, target))
3758 {
Jamie Madill437fa652016-05-03 15:13:24 -04003759 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003760 return false;
3761 }
3762
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003763 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003764
3765 if (buffer == nullptr)
3766 {
Jamie Madill437fa652016-05-03 15:13:24 -04003767 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003768 return false;
3769 }
3770
3771 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3772 {
Jamie Madill437fa652016-05-03 15:13:24 -04003773 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003774 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
3775 return false;
3776 }
3777
3778 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003779 CheckedNumeric<size_t> checkedOffset(offset);
3780 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003781
Jamie Madille2e406c2016-06-02 13:04:10 -04003782 if (!checkedSize.IsValid() ||
3783 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003784 {
Jamie Madill437fa652016-05-03 15:13:24 -04003785 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003786 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3787 return false;
3788 }
3789
3790 return true;
3791}
3792
Olli Etuaho41997e72016-03-10 13:38:39 +02003793bool ValidateGenOrDelete(Context *context, GLint n)
3794{
3795 if (n < 0)
3796 {
Jamie Madill437fa652016-05-03 15:13:24 -04003797 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003798 return false;
3799 }
3800 return true;
3801}
3802
Geoff Langff5b2d52016-09-07 11:32:23 -04003803bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
3804{
3805 if (!context->getExtensions().robustClientMemory)
3806 {
3807 context->handleError(
3808 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
3809 return false;
3810 }
3811
3812 if (bufSize < 0)
3813 {
3814 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3815 return false;
3816 }
3817
3818 return true;
3819}
3820
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003821bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
3822{
3823 if (bufSize < numParams)
3824 {
3825 context->handleError(Error(GL_INVALID_OPERATION,
3826 "%u parameters are required but %i were provided.", numParams,
3827 bufSize));
3828 return false;
3829 }
3830
3831 return true;
3832}
3833
Jamie Madillbe849e42017-05-02 15:49:00 -04003834bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context,
3835 GLenum target,
3836 GLenum attachment,
3837 GLenum pname,
3838 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04003839{
3840 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08003841 if (numParams)
3842 {
3843 *numParams = 1;
3844 }
Geoff Langff5b2d52016-09-07 11:32:23 -04003845
3846 if (!ValidFramebufferTarget(target))
3847 {
3848 context->handleError(Error(GL_INVALID_ENUM));
3849 return false;
3850 }
3851
3852 int clientVersion = context->getClientMajorVersion();
3853
3854 switch (pname)
3855 {
3856 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3857 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3858 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3859 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3860 break;
3861
3862 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3863 if (clientVersion < 3 && !context->getExtensions().sRGB)
3864 {
3865 context->handleError(Error(GL_INVALID_ENUM));
3866 return false;
3867 }
3868 break;
3869
3870 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3871 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3872 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3873 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3874 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3875 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3876 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3877 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3878 if (clientVersion < 3)
3879 {
3880 context->handleError(Error(GL_INVALID_ENUM));
3881 return false;
3882 }
3883 break;
3884
3885 default:
3886 context->handleError(Error(GL_INVALID_ENUM));
3887 return false;
3888 }
3889
3890 // Determine if the attachment is a valid enum
3891 switch (attachment)
3892 {
3893 case GL_BACK:
3894 case GL_FRONT:
3895 case GL_DEPTH:
3896 case GL_STENCIL:
3897 case GL_DEPTH_STENCIL_ATTACHMENT:
3898 if (clientVersion < 3)
3899 {
3900 context->handleError(Error(GL_INVALID_ENUM));
3901 return false;
3902 }
3903 break;
3904
3905 case GL_DEPTH_ATTACHMENT:
3906 case GL_STENCIL_ATTACHMENT:
3907 break;
3908
3909 default:
3910 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
3911 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3912 {
3913 context->handleError(Error(GL_INVALID_ENUM));
3914 return false;
3915 }
3916 break;
3917 }
3918
3919 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
3920 ASSERT(framebuffer);
3921
3922 if (framebuffer->id() == 0)
3923 {
3924 if (clientVersion < 3)
3925 {
3926 context->handleError(Error(GL_INVALID_OPERATION));
3927 return false;
3928 }
3929
3930 switch (attachment)
3931 {
3932 case GL_BACK:
3933 case GL_DEPTH:
3934 case GL_STENCIL:
3935 break;
3936
3937 default:
3938 context->handleError(Error(GL_INVALID_OPERATION));
3939 return false;
3940 }
3941 }
3942 else
3943 {
3944 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3945 {
3946 // Valid attachment query
3947 }
3948 else
3949 {
3950 switch (attachment)
3951 {
3952 case GL_DEPTH_ATTACHMENT:
3953 case GL_STENCIL_ATTACHMENT:
3954 break;
3955
3956 case GL_DEPTH_STENCIL_ATTACHMENT:
3957 if (!framebuffer->hasValidDepthStencil())
3958 {
3959 context->handleError(Error(GL_INVALID_OPERATION));
3960 return false;
3961 }
3962 break;
3963
3964 default:
3965 context->handleError(Error(GL_INVALID_OPERATION));
3966 return false;
3967 }
3968 }
3969 }
3970
3971 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
3972 if (attachmentObject)
3973 {
3974 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
3975 attachmentObject->type() == GL_TEXTURE ||
3976 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
3977
3978 switch (pname)
3979 {
3980 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3981 if (attachmentObject->type() != GL_RENDERBUFFER &&
3982 attachmentObject->type() != GL_TEXTURE)
3983 {
3984 context->handleError(Error(GL_INVALID_ENUM));
3985 return false;
3986 }
3987 break;
3988
3989 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3990 if (attachmentObject->type() != GL_TEXTURE)
3991 {
3992 context->handleError(Error(GL_INVALID_ENUM));
3993 return false;
3994 }
3995 break;
3996
3997 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3998 if (attachmentObject->type() != GL_TEXTURE)
3999 {
4000 context->handleError(Error(GL_INVALID_ENUM));
4001 return false;
4002 }
4003 break;
4004
4005 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4006 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
4007 {
4008 context->handleError(Error(GL_INVALID_OPERATION));
4009 return false;
4010 }
4011 break;
4012
4013 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
4014 if (attachmentObject->type() != GL_TEXTURE)
4015 {
4016 context->handleError(Error(GL_INVALID_ENUM));
4017 return false;
4018 }
4019 break;
4020
4021 default:
4022 break;
4023 }
4024 }
4025 else
4026 {
4027 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
4028 // is NONE, then querying any other pname will generate INVALID_ENUM.
4029
4030 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
4031 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
4032 // INVALID_OPERATION for all other pnames
4033
4034 switch (pname)
4035 {
4036 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
4037 break;
4038
4039 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4040 if (clientVersion < 3)
4041 {
4042 context->handleError(Error(GL_INVALID_ENUM));
4043 return false;
4044 }
4045 break;
4046
4047 default:
4048 if (clientVersion < 3)
4049 {
4050 context->handleError(Error(GL_INVALID_ENUM));
4051 return false;
4052 }
4053 else
4054 {
4055 context->handleError(Error(GL_INVALID_OPERATION));
4056 return false;
4057 }
4058 }
4059 }
4060
4061 return true;
4062}
4063
4064bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
4065 GLenum target,
4066 GLenum attachment,
4067 GLenum pname,
4068 GLsizei bufSize,
4069 GLsizei *numParams)
4070{
4071 if (!ValidateRobustEntryPoint(context, bufSize))
4072 {
4073 return false;
4074 }
4075
Jamie Madillbe849e42017-05-02 15:49:00 -04004076 if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname,
4077 numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004078 {
4079 return false;
4080 }
4081
4082 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4083 {
4084 return false;
4085 }
4086
4087 return true;
4088}
4089
Geoff Langff5b2d52016-09-07 11:32:23 -04004090bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
4091 GLenum target,
4092 GLenum pname,
4093 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04004094 GLsizei *length,
4095 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04004096{
4097 if (!ValidateRobustEntryPoint(context, bufSize))
4098 {
4099 return false;
4100 }
4101
Geoff Langebebe1c2016-10-14 12:01:31 -04004102 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004103 {
4104 return false;
4105 }
4106
Geoff Langebebe1c2016-10-14 12:01:31 -04004107 if (!ValidateRobustBufferSize(context, bufSize, *length))
4108 {
4109 return false;
4110 }
4111
4112 return true;
4113}
4114
4115bool ValidateGetBufferParameteri64v(ValidationContext *context,
4116 GLenum target,
4117 GLenum pname,
4118 GLint64 *params)
4119{
4120 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
4121}
4122
4123bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
4124 GLenum target,
4125 GLenum pname,
4126 GLsizei bufSize,
4127 GLsizei *length,
4128 GLint64 *params)
4129{
4130 if (!ValidateRobustEntryPoint(context, bufSize))
4131 {
4132 return false;
4133 }
4134
4135 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
4136 {
4137 return false;
4138 }
4139
4140 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004141 {
4142 return false;
4143 }
4144
4145 return true;
4146}
4147
Jamie Madillbe849e42017-05-02 15:49:00 -04004148bool ValidateGetProgramivBase(ValidationContext *context,
4149 GLuint program,
4150 GLenum pname,
4151 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04004152{
4153 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08004154 if (numParams)
4155 {
4156 *numParams = 1;
4157 }
Geoff Langff5b2d52016-09-07 11:32:23 -04004158
4159 Program *programObject = GetValidProgram(context, program);
4160 if (!programObject)
4161 {
4162 return false;
4163 }
4164
4165 switch (pname)
4166 {
4167 case GL_DELETE_STATUS:
4168 case GL_LINK_STATUS:
4169 case GL_VALIDATE_STATUS:
4170 case GL_INFO_LOG_LENGTH:
4171 case GL_ATTACHED_SHADERS:
4172 case GL_ACTIVE_ATTRIBUTES:
4173 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
4174 case GL_ACTIVE_UNIFORMS:
4175 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
4176 break;
4177
4178 case GL_PROGRAM_BINARY_LENGTH:
4179 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
4180 {
4181 context->handleError(Error(GL_INVALID_ENUM,
4182 "Querying GL_PROGRAM_BINARY_LENGTH requires "
4183 "GL_OES_get_program_binary or ES 3.0."));
4184 return false;
4185 }
4186 break;
4187
4188 case GL_ACTIVE_UNIFORM_BLOCKS:
4189 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
4190 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
4191 case GL_TRANSFORM_FEEDBACK_VARYINGS:
4192 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
4193 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
4194 if (context->getClientMajorVersion() < 3)
4195 {
4196 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
4197 return false;
4198 }
4199 break;
4200
Yunchao He61afff12017-03-14 15:34:03 +08004201 case GL_PROGRAM_SEPARABLE:
4202 if (context->getClientVersion() < Version(3, 1))
4203 {
4204 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.1."));
4205 return false;
4206 }
4207 break;
4208
Geoff Langff5b2d52016-09-07 11:32:23 -04004209 default:
4210 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
4211 return false;
4212 }
4213
4214 return true;
4215}
4216
4217bool ValidateGetProgramivRobustANGLE(Context *context,
4218 GLuint program,
4219 GLenum pname,
4220 GLsizei bufSize,
4221 GLsizei *numParams)
4222{
4223 if (!ValidateRobustEntryPoint(context, bufSize))
4224 {
4225 return false;
4226 }
4227
Jamie Madillbe849e42017-05-02 15:49:00 -04004228 if (!ValidateGetProgramivBase(context, program, pname, numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004229 {
4230 return false;
4231 }
4232
4233 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4234 {
4235 return false;
4236 }
4237
4238 return true;
4239}
4240
Geoff Lang740d9022016-10-07 11:20:52 -04004241bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
4242 GLenum target,
4243 GLenum pname,
4244 GLsizei bufSize,
4245 GLsizei *length,
4246 GLint *params)
4247{
4248 if (!ValidateRobustEntryPoint(context, bufSize))
4249 {
4250 return false;
4251 }
4252
4253 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
4254 {
4255 return false;
4256 }
4257
4258 if (!ValidateRobustBufferSize(context, bufSize, *length))
4259 {
4260 return false;
4261 }
4262
4263 return true;
4264}
4265
Geoff Langd7d0ed32016-10-07 11:33:51 -04004266bool ValidateGetShaderivRobustANGLE(Context *context,
4267 GLuint shader,
4268 GLenum pname,
4269 GLsizei bufSize,
4270 GLsizei *length,
4271 GLint *params)
4272{
4273 if (!ValidateRobustEntryPoint(context, bufSize))
4274 {
4275 return false;
4276 }
4277
4278 if (!ValidateGetShaderivBase(context, shader, pname, length))
4279 {
4280 return false;
4281 }
4282
4283 if (!ValidateRobustBufferSize(context, bufSize, *length))
4284 {
4285 return false;
4286 }
4287
4288 return true;
4289}
4290
Geoff Langc1984ed2016-10-07 12:41:00 -04004291bool ValidateGetTexParameterfvRobustANGLE(Context *context,
4292 GLenum target,
4293 GLenum pname,
4294 GLsizei bufSize,
4295 GLsizei *length,
4296 GLfloat *params)
4297{
4298 if (!ValidateRobustEntryPoint(context, bufSize))
4299 {
4300 return false;
4301 }
4302
4303 if (!ValidateGetTexParameterBase(context, target, pname, length))
4304 {
4305 return false;
4306 }
4307
4308 if (!ValidateRobustBufferSize(context, bufSize, *length))
4309 {
4310 return false;
4311 }
4312
4313 return true;
4314}
4315
Geoff Langc1984ed2016-10-07 12:41:00 -04004316bool ValidateGetTexParameterivRobustANGLE(Context *context,
4317 GLenum target,
4318 GLenum pname,
4319 GLsizei bufSize,
4320 GLsizei *length,
4321 GLint *params)
4322{
4323 if (!ValidateRobustEntryPoint(context, bufSize))
4324 {
4325 return false;
4326 }
4327
4328 if (!ValidateGetTexParameterBase(context, target, pname, length))
4329 {
4330 return false;
4331 }
4332
4333 if (!ValidateRobustBufferSize(context, bufSize, *length))
4334 {
4335 return false;
4336 }
4337
4338 return true;
4339}
4340
Geoff Langc1984ed2016-10-07 12:41:00 -04004341bool ValidateTexParameterfvRobustANGLE(Context *context,
4342 GLenum target,
4343 GLenum pname,
4344 GLsizei bufSize,
4345 const GLfloat *params)
4346{
4347 if (!ValidateRobustEntryPoint(context, bufSize))
4348 {
4349 return false;
4350 }
4351
4352 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4353}
4354
Geoff Langc1984ed2016-10-07 12:41:00 -04004355bool ValidateTexParameterivRobustANGLE(Context *context,
4356 GLenum target,
4357 GLenum pname,
4358 GLsizei bufSize,
4359 const GLint *params)
4360{
4361 if (!ValidateRobustEntryPoint(context, bufSize))
4362 {
4363 return false;
4364 }
4365
4366 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4367}
4368
4369bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
4370{
4371 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4372}
4373
4374bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
4375 GLuint sampler,
4376 GLenum pname,
4377 GLuint bufSize,
4378 GLsizei *length,
4379 GLfloat *params)
4380{
4381 if (!ValidateRobustEntryPoint(context, bufSize))
4382 {
4383 return false;
4384 }
4385
4386 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4387 {
4388 return false;
4389 }
4390
4391 if (!ValidateRobustBufferSize(context, bufSize, *length))
4392 {
4393 return false;
4394 }
4395
4396 return true;
4397}
4398
4399bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
4400{
4401 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4402}
4403
4404bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
4405 GLuint sampler,
4406 GLenum pname,
4407 GLuint bufSize,
4408 GLsizei *length,
4409 GLint *params)
4410{
4411 if (!ValidateRobustEntryPoint(context, bufSize))
4412 {
4413 return false;
4414 }
4415
4416 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4417 {
4418 return false;
4419 }
4420
4421 if (!ValidateRobustBufferSize(context, bufSize, *length))
4422 {
4423 return false;
4424 }
4425
4426 return true;
4427}
4428
4429bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
4430{
4431 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4432}
4433
4434bool ValidateSamplerParameterfv(Context *context,
4435 GLuint sampler,
4436 GLenum pname,
4437 const GLfloat *params)
4438{
4439 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4440}
4441
4442bool ValidateSamplerParameterfvRobustANGLE(Context *context,
4443 GLuint sampler,
4444 GLenum pname,
4445 GLsizei bufSize,
4446 const GLfloat *params)
4447{
4448 if (!ValidateRobustEntryPoint(context, bufSize))
4449 {
4450 return false;
4451 }
4452
4453 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4454}
4455
4456bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
4457{
4458 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4459}
4460
4461bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
4462{
4463 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4464}
4465
4466bool ValidateSamplerParameterivRobustANGLE(Context *context,
4467 GLuint sampler,
4468 GLenum pname,
4469 GLsizei bufSize,
4470 const GLint *params)
4471{
4472 if (!ValidateRobustEntryPoint(context, bufSize))
4473 {
4474 return false;
4475 }
4476
4477 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4478}
4479
Geoff Lang0b031062016-10-13 14:30:04 -04004480bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
4481 GLuint index,
4482 GLenum pname,
4483 GLsizei bufSize,
4484 GLsizei *length,
4485 GLfloat *params)
4486{
4487 if (!ValidateRobustEntryPoint(context, bufSize))
4488 {
4489 return false;
4490 }
4491
4492 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4493 {
4494 return false;
4495 }
4496
4497 if (!ValidateRobustBufferSize(context, bufSize, *length))
4498 {
4499 return false;
4500 }
4501
4502 return true;
4503}
4504
Geoff Lang0b031062016-10-13 14:30:04 -04004505bool ValidateGetVertexAttribivRobustANGLE(Context *context,
4506 GLuint index,
4507 GLenum pname,
4508 GLsizei bufSize,
4509 GLsizei *length,
4510 GLint *params)
4511{
4512 if (!ValidateRobustEntryPoint(context, bufSize))
4513 {
4514 return false;
4515 }
4516
4517 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4518 {
4519 return false;
4520 }
4521
4522 if (!ValidateRobustBufferSize(context, bufSize, *length))
4523 {
4524 return false;
4525 }
4526
4527 return true;
4528}
4529
Geoff Lang0b031062016-10-13 14:30:04 -04004530bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
4531 GLuint index,
4532 GLenum pname,
4533 GLsizei bufSize,
4534 GLsizei *length,
4535 void **pointer)
4536{
4537 if (!ValidateRobustEntryPoint(context, bufSize))
4538 {
4539 return false;
4540 }
4541
4542 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
4543 {
4544 return false;
4545 }
4546
4547 if (!ValidateRobustBufferSize(context, bufSize, *length))
4548 {
4549 return false;
4550 }
4551
4552 return true;
4553}
4554
4555bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
4556{
4557 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4558}
4559
4560bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
4561 GLuint index,
4562 GLenum pname,
4563 GLsizei bufSize,
4564 GLsizei *length,
4565 GLint *params)
4566{
4567 if (!ValidateRobustEntryPoint(context, bufSize))
4568 {
4569 return false;
4570 }
4571
4572 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4573 {
4574 return false;
4575 }
4576
4577 if (!ValidateRobustBufferSize(context, bufSize, *length))
4578 {
4579 return false;
4580 }
4581
4582 return true;
4583}
4584
4585bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
4586{
4587 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4588}
4589
4590bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
4591 GLuint index,
4592 GLenum pname,
4593 GLsizei bufSize,
4594 GLsizei *length,
4595 GLuint *params)
4596{
4597 if (!ValidateRobustEntryPoint(context, bufSize))
4598 {
4599 return false;
4600 }
4601
4602 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4603 {
4604 return false;
4605 }
4606
4607 if (!ValidateRobustBufferSize(context, bufSize, *length))
4608 {
4609 return false;
4610 }
4611
4612 return true;
4613}
4614
Geoff Lang6899b872016-10-14 11:30:13 -04004615bool ValidateGetActiveUniformBlockiv(Context *context,
4616 GLuint program,
4617 GLuint uniformBlockIndex,
4618 GLenum pname,
4619 GLint *params)
4620{
4621 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
4622}
4623
4624bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
4625 GLuint program,
4626 GLuint uniformBlockIndex,
4627 GLenum pname,
4628 GLsizei bufSize,
4629 GLsizei *length,
4630 GLint *params)
4631{
4632 if (!ValidateRobustEntryPoint(context, bufSize))
4633 {
4634 return false;
4635 }
4636
4637 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
4638 {
4639 return false;
4640 }
4641
4642 if (!ValidateRobustBufferSize(context, bufSize, *length))
4643 {
4644 return false;
4645 }
4646
4647 return true;
4648}
4649
Geoff Lang0a9661f2016-10-20 10:59:20 -07004650bool ValidateGetInternalFormativ(Context *context,
4651 GLenum target,
4652 GLenum internalformat,
4653 GLenum pname,
4654 GLsizei bufSize,
4655 GLint *params)
4656{
4657 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
4658 nullptr);
4659}
4660
4661bool ValidateGetInternalFormativRobustANGLE(Context *context,
4662 GLenum target,
4663 GLenum internalformat,
4664 GLenum pname,
4665 GLsizei bufSize,
4666 GLsizei *length,
4667 GLint *params)
4668{
4669 if (!ValidateRobustEntryPoint(context, bufSize))
4670 {
4671 return false;
4672 }
4673
4674 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
4675 {
4676 return false;
4677 }
4678
4679 if (!ValidateRobustBufferSize(context, bufSize, *length))
4680 {
4681 return false;
4682 }
4683
4684 return true;
4685}
4686
Shao80957d92017-02-20 21:25:59 +08004687bool ValidateVertexFormatBase(ValidationContext *context,
4688 GLuint attribIndex,
4689 GLint size,
4690 GLenum type,
4691 GLboolean pureInteger)
4692{
4693 const Caps &caps = context->getCaps();
4694 if (attribIndex >= caps.maxVertexAttributes)
4695 {
4696 context->handleError(
4697 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
4698 return false;
4699 }
4700
4701 if (size < 1 || size > 4)
4702 {
4703 context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
4704 }
4705
4706 switch (type)
4707 {
4708 case GL_BYTE:
4709 case GL_UNSIGNED_BYTE:
4710 case GL_SHORT:
4711 case GL_UNSIGNED_SHORT:
4712 break;
4713
4714 case GL_INT:
4715 case GL_UNSIGNED_INT:
4716 if (context->getClientMajorVersion() < 3)
4717 {
4718 context->handleError(
4719 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4720 return false;
4721 }
4722 break;
4723
4724 case GL_FIXED:
4725 case GL_FLOAT:
4726 if (pureInteger)
4727 {
4728 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4729 return false;
4730 }
4731 break;
4732
4733 case GL_HALF_FLOAT:
4734 if (context->getClientMajorVersion() < 3)
4735 {
4736 context->handleError(
4737 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4738 return false;
4739 }
4740 if (pureInteger)
4741 {
4742 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4743 return false;
4744 }
4745 break;
4746
4747 case GL_INT_2_10_10_10_REV:
4748 case GL_UNSIGNED_INT_2_10_10_10_REV:
4749 if (context->getClientMajorVersion() < 3)
4750 {
4751 context->handleError(
4752 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4753 return false;
4754 }
4755 if (pureInteger)
4756 {
4757 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4758 return false;
4759 }
4760 if (size != 4)
4761 {
4762 context->handleError(Error(GL_INVALID_OPERATION,
4763 "Type is INT_2_10_10_10_REV or "
4764 "UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
4765 return false;
4766 }
4767 break;
4768
4769 default:
4770 context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
4771 return false;
4772 }
4773
4774 return true;
4775}
4776
Geoff Lang76e65652017-03-27 14:58:02 -04004777// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
4778// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
4779// specified clear value and the type of a buffer that is being cleared generates an
4780// INVALID_OPERATION error instead of producing undefined results
4781bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
4782 GLint drawbuffer,
4783 const GLenum *validComponentTypes,
4784 size_t validComponentTypeCount)
4785{
4786 const FramebufferAttachment *attachment =
4787 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
4788 if (attachment)
4789 {
4790 GLenum componentType = attachment->getFormat().info->componentType;
4791 const GLenum *end = validComponentTypes + validComponentTypeCount;
4792 if (std::find(validComponentTypes, end, componentType) == end)
4793 {
4794 context->handleError(
4795 Error(GL_INVALID_OPERATION,
4796 "No defined conversion between clear value and attachment format."));
4797 return false;
4798 }
4799 }
4800
4801 return true;
4802}
4803
Corentin Wallezb2931602017-04-11 15:58:57 -04004804bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
4805 GLsizei imageSize,
4806 GLsizei dataSize)
4807{
4808 if (!ValidateRobustEntryPoint(context, dataSize))
4809 {
4810 return false;
4811 }
4812
4813 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
4814 if (pixelUnpackBuffer == nullptr)
4815 {
4816 if (dataSize < imageSize)
4817 {
4818 context->handleError(
4819 Error(GL_INVALID_OPERATION, "dataSize must be at least %i.", imageSize));
4820 }
4821 }
4822 return true;
4823}
4824
Jamie Madillbe849e42017-05-02 15:49:00 -04004825bool ValidateGetBufferParameterBase(ValidationContext *context,
4826 GLenum target,
4827 GLenum pname,
4828 bool pointerVersion,
4829 GLsizei *numParams)
4830{
4831 if (numParams)
4832 {
4833 *numParams = 0;
4834 }
4835
4836 if (!ValidBufferTarget(context, target))
4837 {
4838 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
4839 return false;
4840 }
4841
4842 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
4843 if (!buffer)
4844 {
4845 // A null buffer means that "0" is bound to the requested buffer target
4846 context->handleError(Error(GL_INVALID_OPERATION, "No buffer bound."));
4847 return false;
4848 }
4849
4850 const Extensions &extensions = context->getExtensions();
4851
4852 switch (pname)
4853 {
4854 case GL_BUFFER_USAGE:
4855 case GL_BUFFER_SIZE:
4856 break;
4857
4858 case GL_BUFFER_ACCESS_OES:
4859 if (!extensions.mapBuffer)
4860 {
4861 context->handleError(
4862 Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
4863 return false;
4864 }
4865 break;
4866
4867 case GL_BUFFER_MAPPED:
4868 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
4869 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
4870 !extensions.mapBufferRange)
4871 {
4872 context->handleError(Error(
4873 GL_INVALID_ENUM,
4874 "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
4875 return false;
4876 }
4877 break;
4878
4879 case GL_BUFFER_MAP_POINTER:
4880 if (!pointerVersion)
4881 {
4882 context->handleError(
4883 Error(GL_INVALID_ENUM,
4884 "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."));
4885 return false;
4886 }
4887 break;
4888
4889 case GL_BUFFER_ACCESS_FLAGS:
4890 case GL_BUFFER_MAP_OFFSET:
4891 case GL_BUFFER_MAP_LENGTH:
4892 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
4893 {
4894 context->handleError(Error(
4895 GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."));
4896 return false;
4897 }
4898 break;
4899
4900 default:
4901 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4902 return false;
4903 }
4904
4905 // All buffer parameter queries return one value.
4906 if (numParams)
4907 {
4908 *numParams = 1;
4909 }
4910
4911 return true;
4912}
4913
4914bool ValidateGetRenderbufferParameterivBase(Context *context,
4915 GLenum target,
4916 GLenum pname,
4917 GLsizei *length)
4918{
4919 if (length)
4920 {
4921 *length = 0;
4922 }
4923
4924 if (target != GL_RENDERBUFFER)
4925 {
4926 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
4927 return false;
4928 }
4929
4930 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
4931 if (renderbuffer == nullptr)
4932 {
4933 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
4934 return false;
4935 }
4936
4937 switch (pname)
4938 {
4939 case GL_RENDERBUFFER_WIDTH:
4940 case GL_RENDERBUFFER_HEIGHT:
4941 case GL_RENDERBUFFER_INTERNAL_FORMAT:
4942 case GL_RENDERBUFFER_RED_SIZE:
4943 case GL_RENDERBUFFER_GREEN_SIZE:
4944 case GL_RENDERBUFFER_BLUE_SIZE:
4945 case GL_RENDERBUFFER_ALPHA_SIZE:
4946 case GL_RENDERBUFFER_DEPTH_SIZE:
4947 case GL_RENDERBUFFER_STENCIL_SIZE:
4948 break;
4949
4950 case GL_RENDERBUFFER_SAMPLES_ANGLE:
4951 if (!context->getExtensions().framebufferMultisample)
4952 {
4953 context->handleError(
4954 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
4955 return false;
4956 }
4957 break;
4958
4959 default:
4960 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4961 return false;
4962 }
4963
4964 if (length)
4965 {
4966 *length = 1;
4967 }
4968 return true;
4969}
4970
4971bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
4972{
4973 if (length)
4974 {
4975 *length = 0;
4976 }
4977
4978 if (GetValidShader(context, shader) == nullptr)
4979 {
4980 return false;
4981 }
4982
4983 switch (pname)
4984 {
4985 case GL_SHADER_TYPE:
4986 case GL_DELETE_STATUS:
4987 case GL_COMPILE_STATUS:
4988 case GL_INFO_LOG_LENGTH:
4989 case GL_SHADER_SOURCE_LENGTH:
4990 break;
4991
4992 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
4993 if (!context->getExtensions().translatedShaderSource)
4994 {
4995 context->handleError(
4996 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
4997 return false;
4998 }
4999 break;
5000
5001 default:
5002 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5003 return false;
5004 }
5005
5006 if (length)
5007 {
5008 *length = 1;
5009 }
5010 return true;
5011}
5012
5013bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
5014{
5015 if (length)
5016 {
5017 *length = 0;
5018 }
5019
5020 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5021 {
5022 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
5023 return false;
5024 }
5025
5026 if (context->getTargetTexture(target) == nullptr)
5027 {
5028 // Should only be possible for external textures
5029 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
5030 return false;
5031 }
5032
5033 switch (pname)
5034 {
5035 case GL_TEXTURE_MAG_FILTER:
5036 case GL_TEXTURE_MIN_FILTER:
5037 case GL_TEXTURE_WRAP_S:
5038 case GL_TEXTURE_WRAP_T:
5039 break;
5040
5041 case GL_TEXTURE_USAGE_ANGLE:
5042 if (!context->getExtensions().textureUsage)
5043 {
5044 context->handleError(
5045 Error(GL_INVALID_ENUM, "GL_ANGLE_texture_usage is not enabled."));
5046 return false;
5047 }
5048 break;
5049
5050 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5051 if (!context->getExtensions().textureFilterAnisotropic)
5052 {
5053 context->handleError(
5054 Error(GL_INVALID_ENUM, "GL_EXT_texture_filter_anisotropic is not enabled."));
5055 return false;
5056 }
5057 break;
5058
5059 case GL_TEXTURE_IMMUTABLE_FORMAT:
5060 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
5061 {
5062 context->handleError(
5063 Error(GL_INVALID_ENUM, "GL_EXT_texture_storage is not enabled."));
5064 return false;
5065 }
5066 break;
5067
5068 case GL_TEXTURE_WRAP_R:
5069 case GL_TEXTURE_IMMUTABLE_LEVELS:
5070 case GL_TEXTURE_SWIZZLE_R:
5071 case GL_TEXTURE_SWIZZLE_G:
5072 case GL_TEXTURE_SWIZZLE_B:
5073 case GL_TEXTURE_SWIZZLE_A:
5074 case GL_TEXTURE_BASE_LEVEL:
5075 case GL_TEXTURE_MAX_LEVEL:
5076 case GL_TEXTURE_MIN_LOD:
5077 case GL_TEXTURE_MAX_LOD:
5078 case GL_TEXTURE_COMPARE_MODE:
5079 case GL_TEXTURE_COMPARE_FUNC:
5080 if (context->getClientMajorVersion() < 3)
5081 {
5082 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
5083 return false;
5084 }
5085 break;
5086
5087 case GL_TEXTURE_SRGB_DECODE_EXT:
5088 if (!context->getExtensions().textureSRGBDecode)
5089 {
5090 context->handleError(
5091 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
5092 return false;
5093 }
5094 break;
5095
5096 default:
5097 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5098 return false;
5099 }
5100
5101 if (length)
5102 {
5103 *length = 1;
5104 }
5105 return true;
5106}
5107
5108bool ValidateGetVertexAttribBase(Context *context,
5109 GLuint index,
5110 GLenum pname,
5111 GLsizei *length,
5112 bool pointer,
5113 bool pureIntegerEntryPoint)
5114{
5115 if (length)
5116 {
5117 *length = 0;
5118 }
5119
5120 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
5121 {
5122 context->handleError(
5123 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
5124 return false;
5125 }
5126
5127 if (index >= context->getCaps().maxVertexAttributes)
5128 {
5129 context->handleError(Error(
5130 GL_INVALID_VALUE, "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES."));
5131 return false;
5132 }
5133
5134 if (pointer)
5135 {
5136 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
5137 {
5138 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5139 return false;
5140 }
5141 }
5142 else
5143 {
5144 switch (pname)
5145 {
5146 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
5147 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
5148 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
5149 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
5150 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
5151 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
5152 case GL_CURRENT_VERTEX_ATTRIB:
5153 break;
5154
5155 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
5156 static_assert(
5157 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
5158 "ANGLE extension enums not equal to GL enums.");
5159 if (context->getClientMajorVersion() < 3 &&
5160 !context->getExtensions().instancedArrays)
5161 {
5162 context->handleError(Error(GL_INVALID_ENUM,
5163 "GL_VERTEX_ATTRIB_ARRAY_DIVISOR requires OpenGL ES "
5164 "3.0 or GL_ANGLE_instanced_arrays."));
5165 return false;
5166 }
5167 break;
5168
5169 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
5170 if (context->getClientMajorVersion() < 3)
5171 {
5172 context->handleError(Error(
5173 GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
5174 return false;
5175 }
5176 break;
5177
5178 case GL_VERTEX_ATTRIB_BINDING:
5179 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
5180 if (context->getClientVersion() < ES_3_1)
5181 {
5182 context->handleError(
5183 Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
5184 return false;
5185 }
5186 break;
5187
5188 default:
5189 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5190 return false;
5191 }
5192 }
5193
5194 if (length)
5195 {
5196 if (pname == GL_CURRENT_VERTEX_ATTRIB)
5197 {
5198 *length = 4;
5199 }
5200 else
5201 {
5202 *length = 1;
5203 }
5204 }
5205
5206 return true;
5207}
5208
5209bool ValidateReadPixelsBase(ValidationContext *context,
5210 GLint x,
5211 GLint y,
5212 GLsizei width,
5213 GLsizei height,
5214 GLenum format,
5215 GLenum type,
5216 GLsizei bufSize,
5217 GLsizei *length,
5218 GLsizei *columns,
5219 GLsizei *rows,
5220 void *pixels)
5221{
5222 if (length != nullptr)
5223 {
5224 *length = 0;
5225 }
5226 if (rows != nullptr)
5227 {
5228 *rows = 0;
5229 }
5230 if (columns != nullptr)
5231 {
5232 *columns = 0;
5233 }
5234
5235 if (width < 0 || height < 0)
5236 {
5237 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
5238 return false;
5239 }
5240
5241 auto readFramebuffer = context->getGLState().getReadFramebuffer();
5242
5243 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
5244 {
5245 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
5246 return false;
5247 }
5248
5249 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
5250 {
5251 context->handleError(Error(GL_INVALID_OPERATION));
5252 return false;
5253 }
5254
5255 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
5256 ASSERT(framebuffer);
5257
5258 if (framebuffer->getReadBufferState() == GL_NONE)
5259 {
5260 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
5261 return false;
5262 }
5263
5264 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
5265 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
5266 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
5267 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
5268 // situation is an application error that would lead to a crash in ANGLE.
5269 if (readBuffer == nullptr)
5270 {
5271 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
5272 return false;
5273 }
5274
5275 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
5276 GLenum currentType = framebuffer->getImplementationColorReadType();
5277 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
5278
5279 bool validFormatTypeCombination =
5280 ValidReadPixelsFormatType(context, currentComponentType, format, type);
5281
5282 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
5283 {
5284 context->handleError(Error(GL_INVALID_OPERATION));
5285 return false;
5286 }
5287
5288 // Check for pixel pack buffer related API errors
5289 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
5290 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
5291 {
5292 // ...the buffer object's data store is currently mapped.
5293 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
5294 return false;
5295 }
5296
5297 // .. the data would be packed to the buffer object such that the memory writes required
5298 // would exceed the data store size.
5299 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
5300 const gl::Extents size(width, height, 1);
5301 const auto &pack = context->getGLState().getPackState();
5302
5303 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
5304 if (endByteOrErr.isError())
5305 {
5306 context->handleError(endByteOrErr.getError());
5307 return false;
5308 }
5309
5310 size_t endByte = endByteOrErr.getResult();
5311 if (bufSize >= 0)
5312 {
5313 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
5314 {
5315 context->handleError(
5316 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
5317 return false;
5318 }
5319 }
5320
5321 if (pixelPackBuffer != nullptr)
5322 {
5323 CheckedNumeric<size_t> checkedEndByte(endByte);
5324 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
5325 checkedEndByte += checkedOffset;
5326
5327 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
5328 {
5329 // Overflow past the end of the buffer
5330 context->handleError(
5331 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
5332 return false;
5333 }
5334 }
5335
5336 if (pixelPackBuffer == nullptr && length != nullptr)
5337 {
5338 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
5339 {
5340 context->handleError(
5341 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
5342 return false;
5343 }
5344
5345 *length = static_cast<GLsizei>(endByte);
5346 }
5347
5348 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
5349 angle::CheckedNumeric<int> clippedExtent(length);
5350 if (start < 0)
5351 {
5352 // "subtract" the area that is less than 0
5353 clippedExtent += start;
5354 }
5355
5356 const int readExtent = start + length;
5357 if (readExtent > bufferSize)
5358 {
5359 // Subtract the region to the right of the read buffer
5360 clippedExtent -= (readExtent - bufferSize);
5361 }
5362
5363 if (!clippedExtent.IsValid())
5364 {
5365 return 0;
5366 }
5367
5368 return std::max(clippedExtent.ValueOrDie(), 0);
5369 };
5370
5371 if (columns != nullptr)
5372 {
5373 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
5374 }
5375
5376 if (rows != nullptr)
5377 {
5378 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
5379 }
5380
5381 return true;
5382}
5383
5384template <typename ParamType>
5385bool ValidateTexParameterBase(Context *context,
5386 GLenum target,
5387 GLenum pname,
5388 GLsizei bufSize,
5389 const ParamType *params)
5390{
5391 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5392 {
5393 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
5394 return false;
5395 }
5396
5397 if (context->getTargetTexture(target) == nullptr)
5398 {
5399 // Should only be possible for external textures
5400 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
5401 return false;
5402 }
5403
5404 const GLsizei minBufSize = 1;
5405 if (bufSize >= 0 && bufSize < minBufSize)
5406 {
5407 context->handleError(
5408 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
5409 return false;
5410 }
5411
5412 switch (pname)
5413 {
5414 case GL_TEXTURE_WRAP_R:
5415 case GL_TEXTURE_SWIZZLE_R:
5416 case GL_TEXTURE_SWIZZLE_G:
5417 case GL_TEXTURE_SWIZZLE_B:
5418 case GL_TEXTURE_SWIZZLE_A:
5419 case GL_TEXTURE_BASE_LEVEL:
5420 case GL_TEXTURE_MAX_LEVEL:
5421 case GL_TEXTURE_COMPARE_MODE:
5422 case GL_TEXTURE_COMPARE_FUNC:
5423 case GL_TEXTURE_MIN_LOD:
5424 case GL_TEXTURE_MAX_LOD:
5425 if (context->getClientMajorVersion() < 3)
5426 {
5427 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
5428 return false;
5429 }
5430 if (target == GL_TEXTURE_EXTERNAL_OES &&
5431 !context->getExtensions().eglImageExternalEssl3)
5432 {
5433 context->handleError(Error(GL_INVALID_ENUM,
5434 "ES3 texture parameters are not available without "
5435 "GL_OES_EGL_image_external_essl3."));
5436 return false;
5437 }
5438 break;
5439
5440 default:
5441 break;
5442 }
5443
5444 switch (pname)
5445 {
5446 case GL_TEXTURE_WRAP_S:
5447 case GL_TEXTURE_WRAP_T:
5448 case GL_TEXTURE_WRAP_R:
5449 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5450 {
5451 return false;
5452 }
5453 break;
5454
5455 case GL_TEXTURE_MIN_FILTER:
5456 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5457 {
5458 return false;
5459 }
5460 break;
5461
5462 case GL_TEXTURE_MAG_FILTER:
5463 if (!ValidateTextureMagFilterValue(context, params))
5464 {
5465 return false;
5466 }
5467 break;
5468
5469 case GL_TEXTURE_USAGE_ANGLE:
5470 switch (ConvertToGLenum(params[0]))
5471 {
5472 case GL_NONE:
5473 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
5474 break;
5475
5476 default:
5477 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5478 return false;
5479 }
5480 break;
5481
5482 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5483 if (!context->getExtensions().textureFilterAnisotropic)
5484 {
5485 context->handleError(
5486 Error(GL_INVALID_ENUM, "GL_EXT_texture_anisotropic is not enabled."));
5487 return false;
5488 }
5489
5490 // we assume the parameter passed to this validation method is truncated, not rounded
5491 if (params[0] < 1)
5492 {
5493 context->handleError(Error(GL_INVALID_VALUE, "Max anisotropy must be at least 1."));
5494 return false;
5495 }
5496 break;
5497
5498 case GL_TEXTURE_MIN_LOD:
5499 case GL_TEXTURE_MAX_LOD:
5500 // any value is permissible
5501 break;
5502
5503 case GL_TEXTURE_COMPARE_MODE:
5504 if (!ValidateTextureCompareModeValue(context, params))
5505 {
5506 return false;
5507 }
5508 break;
5509
5510 case GL_TEXTURE_COMPARE_FUNC:
5511 if (!ValidateTextureCompareFuncValue(context, params))
5512 {
5513 return false;
5514 }
5515 break;
5516
5517 case GL_TEXTURE_SWIZZLE_R:
5518 case GL_TEXTURE_SWIZZLE_G:
5519 case GL_TEXTURE_SWIZZLE_B:
5520 case GL_TEXTURE_SWIZZLE_A:
5521 switch (ConvertToGLenum(params[0]))
5522 {
5523 case GL_RED:
5524 case GL_GREEN:
5525 case GL_BLUE:
5526 case GL_ALPHA:
5527 case GL_ZERO:
5528 case GL_ONE:
5529 break;
5530
5531 default:
5532 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5533 return false;
5534 }
5535 break;
5536
5537 case GL_TEXTURE_BASE_LEVEL:
5538 if (params[0] < 0)
5539 {
5540 context->handleError(Error(GL_INVALID_VALUE, "Base level must be at least 0."));
5541 return false;
5542 }
5543 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
5544 {
5545 context->handleError(
5546 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
5547 return false;
5548 }
5549 break;
5550
5551 case GL_TEXTURE_MAX_LEVEL:
5552 if (params[0] < 0)
5553 {
5554 context->handleError(Error(GL_INVALID_VALUE, "Max level must be at least 0."));
5555 return false;
5556 }
5557 break;
5558
5559 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5560 if (context->getClientVersion() < Version(3, 1))
5561 {
5562 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.1."));
5563 return false;
5564 }
5565 switch (ConvertToGLenum(params[0]))
5566 {
5567 case GL_DEPTH_COMPONENT:
5568 case GL_STENCIL_INDEX:
5569 break;
5570
5571 default:
5572 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5573 return false;
5574 }
5575 break;
5576
5577 case GL_TEXTURE_SRGB_DECODE_EXT:
5578 if (!ValidateTextureSRGBDecodeValue(context, params))
5579 {
5580 return false;
5581 }
5582 break;
5583
5584 default:
5585 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5586 return false;
5587 }
5588
5589 return true;
5590}
5591
5592template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *);
5593template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *);
5594
Jamie Madillc29968b2016-01-20 11:17:23 -05005595} // namespace gl