blob: ae87b896b0df239252996583071c0e4b0c3e1c35 [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:
Geoff Langfff7a7d2017-06-02 10:39:17 -04001070 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
1071 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
1072 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
1073 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
Minmin Gonge3939b92015-12-01 15:36:51 -08001074 case GL_ETC1_RGB8_LOSSY_DECODE_ANGLE:
Minmin Gong390208b2017-02-28 18:03:06 -08001075 case GL_COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE:
1076 case GL_COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE:
1077 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1078 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE:
1079 case GL_COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
1080 case GL_COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE:
Geoff Lang0d8b7242015-09-09 14:56:53 -04001081 return true;
1082
1083 default:
1084 return false;
1085 }
1086}
1087
Geoff Lang966c9402017-04-18 12:38:27 -04001088bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed)
1089{
1090 return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) ||
1091 (size % blockSize == 0);
1092}
1093
Jamie Madillc29968b2016-01-20 11:17:23 -05001094bool ValidCompressedImageSize(const ValidationContext *context,
1095 GLenum internalFormat,
Geoff Lang966c9402017-04-18 12:38:27 -04001096 GLint level,
Jamie Madillc29968b2016-01-20 11:17:23 -05001097 GLsizei width,
1098 GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -04001099{
Geoff Langca271392017-04-05 12:30:00 -04001100 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
Geoff Lang5d601382014-07-22 15:14:06 -04001101 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -04001102 {
1103 return false;
1104 }
1105
Geoff Lang966c9402017-04-18 12:38:27 -04001106 if (width < 0 || height < 0)
1107 {
1108 return false;
1109 }
1110
1111 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1112 {
1113 // The ANGLE extensions allow specifying compressed textures with sizes smaller than the
1114 // block size for level 0 but WebGL disallows this.
1115 bool smallerThanBlockSizeAllowed =
1116 level > 0 || !context->getExtensions().webglCompatibility;
1117
1118 if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth,
1119 smallerThanBlockSizeAllowed) ||
1120 !ValidCompressedDimension(height, formatInfo.compressedBlockHeight,
1121 smallerThanBlockSizeAllowed))
1122 {
1123 return false;
1124 }
1125 }
1126
1127 return true;
1128}
1129
1130bool ValidCompressedSubImageSize(const ValidationContext *context,
1131 GLenum internalFormat,
1132 GLint xoffset,
1133 GLint yoffset,
1134 GLsizei width,
1135 GLsizei height,
1136 size_t textureWidth,
1137 size_t textureHeight)
1138{
1139 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
1140 if (!formatInfo.compressed)
1141 {
1142 return false;
1143 }
1144
Geoff Lang44ff5a72017-02-03 15:15:43 -05001145 if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
Geoff Langd4f180b2013-09-24 13:57:44 -04001146 {
1147 return false;
1148 }
1149
Geoff Lang0d8b7242015-09-09 14:56:53 -04001150 if (CompressedTextureFormatRequiresExactSize(internalFormat))
1151 {
Geoff Lang44ff5a72017-02-03 15:15:43 -05001152 if (xoffset % formatInfo.compressedBlockWidth != 0 ||
Geoff Lang966c9402017-04-18 12:38:27 -04001153 yoffset % formatInfo.compressedBlockHeight != 0)
1154 {
1155 return false;
1156 }
1157
1158 // Allowed to either have data that is a multiple of block size or is smaller than the block
1159 // size but fills the entire mip
1160 bool fillsEntireMip = xoffset == 0 && yoffset == 0 &&
1161 static_cast<size_t>(width) == textureWidth &&
1162 static_cast<size_t>(height) == textureHeight;
1163 bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
1164 (height % formatInfo.compressedBlockHeight) == 0;
1165 if (!sizeMultipleOfBlockSize && !fillsEntireMip)
Geoff Lang0d8b7242015-09-09 14:56:53 -04001166 {
1167 return false;
1168 }
1169 }
1170
Geoff Langd4f180b2013-09-24 13:57:44 -04001171 return true;
1172}
1173
Geoff Langff5b2d52016-09-07 11:32:23 -04001174bool ValidImageDataSize(ValidationContext *context,
1175 GLenum textureTarget,
1176 GLsizei width,
1177 GLsizei height,
1178 GLsizei depth,
1179 GLenum internalFormat,
1180 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04001181 const void *pixels,
Geoff Langff5b2d52016-09-07 11:32:23 -04001182 GLsizei imageSize)
1183{
1184 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
1185 if (pixelUnpackBuffer == nullptr && imageSize < 0)
1186 {
1187 // Checks are not required
1188 return true;
1189 }
1190
1191 // ...the data would be unpacked from the buffer object such that the memory reads required
1192 // would exceed the data store size.
Geoff Langca271392017-04-05 12:30:00 -04001193 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
Geoff Langff5b2d52016-09-07 11:32:23 -04001194 const gl::Extents size(width, height, depth);
1195 const auto &unpack = context->getGLState().getUnpackState();
1196
1197 bool targetIs3D = textureTarget == GL_TEXTURE_3D || textureTarget == GL_TEXTURE_2D_ARRAY;
1198 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, unpack, targetIs3D);
1199 if (endByteOrErr.isError())
1200 {
1201 context->handleError(endByteOrErr.getError());
1202 return false;
1203 }
1204
1205 GLuint endByte = endByteOrErr.getResult();
1206
1207 if (pixelUnpackBuffer)
1208 {
1209 CheckedNumeric<size_t> checkedEndByte(endByteOrErr.getResult());
1210 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
1211 checkedEndByte += checkedOffset;
1212
1213 if (!checkedEndByte.IsValid() ||
1214 (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelUnpackBuffer->getSize())))
1215 {
1216 // Overflow past the end of the buffer
1217 context->handleError(Error(GL_INVALID_OPERATION));
1218 return false;
1219 }
1220 }
1221 else
1222 {
1223 ASSERT(imageSize >= 0);
1224 if (pixels == nullptr && imageSize != 0)
1225 {
1226 context->handleError(
1227 Error(GL_INVALID_OPERATION, "imageSize must be 0 if no texture data is provided."));
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001228 return false;
Geoff Langff5b2d52016-09-07 11:32:23 -04001229 }
1230
Geoff Lang3feb3ff2016-10-26 10:57:45 -04001231 if (pixels != nullptr && endByte > static_cast<GLuint>(imageSize))
Geoff Langff5b2d52016-09-07 11:32:23 -04001232 {
1233 context->handleError(
1234 Error(GL_INVALID_OPERATION, "imageSize must be at least %u.", endByte));
1235 return false;
1236 }
1237 }
1238
1239 return true;
1240}
1241
Geoff Lang37dde692014-01-31 16:34:54 -05001242bool ValidQueryType(const Context *context, GLenum queryType)
1243{
He Yunchaoced53ae2016-11-29 15:00:51 +08001244 static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT,
1245 "GL extension enums not equal.");
1246 static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1247 "GL extension enums not equal.");
Geoff Lang37dde692014-01-31 16:34:54 -05001248
1249 switch (queryType)
1250 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001251 case GL_ANY_SAMPLES_PASSED:
1252 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
1253 return true;
1254 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1255 return (context->getClientMajorVersion() >= 3);
1256 case GL_TIME_ELAPSED_EXT:
1257 return context->getExtensions().disjointTimerQuery;
1258 case GL_COMMANDS_COMPLETED_CHROMIUM:
1259 return context->getExtensions().syncQuery;
1260 default:
1261 return false;
Geoff Lang37dde692014-01-31 16:34:54 -05001262 }
1263}
1264
Geoff Lang2d62ab72017-03-23 16:54:40 -04001265bool ValidateWebGLVertexAttribPointer(ValidationContext *context,
1266 GLenum type,
1267 GLboolean normalized,
1268 GLsizei stride,
Jamie Madill876429b2017-04-20 15:46:24 -04001269 const void *ptr,
Geoff Lang2d62ab72017-03-23 16:54:40 -04001270 bool pureInteger)
1271{
1272 ASSERT(context->getExtensions().webglCompatibility);
1273
1274 // WebGL 1.0 [Section 6.11] Vertex Attribute Data Stride
1275 // The WebGL API supports vertex attribute data strides up to 255 bytes. A call to
1276 // vertexAttribPointer will generate an INVALID_VALUE error if the value for the stride
1277 // parameter exceeds 255.
1278 constexpr GLsizei kMaxWebGLStride = 255;
1279 if (stride > kMaxWebGLStride)
1280 {
1281 context->handleError(
1282 Error(GL_INVALID_VALUE, "Stride is over the maximum stride allowed by WebGL."));
1283 return false;
1284 }
1285
1286 // WebGL 1.0 [Section 6.4] Buffer Offset and Stride Requirements
1287 // The offset arguments to drawElements and vertexAttribPointer, and the stride argument to
1288 // vertexAttribPointer, must be a multiple of the size of the data type passed to the call,
1289 // or an INVALID_OPERATION error is generated.
1290 VertexFormatType internalType = GetVertexFormatType(type, normalized, 1, pureInteger);
1291 size_t typeSize = GetVertexFormatTypeSize(internalType);
1292
1293 ASSERT(isPow2(typeSize) && typeSize > 0);
1294 size_t sizeMask = (typeSize - 1);
1295 if ((reinterpret_cast<intptr_t>(ptr) & sizeMask) != 0)
1296 {
1297 context->handleError(
1298 Error(GL_INVALID_OPERATION, "Offset is not a multiple of the type size."));
1299 return false;
1300 }
1301
1302 if ((stride & sizeMask) != 0)
1303 {
1304 context->handleError(
1305 Error(GL_INVALID_OPERATION, "Stride is not a multiple of the type size."));
1306 return false;
1307 }
1308
1309 return true;
1310}
1311
Jamie Madillef300b12016-10-07 15:12:09 -04001312Program *GetValidProgram(ValidationContext *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -05001313{
He Yunchaoced53ae2016-11-29 15:00:51 +08001314 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will
1315 // generate the error INVALID_VALUE if the provided name is not the name of either a shader
1316 // or program object and INVALID_OPERATION if the provided name identifies an object
1317 // that is not the expected type."
Geoff Lang48dcae72014-02-05 16:28:24 -05001318
Dian Xiang769769a2015-09-09 15:20:08 -07001319 Program *validProgram = context->getProgram(id);
1320
1321 if (!validProgram)
Geoff Lang48dcae72014-02-05 16:28:24 -05001322 {
Dian Xiang769769a2015-09-09 15:20:08 -07001323 if (context->getShader(id))
1324 {
Jamie Madill437fa652016-05-03 15:13:24 -04001325 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07001326 Error(GL_INVALID_OPERATION, "Expected a program name, but found a shader name"));
1327 }
1328 else
1329 {
Jamie Madill437fa652016-05-03 15:13:24 -04001330 context->handleError(Error(GL_INVALID_VALUE, "Program name is not valid"));
Dian Xiang769769a2015-09-09 15:20:08 -07001331 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001332 }
Dian Xiang769769a2015-09-09 15:20:08 -07001333
1334 return validProgram;
1335}
1336
Jamie Madillef300b12016-10-07 15:12:09 -04001337Shader *GetValidShader(ValidationContext *context, GLuint id)
Dian Xiang769769a2015-09-09 15:20:08 -07001338{
1339 // See ValidProgram for spec details.
1340
1341 Shader *validShader = context->getShader(id);
1342
1343 if (!validShader)
Geoff Lang48dcae72014-02-05 16:28:24 -05001344 {
Dian Xiang769769a2015-09-09 15:20:08 -07001345 if (context->getProgram(id))
1346 {
Jamie Madill437fa652016-05-03 15:13:24 -04001347 context->handleError(
Dian Xiang769769a2015-09-09 15:20:08 -07001348 Error(GL_INVALID_OPERATION, "Expected a shader name, but found a program name"));
1349 }
1350 else
1351 {
Jamie Madill437fa652016-05-03 15:13:24 -04001352 context->handleError(Error(GL_INVALID_VALUE, "Shader name is invalid"));
Dian Xiang769769a2015-09-09 15:20:08 -07001353 }
Geoff Lang48dcae72014-02-05 16:28:24 -05001354 }
Dian Xiang769769a2015-09-09 15:20:08 -07001355
1356 return validShader;
Geoff Lang48dcae72014-02-05 16:28:24 -05001357}
1358
Geoff Langb1196682014-07-23 13:47:29 -04001359bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -04001360{
1361 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
1362 {
1363 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
1364
Geoff Langaae65a42014-05-26 12:43:44 -04001365 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -04001366 {
Jamie Madill437fa652016-05-03 15:13:24 -04001367 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001368 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001369 }
1370 }
1371 else
1372 {
1373 switch (attachment)
1374 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001375 case GL_DEPTH_ATTACHMENT:
1376 case GL_STENCIL_ATTACHMENT:
1377 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001378
He Yunchaoced53ae2016-11-29 15:00:51 +08001379 case GL_DEPTH_STENCIL_ATTACHMENT:
1380 if (!context->getExtensions().webglCompatibility &&
1381 context->getClientMajorVersion() < 3)
1382 {
1383 context->handleError(Error(GL_INVALID_ENUM));
1384 return false;
1385 }
1386 break;
Jamie Madillb4472272014-07-03 10:38:55 -04001387
He Yunchaoced53ae2016-11-29 15:00:51 +08001388 default:
1389 context->handleError(Error(GL_INVALID_ENUM));
1390 return false;
Jamie Madillb4472272014-07-03 10:38:55 -04001391 }
1392 }
1393
1394 return true;
1395}
1396
Jamie Madille8fb6402017-02-14 17:56:40 -05001397bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
He Yunchaoced53ae2016-11-29 15:00:51 +08001398 GLenum target,
1399 GLsizei samples,
1400 GLenum internalformat,
1401 GLsizei width,
1402 GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001403{
1404 switch (target)
1405 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001406 case GL_RENDERBUFFER:
1407 break;
1408 default:
1409 context->handleError(Error(GL_INVALID_ENUM));
1410 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001411 }
1412
1413 if (width < 0 || height < 0 || samples < 0)
1414 {
Jamie Madill437fa652016-05-03 15:13:24 -04001415 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001416 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001417 }
1418
Jamie Madill4e0e6f82017-02-17 11:06:03 -05001419 // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
1420 GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
1421
1422 const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
Geoff Langd87878e2014-09-19 15:42:59 -04001423 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001424 {
Jamie Madill437fa652016-05-03 15:13:24 -04001425 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001426 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001427 }
1428
1429 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
1430 // 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 -08001431 // only sized internal formats.
Geoff Langca271392017-04-05 12:30:00 -04001432 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(convertedInternalFormat);
1433 if (formatInfo.internalFormat == GL_NONE)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001434 {
Jamie Madill437fa652016-05-03 15:13:24 -04001435 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001436 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001437 }
1438
Geoff Langaae65a42014-05-26 12:43:44 -04001439 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001440 {
Jamie Madill437fa652016-05-03 15:13:24 -04001441 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001442 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001443 }
1444
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001445 GLuint handle = context->getGLState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001446 if (handle == 0)
1447 {
Jamie Madill437fa652016-05-03 15:13:24 -04001448 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001449 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001450 }
1451
1452 return true;
1453}
1454
He Yunchaoced53ae2016-11-29 15:00:51 +08001455bool ValidateFramebufferRenderbufferParameters(gl::Context *context,
1456 GLenum target,
1457 GLenum attachment,
1458 GLenum renderbuffertarget,
1459 GLuint renderbuffer)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001460{
Shannon Woods1da3cf62014-06-27 15:32:23 -04001461 if (!ValidFramebufferTarget(target))
1462 {
Jamie Madill437fa652016-05-03 15:13:24 -04001463 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04001464 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -04001465 }
1466
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001467 gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001468
Jamie Madill84115c92015-04-23 15:00:07 -04001469 ASSERT(framebuffer);
1470 if (framebuffer->id() == 0)
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001471 {
Jamie Madill437fa652016-05-03 15:13:24 -04001472 context->handleError(
1473 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04001474 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001475 }
1476
Jamie Madillb4472272014-07-03 10:38:55 -04001477 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001478 {
Jamie Madillb4472272014-07-03 10:38:55 -04001479 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001480 }
1481
Jamie Madillab9d82c2014-01-21 16:38:14 -05001482 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1483 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1484 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1485 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1486 if (renderbuffer != 0)
1487 {
1488 if (!context->getRenderbuffer(renderbuffer))
1489 {
Jamie Madill437fa652016-05-03 15:13:24 -04001490 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001491 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -05001492 }
1493 }
1494
Jamie Madill1fc7e2c2014-01-21 16:47:10 -05001495 return true;
1496}
1497
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001498bool ValidateBlitFramebufferParameters(ValidationContext *context,
Jamie Madillc29968b2016-01-20 11:17:23 -05001499 GLint srcX0,
1500 GLint srcY0,
1501 GLint srcX1,
1502 GLint srcY1,
1503 GLint dstX0,
1504 GLint dstY0,
1505 GLint dstX1,
1506 GLint dstY1,
1507 GLbitfield mask,
1508 GLenum filter)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001509{
1510 switch (filter)
1511 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001512 case GL_NEAREST:
1513 break;
1514 case GL_LINEAR:
1515 break;
1516 default:
1517 context->handleError(Error(GL_INVALID_ENUM));
1518 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001519 }
1520
1521 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1522 {
Jamie Madill437fa652016-05-03 15:13:24 -04001523 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04001524 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001525 }
1526
1527 if (mask == 0)
1528 {
1529 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
1530 // buffers are copied.
1531 return false;
1532 }
1533
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001534 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
1535 // color buffer, leaving only nearest being unfiltered from above
1536 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
1537 {
Jamie Madill437fa652016-05-03 15:13:24 -04001538 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001539 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001540 }
1541
Jamie Madill51f40ec2016-06-15 14:06:00 -04001542 const auto &glState = context->getGLState();
1543 gl::Framebuffer *readFramebuffer = glState.getReadFramebuffer();
1544 gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001545
1546 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001547 {
Jamie Madill437fa652016-05-03 15:13:24 -04001548 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001549 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001550 }
1551
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001552 if (readFramebuffer->id() == drawFramebuffer->id())
1553 {
1554 context->handleError(Error(GL_INVALID_OPERATION));
1555 return false;
1556 }
1557
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001558 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001559 {
Jamie Madill437fa652016-05-03 15:13:24 -04001560 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001561 return false;
1562 }
1563
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001564 if (drawFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill48faf802014-11-06 15:27:22 -05001565 {
Jamie Madill437fa652016-05-03 15:13:24 -04001566 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Jamie Madill48faf802014-11-06 15:27:22 -05001567 return false;
1568 }
1569
Jamie Madilldd43e6c2017-03-24 14:18:49 -04001570 if (drawFramebuffer->getSamples(context) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001571 {
Jamie Madill437fa652016-05-03 15:13:24 -04001572 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001573 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001574 }
1575
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001576 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
1577
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001578 if (mask & GL_COLOR_BUFFER_BIT)
1579 {
Jamie Madillb6bda4a2015-04-20 12:53:26 -04001580 const gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
Jamie Madill6163c752015-12-07 16:32:59 -05001581 const Extensions &extensions = context->getExtensions();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001582
He Yunchao66a41a22016-12-15 16:45:05 +08001583 if (readColorBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001584 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001585 const Format &readFormat = readColorBuffer->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001586
Geoff Langa15472a2015-08-11 11:48:03 -04001587 for (size_t drawbufferIdx = 0;
1588 drawbufferIdx < drawFramebuffer->getDrawbufferStateCount(); ++drawbufferIdx)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001589 {
Geoff Langa15472a2015-08-11 11:48:03 -04001590 const FramebufferAttachment *attachment =
1591 drawFramebuffer->getDrawBuffer(drawbufferIdx);
1592 if (attachment)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001593 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001594 const Format &drawFormat = attachment->getFormat();
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001595
Geoff Langb2f3d052013-08-13 12:49:27 -04001596 // The GL ES 3.0.2 spec (pg 193) states that:
1597 // 1) If the read buffer is fixed point format, the draw buffer must be as well
He Yunchaoced53ae2016-11-29 15:00:51 +08001598 // 2) If the read buffer is an unsigned integer format, the draw buffer must be
1599 // as well
1600 // 3) If the read buffer is a signed integer format, the draw buffer must be as
1601 // well
Jamie Madill6163c752015-12-07 16:32:59 -05001602 // Changes with EXT_color_buffer_float:
1603 // Case 1) is changed to fixed point OR floating point
Jamie Madilla3944d42016-07-22 22:13:26 -04001604 GLenum readComponentType = readFormat.info->componentType;
1605 GLenum drawComponentType = drawFormat.info->componentType;
He Yunchaoced53ae2016-11-29 15:00:51 +08001606 bool readFixedPoint = (readComponentType == GL_UNSIGNED_NORMALIZED ||
Jamie Madill6163c752015-12-07 16:32:59 -05001607 readComponentType == GL_SIGNED_NORMALIZED);
1608 bool drawFixedPoint = (drawComponentType == GL_UNSIGNED_NORMALIZED ||
1609 drawComponentType == GL_SIGNED_NORMALIZED);
1610
1611 if (extensions.colorBufferFloat)
1612 {
1613 bool readFixedOrFloat = (readFixedPoint || readComponentType == GL_FLOAT);
1614 bool drawFixedOrFloat = (drawFixedPoint || drawComponentType == GL_FLOAT);
1615
1616 if (readFixedOrFloat != drawFixedOrFloat)
1617 {
Jamie Madill437fa652016-05-03 15:13:24 -04001618 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001619 "If the read buffer contains fixed-point or "
1620 "floating-point values, the draw buffer "
1621 "must as well."));
1622 return false;
1623 }
1624 }
1625 else if (readFixedPoint != drawFixedPoint)
1626 {
Jamie Madill437fa652016-05-03 15:13:24 -04001627 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madill6163c752015-12-07 16:32:59 -05001628 "If the read buffer contains fixed-point "
1629 "values, the draw buffer must as well."));
1630 return false;
1631 }
1632
1633 if (readComponentType == GL_UNSIGNED_INT &&
1634 drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001635 {
Jamie Madill437fa652016-05-03 15:13:24 -04001636 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001637 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001638 }
1639
Jamie Madill6163c752015-12-07 16:32:59 -05001640 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001641 {
Jamie Madill437fa652016-05-03 15:13:24 -04001642 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001643 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001644 }
1645
Jamie Madilla3944d42016-07-22 22:13:26 -04001646 if (readColorBuffer->getSamples() > 0 &&
1647 (!Format::SameSized(readFormat, drawFormat) || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001648 {
Jamie Madill437fa652016-05-03 15:13:24 -04001649 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001650 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001651 }
Geoff Lange4915782017-04-12 15:19:07 -04001652
1653 if (context->getExtensions().webglCompatibility &&
1654 *readColorBuffer == *attachment)
1655 {
1656 context->handleError(
1657 Error(GL_INVALID_OPERATION,
1658 "Read and write color attachments cannot be the same image."));
1659 return false;
1660 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001661 }
1662 }
1663
Jamie Madilla3944d42016-07-22 22:13:26 -04001664 if ((readFormat.info->componentType == GL_INT ||
1665 readFormat.info->componentType == GL_UNSIGNED_INT) &&
1666 filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001667 {
Jamie Madill437fa652016-05-03 15:13:24 -04001668 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001669 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001670 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001671 }
He Yunchao66a41a22016-12-15 16:45:05 +08001672 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1673 // In OpenGL ES it is undefined what happens when an operation tries to blit from a missing
1674 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
1675 // situation is an application error that would lead to a crash in ANGLE.
1676 else if (drawFramebuffer->hasEnabledDrawBuffer())
1677 {
1678 context->handleError(Error(
1679 GL_INVALID_OPERATION,
1680 "Attempt to read from a missing color attachment of a complete framebuffer."));
1681 return false;
1682 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001683 }
1684
He Yunchaoced53ae2016-11-29 15:00:51 +08001685 GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT};
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001686 GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
1687 for (size_t i = 0; i < 2; i++)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001688 {
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001689 if (mask & masks[i])
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001690 {
He Yunchaoced53ae2016-11-29 15:00:51 +08001691 const gl::FramebufferAttachment *readBuffer =
1692 readFramebuffer->getAttachment(attachments[i]);
1693 const gl::FramebufferAttachment *drawBuffer =
1694 drawFramebuffer->getAttachment(attachments[i]);
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001695
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001696 if (readBuffer && drawBuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001697 {
Jamie Madilla3944d42016-07-22 22:13:26 -04001698 if (!Format::SameSized(readBuffer->getFormat(), drawBuffer->getFormat()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001699 {
Jamie Madill437fa652016-05-03 15:13:24 -04001700 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001701 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001702 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001703
Dongseong Hwang44b422c2014-12-09 15:42:01 +02001704 if (readBuffer->getSamples() > 0 && !sameBounds)
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001705 {
Jamie Madill437fa652016-05-03 15:13:24 -04001706 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04001707 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001708 }
Geoff Lange4915782017-04-12 15:19:07 -04001709
1710 if (context->getExtensions().webglCompatibility && *readBuffer == *drawBuffer)
1711 {
1712 context->handleError(Error(
1713 GL_INVALID_OPERATION,
1714 "Read and write depth stencil attachments cannot be the same image."));
1715 return false;
1716 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001717 }
He Yunchao66a41a22016-12-15 16:45:05 +08001718 // WebGL 2.0 BlitFramebuffer when blitting from a missing attachment
1719 else if (drawBuffer)
1720 {
1721 context->handleError(Error(GL_INVALID_OPERATION,
1722 "Attempt to read from a missing depth/stencil "
1723 "attachment of a complete framebuffer."));
1724 return false;
1725 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001726 }
1727 }
1728
1729 return true;
1730}
1731
Geoff Lang62fce5b2016-09-30 10:46:35 -04001732bool ValidateReadPixelsRobustANGLE(ValidationContext *context,
1733 GLint x,
1734 GLint y,
1735 GLsizei width,
1736 GLsizei height,
1737 GLenum format,
1738 GLenum type,
1739 GLsizei bufSize,
1740 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001741 GLsizei *columns,
1742 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001743 void *pixels)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001744{
1745 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madillc29968b2016-01-20 11:17:23 -05001746 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001747 return false;
1748 }
1749
Geoff Lang62fce5b2016-09-30 10:46:35 -04001750 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
Geoff Lange93daba2017-03-30 13:54:40 -04001751 columns, rows, pixels))
Jamie Madill26e91952014-03-05 15:01:27 -05001752 {
Geoff Langb1196682014-07-23 13:47:29 -04001753 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001754 }
1755
Geoff Lang62fce5b2016-09-30 10:46:35 -04001756 if (!ValidateRobustBufferSize(context, bufSize, *length))
Jamie Madill26e91952014-03-05 15:01:27 -05001757 {
Geoff Langb1196682014-07-23 13:47:29 -04001758 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001759 }
1760
Jamie Madillc29968b2016-01-20 11:17:23 -05001761 return true;
1762}
1763
1764bool ValidateReadnPixelsEXT(Context *context,
1765 GLint x,
1766 GLint y,
1767 GLsizei width,
1768 GLsizei height,
1769 GLenum format,
1770 GLenum type,
1771 GLsizei bufSize,
Jamie Madill876429b2017-04-20 15:46:24 -04001772 void *pixels)
Jamie Madillc29968b2016-01-20 11:17:23 -05001773{
1774 if (bufSize < 0)
1775 {
Jamie Madill437fa652016-05-03 15:13:24 -04001776 context->handleError(Error(GL_INVALID_VALUE, "bufSize must be a positive number"));
Jamie Madillc29968b2016-01-20 11:17:23 -05001777 return false;
1778 }
1779
Geoff Lang62fce5b2016-09-30 10:46:35 -04001780 return ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, nullptr,
Geoff Lange93daba2017-03-30 13:54:40 -04001781 nullptr, nullptr, pixels);
Geoff Lang62fce5b2016-09-30 10:46:35 -04001782}
Jamie Madill26e91952014-03-05 15:01:27 -05001783
Geoff Lang62fce5b2016-09-30 10:46:35 -04001784bool ValidateReadnPixelsRobustANGLE(ValidationContext *context,
1785 GLint x,
1786 GLint y,
1787 GLsizei width,
1788 GLsizei height,
1789 GLenum format,
1790 GLenum type,
1791 GLsizei bufSize,
1792 GLsizei *length,
Geoff Lange93daba2017-03-30 13:54:40 -04001793 GLsizei *columns,
1794 GLsizei *rows,
Jamie Madill876429b2017-04-20 15:46:24 -04001795 void *data)
Geoff Lang62fce5b2016-09-30 10:46:35 -04001796{
1797 if (!ValidateRobustEntryPoint(context, bufSize))
Jamie Madille2e406c2016-06-02 13:04:10 -04001798 {
Jamie Madille2e406c2016-06-02 13:04:10 -04001799 return false;
1800 }
1801
Geoff Lange93daba2017-03-30 13:54:40 -04001802 if (!ValidateReadPixelsBase(context, x, y, width, height, format, type, bufSize, length,
1803 columns, rows, data))
Jamie Madille2e406c2016-06-02 13:04:10 -04001804 {
Jamie Madillc29968b2016-01-20 11:17:23 -05001805 return false;
Jamie Madill26e91952014-03-05 15:01:27 -05001806 }
1807
Geoff Lang62fce5b2016-09-30 10:46:35 -04001808 if (!ValidateRobustBufferSize(context, bufSize, *length))
1809 {
1810 return false;
1811 }
1812
1813 return true;
Jamie Madill26e91952014-03-05 15:01:27 -05001814}
1815
Olli Etuaho41997e72016-03-10 13:38:39 +02001816bool ValidateGenQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001817{
1818 if (!context->getExtensions().occlusionQueryBoolean &&
1819 !context->getExtensions().disjointTimerQuery)
1820 {
Jamie Madill437fa652016-05-03 15:13:24 -04001821 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001822 return false;
1823 }
1824
Olli Etuaho41997e72016-03-10 13:38:39 +02001825 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001826}
1827
Olli Etuaho41997e72016-03-10 13:38:39 +02001828bool ValidateDeleteQueriesEXT(gl::Context *context, GLsizei n)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001829{
1830 if (!context->getExtensions().occlusionQueryBoolean &&
1831 !context->getExtensions().disjointTimerQuery)
1832 {
Jamie Madill437fa652016-05-03 15:13:24 -04001833 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001834 return false;
1835 }
1836
Olli Etuaho41997e72016-03-10 13:38:39 +02001837 return ValidateGenOrDelete(context, n);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001838}
1839
1840bool ValidateBeginQueryBase(gl::Context *context, GLenum target, GLuint id)
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001841{
1842 if (!ValidQueryType(context, target))
1843 {
Jamie Madill437fa652016-05-03 15:13:24 -04001844 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001845 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001846 }
1847
1848 if (id == 0)
1849 {
Jamie Madill437fa652016-05-03 15:13:24 -04001850 context->handleError(Error(GL_INVALID_OPERATION, "Query id is 0"));
Geoff Langb1196682014-07-23 13:47:29 -04001851 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001852 }
1853
1854 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
1855 // of zero, if the active query object name for <target> is non-zero (for the
1856 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
1857 // the active query for either target is non-zero), if <id> is the name of an
1858 // existing query object whose type does not match <target>, or if <id> is the
1859 // active query object name for any query type, the error INVALID_OPERATION is
1860 // generated.
1861
1862 // Ensure no other queries are active
1863 // NOTE: If other queries than occlusion are supported, we will need to check
1864 // separately that:
1865 // a) The query ID passed is not the current active query for any target/type
1866 // b) There are no active queries for the requested target (and in the case
1867 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1868 // no query may be active for either if glBeginQuery targets either.
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001869
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001870 if (context->getGLState().isQueryActive(target))
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001871 {
Jamie Madill437fa652016-05-03 15:13:24 -04001872 context->handleError(Error(GL_INVALID_OPERATION, "Other query is active"));
Geoff Langb1196682014-07-23 13:47:29 -04001873 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001874 }
1875
1876 Query *queryObject = context->getQuery(id, true, target);
1877
1878 // check that name was obtained with glGenQueries
1879 if (!queryObject)
1880 {
Jamie Madill437fa652016-05-03 15:13:24 -04001881 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Geoff Langb1196682014-07-23 13:47:29 -04001882 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001883 }
1884
1885 // check for type mismatch
1886 if (queryObject->getType() != target)
1887 {
Jamie Madill437fa652016-05-03 15:13:24 -04001888 context->handleError(Error(GL_INVALID_OPERATION, "Query type does not match target"));
Geoff Langb1196682014-07-23 13:47:29 -04001889 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001890 }
1891
1892 return true;
1893}
1894
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001895bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
1896{
1897 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001898 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001899 {
Jamie Madill437fa652016-05-03 15:13:24 -04001900 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001901 return false;
1902 }
1903
1904 return ValidateBeginQueryBase(context, target, id);
1905}
1906
1907bool ValidateEndQueryBase(gl::Context *context, GLenum target)
Jamie Madill45c785d2014-05-13 14:09:34 -04001908{
1909 if (!ValidQueryType(context, target))
1910 {
Jamie Madill437fa652016-05-03 15:13:24 -04001911 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Geoff Langb1196682014-07-23 13:47:29 -04001912 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001913 }
1914
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001915 const Query *queryObject = context->getGLState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001916
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001917 if (queryObject == nullptr)
Jamie Madill45c785d2014-05-13 14:09:34 -04001918 {
Jamie Madill437fa652016-05-03 15:13:24 -04001919 context->handleError(Error(GL_INVALID_OPERATION, "Query target not active"));
Geoff Langb1196682014-07-23 13:47:29 -04001920 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001921 }
1922
Jamie Madill45c785d2014-05-13 14:09:34 -04001923 return true;
1924}
1925
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001926bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
1927{
1928 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04001929 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001930 {
Jamie Madill437fa652016-05-03 15:13:24 -04001931 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001932 return false;
1933 }
1934
1935 return ValidateEndQueryBase(context, target);
1936}
1937
1938bool ValidateQueryCounterEXT(Context *context, GLuint id, GLenum target)
1939{
1940 if (!context->getExtensions().disjointTimerQuery)
1941 {
Jamie Madill437fa652016-05-03 15:13:24 -04001942 context->handleError(Error(GL_INVALID_OPERATION, "Disjoint timer query not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001943 return false;
1944 }
1945
1946 if (target != GL_TIMESTAMP_EXT)
1947 {
Jamie Madill437fa652016-05-03 15:13:24 -04001948 context->handleError(Error(GL_INVALID_ENUM, "Invalid query target"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001949 return false;
1950 }
1951
1952 Query *queryObject = context->getQuery(id, true, target);
1953 if (queryObject == nullptr)
1954 {
Jamie Madill437fa652016-05-03 15:13:24 -04001955 context->handleError(Error(GL_INVALID_OPERATION, "Invalid query id"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001956 return false;
1957 }
1958
Jamie Madilldfde6ab2016-06-09 07:07:18 -07001959 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001960 {
Jamie Madill437fa652016-05-03 15:13:24 -04001961 context->handleError(Error(GL_INVALID_OPERATION, "Query is active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001962 return false;
1963 }
1964
1965 return true;
1966}
1967
Geoff Lang2186c382016-10-14 10:54:54 -04001968bool ValidateGetQueryivBase(Context *context, GLenum target, GLenum pname, GLsizei *numParams)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001969{
Geoff Lang2186c382016-10-14 10:54:54 -04001970 if (numParams)
1971 {
1972 *numParams = 0;
1973 }
1974
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001975 if (!ValidQueryType(context, target) && target != GL_TIMESTAMP_EXT)
1976 {
Jamie Madill437fa652016-05-03 15:13:24 -04001977 context->handleError(Error(GL_INVALID_ENUM, "Invalid query type"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001978 return false;
1979 }
1980
1981 switch (pname)
1982 {
1983 case GL_CURRENT_QUERY_EXT:
1984 if (target == GL_TIMESTAMP_EXT)
1985 {
Jamie Madill437fa652016-05-03 15:13:24 -04001986 context->handleError(
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001987 Error(GL_INVALID_ENUM, "Cannot use current query for timestamp"));
1988 return false;
1989 }
1990 break;
1991 case GL_QUERY_COUNTER_BITS_EXT:
1992 if (!context->getExtensions().disjointTimerQuery ||
1993 (target != GL_TIMESTAMP_EXT && target != GL_TIME_ELAPSED_EXT))
1994 {
Jamie Madill437fa652016-05-03 15:13:24 -04001995 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05001996 return false;
1997 }
1998 break;
1999 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002000 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002001 return false;
2002 }
2003
Geoff Lang2186c382016-10-14 10:54:54 -04002004 if (numParams)
2005 {
2006 // All queries return only one value
2007 *numParams = 1;
2008 }
2009
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002010 return true;
2011}
2012
2013bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
2014{
2015 if (!context->getExtensions().occlusionQueryBoolean &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002016 !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002017 {
Jamie Madill437fa652016-05-03 15:13:24 -04002018 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002019 return false;
2020 }
2021
Geoff Lang2186c382016-10-14 10:54:54 -04002022 return ValidateGetQueryivBase(context, target, pname, nullptr);
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002023}
2024
Geoff Lang2186c382016-10-14 10:54:54 -04002025bool ValidateGetQueryivRobustANGLE(Context *context,
2026 GLenum target,
2027 GLenum pname,
2028 GLsizei bufSize,
2029 GLsizei *length,
2030 GLint *params)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002031{
Geoff Lang2186c382016-10-14 10:54:54 -04002032 if (!ValidateRobustEntryPoint(context, bufSize))
2033 {
2034 return false;
2035 }
2036
2037 if (!ValidateGetQueryivBase(context, target, pname, length))
2038 {
2039 return false;
2040 }
2041
2042 if (!ValidateRobustBufferSize(context, bufSize, *length))
2043 {
2044 return false;
2045 }
2046
2047 return true;
2048}
2049
2050bool ValidateGetQueryObjectValueBase(Context *context, GLuint id, GLenum pname, GLsizei *numParams)
2051{
2052 if (numParams)
2053 {
2054 *numParams = 0;
2055 }
2056
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002057 Query *queryObject = context->getQuery(id, false, GL_NONE);
2058
2059 if (!queryObject)
2060 {
Jamie Madill437fa652016-05-03 15:13:24 -04002061 context->handleError(Error(GL_INVALID_OPERATION, "Query does not exist"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002062 return false;
2063 }
2064
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002065 if (context->getGLState().isQueryActive(queryObject))
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002066 {
Jamie Madill437fa652016-05-03 15:13:24 -04002067 context->handleError(Error(GL_INVALID_OPERATION, "Query currently active"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002068 return false;
2069 }
2070
2071 switch (pname)
2072 {
2073 case GL_QUERY_RESULT_EXT:
2074 case GL_QUERY_RESULT_AVAILABLE_EXT:
2075 break;
2076
2077 default:
Jamie Madill437fa652016-05-03 15:13:24 -04002078 context->handleError(Error(GL_INVALID_ENUM, "Invalid pname enum"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002079 return false;
2080 }
2081
Geoff Lang2186c382016-10-14 10:54:54 -04002082 if (numParams)
2083 {
2084 *numParams = 1;
2085 }
2086
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002087 return true;
2088}
2089
2090bool ValidateGetQueryObjectivEXT(Context *context, GLuint id, GLenum pname, GLint *params)
2091{
2092 if (!context->getExtensions().disjointTimerQuery)
2093 {
Jamie Madill437fa652016-05-03 15:13:24 -04002094 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002095 return false;
2096 }
Geoff Lang2186c382016-10-14 10:54:54 -04002097 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2098}
2099
2100bool ValidateGetQueryObjectivRobustANGLE(Context *context,
2101 GLuint id,
2102 GLenum pname,
2103 GLsizei bufSize,
2104 GLsizei *length,
2105 GLint *params)
2106{
2107 if (!context->getExtensions().disjointTimerQuery)
2108 {
2109 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2110 return false;
2111 }
2112
2113 if (!ValidateRobustEntryPoint(context, bufSize))
2114 {
2115 return false;
2116 }
2117
2118 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2119 {
2120 return false;
2121 }
2122
2123 if (!ValidateRobustBufferSize(context, bufSize, *length))
2124 {
2125 return false;
2126 }
2127
2128 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002129}
2130
2131bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
2132{
2133 if (!context->getExtensions().disjointTimerQuery &&
Geoff Lang2b4ce802016-04-28 13:34:50 -04002134 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002135 {
Jamie Madill437fa652016-05-03 15:13:24 -04002136 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002137 return false;
2138 }
Geoff Lang2186c382016-10-14 10:54:54 -04002139 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2140}
2141
2142bool ValidateGetQueryObjectuivRobustANGLE(Context *context,
2143 GLuint id,
2144 GLenum pname,
2145 GLsizei bufSize,
2146 GLsizei *length,
2147 GLuint *params)
2148{
2149 if (!context->getExtensions().disjointTimerQuery &&
2150 !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
2151 {
2152 context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
2153 return false;
2154 }
2155
2156 if (!ValidateRobustEntryPoint(context, bufSize))
2157 {
2158 return false;
2159 }
2160
2161 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2162 {
2163 return false;
2164 }
2165
2166 if (!ValidateRobustBufferSize(context, bufSize, *length))
2167 {
2168 return false;
2169 }
2170
2171 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002172}
2173
2174bool ValidateGetQueryObjecti64vEXT(Context *context, GLuint id, GLenum pname, GLint64 *params)
2175{
2176 if (!context->getExtensions().disjointTimerQuery)
2177 {
Jamie Madill437fa652016-05-03 15:13:24 -04002178 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002179 return false;
2180 }
Geoff Lang2186c382016-10-14 10:54:54 -04002181 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2182}
2183
2184bool ValidateGetQueryObjecti64vRobustANGLE(Context *context,
2185 GLuint id,
2186 GLenum pname,
2187 GLsizei bufSize,
2188 GLsizei *length,
2189 GLint64 *params)
2190{
2191 if (!context->getExtensions().disjointTimerQuery)
2192 {
2193 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2194 return false;
2195 }
2196
2197 if (!ValidateRobustEntryPoint(context, bufSize))
2198 {
2199 return false;
2200 }
2201
2202 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2203 {
2204 return false;
2205 }
2206
2207 if (!ValidateRobustBufferSize(context, bufSize, *length))
2208 {
2209 return false;
2210 }
2211
2212 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002213}
2214
2215bool ValidateGetQueryObjectui64vEXT(Context *context, GLuint id, GLenum pname, GLuint64 *params)
2216{
2217 if (!context->getExtensions().disjointTimerQuery)
2218 {
Jamie Madill437fa652016-05-03 15:13:24 -04002219 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002220 return false;
2221 }
Geoff Lang2186c382016-10-14 10:54:54 -04002222 return ValidateGetQueryObjectValueBase(context, id, pname, nullptr);
2223}
2224
2225bool ValidateGetQueryObjectui64vRobustANGLE(Context *context,
2226 GLuint id,
2227 GLenum pname,
2228 GLsizei bufSize,
2229 GLsizei *length,
2230 GLuint64 *params)
2231{
2232 if (!context->getExtensions().disjointTimerQuery)
2233 {
2234 context->handleError(Error(GL_INVALID_OPERATION, "Timer query extension not enabled"));
2235 return false;
2236 }
2237
2238 if (!ValidateRobustEntryPoint(context, bufSize))
2239 {
2240 return false;
2241 }
2242
2243 if (!ValidateGetQueryObjectValueBase(context, id, pname, length))
2244 {
2245 return false;
2246 }
2247
2248 if (!ValidateRobustBufferSize(context, bufSize, *length))
2249 {
2250 return false;
2251 }
2252
2253 return true;
Ian Ewell3ffd78b2016-01-22 16:09:42 -05002254}
2255
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002256bool ValidateProgramUniform(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002257 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002258 GLuint program,
2259 GLint location,
2260 GLsizei count)
2261{
2262 // Check for ES31 program uniform entry points
2263 if (context->getClientVersion() < Version(3, 1))
2264 {
2265 context->handleError(Error(GL_INVALID_OPERATION));
2266 return false;
2267 }
2268
2269 const LinkedUniform *uniform = nullptr;
2270 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002271 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2272 ValidateUniformValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002273}
2274
Frank Henigmana98a6472017-02-02 21:38:32 -05002275bool ValidateProgramUniform1iv(gl::Context *context,
2276 GLuint program,
2277 GLint location,
2278 GLsizei count,
2279 const GLint *value)
2280{
2281 // Check for ES31 program uniform entry points
2282 if (context->getClientVersion() < Version(3, 1))
2283 {
2284 context->handleError(Error(GL_INVALID_OPERATION));
2285 return false;
2286 }
2287
2288 const LinkedUniform *uniform = nullptr;
2289 gl::Program *programObject = GetValidProgram(context, program);
2290 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2291 ValidateUniform1ivValue(context, uniform->type, count, value);
2292}
2293
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002294bool ValidateProgramUniformMatrix(gl::Context *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002295 GLenum valueType,
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002296 GLuint program,
2297 GLint location,
2298 GLsizei count,
2299 GLboolean transpose)
2300{
2301 // Check for ES31 program uniform entry points
2302 if (context->getClientVersion() < Version(3, 1))
2303 {
2304 context->handleError(Error(GL_INVALID_OPERATION));
2305 return false;
2306 }
2307
2308 const LinkedUniform *uniform = nullptr;
2309 gl::Program *programObject = GetValidProgram(context, program);
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002310 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2311 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jiajia Qinee9f08c2016-11-16 10:06:10 +08002312}
2313
Jamie Madillc1d770e2017-04-13 17:31:24 -04002314bool ValidateUniform(ValidationContext *context, GLenum valueType, GLint location, GLsizei count)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002315{
2316 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002317 if (VariableComponentType(valueType) == GL_UNSIGNED_INT && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002318 {
Jamie Madill437fa652016-05-03 15:13:24 -04002319 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002320 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002321 }
2322
Jamie Madill62d31cb2015-09-11 13:25:51 -04002323 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002324 gl::Program *programObject = context->getGLState().getProgram();
2325 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2326 ValidateUniformValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002327}
2328
Jamie Madillbe849e42017-05-02 15:49:00 -04002329bool ValidateUniform1iv(ValidationContext *context,
2330 GLint location,
2331 GLsizei count,
2332 const GLint *value)
Frank Henigmana98a6472017-02-02 21:38:32 -05002333{
2334 const LinkedUniform *uniform = nullptr;
2335 gl::Program *programObject = context->getGLState().getProgram();
2336 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2337 ValidateUniform1ivValue(context, uniform->type, count, value);
2338}
2339
Jamie Madillc1d770e2017-04-13 17:31:24 -04002340bool ValidateUniformMatrix(ValidationContext *context,
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002341 GLenum valueType,
He Yunchaoced53ae2016-11-29 15:00:51 +08002342 GLint location,
2343 GLsizei count,
Jamie Madillaa981bd2014-05-20 10:55:55 -04002344 GLboolean transpose)
2345{
2346 // Check for ES3 uniform entry points
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002347 int rows = VariableRowCount(valueType);
2348 int cols = VariableColumnCount(valueType);
Martin Radev1be913c2016-07-11 17:59:16 +03002349 if (rows != cols && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002350 {
Jamie Madill437fa652016-05-03 15:13:24 -04002351 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002352 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002353 }
2354
Martin Radev1be913c2016-07-11 17:59:16 +03002355 if (transpose != GL_FALSE && context->getClientMajorVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04002356 {
Jamie Madill437fa652016-05-03 15:13:24 -04002357 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002358 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04002359 }
2360
Jamie Madill62d31cb2015-09-11 13:25:51 -04002361 const LinkedUniform *uniform = nullptr;
Frank Henigmanf5f74ae2017-02-02 21:14:23 -05002362 gl::Program *programObject = context->getGLState().getProgram();
2363 return ValidateUniformCommonBase(context, programObject, location, count, &uniform) &&
2364 ValidateUniformMatrixValue(context, valueType, uniform->type);
Jamie Madillaa981bd2014-05-20 10:55:55 -04002365}
2366
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002367bool ValidateStateQuery(ValidationContext *context,
2368 GLenum pname,
2369 GLenum *nativeType,
2370 unsigned int *numParams)
Jamie Madill893ab082014-05-16 16:56:10 -04002371{
2372 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
2373 {
Jamie Madill437fa652016-05-03 15:13:24 -04002374 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002375 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002376 }
2377
Jamie Madill0af26e12015-03-05 19:54:33 -05002378 const Caps &caps = context->getCaps();
2379
Jamie Madill893ab082014-05-16 16:56:10 -04002380 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
2381 {
2382 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
2383
Jamie Madill0af26e12015-03-05 19:54:33 -05002384 if (colorAttachment >= caps.maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04002385 {
Jamie Madill437fa652016-05-03 15:13:24 -04002386 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002387 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002388 }
2389 }
2390
2391 switch (pname)
2392 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002393 case GL_TEXTURE_BINDING_2D:
2394 case GL_TEXTURE_BINDING_CUBE_MAP:
2395 case GL_TEXTURE_BINDING_3D:
2396 case GL_TEXTURE_BINDING_2D_ARRAY:
2397 break;
2398 case GL_TEXTURE_BINDING_EXTERNAL_OES:
2399 if (!context->getExtensions().eglStreamConsumerExternal &&
2400 !context->getExtensions().eglImageExternal)
2401 {
2402 context->handleError(Error(GL_INVALID_ENUM,
2403 "Neither NV_EGL_stream_consumer_external nor "
2404 "GL_OES_EGL_image_external extensions enabled"));
2405 return false;
2406 }
2407 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002408
He Yunchaoced53ae2016-11-29 15:00:51 +08002409 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2410 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
Jamie Madill893ab082014-05-16 16:56:10 -04002411 {
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002412 if (context->getGLState().getReadFramebuffer()->checkStatus(context) !=
2413 GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04002414 {
Jamie Madill437fa652016-05-03 15:13:24 -04002415 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002416 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002417 }
2418
Jamie Madill51f40ec2016-06-15 14:06:00 -04002419 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
2420 ASSERT(framebuffer);
Martin Radev138064f2016-07-15 12:03:41 +03002421
2422 if (framebuffer->getReadBufferState() == GL_NONE)
2423 {
2424 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2425 return false;
2426 }
2427
Jamie Madillb6bda4a2015-04-20 12:53:26 -04002428 const FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
Jamie Madill3c7fa222014-06-05 13:08:51 -04002429 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04002430 {
Jamie Madill437fa652016-05-03 15:13:24 -04002431 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002432 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04002433 }
2434 }
2435 break;
2436
He Yunchaoced53ae2016-11-29 15:00:51 +08002437 default:
2438 break;
Jamie Madill893ab082014-05-16 16:56:10 -04002439 }
2440
2441 // pname is valid, but there are no parameters to return
Geoff Langff5b2d52016-09-07 11:32:23 -04002442 if (*numParams == 0)
2443 {
2444 return false;
2445 }
2446
2447 return true;
2448}
2449
2450bool ValidateRobustStateQuery(ValidationContext *context,
2451 GLenum pname,
2452 GLsizei bufSize,
2453 GLenum *nativeType,
2454 unsigned int *numParams)
2455{
2456 if (!ValidateRobustEntryPoint(context, bufSize))
2457 {
2458 return false;
2459 }
2460
2461 if (!ValidateStateQuery(context, pname, nativeType, numParams))
2462 {
2463 return false;
2464 }
2465
2466 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
Jamie Madill893ab082014-05-16 16:56:10 -04002467 {
2468 return false;
2469 }
2470
2471 return true;
2472}
2473
Jamie Madillc29968b2016-01-20 11:17:23 -05002474bool ValidateCopyTexImageParametersBase(ValidationContext *context,
2475 GLenum target,
2476 GLint level,
2477 GLenum internalformat,
2478 bool isSubImage,
2479 GLint xoffset,
2480 GLint yoffset,
2481 GLint zoffset,
2482 GLint x,
2483 GLint y,
2484 GLsizei width,
2485 GLsizei height,
2486 GLint border,
Jamie Madill0c8abca2016-07-22 20:21:26 -04002487 Format *textureFormatOut)
Jamie Madill560a8d82014-05-21 13:06:20 -04002488{
Jamie Madill560a8d82014-05-21 13:06:20 -04002489 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
2490 {
Jamie Madill437fa652016-05-03 15:13:24 -04002491 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002492 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002493 }
2494
He Yunchaoced53ae2016-11-29 15:00:51 +08002495 if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
2496 std::numeric_limits<GLsizei>::max() - yoffset < height)
Jamie Madill560a8d82014-05-21 13:06:20 -04002497 {
Jamie Madill437fa652016-05-03 15:13:24 -04002498 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002499 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002500 }
2501
2502 if (border != 0)
2503 {
Jamie Madill437fa652016-05-03 15:13:24 -04002504 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002505 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002506 }
2507
2508 if (!ValidMipLevel(context, target, level))
2509 {
Jamie Madill437fa652016-05-03 15:13:24 -04002510 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002511 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002512 }
2513
Jamie Madill51f40ec2016-06-15 14:06:00 -04002514 const auto &state = context->getGLState();
2515 auto readFramebuffer = state.getReadFramebuffer();
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002516 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04002517 {
Jamie Madill437fa652016-05-03 15:13:24 -04002518 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002519 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002520 }
2521
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002522 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04002523 {
Jamie Madill437fa652016-05-03 15:13:24 -04002524 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002525 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002526 }
2527
Martin Radev138064f2016-07-15 12:03:41 +03002528 if (readFramebuffer->getReadBufferState() == GL_NONE)
2529 {
2530 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
2531 return false;
2532 }
2533
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002534 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
2535 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
He Yunchao66a41a22016-12-15 16:45:05 +08002536 // attachment and WebGL defines it to be an error. We do the check unconditionally as the
Corentin Wallez3c90ed62016-12-16 16:19:28 -05002537 // situation is an application error that would lead to a crash in ANGLE.
2538 if (readFramebuffer->getReadColorbuffer() == nullptr)
2539 {
2540 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
2541 return false;
2542 }
2543
Geoff Langaae65a42014-05-26 12:43:44 -04002544 const gl::Caps &caps = context->getCaps();
2545
Geoff Langaae65a42014-05-26 12:43:44 -04002546 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04002547 switch (target)
2548 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002549 case GL_TEXTURE_2D:
2550 maxDimension = caps.max2DTextureSize;
2551 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002552
He Yunchaoced53ae2016-11-29 15:00:51 +08002553 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
2554 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
2555 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
2556 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
2557 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
2558 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
2559 maxDimension = caps.maxCubeMapTextureSize;
2560 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002561
He Yunchaoced53ae2016-11-29 15:00:51 +08002562 case GL_TEXTURE_2D_ARRAY:
2563 maxDimension = caps.max2DTextureSize;
2564 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002565
He Yunchaoced53ae2016-11-29 15:00:51 +08002566 case GL_TEXTURE_3D:
2567 maxDimension = caps.max3DTextureSize;
2568 break;
Jamie Madill560a8d82014-05-21 13:06:20 -04002569
He Yunchaoced53ae2016-11-29 15:00:51 +08002570 default:
2571 context->handleError(Error(GL_INVALID_ENUM));
2572 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002573 }
2574
Jamie Madillc29968b2016-01-20 11:17:23 -05002575 gl::Texture *texture =
2576 state.getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
Jamie Madill560a8d82014-05-21 13:06:20 -04002577 if (!texture)
2578 {
Jamie Madill437fa652016-05-03 15:13:24 -04002579 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002580 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002581 }
2582
Geoff Lang69cce582015-09-17 13:20:36 -04002583 if (texture->getImmutableFormat() && !isSubImage)
Jamie Madill560a8d82014-05-21 13:06:20 -04002584 {
Jamie Madill437fa652016-05-03 15:13:24 -04002585 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002586 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002587 }
2588
Geoff Langca271392017-04-05 12:30:00 -04002589 const gl::InternalFormat &formatInfo =
2590 gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04002591
Geoff Lang966c9402017-04-18 12:38:27 -04002592 if (formatInfo.depthBits > 0 || formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04002593 {
Jamie Madill437fa652016-05-03 15:13:24 -04002594 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa9be0dc2014-12-17 12:34:40 -05002595 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002596 }
2597
2598 if (isSubImage)
2599 {
Geoff Langa9be0dc2014-12-17 12:34:40 -05002600 if (static_cast<size_t>(xoffset + width) > texture->getWidth(target, level) ||
2601 static_cast<size_t>(yoffset + height) > texture->getHeight(target, level) ||
2602 static_cast<size_t>(zoffset) >= texture->getDepth(target, level))
Jamie Madill560a8d82014-05-21 13:06:20 -04002603 {
Jamie Madill437fa652016-05-03 15:13:24 -04002604 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002605 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04002606 }
2607 }
Jamie Madill6f38f822014-06-06 17:12:20 -04002608 else
2609 {
Geoff Lang691e58c2014-12-19 17:03:25 -05002610 if (IsCubeMapTextureTarget(target) && width != height)
Jamie Madill6f38f822014-06-06 17:12:20 -04002611 {
Jamie Madill437fa652016-05-03 15:13:24 -04002612 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002613 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002614 }
2615
Geoff Langeb66a6e2016-10-31 13:06:12 -04002616 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04002617 {
Jamie Madill437fa652016-05-03 15:13:24 -04002618 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04002619 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002620 }
2621
2622 int maxLevelDimension = (maxDimension >> level);
He Yunchaoced53ae2016-11-29 15:00:51 +08002623 if (static_cast<int>(width) > maxLevelDimension ||
2624 static_cast<int>(height) > maxLevelDimension)
Jamie Madill6f38f822014-06-06 17:12:20 -04002625 {
Jamie Madill437fa652016-05-03 15:13:24 -04002626 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002627 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04002628 }
2629 }
Jamie Madill560a8d82014-05-21 13:06:20 -04002630
Jamie Madill0c8abca2016-07-22 20:21:26 -04002631 if (textureFormatOut)
2632 {
2633 *textureFormatOut = texture->getFormat(target, level);
2634 }
Jamie Madillf695a3a2017-01-11 17:36:35 -05002635
2636 // Detect texture copying feedback loops for WebGL.
2637 if (context->getExtensions().webglCompatibility)
2638 {
Jamie Madillfd3dd432017-02-02 19:59:59 -05002639 if (readFramebuffer->formsCopyingFeedbackLoopWith(texture->id(), level, zoffset))
Jamie Madillf695a3a2017-01-11 17:36:35 -05002640 {
2641 context->handleError(Error(GL_INVALID_OPERATION,
2642 "Texture copying feedback loop formed between Framebuffer "
2643 "and specified Texture level."));
2644 return false;
2645 }
2646 }
2647
Jamie Madill560a8d82014-05-21 13:06:20 -04002648 return true;
2649}
2650
Jiajia Qind9671222016-11-29 16:30:31 +08002651bool ValidateDrawBase(ValidationContext *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04002652{
Jamie Madill1aeb1312014-06-20 13:21:25 -04002653 switch (mode)
2654 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002655 case GL_POINTS:
2656 case GL_LINES:
2657 case GL_LINE_LOOP:
2658 case GL_LINE_STRIP:
2659 case GL_TRIANGLES:
2660 case GL_TRIANGLE_STRIP:
2661 case GL_TRIANGLE_FAN:
2662 break;
2663 default:
2664 context->handleError(Error(GL_INVALID_ENUM));
2665 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04002666 }
2667
Jamie Madill250d33f2014-06-06 17:09:03 -04002668 if (count < 0)
2669 {
Jamie Madill437fa652016-05-03 15:13:24 -04002670 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002671 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002672 }
2673
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002674 const State &state = context->getGLState();
Geoff Langb1196682014-07-23 13:47:29 -04002675
Jamie Madill250d33f2014-06-06 17:09:03 -04002676 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002677 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002678 {
Jamie Madill437fa652016-05-03 15:13:24 -04002679 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002680 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002681 }
2682
Jamie Madillcbcde722017-01-06 14:50:00 -05002683 // Note: these separate values are not supported in WebGL, due to D3D's limitations. See
2684 // Section 6.10 of the WebGL 1.0 spec.
Jamie Madill51f40ec2016-06-15 14:06:00 -04002685 Framebuffer *framebuffer = state.getDrawFramebuffer();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002686 if (context->getLimitations().noSeparateStencilRefsAndMasks ||
2687 context->getExtensions().webglCompatibility)
Jamie Madillac528012014-06-20 13:21:23 -04002688 {
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002689 const FramebufferAttachment *dsAttachment =
2690 framebuffer->getStencilOrDepthStencilAttachment();
2691 GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
He Yunchaoced53ae2016-11-29 15:00:51 +08002692 GLuint minimumRequiredStencilMask = (1 << stencilBits) - 1;
Jinyoung Hur85769f02015-10-20 17:08:44 -04002693 const DepthStencilState &depthStencilState = state.getDepthStencilState();
Corentin Wallezb1d0a2552016-12-19 16:15:54 -05002694
2695 bool differentRefs = state.getStencilRef() != state.getStencilBackRef();
2696 bool differentWritemasks =
2697 (depthStencilState.stencilWritemask & minimumRequiredStencilMask) !=
2698 (depthStencilState.stencilBackWritemask & minimumRequiredStencilMask);
2699 bool differentMasks = (depthStencilState.stencilMask & minimumRequiredStencilMask) !=
2700 (depthStencilState.stencilBackMask & minimumRequiredStencilMask);
2701
2702 if (differentRefs || differentWritemasks || differentMasks)
Geoff Lang3a86ad32015-09-01 11:47:05 -04002703 {
Jamie Madillcbcde722017-01-06 14:50:00 -05002704 if (!context->getExtensions().webglCompatibility)
2705 {
Yuly Novikovd73f8522017-01-13 17:48:57 -05002706 ERR() << "This ANGLE implementation does not support separate front/back stencil "
2707 "writemasks, reference values, or stencil mask values.";
Jamie Madillcbcde722017-01-06 14:50:00 -05002708 }
Jamie Madill437fa652016-05-03 15:13:24 -04002709 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Lang3a86ad32015-09-01 11:47:05 -04002710 return false;
2711 }
Jamie Madillac528012014-06-20 13:21:23 -04002712 }
2713
Jamie Madilldd43e6c2017-03-24 14:18:49 -04002714 if (framebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002715 {
Jamie Madill437fa652016-05-03 15:13:24 -04002716 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002717 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04002718 }
2719
Geoff Lang7dd2e102014-11-10 15:19:26 -05002720 gl::Program *program = state.getProgram();
2721 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04002722 {
Jamie Madill437fa652016-05-03 15:13:24 -04002723 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002724 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002725 }
2726
Yunchao Hef81ce4a2017-04-24 10:49:17 +08002727 if (!program->validateSamplers(nullptr, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04002728 {
Jamie Madill437fa652016-05-03 15:13:24 -04002729 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002730 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002731 }
2732
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002733 // Uniform buffer validation
He Yunchaoced53ae2016-11-29 15:00:51 +08002734 for (unsigned int uniformBlockIndex = 0;
2735 uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002736 {
Jamie Madill62d31cb2015-09-11 13:25:51 -04002737 const gl::UniformBlock &uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex);
He Yunchaoced53ae2016-11-29 15:00:51 +08002738 GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
Geoff Lang5d124a62015-09-15 13:03:27 -04002739 const OffsetBindingPointer<Buffer> &uniformBuffer =
2740 state.getIndexedUniformBuffer(blockBinding);
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002741
Geoff Lang5d124a62015-09-15 13:03:27 -04002742 if (uniformBuffer.get() == nullptr)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002743 {
2744 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002745 context->handleError(
2746 Error(GL_INVALID_OPERATION,
2747 "It is undefined behaviour to have a used but unbound uniform buffer."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002748 return false;
2749 }
2750
Geoff Lang5d124a62015-09-15 13:03:27 -04002751 size_t uniformBufferSize = uniformBuffer.getSize();
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002752 if (uniformBufferSize == 0)
2753 {
2754 // Bind the whole buffer.
Minmin Gong794e0002015-04-07 18:31:54 -07002755 uniformBufferSize = static_cast<size_t>(uniformBuffer->getSize());
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002756 }
2757
Jamie Madill62d31cb2015-09-11 13:25:51 -04002758 if (uniformBufferSize < uniformBlock.dataSize)
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002759 {
2760 // undefined behaviour
Jamie Madill437fa652016-05-03 15:13:24 -04002761 context->handleError(
2762 Error(GL_INVALID_OPERATION,
2763 "It is undefined behaviour to use a uniform buffer that is too small."));
Gregoire Payen de La Garanderie68694e92015-03-24 14:03:37 +00002764 return false;
2765 }
2766 }
2767
Geoff Lange0cff192017-05-30 13:04:56 -04002768 // Do some additonal WebGL-specific validation
Jamie Madilla4595b82017-01-11 17:36:34 -05002769 if (context->getExtensions().webglCompatibility)
2770 {
Geoff Lange0cff192017-05-30 13:04:56 -04002771 // Detect rendering feedback loops for WebGL.
Jamie Madilla4595b82017-01-11 17:36:34 -05002772 if (framebuffer->formsRenderingFeedbackLoopWith(state))
2773 {
2774 context->handleError(
2775 Error(GL_INVALID_OPERATION,
2776 "Rendering feedback loop formed between Framebuffer and active Texture."));
2777 return false;
2778 }
Geoff Lange0cff192017-05-30 13:04:56 -04002779
Geoff Lang9ab5b822017-05-30 16:19:23 -04002780 // Detect that the vertex shader input types match the attribute types
2781 if (!ValidateVertexShaderAttributeTypeMatch(context))
2782 {
2783 return false;
2784 }
2785
Geoff Lange0cff192017-05-30 13:04:56 -04002786 // Detect that the color buffer types match the fragment shader output types
2787 if (!ValidateFragmentShaderColorBufferTypeMatch(context))
2788 {
2789 return false;
2790 }
Jamie Madilla4595b82017-01-11 17:36:34 -05002791 }
2792
Jamie Madill250d33f2014-06-06 17:09:03 -04002793 // No-op if zero count
2794 return (count > 0);
2795}
2796
Jamie Madillc1d770e2017-04-13 17:31:24 -04002797bool ValidateDrawArraysCommon(ValidationContext *context,
2798 GLenum mode,
2799 GLint first,
2800 GLsizei count,
2801 GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04002802{
Jamie Madillfd716582014-06-06 17:09:04 -04002803 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04002804 {
Jamie Madill437fa652016-05-03 15:13:24 -04002805 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04002806 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002807 }
2808
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002809 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002810 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002811 if (curTransformFeedback && curTransformFeedback->isActive() &&
2812 !curTransformFeedback->isPaused() && curTransformFeedback->getPrimitiveMode() != mode)
Jamie Madillfd716582014-06-06 17:09:04 -04002813 {
2814 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
He Yunchaoced53ae2016-11-29 15:00:51 +08002815 // that does not match the current transform feedback object's draw mode (if transform
2816 // feedback
Jamie Madillfd716582014-06-06 17:09:04 -04002817 // is active), (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002818 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002819 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04002820 }
2821
Jiajia Qind9671222016-11-29 16:30:31 +08002822 if (!ValidateDrawBase(context, mode, count))
Corentin Wallez18a2fb32015-08-10 12:58:14 -07002823 {
2824 return false;
2825 }
2826
Corentin Wallez71168a02016-12-19 15:11:18 -08002827 // Check the computation of maxVertex doesn't overflow.
2828 // - first < 0 or count < 0 have been checked as an error condition
2829 // - count > 0 has been checked in ValidateDrawBase as it makes the call a noop
2830 // From this we know maxVertex will be positive, and only need to check if it overflows GLint.
2831 ASSERT(count > 0 && first >= 0);
2832 int64_t maxVertex = static_cast<int64_t>(first) + static_cast<int64_t>(count) - 1;
2833 if (maxVertex > static_cast<int64_t>(std::numeric_limits<GLint>::max()))
Corentin Wallez92db6942016-12-09 13:10:36 -05002834 {
2835 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
2836 return false;
2837 }
2838
Corentin Wallez71168a02016-12-19 15:11:18 -08002839 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(maxVertex), count))
Jamie Madillfd716582014-06-06 17:09:04 -04002840 {
2841 return false;
2842 }
2843
2844 return true;
2845}
2846
He Yunchaoced53ae2016-11-29 15:00:51 +08002847bool ValidateDrawArraysInstanced(Context *context,
2848 GLenum mode,
2849 GLint first,
2850 GLsizei count,
2851 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04002852{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002853 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04002854 {
2855 return false;
2856 }
2857
Corentin Wallez170efbf2017-05-02 13:45:01 -04002858 return !context->getExtensions().webglCompatibility ||
2859 ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002860}
2861
He Yunchaoced53ae2016-11-29 15:00:51 +08002862bool ValidateDrawArraysInstancedANGLE(Context *context,
2863 GLenum mode,
2864 GLint first,
2865 GLsizei count,
2866 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04002867{
Corentin Wallez170efbf2017-05-02 13:45:01 -04002868 if (!ValidateDrawArraysInstancedBase(context, mode, first, count, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04002869 {
2870 return false;
2871 }
2872
Corentin Wallez170efbf2017-05-02 13:45:01 -04002873 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04002874}
2875
Jiajia Qind9671222016-11-29 16:30:31 +08002876bool ValidateDrawElementsBase(ValidationContext *context, GLenum type)
Jamie Madillfd716582014-06-06 17:09:04 -04002877{
Jamie Madill250d33f2014-06-06 17:09:03 -04002878 switch (type)
2879 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002880 case GL_UNSIGNED_BYTE:
2881 case GL_UNSIGNED_SHORT:
2882 break;
2883 case GL_UNSIGNED_INT:
2884 if (context->getClientMajorVersion() < 3 && !context->getExtensions().elementIndexUint)
2885 {
2886 context->handleError(Error(GL_INVALID_ENUM));
2887 return false;
2888 }
2889 break;
2890 default:
2891 context->handleError(Error(GL_INVALID_ENUM));
2892 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002893 }
2894
Jamie Madilldfde6ab2016-06-09 07:07:18 -07002895 const State &state = context->getGLState();
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002896
2897 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
He Yunchaoced53ae2016-11-29 15:00:51 +08002898 if (curTransformFeedback && curTransformFeedback->isActive() &&
2899 !curTransformFeedback->isPaused())
Jamie Madill250d33f2014-06-06 17:09:03 -04002900 {
He Yunchaoced53ae2016-11-29 15:00:51 +08002901 // It is an invalid operation to call DrawElements, DrawRangeElements or
2902 // DrawElementsInstanced
Jamie Madill250d33f2014-06-06 17:09:03 -04002903 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Jamie Madill437fa652016-05-03 15:13:24 -04002904 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04002905 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002906 }
2907
Jiajia Qind9671222016-11-29 16:30:31 +08002908 return true;
2909}
2910
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002911bool ValidateDrawElementsCommon(ValidationContext *context,
2912 GLenum mode,
2913 GLsizei count,
2914 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04002915 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04002916 GLsizei primcount)
Jiajia Qind9671222016-11-29 16:30:31 +08002917{
2918 if (!ValidateDrawElementsBase(context, type))
2919 return false;
2920
2921 const State &state = context->getGLState();
2922
Corentin Wallez170efbf2017-05-02 13:45:01 -04002923 if (!ValidateDrawBase(context, mode, count))
2924 {
2925 return false;
2926 }
2927
Jamie Madill250d33f2014-06-06 17:09:03 -04002928 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04002929 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04002930 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002931 context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
Geoff Langb1196682014-07-23 13:47:29 -04002932 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04002933 }
2934
He Yunchaoced53ae2016-11-29 15:00:51 +08002935 const gl::VertexArray *vao = state.getVertexArray();
Jamie Madill8e344942015-07-09 14:22:07 -04002936 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
Jamie Madilld4cfa572014-07-08 10:00:32 -04002937
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002938 GLuint typeBytes = gl::GetTypeInfo(type).bytes;
2939
2940 if (context->getExtensions().webglCompatibility)
2941 {
2942 ASSERT(isPow2(typeBytes) && typeBytes > 0);
2943 if ((reinterpret_cast<uintptr_t>(indices) & static_cast<uintptr_t>(typeBytes - 1)) != 0)
2944 {
2945 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2946 // The offset arguments to drawElements and [...], must be a multiple of the size of the
2947 // data type passed to the call, or an INVALID_OPERATION error is generated.
2948 context->handleError(Error(GL_INVALID_OPERATION,
2949 "indices must be a multiple of the element type size."));
2950 return false;
2951 }
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002952
2953 // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
2954 // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
2955 // error is generated.
2956 if (reinterpret_cast<intptr_t>(indices) < 0)
2957 {
2958 context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
2959 return false;
2960 }
Geoff Langfeb8c682017-02-13 16:07:35 -05002961 }
2962
2963 if (context->getExtensions().webglCompatibility ||
2964 !context->getGLState().areClientArraysEnabled())
2965 {
Corentin Wallez3f6d4df2017-01-30 18:04:36 -05002966 if (!elementArrayBuffer && count > 0)
2967 {
2968 // [WebGL 1.0] Section 6.2 No Client Side Arrays
2969 // If drawElements is called with a count greater than zero, and no WebGLBuffer is bound
2970 // to the ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated.
2971 context->handleError(Error(GL_INVALID_OPERATION,
2972 "There is no element array buffer bound and count > 0."));
2973 return false;
2974 }
2975 }
2976
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002977 if (count > 0)
Jamie Madillae3000b2014-08-25 15:47:51 -04002978 {
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002979 if (elementArrayBuffer)
Jamie Madillae3000b2014-08-25 15:47:51 -04002980 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002981 // The max possible type size is 8 and count is on 32 bits so doing the multiplication
2982 // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
2983 static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
2984 constexpr uint64_t kMaxTypeSize = 8;
2985 constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
2986 constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
2987 static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002988
Corentin Wallezfe9306a2017-02-01 17:41:05 -05002989 uint64_t typeSize = typeBytes;
2990 uint64_t elementCount = static_cast<uint64_t>(count);
2991 ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
2992
2993 // Doing the multiplication here is overflow-safe
2994 uint64_t elementDataSizeNoOffset = typeSize * elementCount;
2995
2996 // The offset can be any value, check for overflows
2997 uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
2998 if (elementDataSizeNoOffset > kUint64Max - offset)
Corentin Wallez0844f2d2017-01-31 17:02:59 -05002999 {
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003000 context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003001 return false;
3002 }
3003
Corentin Wallezfe9306a2017-02-01 17:41:05 -05003004 uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
3005 if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
Corentin Wallez0844f2d2017-01-31 17:02:59 -05003006 {
3007 context->handleError(
3008 Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
3009 return false;
3010 }
3011 }
3012 else if (!indices)
3013 {
3014 // This is an application error that would normally result in a crash,
3015 // but we catch it and return an error
3016 context->handleError(
3017 Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
Geoff Langb1196682014-07-23 13:47:29 -04003018 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04003019 }
Jamie Madillae3000b2014-08-25 15:47:51 -04003020 }
3021
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003022 // Use the parameter buffer to retrieve and cache the index range.
Jamie Madill2b976812014-08-25 15:47:49 -04003023 // TODO: offer fast path, with disabled index validation.
3024 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003025 const auto &params = context->getParams<HasIndexRange>();
3026 const auto &indexRangeOpt = params.getIndexRange();
3027 if (!indexRangeOpt.valid())
Jamie Madill2b976812014-08-25 15:47:49 -04003028 {
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003029 // Unexpected error.
3030 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04003031 }
3032
Jamie Madille79b1e12015-11-04 16:36:37 -05003033 // If we use an index greater than our maximum supported index range, return an error.
3034 // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should always
3035 // return an error if possible here.
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003036 if (static_cast<GLuint64>(indexRangeOpt.value().end) >= context->getCaps().maxElementIndex)
Jamie Madille79b1e12015-11-04 16:36:37 -05003037 {
Jamie Madill437fa652016-05-03 15:13:24 -04003038 context->handleError(Error(GL_INVALID_OPERATION, g_ExceedsMaxElementErrorMessage));
Jamie Madille79b1e12015-11-04 16:36:37 -05003039 return false;
3040 }
3041
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003042 if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOpt.value().end),
3043 static_cast<GLint>(indexRangeOpt.value().vertexCount())))
Jamie Madillfd716582014-06-06 17:09:04 -04003044 {
3045 return false;
3046 }
3047
Geoff Lang3edfe032015-09-04 16:38:24 -04003048 // No op if there are no real indices in the index data (all are primitive restart).
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003049 return (indexRangeOpt.value().vertexIndexCount > 0);
Jamie Madillfd716582014-06-06 17:09:04 -04003050}
3051
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003052bool ValidateDrawElementsInstancedCommon(ValidationContext *context,
3053 GLenum mode,
3054 GLsizei count,
3055 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003056 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003057 GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04003058{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003059 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04003060 {
3061 return false;
3062 }
3063
Corentin Wallez170efbf2017-05-02 13:45:01 -04003064 return !context->getExtensions().webglCompatibility ||
3065 ValidateDrawInstancedANGLEAndWebGL(context);
Jamie Madill250d33f2014-06-06 17:09:03 -04003066}
3067
Geoff Lang3edfe032015-09-04 16:38:24 -04003068bool ValidateDrawElementsInstancedANGLE(Context *context,
3069 GLenum mode,
3070 GLsizei count,
3071 GLenum type,
Jamie Madill876429b2017-04-20 15:46:24 -04003072 const void *indices,
Jamie Madill9c9b40a2017-04-26 16:31:57 -04003073 GLsizei primcount)
Geoff Lang87a93302014-09-16 13:29:43 -04003074{
Corentin Wallez170efbf2017-05-02 13:45:01 -04003075 if (!ValidateDrawElementsInstancedBase(context, mode, count, type, indices, primcount))
Geoff Lang87a93302014-09-16 13:29:43 -04003076 {
3077 return false;
3078 }
3079
Corentin Wallez170efbf2017-05-02 13:45:01 -04003080 return ValidateDrawInstancedANGLEAndWebGL(context);
Geoff Lang87a93302014-09-16 13:29:43 -04003081}
3082
He Yunchaoced53ae2016-11-29 15:00:51 +08003083bool ValidateFramebufferTextureBase(Context *context,
3084 GLenum target,
3085 GLenum attachment,
3086 GLuint texture,
3087 GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04003088{
Jamie Madill55ec3b12014-07-03 10:38:57 -04003089 if (!ValidFramebufferTarget(target))
3090 {
Jamie Madill437fa652016-05-03 15:13:24 -04003091 context->handleError(Error(GL_INVALID_ENUM));
Geoff Langb1196682014-07-23 13:47:29 -04003092 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003093 }
3094
3095 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04003096 {
3097 return false;
3098 }
3099
Jamie Madill55ec3b12014-07-03 10:38:57 -04003100 if (texture != 0)
3101 {
3102 gl::Texture *tex = context->getTexture(texture);
3103
Jamie Madillbe849e42017-05-02 15:49:00 -04003104 if (tex == NULL)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003105 {
Jamie Madill437fa652016-05-03 15:13:24 -04003106 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003107 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003108 }
3109
3110 if (level < 0)
3111 {
Jamie Madill437fa652016-05-03 15:13:24 -04003112 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003113 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003114 }
3115 }
3116
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003117 const gl::Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
Jamie Madill84115c92015-04-23 15:00:07 -04003118 ASSERT(framebuffer);
Jamie Madill55ec3b12014-07-03 10:38:57 -04003119
Jamie Madill84115c92015-04-23 15:00:07 -04003120 if (framebuffer->id() == 0)
Jamie Madill55ec3b12014-07-03 10:38:57 -04003121 {
Jamie Madill437fa652016-05-03 15:13:24 -04003122 context->handleError(
3123 Error(GL_INVALID_OPERATION, "Cannot change default FBO's attachments"));
Geoff Langb1196682014-07-23 13:47:29 -04003124 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04003125 }
3126
3127 return true;
3128}
3129
Geoff Langb1196682014-07-23 13:47:29 -04003130bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04003131{
3132 if (program == 0)
3133 {
Jamie Madill437fa652016-05-03 15:13:24 -04003134 context->handleError(Error(GL_INVALID_VALUE));
Geoff Langb1196682014-07-23 13:47:29 -04003135 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003136 }
3137
Dian Xiang769769a2015-09-09 15:20:08 -07003138 gl::Program *programObject = GetValidProgram(context, program);
3139 if (!programObject)
Shannon Woods4de4fd62014-11-07 16:22:02 -05003140 {
3141 return false;
3142 }
3143
Jamie Madill0063c512014-08-25 15:47:53 -04003144 if (!programObject || !programObject->isLinked())
3145 {
Jamie Madill437fa652016-05-03 15:13:24 -04003146 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003147 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003148 }
3149
Geoff Lang7dd2e102014-11-10 15:19:26 -05003150 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04003151 {
Jamie Madill437fa652016-05-03 15:13:24 -04003152 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langb1196682014-07-23 13:47:29 -04003153 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04003154 }
3155
Jamie Madill0063c512014-08-25 15:47:53 -04003156 return true;
3157}
3158
Geoff Langf41d0ee2016-10-07 13:04:23 -04003159static bool ValidateSizedGetUniform(Context *context,
3160 GLuint program,
3161 GLint location,
3162 GLsizei bufSize,
3163 GLsizei *length)
Jamie Madill78f41802014-08-25 15:47:55 -04003164{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003165 if (length)
3166 {
3167 *length = 0;
3168 }
3169
Jamie Madill78f41802014-08-25 15:47:55 -04003170 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04003171 {
Jamie Madill78f41802014-08-25 15:47:55 -04003172 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003173 }
3174
Geoff Langf41d0ee2016-10-07 13:04:23 -04003175 if (bufSize < 0)
3176 {
3177 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3178 return false;
3179 }
3180
Jamie Madilla502c742014-08-28 17:19:13 -04003181 gl::Program *programObject = context->getProgram(program);
3182 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04003183
Jamie Madill78f41802014-08-25 15:47:55 -04003184 // sized queries -- ensure the provided buffer is large enough
Jamie Madill62d31cb2015-09-11 13:25:51 -04003185 const LinkedUniform &uniform = programObject->getUniformByLocation(location);
He Yunchaoced53ae2016-11-29 15:00:51 +08003186 size_t requiredBytes = VariableExternalSize(uniform.type);
Jamie Madill78f41802014-08-25 15:47:55 -04003187 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04003188 {
Geoff Langf41d0ee2016-10-07 13:04:23 -04003189 context->handleError(
3190 Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
Geoff Langb1196682014-07-23 13:47:29 -04003191 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04003192 }
3193
Geoff Langf41d0ee2016-10-07 13:04:23 -04003194 if (length)
3195 {
Geoff Lang94177fb2016-11-14 16:12:26 -05003196 *length = VariableComponentCount(uniform.type);
Geoff Langf41d0ee2016-10-07 13:04:23 -04003197 }
3198
Jamie Madill0063c512014-08-25 15:47:53 -04003199 return true;
3200}
3201
He Yunchaoced53ae2016-11-29 15:00:51 +08003202bool ValidateGetnUniformfvEXT(Context *context,
3203 GLuint program,
3204 GLint location,
3205 GLsizei bufSize,
3206 GLfloat *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003207{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003208 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
Jamie Madill0063c512014-08-25 15:47:53 -04003209}
3210
He Yunchaoced53ae2016-11-29 15:00:51 +08003211bool ValidateGetnUniformivEXT(Context *context,
3212 GLuint program,
3213 GLint location,
3214 GLsizei bufSize,
3215 GLint *params)
Jamie Madill0063c512014-08-25 15:47:53 -04003216{
Geoff Langf41d0ee2016-10-07 13:04:23 -04003217 return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
3218}
3219
3220bool ValidateGetUniformfvRobustANGLE(Context *context,
3221 GLuint program,
3222 GLint location,
3223 GLsizei bufSize,
3224 GLsizei *length,
3225 GLfloat *params)
3226{
3227 if (!ValidateRobustEntryPoint(context, bufSize))
3228 {
3229 return false;
3230 }
3231
3232 // bufSize is validated in ValidateSizedGetUniform
3233 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3234}
3235
3236bool ValidateGetUniformivRobustANGLE(Context *context,
3237 GLuint program,
3238 GLint location,
3239 GLsizei bufSize,
3240 GLsizei *length,
3241 GLint *params)
3242{
3243 if (!ValidateRobustEntryPoint(context, bufSize))
3244 {
3245 return false;
3246 }
3247
3248 // bufSize is validated in ValidateSizedGetUniform
3249 return ValidateSizedGetUniform(context, program, location, bufSize, length);
3250}
3251
3252bool ValidateGetUniformuivRobustANGLE(Context *context,
3253 GLuint program,
3254 GLint location,
3255 GLsizei bufSize,
3256 GLsizei *length,
3257 GLuint *params)
3258{
3259 if (!ValidateRobustEntryPoint(context, bufSize))
3260 {
3261 return false;
3262 }
3263
3264 if (context->getClientMajorVersion() < 3)
3265 {
3266 context->handleError(
3267 Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
3268 return false;
3269 }
3270
3271 // bufSize is validated in ValidateSizedGetUniform
3272 return ValidateSizedGetUniform(context, program, location, bufSize, length);
Jamie Madill0063c512014-08-25 15:47:53 -04003273}
3274
He Yunchaoced53ae2016-11-29 15:00:51 +08003275bool ValidateDiscardFramebufferBase(Context *context,
3276 GLenum target,
3277 GLsizei numAttachments,
3278 const GLenum *attachments,
3279 bool defaultFramebuffer)
Austin Kinross08332632015-05-05 13:35:47 -07003280{
3281 if (numAttachments < 0)
3282 {
Jamie Madill437fa652016-05-03 15:13:24 -04003283 context->handleError(Error(GL_INVALID_VALUE, "numAttachments must not be less than zero"));
Austin Kinross08332632015-05-05 13:35:47 -07003284 return false;
3285 }
3286
3287 for (GLsizei i = 0; i < numAttachments; ++i)
3288 {
Olli Etuaho84c9f592016-03-09 14:37:25 +02003289 if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT31)
Austin Kinross08332632015-05-05 13:35:47 -07003290 {
3291 if (defaultFramebuffer)
3292 {
Jamie Madill437fa652016-05-03 15:13:24 -04003293 context->handleError(Error(
3294 GL_INVALID_ENUM, "Invalid attachment when the default framebuffer is bound"));
Austin Kinross08332632015-05-05 13:35:47 -07003295 return false;
3296 }
3297
3298 if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments)
3299 {
Jamie Madill437fa652016-05-03 15:13:24 -04003300 context->handleError(Error(GL_INVALID_OPERATION,
3301 "Requested color attachment is greater than the maximum "
3302 "supported color attachments"));
Austin Kinross08332632015-05-05 13:35:47 -07003303 return false;
3304 }
3305 }
3306 else
3307 {
3308 switch (attachments[i])
3309 {
He Yunchaoced53ae2016-11-29 15:00:51 +08003310 case GL_DEPTH_ATTACHMENT:
3311 case GL_STENCIL_ATTACHMENT:
3312 case GL_DEPTH_STENCIL_ATTACHMENT:
3313 if (defaultFramebuffer)
3314 {
3315 context->handleError(
3316 Error(GL_INVALID_ENUM,
3317 "Invalid attachment when the default framebuffer is bound"));
3318 return false;
3319 }
3320 break;
3321 case GL_COLOR:
3322 case GL_DEPTH:
3323 case GL_STENCIL:
3324 if (!defaultFramebuffer)
3325 {
3326 context->handleError(
3327 Error(GL_INVALID_ENUM,
3328 "Invalid attachment when the default framebuffer is not bound"));
3329 return false;
3330 }
3331 break;
3332 default:
3333 context->handleError(Error(GL_INVALID_ENUM, "Invalid attachment"));
Austin Kinross08332632015-05-05 13:35:47 -07003334 return false;
Austin Kinross08332632015-05-05 13:35:47 -07003335 }
3336 }
3337 }
3338
3339 return true;
3340}
3341
Austin Kinross6ee1e782015-05-29 17:05:37 -07003342bool ValidateInsertEventMarkerEXT(Context *context, GLsizei length, const char *marker)
3343{
3344 // Note that debug marker calls must not set error state
3345
3346 if (length < 0)
3347 {
3348 return false;
3349 }
3350
3351 if (marker == nullptr)
3352 {
3353 return false;
3354 }
3355
3356 return true;
3357}
3358
3359bool ValidatePushGroupMarkerEXT(Context *context, GLsizei length, const char *marker)
3360{
3361 // Note that debug marker calls must not set error state
3362
3363 if (length < 0)
3364 {
3365 return false;
3366 }
3367
3368 if (length > 0 && marker == nullptr)
3369 {
3370 return false;
3371 }
3372
3373 return true;
3374}
3375
Geoff Langdcab33b2015-07-21 13:03:16 -04003376bool ValidateEGLImageTargetTexture2DOES(Context *context,
3377 egl::Display *display,
3378 GLenum target,
3379 egl::Image *image)
3380{
Geoff Langa8406172015-07-21 16:53:39 -04003381 if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
3382 {
Jamie Madill437fa652016-05-03 15:13:24 -04003383 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04003384 return false;
3385 }
3386
3387 switch (target)
3388 {
3389 case GL_TEXTURE_2D:
Geoff Langb66a9092016-05-16 15:59:14 -04003390 if (!context->getExtensions().eglImage)
3391 {
3392 context->handleError(Error(
3393 GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image."));
3394 }
3395 break;
3396
3397 case GL_TEXTURE_EXTERNAL_OES:
3398 if (!context->getExtensions().eglImageExternal)
3399 {
3400 context->handleError(Error(
3401 GL_INVALID_ENUM,
3402 "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external."));
3403 }
Geoff Langa8406172015-07-21 16:53:39 -04003404 break;
3405
3406 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003407 context->handleError(Error(GL_INVALID_ENUM, "invalid texture target."));
Geoff Langa8406172015-07-21 16:53:39 -04003408 return false;
3409 }
3410
3411 if (!display->isValidImage(image))
3412 {
Jamie Madill437fa652016-05-03 15:13:24 -04003413 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04003414 return false;
3415 }
3416
3417 if (image->getSamples() > 0)
3418 {
Jamie Madill437fa652016-05-03 15:13:24 -04003419 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04003420 "cannot create a 2D texture from a multisampled EGL image."));
3421 return false;
3422 }
3423
Geoff Langca271392017-04-05 12:30:00 -04003424 const TextureCaps &textureCaps =
3425 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003426 if (!textureCaps.texturable)
3427 {
Jamie Madill437fa652016-05-03 15:13:24 -04003428 context->handleError(Error(GL_INVALID_OPERATION,
Geoff Langa8406172015-07-21 16:53:39 -04003429 "EGL image internal format is not supported as a texture."));
3430 return false;
3431 }
3432
Geoff Langdcab33b2015-07-21 13:03:16 -04003433 return true;
3434}
3435
3436bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
3437 egl::Display *display,
3438 GLenum target,
3439 egl::Image *image)
3440{
Geoff Langa8406172015-07-21 16:53:39 -04003441 if (!context->getExtensions().eglImage)
3442 {
Jamie Madill437fa652016-05-03 15:13:24 -04003443 context->handleError(Error(GL_INVALID_OPERATION));
Geoff Langa8406172015-07-21 16:53:39 -04003444 return false;
3445 }
3446
3447 switch (target)
3448 {
3449 case GL_RENDERBUFFER:
3450 break;
3451
3452 default:
Jamie Madill437fa652016-05-03 15:13:24 -04003453 context->handleError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
Geoff Langa8406172015-07-21 16:53:39 -04003454 return false;
3455 }
3456
3457 if (!display->isValidImage(image))
3458 {
Jamie Madill437fa652016-05-03 15:13:24 -04003459 context->handleError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
Geoff Langa8406172015-07-21 16:53:39 -04003460 return false;
3461 }
3462
Geoff Langca271392017-04-05 12:30:00 -04003463 const TextureCaps &textureCaps =
3464 context->getTextureCaps().get(image->getFormat().info->sizedInternalFormat);
Geoff Langa8406172015-07-21 16:53:39 -04003465 if (!textureCaps.renderable)
3466 {
Jamie Madill437fa652016-05-03 15:13:24 -04003467 context->handleError(Error(
Geoff Langa8406172015-07-21 16:53:39 -04003468 GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
3469 return false;
3470 }
3471
Geoff Langdcab33b2015-07-21 13:03:16 -04003472 return true;
3473}
Austin Kinrossbc781f32015-10-26 09:27:38 -07003474
3475bool ValidateBindVertexArrayBase(Context *context, GLuint array)
3476{
Geoff Lang36167ab2015-12-07 10:27:14 -05003477 if (!context->isVertexArrayGenerated(array))
Austin Kinrossbc781f32015-10-26 09:27:38 -07003478 {
3479 // The default VAO should always exist
3480 ASSERT(array != 0);
Jamie Madill437fa652016-05-03 15:13:24 -04003481 context->handleError(Error(GL_INVALID_OPERATION));
Austin Kinrossbc781f32015-10-26 09:27:38 -07003482 return false;
3483 }
3484
3485 return true;
3486}
3487
Geoff Langc5629752015-12-07 16:29:04 -05003488bool ValidateProgramBinaryBase(Context *context,
3489 GLuint program,
3490 GLenum binaryFormat,
3491 const void *binary,
3492 GLint length)
3493{
3494 Program *programObject = GetValidProgram(context, program);
3495 if (programObject == nullptr)
3496 {
3497 return false;
3498 }
3499
3500 const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
3501 if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
3502 programBinaryFormats.end())
3503 {
Jamie Madill437fa652016-05-03 15:13:24 -04003504 context->handleError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
Geoff Langc5629752015-12-07 16:29:04 -05003505 return false;
3506 }
3507
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003508 if (context->hasActiveTransformFeedback(program))
3509 {
3510 // ES 3.0.4 section 2.15 page 91
Jamie Madill437fa652016-05-03 15:13:24 -04003511 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuahoc3e55a42016-03-09 16:29:18 +02003512 "Cannot change program binary while program is associated with "
3513 "an active transform feedback object."));
3514 return false;
3515 }
3516
Geoff Langc5629752015-12-07 16:29:04 -05003517 return true;
3518}
3519
3520bool ValidateGetProgramBinaryBase(Context *context,
3521 GLuint program,
3522 GLsizei bufSize,
3523 GLsizei *length,
3524 GLenum *binaryFormat,
3525 void *binary)
3526{
3527 Program *programObject = GetValidProgram(context, program);
3528 if (programObject == nullptr)
3529 {
3530 return false;
3531 }
3532
3533 if (!programObject->isLinked())
3534 {
Jamie Madill437fa652016-05-03 15:13:24 -04003535 context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
Geoff Langc5629752015-12-07 16:29:04 -05003536 return false;
3537 }
3538
Jamie Madilla7d12dc2016-12-13 15:08:19 -05003539 if (context->getCaps().programBinaryFormats.empty())
3540 {
3541 context->handleError(Error(GL_INVALID_OPERATION, "No program binary formats supported."));
3542 return false;
3543 }
3544
Geoff Langc5629752015-12-07 16:29:04 -05003545 return true;
3546}
Jamie Madillc29968b2016-01-20 11:17:23 -05003547
Jamie Madillc29968b2016-01-20 11:17:23 -05003548bool ValidateDrawBuffersBase(ValidationContext *context, GLsizei n, const GLenum *bufs)
3549{
3550 // INVALID_VALUE is generated if n is negative or greater than value of MAX_DRAW_BUFFERS
3551 if (n < 0 || static_cast<GLuint>(n) > context->getCaps().maxDrawBuffers)
3552 {
Jamie Madill437fa652016-05-03 15:13:24 -04003553 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003554 Error(GL_INVALID_VALUE, "n must be non-negative and no greater than MAX_DRAW_BUFFERS"));
3555 return false;
3556 }
3557
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003558 ASSERT(context->getGLState().getDrawFramebuffer());
3559 GLuint frameBufferId = context->getGLState().getDrawFramebuffer()->id();
Jamie Madillc29968b2016-01-20 11:17:23 -05003560 GLuint maxColorAttachment = GL_COLOR_ATTACHMENT0_EXT + context->getCaps().maxColorAttachments;
3561
3562 // This should come first before the check for the default frame buffer
3563 // because when we switch to ES3.1+, invalid enums will return INVALID_ENUM
3564 // rather than INVALID_OPERATION
3565 for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
3566 {
3567 const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
3568
3569 if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != GL_BACK &&
Olli Etuaho84c9f592016-03-09 14:37:25 +02003570 (bufs[colorAttachment] < GL_COLOR_ATTACHMENT0 ||
3571 bufs[colorAttachment] > GL_COLOR_ATTACHMENT31))
Jamie Madillc29968b2016-01-20 11:17:23 -05003572 {
3573 // Value in bufs is not NONE, BACK, or GL_COLOR_ATTACHMENTi
Olli Etuaho84c9f592016-03-09 14:37:25 +02003574 // The 3.0.4 spec says to generate GL_INVALID_OPERATION here, but this
3575 // was changed to GL_INVALID_ENUM in 3.1, which dEQP also expects.
3576 // 3.1 is still a bit ambiguous about the error, but future specs are
3577 // expected to clarify that GL_INVALID_ENUM is the correct error.
Jamie Madill437fa652016-05-03 15:13:24 -04003578 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer value"));
Olli Etuaho84c9f592016-03-09 14:37:25 +02003579 return false;
3580 }
3581 else if (bufs[colorAttachment] >= maxColorAttachment)
3582 {
Jamie Madill437fa652016-05-03 15:13:24 -04003583 context->handleError(
Olli Etuaho84c9f592016-03-09 14:37:25 +02003584 Error(GL_INVALID_OPERATION, "Buffer value is greater than MAX_DRAW_BUFFERS"));
Jamie Madillc29968b2016-01-20 11:17:23 -05003585 return false;
3586 }
3587 else if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment &&
3588 frameBufferId != 0)
3589 {
3590 // INVALID_OPERATION-GL is bound to buffer and ith argument
3591 // is not COLOR_ATTACHMENTi or NONE
Jamie Madill437fa652016-05-03 15:13:24 -04003592 context->handleError(
Jamie Madillc29968b2016-01-20 11:17:23 -05003593 Error(GL_INVALID_OPERATION, "Ith value does not match COLOR_ATTACHMENTi or NONE"));
3594 return false;
3595 }
3596 }
3597
3598 // INVALID_OPERATION is generated if GL is bound to the default framebuffer
3599 // and n is not 1 or bufs is bound to value other than BACK and NONE
3600 if (frameBufferId == 0)
3601 {
3602 if (n != 1)
3603 {
Jamie Madill437fa652016-05-03 15:13:24 -04003604 context->handleError(Error(GL_INVALID_OPERATION,
Jamie Madillc29968b2016-01-20 11:17:23 -05003605 "n must be 1 when GL is bound to the default framebuffer"));
3606 return false;
3607 }
3608
3609 if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
3610 {
Jamie Madill437fa652016-05-03 15:13:24 -04003611 context->handleError(Error(
Jamie Madillc29968b2016-01-20 11:17:23 -05003612 GL_INVALID_OPERATION,
3613 "Only NONE or BACK are valid values when drawing to the default framebuffer"));
3614 return false;
3615 }
3616 }
3617
3618 return true;
3619}
3620
Geoff Lang496c02d2016-10-20 11:38:11 -07003621bool ValidateGetBufferPointervBase(Context *context,
3622 GLenum target,
3623 GLenum pname,
3624 GLsizei *length,
3625 void **params)
Olli Etuaho4f667482016-03-30 15:56:35 +03003626{
Geoff Lang496c02d2016-10-20 11:38:11 -07003627 if (length)
3628 {
3629 *length = 0;
3630 }
3631
3632 if (context->getClientMajorVersion() < 3 && !context->getExtensions().mapBuffer)
3633 {
3634 context->handleError(
3635 Error(GL_INVALID_OPERATION,
Jamie Madillcc6ac252017-01-25 12:57:21 -08003636 "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
Geoff Lang496c02d2016-10-20 11:38:11 -07003637 return false;
3638 }
3639
Olli Etuaho4f667482016-03-30 15:56:35 +03003640 if (!ValidBufferTarget(context, target))
3641 {
Jamie Madill437fa652016-05-03 15:13:24 -04003642 context->handleError(Error(GL_INVALID_ENUM, "Buffer target not valid: 0x%X", target));
Olli Etuaho4f667482016-03-30 15:56:35 +03003643 return false;
3644 }
3645
Geoff Lang496c02d2016-10-20 11:38:11 -07003646 switch (pname)
Olli Etuaho4f667482016-03-30 15:56:35 +03003647 {
Geoff Lang496c02d2016-10-20 11:38:11 -07003648 case GL_BUFFER_MAP_POINTER:
3649 break;
Olli Etuaho4f667482016-03-30 15:56:35 +03003650
Geoff Lang496c02d2016-10-20 11:38:11 -07003651 default:
3652 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
3653 return false;
3654 }
Olli Etuaho4f667482016-03-30 15:56:35 +03003655
3656 // GLES 3.0 section 2.10.1: "Attempts to attempts to modify or query buffer object state for a
3657 // target bound to zero generate an INVALID_OPERATION error."
3658 // GLES 3.1 section 6.6 explicitly specifies this error.
Geoff Lang496c02d2016-10-20 11:38:11 -07003659 if (context->getGLState().getTargetBuffer(target) == nullptr)
Olli Etuaho4f667482016-03-30 15:56:35 +03003660 {
Jamie Madill437fa652016-05-03 15:13:24 -04003661 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003662 Error(GL_INVALID_OPERATION, "Can not get pointer for reserved buffer name zero."));
3663 return false;
3664 }
3665
Geoff Lang496c02d2016-10-20 11:38:11 -07003666 if (length)
3667 {
3668 *length = 1;
3669 }
3670
Olli Etuaho4f667482016-03-30 15:56:35 +03003671 return true;
3672}
3673
3674bool ValidateUnmapBufferBase(Context *context, GLenum target)
3675{
3676 if (!ValidBufferTarget(context, target))
3677 {
Jamie Madill437fa652016-05-03 15:13:24 -04003678 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003679 return false;
3680 }
3681
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003682 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003683
3684 if (buffer == nullptr || !buffer->isMapped())
3685 {
Jamie Madill437fa652016-05-03 15:13:24 -04003686 context->handleError(Error(GL_INVALID_OPERATION, "Buffer not mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003687 return false;
3688 }
3689
3690 return true;
3691}
3692
3693bool ValidateMapBufferRangeBase(Context *context,
3694 GLenum target,
3695 GLintptr offset,
3696 GLsizeiptr length,
3697 GLbitfield access)
3698{
3699 if (!ValidBufferTarget(context, target))
3700 {
Jamie Madill437fa652016-05-03 15:13:24 -04003701 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003702 return false;
3703 }
3704
3705 if (offset < 0 || length < 0)
3706 {
Jamie Madill437fa652016-05-03 15:13:24 -04003707 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset or length."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003708 return false;
3709 }
3710
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003711 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003712
3713 if (!buffer)
3714 {
Jamie Madill437fa652016-05-03 15:13:24 -04003715 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to map buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003716 return false;
3717 }
3718
3719 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003720 CheckedNumeric<size_t> checkedOffset(offset);
3721 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003722
Jamie Madille2e406c2016-06-02 13:04:10 -04003723 if (!checkedSize.IsValid() || checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getSize()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003724 {
Jamie Madill437fa652016-05-03 15:13:24 -04003725 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003726 Error(GL_INVALID_VALUE, "Mapped range does not fit into buffer dimensions."));
3727 return false;
3728 }
3729
3730 // Check for invalid bits in the mask
3731 GLbitfield allAccessBits = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
3732 GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT |
3733 GL_MAP_UNSYNCHRONIZED_BIT;
3734
3735 if (access & ~(allAccessBits))
3736 {
Jamie Madill437fa652016-05-03 15:13:24 -04003737 context->handleError(Error(GL_INVALID_VALUE, "Invalid access bits: 0x%X.", access));
Olli Etuaho4f667482016-03-30 15:56:35 +03003738 return false;
3739 }
3740
3741 if (length == 0)
3742 {
Jamie Madill437fa652016-05-03 15:13:24 -04003743 context->handleError(Error(GL_INVALID_OPERATION, "Buffer mapping length is zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003744 return false;
3745 }
3746
3747 if (buffer->isMapped())
3748 {
Jamie Madill437fa652016-05-03 15:13:24 -04003749 context->handleError(Error(GL_INVALID_OPERATION, "Buffer is already mapped."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003750 return false;
3751 }
3752
3753 // Check for invalid bit combinations
3754 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0)
3755 {
Jamie Madill437fa652016-05-03 15:13:24 -04003756 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003757 Error(GL_INVALID_OPERATION, "Need to map buffer for either reading or writing."));
3758 return false;
3759 }
3760
3761 GLbitfield writeOnlyBits =
3762 GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
3763
3764 if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0)
3765 {
Jamie Madill437fa652016-05-03 15:13:24 -04003766 context->handleError(Error(GL_INVALID_OPERATION,
Olli Etuaho4f667482016-03-30 15:56:35 +03003767 "Invalid access bits when mapping buffer for reading: 0x%X.",
3768 access));
3769 return false;
3770 }
3771
3772 if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0)
3773 {
Jamie Madill437fa652016-05-03 15:13:24 -04003774 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003775 GL_INVALID_OPERATION,
3776 "The explicit flushing bit may only be set if the buffer is mapped for writing."));
3777 return false;
3778 }
3779 return true;
3780}
3781
3782bool ValidateFlushMappedBufferRangeBase(Context *context,
3783 GLenum target,
3784 GLintptr offset,
3785 GLsizeiptr length)
3786{
3787 if (offset < 0 || length < 0)
3788 {
Jamie Madill437fa652016-05-03 15:13:24 -04003789 context->handleError(Error(GL_INVALID_VALUE, "Invalid offset/length parameters."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003790 return false;
3791 }
3792
3793 if (!ValidBufferTarget(context, target))
3794 {
Jamie Madill437fa652016-05-03 15:13:24 -04003795 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003796 return false;
3797 }
3798
Jamie Madilldfde6ab2016-06-09 07:07:18 -07003799 Buffer *buffer = context->getGLState().getTargetBuffer(target);
Olli Etuaho4f667482016-03-30 15:56:35 +03003800
3801 if (buffer == nullptr)
3802 {
Jamie Madill437fa652016-05-03 15:13:24 -04003803 context->handleError(Error(GL_INVALID_OPERATION, "Attempted to flush buffer object zero."));
Olli Etuaho4f667482016-03-30 15:56:35 +03003804 return false;
3805 }
3806
3807 if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0)
3808 {
Jamie Madill437fa652016-05-03 15:13:24 -04003809 context->handleError(Error(
Olli Etuaho4f667482016-03-30 15:56:35 +03003810 GL_INVALID_OPERATION, "Attempted to flush a buffer not mapped for explicit flushing."));
3811 return false;
3812 }
3813
3814 // Check for buffer overflow
Jamie Madille2e406c2016-06-02 13:04:10 -04003815 CheckedNumeric<size_t> checkedOffset(offset);
3816 auto checkedSize = checkedOffset + length;
Olli Etuaho4f667482016-03-30 15:56:35 +03003817
Jamie Madille2e406c2016-06-02 13:04:10 -04003818 if (!checkedSize.IsValid() ||
3819 checkedSize.ValueOrDie() > static_cast<size_t>(buffer->getMapLength()))
Olli Etuaho4f667482016-03-30 15:56:35 +03003820 {
Jamie Madill437fa652016-05-03 15:13:24 -04003821 context->handleError(
Olli Etuaho4f667482016-03-30 15:56:35 +03003822 Error(GL_INVALID_VALUE, "Flushed range does not fit into buffer mapping dimensions."));
3823 return false;
3824 }
3825
3826 return true;
3827}
3828
Olli Etuaho41997e72016-03-10 13:38:39 +02003829bool ValidateGenOrDelete(Context *context, GLint n)
3830{
3831 if (n < 0)
3832 {
Jamie Madill437fa652016-05-03 15:13:24 -04003833 context->handleError(Error(GL_INVALID_VALUE, "n < 0"));
Olli Etuaho41997e72016-03-10 13:38:39 +02003834 return false;
3835 }
3836 return true;
3837}
3838
Geoff Langff5b2d52016-09-07 11:32:23 -04003839bool ValidateRobustEntryPoint(ValidationContext *context, GLsizei bufSize)
3840{
3841 if (!context->getExtensions().robustClientMemory)
3842 {
3843 context->handleError(
3844 Error(GL_INVALID_OPERATION, "GL_ANGLE_robust_client_memory is not available."));
3845 return false;
3846 }
3847
3848 if (bufSize < 0)
3849 {
3850 context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
3851 return false;
3852 }
3853
3854 return true;
3855}
3856
Geoff Lang2e43dbb2016-10-14 12:27:35 -04003857bool ValidateRobustBufferSize(ValidationContext *context, GLsizei bufSize, GLsizei numParams)
3858{
3859 if (bufSize < numParams)
3860 {
3861 context->handleError(Error(GL_INVALID_OPERATION,
3862 "%u parameters are required but %i were provided.", numParams,
3863 bufSize));
3864 return false;
3865 }
3866
3867 return true;
3868}
3869
Jamie Madillbe849e42017-05-02 15:49:00 -04003870bool ValidateGetFramebufferAttachmentParameterivBase(ValidationContext *context,
3871 GLenum target,
3872 GLenum attachment,
3873 GLenum pname,
3874 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04003875{
3876 // Only one parameter is returned from glGetFramebufferAttachmentParameteriv
Yunchao He33151a52017-04-13 09:58:17 +08003877 if (numParams)
3878 {
3879 *numParams = 1;
3880 }
Geoff Langff5b2d52016-09-07 11:32:23 -04003881
3882 if (!ValidFramebufferTarget(target))
3883 {
3884 context->handleError(Error(GL_INVALID_ENUM));
3885 return false;
3886 }
3887
3888 int clientVersion = context->getClientMajorVersion();
3889
3890 switch (pname)
3891 {
3892 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3893 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3894 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3895 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
3896 break;
3897
3898 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
3899 if (clientVersion < 3 && !context->getExtensions().sRGB)
3900 {
3901 context->handleError(Error(GL_INVALID_ENUM));
3902 return false;
3903 }
3904 break;
3905
3906 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
3907 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
3908 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
3909 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
3910 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
3911 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
3912 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
3913 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
3914 if (clientVersion < 3)
3915 {
3916 context->handleError(Error(GL_INVALID_ENUM));
3917 return false;
3918 }
3919 break;
3920
3921 default:
3922 context->handleError(Error(GL_INVALID_ENUM));
3923 return false;
3924 }
3925
3926 // Determine if the attachment is a valid enum
3927 switch (attachment)
3928 {
3929 case GL_BACK:
3930 case GL_FRONT:
3931 case GL_DEPTH:
3932 case GL_STENCIL:
3933 case GL_DEPTH_STENCIL_ATTACHMENT:
3934 if (clientVersion < 3)
3935 {
3936 context->handleError(Error(GL_INVALID_ENUM));
3937 return false;
3938 }
3939 break;
3940
3941 case GL_DEPTH_ATTACHMENT:
3942 case GL_STENCIL_ATTACHMENT:
3943 break;
3944
3945 default:
3946 if (attachment < GL_COLOR_ATTACHMENT0_EXT ||
3947 (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments)
3948 {
3949 context->handleError(Error(GL_INVALID_ENUM));
3950 return false;
3951 }
3952 break;
3953 }
3954
3955 const Framebuffer *framebuffer = context->getGLState().getTargetFramebuffer(target);
3956 ASSERT(framebuffer);
3957
3958 if (framebuffer->id() == 0)
3959 {
3960 if (clientVersion < 3)
3961 {
3962 context->handleError(Error(GL_INVALID_OPERATION));
3963 return false;
3964 }
3965
3966 switch (attachment)
3967 {
3968 case GL_BACK:
3969 case GL_DEPTH:
3970 case GL_STENCIL:
3971 break;
3972
3973 default:
3974 context->handleError(Error(GL_INVALID_OPERATION));
3975 return false;
3976 }
3977 }
3978 else
3979 {
3980 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
3981 {
3982 // Valid attachment query
3983 }
3984 else
3985 {
3986 switch (attachment)
3987 {
3988 case GL_DEPTH_ATTACHMENT:
3989 case GL_STENCIL_ATTACHMENT:
3990 break;
3991
3992 case GL_DEPTH_STENCIL_ATTACHMENT:
3993 if (!framebuffer->hasValidDepthStencil())
3994 {
3995 context->handleError(Error(GL_INVALID_OPERATION));
3996 return false;
3997 }
3998 break;
3999
4000 default:
4001 context->handleError(Error(GL_INVALID_OPERATION));
4002 return false;
4003 }
4004 }
4005 }
4006
4007 const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment);
4008 if (attachmentObject)
4009 {
4010 ASSERT(attachmentObject->type() == GL_RENDERBUFFER ||
4011 attachmentObject->type() == GL_TEXTURE ||
4012 attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT);
4013
4014 switch (pname)
4015 {
4016 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4017 if (attachmentObject->type() != GL_RENDERBUFFER &&
4018 attachmentObject->type() != GL_TEXTURE)
4019 {
4020 context->handleError(Error(GL_INVALID_ENUM));
4021 return false;
4022 }
4023 break;
4024
4025 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
4026 if (attachmentObject->type() != GL_TEXTURE)
4027 {
4028 context->handleError(Error(GL_INVALID_ENUM));
4029 return false;
4030 }
4031 break;
4032
4033 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
4034 if (attachmentObject->type() != GL_TEXTURE)
4035 {
4036 context->handleError(Error(GL_INVALID_ENUM));
4037 return false;
4038 }
4039 break;
4040
4041 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
4042 if (attachment == GL_DEPTH_STENCIL_ATTACHMENT)
4043 {
4044 context->handleError(Error(GL_INVALID_OPERATION));
4045 return false;
4046 }
4047 break;
4048
4049 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
4050 if (attachmentObject->type() != GL_TEXTURE)
4051 {
4052 context->handleError(Error(GL_INVALID_ENUM));
4053 return false;
4054 }
4055 break;
4056
4057 default:
4058 break;
4059 }
4060 }
4061 else
4062 {
4063 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
4064 // is NONE, then querying any other pname will generate INVALID_ENUM.
4065
4066 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
4067 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
4068 // INVALID_OPERATION for all other pnames
4069
4070 switch (pname)
4071 {
4072 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
4073 break;
4074
4075 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
4076 if (clientVersion < 3)
4077 {
4078 context->handleError(Error(GL_INVALID_ENUM));
4079 return false;
4080 }
4081 break;
4082
4083 default:
4084 if (clientVersion < 3)
4085 {
4086 context->handleError(Error(GL_INVALID_ENUM));
4087 return false;
4088 }
4089 else
4090 {
4091 context->handleError(Error(GL_INVALID_OPERATION));
4092 return false;
4093 }
4094 }
4095 }
4096
4097 return true;
4098}
4099
4100bool ValidateGetFramebufferAttachmentParameterivRobustANGLE(ValidationContext *context,
4101 GLenum target,
4102 GLenum attachment,
4103 GLenum pname,
4104 GLsizei bufSize,
4105 GLsizei *numParams)
4106{
4107 if (!ValidateRobustEntryPoint(context, bufSize))
4108 {
4109 return false;
4110 }
4111
Jamie Madillbe849e42017-05-02 15:49:00 -04004112 if (!ValidateGetFramebufferAttachmentParameterivBase(context, target, attachment, pname,
4113 numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004114 {
4115 return false;
4116 }
4117
4118 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4119 {
4120 return false;
4121 }
4122
4123 return true;
4124}
4125
Geoff Langff5b2d52016-09-07 11:32:23 -04004126bool ValidateGetBufferParameterivRobustANGLE(ValidationContext *context,
4127 GLenum target,
4128 GLenum pname,
4129 GLsizei bufSize,
Geoff Langebebe1c2016-10-14 12:01:31 -04004130 GLsizei *length,
4131 GLint *params)
Geoff Langff5b2d52016-09-07 11:32:23 -04004132{
4133 if (!ValidateRobustEntryPoint(context, bufSize))
4134 {
4135 return false;
4136 }
4137
Geoff Langebebe1c2016-10-14 12:01:31 -04004138 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004139 {
4140 return false;
4141 }
4142
Geoff Langebebe1c2016-10-14 12:01:31 -04004143 if (!ValidateRobustBufferSize(context, bufSize, *length))
4144 {
4145 return false;
4146 }
4147
4148 return true;
4149}
4150
4151bool ValidateGetBufferParameteri64v(ValidationContext *context,
4152 GLenum target,
4153 GLenum pname,
4154 GLint64 *params)
4155{
4156 return ValidateGetBufferParameterBase(context, target, pname, false, nullptr);
4157}
4158
4159bool ValidateGetBufferParameteri64vRobustANGLE(ValidationContext *context,
4160 GLenum target,
4161 GLenum pname,
4162 GLsizei bufSize,
4163 GLsizei *length,
4164 GLint64 *params)
4165{
4166 if (!ValidateRobustEntryPoint(context, bufSize))
4167 {
4168 return false;
4169 }
4170
4171 if (!ValidateGetBufferParameterBase(context, target, pname, false, length))
4172 {
4173 return false;
4174 }
4175
4176 if (!ValidateRobustBufferSize(context, bufSize, *length))
Geoff Langff5b2d52016-09-07 11:32:23 -04004177 {
4178 return false;
4179 }
4180
4181 return true;
4182}
4183
Jamie Madillbe849e42017-05-02 15:49:00 -04004184bool ValidateGetProgramivBase(ValidationContext *context,
4185 GLuint program,
4186 GLenum pname,
4187 GLsizei *numParams)
Geoff Langff5b2d52016-09-07 11:32:23 -04004188{
4189 // Currently, all GetProgramiv queries return 1 parameter
Yunchao He33151a52017-04-13 09:58:17 +08004190 if (numParams)
4191 {
4192 *numParams = 1;
4193 }
Geoff Langff5b2d52016-09-07 11:32:23 -04004194
4195 Program *programObject = GetValidProgram(context, program);
4196 if (!programObject)
4197 {
4198 return false;
4199 }
4200
4201 switch (pname)
4202 {
4203 case GL_DELETE_STATUS:
4204 case GL_LINK_STATUS:
4205 case GL_VALIDATE_STATUS:
4206 case GL_INFO_LOG_LENGTH:
4207 case GL_ATTACHED_SHADERS:
4208 case GL_ACTIVE_ATTRIBUTES:
4209 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
4210 case GL_ACTIVE_UNIFORMS:
4211 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
4212 break;
4213
4214 case GL_PROGRAM_BINARY_LENGTH:
4215 if (context->getClientMajorVersion() < 3 && !context->getExtensions().getProgramBinary)
4216 {
4217 context->handleError(Error(GL_INVALID_ENUM,
4218 "Querying GL_PROGRAM_BINARY_LENGTH requires "
4219 "GL_OES_get_program_binary or ES 3.0."));
4220 return false;
4221 }
4222 break;
4223
4224 case GL_ACTIVE_UNIFORM_BLOCKS:
4225 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
4226 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
4227 case GL_TRANSFORM_FEEDBACK_VARYINGS:
4228 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
4229 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
4230 if (context->getClientMajorVersion() < 3)
4231 {
4232 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.0."));
4233 return false;
4234 }
4235 break;
4236
Yunchao He61afff12017-03-14 15:34:03 +08004237 case GL_PROGRAM_SEPARABLE:
4238 if (context->getClientVersion() < Version(3, 1))
4239 {
4240 context->handleError(Error(GL_INVALID_ENUM, "Querying requires at least ES 3.1."));
4241 return false;
4242 }
4243 break;
4244
Geoff Langff5b2d52016-09-07 11:32:23 -04004245 default:
4246 context->handleError(Error(GL_INVALID_ENUM, "Unknown parameter name."));
4247 return false;
4248 }
4249
4250 return true;
4251}
4252
4253bool ValidateGetProgramivRobustANGLE(Context *context,
4254 GLuint program,
4255 GLenum pname,
4256 GLsizei bufSize,
4257 GLsizei *numParams)
4258{
4259 if (!ValidateRobustEntryPoint(context, bufSize))
4260 {
4261 return false;
4262 }
4263
Jamie Madillbe849e42017-05-02 15:49:00 -04004264 if (!ValidateGetProgramivBase(context, program, pname, numParams))
Geoff Langff5b2d52016-09-07 11:32:23 -04004265 {
4266 return false;
4267 }
4268
4269 if (!ValidateRobustBufferSize(context, bufSize, *numParams))
4270 {
4271 return false;
4272 }
4273
4274 return true;
4275}
4276
Geoff Lang740d9022016-10-07 11:20:52 -04004277bool ValidateGetRenderbufferParameterivRobustANGLE(Context *context,
4278 GLenum target,
4279 GLenum pname,
4280 GLsizei bufSize,
4281 GLsizei *length,
4282 GLint *params)
4283{
4284 if (!ValidateRobustEntryPoint(context, bufSize))
4285 {
4286 return false;
4287 }
4288
4289 if (!ValidateGetRenderbufferParameterivBase(context, target, pname, length))
4290 {
4291 return false;
4292 }
4293
4294 if (!ValidateRobustBufferSize(context, bufSize, *length))
4295 {
4296 return false;
4297 }
4298
4299 return true;
4300}
4301
Geoff Langd7d0ed32016-10-07 11:33:51 -04004302bool ValidateGetShaderivRobustANGLE(Context *context,
4303 GLuint shader,
4304 GLenum pname,
4305 GLsizei bufSize,
4306 GLsizei *length,
4307 GLint *params)
4308{
4309 if (!ValidateRobustEntryPoint(context, bufSize))
4310 {
4311 return false;
4312 }
4313
4314 if (!ValidateGetShaderivBase(context, shader, pname, length))
4315 {
4316 return false;
4317 }
4318
4319 if (!ValidateRobustBufferSize(context, bufSize, *length))
4320 {
4321 return false;
4322 }
4323
4324 return true;
4325}
4326
Geoff Langc1984ed2016-10-07 12:41:00 -04004327bool ValidateGetTexParameterfvRobustANGLE(Context *context,
4328 GLenum target,
4329 GLenum pname,
4330 GLsizei bufSize,
4331 GLsizei *length,
4332 GLfloat *params)
4333{
4334 if (!ValidateRobustEntryPoint(context, bufSize))
4335 {
4336 return false;
4337 }
4338
4339 if (!ValidateGetTexParameterBase(context, target, pname, length))
4340 {
4341 return false;
4342 }
4343
4344 if (!ValidateRobustBufferSize(context, bufSize, *length))
4345 {
4346 return false;
4347 }
4348
4349 return true;
4350}
4351
Geoff Langc1984ed2016-10-07 12:41:00 -04004352bool ValidateGetTexParameterivRobustANGLE(Context *context,
4353 GLenum target,
4354 GLenum pname,
4355 GLsizei bufSize,
4356 GLsizei *length,
4357 GLint *params)
4358{
4359 if (!ValidateRobustEntryPoint(context, bufSize))
4360 {
4361 return false;
4362 }
4363
4364 if (!ValidateGetTexParameterBase(context, target, pname, length))
4365 {
4366 return false;
4367 }
4368
4369 if (!ValidateRobustBufferSize(context, bufSize, *length))
4370 {
4371 return false;
4372 }
4373
4374 return true;
4375}
4376
Geoff Langc1984ed2016-10-07 12:41:00 -04004377bool ValidateTexParameterfvRobustANGLE(Context *context,
4378 GLenum target,
4379 GLenum pname,
4380 GLsizei bufSize,
4381 const GLfloat *params)
4382{
4383 if (!ValidateRobustEntryPoint(context, bufSize))
4384 {
4385 return false;
4386 }
4387
4388 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4389}
4390
Geoff Langc1984ed2016-10-07 12:41:00 -04004391bool ValidateTexParameterivRobustANGLE(Context *context,
4392 GLenum target,
4393 GLenum pname,
4394 GLsizei bufSize,
4395 const GLint *params)
4396{
4397 if (!ValidateRobustEntryPoint(context, bufSize))
4398 {
4399 return false;
4400 }
4401
4402 return ValidateTexParameterBase(context, target, pname, bufSize, params);
4403}
4404
4405bool ValidateGetSamplerParameterfv(Context *context, GLuint sampler, GLenum pname, GLfloat *params)
4406{
4407 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4408}
4409
4410bool ValidateGetSamplerParameterfvRobustANGLE(Context *context,
4411 GLuint sampler,
4412 GLenum pname,
4413 GLuint bufSize,
4414 GLsizei *length,
4415 GLfloat *params)
4416{
4417 if (!ValidateRobustEntryPoint(context, bufSize))
4418 {
4419 return false;
4420 }
4421
4422 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4423 {
4424 return false;
4425 }
4426
4427 if (!ValidateRobustBufferSize(context, bufSize, *length))
4428 {
4429 return false;
4430 }
4431
4432 return true;
4433}
4434
4435bool ValidateGetSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, GLint *params)
4436{
4437 return ValidateGetSamplerParameterBase(context, sampler, pname, nullptr);
4438}
4439
4440bool ValidateGetSamplerParameterivRobustANGLE(Context *context,
4441 GLuint sampler,
4442 GLenum pname,
4443 GLuint bufSize,
4444 GLsizei *length,
4445 GLint *params)
4446{
4447 if (!ValidateRobustEntryPoint(context, bufSize))
4448 {
4449 return false;
4450 }
4451
4452 if (!ValidateGetSamplerParameterBase(context, sampler, pname, length))
4453 {
4454 return false;
4455 }
4456
4457 if (!ValidateRobustBufferSize(context, bufSize, *length))
4458 {
4459 return false;
4460 }
4461
4462 return true;
4463}
4464
4465bool ValidateSamplerParameterf(Context *context, GLuint sampler, GLenum pname, GLfloat param)
4466{
4467 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4468}
4469
4470bool ValidateSamplerParameterfv(Context *context,
4471 GLuint sampler,
4472 GLenum pname,
4473 const GLfloat *params)
4474{
4475 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4476}
4477
4478bool ValidateSamplerParameterfvRobustANGLE(Context *context,
4479 GLuint sampler,
4480 GLenum pname,
4481 GLsizei bufSize,
4482 const GLfloat *params)
4483{
4484 if (!ValidateRobustEntryPoint(context, bufSize))
4485 {
4486 return false;
4487 }
4488
4489 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4490}
4491
4492bool ValidateSamplerParameteri(Context *context, GLuint sampler, GLenum pname, GLint param)
4493{
4494 return ValidateSamplerParameterBase(context, sampler, pname, -1, &param);
4495}
4496
4497bool ValidateSamplerParameteriv(Context *context, GLuint sampler, GLenum pname, const GLint *params)
4498{
4499 return ValidateSamplerParameterBase(context, sampler, pname, -1, params);
4500}
4501
4502bool ValidateSamplerParameterivRobustANGLE(Context *context,
4503 GLuint sampler,
4504 GLenum pname,
4505 GLsizei bufSize,
4506 const GLint *params)
4507{
4508 if (!ValidateRobustEntryPoint(context, bufSize))
4509 {
4510 return false;
4511 }
4512
4513 return ValidateSamplerParameterBase(context, sampler, pname, bufSize, params);
4514}
4515
Geoff Lang0b031062016-10-13 14:30:04 -04004516bool ValidateGetVertexAttribfvRobustANGLE(Context *context,
4517 GLuint index,
4518 GLenum pname,
4519 GLsizei bufSize,
4520 GLsizei *length,
4521 GLfloat *params)
4522{
4523 if (!ValidateRobustEntryPoint(context, bufSize))
4524 {
4525 return false;
4526 }
4527
4528 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4529 {
4530 return false;
4531 }
4532
4533 if (!ValidateRobustBufferSize(context, bufSize, *length))
4534 {
4535 return false;
4536 }
4537
4538 return true;
4539}
4540
Geoff Lang0b031062016-10-13 14:30:04 -04004541bool ValidateGetVertexAttribivRobustANGLE(Context *context,
4542 GLuint index,
4543 GLenum pname,
4544 GLsizei bufSize,
4545 GLsizei *length,
4546 GLint *params)
4547{
4548 if (!ValidateRobustEntryPoint(context, bufSize))
4549 {
4550 return false;
4551 }
4552
4553 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, false))
4554 {
4555 return false;
4556 }
4557
4558 if (!ValidateRobustBufferSize(context, bufSize, *length))
4559 {
4560 return false;
4561 }
4562
4563 return true;
4564}
4565
Geoff Lang0b031062016-10-13 14:30:04 -04004566bool ValidateGetVertexAttribPointervRobustANGLE(Context *context,
4567 GLuint index,
4568 GLenum pname,
4569 GLsizei bufSize,
4570 GLsizei *length,
4571 void **pointer)
4572{
4573 if (!ValidateRobustEntryPoint(context, bufSize))
4574 {
4575 return false;
4576 }
4577
4578 if (!ValidateGetVertexAttribBase(context, index, pname, length, true, false))
4579 {
4580 return false;
4581 }
4582
4583 if (!ValidateRobustBufferSize(context, bufSize, *length))
4584 {
4585 return false;
4586 }
4587
4588 return true;
4589}
4590
4591bool ValidateGetVertexAttribIiv(Context *context, GLuint index, GLenum pname, GLint *params)
4592{
4593 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4594}
4595
4596bool ValidateGetVertexAttribIivRobustANGLE(Context *context,
4597 GLuint index,
4598 GLenum pname,
4599 GLsizei bufSize,
4600 GLsizei *length,
4601 GLint *params)
4602{
4603 if (!ValidateRobustEntryPoint(context, bufSize))
4604 {
4605 return false;
4606 }
4607
4608 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4609 {
4610 return false;
4611 }
4612
4613 if (!ValidateRobustBufferSize(context, bufSize, *length))
4614 {
4615 return false;
4616 }
4617
4618 return true;
4619}
4620
4621bool ValidateGetVertexAttribIuiv(Context *context, GLuint index, GLenum pname, GLuint *params)
4622{
4623 return ValidateGetVertexAttribBase(context, index, pname, nullptr, false, true);
4624}
4625
4626bool ValidateGetVertexAttribIuivRobustANGLE(Context *context,
4627 GLuint index,
4628 GLenum pname,
4629 GLsizei bufSize,
4630 GLsizei *length,
4631 GLuint *params)
4632{
4633 if (!ValidateRobustEntryPoint(context, bufSize))
4634 {
4635 return false;
4636 }
4637
4638 if (!ValidateGetVertexAttribBase(context, index, pname, length, false, true))
4639 {
4640 return false;
4641 }
4642
4643 if (!ValidateRobustBufferSize(context, bufSize, *length))
4644 {
4645 return false;
4646 }
4647
4648 return true;
4649}
4650
Geoff Lang6899b872016-10-14 11:30:13 -04004651bool ValidateGetActiveUniformBlockiv(Context *context,
4652 GLuint program,
4653 GLuint uniformBlockIndex,
4654 GLenum pname,
4655 GLint *params)
4656{
4657 return ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, nullptr);
4658}
4659
4660bool ValidateGetActiveUniformBlockivRobustANGLE(Context *context,
4661 GLuint program,
4662 GLuint uniformBlockIndex,
4663 GLenum pname,
4664 GLsizei bufSize,
4665 GLsizei *length,
4666 GLint *params)
4667{
4668 if (!ValidateRobustEntryPoint(context, bufSize))
4669 {
4670 return false;
4671 }
4672
4673 if (!ValidateGetActiveUniformBlockivBase(context, program, uniformBlockIndex, pname, length))
4674 {
4675 return false;
4676 }
4677
4678 if (!ValidateRobustBufferSize(context, bufSize, *length))
4679 {
4680 return false;
4681 }
4682
4683 return true;
4684}
4685
Geoff Lang0a9661f2016-10-20 10:59:20 -07004686bool ValidateGetInternalFormativ(Context *context,
4687 GLenum target,
4688 GLenum internalformat,
4689 GLenum pname,
4690 GLsizei bufSize,
4691 GLint *params)
4692{
4693 return ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize,
4694 nullptr);
4695}
4696
4697bool ValidateGetInternalFormativRobustANGLE(Context *context,
4698 GLenum target,
4699 GLenum internalformat,
4700 GLenum pname,
4701 GLsizei bufSize,
4702 GLsizei *length,
4703 GLint *params)
4704{
4705 if (!ValidateRobustEntryPoint(context, bufSize))
4706 {
4707 return false;
4708 }
4709
4710 if (!ValidateGetInternalFormativBase(context, target, internalformat, pname, bufSize, length))
4711 {
4712 return false;
4713 }
4714
4715 if (!ValidateRobustBufferSize(context, bufSize, *length))
4716 {
4717 return false;
4718 }
4719
4720 return true;
4721}
4722
Shao80957d92017-02-20 21:25:59 +08004723bool ValidateVertexFormatBase(ValidationContext *context,
4724 GLuint attribIndex,
4725 GLint size,
4726 GLenum type,
4727 GLboolean pureInteger)
4728{
4729 const Caps &caps = context->getCaps();
4730 if (attribIndex >= caps.maxVertexAttributes)
4731 {
4732 context->handleError(
4733 Error(GL_INVALID_VALUE, "attribindex must be smaller than MAX_VERTEX_ATTRIBS."));
4734 return false;
4735 }
4736
4737 if (size < 1 || size > 4)
4738 {
4739 context->handleError(Error(GL_INVALID_VALUE, "size must be between one and four."));
4740 }
4741
4742 switch (type)
4743 {
4744 case GL_BYTE:
4745 case GL_UNSIGNED_BYTE:
4746 case GL_SHORT:
4747 case GL_UNSIGNED_SHORT:
4748 break;
4749
4750 case GL_INT:
4751 case GL_UNSIGNED_INT:
4752 if (context->getClientMajorVersion() < 3)
4753 {
4754 context->handleError(
4755 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4756 return false;
4757 }
4758 break;
4759
4760 case GL_FIXED:
4761 case GL_FLOAT:
4762 if (pureInteger)
4763 {
4764 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4765 return false;
4766 }
4767 break;
4768
4769 case GL_HALF_FLOAT:
4770 if (context->getClientMajorVersion() < 3)
4771 {
4772 context->handleError(
4773 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4774 return false;
4775 }
4776 if (pureInteger)
4777 {
4778 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4779 return false;
4780 }
4781 break;
4782
4783 case GL_INT_2_10_10_10_REV:
4784 case GL_UNSIGNED_INT_2_10_10_10_REV:
4785 if (context->getClientMajorVersion() < 3)
4786 {
4787 context->handleError(
4788 Error(GL_INVALID_ENUM, "Vertex type not supported before OpenGL ES 3.0."));
4789 return false;
4790 }
4791 if (pureInteger)
4792 {
4793 context->handleError(Error(GL_INVALID_ENUM, "Type is not integer."));
4794 return false;
4795 }
4796 if (size != 4)
4797 {
4798 context->handleError(Error(GL_INVALID_OPERATION,
4799 "Type is INT_2_10_10_10_REV or "
4800 "UNSIGNED_INT_2_10_10_10_REV and size is not 4."));
4801 return false;
4802 }
4803 break;
4804
4805 default:
4806 context->handleError(Error(GL_INVALID_ENUM, "Invalid vertex type."));
4807 return false;
4808 }
4809
4810 return true;
4811}
4812
Geoff Lang76e65652017-03-27 14:58:02 -04004813// Perform validation from WebGL 2 section 5.10 "Invalid Clears":
4814// In the WebGL 2 API, trying to perform a clear when there is a mismatch between the type of the
4815// specified clear value and the type of a buffer that is being cleared generates an
4816// INVALID_OPERATION error instead of producing undefined results
4817bool ValidateWebGLFramebufferAttachmentClearType(ValidationContext *context,
4818 GLint drawbuffer,
4819 const GLenum *validComponentTypes,
4820 size_t validComponentTypeCount)
4821{
4822 const FramebufferAttachment *attachment =
4823 context->getGLState().getDrawFramebuffer()->getDrawBuffer(drawbuffer);
4824 if (attachment)
4825 {
4826 GLenum componentType = attachment->getFormat().info->componentType;
4827 const GLenum *end = validComponentTypes + validComponentTypeCount;
4828 if (std::find(validComponentTypes, end, componentType) == end)
4829 {
4830 context->handleError(
4831 Error(GL_INVALID_OPERATION,
4832 "No defined conversion between clear value and attachment format."));
4833 return false;
4834 }
4835 }
4836
4837 return true;
4838}
4839
Corentin Wallezb2931602017-04-11 15:58:57 -04004840bool ValidateRobustCompressedTexImageBase(ValidationContext *context,
4841 GLsizei imageSize,
4842 GLsizei dataSize)
4843{
4844 if (!ValidateRobustEntryPoint(context, dataSize))
4845 {
4846 return false;
4847 }
4848
4849 gl::Buffer *pixelUnpackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER);
4850 if (pixelUnpackBuffer == nullptr)
4851 {
4852 if (dataSize < imageSize)
4853 {
4854 context->handleError(
4855 Error(GL_INVALID_OPERATION, "dataSize must be at least %i.", imageSize));
4856 }
4857 }
4858 return true;
4859}
4860
Jamie Madillbe849e42017-05-02 15:49:00 -04004861bool ValidateGetBufferParameterBase(ValidationContext *context,
4862 GLenum target,
4863 GLenum pname,
4864 bool pointerVersion,
4865 GLsizei *numParams)
4866{
4867 if (numParams)
4868 {
4869 *numParams = 0;
4870 }
4871
4872 if (!ValidBufferTarget(context, target))
4873 {
4874 context->handleError(Error(GL_INVALID_ENUM, "Invalid buffer target."));
4875 return false;
4876 }
4877
4878 const Buffer *buffer = context->getGLState().getTargetBuffer(target);
4879 if (!buffer)
4880 {
4881 // A null buffer means that "0" is bound to the requested buffer target
4882 context->handleError(Error(GL_INVALID_OPERATION, "No buffer bound."));
4883 return false;
4884 }
4885
4886 const Extensions &extensions = context->getExtensions();
4887
4888 switch (pname)
4889 {
4890 case GL_BUFFER_USAGE:
4891 case GL_BUFFER_SIZE:
4892 break;
4893
4894 case GL_BUFFER_ACCESS_OES:
4895 if (!extensions.mapBuffer)
4896 {
4897 context->handleError(
4898 Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
4899 return false;
4900 }
4901 break;
4902
4903 case GL_BUFFER_MAPPED:
4904 static_assert(GL_BUFFER_MAPPED == GL_BUFFER_MAPPED_OES, "GL enums should be equal.");
4905 if (context->getClientMajorVersion() < 3 && !extensions.mapBuffer &&
4906 !extensions.mapBufferRange)
4907 {
4908 context->handleError(Error(
4909 GL_INVALID_ENUM,
4910 "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
4911 return false;
4912 }
4913 break;
4914
4915 case GL_BUFFER_MAP_POINTER:
4916 if (!pointerVersion)
4917 {
4918 context->handleError(
4919 Error(GL_INVALID_ENUM,
4920 "GL_BUFFER_MAP_POINTER can only be queried with GetBufferPointerv."));
4921 return false;
4922 }
4923 break;
4924
4925 case GL_BUFFER_ACCESS_FLAGS:
4926 case GL_BUFFER_MAP_OFFSET:
4927 case GL_BUFFER_MAP_LENGTH:
4928 if (context->getClientMajorVersion() < 3 && !extensions.mapBufferRange)
4929 {
4930 context->handleError(Error(
4931 GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_EXT_map_buffer_range."));
4932 return false;
4933 }
4934 break;
4935
4936 default:
4937 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4938 return false;
4939 }
4940
4941 // All buffer parameter queries return one value.
4942 if (numParams)
4943 {
4944 *numParams = 1;
4945 }
4946
4947 return true;
4948}
4949
4950bool ValidateGetRenderbufferParameterivBase(Context *context,
4951 GLenum target,
4952 GLenum pname,
4953 GLsizei *length)
4954{
4955 if (length)
4956 {
4957 *length = 0;
4958 }
4959
4960 if (target != GL_RENDERBUFFER)
4961 {
4962 context->handleError(Error(GL_INVALID_ENUM, "Invalid target."));
4963 return false;
4964 }
4965
4966 Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
4967 if (renderbuffer == nullptr)
4968 {
4969 context->handleError(Error(GL_INVALID_OPERATION, "No renderbuffer bound."));
4970 return false;
4971 }
4972
4973 switch (pname)
4974 {
4975 case GL_RENDERBUFFER_WIDTH:
4976 case GL_RENDERBUFFER_HEIGHT:
4977 case GL_RENDERBUFFER_INTERNAL_FORMAT:
4978 case GL_RENDERBUFFER_RED_SIZE:
4979 case GL_RENDERBUFFER_GREEN_SIZE:
4980 case GL_RENDERBUFFER_BLUE_SIZE:
4981 case GL_RENDERBUFFER_ALPHA_SIZE:
4982 case GL_RENDERBUFFER_DEPTH_SIZE:
4983 case GL_RENDERBUFFER_STENCIL_SIZE:
4984 break;
4985
4986 case GL_RENDERBUFFER_SAMPLES_ANGLE:
4987 if (!context->getExtensions().framebufferMultisample)
4988 {
4989 context->handleError(
4990 Error(GL_INVALID_ENUM, "GL_ANGLE_framebuffer_multisample is not enabled."));
4991 return false;
4992 }
4993 break;
4994
4995 default:
4996 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
4997 return false;
4998 }
4999
5000 if (length)
5001 {
5002 *length = 1;
5003 }
5004 return true;
5005}
5006
5007bool ValidateGetShaderivBase(Context *context, GLuint shader, GLenum pname, GLsizei *length)
5008{
5009 if (length)
5010 {
5011 *length = 0;
5012 }
5013
5014 if (GetValidShader(context, shader) == nullptr)
5015 {
5016 return false;
5017 }
5018
5019 switch (pname)
5020 {
5021 case GL_SHADER_TYPE:
5022 case GL_DELETE_STATUS:
5023 case GL_COMPILE_STATUS:
5024 case GL_INFO_LOG_LENGTH:
5025 case GL_SHADER_SOURCE_LENGTH:
5026 break;
5027
5028 case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
5029 if (!context->getExtensions().translatedShaderSource)
5030 {
5031 context->handleError(
5032 Error(GL_INVALID_ENUM, "GL_ANGLE_translated_shader_source is not enabled."));
5033 return false;
5034 }
5035 break;
5036
5037 default:
5038 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5039 return false;
5040 }
5041
5042 if (length)
5043 {
5044 *length = 1;
5045 }
5046 return true;
5047}
5048
5049bool ValidateGetTexParameterBase(Context *context, GLenum target, GLenum pname, GLsizei *length)
5050{
5051 if (length)
5052 {
5053 *length = 0;
5054 }
5055
5056 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5057 {
5058 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
5059 return false;
5060 }
5061
5062 if (context->getTargetTexture(target) == nullptr)
5063 {
5064 // Should only be possible for external textures
5065 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
5066 return false;
5067 }
5068
5069 switch (pname)
5070 {
5071 case GL_TEXTURE_MAG_FILTER:
5072 case GL_TEXTURE_MIN_FILTER:
5073 case GL_TEXTURE_WRAP_S:
5074 case GL_TEXTURE_WRAP_T:
5075 break;
5076
5077 case GL_TEXTURE_USAGE_ANGLE:
5078 if (!context->getExtensions().textureUsage)
5079 {
5080 context->handleError(
5081 Error(GL_INVALID_ENUM, "GL_ANGLE_texture_usage is not enabled."));
5082 return false;
5083 }
5084 break;
5085
5086 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5087 if (!context->getExtensions().textureFilterAnisotropic)
5088 {
5089 context->handleError(
5090 Error(GL_INVALID_ENUM, "GL_EXT_texture_filter_anisotropic is not enabled."));
5091 return false;
5092 }
5093 break;
5094
5095 case GL_TEXTURE_IMMUTABLE_FORMAT:
5096 if (context->getClientMajorVersion() < 3 && !context->getExtensions().textureStorage)
5097 {
5098 context->handleError(
5099 Error(GL_INVALID_ENUM, "GL_EXT_texture_storage is not enabled."));
5100 return false;
5101 }
5102 break;
5103
5104 case GL_TEXTURE_WRAP_R:
5105 case GL_TEXTURE_IMMUTABLE_LEVELS:
5106 case GL_TEXTURE_SWIZZLE_R:
5107 case GL_TEXTURE_SWIZZLE_G:
5108 case GL_TEXTURE_SWIZZLE_B:
5109 case GL_TEXTURE_SWIZZLE_A:
5110 case GL_TEXTURE_BASE_LEVEL:
5111 case GL_TEXTURE_MAX_LEVEL:
5112 case GL_TEXTURE_MIN_LOD:
5113 case GL_TEXTURE_MAX_LOD:
5114 case GL_TEXTURE_COMPARE_MODE:
5115 case GL_TEXTURE_COMPARE_FUNC:
5116 if (context->getClientMajorVersion() < 3)
5117 {
5118 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
5119 return false;
5120 }
5121 break;
5122
5123 case GL_TEXTURE_SRGB_DECODE_EXT:
5124 if (!context->getExtensions().textureSRGBDecode)
5125 {
5126 context->handleError(
5127 Error(GL_INVALID_ENUM, "GL_EXT_texture_sRGB_decode is not enabled."));
5128 return false;
5129 }
5130 break;
5131
5132 default:
5133 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5134 return false;
5135 }
5136
5137 if (length)
5138 {
5139 *length = 1;
5140 }
5141 return true;
5142}
5143
5144bool ValidateGetVertexAttribBase(Context *context,
5145 GLuint index,
5146 GLenum pname,
5147 GLsizei *length,
5148 bool pointer,
5149 bool pureIntegerEntryPoint)
5150{
5151 if (length)
5152 {
5153 *length = 0;
5154 }
5155
5156 if (pureIntegerEntryPoint && context->getClientMajorVersion() < 3)
5157 {
5158 context->handleError(
5159 Error(GL_INVALID_OPERATION, "Context does not support OpenGL ES 3.0."));
5160 return false;
5161 }
5162
5163 if (index >= context->getCaps().maxVertexAttributes)
5164 {
5165 context->handleError(Error(
5166 GL_INVALID_VALUE, "index must be less than the value of GL_MAX_VERTEX_ATTRIBUTES."));
5167 return false;
5168 }
5169
5170 if (pointer)
5171 {
5172 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
5173 {
5174 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5175 return false;
5176 }
5177 }
5178 else
5179 {
5180 switch (pname)
5181 {
5182 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
5183 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
5184 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
5185 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
5186 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
5187 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
5188 case GL_CURRENT_VERTEX_ATTRIB:
5189 break;
5190
5191 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
5192 static_assert(
5193 GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE,
5194 "ANGLE extension enums not equal to GL enums.");
5195 if (context->getClientMajorVersion() < 3 &&
5196 !context->getExtensions().instancedArrays)
5197 {
5198 context->handleError(Error(GL_INVALID_ENUM,
5199 "GL_VERTEX_ATTRIB_ARRAY_DIVISOR requires OpenGL ES "
5200 "3.0 or GL_ANGLE_instanced_arrays."));
5201 return false;
5202 }
5203 break;
5204
5205 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
5206 if (context->getClientMajorVersion() < 3)
5207 {
5208 context->handleError(Error(
5209 GL_INVALID_ENUM, "GL_VERTEX_ATTRIB_ARRAY_INTEGER requires OpenGL ES 3.0."));
5210 return false;
5211 }
5212 break;
5213
5214 case GL_VERTEX_ATTRIB_BINDING:
5215 case GL_VERTEX_ATTRIB_RELATIVE_OFFSET:
5216 if (context->getClientVersion() < ES_3_1)
5217 {
5218 context->handleError(
5219 Error(GL_INVALID_ENUM, "Vertex Attrib Bindings require OpenGL ES 3.1."));
5220 return false;
5221 }
5222 break;
5223
5224 default:
5225 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5226 return false;
5227 }
5228 }
5229
5230 if (length)
5231 {
5232 if (pname == GL_CURRENT_VERTEX_ATTRIB)
5233 {
5234 *length = 4;
5235 }
5236 else
5237 {
5238 *length = 1;
5239 }
5240 }
5241
5242 return true;
5243}
5244
5245bool ValidateReadPixelsBase(ValidationContext *context,
5246 GLint x,
5247 GLint y,
5248 GLsizei width,
5249 GLsizei height,
5250 GLenum format,
5251 GLenum type,
5252 GLsizei bufSize,
5253 GLsizei *length,
5254 GLsizei *columns,
5255 GLsizei *rows,
5256 void *pixels)
5257{
5258 if (length != nullptr)
5259 {
5260 *length = 0;
5261 }
5262 if (rows != nullptr)
5263 {
5264 *rows = 0;
5265 }
5266 if (columns != nullptr)
5267 {
5268 *columns = 0;
5269 }
5270
5271 if (width < 0 || height < 0)
5272 {
5273 context->handleError(Error(GL_INVALID_VALUE, "width and height must be positive"));
5274 return false;
5275 }
5276
5277 auto readFramebuffer = context->getGLState().getReadFramebuffer();
5278
5279 if (readFramebuffer->checkStatus(context) != GL_FRAMEBUFFER_COMPLETE)
5280 {
5281 context->handleError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
5282 return false;
5283 }
5284
5285 if (readFramebuffer->id() != 0 && readFramebuffer->getSamples(context) != 0)
5286 {
5287 context->handleError(Error(GL_INVALID_OPERATION));
5288 return false;
5289 }
5290
5291 const Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
5292 ASSERT(framebuffer);
5293
5294 if (framebuffer->getReadBufferState() == GL_NONE)
5295 {
5296 context->handleError(Error(GL_INVALID_OPERATION, "Read buffer is GL_NONE"));
5297 return false;
5298 }
5299
5300 const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer();
5301 // WebGL 1.0 [Section 6.26] Reading From a Missing Attachment
5302 // In OpenGL ES it is undefined what happens when an operation tries to read from a missing
5303 // attachment and WebGL defines it to be an error. We do the check unconditionnaly as the
5304 // situation is an application error that would lead to a crash in ANGLE.
5305 if (readBuffer == nullptr)
5306 {
5307 context->handleError(Error(GL_INVALID_OPERATION, "Missing read attachment"));
5308 return false;
5309 }
5310
5311 GLenum currentFormat = framebuffer->getImplementationColorReadFormat();
5312 GLenum currentType = framebuffer->getImplementationColorReadType();
5313 GLenum currentComponentType = readBuffer->getFormat().info->componentType;
5314
5315 bool validFormatTypeCombination =
5316 ValidReadPixelsFormatType(context, currentComponentType, format, type);
5317
5318 if (!(currentFormat == format && currentType == type) && !validFormatTypeCombination)
5319 {
5320 context->handleError(Error(GL_INVALID_OPERATION));
5321 return false;
5322 }
5323
5324 // Check for pixel pack buffer related API errors
5325 gl::Buffer *pixelPackBuffer = context->getGLState().getTargetBuffer(GL_PIXEL_PACK_BUFFER);
5326 if (pixelPackBuffer != nullptr && pixelPackBuffer->isMapped())
5327 {
5328 // ...the buffer object's data store is currently mapped.
5329 context->handleError(Error(GL_INVALID_OPERATION, "Pixel pack buffer is mapped."));
5330 return false;
5331 }
5332
5333 // .. the data would be packed to the buffer object such that the memory writes required
5334 // would exceed the data store size.
5335 const InternalFormat &formatInfo = GetInternalFormatInfo(format, type);
5336 const gl::Extents size(width, height, 1);
5337 const auto &pack = context->getGLState().getPackState();
5338
5339 auto endByteOrErr = formatInfo.computePackUnpackEndByte(type, size, pack, false);
5340 if (endByteOrErr.isError())
5341 {
5342 context->handleError(endByteOrErr.getError());
5343 return false;
5344 }
5345
5346 size_t endByte = endByteOrErr.getResult();
5347 if (bufSize >= 0)
5348 {
5349 if (pixelPackBuffer == nullptr && static_cast<size_t>(bufSize) < endByte)
5350 {
5351 context->handleError(
5352 Error(GL_INVALID_OPERATION, "bufSize must be at least %u bytes.", endByte));
5353 return false;
5354 }
5355 }
5356
5357 if (pixelPackBuffer != nullptr)
5358 {
5359 CheckedNumeric<size_t> checkedEndByte(endByte);
5360 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(pixels));
5361 checkedEndByte += checkedOffset;
5362
5363 if (checkedEndByte.ValueOrDie() > static_cast<size_t>(pixelPackBuffer->getSize()))
5364 {
5365 // Overflow past the end of the buffer
5366 context->handleError(
5367 Error(GL_INVALID_OPERATION, "Writes would overflow the pixel pack buffer."));
5368 return false;
5369 }
5370 }
5371
5372 if (pixelPackBuffer == nullptr && length != nullptr)
5373 {
5374 if (endByte > static_cast<size_t>(std::numeric_limits<GLsizei>::max()))
5375 {
5376 context->handleError(
5377 Error(GL_INVALID_OPERATION, "length would overflow GLsizei.", endByte));
5378 return false;
5379 }
5380
5381 *length = static_cast<GLsizei>(endByte);
5382 }
5383
5384 auto getClippedExtent = [](GLint start, GLsizei length, int bufferSize) {
5385 angle::CheckedNumeric<int> clippedExtent(length);
5386 if (start < 0)
5387 {
5388 // "subtract" the area that is less than 0
5389 clippedExtent += start;
5390 }
5391
5392 const int readExtent = start + length;
5393 if (readExtent > bufferSize)
5394 {
5395 // Subtract the region to the right of the read buffer
5396 clippedExtent -= (readExtent - bufferSize);
5397 }
5398
5399 if (!clippedExtent.IsValid())
5400 {
5401 return 0;
5402 }
5403
5404 return std::max(clippedExtent.ValueOrDie(), 0);
5405 };
5406
5407 if (columns != nullptr)
5408 {
5409 *columns = getClippedExtent(x, width, readBuffer->getSize().width);
5410 }
5411
5412 if (rows != nullptr)
5413 {
5414 *rows = getClippedExtent(y, height, readBuffer->getSize().height);
5415 }
5416
5417 return true;
5418}
5419
5420template <typename ParamType>
5421bool ValidateTexParameterBase(Context *context,
5422 GLenum target,
5423 GLenum pname,
5424 GLsizei bufSize,
5425 const ParamType *params)
5426{
5427 if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target))
5428 {
5429 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
5430 return false;
5431 }
5432
5433 if (context->getTargetTexture(target) == nullptr)
5434 {
5435 // Should only be possible for external textures
5436 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
5437 return false;
5438 }
5439
5440 const GLsizei minBufSize = 1;
5441 if (bufSize >= 0 && bufSize < minBufSize)
5442 {
5443 context->handleError(
5444 Error(GL_INVALID_OPERATION, "bufSize must be at least %i.", minBufSize));
5445 return false;
5446 }
5447
5448 switch (pname)
5449 {
5450 case GL_TEXTURE_WRAP_R:
5451 case GL_TEXTURE_SWIZZLE_R:
5452 case GL_TEXTURE_SWIZZLE_G:
5453 case GL_TEXTURE_SWIZZLE_B:
5454 case GL_TEXTURE_SWIZZLE_A:
5455 case GL_TEXTURE_BASE_LEVEL:
5456 case GL_TEXTURE_MAX_LEVEL:
5457 case GL_TEXTURE_COMPARE_MODE:
5458 case GL_TEXTURE_COMPARE_FUNC:
5459 case GL_TEXTURE_MIN_LOD:
5460 case GL_TEXTURE_MAX_LOD:
5461 if (context->getClientMajorVersion() < 3)
5462 {
5463 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0."));
5464 return false;
5465 }
5466 if (target == GL_TEXTURE_EXTERNAL_OES &&
5467 !context->getExtensions().eglImageExternalEssl3)
5468 {
5469 context->handleError(Error(GL_INVALID_ENUM,
5470 "ES3 texture parameters are not available without "
5471 "GL_OES_EGL_image_external_essl3."));
5472 return false;
5473 }
5474 break;
5475
5476 default:
5477 break;
5478 }
5479
5480 switch (pname)
5481 {
5482 case GL_TEXTURE_WRAP_S:
5483 case GL_TEXTURE_WRAP_T:
5484 case GL_TEXTURE_WRAP_R:
5485 if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5486 {
5487 return false;
5488 }
5489 break;
5490
5491 case GL_TEXTURE_MIN_FILTER:
5492 if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES))
5493 {
5494 return false;
5495 }
5496 break;
5497
5498 case GL_TEXTURE_MAG_FILTER:
5499 if (!ValidateTextureMagFilterValue(context, params))
5500 {
5501 return false;
5502 }
5503 break;
5504
5505 case GL_TEXTURE_USAGE_ANGLE:
5506 switch (ConvertToGLenum(params[0]))
5507 {
5508 case GL_NONE:
5509 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
5510 break;
5511
5512 default:
5513 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5514 return false;
5515 }
5516 break;
5517
5518 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
5519 if (!context->getExtensions().textureFilterAnisotropic)
5520 {
5521 context->handleError(
5522 Error(GL_INVALID_ENUM, "GL_EXT_texture_anisotropic is not enabled."));
5523 return false;
5524 }
5525
5526 // we assume the parameter passed to this validation method is truncated, not rounded
5527 if (params[0] < 1)
5528 {
5529 context->handleError(Error(GL_INVALID_VALUE, "Max anisotropy must be at least 1."));
5530 return false;
5531 }
5532 break;
5533
5534 case GL_TEXTURE_MIN_LOD:
5535 case GL_TEXTURE_MAX_LOD:
5536 // any value is permissible
5537 break;
5538
5539 case GL_TEXTURE_COMPARE_MODE:
5540 if (!ValidateTextureCompareModeValue(context, params))
5541 {
5542 return false;
5543 }
5544 break;
5545
5546 case GL_TEXTURE_COMPARE_FUNC:
5547 if (!ValidateTextureCompareFuncValue(context, params))
5548 {
5549 return false;
5550 }
5551 break;
5552
5553 case GL_TEXTURE_SWIZZLE_R:
5554 case GL_TEXTURE_SWIZZLE_G:
5555 case GL_TEXTURE_SWIZZLE_B:
5556 case GL_TEXTURE_SWIZZLE_A:
5557 switch (ConvertToGLenum(params[0]))
5558 {
5559 case GL_RED:
5560 case GL_GREEN:
5561 case GL_BLUE:
5562 case GL_ALPHA:
5563 case GL_ZERO:
5564 case GL_ONE:
5565 break;
5566
5567 default:
5568 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5569 return false;
5570 }
5571 break;
5572
5573 case GL_TEXTURE_BASE_LEVEL:
5574 if (params[0] < 0)
5575 {
5576 context->handleError(Error(GL_INVALID_VALUE, "Base level must be at least 0."));
5577 return false;
5578 }
5579 if (target == GL_TEXTURE_EXTERNAL_OES && static_cast<GLuint>(params[0]) != 0)
5580 {
5581 context->handleError(
5582 Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures."));
5583 return false;
5584 }
5585 break;
5586
5587 case GL_TEXTURE_MAX_LEVEL:
5588 if (params[0] < 0)
5589 {
5590 context->handleError(Error(GL_INVALID_VALUE, "Max level must be at least 0."));
5591 return false;
5592 }
5593 break;
5594
5595 case GL_DEPTH_STENCIL_TEXTURE_MODE:
5596 if (context->getClientVersion() < Version(3, 1))
5597 {
5598 context->handleError(Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.1."));
5599 return false;
5600 }
5601 switch (ConvertToGLenum(params[0]))
5602 {
5603 case GL_DEPTH_COMPONENT:
5604 case GL_STENCIL_INDEX:
5605 break;
5606
5607 default:
5608 context->handleError(Error(GL_INVALID_ENUM, "Unknown param value."));
5609 return false;
5610 }
5611 break;
5612
5613 case GL_TEXTURE_SRGB_DECODE_EXT:
5614 if (!ValidateTextureSRGBDecodeValue(context, params))
5615 {
5616 return false;
5617 }
5618 break;
5619
5620 default:
5621 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
5622 return false;
5623 }
5624
5625 return true;
5626}
5627
5628template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLfloat *);
5629template bool ValidateTexParameterBase(Context *, GLenum, GLenum, GLsizei, const GLint *);
5630
Jamie Madillc29968b2016-01-20 11:17:23 -05005631} // namespace gl