blob: 8fe9d4960dd6ea284f0e344c6c0b4f534e97db24 [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 Lang9ab5b822017-05-30 16:19:23 -0400743bool ValidateVertexShaderAttributeTypeMatch(ValidationContext *context)
744{
745 const Program *program = context->getGLState().getProgram();
746 const VertexArray *vao = context->getGLState().getVertexArray();
747
748 for (const auto &shaderAttribute : program->getAttributes())
749 {
750 GLenum shaderInputType = VariableComponentType(shaderAttribute.type);
751
752 const auto &attrib = vao->getVertexAttribute(shaderAttribute.location);
753 const auto &currentValue =
754 context->getGLState().getVertexAttribCurrentValue(shaderAttribute.location);
755 GLenum vertexType = attrib.enabled ? GetVertexAttributeBaseType(attrib) : currentValue.Type;
756
757 if (shaderInputType != GL_NONE && vertexType != GL_NONE && shaderInputType != vertexType)
758 {
759 context->handleError(Error(
760 GL_INVALID_OPERATION,
761 "Vertex shader input type does not match the type of the bound vertex attribute."));
762 return false;
763 }
764 }
765
766 return true;
767}
768
Geoff Langf41a7152016-09-19 15:11:17 -0400769} // anonymous namespace
770
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500771bool ValidTextureTarget(const ValidationContext *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -0400772{
Jamie Madilld7460c72014-01-21 16:38:14 -0500773 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -0400774 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800775 case GL_TEXTURE_2D:
776 case GL_TEXTURE_CUBE_MAP:
777 return true;
Jamie Madill35d15012013-10-07 10:46:37 -0400778
He Yunchaoced53ae2016-11-29 15:00:51 +0800779 case GL_TEXTURE_3D:
780 case GL_TEXTURE_2D_ARRAY:
781 return (context->getClientMajorVersion() >= 3);
Jamie Madilld7460c72014-01-21 16:38:14 -0500782
He Yunchaoced53ae2016-11-29 15:00:51 +0800783 case GL_TEXTURE_2D_MULTISAMPLE:
He Yunchaoced53ae2016-11-29 15:00:51 +0800784 return (context->getClientVersion() >= Version(3, 1));
Geoff Lang3b573612016-10-31 14:08:10 -0400785
He Yunchaoced53ae2016-11-29 15:00:51 +0800786 default:
787 return false;
Jamie Madilld7460c72014-01-21 16:38:14 -0500788 }
Jamie Madill35d15012013-10-07 10:46:37 -0400789}
790
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500791bool ValidTexture2DTarget(const ValidationContext *context, GLenum target)
792{
793 switch (target)
794 {
795 case GL_TEXTURE_2D:
796 case GL_TEXTURE_CUBE_MAP:
797 return true;
798
799 default:
800 return false;
801 }
802}
803
804bool ValidTexture3DTarget(const ValidationContext *context, GLenum target)
805{
806 switch (target)
807 {
808 case GL_TEXTURE_3D:
809 case GL_TEXTURE_2D_ARRAY:
Martin Radev1be913c2016-07-11 17:59:16 +0300810 return (context->getClientMajorVersion() >= 3);
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500811
812 default:
813 return false;
814 }
815}
816
Ian Ewellbda75592016-04-18 17:25:54 -0400817// Most texture GL calls are not compatible with external textures, so we have a separate validation
818// function for use in the GL calls that do
819bool ValidTextureExternalTarget(const ValidationContext *context, GLenum target)
820{
821 return (target == GL_TEXTURE_EXTERNAL_OES) &&
822 (context->getExtensions().eglImageExternal ||
823 context->getExtensions().eglStreamConsumerExternal);
824}
825
Shannon Woods4dfed832014-03-17 20:03:39 -0400826// This function differs from ValidTextureTarget in that the target must be
827// usable as the destination of a 2D operation-- so a cube face is valid, but
828// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -0400829// Note: duplicate of IsInternalTextureTarget
Jamie Madillc29968b2016-01-20 11:17:23 -0500830bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum target)
Shannon Woods4dfed832014-03-17 20:03:39 -0400831{
832 switch (target)
833 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800834 case GL_TEXTURE_2D:
835 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
836 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
837 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
838 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
839 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
840 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
841 return true;
842 default:
843 return false;
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500844 }
845}
846
Jamie Madillbe849e42017-05-02 15:49:00 -0400847bool ValidateDrawElementsInstancedBase(ValidationContext *context,
848 GLenum mode,
849 GLsizei count,
850 GLenum type,
851 const GLvoid *indices,
852 GLsizei primcount)
853{
854 if (primcount < 0)
855 {
856 context->handleError(Error(GL_INVALID_VALUE, "primcount cannot be negative."));
857 return false;
858 }
859
860 if (!ValidateDrawElementsCommon(context, mode, count, type, indices, primcount))
861 {
862 return false;
863 }
864
865 // No-op zero primitive count
866 return (primcount > 0);
867}
868
869bool ValidateDrawArraysInstancedBase(Context *context,
870 GLenum mode,
871 GLint first,
872 GLsizei count,
873 GLsizei primcount)
874{
875 if (primcount < 0)
876 {
877 context->handleError(Error(GL_INVALID_VALUE, "primcount cannot be negative."));
878 return false;
879 }
880
881 if (!ValidateDrawArraysCommon(context, mode, first, count, primcount))
882 {
883 return false;
884 }
885
886 // No-op if zero primitive count
887 return (primcount > 0);
888}
889
890bool ValidateDrawInstancedANGLEAndWebGL(ValidationContext *context)
891{
892 // Verify there is at least one active attribute with a divisor of zero
893 const State &state = context->getGLState();
894
895 Program *program = state.getProgram();
896
897 const auto &attribs = state.getVertexArray()->getVertexAttributes();
898 const auto &bindings = state.getVertexArray()->getVertexBindings();
899 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
900 {
901 const VertexAttribute &attrib = attribs[attributeIndex];
902 const VertexBinding &binding = bindings[attrib.bindingIndex];
903 if (program->isAttribLocationActive(attributeIndex) && binding.divisor == 0)
904 {
905 return true;
906 }
907 }
908
909 context->handleError(
910 Error(GL_INVALID_OPERATION, "At least one attribute must have a divisor of zero."));
911 return false;
912}
913
Ian Ewellfc7cf8e2016-01-20 15:57:46 -0500914bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target)
915{
916 switch (target)
917 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800918 case GL_TEXTURE_3D:
919 case GL_TEXTURE_2D_ARRAY:
920 return true;
921 default:
922 return false;
Shannon Woods4dfed832014-03-17 20:03:39 -0400923 }
924}
925
He Yunchao11b038b2016-11-22 21:24:04 +0800926bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target)
927{
928 switch (target)
929 {
930 case GL_TEXTURE_2D:
931 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
932 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
933 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
934 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
935 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
936 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
937 case GL_TEXTURE_3D:
938 case GL_TEXTURE_2D_ARRAY:
939 case GL_TEXTURE_2D_MULTISAMPLE:
940 return true;
941 default:
942 return false;
943 }
944}
945
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500946bool ValidFramebufferTarget(GLenum target)
947{
He Yunchaoced53ae2016-11-29 15:00:51 +0800948 static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER &&
949 GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER,
Geoff Langd4475812015-03-18 10:53:05 -0400950 "ANGLE framebuffer enums must equal the ES3 framebuffer enums.");
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500951
952 switch (target)
953 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800954 case GL_FRAMEBUFFER:
955 return true;
956 case GL_READ_FRAMEBUFFER:
957 return true;
958 case GL_DRAW_FRAMEBUFFER:
959 return true;
960 default:
961 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500962 }
963}
964
Jamie Madill29639852016-09-02 15:00:09 -0400965bool ValidBufferTarget(const ValidationContext *context, GLenum target)
Jamie Madill8c96d582014-03-05 15:01:23 -0500966{
967 switch (target)
968 {
He Yunchaoced53ae2016-11-29 15:00:51 +0800969 case GL_ARRAY_BUFFER:
970 case GL_ELEMENT_ARRAY_BUFFER:
971 return true;
Jamie Madill8c96d582014-03-05 15:01:23 -0500972
He Yunchaoced53ae2016-11-29 15:00:51 +0800973 case GL_PIXEL_PACK_BUFFER:
974 case GL_PIXEL_UNPACK_BUFFER:
975 return (context->getExtensions().pixelBufferObject ||
976 context->getClientMajorVersion() >= 3);
Shannon Woods158c4382014-05-06 13:00:07 -0400977
He Yunchaoced53ae2016-11-29 15:00:51 +0800978 case GL_COPY_READ_BUFFER:
979 case GL_COPY_WRITE_BUFFER:
980 case GL_TRANSFORM_FEEDBACK_BUFFER:
981 case GL_UNIFORM_BUFFER:
982 return (context->getClientMajorVersion() >= 3);
Jamie Madill8c96d582014-03-05 15:01:23 -0500983
He Yunchaoced53ae2016-11-29 15:00:51 +0800984 case GL_ATOMIC_COUNTER_BUFFER:
985 case GL_SHADER_STORAGE_BUFFER:
986 case GL_DRAW_INDIRECT_BUFFER:
987 case GL_DISPATCH_INDIRECT_BUFFER:
He Yunchaoced53ae2016-11-29 15:00:51 +0800988 return context->getClientVersion() >= Version(3, 1);
Geoff Lang3b573612016-10-31 14:08:10 -0400989
He Yunchaoced53ae2016-11-29 15:00:51 +0800990 default:
991 return false;
Jamie Madill8c96d582014-03-05 15:01:23 -0500992 }
993}
994
Jamie Madillc29968b2016-01-20 11:17:23 -0500995bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400996{
Jamie Madillc29968b2016-01-20 11:17:23 -0500997 const auto &caps = context->getCaps();
Geoff Langaae65a42014-05-26 12:43:44 -0400998 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400999 switch (target)
1000 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001001 case GL_TEXTURE_2D:
1002 maxDimension = caps.max2DTextureSize;
1003 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08001004 case GL_TEXTURE_CUBE_MAP:
1005 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1006 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1007 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1008 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1009 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1010 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1011 maxDimension = caps.maxCubeMapTextureSize;
1012 break;
1013 case GL_TEXTURE_3D:
1014 maxDimension = caps.max3DTextureSize;
1015 break;
1016 case GL_TEXTURE_2D_ARRAY:
1017 maxDimension = caps.max2DTextureSize;
1018 break;
He Yunchao11b038b2016-11-22 21:24:04 +08001019 case GL_TEXTURE_2D_MULTISAMPLE:
1020 maxDimension = caps.max2DTextureSize;
1021 break;
He Yunchaoced53ae2016-11-29 15:00:51 +08001022 default:
1023 UNREACHABLE();
Geoff Langce635692013-09-24 13:56:32 -04001024 }
1025
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001026 return level <= gl::log2(static_cast<int>(maxDimension));
Geoff Langce635692013-09-24 13:56:32 -04001027}
1028
Geoff Langcc507aa2016-12-12 10:09:52 -05001029bool ValidImageSizeParameters(const ValidationContext *context,
Austin Kinross08528e12015-10-07 16:24:40 -07001030 GLenum target,
1031 GLint level,
1032 GLsizei width,
1033 GLsizei height,
1034 GLsizei depth,
1035 bool isSubImage)
Geoff Langce635692013-09-24 13:56:32 -04001036{
1037 if (level < 0 || width < 0 || height < 0 || depth < 0)
1038 {
1039 return false;
1040 }
1041
Austin Kinross08528e12015-10-07 16:24:40 -07001042 // TexSubImage parameters can be NPOT without textureNPOT extension,
1043 // as long as the destination texture is POT.
Geoff Langcc507aa2016-12-12 10:09:52 -05001044 bool hasNPOTSupport =
Geoff Lang5f319a42017-01-09 16:49:19 -05001045 context->getExtensions().textureNPOT || context->getClientVersion() >= Version(3, 0);
Geoff Langcc507aa2016-12-12 10:09:52 -05001046 if (!isSubImage && !hasNPOTSupport &&
Jamie Madill4fd75c12014-06-23 10:53:54 -04001047 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -04001048 {
1049 return false;
1050 }
1051
1052 if (!ValidMipLevel(context, target, level))
1053 {
1054 return false;
1055 }
1056
1057 return true;
1058}
1059
Geoff Lang0d8b7242015-09-09 14:56:53 -04001060bool CompressedTextureFormatRequiresExactSize(GLenum internalFormat)
1061{
1062 // List of compressed format that require that the texture size is smaller than or a multiple of
1063 // the compressed block size.
1064 switch (internalFormat)
1065 {
1066 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1067 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1068 case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
1069 case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
Minmin Gonge3939b92015-12-01 15:36:51 -08001070 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08001071 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1072 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1073 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1074 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1075 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
1076 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04001077 return true;
1078
1079 default:
1080 return false;
1081 }
1082}
1083
Geoff Lang966c9402017-04-18 12:38:27 -04001084bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed)
1085{
1086 return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) ||
1087 (size % blockSize == 0);
1088}
1089
Jamie Madillc29968b2016-01-20 11:17:23 -05001090bool ValidCompressedImageSize(const ValidationContext *context,
1091 GLenum internalFormat,
Geoff Lang966c9402017-04-18 12:38:27 -04001092 GLint level,
Jamie Madillc29968b2016-01-20 11:17:23 -05001093 GLsizei width,
1094 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04001095{
Geoff Langca271392017-04-05 12:30:00 -04001096 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04001097 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04001098 {
1099 return false;
1100 }
1101
Geoff Lang966c9402017-04-18 12:38:27 -04001102 if (width < 0 || height < 0)
1103 {
1104 return false;
1105 }
1106
1107 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1108 {
1109 // The ANGLE extensions allow specifying compressed textures with sizes smaller than the
1110 // block size for level 0 but WebGL disallows this.
1111 bool smallerThanBlockSizeAllowed =
1112 level > 0 || !context->getExtensions().webglCompatibility;
1113
1114 if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth,
1115 smallerThanBlockSizeAllowed) ||
1116 !ValidCompressedDimension(height, formatInfo.compressedBlockHeight,
1117 smallerThanBlockSizeAllowed))
1118 {
1119 return false;
1120 }
1121 }
1122
1123 return true;
1124}
1125
1126bool ValidCompressedSubImageSize(const ValidationContext *context,
1127 GLenum internalFormat,
1128 GLint xoffset,
1129 GLint yoffset,
1130 GLsizei width,
1131 GLsizei height,
1132 size_t textureWidth,
1133 size_t textureHeight)
1134{
1135 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1136 if (!formatInfo.compressed)
1137 {
1138 return false;
1139 }
1140
Geoff Lang44ff5a72017-02-03 15:15:43 -05001141 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04001142 {
1143 return false;
1144 }
1145
Geoff Lang0d8b7242015-09-09 14:56:53 -04001146 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1147 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05001148 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
Geoff Lang966c9402017-04-18 12:38:27 -04001149 yoffset % formatInfo.compressedBlockHeight != 0)
1150 {
1151 return false;
1152 }
1153
1154 // Allowed to either have data that is a multiple of block size or is smaller than the block
1155 // size but fills the entire mip
1156 bool fillsEntireMip = xoffset == 0 && yoffset == 0 &&
1157 static_cast<size_t>(width) == textureWidth &&
1158 static_cast<size_t>(height) == textureHeight;
1159 bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
1160 (height % formatInfo.compressedBlockHeight) == 0;
1161 if (!sizeMultipleOfBlockSize && !fillsEntireMip)
Geoff Lang0d8b7242015-09-09 14:56:53 -04001162 {
1163 return false;
1164 }
1165 }
1166
Geoff Langd4f180b2013-09-24 13:57:44 -04001167 return true;
1168}
1169
Geoff Langff5b2d52016-09-07 11:32:23 -04001170bool ValidImageDataSize(ValidationContext *context,
1171 GLenum textureTarget,
1172 GLsizei width,
1173 GLsizei height,
1174 GLsizei depth,
1175 GLenum internalFormat,
1176 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001177 const void *pixels,
Geoff Langff5b2d52016-09-07 11:32:23 -04001178 GLsizei imageSize)
1179{
1180 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
1181 if (pixelUnpackBuffer == nullptr && imageSize < 0)
1182 {
1183 // Checks are not required
1184 return true;
1185 }
1186
1187 // ...the data would be unpacked from the buffer object such that the memory reads required
1188 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -04001189 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
Geoff Langff5b2d52016-09-07 11:32:23 -04001190 const gl::Extents size(width, height, depth);
1191 const auto &unpack = context->getGLState().getUnpackState();
1192
1193 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
1194 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
1195 if (endByteOrErr.isError())
1196 {
1197 context->handleError(endByteOrErr.getError());
1198 return false;
1199 }
1200
1201 GLuint endByte = endByteOrErr.getResult();
1202
1203 if (pixelUnpackBuffer)
1204 {
1205 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
1206 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
1207 checkedEndByte += checkedOffset;
1208
1209 if (!checkedEndByte.IsValid() ||
1210 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
1211 {
1212 // Overflow past the end of the buffer
1213 context->handleError(Error(GL_INVALID_OPERATION));
1214 return false;
1215 }
1216 }
1217 else
1218 {
1219 ASSERT(imageSize >= 0);
1220 if (pixels == nullptr && imageSize != 0)
1221 {
1222 context->handleError(
1223 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001224 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04001225 }
1226
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001227 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04001228 {
1229 context->handleError(
1230 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
1231 return false;
1232 }
1233 }
1234
1235 return true;
1236}
1237
Geoff Lang37dde692014-01-31 16:34:54 -05001238bool ValidQueryType(const Context *context, GLenum queryType)
1239{
He Yunchaoced53ae2016-11-29 15:00:51 +08001240 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
1241 "GL extension enums not equal.");
1242 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1243 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05001244
1245 switch (queryType)
1246 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001247 case GL_ANY_SAMPLES_PASSED:
1248 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
1249 return true;
1250 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1251 return (context->getClientMajorVersion() >= 3);
1252 case GL_TIME_ELAPSED_EXT:
1253 return context->getExtensions().disjointTimerQuery;
1254 case GL_COMMANDS_COMPLETED_CHROMIUM:
1255 return context->getExtensions().syncQuery;
1256 default:
1257 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05001258 }
1259}
1260
Geoff Lang2d62ab72017-03-23 16:54:40 -04001261bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
1262 GLenum type,
1263 GLboolean normalized,
1264 GLsizei stride,
Jamie Madill876429b2017-04-20 15:46:24 -04001265 const void *ptr,
Geoff Lang2d62ab72017-03-23 16:54:40 -04001266 bool pureInteger)
1267{
1268 ASSERT(context->getExtensions().webglCompatibility);
1269
1270 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
1271 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
1272 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
1273 // parameter exceeds 255.
1274 constexpr GLsizei kMaxWebGLStride = 255;
1275 if (stride > kMaxWebGLStride)
1276 {
1277 context->handleError(
1278 Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
1279 return false;
1280 }
1281
1282 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
1283 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
1284 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
1285 // or an INVALID_OPERATION error is generated.
1286 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
1287 size_t typeSize = GetVertexFormatTypeSize(internalType);
1288
1289 ASSERT(isPow2(typeSize) && typeSize > 0);
1290 size_t sizeMask = (typeSize - 1);
1291 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
1292 {
1293 context->handleError(
1294 Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
1295 return false;
1296 }
1297
1298 if ((stride & sizeMask) != 0)
1299 {
1300 context->handleError(
1301 Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
1302 return false;
1303 }
1304
1305 return true;
1306}
1307
Jamie Madillef300b12016-10-07 15:12:09 -04001308Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05001309{
He Yunchaoced53ae2016-11-29 15:00:51 +08001310 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
1311 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
1312 // or program object and INVALID_OPERATION if the provided name identifies an object
1313 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05001314
Dian Xiang769769a2015-09-09 15:20:08 -07001315 Program *validProgram = context->getProgram(id);
1316
1317 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05001318 {
Dian Xiang769769a2015-09-09 15:20:08 -07001319 if (context->getShader(id))
1320 {
Jamie Madill437fa652016-05-03 15:13:24 -04001321 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07001322 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
1323 }
1324 else
1325 {
Jamie Madill437fa652016-05-03 15:13:24 -04001326 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -07001327 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001328 }
Dian Xiang769769a2015-09-09 15:20:08 -07001329
1330 return validProgram;
1331}
1332
Jamie Madillef300b12016-10-07 15:12:09 -04001333Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07001334{
1335 // See ValidProgram for spec details.
1336
1337 Shader *validShader = context->getShader(id);
1338
1339 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05001340 {
Dian Xiang769769a2015-09-09 15:20:08 -07001341 if (context->getProgram(id))
1342 {
Jamie Madill437fa652016-05-03 15:13:24 -04001343 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07001344 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
1345 }
1346 else
1347 {
Jamie Madill437fa652016-05-03 15:13:24 -04001348 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -07001349 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001350 }
Dian Xiang769769a2015-09-09 15:20:08 -07001351
1352 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05001353}
1354
Geoff Langb1196682014-07-23 13:47:29 -04001355bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04001356{
1357 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
1358 {
1359 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
1360
Geoff Langaae65a42014-05-26 12:43:44 -04001361 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04001362 {
Jamie Madill437fa652016-05-03 15:13:24 -04001363 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001364 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001365 }
1366 }
1367 else
1368 {
1369 switch (attachment)
1370 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001371 case GL_DEPTH_ATTACHMENT:
1372 case GL_STENCIL_ATTACHMENT:
1373 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001374
He Yunchaoced53ae2016-11-29 15:00:51 +08001375 case GL_DEPTH_STENCIL_ATTACHMENT:
1376 if (!context->getExtensions().webglCompatibility &&
1377 context->getClientMajorVersion() < 3)
1378 {
1379 context->handleError(Error(GL_INVALID_ENUM));
1380 return false;
1381 }
1382 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001383
He Yunchaoced53ae2016-11-29 15:00:51 +08001384 default:
1385 context->handleError(Error(GL_INVALID_ENUM));
1386 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001387 }
1388 }
1389
1390 return true;
1391}
1392
Jamie Madille8fb6402017-02-14 17:56:40 -05001393bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08001394 GLenum target,
1395 GLsizei samples,
1396 GLenum internalformat,
1397 GLsizei width,
1398 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001399{
1400 switch (target)
1401 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001402 case GL_RENDERBUFFER:
1403 break;
1404 default:
1405 context->handleError(Error(GL_INVALID_ENUM));
1406 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001407 }
1408
1409 if (width < 0 || height < 0 || samples < 0)
1410 {
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 Madill4e0e6f82017-02-17 11:06:03 -05001415 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
1416 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
1417
1418 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04001419 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001420 {
Jamie Madill437fa652016-05-03 15:13:24 -04001421 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001422 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001423 }
1424
1425 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
1426 // 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 -08001427 // only sized internal formats.
Geoff Langca271392017-04-05 12:30:00 -04001428 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat);
1429 if (formatInfo.internalFormat == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001430 {
Jamie Madill437fa652016-05-03 15:13:24 -04001431 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001432 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001433 }
1434
Geoff Langaae65a42014-05-26 12:43:44 -04001435 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001436 {
Jamie Madill437fa652016-05-03 15:13:24 -04001437 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001438 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001439 }
1440
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001441 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001442 if (handle == 0)
1443 {
Jamie Madill437fa652016-05-03 15:13:24 -04001444 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001445 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001446 }
1447
1448 return true;
1449}
1450
He Yunchaoced53ae2016-11-29 15:00:51 +08001451bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
1452 GLenum target,
1453 GLenum attachment,
1454 GLenum renderbuffertarget,
1455 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001456{
Shannon Woods1da3cf62014-06-27 15:32:23 -04001457 if (!ValidFramebufferTarget(target))
1458 {
Jamie Madill437fa652016-05-03 15:13:24 -04001459 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001460 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04001461 }
1462
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001463 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001464
Jamie Madill84115c92015-04-23 15:00:07 -04001465 ASSERT(framebuffer);
1466 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001467 {
Jamie Madill437fa652016-05-03 15:13:24 -04001468 context->handleError(
1469 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001470 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001471 }
1472
Jamie Madillb4472272014-07-03 10:38:55 -04001473 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001474 {
Jamie Madillb4472272014-07-03 10:38:55 -04001475 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001476 }
1477
Jamie Madillab9d82c2014-01-21 16:38:14 -05001478 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1479 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1480 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1481 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1482 if (renderbuffer != 0)
1483 {
1484 if (!context->getRenderbuffer(renderbuffer))
1485 {
Jamie Madill437fa652016-05-03 15:13:24 -04001486 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001487 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05001488 }
1489 }
1490
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001491 return true;
1492}
1493
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001494bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001495 GLint srcX0,
1496 GLint srcY0,
1497 GLint srcX1,
1498 GLint srcY1,
1499 GLint dstX0,
1500 GLint dstY0,
1501 GLint dstX1,
1502 GLint dstY1,
1503 GLbitfield mask,
1504 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001505{
1506 switch (filter)
1507 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001508 case GL_NEAREST:
1509 break;
1510 case GL_LINEAR:
1511 break;
1512 default:
1513 context->handleError(Error(GL_INVALID_ENUM));
1514 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001515 }
1516
1517 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1518 {
Jamie Madill437fa652016-05-03 15:13:24 -04001519 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001520 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001521 }
1522
1523 if (mask == 0)
1524 {
1525 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
1526 // buffers are copied.
1527 return false;
1528 }
1529
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001530 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1531 // color buffer, leaving only nearest being unfiltered from above
1532 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1533 {
Jamie Madill437fa652016-05-03 15:13:24 -04001534 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001535 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001536 }
1537
Jamie Madill51f40ec2016-06-15 14:06:00 -04001538 const auto &glState = context->getGLState();
1539 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1540 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001541
1542 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001543 {
Jamie Madill437fa652016-05-03 15:13:24 -04001544 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001545 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001546 }
1547
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001548 if (readFramebuffer->id() == drawFramebuffer->id())
1549 {
1550 context->handleError(Error(GL_INVALID_OPERATION));
1551 return false;
1552 }
1553
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001554 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001555 {
Jamie Madill437fa652016-05-03 15:13:24 -04001556 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001557 return false;
1558 }
1559
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001560 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001561 {
Jamie Madill437fa652016-05-03 15:13:24 -04001562 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001563 return false;
1564 }
1565
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001566 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001567 {
Jamie Madill437fa652016-05-03 15:13:24 -04001568 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001569 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001570 }
1571
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001572 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1573
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001574 if (mask & GL_COLOR_BUFFER_BIT)
1575 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001576 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05001577 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001578
He Yunchao66a41a22016-12-15 16:45:05 +08001579 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001580 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001581 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001582
Geoff Langa15472a2015-08-11 11:48:03 -04001583 for (size_t drawbufferIdx = 0;
1584 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001585 {
Geoff Langa15472a2015-08-11 11:48:03 -04001586 const FramebufferAttachment *attachment =
1587 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1588 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001589 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001590 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001591
Geoff Langb2f3d052013-08-13 12:49:27 -04001592 // The GL ES 3.0.2 spec (pg 193) states that:
1593 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08001594 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
1595 // as well
1596 // 3) If the read buffer is a signed integer format, the draw buffer must be as
1597 // well
Jamie Madill6163c752015-12-07 16:32:59 -05001598 // Changes with EXT_color_buffer_float:
1599 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04001600 GLenum readComponentType = readFormat.info->componentType;
1601 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08001602 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05001603 readComponentType == GL_SIGNED_NORMALIZED);
1604 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1605 drawComponentType == GL_SIGNED_NORMALIZED);
1606
1607 if (extensions.colorBufferFloat)
1608 {
1609 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1610 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1611
1612 if (readFixedOrFloat != drawFixedOrFloat)
1613 {
Jamie Madill437fa652016-05-03 15:13:24 -04001614 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001615 "If the read buffer contains fixed-point or "
1616 "floating-point values, the draw buffer "
1617 "must as well."));
1618 return false;
1619 }
1620 }
1621 else if (readFixedPoint != drawFixedPoint)
1622 {
Jamie Madill437fa652016-05-03 15:13:24 -04001623 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001624 "If the read buffer contains fixed-point "
1625 "values, the draw buffer must as well."));
1626 return false;
1627 }
1628
1629 if (readComponentType == GL_UNSIGNED_INT &&
1630 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001631 {
Jamie Madill437fa652016-05-03 15:13:24 -04001632 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001633 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001634 }
1635
Jamie Madill6163c752015-12-07 16:32:59 -05001636 if (readComponentType == GL_INT && drawComponentType != GL_INT)
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 }
1641
Jamie Madilla3944d42016-07-22 22:13:26 -04001642 if (readColorBuffer->getSamples() > 0 &&
1643 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001644 {
Jamie Madill437fa652016-05-03 15:13:24 -04001645 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001646 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001647 }
Geoff Lange4915782017-04-12 15:19:07 -04001648
1649 if (context->getExtensions().webglCompatibility &&
1650 *readColorBuffer == *attachment)
1651 {
1652 context->handleError(
1653 Error(GL_INVALID_OPERATION,
1654 "Read and write color attachments cannot be the same image."));
1655 return false;
1656 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001657 }
1658 }
1659
Jamie Madilla3944d42016-07-22 22:13:26 -04001660 if ((readFormat.info->componentType == GL_INT ||
1661 readFormat.info->componentType == GL_UNSIGNED_INT) &&
1662 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001663 {
Jamie Madill437fa652016-05-03 15:13:24 -04001664 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001665 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001666 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001667 }
He Yunchao66a41a22016-12-15 16:45:05 +08001668 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1669 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
1670 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
1671 // situation is an application error that would lead to a crash in ANGLE.
1672 else if (drawFramebuffer->hasEnabledDrawBuffer())
1673 {
1674 context->handleError(Error(
1675 GL_INVALID_OPERATION,
1676 "Attempt to read from a missing color attachment of a complete framebuffer."));
1677 return false;
1678 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001679 }
1680
He Yunchaoced53ae2016-11-29 15:00:51 +08001681 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001682 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1683 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001684 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001685 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001686 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001687 const gl::FramebufferAttachment *readBuffer =
1688 readFramebuffer->getAttachment(attachments[i]);
1689 const gl::FramebufferAttachment *drawBuffer =
1690 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001691
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001692 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001693 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001694 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001695 {
Jamie Madill437fa652016-05-03 15:13:24 -04001696 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001697 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001698 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001699
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001700 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001701 {
Jamie Madill437fa652016-05-03 15:13:24 -04001702 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001703 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001704 }
Geoff Lange4915782017-04-12 15:19:07 -04001705
1706 if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer)
1707 {
1708 context->handleError(Error(
1709 GL_INVALID_OPERATION,
1710 "Read and write depth stencil attachments cannot be the same image."));
1711 return false;
1712 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001713 }
He Yunchao66a41a22016-12-15 16:45:05 +08001714 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1715 else if (drawBuffer)
1716 {
1717 context->handleError(Error(GL_INVALID_OPERATION,
1718 "Attempt to read from a missing depth/stencil "
1719 "attachment of a complete framebuffer."));
1720 return false;
1721 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001722 }
1723 }
1724
1725 return true;
1726}
1727
Geoff Lang62fce5b2016-09-30 10:46:35 -04001728bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
1729 GLint x,
1730 GLint y,
1731 GLsizei width,
1732 GLsizei height,
1733 GLenum format,
1734 GLenum type,
1735 GLsizei bufSize,
1736 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001737 GLsizei *columns,
1738 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001739 void *pixels)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001740{
1741 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05001742 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001743 return false;
1744 }
1745
Geoff Lang62fce5b2016-09-30 10:46:35 -04001746 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04001747 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05001748 {
Geoff Langb1196682014-07-23 13:47:29 -04001749 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001750 }
1751
Geoff Lang62fce5b2016-09-30 10:46:35 -04001752 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05001753 {
Geoff Langb1196682014-07-23 13:47:29 -04001754 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001755 }
1756
Jamie Madillc29968b2016-01-20 11:17:23 -05001757 return true;
1758}
1759
1760bool ValidateReadnPixelsEXT(Context *context,
1761 GLint x,
1762 GLint y,
1763 GLsizei width,
1764 GLsizei height,
1765 GLenum format,
1766 GLenum type,
1767 GLsizei bufSize,
Jamie Madill876429b2017-04-20 15:46:24 -04001768 void *pixels)
Jamie Madillc29968b2016-01-20 11:17:23 -05001769{
1770 if (bufSize < 0)
1771 {
Jamie Madill437fa652016-05-03 15:13:24 -04001772 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001773 return false;
1774 }
1775
Geoff Lang62fce5b2016-09-30 10:46:35 -04001776 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04001777 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04001778}
Jamie Madill26e91952014-03-05 15:01:27 -05001779
Geoff Lang62fce5b2016-09-30 10:46:35 -04001780bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
1781 GLint x,
1782 GLint y,
1783 GLsizei width,
1784 GLsizei height,
1785 GLenum format,
1786 GLenum type,
1787 GLsizei bufSize,
1788 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001789 GLsizei *columns,
1790 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001791 void *data)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001792{
1793 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04001794 {
Jamie Madille2e406c2016-06-02 13:04:10 -04001795 return false;
1796 }
1797
Geoff Lange93daba2017-03-30 13:54:40 -04001798 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
1799 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04001800 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001801 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001802 }
1803
Geoff Lang62fce5b2016-09-30 10:46:35 -04001804 if (!ValidateRobustBufferSize(context, bufSize, *length))
1805 {
1806 return false;
1807 }
1808
1809 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05001810}
1811
Olli Etuaho41997e72016-03-10 13:38:39 +02001812bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001813{
1814 if (!context->getExtensions().occlusionQueryBoolean &&
1815 !context->getExtensions().disjointTimerQuery)
1816 {
Jamie Madill437fa652016-05-03 15:13:24 -04001817 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001818 return false;
1819 }
1820
Olli Etuaho41997e72016-03-10 13:38:39 +02001821 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001822}
1823
Olli Etuaho41997e72016-03-10 13:38:39 +02001824bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001825{
1826 if (!context->getExtensions().occlusionQueryBoolean &&
1827 !context->getExtensions().disjointTimerQuery)
1828 {
Jamie Madill437fa652016-05-03 15:13:24 -04001829 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001830 return false;
1831 }
1832
Olli Etuaho41997e72016-03-10 13:38:39 +02001833 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001834}
1835
1836bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001837{
1838 if (!ValidQueryType(context, target))
1839 {
Jamie Madill437fa652016-05-03 15:13:24 -04001840 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001841 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001842 }
1843
1844 if (id == 0)
1845 {
Jamie Madill437fa652016-05-03 15:13:24 -04001846 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001847 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001848 }
1849
1850 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1851 // of zero, if the active query object name for <target> is non-zero (for the
1852 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1853 // the active query for either target is non-zero), if <id> is the name of an
1854 // existing query object whose type does not match <target>, or if <id> is the
1855 // active query object name for any query type, the error INVALID_OPERATION is
1856 // generated.
1857
1858 // Ensure no other queries are active
1859 // NOTE: If other queries than occlusion are supported, we will need to check
1860 // separately that:
1861 // a) The query ID passed is not the current active query for any target/type
1862 // b) There are no active queries for the requested target (and in the case
1863 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1864 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001865
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001866 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001867 {
Jamie Madill437fa652016-05-03 15:13:24 -04001868 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001869 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001870 }
1871
1872 Query *queryObject = context->getQuery(id, true, target);
1873
1874 // check that name was obtained with glGenQueries
1875 if (!queryObject)
1876 {
Jamie Madill437fa652016-05-03 15:13:24 -04001877 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001878 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001879 }
1880
1881 // check for type mismatch
1882 if (queryObject->getType() != target)
1883 {
Jamie Madill437fa652016-05-03 15:13:24 -04001884 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001885 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001886 }
1887
1888 return true;
1889}
1890
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001891bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1892{
1893 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001894 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001895 {
Jamie Madill437fa652016-05-03 15:13:24 -04001896 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001897 return false;
1898 }
1899
1900 return ValidateBeginQueryBase(context, target, id);
1901}
1902
1903bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001904{
1905 if (!ValidQueryType(context, target))
1906 {
Jamie Madill437fa652016-05-03 15:13:24 -04001907 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001908 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001909 }
1910
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001911 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001912
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001913 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001914 {
Jamie Madill437fa652016-05-03 15:13:24 -04001915 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001916 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001917 }
1918
Jamie Madill45c785d2014-05-13 14:09:34 -04001919 return true;
1920}
1921
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001922bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1923{
1924 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001925 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001926 {
Jamie Madill437fa652016-05-03 15:13:24 -04001927 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001928 return false;
1929 }
1930
1931 return ValidateEndQueryBase(context, target);
1932}
1933
1934bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1935{
1936 if (!context->getExtensions().disjointTimerQuery)
1937 {
Jamie Madill437fa652016-05-03 15:13:24 -04001938 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001939 return false;
1940 }
1941
1942 if (target != GL_TIMESTAMP_EXT)
1943 {
Jamie Madill437fa652016-05-03 15:13:24 -04001944 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001945 return false;
1946 }
1947
1948 Query *queryObject = context->getQuery(id, true, target);
1949 if (queryObject == nullptr)
1950 {
Jamie Madill437fa652016-05-03 15:13:24 -04001951 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001952 return false;
1953 }
1954
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001955 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001956 {
Jamie Madill437fa652016-05-03 15:13:24 -04001957 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001958 return false;
1959 }
1960
1961 return true;
1962}
1963
Geoff Lang2186c382016-10-14 10:54:54 -04001964bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001965{
Geoff Lang2186c382016-10-14 10:54:54 -04001966 if (numParams)
1967 {
1968 *numParams = 0;
1969 }
1970
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001971 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1972 {
Jamie Madill437fa652016-05-03 15:13:24 -04001973 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001974 return false;
1975 }
1976
1977 switch (pname)
1978 {
1979 case GL_CURRENT_QUERY_EXT:
1980 if (target == GL_TIMESTAMP_EXT)
1981 {
Jamie Madill437fa652016-05-03 15:13:24 -04001982 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001983 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1984 return false;
1985 }
1986 break;
1987 case GL_QUERY_COUNTER_BITS_EXT:
1988 if (!context->getExtensions().disjointTimerQuery ||
1989 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1990 {
Jamie Madill437fa652016-05-03 15:13:24 -04001991 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001992 return false;
1993 }
1994 break;
1995 default:
Jamie Madill437fa652016-05-03 15:13:24 -04001996 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001997 return false;
1998 }
1999
Geoff Lang2186c382016-10-14 10:54:54 -04002000 if (numParams)
2001 {
2002 // All queries return only one value
2003 *numParams = 1;
2004 }
2005
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002006 return true;
2007}
2008
2009bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
2010{
2011 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002012 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002013 {
Jamie Madill437fa652016-05-03 15:13:24 -04002014 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002015 return false;
2016 }
2017
Geoff Lang2186c382016-10-14 10:54:54 -04002018 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002019}
2020
Geoff Lang2186c382016-10-14 10:54:54 -04002021bool ValidateGetQueryivRobustANGLE(Context *context,
2022 GLenum target,
2023 GLenum pname,
2024 GLsizei bufSize,
2025 GLsizei *length,
2026 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002027{
Geoff Lang2186c382016-10-14 10:54:54 -04002028 if (!ValidateRobustEntryPoint(context, bufSize))
2029 {
2030 return false;
2031 }
2032
2033 if (!ValidateGetQueryivBase(context, target, pname, length))
2034 {
2035 return false;
2036 }
2037
2038 if (!ValidateRobustBufferSize(context, bufSize, *length))
2039 {
2040 return false;
2041 }
2042
2043 return true;
2044}
2045
2046bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
2047{
2048 if (numParams)
2049 {
2050 *numParams = 0;
2051 }
2052
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002053 Query *queryObject = context->getQuery(id, false, GL_NONE);
2054
2055 if (!queryObject)
2056 {
Jamie Madill437fa652016-05-03 15:13:24 -04002057 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002058 return false;
2059 }
2060
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002061 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002062 {
Jamie Madill437fa652016-05-03 15:13:24 -04002063 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002064 return false;
2065 }
2066
2067 switch (pname)
2068 {
2069 case GL_QUERY_RESULT_EXT:
2070 case GL_QUERY_RESULT_AVAILABLE_EXT:
2071 break;
2072
2073 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002074 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002075 return false;
2076 }
2077
Geoff Lang2186c382016-10-14 10:54:54 -04002078 if (numParams)
2079 {
2080 *numParams = 1;
2081 }
2082
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002083 return true;
2084}
2085
2086bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
2087{
2088 if (!context->getExtensions().disjointTimerQuery)
2089 {
Jamie Madill437fa652016-05-03 15:13:24 -04002090 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002091 return false;
2092 }
Geoff Lang2186c382016-10-14 10:54:54 -04002093 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2094}
2095
2096bool ValidateGetQueryObjectivRobustANGLE(Context *context,
2097 GLuint id,
2098 GLenum pname,
2099 GLsizei bufSize,
2100 GLsizei *length,
2101 GLint *params)
2102{
2103 if (!context->getExtensions().disjointTimerQuery)
2104 {
2105 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2106 return false;
2107 }
2108
2109 if (!ValidateRobustEntryPoint(context, bufSize))
2110 {
2111 return false;
2112 }
2113
2114 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2115 {
2116 return false;
2117 }
2118
2119 if (!ValidateRobustBufferSize(context, bufSize, *length))
2120 {
2121 return false;
2122 }
2123
2124 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002125}
2126
2127bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
2128{
2129 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002130 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002131 {
Jamie Madill437fa652016-05-03 15:13:24 -04002132 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002133 return false;
2134 }
Geoff Lang2186c382016-10-14 10:54:54 -04002135 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2136}
2137
2138bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
2139 GLuint id,
2140 GLenum pname,
2141 GLsizei bufSize,
2142 GLsizei *length,
2143 GLuint *params)
2144{
2145 if (!context->getExtensions().disjointTimerQuery &&
2146 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
2147 {
2148 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
2149 return false;
2150 }
2151
2152 if (!ValidateRobustEntryPoint(context, bufSize))
2153 {
2154 return false;
2155 }
2156
2157 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2158 {
2159 return false;
2160 }
2161
2162 if (!ValidateRobustBufferSize(context, bufSize, *length))
2163 {
2164 return false;
2165 }
2166
2167 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002168}
2169
2170bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
2171{
2172 if (!context->getExtensions().disjointTimerQuery)
2173 {
Jamie Madill437fa652016-05-03 15:13:24 -04002174 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002175 return false;
2176 }
Geoff Lang2186c382016-10-14 10:54:54 -04002177 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2178}
2179
2180bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
2181 GLuint id,
2182 GLenum pname,
2183 GLsizei bufSize,
2184 GLsizei *length,
2185 GLint64 *params)
2186{
2187 if (!context->getExtensions().disjointTimerQuery)
2188 {
2189 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2190 return false;
2191 }
2192
2193 if (!ValidateRobustEntryPoint(context, bufSize))
2194 {
2195 return false;
2196 }
2197
2198 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2199 {
2200 return false;
2201 }
2202
2203 if (!ValidateRobustBufferSize(context, bufSize, *length))
2204 {
2205 return false;
2206 }
2207
2208 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002209}
2210
2211bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
2212{
2213 if (!context->getExtensions().disjointTimerQuery)
2214 {
Jamie Madill437fa652016-05-03 15:13:24 -04002215 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002216 return false;
2217 }
Geoff Lang2186c382016-10-14 10:54:54 -04002218 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2219}
2220
2221bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
2222 GLuint id,
2223 GLenum pname,
2224 GLsizei bufSize,
2225 GLsizei *length,
2226 GLuint64 *params)
2227{
2228 if (!context->getExtensions().disjointTimerQuery)
2229 {
2230 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2231 return false;
2232 }
2233
2234 if (!ValidateRobustEntryPoint(context, bufSize))
2235 {
2236 return false;
2237 }
2238
2239 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2240 {
2241 return false;
2242 }
2243
2244 if (!ValidateRobustBufferSize(context, bufSize, *length))
2245 {
2246 return false;
2247 }
2248
2249 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002250}
2251
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002252bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002253 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002254 GLuint program,
2255 GLint location,
2256 GLsizei count)
2257{
2258 // Check for ES31 program uniform entry points
2259 if (context->getClientVersion() < Version(3, 1))
2260 {
2261 context->handleError(Error(GL_INVALID_OPERATION));
2262 return false;
2263 }
2264
2265 const LinkedUniform *uniform = nullptr;
2266 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002267 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2268 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002269}
2270
Frank Henigmana98a6472017-02-02 21:38:32 -05002271bool ValidateProgramUniform1iv(gl::Context *context,
2272 GLuint program,
2273 GLint location,
2274 GLsizei count,
2275 const GLint *value)
2276{
2277 // Check for ES31 program uniform entry points
2278 if (context->getClientVersion() < Version(3, 1))
2279 {
2280 context->handleError(Error(GL_INVALID_OPERATION));
2281 return false;
2282 }
2283
2284 const LinkedUniform *uniform = nullptr;
2285 gl::Program *programObject = GetValidProgram(context, program);
2286 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2287 ValidateUniform1ivValue(context, uniform->type, count, value);
2288}
2289
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002290bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002291 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002292 GLuint program,
2293 GLint location,
2294 GLsizei count,
2295 GLboolean transpose)
2296{
2297 // Check for ES31 program uniform entry points
2298 if (context->getClientVersion() < Version(3, 1))
2299 {
2300 context->handleError(Error(GL_INVALID_OPERATION));
2301 return false;
2302 }
2303
2304 const LinkedUniform *uniform = nullptr;
2305 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002306 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2307 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002308}
2309
Jamie Madillc1d770e2017-04-13 17:31:24 -04002310bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002311{
2312 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002313 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002314 {
Jamie Madill437fa652016-05-03 15:13:24 -04002315 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002316 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002317 }
2318
Jamie Madill62d31cb2015-09-11 13:25:51 -04002319 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002320 gl::Program *programObject = context->getGLState().getProgram();
2321 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2322 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002323}
2324
Jamie Madillbe849e42017-05-02 15:49:00 -04002325bool ValidateUniform1iv(ValidationContext *context,
2326 GLint location,
2327 GLsizei count,
2328 const GLint *value)
Frank Henigmana98a6472017-02-02 21:38:32 -05002329{
2330 const LinkedUniform *uniform = nullptr;
2331 gl::Program *programObject = context->getGLState().getProgram();
2332 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2333 ValidateUniform1ivValue(context, uniform->type, count, value);
2334}
2335
Jamie Madillc1d770e2017-04-13 17:31:24 -04002336bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002337 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08002338 GLint location,
2339 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04002340 GLboolean transpose)
2341{
2342 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002343 int rows = VariableRowCount(valueType);
2344 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03002345 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002346 {
Jamie Madill437fa652016-05-03 15:13:24 -04002347 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002348 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002349 }
2350
Martin Radev1be913c2016-07-11 17:59:16 +03002351 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002352 {
Jamie Madill437fa652016-05-03 15:13:24 -04002353 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002354 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002355 }
2356
Jamie Madill62d31cb2015-09-11 13:25:51 -04002357 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002358 gl::Program *programObject = context->getGLState().getProgram();
2359 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2360 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002361}
2362
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002363bool ValidateStateQuery(ValidationContext *context,
2364 GLenum pname,
2365 GLenum *nativeType,
2366 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04002367{
2368 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
2369 {
Jamie Madill437fa652016-05-03 15:13:24 -04002370 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002371 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002372 }
2373
Jamie Madill0af26e12015-03-05 19:54:33 -05002374 const Caps &caps = context->getCaps();
2375
Jamie Madill893ab082014-05-16 16:56:10 -04002376 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
2377 {
2378 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
2379
Jamie Madill0af26e12015-03-05 19:54:33 -05002380 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04002381 {
Jamie Madill437fa652016-05-03 15:13:24 -04002382 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002383 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002384 }
2385 }
2386
2387 switch (pname)
2388 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002389 case GL_TEXTURE_BINDING_2D:
2390 case GL_TEXTURE_BINDING_CUBE_MAP:
2391 case GL_TEXTURE_BINDING_3D:
2392 case GL_TEXTURE_BINDING_2D_ARRAY:
2393 break;
2394 case GL_TEXTURE_BINDING_EXTERNAL_OES:
2395 if (!context->getExtensions().eglStreamConsumerExternal &&
2396 !context->getExtensions().eglImageExternal)
2397 {
2398 context->handleError(Error(GL_INVALID_ENUM,
2399 "Neither NV_EGL_stream_consumer_external nor "
2400 "GL_OES_EGL_image_external extensions enabled"));
2401 return false;
2402 }
2403 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002404
He Yunchaoced53ae2016-11-29 15:00:51 +08002405 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2406 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04002407 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002408 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
2409 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04002410 {
Jamie Madill437fa652016-05-03 15:13:24 -04002411 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002412 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002413 }
2414
Jamie Madill51f40ec2016-06-15 14:06:00 -04002415 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
2416 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03002417
2418 if (framebuffer->getReadBufferState() == GL_NONE)
2419 {
2420 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2421 return false;
2422 }
2423
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002424 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04002425 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04002426 {
Jamie Madill437fa652016-05-03 15:13:24 -04002427 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002428 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002429 }
2430 }
2431 break;
2432
He Yunchaoced53ae2016-11-29 15:00:51 +08002433 default:
2434 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002435 }
2436
2437 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04002438 if (*numParams == 0)
2439 {
2440 return false;
2441 }
2442
2443 return true;
2444}
2445
2446bool ValidateRobustStateQuery(ValidationContext *context,
2447 GLenum pname,
2448 GLsizei bufSize,
2449 GLenum *nativeType,
2450 unsigned int *numParams)
2451{
2452 if (!ValidateRobustEntryPoint(context, bufSize))
2453 {
2454 return false;
2455 }
2456
2457 if (!ValidateStateQuery(context, pname, nativeType, numParams))
2458 {
2459 return false;
2460 }
2461
2462 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04002463 {
2464 return false;
2465 }
2466
2467 return true;
2468}
2469
Jamie Madillc29968b2016-01-20 11:17:23 -05002470bool ValidateCopyTexImageParametersBase(ValidationContext *context,
2471 GLenum target,
2472 GLint level,
2473 GLenum internalformat,
2474 bool isSubImage,
2475 GLint xoffset,
2476 GLint yoffset,
2477 GLint zoffset,
2478 GLint x,
2479 GLint y,
2480 GLsizei width,
2481 GLsizei height,
2482 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04002483 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04002484{
Jamie Madill560a8d82014-05-21 13:06:20 -04002485 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
2486 {
Jamie Madill437fa652016-05-03 15:13:24 -04002487 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002488 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002489 }
2490
He Yunchaoced53ae2016-11-29 15:00:51 +08002491 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
2492 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04002493 {
Jamie Madill437fa652016-05-03 15:13:24 -04002494 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002495 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002496 }
2497
2498 if (border != 0)
2499 {
Jamie Madill437fa652016-05-03 15:13:24 -04002500 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002501 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002502 }
2503
2504 if (!ValidMipLevel(context, target, level))
2505 {
Jamie Madill437fa652016-05-03 15:13:24 -04002506 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002507 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002508 }
2509
Jamie Madill51f40ec2016-06-15 14:06:00 -04002510 const auto &state = context->getGLState();
2511 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002512 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04002513 {
Jamie Madill437fa652016-05-03 15:13:24 -04002514 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002515 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002516 }
2517
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002518 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04002519 {
Jamie Madill437fa652016-05-03 15:13:24 -04002520 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002521 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002522 }
2523
Martin Radev138064f2016-07-15 12:03:41 +03002524 if (readFramebuffer->getReadBufferState() == GL_NONE)
2525 {
2526 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2527 return false;
2528 }
2529
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002530 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
2531 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08002532 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002533 // situation is an application error that would lead to a crash in ANGLE.
2534 if (readFramebuffer->getReadColorbuffer() == nullptr)
2535 {
2536 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
2537 return false;
2538 }
2539
Geoff Langaae65a42014-05-26 12:43:44 -04002540 const gl::Caps &caps = context->getCaps();
2541
Geoff Langaae65a42014-05-26 12:43:44 -04002542 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04002543 switch (target)
2544 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002545 case GL_TEXTURE_2D:
2546 maxDimension = caps.max2DTextureSize;
2547 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002548
He Yunchaoced53ae2016-11-29 15:00:51 +08002549 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2550 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2551 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2552 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2553 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2554 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2555 maxDimension = caps.maxCubeMapTextureSize;
2556 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002557
He Yunchaoced53ae2016-11-29 15:00:51 +08002558 case GL_TEXTURE_2D_ARRAY:
2559 maxDimension = caps.max2DTextureSize;
2560 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002561
He Yunchaoced53ae2016-11-29 15:00:51 +08002562 case GL_TEXTURE_3D:
2563 maxDimension = caps.max3DTextureSize;
2564 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002565
He Yunchaoced53ae2016-11-29 15:00:51 +08002566 default:
2567 context->handleError(Error(GL_INVALID_ENUM));
2568 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002569 }
2570
Jamie Madillc29968b2016-01-20 11:17:23 -05002571 gl::Texture *texture =
2572 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04002573 if (!texture)
2574 {
Jamie Madill437fa652016-05-03 15:13:24 -04002575 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002576 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002577 }
2578
Geoff Lang69cce582015-09-17 13:20:36 -04002579 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04002580 {
Jamie Madill437fa652016-05-03 15:13:24 -04002581 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002582 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002583 }
2584
Geoff Langca271392017-04-05 12:30:00 -04002585 const gl::InternalFormat &formatInfo =
2586 gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04002587
Geoff Lang966c9402017-04-18 12:38:27 -04002588 if (formatInfo.depthBits > 0 || formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04002589 {
Jamie Madill437fa652016-05-03 15:13:24 -04002590 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002591 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002592 }
2593
2594 if (isSubImage)
2595 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05002596 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
2597 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
2598 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04002599 {
Jamie Madill437fa652016-05-03 15:13:24 -04002600 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002601 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002602 }
2603 }
Jamie Madill6f38f822014-06-06 17:12:20 -04002604 else
2605 {
Geoff Lang691e58c2014-12-19 17:03:25 -05002606 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04002607 {
Jamie Madill437fa652016-05-03 15:13:24 -04002608 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002609 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002610 }
2611
Geoff Langeb66a6e2016-10-31 13:06:12 -04002612 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04002613 {
Jamie Madill437fa652016-05-03 15:13:24 -04002614 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002615 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002616 }
2617
2618 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08002619 if (static_cast<int>(width) > maxLevelDimension ||
2620 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04002621 {
Jamie Madill437fa652016-05-03 15:13:24 -04002622 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002623 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002624 }
2625 }
Jamie Madill560a8d82014-05-21 13:06:20 -04002626
Jamie Madill0c8abca2016-07-22 20:21:26 -04002627 if (textureFormatOut)
2628 {
2629 *textureFormatOut = texture->getFormat(target, level);
2630 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05002631
2632 // Detect texture copying feedback loops for WebGL.
2633 if (context->getExtensions().webglCompatibility)
2634 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05002635 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05002636 {
2637 context->handleError(Error(GL_INVALID_OPERATION,
2638 "Texture copying feedback loop formed between Framebuffer "
2639 "and specified Texture level."));
2640 return false;
2641 }
2642 }
2643
Jamie Madill560a8d82014-05-21 13:06:20 -04002644 return true;
2645}
2646
Jiajia Qind9671222016-11-29 16:30:31 +08002647bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04002648{
Jamie Madill1aeb1312014-06-20 13:21:25 -04002649 switch (mode)
2650 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002651 case GL_POINTS:
2652 case GL_LINES:
2653 case GL_LINE_LOOP:
2654 case GL_LINE_STRIP:
2655 case GL_TRIANGLES:
2656 case GL_TRIANGLE_STRIP:
2657 case GL_TRIANGLE_FAN:
2658 break;
2659 default:
2660 context->handleError(Error(GL_INVALID_ENUM));
2661 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04002662 }
2663
Jamie Madill250d33f2014-06-06 17:09:03 -04002664 if (count < 0)
2665 {
Jamie Madill437fa652016-05-03 15:13:24 -04002666 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002667 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002668 }
2669
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002670 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04002671
Jamie Madill250d33f2014-06-06 17:09:03 -04002672 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002673 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002674 {
Jamie Madill437fa652016-05-03 15:13:24 -04002675 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002676 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002677 }
2678
Jamie Madillcbcde722017-01-06 14:50:00 -05002679 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
2680 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04002681 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002682 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
2683 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04002684 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002685 const FramebufferAttachment *dsAttachment =
2686 framebuffer->getStencilOrDepthStencilAttachment();
2687 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08002688 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04002689 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002690
2691 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
2692 bool differentWritemasks =
2693 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
2694 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
2695 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
2696 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
2697
2698 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04002699 {
Jamie Madillcbcde722017-01-06 14:50:00 -05002700 if (!context->getExtensions().webglCompatibility)
2701 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05002702 ERR() << "This ANGLE implementation does not support separate front/back stencil "
2703 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05002704 }
Jamie Madill437fa652016-05-03 15:13:24 -04002705 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04002706 return false;
2707 }
Jamie Madillac528012014-06-20 13:21:23 -04002708 }
2709
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002710 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002711 {
Jamie Madill437fa652016-05-03 15:13:24 -04002712 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002713 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002714 }
2715
Geoff Lang7dd2e102014-11-10 15:19:26 -05002716 gl::Program *program = state.getProgram();
2717 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002718 {
Jamie Madill437fa652016-05-03 15:13:24 -04002719 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002720 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002721 }
2722
Yunchao Hef81ce4a2017-04-24 10:49:17 +08002723 if (!program->validateSamplers(nullptr, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04002724 {
Jamie Madill437fa652016-05-03 15:13:24 -04002725 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002726 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002727 }
2728
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002729 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08002730 for (unsigned int uniformBlockIndex = 0;
2731 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002732 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04002733 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08002734 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04002735 const OffsetBindingPointer<Buffer> &uniformBuffer =
2736 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002737
Geoff Lang5d124a62015-09-15 13:03:27 -04002738 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002739 {
2740 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002741 context->handleError(
2742 Error(GL_INVALID_OPERATION,
2743 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002744 return false;
2745 }
2746
Geoff Lang5d124a62015-09-15 13:03:27 -04002747 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002748 if (uniformBufferSize == 0)
2749 {
2750 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07002751 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002752 }
2753
Jamie Madill62d31cb2015-09-11 13:25:51 -04002754 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002755 {
2756 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002757 context->handleError(
2758 Error(GL_INVALID_OPERATION,
2759 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002760 return false;
2761 }
2762 }
2763
Geoff Lange0cff192017-05-30 13:04:56 -04002764 // Do some additonal WebGL-specific validation
Jamie Madilla4595b82017-01-11 17:36:34 -05002765 if (context->getExtensions().webglCompatibility)
2766 {
Geoff Lange0cff192017-05-30 13:04:56 -04002767 // Detect rendering feedback loops for WebGL.
Jamie Madilla4595b82017-01-11 17:36:34 -05002768 if (framebuffer->formsRenderingFeedbackLoopWith(state))
2769 {
2770 context->handleError(
2771 Error(GL_INVALID_OPERATION,
2772 "Rendering feedback loop formed between Framebuffer and active Texture."));
2773 return false;
2774 }
Geoff Lange0cff192017-05-30 13:04:56 -04002775
Geoff Lang9ab5b822017-05-30 16:19:23 -04002776 // Detect that the vertex shader input types match the attribute types
2777 if (!ValidateVertexShaderAttributeTypeMatch(context))
2778 {
2779 return false;
2780 }
2781
Geoff Lange0cff192017-05-30 13:04:56 -04002782 // Detect that the color buffer types match the fragment shader output types
2783 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
2784 {
2785 return false;
2786 }
Jamie Madilla4595b82017-01-11 17:36:34 -05002787 }
2788
Jamie Madill250d33f2014-06-06 17:09:03 -04002789 // No-op if zero count
2790 return (count > 0);
2791}
2792
Jamie Madillc1d770e2017-04-13 17:31:24 -04002793bool ValidateDrawArraysCommon(ValidationContext *context,
2794 GLenum mode,
2795 GLint first,
2796 GLsizei count,
2797 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04002798{
Jamie Madillfd716582014-06-06 17:09:04 -04002799 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04002800 {
Jamie Madill437fa652016-05-03 15:13:24 -04002801 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002802 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002803 }
2804
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002805 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002806 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002807 if (curTransformFeedback && curTransformFeedback->isActive() &&
2808 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04002809 {
2810 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08002811 // that does not match the current transform feedback object's draw mode (if transform
2812 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04002813 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002814 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002815 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002816 }
2817
Jiajia Qind9671222016-11-29 16:30:31 +08002818 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002819 {
2820 return false;
2821 }
2822
Corentin Wallez71168a02016-12-19 15:11:18 -08002823 // Check the computation of maxVertex doesn't overflow.
2824 // - first < 0 or count < 0 have been checked as an error condition
2825 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
2826 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
2827 ASSERT(count > 0 && first >= 0);
2828 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
2829 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05002830 {
2831 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
2832 return false;
2833 }
2834
Corentin Wallez71168a02016-12-19 15:11:18 -08002835 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04002836 {
2837 return false;
2838 }
2839
2840 return true;
2841}
2842
He Yunchaoced53ae2016-11-29 15:00:51 +08002843bool ValidateDrawArraysInstanced(Context *context,
2844 GLenum mode,
2845 GLint first,
2846 GLsizei count,
2847 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04002848{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002849 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04002850 {
2851 return false;
2852 }
2853
Corentin Wallez170efbf2017-05-02 13:45:01 -04002854 return !context->getExtensions().webglCompatibility ||
2855 ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002856}
2857
He Yunchaoced53ae2016-11-29 15:00:51 +08002858bool ValidateDrawArraysInstancedANGLE(Context *context,
2859 GLenum mode,
2860 GLint first,
2861 GLsizei count,
2862 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04002863{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002864 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04002865 {
2866 return false;
2867 }
2868
Corentin Wallez170efbf2017-05-02 13:45:01 -04002869 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002870}
2871
Jiajia Qind9671222016-11-29 16:30:31 +08002872bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04002873{
Jamie Madill250d33f2014-06-06 17:09:03 -04002874 switch (type)
2875 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002876 case GL_UNSIGNED_BYTE:
2877 case GL_UNSIGNED_SHORT:
2878 break;
2879 case GL_UNSIGNED_INT:
2880 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2881 {
2882 context->handleError(Error(GL_INVALID_ENUM));
2883 return false;
2884 }
2885 break;
2886 default:
2887 context->handleError(Error(GL_INVALID_ENUM));
2888 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002889 }
2890
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002891 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002892
2893 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002894 if (curTransformFeedback && curTransformFeedback->isActive() &&
2895 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002896 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002897 // It is an invalid operation to call DrawElements, DrawRangeElements or
2898 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04002899 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002900 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002901 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002902 }
2903
Jiajia Qind9671222016-11-29 16:30:31 +08002904 return true;
2905}
2906
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002907bool ValidateDrawElementsCommon(ValidationContext *context,
2908 GLenum mode,
2909 GLsizei count,
2910 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04002911 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002912 GLsizei primcount)
Jiajia Qind9671222016-11-29 16:30:31 +08002913{
2914 if (!ValidateDrawElementsBase(context, type))
2915 return false;
2916
2917 const State &state = context->getGLState();
2918
Corentin Wallez170efbf2017-05-02 13:45:01 -04002919 if (!ValidateDrawBase(context, mode, count))
2920 {
2921 return false;
2922 }
2923
Jamie Madill250d33f2014-06-06 17:09:03 -04002924 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002925 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002926 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002927 context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
Geoff Langb1196682014-07-23 13:47:29 -04002928 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002929 }
2930
He Yunchaoced53ae2016-11-29 15:00:51 +08002931 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002932 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04002933
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002934 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
2935
2936 if (context->getExtensions().webglCompatibility)
2937 {
2938 ASSERT(isPow2(typeBytes) && typeBytes > 0);
2939 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
2940 {
2941 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2942 // The offset arguments to drawElements and [...], must be a multiple of the size of the
2943 // data type passed to the call, or an INVALID_OPERATION error is generated.
2944 context->handleError(Error(GL_INVALID_OPERATION,
2945 "indices must be a multiple of the element type size."));
2946 return false;
2947 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002948
2949 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2950 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
2951 // error is generated.
2952 if (reinterpret_cast<intptr_t>(indices) < 0)
2953 {
2954 context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
2955 return false;
2956 }
Geoff Langfeb8c682017-02-13 16:07:35 -05002957 }
2958
2959 if (context->getExtensions().webglCompatibility ||
2960 !context->getGLState().areClientArraysEnabled())
2961 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002962 if (!elementArrayBuffer && count > 0)
2963 {
2964 // [WebGL 1.0] Section 6.2 No Client Side Arrays
2965 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
2966 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
2967 context->handleError(Error(GL_INVALID_OPERATION,
2968 "There is no element array buffer bound and count > 0."));
2969 return false;
2970 }
2971 }
2972
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002973 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04002974 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002975 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04002976 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002977 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
2978 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
2979 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
2980 constexpr uint64_t kMaxTypeSize = 8;
2981 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
2982 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
2983 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002984
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002985 uint64_t typeSize = typeBytes;
2986 uint64_t elementCount = static_cast<uint64_t>(count);
2987 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
2988
2989 // Doing the multiplication here is overflow-safe
2990 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
2991
2992 // The offset can be any value, check for overflows
2993 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
2994 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002995 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002996 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002997 return false;
2998 }
2999
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003000 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
3001 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003002 {
3003 context->handleError(
3004 Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
3005 return false;
3006 }
3007 }
3008 else if (!indices)
3009 {
3010 // This is an application error that would normally result in a crash,
3011 // but we catch it and return an error
3012 context->handleError(
3013 Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
Geoff Langb1196682014-07-23 13:47:29 -04003014 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04003015 }
Jamie Madillae3000b2014-08-25 15:47:51 -04003016 }
3017
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003018 // Use the parameter buffer to retrieve and cache the index range.
Jamie Madill2b976812014-08-25 15:47:49 -04003019 // TODO: offer fast path, with disabled index validation.
3020 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003021 const auto &params = context->getParams<HasIndexRange>();
3022 const auto &indexRangeOpt = params.getIndexRange();
3023 if (!indexRangeOpt.valid())
Jamie Madill2b976812014-08-25 15:47:49 -04003024 {
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003025 // Unexpected error.
3026 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04003027 }
3028
Jamie Madille79b1e12015-11-04 16:36:37 -05003029 // If we use an index greater than our maximum supported index range, return an error.
3030 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
3031 // return an error if possible here.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003032 if (static_cast<GLuint64>(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex)
Jamie Madille79b1e12015-11-04 16:36:37 -05003033 {
Jamie Madill437fa652016-05-03 15:13:24 -04003034 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05003035 return false;
3036 }
3037
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003038 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOpt.value().end),
3039 static_cast<GLint>(indexRangeOpt.value().vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04003040 {
3041 return false;
3042 }
3043
Geoff Lang3edfe032015-09-04 16:38:24 -04003044 // No op if there are no real indices in the index data (all are primitive restart).
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003045 return (indexRangeOpt.value().vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04003046}
3047
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003048bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
3049 GLenum mode,
3050 GLsizei count,
3051 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003052 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003053 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003054{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003055 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04003056 {
3057 return false;
3058 }
3059
Corentin Wallez170efbf2017-05-02 13:45:01 -04003060 return !context->getExtensions().webglCompatibility ||
3061 ValidateDrawInstancedANGLEAndWebGL(context);
Jamie Madill250d33f2014-06-06 17:09:03 -04003062}
3063
Geoff Lang3edfe032015-09-04 16:38:24 -04003064bool ValidateDrawElementsInstancedANGLE(Context *context,
3065 GLenum mode,
3066 GLsizei count,
3067 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003068 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003069 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003070{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003071 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04003072 {
3073 return false;
3074 }
3075
Corentin Wallez170efbf2017-05-02 13:45:01 -04003076 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04003077}
3078
He Yunchaoced53ae2016-11-29 15:00:51 +08003079bool ValidateFramebufferTextureBase(Context *context,
3080 GLenum target,
3081 GLenum attachment,
3082 GLuint texture,
3083 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04003084{
Jamie Madill55ec3b12014-07-03 10:38:57 -04003085 if (!ValidFramebufferTarget(target))
3086 {
Jamie Madill437fa652016-05-03 15:13:24 -04003087 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003088 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003089 }
3090
3091 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04003092 {
3093 return false;
3094 }
3095
Jamie Madill55ec3b12014-07-03 10:38:57 -04003096 if (texture != 0)
3097 {
3098 gl::Texture *tex = context->getTexture(texture);
3099
Jamie Madillbe849e42017-05-02 15:49:00 -04003100 if (tex == NULL)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003101 {
Jamie Madill437fa652016-05-03 15:13:24 -04003102 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003103 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003104 }
3105
3106 if (level < 0)
3107 {
Jamie Madill437fa652016-05-03 15:13:24 -04003108 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003109 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003110 }
3111 }
3112
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003113 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04003114 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04003115
Jamie Madill84115c92015-04-23 15:00:07 -04003116 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003117 {
Jamie Madill437fa652016-05-03 15:13:24 -04003118 context->handleError(
3119 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04003120 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003121 }
3122
3123 return true;
3124}
3125
Geoff Langb1196682014-07-23 13:47:29 -04003126bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04003127{
3128 if (program == 0)
3129 {
Jamie Madill437fa652016-05-03 15:13:24 -04003130 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003131 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003132 }
3133
Dian Xiang769769a2015-09-09 15:20:08 -07003134 gl::Program *programObject = GetValidProgram(context, program);
3135 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05003136 {
3137 return false;
3138 }
3139
Jamie Madill0063c512014-08-25 15:47:53 -04003140 if (!programObject || !programObject->isLinked())
3141 {
Jamie Madill437fa652016-05-03 15:13:24 -04003142 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003143 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003144 }
3145
Geoff Lang7dd2e102014-11-10 15:19:26 -05003146 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04003147 {
Jamie Madill437fa652016-05-03 15:13:24 -04003148 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003149 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04003150 }
3151
Jamie Madill0063c512014-08-25 15:47:53 -04003152 return true;
3153}
3154
Geoff Langf41d0ee2016-10-07 13:04:23 -04003155static bool ValidateSizedGetUniform(Context *context,
3156 GLuint program,
3157 GLint location,
3158 GLsizei bufSize,
3159 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04003160{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003161 if (length)
3162 {
3163 *length = 0;
3164 }
3165
Jamie Madill78f41802014-08-25 15:47:55 -04003166 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04003167 {
Jamie Madill78f41802014-08-25 15:47:55 -04003168 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003169 }
3170
Geoff Langf41d0ee2016-10-07 13:04:23 -04003171 if (bufSize < 0)
3172 {
3173 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3174 return false;
3175 }
3176
Jamie Madilla502c742014-08-28 17:19:13 -04003177 gl::Program *programObject = context->getProgram(program);
3178 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04003179
Jamie Madill78f41802014-08-25 15:47:55 -04003180 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04003181 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08003182 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04003183 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04003184 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04003185 context->handleError(
3186 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04003187 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003188 }
3189
Geoff Langf41d0ee2016-10-07 13:04:23 -04003190 if (length)
3191 {
Geoff Lang94177fb2016-11-14 16:12:26 -05003192 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04003193 }
3194
Jamie Madill0063c512014-08-25 15:47:53 -04003195 return true;
3196}
3197
He Yunchaoced53ae2016-11-29 15:00:51 +08003198bool ValidateGetnUniformfvEXT(Context *context,
3199 GLuint program,
3200 GLint location,
3201 GLsizei bufSize,
3202 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003203{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003204 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04003205}
3206
He Yunchaoced53ae2016-11-29 15:00:51 +08003207bool ValidateGetnUniformivEXT(Context *context,
3208 GLuint program,
3209 GLint location,
3210 GLsizei bufSize,
3211 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003212{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003213 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3214}
3215
3216bool ValidateGetUniformfvRobustANGLE(Context *context,
3217 GLuint program,
3218 GLint location,
3219 GLsizei bufSize,
3220 GLsizei *length,
3221 GLfloat *params)
3222{
3223 if (!ValidateRobustEntryPoint(context, bufSize))
3224 {
3225 return false;
3226 }
3227
3228 // bufSize is validated in ValidateSizedGetUniform
3229 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3230}
3231
3232bool ValidateGetUniformivRobustANGLE(Context *context,
3233 GLuint program,
3234 GLint location,
3235 GLsizei bufSize,
3236 GLsizei *length,
3237 GLint *params)
3238{
3239 if (!ValidateRobustEntryPoint(context, bufSize))
3240 {
3241 return false;
3242 }
3243
3244 // bufSize is validated in ValidateSizedGetUniform
3245 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3246}
3247
3248bool ValidateGetUniformuivRobustANGLE(Context *context,
3249 GLuint program,
3250 GLint location,
3251 GLsizei bufSize,
3252 GLsizei *length,
3253 GLuint *params)
3254{
3255 if (!ValidateRobustEntryPoint(context, bufSize))
3256 {
3257 return false;
3258 }
3259
3260 if (context->getClientMajorVersion() < 3)
3261 {
3262 context->handleError(
3263 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
3264 return false;
3265 }
3266
3267 // bufSize is validated in ValidateSizedGetUniform
3268 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04003269}
3270
He Yunchaoced53ae2016-11-29 15:00:51 +08003271bool ValidateDiscardFramebufferBase(Context *context,
3272 GLenum target,
3273 GLsizei numAttachments,
3274 const GLenum *attachments,
3275 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07003276{
3277 if (numAttachments < 0)
3278 {
Jamie Madill437fa652016-05-03 15:13:24 -04003279 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07003280 return false;
3281 }
3282
3283 for (GLsizei i = 0; i < numAttachments; ++i)
3284 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02003285 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07003286 {
3287 if (defaultFramebuffer)
3288 {
Jamie Madill437fa652016-05-03 15:13:24 -04003289 context->handleError(Error(
3290 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07003291 return false;
3292 }
3293
3294 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
3295 {
Jamie Madill437fa652016-05-03 15:13:24 -04003296 context->handleError(Error(GL_INVALID_OPERATION,
3297 "Requested color attachment is greater than the maximum "
3298 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07003299 return false;
3300 }
3301 }
3302 else
3303 {
3304 switch (attachments[i])
3305 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003306 case GL_DEPTH_ATTACHMENT:
3307 case GL_STENCIL_ATTACHMENT:
3308 case GL_DEPTH_STENCIL_ATTACHMENT:
3309 if (defaultFramebuffer)
3310 {
3311 context->handleError(
3312 Error(GL_INVALID_ENUM,
3313 "Invalid attachment when the default framebuffer is bound"));
3314 return false;
3315 }
3316 break;
3317 case GL_COLOR:
3318 case GL_DEPTH:
3319 case GL_STENCIL:
3320 if (!defaultFramebuffer)
3321 {
3322 context->handleError(
3323 Error(GL_INVALID_ENUM,
3324 "Invalid attachment when the default framebuffer is not bound"));
3325 return false;
3326 }
3327 break;
3328 default:
3329 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07003330 return false;
Austin Kinross08332632015-05-05 13:35:47 -07003331 }
3332 }
3333 }
3334
3335 return true;
3336}
3337
Austin Kinross6ee1e782015-05-29 17:05:37 -07003338bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
3339{
3340 // Note that debug marker calls must not set error state
3341
3342 if (length < 0)
3343 {
3344 return false;
3345 }
3346
3347 if (marker == nullptr)
3348 {
3349 return false;
3350 }
3351
3352 return true;
3353}
3354
3355bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
3356{
3357 // Note that debug marker calls must not set error state
3358
3359 if (length < 0)
3360 {
3361 return false;
3362 }
3363
3364 if (length > 0 && marker == nullptr)
3365 {
3366 return false;
3367 }
3368
3369 return true;
3370}
3371
Geoff Langdcab33b2015-07-21 13:03:16 -04003372bool ValidateEGLImageTargetTexture2DOES(Context *context,
3373 egl::Display *display,
3374 GLenum target,
3375 egl::Image *image)
3376{
Geoff Langa8406172015-07-21 16:53:39 -04003377 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
3378 {
Jamie Madill437fa652016-05-03 15:13:24 -04003379 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04003380 return false;
3381 }
3382
3383 switch (target)
3384 {
3385 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04003386 if (!context->getExtensions().eglImage)
3387 {
3388 context->handleError(Error(
3389 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
3390 }
3391 break;
3392
3393 case GL_TEXTURE_EXTERNAL_OES:
3394 if (!context->getExtensions().eglImageExternal)
3395 {
3396 context->handleError(Error(
3397 GL_INVALID_ENUM,
3398 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
3399 }
Geoff Langa8406172015-07-21 16:53:39 -04003400 break;
3401
3402 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003403 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04003404 return false;
3405 }
3406
3407 if (!display->isValidImage(image))
3408 {
Jamie Madill437fa652016-05-03 15:13:24 -04003409 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04003410 return false;
3411 }
3412
3413 if (image->getSamples() > 0)
3414 {
Jamie Madill437fa652016-05-03 15:13:24 -04003415 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04003416 "cannot create a 2D texture from a multisampled EGL image."));
3417 return false;
3418 }
3419
Geoff Langca271392017-04-05 12:30:00 -04003420 const TextureCaps &textureCaps =
3421 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003422 if (!textureCaps.texturable)
3423 {
Jamie Madill437fa652016-05-03 15:13:24 -04003424 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04003425 "EGL image internal format is not supported as a texture."));
3426 return false;
3427 }
3428
Geoff Langdcab33b2015-07-21 13:03:16 -04003429 return true;
3430}
3431
3432bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
3433 egl::Display *display,
3434 GLenum target,
3435 egl::Image *image)
3436{
Geoff Langa8406172015-07-21 16:53:39 -04003437 if (!context->getExtensions().eglImage)
3438 {
Jamie Madill437fa652016-05-03 15:13:24 -04003439 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04003440 return false;
3441 }
3442
3443 switch (target)
3444 {
3445 case GL_RENDERBUFFER:
3446 break;
3447
3448 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003449 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04003450 return false;
3451 }
3452
3453 if (!display->isValidImage(image))
3454 {
Jamie Madill437fa652016-05-03 15:13:24 -04003455 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04003456 return false;
3457 }
3458
Geoff Langca271392017-04-05 12:30:00 -04003459 const TextureCaps &textureCaps =
3460 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003461 if (!textureCaps.renderable)
3462 {
Jamie Madill437fa652016-05-03 15:13:24 -04003463 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04003464 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
3465 return false;
3466 }
3467
Geoff Langdcab33b2015-07-21 13:03:16 -04003468 return true;
3469}
Austin Kinrossbc781f32015-10-26 09:27:38 -07003470
3471bool ValidateBindVertexArrayBase(Context *context, GLuint array)
3472{
Geoff Lang36167ab2015-12-07 10:27:14 -05003473 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07003474 {
3475 // The default VAO should always exist
3476 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04003477 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07003478 return false;
3479 }
3480
3481 return true;
3482}
3483
Geoff Langc5629752015-12-07 16:29:04 -05003484bool ValidateProgramBinaryBase(Context *context,
3485 GLuint program,
3486 GLenum binaryFormat,
3487 const void *binary,
3488 GLint length)
3489{
3490 Program *programObject = GetValidProgram(context, program);
3491 if (programObject == nullptr)
3492 {
3493 return false;
3494 }
3495
3496 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3497 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3498 programBinaryFormats.end())
3499 {
Jamie Madill437fa652016-05-03 15:13:24 -04003500 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05003501 return false;
3502 }
3503
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003504 if (context->hasActiveTransformFeedback(program))
3505 {
3506 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04003507 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003508 "Cannot change program binary while program is associated with "
3509 "an active transform feedback object."));
3510 return false;
3511 }
3512
Geoff Langc5629752015-12-07 16:29:04 -05003513 return true;
3514}
3515
3516bool ValidateGetProgramBinaryBase(Context *context,
3517 GLuint program,
3518 GLsizei bufSize,
3519 GLsizei *length,
3520 GLenum *binaryFormat,
3521 void *binary)
3522{
3523 Program *programObject = GetValidProgram(context, program);
3524 if (programObject == nullptr)
3525 {
3526 return false;
3527 }
3528
3529 if (!programObject->isLinked())
3530 {
Jamie Madill437fa652016-05-03 15:13:24 -04003531 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05003532 return false;
3533 }
3534
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003535 if (context->getCaps().programBinaryFormats.empty())
3536 {
3537 context->handleError(Error(GL_INVALID_OPERATION, "No program binary formats supported."));
3538 return false;
3539 }
3540
Geoff Langc5629752015-12-07 16:29:04 -05003541 return true;
3542}
Jamie Madillc29968b2016-01-20 11:17:23 -05003543
Jamie Madillc29968b2016-01-20 11:17:23 -05003544bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
3545{
3546 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3547 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3548 {
Jamie Madill437fa652016-05-03 15:13:24 -04003549 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003550 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
3551 return false;
3552 }
3553
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003554 ASSERT(context->getGLState().getDrawFramebuffer());
3555 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05003556 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3557
3558 // This should come first before the check for the default frame buffer
3559 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3560 // rather than INVALID_OPERATION
3561 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3562 {
3563 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3564
3565 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02003566 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3567 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05003568 {
3569 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02003570 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3571 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3572 // 3.1 is still a bit ambiguous about the error, but future specs are
3573 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04003574 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02003575 return false;
3576 }
3577 else if (bufs[colorAttachment] >= maxColorAttachment)
3578 {
Jamie Madill437fa652016-05-03 15:13:24 -04003579 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02003580 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05003581 return false;
3582 }
3583 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3584 frameBufferId != 0)
3585 {
3586 // INVALID_OPERATION-GL is bound to buffer and ith argument
3587 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04003588 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003589 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
3590 return false;
3591 }
3592 }
3593
3594 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3595 // and n is not 1 or bufs is bound to value other than BACK and NONE
3596 if (frameBufferId == 0)
3597 {
3598 if (n != 1)
3599 {
Jamie Madill437fa652016-05-03 15:13:24 -04003600 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05003601 "n must be 1 when GL is bound to the default framebuffer"));
3602 return false;
3603 }
3604
3605 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3606 {
Jamie Madill437fa652016-05-03 15:13:24 -04003607 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05003608 GL_INVALID_OPERATION,
3609 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
3610 return false;
3611 }
3612 }
3613
3614 return true;
3615}
3616
Geoff Lang496c02d2016-10-20 11:38:11 -07003617bool ValidateGetBufferPointervBase(Context *context,
3618 GLenum target,
3619 GLenum pname,
3620 GLsizei *length,
3621 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03003622{
Geoff Lang496c02d2016-10-20 11:38:11 -07003623 if (length)
3624 {
3625 *length = 0;
3626 }
3627
3628 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
3629 {
3630 context->handleError(
3631 Error(GL_INVALID_OPERATION,
Jamie Madillcc6ac252017-01-25 12:57:21 -08003632 "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
Geoff Lang496c02d2016-10-20 11:38:11 -07003633 return false;
3634 }
3635
Olli Etuaho4f667482016-03-30 15:56:35 +03003636 if (!ValidBufferTarget(context, target))
3637 {
Jamie Madill437fa652016-05-03 15:13:24 -04003638 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03003639 return false;
3640 }
3641
Geoff Lang496c02d2016-10-20 11:38:11 -07003642 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03003643 {
Geoff Lang496c02d2016-10-20 11:38:11 -07003644 case GL_BUFFER_MAP_POINTER:
3645 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03003646
Geoff Lang496c02d2016-10-20 11:38:11 -07003647 default:
3648 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
3649 return false;
3650 }
Olli Etuaho4f667482016-03-30 15:56:35 +03003651
3652 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3653 // target bound to zero generate an INVALID_OPERATION error."
3654 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07003655 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03003656 {
Jamie Madill437fa652016-05-03 15:13:24 -04003657 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003658 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
3659 return false;
3660 }
3661
Geoff Lang496c02d2016-10-20 11:38:11 -07003662 if (length)
3663 {
3664 *length = 1;
3665 }
3666
Olli Etuaho4f667482016-03-30 15:56:35 +03003667 return true;
3668}
3669
3670bool ValidateUnmapBufferBase(Context *context, GLenum target)
3671{
3672 if (!ValidBufferTarget(context, target))
3673 {
Jamie Madill437fa652016-05-03 15:13:24 -04003674 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003675 return false;
3676 }
3677
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003678 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003679
3680 if (buffer == nullptr || !buffer->isMapped())
3681 {
Jamie Madill437fa652016-05-03 15:13:24 -04003682 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003683 return false;
3684 }
3685
3686 return true;
3687}
3688
3689bool ValidateMapBufferRangeBase(Context *context,
3690 GLenum target,
3691 GLintptr offset,
3692 GLsizeiptr length,
3693 GLbitfield access)
3694{
3695 if (!ValidBufferTarget(context, target))
3696 {
Jamie Madill437fa652016-05-03 15:13:24 -04003697 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003698 return false;
3699 }
3700
3701 if (offset < 0 || length < 0)
3702 {
Jamie Madill437fa652016-05-03 15:13:24 -04003703 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003704 return false;
3705 }
3706
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003707 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003708
3709 if (!buffer)
3710 {
Jamie Madill437fa652016-05-03 15:13:24 -04003711 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003712 return false;
3713 }
3714
3715 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003716 CheckedNumeric<size_t> checkedOffset(offset);
3717 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003718
Jamie Madille2e406c2016-06-02 13:04:10 -04003719 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003720 {
Jamie Madill437fa652016-05-03 15:13:24 -04003721 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003722 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
3723 return false;
3724 }
3725
3726 // Check for invalid bits in the mask
3727 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3728 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3729 GL_MAP_UNSYNCHRONIZED_BIT;
3730
3731 if (access & ~(allAccessBits))
3732 {
Jamie Madill437fa652016-05-03 15:13:24 -04003733 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03003734 return false;
3735 }
3736
3737 if (length == 0)
3738 {
Jamie Madill437fa652016-05-03 15:13:24 -04003739 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003740 return false;
3741 }
3742
3743 if (buffer->isMapped())
3744 {
Jamie Madill437fa652016-05-03 15:13:24 -04003745 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003746 return false;
3747 }
3748
3749 // Check for invalid bit combinations
3750 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3751 {
Jamie Madill437fa652016-05-03 15:13:24 -04003752 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003753 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
3754 return false;
3755 }
3756
3757 GLbitfield writeOnlyBits =
3758 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3759
3760 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3761 {
Jamie Madill437fa652016-05-03 15:13:24 -04003762 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03003763 "Invalid access bits when mapping buffer for reading: 0x%X.",
3764 access));
3765 return false;
3766 }
3767
3768 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3769 {
Jamie Madill437fa652016-05-03 15:13:24 -04003770 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003771 GL_INVALID_OPERATION,
3772 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
3773 return false;
3774 }
3775 return true;
3776}
3777
3778bool ValidateFlushMappedBufferRangeBase(Context *context,
3779 GLenum target,
3780 GLintptr offset,
3781 GLsizeiptr length)
3782{
3783 if (offset < 0 || length < 0)
3784 {
Jamie Madill437fa652016-05-03 15:13:24 -04003785 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003786 return false;
3787 }
3788
3789 if (!ValidBufferTarget(context, target))
3790 {
Jamie Madill437fa652016-05-03 15:13:24 -04003791 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003792 return false;
3793 }
3794
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003795 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003796
3797 if (buffer == nullptr)
3798 {
Jamie Madill437fa652016-05-03 15:13:24 -04003799 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003800 return false;
3801 }
3802
3803 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3804 {
Jamie Madill437fa652016-05-03 15:13:24 -04003805 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003806 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
3807 return false;
3808 }
3809
3810 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003811 CheckedNumeric<size_t> checkedOffset(offset);
3812 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003813
Jamie Madille2e406c2016-06-02 13:04:10 -04003814 if (!checkedSize.IsValid() ||
3815 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003816 {
Jamie Madill437fa652016-05-03 15:13:24 -04003817 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003818 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3819 return false;
3820 }
3821
3822 return true;
3823}
3824
Olli Etuaho41997e72016-03-10 13:38:39 +02003825bool ValidateGenOrDelete(Context *context, GLint n)
3826{
3827 if (n < 0)
3828 {
Jamie Madill437fa652016-05-03 15:13:24 -04003829 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003830 return false;
3831 }
3832 return true;
3833}
3834
Geoff Langff5b2d52016-09-07 11:32:23 -04003835bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
3836{
3837 if (!context->getExtensions().robustClientMemory)
3838 {
3839 context->handleError(
3840 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
3841 return false;
3842 }
3843
3844 if (bufSize < 0)
3845 {
3846 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3847 return false;
3848 }
3849
3850 return true;
3851}
3852
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003853bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
3854{
3855 if (bufSize < numParams)
3856 {
3857 context->handleError(Error(GL_INVALID_OPERATION,
3858 "%u parameters are required but %i were provided.", numParams,
3859 bufSize));
3860 return false;
3861 }
3862
3863 return true;
3864}
3865
Jamie Madillbe849e42017-05-02 15:49:00 -04003866bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context,
3867 GLenum target,
3868 GLenum attachment,
3869 GLenum pname,
3870 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04003871{
3872 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08003873 if (numParams)
3874 {
3875 *numParams = 1;
3876 }
Geoff Langff5b2d52016-09-07 11:32:23 -04003877
3878 if (!ValidFramebufferTarget(target))
3879 {
3880 context->handleError(Error(GL_INVALID_ENUM));
3881 return false;
3882 }
3883
3884 int clientVersion = context->getClientMajorVersion();
3885
3886 switch (pname)
3887 {
3888 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3889 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3890 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3891 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3892 break;
3893
3894 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3895 if (clientVersion < 3 && !context->getExtensions().sRGB)
3896 {
3897 context->handleError(Error(GL_INVALID_ENUM));
3898 return false;
3899 }
3900 break;
3901
3902 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3903 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3904 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3905 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3906 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3907 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3908 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3909 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3910 if (clientVersion < 3)
3911 {
3912 context->handleError(Error(GL_INVALID_ENUM));
3913 return false;
3914 }
3915 break;
3916
3917 default:
3918 context->handleError(Error(GL_INVALID_ENUM));
3919 return false;
3920 }
3921
3922 // Determine if the attachment is a valid enum
3923 switch (attachment)
3924 {
3925 case GL_BACK:
3926 case GL_FRONT:
3927 case GL_DEPTH:
3928 case GL_STENCIL:
3929 case GL_DEPTH_STENCIL_ATTACHMENT:
3930 if (clientVersion < 3)
3931 {
3932 context->handleError(Error(GL_INVALID_ENUM));
3933 return false;
3934 }
3935 break;
3936
3937 case GL_DEPTH_ATTACHMENT:
3938 case GL_STENCIL_ATTACHMENT:
3939 break;
3940
3941 default:
3942 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
3943 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3944 {
3945 context->handleError(Error(GL_INVALID_ENUM));
3946 return false;
3947 }
3948 break;
3949 }
3950
3951 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
3952 ASSERT(framebuffer);
3953
3954 if (framebuffer->id() == 0)
3955 {
3956 if (clientVersion < 3)
3957 {
3958 context->handleError(Error(GL_INVALID_OPERATION));
3959 return false;
3960 }
3961
3962 switch (attachment)
3963 {
3964 case GL_BACK:
3965 case GL_DEPTH:
3966 case GL_STENCIL:
3967 break;
3968
3969 default:
3970 context->handleError(Error(GL_INVALID_OPERATION));
3971 return false;
3972 }
3973 }
3974 else
3975 {
3976 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3977 {
3978 // Valid attachment query
3979 }
3980 else
3981 {
3982 switch (attachment)
3983 {
3984 case GL_DEPTH_ATTACHMENT:
3985 case GL_STENCIL_ATTACHMENT:
3986 break;
3987
3988 case GL_DEPTH_STENCIL_ATTACHMENT:
3989 if (!framebuffer->hasValidDepthStencil())
3990 {
3991 context->handleError(Error(GL_INVALID_OPERATION));
3992 return false;
3993 }
3994 break;
3995
3996 default:
3997 context->handleError(Error(GL_INVALID_OPERATION));
3998 return false;
3999 }
4000 }
4001 }
4002
4003 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
4004 if (attachmentObject)
4005 {
4006 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
4007 attachmentObject->type() == GL_TEXTURE ||
4008 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
4009
4010 switch (pname)
4011 {
4012 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4013 if (attachmentObject->type() != GL_RENDERBUFFER &&
4014 attachmentObject->type() != GL_TEXTURE)
4015 {
4016 context->handleError(Error(GL_INVALID_ENUM));
4017 return false;
4018 }
4019 break;
4020
4021 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
4022 if (attachmentObject->type() != GL_TEXTURE)
4023 {
4024 context->handleError(Error(GL_INVALID_ENUM));
4025 return false;
4026 }
4027 break;
4028
4029 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
4030 if (attachmentObject->type() != GL_TEXTURE)
4031 {
4032 context->handleError(Error(GL_INVALID_ENUM));
4033 return false;
4034 }
4035 break;
4036
4037 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4038 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
4039 {
4040 context->handleError(Error(GL_INVALID_OPERATION));
4041 return false;
4042 }
4043 break;
4044
4045 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
4046 if (attachmentObject->type() != GL_TEXTURE)
4047 {
4048 context->handleError(Error(GL_INVALID_ENUM));
4049 return false;
4050 }
4051 break;
4052
4053 default:
4054 break;
4055 }
4056 }
4057 else
4058 {
4059 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
4060 // is NONE, then querying any other pname will generate INVALID_ENUM.
4061
4062 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
4063 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
4064 // INVALID_OPERATION for all other pnames
4065
4066 switch (pname)
4067 {
4068 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
4069 break;
4070
4071 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4072 if (clientVersion < 3)
4073 {
4074 context->handleError(Error(GL_INVALID_ENUM));
4075 return false;
4076 }
4077 break;
4078
4079 default:
4080 if (clientVersion < 3)
4081 {
4082 context->handleError(Error(GL_INVALID_ENUM));
4083 return false;
4084 }
4085 else
4086 {
4087 context->handleError(Error(GL_INVALID_OPERATION));
4088 return false;
4089 }
4090 }
4091 }
4092
4093 return true;
4094}
4095
4096bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
4097 GLenum target,
4098 GLenum attachment,
4099 GLenum pname,
4100 GLsizei bufSize,
4101 GLsizei *numParams)
4102{
4103 if (!ValidateRobustEntryPoint(context, bufSize))
4104 {
4105 return false;
4106 }
4107
Jamie Madillbe849e42017-05-02 15:49:00 -04004108 if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname,
4109 numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004110 {
4111 return false;
4112 }
4113
4114 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4115 {
4116 return false;
4117 }
4118
4119 return true;
4120}
4121
Geoff Langff5b2d52016-09-07 11:32:23 -04004122bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
4123 GLenum target,
4124 GLenum pname,
4125 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04004126 GLsizei *length,
4127 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04004128{
4129 if (!ValidateRobustEntryPoint(context, bufSize))
4130 {
4131 return false;
4132 }
4133
Geoff Langebebe1c2016-10-14 12:01:31 -04004134 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004135 {
4136 return false;
4137 }
4138
Geoff Langebebe1c2016-10-14 12:01:31 -04004139 if (!ValidateRobustBufferSize(context, bufSize, *length))
4140 {
4141 return false;
4142 }
4143
4144 return true;
4145}
4146
4147bool ValidateGetBufferParameteri64v(ValidationContext *context,
4148 GLenum target,
4149 GLenum pname,
4150 GLint64 *params)
4151{
4152 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
4153}
4154
4155bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
4156 GLenum target,
4157 GLenum pname,
4158 GLsizei bufSize,
4159 GLsizei *length,
4160 GLint64 *params)
4161{
4162 if (!ValidateRobustEntryPoint(context, bufSize))
4163 {
4164 return false;
4165 }
4166
4167 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
4168 {
4169 return false;
4170 }
4171
4172 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004173 {
4174 return false;
4175 }
4176
4177 return true;
4178}
4179
Jamie Madillbe849e42017-05-02 15:49:00 -04004180bool ValidateGetProgramivBase(ValidationContext *context,
4181 GLuint program,
4182 GLenum pname,
4183 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04004184{
4185 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08004186 if (numParams)
4187 {
4188 *numParams = 1;
4189 }
Geoff Langff5b2d52016-09-07 11:32:23 -04004190
4191 Program *programObject = GetValidProgram(context, program);
4192 if (!programObject)
4193 {
4194 return false;
4195 }
4196
4197 switch (pname)
4198 {
4199 case GL_DELETE_STATUS:
4200 case GL_LINK_STATUS:
4201 case GL_VALIDATE_STATUS:
4202 case GL_INFO_LOG_LENGTH:
4203 case GL_ATTACHED_SHADERS:
4204 case GL_ACTIVE_ATTRIBUTES:
4205 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
4206 case GL_ACTIVE_UNIFORMS:
4207 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
4208 break;
4209
4210 case GL_PROGRAM_BINARY_LENGTH:
4211 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
4212 {
4213 context->handleError(Error(GL_INVALID_ENUM,
4214 "Querying GL_PROGRAM_BINARY_LENGTH requires "
4215 "GL_OES_get_program_binary or ES 3.0."));
4216 return false;
4217 }
4218 break;
4219
4220 case GL_ACTIVE_UNIFORM_BLOCKS:
4221 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
4222 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
4223 case GL_TRANSFORM_FEEDBACK_VARYINGS:
4224 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
4225 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
4226 if (context->getClientMajorVersion() < 3)
4227 {
4228 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
4229 return false;
4230 }
4231 break;
4232
Yunchao He61afff12017-03-14 15:34:03 +08004233 case GL_PROGRAM_SEPARABLE:
4234 if (context->getClientVersion() < Version(3, 1))
4235 {
4236 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.1."));
4237 return false;
4238 }
4239 break;
4240
Geoff Langff5b2d52016-09-07 11:32:23 -04004241 default:
4242 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
4243 return false;
4244 }
4245
4246 return true;
4247}
4248
4249bool ValidateGetProgramivRobustANGLE(Context *context,
4250 GLuint program,
4251 GLenum pname,
4252 GLsizei bufSize,
4253 GLsizei *numParams)
4254{
4255 if (!ValidateRobustEntryPoint(context, bufSize))
4256 {
4257 return false;
4258 }
4259
Jamie Madillbe849e42017-05-02 15:49:00 -04004260 if (!ValidateGetProgramivBase(context, program, pname, numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004261 {
4262 return false;
4263 }
4264
4265 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4266 {
4267 return false;
4268 }
4269
4270 return true;
4271}
4272
Geoff Lang740d9022016-10-07 11:20:52 -04004273bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
4274 GLenum target,
4275 GLenum pname,
4276 GLsizei bufSize,
4277 GLsizei *length,
4278 GLint *params)
4279{
4280 if (!ValidateRobustEntryPoint(context, bufSize))
4281 {
4282 return false;
4283 }
4284
4285 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
4286 {
4287 return false;
4288 }
4289
4290 if (!ValidateRobustBufferSize(context, bufSize, *length))
4291 {
4292 return false;
4293 }
4294
4295 return true;
4296}
4297
Geoff Langd7d0ed32016-10-07 11:33:51 -04004298bool ValidateGetShaderivRobustANGLE(Context *context,
4299 GLuint shader,
4300 GLenum pname,
4301 GLsizei bufSize,
4302 GLsizei *length,
4303 GLint *params)
4304{
4305 if (!ValidateRobustEntryPoint(context, bufSize))
4306 {
4307 return false;
4308 }
4309
4310 if (!ValidateGetShaderivBase(context, shader, pname, length))
4311 {
4312 return false;
4313 }
4314
4315 if (!ValidateRobustBufferSize(context, bufSize, *length))
4316 {
4317 return false;
4318 }
4319
4320 return true;
4321}
4322
Geoff Langc1984ed2016-10-07 12:41:00 -04004323bool ValidateGetTexParameterfvRobustANGLE(Context *context,
4324 GLenum target,
4325 GLenum pname,
4326 GLsizei bufSize,
4327 GLsizei *length,
4328 GLfloat *params)
4329{
4330 if (!ValidateRobustEntryPoint(context, bufSize))
4331 {
4332 return false;
4333 }
4334
4335 if (!ValidateGetTexParameterBase(context, target, pname, length))
4336 {
4337 return false;
4338 }
4339
4340 if (!ValidateRobustBufferSize(context, bufSize, *length))
4341 {
4342 return false;
4343 }
4344
4345 return true;
4346}
4347
Geoff Langc1984ed2016-10-07 12:41:00 -04004348bool ValidateGetTexParameterivRobustANGLE(Context *context,
4349 GLenum target,
4350 GLenum pname,
4351 GLsizei bufSize,
4352 GLsizei *length,
4353 GLint *params)
4354{
4355 if (!ValidateRobustEntryPoint(context, bufSize))
4356 {
4357 return false;
4358 }
4359
4360 if (!ValidateGetTexParameterBase(context, target, pname, length))
4361 {
4362 return false;
4363 }
4364
4365 if (!ValidateRobustBufferSize(context, bufSize, *length))
4366 {
4367 return false;
4368 }
4369
4370 return true;
4371}
4372
Geoff Langc1984ed2016-10-07 12:41:00 -04004373bool ValidateTexParameterfvRobustANGLE(Context *context,
4374 GLenum target,
4375 GLenum pname,
4376 GLsizei bufSize,
4377 const GLfloat *params)
4378{
4379 if (!ValidateRobustEntryPoint(context, bufSize))
4380 {
4381 return false;
4382 }
4383
4384 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4385}
4386
Geoff Langc1984ed2016-10-07 12:41:00 -04004387bool ValidateTexParameterivRobustANGLE(Context *context,
4388 GLenum target,
4389 GLenum pname,
4390 GLsizei bufSize,
4391 const GLint *params)
4392{
4393 if (!ValidateRobustEntryPoint(context, bufSize))
4394 {
4395 return false;
4396 }
4397
4398 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4399}
4400
4401bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
4402{
4403 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4404}
4405
4406bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
4407 GLuint sampler,
4408 GLenum pname,
4409 GLuint bufSize,
4410 GLsizei *length,
4411 GLfloat *params)
4412{
4413 if (!ValidateRobustEntryPoint(context, bufSize))
4414 {
4415 return false;
4416 }
4417
4418 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4419 {
4420 return false;
4421 }
4422
4423 if (!ValidateRobustBufferSize(context, bufSize, *length))
4424 {
4425 return false;
4426 }
4427
4428 return true;
4429}
4430
4431bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
4432{
4433 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4434}
4435
4436bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
4437 GLuint sampler,
4438 GLenum pname,
4439 GLuint bufSize,
4440 GLsizei *length,
4441 GLint *params)
4442{
4443 if (!ValidateRobustEntryPoint(context, bufSize))
4444 {
4445 return false;
4446 }
4447
4448 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4449 {
4450 return false;
4451 }
4452
4453 if (!ValidateRobustBufferSize(context, bufSize, *length))
4454 {
4455 return false;
4456 }
4457
4458 return true;
4459}
4460
4461bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
4462{
4463 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4464}
4465
4466bool ValidateSamplerParameterfv(Context *context,
4467 GLuint sampler,
4468 GLenum pname,
4469 const GLfloat *params)
4470{
4471 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4472}
4473
4474bool ValidateSamplerParameterfvRobustANGLE(Context *context,
4475 GLuint sampler,
4476 GLenum pname,
4477 GLsizei bufSize,
4478 const GLfloat *params)
4479{
4480 if (!ValidateRobustEntryPoint(context, bufSize))
4481 {
4482 return false;
4483 }
4484
4485 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4486}
4487
4488bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
4489{
4490 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4491}
4492
4493bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
4494{
4495 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4496}
4497
4498bool ValidateSamplerParameterivRobustANGLE(Context *context,
4499 GLuint sampler,
4500 GLenum pname,
4501 GLsizei bufSize,
4502 const GLint *params)
4503{
4504 if (!ValidateRobustEntryPoint(context, bufSize))
4505 {
4506 return false;
4507 }
4508
4509 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4510}
4511
Geoff Lang0b031062016-10-13 14:30:04 -04004512bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
4513 GLuint index,
4514 GLenum pname,
4515 GLsizei bufSize,
4516 GLsizei *length,
4517 GLfloat *params)
4518{
4519 if (!ValidateRobustEntryPoint(context, bufSize))
4520 {
4521 return false;
4522 }
4523
4524 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4525 {
4526 return false;
4527 }
4528
4529 if (!ValidateRobustBufferSize(context, bufSize, *length))
4530 {
4531 return false;
4532 }
4533
4534 return true;
4535}
4536
Geoff Lang0b031062016-10-13 14:30:04 -04004537bool ValidateGetVertexAttribivRobustANGLE(Context *context,
4538 GLuint index,
4539 GLenum pname,
4540 GLsizei bufSize,
4541 GLsizei *length,
4542 GLint *params)
4543{
4544 if (!ValidateRobustEntryPoint(context, bufSize))
4545 {
4546 return false;
4547 }
4548
4549 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4550 {
4551 return false;
4552 }
4553
4554 if (!ValidateRobustBufferSize(context, bufSize, *length))
4555 {
4556 return false;
4557 }
4558
4559 return true;
4560}
4561
Geoff Lang0b031062016-10-13 14:30:04 -04004562bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
4563 GLuint index,
4564 GLenum pname,
4565 GLsizei bufSize,
4566 GLsizei *length,
4567 void **pointer)
4568{
4569 if (!ValidateRobustEntryPoint(context, bufSize))
4570 {
4571 return false;
4572 }
4573
4574 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
4575 {
4576 return false;
4577 }
4578
4579 if (!ValidateRobustBufferSize(context, bufSize, *length))
4580 {
4581 return false;
4582 }
4583
4584 return true;
4585}
4586
4587bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
4588{
4589 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4590}
4591
4592bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
4593 GLuint index,
4594 GLenum pname,
4595 GLsizei bufSize,
4596 GLsizei *length,
4597 GLint *params)
4598{
4599 if (!ValidateRobustEntryPoint(context, bufSize))
4600 {
4601 return false;
4602 }
4603
4604 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4605 {
4606 return false;
4607 }
4608
4609 if (!ValidateRobustBufferSize(context, bufSize, *length))
4610 {
4611 return false;
4612 }
4613
4614 return true;
4615}
4616
4617bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
4618{
4619 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4620}
4621
4622bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
4623 GLuint index,
4624 GLenum pname,
4625 GLsizei bufSize,
4626 GLsizei *length,
4627 GLuint *params)
4628{
4629 if (!ValidateRobustEntryPoint(context, bufSize))
4630 {
4631 return false;
4632 }
4633
4634 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4635 {
4636 return false;
4637 }
4638
4639 if (!ValidateRobustBufferSize(context, bufSize, *length))
4640 {
4641 return false;
4642 }
4643
4644 return true;
4645}
4646
Geoff Lang6899b872016-10-14 11:30:13 -04004647bool ValidateGetActiveUniformBlockiv(Context *context,
4648 GLuint program,
4649 GLuint uniformBlockIndex,
4650 GLenum pname,
4651 GLint *params)
4652{
4653 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
4654}
4655
4656bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
4657 GLuint program,
4658 GLuint uniformBlockIndex,
4659 GLenum pname,
4660 GLsizei bufSize,
4661 GLsizei *length,
4662 GLint *params)
4663{
4664 if (!ValidateRobustEntryPoint(context, bufSize))
4665 {
4666 return false;
4667 }
4668
4669 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
4670 {
4671 return false;
4672 }
4673
4674 if (!ValidateRobustBufferSize(context, bufSize, *length))
4675 {
4676 return false;
4677 }
4678
4679 return true;
4680}
4681
Geoff Lang0a9661f2016-10-20 10:59:20 -07004682bool ValidateGetInternalFormativ(Context *context,
4683 GLenum target,
4684 GLenum internalformat,
4685 GLenum pname,
4686 GLsizei bufSize,
4687 GLint *params)
4688{
4689 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
4690 nullptr);
4691}
4692
4693bool ValidateGetInternalFormativRobustANGLE(Context *context,
4694 GLenum target,
4695 GLenum internalformat,
4696 GLenum pname,
4697 GLsizei bufSize,
4698 GLsizei *length,
4699 GLint *params)
4700{
4701 if (!ValidateRobustEntryPoint(context, bufSize))
4702 {
4703 return false;
4704 }
4705
4706 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
4707 {
4708 return false;
4709 }
4710
4711 if (!ValidateRobustBufferSize(context, bufSize, *length))
4712 {
4713 return false;
4714 }
4715
4716 return true;
4717}
4718
Shao80957d92017-02-20 21:25:59 +08004719bool ValidateVertexFormatBase(ValidationContext *context,
4720 GLuint attribIndex,
4721 GLint size,
4722 GLenum type,
4723 GLboolean pureInteger)
4724{
4725 const Caps &caps = context->getCaps();
4726 if (attribIndex >= caps.maxVertexAttributes)
4727 {
4728 context->handleError(
4729 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
4730 return false;
4731 }
4732
4733 if (size < 1 || size > 4)
4734 {
4735 context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
4736 }
4737
4738 switch (type)
4739 {
4740 case GL_BYTE:
4741 case GL_UNSIGNED_BYTE:
4742 case GL_SHORT:
4743 case GL_UNSIGNED_SHORT:
4744 break;
4745
4746 case GL_INT:
4747 case GL_UNSIGNED_INT:
4748 if (context->getClientMajorVersion() < 3)
4749 {
4750 context->handleError(
4751 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4752 return false;
4753 }
4754 break;
4755
4756 case GL_FIXED:
4757 case GL_FLOAT:
4758 if (pureInteger)
4759 {
4760 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4761 return false;
4762 }
4763 break;
4764
4765 case GL_HALF_FLOAT:
4766 if (context->getClientMajorVersion() < 3)
4767 {
4768 context->handleError(
4769 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4770 return false;
4771 }
4772 if (pureInteger)
4773 {
4774 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4775 return false;
4776 }
4777 break;
4778
4779 case GL_INT_2_10_10_10_REV:
4780 case GL_UNSIGNED_INT_2_10_10_10_REV:
4781 if (context->getClientMajorVersion() < 3)
4782 {
4783 context->handleError(
4784 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4785 return false;
4786 }
4787 if (pureInteger)
4788 {
4789 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4790 return false;
4791 }
4792 if (size != 4)
4793 {
4794 context->handleError(Error(GL_INVALID_OPERATION,
4795 "Type is INT_2_10_10_10_REV or "
4796 "UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
4797 return false;
4798 }
4799 break;
4800
4801 default:
4802 context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
4803 return false;
4804 }
4805
4806 return true;
4807}
4808
Geoff Lang76e65652017-03-27 14:58:02 -04004809// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
4810// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
4811// specified clear value and the type of a buffer that is being cleared generates an
4812// INVALID_OPERATION error instead of producing undefined results
4813bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
4814 GLint drawbuffer,
4815 const GLenum *validComponentTypes,
4816 size_t validComponentTypeCount)
4817{
4818 const FramebufferAttachment *attachment =
4819 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
4820 if (attachment)
4821 {
4822 GLenum componentType = attachment->getFormat().info->componentType;
4823 const GLenum *end = validComponentTypes + validComponentTypeCount;
4824 if (std::find(validComponentTypes, end, componentType) == end)
4825 {
4826 context->handleError(
4827 Error(GL_INVALID_OPERATION,
4828 "No defined conversion between clear value and attachment format."));
4829 return false;
4830 }
4831 }
4832
4833 return true;
4834}
4835
Corentin Wallezb2931602017-04-11 15:58:57 -04004836bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
4837 GLsizei imageSize,
4838 GLsizei dataSize)
4839{
4840 if (!ValidateRobustEntryPoint(context, dataSize))
4841 {
4842 return false;
4843 }
4844
4845 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
4846 if (pixelUnpackBuffer == nullptr)
4847 {
4848 if (dataSize < imageSize)
4849 {
4850 context->handleError(
4851 Error(GL_INVALID_OPERATION, "dataSize must be at least %i.", imageSize));
4852 }
4853 }
4854 return true;
4855}
4856
Jamie Madillbe849e42017-05-02 15:49:00 -04004857bool ValidateGetBufferParameterBase(ValidationContext *context,
4858 GLenum target,
4859 GLenum pname,
4860 bool pointerVersion,
4861 GLsizei *numParams)
4862{
4863 if (numParams)
4864 {
4865 *numParams = 0;
4866 }
4867
4868 if (!ValidBufferTarget(context, target))
4869 {
4870 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
4871 return false;
4872 }
4873
4874 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
4875 if (!buffer)
4876 {
4877 // A null buffer means that "0" is bound to the requested buffer target
4878 context->handleError(Error(GL_INVALID_OPERATION, "No buffer bound."));
4879 return false;
4880 }
4881
4882 const Extensions &extensions = context->getExtensions();
4883
4884 switch (pname)
4885 {
4886 case GL_BUFFER_USAGE:
4887 case GL_BUFFER_SIZE:
4888 break;
4889
4890 case GL_BUFFER_ACCESS_OES:
4891 if (!extensions.mapBuffer)
4892 {
4893 context->handleError(
4894 Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
4895 return false;
4896 }
4897 break;
4898
4899 case GL_BUFFER_MAPPED:
4900 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
4901 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
4902 !extensions.mapBufferRange)
4903 {
4904 context->handleError(Error(
4905 GL_INVALID_ENUM,
4906 "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
4907 return false;
4908 }
4909 break;
4910
4911 case GL_BUFFER_MAP_POINTER:
4912 if (!pointerVersion)
4913 {
4914 context->handleError(
4915 Error(GL_INVALID_ENUM,
4916 "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."));
4917 return false;
4918 }
4919 break;
4920
4921 case GL_BUFFER_ACCESS_FLAGS:
4922 case GL_BUFFER_MAP_OFFSET:
4923 case GL_BUFFER_MAP_LENGTH:
4924 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
4925 {
4926 context->handleError(Error(
4927 GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."));
4928 return false;
4929 }
4930 break;
4931
4932 default:
4933 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4934 return false;
4935 }
4936
4937 // All buffer parameter queries return one value.
4938 if (numParams)
4939 {
4940 *numParams = 1;
4941 }
4942
4943 return true;
4944}
4945
4946bool ValidateGetRenderbufferParameterivBase(Context *context,
4947 GLenum target,
4948 GLenum pname,
4949 GLsizei *length)
4950{
4951 if (length)
4952 {
4953 *length = 0;
4954 }
4955
4956 if (target != GL_RENDERBUFFER)
4957 {
4958 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
4959 return false;
4960 }
4961
4962 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
4963 if (renderbuffer == nullptr)
4964 {
4965 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
4966 return false;
4967 }
4968
4969 switch (pname)
4970 {
4971 case GL_RENDERBUFFER_WIDTH:
4972 case GL_RENDERBUFFER_HEIGHT:
4973 case GL_RENDERBUFFER_INTERNAL_FORMAT:
4974 case GL_RENDERBUFFER_RED_SIZE:
4975 case GL_RENDERBUFFER_GREEN_SIZE:
4976 case GL_RENDERBUFFER_BLUE_SIZE:
4977 case GL_RENDERBUFFER_ALPHA_SIZE:
4978 case GL_RENDERBUFFER_DEPTH_SIZE:
4979 case GL_RENDERBUFFER_STENCIL_SIZE:
4980 break;
4981
4982 case GL_RENDERBUFFER_SAMPLES_ANGLE:
4983 if (!context->getExtensions().framebufferMultisample)
4984 {
4985 context->handleError(
4986 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
4987 return false;
4988 }
4989 break;
4990
4991 default:
4992 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4993 return false;
4994 }
4995
4996 if (length)
4997 {
4998 *length = 1;
4999 }
5000 return true;
5001}
5002
5003bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
5004{
5005 if (length)
5006 {
5007 *length = 0;
5008 }
5009
5010 if (GetValidShader(context, shader) == nullptr)
5011 {
5012 return false;
5013 }
5014
5015 switch (pname)
5016 {
5017 case GL_SHADER_TYPE:
5018 case GL_DELETE_STATUS:
5019 case GL_COMPILE_STATUS:
5020 case GL_INFO_LOG_LENGTH:
5021 case GL_SHADER_SOURCE_LENGTH:
5022 break;
5023
5024 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
5025 if (!context->getExtensions().translatedShaderSource)
5026 {
5027 context->handleError(
5028 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
5029 return false;
5030 }
5031 break;
5032
5033 default:
5034 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5035 return false;
5036 }
5037
5038 if (length)
5039 {
5040 *length = 1;
5041 }
5042 return true;
5043}
5044
5045bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
5046{
5047 if (length)
5048 {
5049 *length = 0;
5050 }
5051
5052 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5053 {
5054 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
5055 return false;
5056 }
5057
5058 if (context->getTargetTexture(target) == nullptr)
5059 {
5060 // Should only be possible for external textures
5061 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
5062 return false;
5063 }
5064
5065 switch (pname)
5066 {
5067 case GL_TEXTURE_MAG_FILTER:
5068 case GL_TEXTURE_MIN_FILTER:
5069 case GL_TEXTURE_WRAP_S:
5070 case GL_TEXTURE_WRAP_T:
5071 break;
5072
5073 case GL_TEXTURE_USAGE_ANGLE:
5074 if (!context->getExtensions().textureUsage)
5075 {
5076 context->handleError(
5077 Error(GL_INVALID_ENUM, "GL_ANGLE_texture_usage is not enabled."));
5078 return false;
5079 }
5080 break;
5081
5082 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5083 if (!context->getExtensions().textureFilterAnisotropic)
5084 {
5085 context->handleError(
5086 Error(GL_INVALID_ENUM, "GL_EXT_texture_filter_anisotropic is not enabled."));
5087 return false;
5088 }
5089 break;
5090
5091 case GL_TEXTURE_IMMUTABLE_FORMAT:
5092 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
5093 {
5094 context->handleError(
5095 Error(GL_INVALID_ENUM, "GL_EXT_texture_storage is not enabled."));
5096 return false;
5097 }
5098 break;
5099
5100 case GL_TEXTURE_WRAP_R:
5101 case GL_TEXTURE_IMMUTABLE_LEVELS:
5102 case GL_TEXTURE_SWIZZLE_R:
5103 case GL_TEXTURE_SWIZZLE_G:
5104 case GL_TEXTURE_SWIZZLE_B:
5105 case GL_TEXTURE_SWIZZLE_A:
5106 case GL_TEXTURE_BASE_LEVEL:
5107 case GL_TEXTURE_MAX_LEVEL:
5108 case GL_TEXTURE_MIN_LOD:
5109 case GL_TEXTURE_MAX_LOD:
5110 case GL_TEXTURE_COMPARE_MODE:
5111 case GL_TEXTURE_COMPARE_FUNC:
5112 if (context->getClientMajorVersion() < 3)
5113 {
5114 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
5115 return false;
5116 }
5117 break;
5118
5119 case GL_TEXTURE_SRGB_DECODE_EXT:
5120 if (!context->getExtensions().textureSRGBDecode)
5121 {
5122 context->handleError(
5123 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
5124 return false;
5125 }
5126 break;
5127
5128 default:
5129 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5130 return false;
5131 }
5132
5133 if (length)
5134 {
5135 *length = 1;
5136 }
5137 return true;
5138}
5139
5140bool ValidateGetVertexAttribBase(Context *context,
5141 GLuint index,
5142 GLenum pname,
5143 GLsizei *length,
5144 bool pointer,
5145 bool pureIntegerEntryPoint)
5146{
5147 if (length)
5148 {
5149 *length = 0;
5150 }
5151
5152 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
5153 {
5154 context->handleError(
5155 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
5156 return false;
5157 }
5158
5159 if (index >= context->getCaps().maxVertexAttributes)
5160 {
5161 context->handleError(Error(
5162 GL_INVALID_VALUE, "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES."));
5163 return false;
5164 }
5165
5166 if (pointer)
5167 {
5168 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
5169 {
5170 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5171 return false;
5172 }
5173 }
5174 else
5175 {
5176 switch (pname)
5177 {
5178 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
5179 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
5180 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
5181 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
5182 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
5183 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
5184 case GL_CURRENT_VERTEX_ATTRIB:
5185 break;
5186
5187 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
5188 static_assert(
5189 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
5190 "ANGLE extension enums not equal to GL enums.");
5191 if (context->getClientMajorVersion() < 3 &&
5192 !context->getExtensions().instancedArrays)
5193 {
5194 context->handleError(Error(GL_INVALID_ENUM,
5195 "GL_VERTEX_ATTRIB_ARRAY_DIVISOR requires OpenGL ES "
5196 "3.0 or GL_ANGLE_instanced_arrays."));
5197 return false;
5198 }
5199 break;
5200
5201 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
5202 if (context->getClientMajorVersion() < 3)
5203 {
5204 context->handleError(Error(
5205 GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
5206 return false;
5207 }
5208 break;
5209
5210 case GL_VERTEX_ATTRIB_BINDING:
5211 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
5212 if (context->getClientVersion() < ES_3_1)
5213 {
5214 context->handleError(
5215 Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
5216 return false;
5217 }
5218 break;
5219
5220 default:
5221 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5222 return false;
5223 }
5224 }
5225
5226 if (length)
5227 {
5228 if (pname == GL_CURRENT_VERTEX_ATTRIB)
5229 {
5230 *length = 4;
5231 }
5232 else
5233 {
5234 *length = 1;
5235 }
5236 }
5237
5238 return true;
5239}
5240
5241bool ValidateReadPixelsBase(ValidationContext *context,
5242 GLint x,
5243 GLint y,
5244 GLsizei width,
5245 GLsizei height,
5246 GLenum format,
5247 GLenum type,
5248 GLsizei bufSize,
5249 GLsizei *length,
5250 GLsizei *columns,
5251 GLsizei *rows,
5252 void *pixels)
5253{
5254 if (length != nullptr)
5255 {
5256 *length = 0;
5257 }
5258 if (rows != nullptr)
5259 {
5260 *rows = 0;
5261 }
5262 if (columns != nullptr)
5263 {
5264 *columns = 0;
5265 }
5266
5267 if (width < 0 || height < 0)
5268 {
5269 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
5270 return false;
5271 }
5272
5273 auto readFramebuffer = context->getGLState().getReadFramebuffer();
5274
5275 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
5276 {
5277 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
5278 return false;
5279 }
5280
5281 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
5282 {
5283 context->handleError(Error(GL_INVALID_OPERATION));
5284 return false;
5285 }
5286
5287 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
5288 ASSERT(framebuffer);
5289
5290 if (framebuffer->getReadBufferState() == GL_NONE)
5291 {
5292 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
5293 return false;
5294 }
5295
5296 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
5297 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
5298 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
5299 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
5300 // situation is an application error that would lead to a crash in ANGLE.
5301 if (readBuffer == nullptr)
5302 {
5303 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
5304 return false;
5305 }
5306
5307 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
5308 GLenum currentType = framebuffer->getImplementationColorReadType();
5309 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
5310
5311 bool validFormatTypeCombination =
5312 ValidReadPixelsFormatType(context, currentComponentType, format, type);
5313
5314 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
5315 {
5316 context->handleError(Error(GL_INVALID_OPERATION));
5317 return false;
5318 }
5319
5320 // Check for pixel pack buffer related API errors
5321 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
5322 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
5323 {
5324 // ...the buffer object's data store is currently mapped.
5325 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
5326 return false;
5327 }
5328
5329 // .. the data would be packed to the buffer object such that the memory writes required
5330 // would exceed the data store size.
5331 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
5332 const gl::Extents size(width, height, 1);
5333 const auto &pack = context->getGLState().getPackState();
5334
5335 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
5336 if (endByteOrErr.isError())
5337 {
5338 context->handleError(endByteOrErr.getError());
5339 return false;
5340 }
5341
5342 size_t endByte = endByteOrErr.getResult();
5343 if (bufSize >= 0)
5344 {
5345 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
5346 {
5347 context->handleError(
5348 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
5349 return false;
5350 }
5351 }
5352
5353 if (pixelPackBuffer != nullptr)
5354 {
5355 CheckedNumeric<size_t> checkedEndByte(endByte);
5356 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
5357 checkedEndByte += checkedOffset;
5358
5359 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
5360 {
5361 // Overflow past the end of the buffer
5362 context->handleError(
5363 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
5364 return false;
5365 }
5366 }
5367
5368 if (pixelPackBuffer == nullptr && length != nullptr)
5369 {
5370 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
5371 {
5372 context->handleError(
5373 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
5374 return false;
5375 }
5376
5377 *length = static_cast<GLsizei>(endByte);
5378 }
5379
5380 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
5381 angle::CheckedNumeric<int> clippedExtent(length);
5382 if (start < 0)
5383 {
5384 // "subtract" the area that is less than 0
5385 clippedExtent += start;
5386 }
5387
5388 const int readExtent = start + length;
5389 if (readExtent > bufferSize)
5390 {
5391 // Subtract the region to the right of the read buffer
5392 clippedExtent -= (readExtent - bufferSize);
5393 }
5394
5395 if (!clippedExtent.IsValid())
5396 {
5397 return 0;
5398 }
5399
5400 return std::max(clippedExtent.ValueOrDie(), 0);
5401 };
5402
5403 if (columns != nullptr)
5404 {
5405 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
5406 }
5407
5408 if (rows != nullptr)
5409 {
5410 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
5411 }
5412
5413 return true;
5414}
5415
5416template <typename ParamType>
5417bool ValidateTexParameterBase(Context *context,
5418 GLenum target,
5419 GLenum pname,
5420 GLsizei bufSize,
5421 const ParamType *params)
5422{
5423 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5424 {
5425 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
5426 return false;
5427 }
5428
5429 if (context->getTargetTexture(target) == nullptr)
5430 {
5431 // Should only be possible for external textures
5432 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
5433 return false;
5434 }
5435
5436 const GLsizei minBufSize = 1;
5437 if (bufSize >= 0 && bufSize < minBufSize)
5438 {
5439 context->handleError(
5440 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
5441 return false;
5442 }
5443
5444 switch (pname)
5445 {
5446 case GL_TEXTURE_WRAP_R:
5447 case GL_TEXTURE_SWIZZLE_R:
5448 case GL_TEXTURE_SWIZZLE_G:
5449 case GL_TEXTURE_SWIZZLE_B:
5450 case GL_TEXTURE_SWIZZLE_A:
5451 case GL_TEXTURE_BASE_LEVEL:
5452 case GL_TEXTURE_MAX_LEVEL:
5453 case GL_TEXTURE_COMPARE_MODE:
5454 case GL_TEXTURE_COMPARE_FUNC:
5455 case GL_TEXTURE_MIN_LOD:
5456 case GL_TEXTURE_MAX_LOD:
5457 if (context->getClientMajorVersion() < 3)
5458 {
5459 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
5460 return false;
5461 }
5462 if (target == GL_TEXTURE_EXTERNAL_OES &&
5463 !context->getExtensions().eglImageExternalEssl3)
5464 {
5465 context->handleError(Error(GL_INVALID_ENUM,
5466 "ES3 texture parameters are not available without "
5467 "GL_OES_EGL_image_external_essl3."));
5468 return false;
5469 }
5470 break;
5471
5472 default:
5473 break;
5474 }
5475
5476 switch (pname)
5477 {
5478 case GL_TEXTURE_WRAP_S:
5479 case GL_TEXTURE_WRAP_T:
5480 case GL_TEXTURE_WRAP_R:
5481 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5482 {
5483 return false;
5484 }
5485 break;
5486
5487 case GL_TEXTURE_MIN_FILTER:
5488 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5489 {
5490 return false;
5491 }
5492 break;
5493
5494 case GL_TEXTURE_MAG_FILTER:
5495 if (!ValidateTextureMagFilterValue(context, params))
5496 {
5497 return false;
5498 }
5499 break;
5500
5501 case GL_TEXTURE_USAGE_ANGLE:
5502 switch (ConvertToGLenum(params[0]))
5503 {
5504 case GL_NONE:
5505 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
5506 break;
5507
5508 default:
5509 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5510 return false;
5511 }
5512 break;
5513
5514 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5515 if (!context->getExtensions().textureFilterAnisotropic)
5516 {
5517 context->handleError(
5518 Error(GL_INVALID_ENUM, "GL_EXT_texture_anisotropic is not enabled."));
5519 return false;
5520 }
5521
5522 // we assume the parameter passed to this validation method is truncated, not rounded
5523 if (params[0] < 1)
5524 {
5525 context->handleError(Error(GL_INVALID_VALUE, "Max anisotropy must be at least 1."));
5526 return false;
5527 }
5528 break;
5529
5530 case GL_TEXTURE_MIN_LOD:
5531 case GL_TEXTURE_MAX_LOD:
5532 // any value is permissible
5533 break;
5534
5535 case GL_TEXTURE_COMPARE_MODE:
5536 if (!ValidateTextureCompareModeValue(context, params))
5537 {
5538 return false;
5539 }
5540 break;
5541
5542 case GL_TEXTURE_COMPARE_FUNC:
5543 if (!ValidateTextureCompareFuncValue(context, params))
5544 {
5545 return false;
5546 }
5547 break;
5548
5549 case GL_TEXTURE_SWIZZLE_R:
5550 case GL_TEXTURE_SWIZZLE_G:
5551 case GL_TEXTURE_SWIZZLE_B:
5552 case GL_TEXTURE_SWIZZLE_A:
5553 switch (ConvertToGLenum(params[0]))
5554 {
5555 case GL_RED:
5556 case GL_GREEN:
5557 case GL_BLUE:
5558 case GL_ALPHA:
5559 case GL_ZERO:
5560 case GL_ONE:
5561 break;
5562
5563 default:
5564 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5565 return false;
5566 }
5567 break;
5568
5569 case GL_TEXTURE_BASE_LEVEL:
5570 if (params[0] < 0)
5571 {
5572 context->handleError(Error(GL_INVALID_VALUE, "Base level must be at least 0."));
5573 return false;
5574 }
5575 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
5576 {
5577 context->handleError(
5578 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
5579 return false;
5580 }
5581 break;
5582
5583 case GL_TEXTURE_MAX_LEVEL:
5584 if (params[0] < 0)
5585 {
5586 context->handleError(Error(GL_INVALID_VALUE, "Max level must be at least 0."));
5587 return false;
5588 }
5589 break;
5590
5591 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5592 if (context->getClientVersion() < Version(3, 1))
5593 {
5594 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.1."));
5595 return false;
5596 }
5597 switch (ConvertToGLenum(params[0]))
5598 {
5599 case GL_DEPTH_COMPONENT:
5600 case GL_STENCIL_INDEX:
5601 break;
5602
5603 default:
5604 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5605 return false;
5606 }
5607 break;
5608
5609 case GL_TEXTURE_SRGB_DECODE_EXT:
5610 if (!ValidateTextureSRGBDecodeValue(context, params))
5611 {
5612 return false;
5613 }
5614 break;
5615
5616 default:
5617 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5618 return false;
5619 }
5620
5621 return true;
5622}
5623
5624template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *);
5625template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *);
5626
Jamie Madillc29968b2016-01-20 11:17:23 -05005627} // namespace gl