1//
2// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
3// 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
9#include "libGLESv2/validationES.h"
10#include "libGLESv2/validationES2.h"
11#include "libGLESv2/validationES3.h"
12#include "libGLESv2/Context.h"
13#include "libGLESv2/Texture.h"
14#include "libGLESv2/Framebuffer.h"
15#include "libGLESv2/FramebufferAttachment.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/main.h"
18#include "libGLESv2/Query.h"
19#include "libGLESv2/ProgramBinary.h"
20#include "libGLESv2/TransformFeedback.h"
21#include "libGLESv2/VertexArray.h"
22#include "libGLESv2/renderer/BufferImpl.h"
23
24#include "common/mathutil.h"
25#include "common/utilities.h"
26
27namespace gl
28{
29
30bool ValidCap(const Context *context, GLenum cap)
31{
32    switch (cap)
33    {
34      case GL_CULL_FACE:
35      case GL_POLYGON_OFFSET_FILL:
36      case GL_SAMPLE_ALPHA_TO_COVERAGE:
37      case GL_SAMPLE_COVERAGE:
38      case GL_SCISSOR_TEST:
39      case GL_STENCIL_TEST:
40      case GL_DEPTH_TEST:
41      case GL_BLEND:
42      case GL_DITHER:
43        return true;
44      case GL_PRIMITIVE_RESTART_FIXED_INDEX:
45      case GL_RASTERIZER_DISCARD:
46        return (context->getClientVersion() >= 3);
47      default:
48        return false;
49    }
50}
51
52bool ValidTextureTarget(const Context *context, GLenum target)
53{
54    switch (target)
55    {
56      case GL_TEXTURE_2D:
57      case GL_TEXTURE_CUBE_MAP:
58        return true;
59
60      case GL_TEXTURE_3D:
61      case GL_TEXTURE_2D_ARRAY:
62        return (context->getClientVersion() >= 3);
63
64      default:
65        return false;
66    }
67}
68
69// This function differs from ValidTextureTarget in that the target must be
70// usable as the destination of a 2D operation-- so a cube face is valid, but
71// GL_TEXTURE_CUBE_MAP is not.
72// Note: duplicate of IsInternalTextureTarget
73bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
74{
75    switch (target)
76    {
77      case GL_TEXTURE_2D:
78      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
79      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
80      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
81      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
82      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
83      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
84        return true;
85      case GL_TEXTURE_2D_ARRAY:
86      case GL_TEXTURE_3D:
87        return (context->getClientVersion() >= 3);
88      default:
89        return false;
90    }
91}
92
93bool ValidFramebufferTarget(GLenum target)
94{
95    META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
96
97    switch (target)
98    {
99      case GL_FRAMEBUFFER:      return true;
100      case GL_READ_FRAMEBUFFER: return true;
101      case GL_DRAW_FRAMEBUFFER: return true;
102      default:                  return false;
103    }
104}
105
106bool ValidBufferTarget(const Context *context, GLenum target)
107{
108    switch (target)
109    {
110      case GL_ARRAY_BUFFER:
111      case GL_ELEMENT_ARRAY_BUFFER:
112        return true;
113
114      case GL_PIXEL_PACK_BUFFER:
115      case GL_PIXEL_UNPACK_BUFFER:
116        return context->getExtensions().pixelBufferObject;
117
118      case GL_COPY_READ_BUFFER:
119      case GL_COPY_WRITE_BUFFER:
120      case GL_TRANSFORM_FEEDBACK_BUFFER:
121      case GL_UNIFORM_BUFFER:
122        return (context->getClientVersion() >= 3);
123
124      default:
125        return false;
126    }
127}
128
129bool ValidBufferParameter(const Context *context, GLenum pname)
130{
131    switch (pname)
132    {
133      case GL_BUFFER_USAGE:
134      case GL_BUFFER_SIZE:
135        return true;
136
137      // GL_BUFFER_MAP_POINTER is a special case, and may only be
138      // queried with GetBufferPointerv
139      case GL_BUFFER_ACCESS_FLAGS:
140      case GL_BUFFER_MAPPED:
141      case GL_BUFFER_MAP_OFFSET:
142      case GL_BUFFER_MAP_LENGTH:
143        return (context->getClientVersion() >= 3);
144
145      default:
146        return false;
147    }
148}
149
150bool ValidMipLevel(const Context *context, GLenum target, GLint level)
151{
152    size_t maxDimension = 0;
153    switch (target)
154    {
155      case GL_TEXTURE_2D:                  maxDimension = context->getCaps().max2DTextureSize;       break;
156      case GL_TEXTURE_CUBE_MAP:
157      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
158      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
159      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
160      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
161      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
162      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize;  break;
163      case GL_TEXTURE_3D:                  maxDimension = context->getCaps().max3DTextureSize;       break;
164      case GL_TEXTURE_2D_ARRAY:            maxDimension = context->getCaps().max2DTextureSize;       break;
165      default: UNREACHABLE();
166    }
167
168    return level <= gl::log2(maxDimension);
169}
170
171bool ValidImageSize(const Context *context, GLenum target, GLint level,
172                    GLsizei width, GLsizei height, GLsizei depth)
173{
174    if (level < 0 || width < 0 || height < 0 || depth < 0)
175    {
176        return false;
177    }
178
179    if (!context->getExtensions().textureNPOT &&
180        (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
181    {
182        return false;
183    }
184
185    if (!ValidMipLevel(context, target, level))
186    {
187        return false;
188    }
189
190    return true;
191}
192
193bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
194{
195    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
196    if (!formatInfo.compressed)
197    {
198        return false;
199    }
200
201    if (width  < 0 || (static_cast<GLuint>(width)  > formatInfo.compressedBlockWidth  && width  % formatInfo.compressedBlockWidth != 0) ||
202        height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
203    {
204        return false;
205    }
206
207    return true;
208}
209
210bool ValidQueryType(const Context *context, GLenum queryType)
211{
212    META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
213    META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
214
215    switch (queryType)
216    {
217      case GL_ANY_SAMPLES_PASSED:
218      case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
219        return true;
220      case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
221        return (context->getClientVersion() >= 3);
222      default:
223        return false;
224    }
225}
226
227bool ValidProgram(Context *context, GLuint id)
228{
229    // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
230    // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
231    // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
232
233    if (context->getProgram(id) != NULL)
234    {
235        return true;
236    }
237    else if (context->getShader(id) != NULL)
238    {
239        // ID is the wrong type
240        context->recordError(Error(GL_INVALID_OPERATION));
241        return false;
242    }
243    else
244    {
245        // No shader/program object has this ID
246        context->recordError(Error(GL_INVALID_VALUE));
247        return false;
248    }
249}
250
251bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
252{
253    if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
254    {
255        const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
256
257        if (colorAttachment >= context->getCaps().maxColorAttachments)
258        {
259            context->recordError(Error(GL_INVALID_VALUE));
260            return false;
261        }
262    }
263    else
264    {
265        switch (attachment)
266        {
267          case GL_DEPTH_ATTACHMENT:
268          case GL_STENCIL_ATTACHMENT:
269            break;
270
271          case GL_DEPTH_STENCIL_ATTACHMENT:
272            if (context->getClientVersion() < 3)
273            {
274                context->recordError(Error(GL_INVALID_ENUM));
275                return false;
276            }
277            break;
278
279          default:
280            context->recordError(Error(GL_INVALID_ENUM));
281            return false;
282        }
283    }
284
285    return true;
286}
287
288bool ValidateRenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
289                                           GLenum internalformat, GLsizei width, GLsizei height,
290                                           bool angleExtension)
291{
292    switch (target)
293    {
294      case GL_RENDERBUFFER:
295        break;
296      default:
297        context->recordError(Error(GL_INVALID_ENUM));
298        return false;
299    }
300
301    if (width < 0 || height < 0 || samples < 0)
302    {
303        context->recordError(Error(GL_INVALID_VALUE));
304        return false;
305    }
306
307    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
308    if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
309    {
310        context->recordError(Error(GL_INVALID_ENUM));
311        return false;
312    }
313
314    // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
315    // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
316    // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
317    // internal format must be sized and not an integer format if samples is greater than zero.
318    if (formatInfo.pixelBytes == 0)
319    {
320        context->recordError(Error(GL_INVALID_ENUM));
321        return false;
322    }
323
324    if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
325    {
326        context->recordError(Error(GL_INVALID_OPERATION));
327        return false;
328    }
329
330    const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
331    if (!formatCaps.renderable)
332    {
333        context->recordError(Error(GL_INVALID_ENUM));
334        return false;
335    }
336
337    if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
338    {
339        context->recordError(Error(GL_INVALID_VALUE));
340        return false;
341    }
342
343    // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
344    // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
345    // states that samples must be less than or equal to the maximum samples for the specified
346    // internal format.
347    if (angleExtension)
348    {
349        ASSERT(context->getExtensions().framebufferMultisample);
350        if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
351        {
352            context->recordError(Error(GL_INVALID_VALUE));
353            return false;
354        }
355
356        // Check if this specific format supports enough samples
357        if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
358        {
359            context->recordError(Error(GL_OUT_OF_MEMORY));
360            return false;
361        }
362    }
363    else
364    {
365        if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
366        {
367            context->recordError(Error(GL_INVALID_VALUE));
368            return false;
369        }
370    }
371
372    GLuint handle = context->getState().getRenderbufferId();
373    if (handle == 0)
374    {
375        context->recordError(Error(GL_INVALID_OPERATION));
376        return false;
377    }
378
379    return true;
380}
381
382bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
383                                               GLenum renderbuffertarget, GLuint renderbuffer)
384{
385    if (!ValidFramebufferTarget(target))
386    {
387        context->recordError(Error(GL_INVALID_ENUM));
388        return false;
389    }
390
391    gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
392    GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
393
394    if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
395    {
396        context->recordError(Error(GL_INVALID_OPERATION));
397        return false;
398    }
399
400    if (!ValidateAttachmentTarget(context, attachment))
401    {
402        return false;
403    }
404
405    // [OpenGL ES 2.0.25] Section 4.4.3 page 112
406    // [OpenGL ES 3.0.2] Section 4.4.2 page 201
407    // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
408    // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
409    if (renderbuffer != 0)
410    {
411        if (!context->getRenderbuffer(renderbuffer))
412        {
413            context->recordError(Error(GL_INVALID_OPERATION));
414            return false;
415        }
416    }
417
418    return true;
419}
420
421static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
422                          GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
423                          GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
424{
425    if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
426        dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
427        srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
428    {
429        return true;
430    }
431    else if (context->getState().isScissorTestEnabled())
432    {
433        const Rectangle &scissor = context->getState().getScissor();
434
435        return scissor.x > 0 || scissor.y > 0 ||
436               scissor.width < writeBuffer->getWidth() ||
437               scissor.height < writeBuffer->getHeight();
438    }
439    else
440    {
441        return false;
442    }
443}
444
445bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
446                                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
447                                       GLenum filter, bool fromAngleExtension)
448{
449    switch (filter)
450    {
451      case GL_NEAREST:
452        break;
453      case GL_LINEAR:
454        if (fromAngleExtension)
455        {
456            context->recordError(Error(GL_INVALID_ENUM));
457            return false;
458        }
459        break;
460      default:
461        context->recordError(Error(GL_INVALID_ENUM));
462        return false;
463    }
464
465    if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
466    {
467        context->recordError(Error(GL_INVALID_VALUE));
468        return false;
469    }
470
471    if (mask == 0)
472    {
473        // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
474        // buffers are copied.
475        return false;
476    }
477
478    if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
479    {
480        ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
481        context->recordError(Error(GL_INVALID_OPERATION));
482        return false;
483    }
484
485    // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
486    // color buffer, leaving only nearest being unfiltered from above
487    if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
488    {
489        context->recordError(Error(GL_INVALID_OPERATION));
490        return false;
491    }
492
493    if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
494    {
495        if (fromAngleExtension)
496        {
497            ERR("Blits with the same source and destination framebuffer are not supported by this "
498                "implementation.");
499        }
500        context->recordError(Error(GL_INVALID_OPERATION));
501        return false;
502    }
503
504    gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
505    gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
506    if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
507        !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
508    {
509        context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
510        return false;
511    }
512
513    if (drawFramebuffer->getSamples() != 0)
514    {
515        context->recordError(Error(GL_INVALID_OPERATION));
516        return false;
517    }
518
519    bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
520
521    if (mask & GL_COLOR_BUFFER_BIT)
522    {
523        gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
524        gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
525
526        if (readColorBuffer && drawColorBuffer)
527        {
528            GLenum readInternalFormat = readColorBuffer->getActualFormat();
529            const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
530
531            for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
532            {
533                if (drawFramebuffer->isEnabledColorAttachment(i))
534                {
535                    GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
536                    const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
537
538                    // The GL ES 3.0.2 spec (pg 193) states that:
539                    // 1) If the read buffer is fixed point format, the draw buffer must be as well
540                    // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
541                    // 3) If the read buffer is a signed integer format, the draw buffer must be as well
542                    if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
543                        !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
544                    {
545                        context->recordError(Error(GL_INVALID_OPERATION));
546                        return false;
547                    }
548
549                    if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
550                    {
551                        context->recordError(Error(GL_INVALID_OPERATION));
552                        return false;
553                    }
554
555                    if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
556                    {
557                        context->recordError(Error(GL_INVALID_OPERATION));
558                        return false;
559                    }
560
561                    if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
562                    {
563                        context->recordError(Error(GL_INVALID_OPERATION));
564                        return false;
565                    }
566                }
567            }
568
569            if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
570            {
571                context->recordError(Error(GL_INVALID_OPERATION));
572                return false;
573            }
574
575            if (fromAngleExtension)
576            {
577                const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
578                if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
579                {
580                    context->recordError(Error(GL_INVALID_OPERATION));
581                    return false;
582                }
583
584                for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
585                {
586                    if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
587                    {
588                        FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
589                        ASSERT(attachment);
590
591                        if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
592                        {
593                            context->recordError(Error(GL_INVALID_OPERATION));
594                            return false;
595                        }
596
597                        if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
598                        {
599                            context->recordError(Error(GL_INVALID_OPERATION));
600                            return false;
601                        }
602                    }
603                }
604                if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
605                                                                        srcX0, srcY0, srcX1, srcY1,
606                                                                        dstX0, dstY0, dstX1, dstY1))
607                {
608                    context->recordError(Error(GL_INVALID_OPERATION));
609                    return false;
610                }
611            }
612        }
613    }
614
615    if (mask & GL_DEPTH_BUFFER_BIT)
616    {
617        gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
618        gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
619
620        if (readDepthBuffer && drawDepthBuffer)
621        {
622            if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
623            {
624                context->recordError(Error(GL_INVALID_OPERATION));
625                return false;
626            }
627
628            if (readDepthBuffer->getSamples() > 0 && !sameBounds)
629            {
630                context->recordError(Error(GL_INVALID_OPERATION));
631                return false;
632            }
633
634            if (fromAngleExtension)
635            {
636                if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
637                                  srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
638                {
639                    ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
640                    context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
641                    return false;
642                }
643
644                if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
645                {
646                    context->recordError(Error(GL_INVALID_OPERATION));
647                    return false;
648                }
649            }
650        }
651    }
652
653    if (mask & GL_STENCIL_BUFFER_BIT)
654    {
655        gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
656        gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
657
658        if (readStencilBuffer && drawStencilBuffer)
659        {
660            if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
661            {
662                context->recordError(Error(GL_INVALID_OPERATION));
663                return false;
664            }
665
666            if (readStencilBuffer->getSamples() > 0 && !sameBounds)
667            {
668                context->recordError(Error(GL_INVALID_OPERATION));
669                return false;
670            }
671
672            if (fromAngleExtension)
673            {
674                if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
675                                  srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
676                {
677                    ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
678                    context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
679                    return false;
680                }
681
682                if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
683                {
684                    context->recordError(Error(GL_INVALID_OPERATION));
685                    return false;
686                }
687            }
688        }
689    }
690
691    return true;
692}
693
694bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
695{
696    switch (pname)
697    {
698      case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
699      case GL_VERTEX_ATTRIB_ARRAY_SIZE:
700      case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
701      case GL_VERTEX_ATTRIB_ARRAY_TYPE:
702      case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
703      case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
704      case GL_CURRENT_VERTEX_ATTRIB:
705        return true;
706
707      case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
708        // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
709        // the same constant.
710        META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
711        return true;
712
713      case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
714        if (context->getClientVersion() < 3)
715        {
716            context->recordError(Error(GL_INVALID_ENUM));
717            return false;
718        }
719        return true;
720
721      default:
722        context->recordError(Error(GL_INVALID_ENUM));
723        return false;
724    }
725}
726
727bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
728{
729    switch (pname)
730    {
731      case GL_TEXTURE_WRAP_R:
732      case GL_TEXTURE_SWIZZLE_R:
733      case GL_TEXTURE_SWIZZLE_G:
734      case GL_TEXTURE_SWIZZLE_B:
735      case GL_TEXTURE_SWIZZLE_A:
736      case GL_TEXTURE_BASE_LEVEL:
737      case GL_TEXTURE_MAX_LEVEL:
738      case GL_TEXTURE_COMPARE_MODE:
739      case GL_TEXTURE_COMPARE_FUNC:
740      case GL_TEXTURE_MIN_LOD:
741      case GL_TEXTURE_MAX_LOD:
742        if (context->getClientVersion() < 3)
743        {
744            context->recordError(Error(GL_INVALID_ENUM));
745            return false;
746        }
747        break;
748
749      default: break;
750    }
751
752    switch (pname)
753    {
754      case GL_TEXTURE_WRAP_S:
755      case GL_TEXTURE_WRAP_T:
756      case GL_TEXTURE_WRAP_R:
757        switch (param)
758        {
759          case GL_REPEAT:
760          case GL_CLAMP_TO_EDGE:
761          case GL_MIRRORED_REPEAT:
762            return true;
763          default:
764            context->recordError(Error(GL_INVALID_ENUM));
765            return false;
766        }
767
768      case GL_TEXTURE_MIN_FILTER:
769        switch (param)
770        {
771          case GL_NEAREST:
772          case GL_LINEAR:
773          case GL_NEAREST_MIPMAP_NEAREST:
774          case GL_LINEAR_MIPMAP_NEAREST:
775          case GL_NEAREST_MIPMAP_LINEAR:
776          case GL_LINEAR_MIPMAP_LINEAR:
777            return true;
778          default:
779            context->recordError(Error(GL_INVALID_ENUM));
780            return false;
781        }
782        break;
783
784      case GL_TEXTURE_MAG_FILTER:
785        switch (param)
786        {
787          case GL_NEAREST:
788          case GL_LINEAR:
789            return true;
790          default:
791            context->recordError(Error(GL_INVALID_ENUM));
792            return false;
793        }
794        break;
795
796      case GL_TEXTURE_USAGE_ANGLE:
797        switch (param)
798        {
799          case GL_NONE:
800          case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
801            return true;
802          default:
803            context->recordError(Error(GL_INVALID_ENUM));
804            return false;
805        }
806        break;
807
808      case GL_TEXTURE_MAX_ANISOTROPY_EXT:
809        if (!context->getExtensions().textureFilterAnisotropic)
810        {
811            context->recordError(Error(GL_INVALID_ENUM));
812            return false;
813        }
814
815        // we assume the parameter passed to this validation method is truncated, not rounded
816        if (param < 1)
817        {
818            context->recordError(Error(GL_INVALID_VALUE));
819            return false;
820        }
821        return true;
822
823      case GL_TEXTURE_MIN_LOD:
824      case GL_TEXTURE_MAX_LOD:
825        // any value is permissible
826        return true;
827
828      case GL_TEXTURE_COMPARE_MODE:
829        // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
830        switch (param)
831        {
832          case GL_NONE:
833          case GL_COMPARE_REF_TO_TEXTURE:
834            return true;
835          default:
836            context->recordError(Error(GL_INVALID_ENUM));
837            return false;
838        }
839        break;
840
841      case GL_TEXTURE_COMPARE_FUNC:
842        // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
843        switch (param)
844        {
845          case GL_LEQUAL:
846          case GL_GEQUAL:
847          case GL_LESS:
848          case GL_GREATER:
849          case GL_EQUAL:
850          case GL_NOTEQUAL:
851          case GL_ALWAYS:
852          case GL_NEVER:
853            return true;
854          default:
855            context->recordError(Error(GL_INVALID_ENUM));
856            return false;
857        }
858        break;
859
860      case GL_TEXTURE_SWIZZLE_R:
861      case GL_TEXTURE_SWIZZLE_G:
862      case GL_TEXTURE_SWIZZLE_B:
863      case GL_TEXTURE_SWIZZLE_A:
864        switch (param)
865        {
866          case GL_RED:
867          case GL_GREEN:
868          case GL_BLUE:
869          case GL_ALPHA:
870          case GL_ZERO:
871          case GL_ONE:
872            return true;
873          default:
874            context->recordError(Error(GL_INVALID_ENUM));
875            return false;
876        }
877        break;
878
879      case GL_TEXTURE_BASE_LEVEL:
880      case GL_TEXTURE_MAX_LEVEL:
881        if (param < 0)
882        {
883            context->recordError(Error(GL_INVALID_VALUE));
884            return false;
885        }
886        return true;
887
888      default:
889        context->recordError(Error(GL_INVALID_ENUM));
890        return false;
891    }
892}
893
894bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
895{
896    switch (pname)
897    {
898      case GL_TEXTURE_MIN_FILTER:
899      case GL_TEXTURE_MAG_FILTER:
900      case GL_TEXTURE_WRAP_S:
901      case GL_TEXTURE_WRAP_T:
902      case GL_TEXTURE_WRAP_R:
903      case GL_TEXTURE_MIN_LOD:
904      case GL_TEXTURE_MAX_LOD:
905      case GL_TEXTURE_COMPARE_MODE:
906      case GL_TEXTURE_COMPARE_FUNC:
907        return true;
908
909      default:
910        context->recordError(Error(GL_INVALID_ENUM));
911        return false;
912    }
913}
914
915bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
916                                  GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
917{
918    gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
919    ASSERT(framebuffer);
920
921    if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
922    {
923        context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
924        return false;
925    }
926
927    if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
928    {
929        context->recordError(Error(GL_INVALID_OPERATION));
930        return false;
931    }
932
933    if (!framebuffer->getReadColorbuffer())
934    {
935        context->recordError(Error(GL_INVALID_OPERATION));
936        return false;
937    }
938
939    GLenum currentInternalFormat, currentFormat, currentType;
940    GLuint clientVersion = context->getClientVersion();
941
942    context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
943
944    bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
945                                                 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
946
947    if (!(currentFormat == format && currentType == type) && !validReadFormat)
948    {
949        context->recordError(Error(GL_INVALID_OPERATION));
950        return false;
951    }
952
953    GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
954    const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
955
956    GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
957    // sized query sanity check
958    if (bufSize)
959    {
960        int requiredSize = outputPitch * height;
961        if (requiredSize > *bufSize)
962        {
963            context->recordError(Error(GL_INVALID_OPERATION));
964            return false;
965        }
966    }
967
968    return true;
969}
970
971bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
972{
973    if (!ValidQueryType(context, target))
974    {
975        context->recordError(Error(GL_INVALID_ENUM));
976        return false;
977    }
978
979    if (id == 0)
980    {
981        context->recordError(Error(GL_INVALID_OPERATION));
982        return false;
983    }
984
985    // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
986    // of zero, if the active query object name for <target> is non-zero (for the
987    // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
988    // the active query for either target is non-zero), if <id> is the name of an
989    // existing query object whose type does not match <target>, or if <id> is the
990    // active query object name for any query type, the error INVALID_OPERATION is
991    // generated.
992
993    // Ensure no other queries are active
994    // NOTE: If other queries than occlusion are supported, we will need to check
995    // separately that:
996    //    a) The query ID passed is not the current active query for any target/type
997    //    b) There are no active queries for the requested target (and in the case
998    //       of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
999    //       no query may be active for either if glBeginQuery targets either.
1000    if (context->getState().isQueryActive())
1001    {
1002        context->recordError(Error(GL_INVALID_OPERATION));
1003        return false;
1004    }
1005
1006    Query *queryObject = context->getQuery(id, true, target);
1007
1008    // check that name was obtained with glGenQueries
1009    if (!queryObject)
1010    {
1011        context->recordError(Error(GL_INVALID_OPERATION));
1012        return false;
1013    }
1014
1015    // check for type mismatch
1016    if (queryObject->getType() != target)
1017    {
1018        context->recordError(Error(GL_INVALID_OPERATION));
1019        return false;
1020    }
1021
1022    return true;
1023}
1024
1025bool ValidateEndQuery(gl::Context *context, GLenum target)
1026{
1027    if (!ValidQueryType(context, target))
1028    {
1029        context->recordError(Error(GL_INVALID_ENUM));
1030        return false;
1031    }
1032
1033    const Query *queryObject = context->getState().getActiveQuery(target);
1034
1035    if (queryObject == NULL)
1036    {
1037        context->recordError(Error(GL_INVALID_OPERATION));
1038        return false;
1039    }
1040
1041    return true;
1042}
1043
1044static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1045                                      GLint location, GLsizei count, LinkedUniform **uniformOut)
1046{
1047    if (count < 0)
1048    {
1049        context->recordError(Error(GL_INVALID_VALUE));
1050        return false;
1051    }
1052
1053    gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
1054    if (!programBinary)
1055    {
1056        context->recordError(Error(GL_INVALID_OPERATION));
1057        return false;
1058    }
1059
1060    if (location == -1)
1061    {
1062        // Silently ignore the uniform command
1063        return false;
1064    }
1065
1066    if (!programBinary->isValidUniformLocation(location))
1067    {
1068        context->recordError(Error(GL_INVALID_OPERATION));
1069        return false;
1070    }
1071
1072    LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1073
1074    // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1075    if (uniform->elementCount() == 1 && count > 1)
1076    {
1077        context->recordError(Error(GL_INVALID_OPERATION));
1078        return false;
1079    }
1080
1081    *uniformOut = uniform;
1082    return true;
1083}
1084
1085bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1086{
1087    // Check for ES3 uniform entry points
1088    if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
1089    {
1090        context->recordError(Error(GL_INVALID_OPERATION));
1091        return false;
1092    }
1093
1094    LinkedUniform *uniform = NULL;
1095    if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1096    {
1097        return false;
1098    }
1099
1100    GLenum targetBoolType = VariableBoolVectorType(uniformType);
1101    bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1102    if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1103    {
1104        context->recordError(Error(GL_INVALID_OPERATION));
1105        return false;
1106    }
1107
1108    return true;
1109}
1110
1111bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1112                           GLboolean transpose)
1113{
1114    // Check for ES3 uniform entry points
1115    int rows = VariableRowCount(matrixType);
1116    int cols = VariableColumnCount(matrixType);
1117    if (rows != cols && context->getClientVersion() < 3)
1118    {
1119        context->recordError(Error(GL_INVALID_OPERATION));
1120        return false;
1121    }
1122
1123    if (transpose != GL_FALSE && context->getClientVersion() < 3)
1124    {
1125        context->recordError(Error(GL_INVALID_VALUE));
1126        return false;
1127    }
1128
1129    LinkedUniform *uniform = NULL;
1130    if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1131    {
1132        return false;
1133    }
1134
1135    if (uniform->type != matrixType)
1136    {
1137        context->recordError(Error(GL_INVALID_OPERATION));
1138        return false;
1139    }
1140
1141    return true;
1142}
1143
1144bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1145{
1146    if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1147    {
1148        context->recordError(Error(GL_INVALID_ENUM));
1149        return false;
1150    }
1151
1152    if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1153    {
1154        unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1155
1156        if (colorAttachment >= context->getCaps().maxDrawBuffers)
1157        {
1158            context->recordError(Error(GL_INVALID_OPERATION));
1159            return false;
1160        }
1161    }
1162
1163    switch (pname)
1164    {
1165      case GL_TEXTURE_BINDING_2D:
1166      case GL_TEXTURE_BINDING_CUBE_MAP:
1167      case GL_TEXTURE_BINDING_3D:
1168      case GL_TEXTURE_BINDING_2D_ARRAY:
1169        if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
1170        {
1171            context->recordError(Error(GL_INVALID_OPERATION));
1172            return false;
1173        }
1174        break;
1175
1176      case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1177      case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1178        {
1179            Framebuffer *framebuffer = context->getState().getReadFramebuffer();
1180            ASSERT(framebuffer);
1181            if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1182            {
1183                context->recordError(Error(GL_INVALID_OPERATION));
1184                return false;
1185            }
1186
1187            FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1188            if (!attachment)
1189            {
1190                context->recordError(Error(GL_INVALID_OPERATION));
1191                return false;
1192            }
1193        }
1194        break;
1195
1196      default:
1197        break;
1198    }
1199
1200    // pname is valid, but there are no parameters to return
1201    if (numParams == 0)
1202    {
1203        return false;
1204    }
1205
1206    return true;
1207}
1208
1209bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1210                                        GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1211                                        GLint border, GLenum *textureFormatOut)
1212{
1213
1214    if (!ValidTexture2DDestinationTarget(context, target))
1215    {
1216        context->recordError(Error(GL_INVALID_ENUM));
1217        return false;
1218    }
1219
1220    if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1221    {
1222        context->recordError(Error(GL_INVALID_VALUE));
1223        return false;
1224    }
1225
1226    if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1227    {
1228        context->recordError(Error(GL_INVALID_VALUE));
1229        return false;
1230    }
1231
1232    if (border != 0)
1233    {
1234        context->recordError(Error(GL_INVALID_VALUE));
1235        return false;
1236    }
1237
1238    if (!ValidMipLevel(context, target, level))
1239    {
1240        context->recordError(Error(GL_INVALID_VALUE));
1241        return false;
1242    }
1243
1244    gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
1245    if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1246    {
1247        context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1248        return false;
1249    }
1250
1251    if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
1252    {
1253        context->recordError(Error(GL_INVALID_OPERATION));
1254        return false;
1255    }
1256
1257    const gl::Caps &caps = context->getCaps();
1258
1259    gl::Texture *texture = NULL;
1260    GLenum textureInternalFormat = GL_NONE;
1261    GLint textureLevelWidth = 0;
1262    GLint textureLevelHeight = 0;
1263    GLint textureLevelDepth = 0;
1264    GLuint maxDimension = 0;
1265
1266    switch (target)
1267    {
1268      case GL_TEXTURE_2D:
1269        {
1270            gl::Texture2D *texture2d = context->getTexture2D();
1271            if (texture2d)
1272            {
1273                textureInternalFormat = texture2d->getInternalFormat(level);
1274                textureLevelWidth = texture2d->getWidth(level);
1275                textureLevelHeight = texture2d->getHeight(level);
1276                textureLevelDepth = 1;
1277                texture = texture2d;
1278                maxDimension = caps.max2DTextureSize;
1279            }
1280        }
1281        break;
1282
1283      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1284      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1285      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1286      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1287      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1288      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1289        {
1290            gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1291            if (textureCube)
1292            {
1293                textureInternalFormat = textureCube->getInternalFormat(target, level);
1294                textureLevelWidth = textureCube->getWidth(target, level);
1295                textureLevelHeight = textureCube->getHeight(target, level);
1296                textureLevelDepth = 1;
1297                texture = textureCube;
1298                maxDimension = caps.maxCubeMapTextureSize;
1299            }
1300        }
1301        break;
1302
1303      case GL_TEXTURE_2D_ARRAY:
1304        {
1305            gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1306            if (texture2dArray)
1307            {
1308                textureInternalFormat = texture2dArray->getInternalFormat(level);
1309                textureLevelWidth = texture2dArray->getWidth(level);
1310                textureLevelHeight = texture2dArray->getHeight(level);
1311                textureLevelDepth = texture2dArray->getLayers(level);
1312                texture = texture2dArray;
1313                maxDimension = caps.max2DTextureSize;
1314            }
1315        }
1316        break;
1317
1318      case GL_TEXTURE_3D:
1319        {
1320            gl::Texture3D *texture3d = context->getTexture3D();
1321            if (texture3d)
1322            {
1323                textureInternalFormat = texture3d->getInternalFormat(level);
1324                textureLevelWidth = texture3d->getWidth(level);
1325                textureLevelHeight = texture3d->getHeight(level);
1326                textureLevelDepth = texture3d->getDepth(level);
1327                texture = texture3d;
1328                maxDimension = caps.max3DTextureSize;
1329            }
1330        }
1331        break;
1332
1333      default:
1334        context->recordError(Error(GL_INVALID_ENUM));
1335        return false;
1336    }
1337
1338    if (!texture)
1339    {
1340        context->recordError(Error(GL_INVALID_OPERATION));
1341        return false;
1342    }
1343
1344    if (texture->isImmutable() && !isSubImage)
1345    {
1346        context->recordError(Error(GL_INVALID_OPERATION));
1347        return false;
1348    }
1349
1350    const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1351
1352    if (formatInfo.depthBits > 0)
1353    {
1354        context->recordError(Error(GL_INVALID_OPERATION));
1355        return false;
1356    }
1357
1358    if (formatInfo.compressed)
1359    {
1360        if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1361            ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
1362        {
1363            context->recordError(Error(GL_INVALID_OPERATION));
1364            return false;
1365        }
1366    }
1367
1368    if (isSubImage)
1369    {
1370        if (xoffset + width > textureLevelWidth ||
1371            yoffset + height > textureLevelHeight ||
1372            zoffset >= textureLevelDepth)
1373        {
1374            context->recordError(Error(GL_INVALID_VALUE));
1375            return false;
1376        }
1377    }
1378    else
1379    {
1380        if (IsCubemapTextureTarget(target) && width != height)
1381        {
1382            context->recordError(Error(GL_INVALID_VALUE));
1383            return false;
1384        }
1385
1386        if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
1387        {
1388            context->recordError(Error(GL_INVALID_ENUM));
1389            return false;
1390        }
1391
1392        int maxLevelDimension = (maxDimension >> level);
1393        if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1394        {
1395            context->recordError(Error(GL_INVALID_VALUE));
1396            return false;
1397        }
1398    }
1399
1400    *textureFormatOut = textureInternalFormat;
1401    return true;
1402}
1403
1404static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
1405{
1406    switch (mode)
1407    {
1408      case GL_POINTS:
1409      case GL_LINES:
1410      case GL_LINE_LOOP:
1411      case GL_LINE_STRIP:
1412      case GL_TRIANGLES:
1413      case GL_TRIANGLE_STRIP:
1414      case GL_TRIANGLE_FAN:
1415        break;
1416      default:
1417        context->recordError(Error(GL_INVALID_ENUM));
1418        return false;
1419    }
1420
1421    if (count < 0)
1422    {
1423        context->recordError(Error(GL_INVALID_VALUE));
1424        return false;
1425    }
1426
1427    const State &state = context->getState();
1428
1429    // Check for mapped buffers
1430    if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
1431    {
1432        context->recordError(Error(GL_INVALID_OPERATION));
1433        return false;
1434    }
1435
1436    const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
1437    if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1438        state.getStencilRef() != state.getStencilBackRef() ||
1439        depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1440    {
1441        // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1442        // See Section 6.10 of the WebGL 1.0 spec
1443        ERR("This ANGLE implementation does not support separate front/back stencil "
1444            "writemasks, reference values, or stencil mask values.");
1445        context->recordError(Error(GL_INVALID_OPERATION));
1446        return false;
1447    }
1448
1449    const gl::Framebuffer *fbo = state.getDrawFramebuffer();
1450    if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1451    {
1452        context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1453        return false;
1454    }
1455
1456    if (state.getCurrentProgramId() == 0)
1457    {
1458        context->recordError(Error(GL_INVALID_OPERATION));
1459        return false;
1460    }
1461
1462    gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1463    if (!programBinary->validateSamplers(NULL, context->getCaps()))
1464    {
1465        context->recordError(Error(GL_INVALID_OPERATION));
1466        return false;
1467    }
1468
1469    // Buffer validations
1470    const VertexArray *vao = state.getVertexArray();
1471    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1472    {
1473        const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1474        bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
1475        if (attribActive && attrib.enabled)
1476        {
1477            gl::Buffer *buffer = attrib.buffer.get();
1478
1479            if (buffer)
1480            {
1481                GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1482                GLint64 maxVertexElement = 0;
1483
1484                if (attrib.divisor > 0)
1485                {
1486                    maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1487                }
1488                else
1489                {
1490                    maxVertexElement = static_cast<GLint64>(maxVertex);
1491                }
1492
1493                GLint64 attribDataSize = maxVertexElement * attribStride;
1494
1495                // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1496                // We can return INVALID_OPERATION if our vertex attribute does not have
1497                // enough backing data.
1498                if (attribDataSize > buffer->getSize())
1499                {
1500                    context->recordError(Error(GL_INVALID_OPERATION));
1501                    return false;
1502                }
1503            }
1504            else if (attrib.pointer == NULL)
1505            {
1506                // This is an application error that would normally result in a crash,
1507                // but we catch it and return an error
1508                context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1509                return false;
1510            }
1511        }
1512    }
1513
1514    // No-op if zero count
1515    return (count > 0);
1516}
1517
1518bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1519{
1520    if (first < 0)
1521    {
1522        context->recordError(Error(GL_INVALID_VALUE));
1523        return false;
1524    }
1525
1526    const State &state = context->getState();
1527    gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1528    if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1529        curTransformFeedback->getDrawMode() != mode)
1530    {
1531        // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1532        // that does not match the current transform feedback object's draw mode (if transform feedback
1533        // is active), (3.0.2, section 2.14, pg 86)
1534        context->recordError(Error(GL_INVALID_OPERATION));
1535        return false;
1536    }
1537
1538    if (!ValidateDrawBase(context, mode, count, count, primcount))
1539    {
1540        return false;
1541    }
1542
1543    return true;
1544}
1545
1546bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1547{
1548    if (primcount < 0)
1549    {
1550        context->recordError(Error(GL_INVALID_VALUE));
1551        return false;
1552    }
1553
1554    if (!ValidateDrawArrays(context, mode, first, count, primcount))
1555    {
1556        return false;
1557    }
1558
1559    // No-op if zero primitive count
1560    return (primcount > 0);
1561}
1562
1563static bool ValidateDrawInstancedANGLE(Context *context)
1564{
1565    // Verify there is at least one active attribute with a divisor of zero
1566    const gl::State& state = context->getState();
1567
1568    gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1569
1570    const VertexArray *vao = state.getVertexArray();
1571    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1572    {
1573        const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1574        bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
1575        if (active && attrib.divisor == 0)
1576        {
1577            return true;
1578        }
1579    }
1580
1581    context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1582                                                     "has a divisor of zero."));
1583    return false;
1584}
1585
1586bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1587{
1588    if (!ValidateDrawInstancedANGLE(context))
1589    {
1590        return false;
1591    }
1592
1593    return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1594}
1595
1596bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
1597                          const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1598{
1599    switch (type)
1600    {
1601      case GL_UNSIGNED_BYTE:
1602      case GL_UNSIGNED_SHORT:
1603        break;
1604      case GL_UNSIGNED_INT:
1605        if (!context->getExtensions().elementIndexUint)
1606        {
1607            context->recordError(Error(GL_INVALID_ENUM));
1608            return false;
1609        }
1610        break;
1611      default:
1612        context->recordError(Error(GL_INVALID_ENUM));
1613        return false;
1614    }
1615
1616    const State &state = context->getState();
1617
1618    gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1619    if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1620    {
1621        // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1622        // while transform feedback is active, (3.0.2, section 2.14, pg 86)
1623        context->recordError(Error(GL_INVALID_OPERATION));
1624        return false;
1625    }
1626
1627    // Check for mapped buffers
1628    if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
1629    {
1630        context->recordError(Error(GL_INVALID_OPERATION));
1631        return false;
1632    }
1633
1634    const gl::VertexArray *vao = state.getVertexArray();
1635    const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1636    if (!indices && !elementArrayBuffer)
1637    {
1638        context->recordError(Error(GL_INVALID_OPERATION));
1639        return false;
1640    }
1641
1642    if (elementArrayBuffer)
1643    {
1644        const gl::Type &typeInfo = gl::GetTypeInfo(type);
1645
1646        GLint64 offset = reinterpret_cast<GLint64>(indices);
1647        GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1648
1649        // check for integer overflows
1650        if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1651            byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1652        {
1653            context->recordError(Error(GL_OUT_OF_MEMORY));
1654            return false;
1655        }
1656
1657        // Check for reading past the end of the bound buffer object
1658        if (byteCount > elementArrayBuffer->getSize())
1659        {
1660            context->recordError(Error(GL_INVALID_OPERATION));
1661            return false;
1662        }
1663    }
1664    else if (!indices)
1665    {
1666        // Catch this programming error here
1667        context->recordError(Error(GL_INVALID_OPERATION));
1668        return false;
1669    }
1670
1671    // Use max index to validate if our vertex buffers are large enough for the pull.
1672    // TODO: offer fast path, with disabled index validation.
1673    // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1674    if (elementArrayBuffer)
1675    {
1676        unsigned int offset = reinterpret_cast<unsigned int>(indices);
1677        if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1678        {
1679            const void *dataPointer = elementArrayBuffer->getImplementation()->getData();
1680            const uint8_t *offsetPointer = static_cast<const uint8_t *>(dataPointer) + offset;
1681            *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1682        }
1683    }
1684    else
1685    {
1686        *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1687    }
1688
1689    if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
1690    {
1691        return false;
1692    }
1693
1694    return true;
1695}
1696
1697bool ValidateDrawElementsInstanced(Context *context,
1698                                   GLenum mode, GLsizei count, GLenum type,
1699                                   const GLvoid *indices, GLsizei primcount,
1700                                   rx::RangeUI *indexRangeOut)
1701{
1702    if (primcount < 0)
1703    {
1704        context->recordError(Error(GL_INVALID_VALUE));
1705        return false;
1706    }
1707
1708    if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
1709    {
1710        return false;
1711    }
1712
1713    // No-op zero primitive count
1714    return (primcount > 0);
1715}
1716
1717bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1718                                        const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1719{
1720    if (!ValidateDrawInstancedANGLE(context))
1721    {
1722        return false;
1723    }
1724
1725    return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1726}
1727
1728bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
1729                                    GLuint texture, GLint level)
1730{
1731    if (!ValidFramebufferTarget(target))
1732    {
1733        context->recordError(Error(GL_INVALID_ENUM));
1734        return false;
1735    }
1736
1737    if (!ValidateAttachmentTarget(context, attachment))
1738    {
1739        return false;
1740    }
1741
1742    if (texture != 0)
1743    {
1744        gl::Texture *tex = context->getTexture(texture);
1745
1746        if (tex == NULL)
1747        {
1748            context->recordError(Error(GL_INVALID_OPERATION));
1749            return false;
1750        }
1751
1752        if (level < 0)
1753        {
1754            context->recordError(Error(GL_INVALID_VALUE));
1755            return false;
1756        }
1757    }
1758
1759    const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1760    GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
1761
1762    if (framebufferHandle == 0 || !framebuffer)
1763    {
1764        context->recordError(Error(GL_INVALID_OPERATION));
1765        return false;
1766    }
1767
1768    return true;
1769}
1770
1771bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
1772                                  GLenum textarget, GLuint texture, GLint level)
1773{
1774    // Attachments are required to be bound to level 0 in ES2
1775    if (context->getClientVersion() < 3 && level != 0)
1776    {
1777        context->recordError(Error(GL_INVALID_VALUE));
1778        return false;
1779    }
1780
1781    if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
1782    {
1783        return false;
1784    }
1785
1786    if (texture != 0)
1787    {
1788        gl::Texture *tex = context->getTexture(texture);
1789        ASSERT(tex);
1790
1791        const gl::Caps &caps = context->getCaps();
1792
1793        switch (textarget)
1794        {
1795          case GL_TEXTURE_2D:
1796            {
1797                if (level > gl::log2(caps.max2DTextureSize))
1798                {
1799                    context->recordError(Error(GL_INVALID_VALUE));
1800                    return false;
1801                }
1802                if (tex->getTarget() != GL_TEXTURE_2D)
1803                {
1804                    context->recordError(Error(GL_INVALID_OPERATION));
1805                    return false;
1806                }
1807                gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1808                if (tex2d->isCompressed(level))
1809                {
1810                    context->recordError(Error(GL_INVALID_OPERATION));
1811                    return false;
1812                }
1813            }
1814            break;
1815
1816          case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1817          case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1818          case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1819          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1820          case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1821          case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1822            {
1823                if (level > gl::log2(caps.maxCubeMapTextureSize))
1824                {
1825                    context->recordError(Error(GL_INVALID_VALUE));
1826                    return false;
1827                }
1828                if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1829                {
1830                    context->recordError(Error(GL_INVALID_OPERATION));
1831                    return false;
1832                }
1833                gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1834                if (texcube->isCompressed(textarget, level))
1835                {
1836                    context->recordError(Error(GL_INVALID_OPERATION));
1837                    return false;
1838                }
1839            }
1840            break;
1841
1842          default:
1843            context->recordError(Error(GL_INVALID_ENUM));
1844            return false;
1845        }
1846    }
1847
1848    return true;
1849}
1850
1851bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
1852{
1853    if (program == 0)
1854    {
1855        context->recordError(Error(GL_INVALID_VALUE));
1856        return false;
1857    }
1858
1859    gl::Program *programObject = context->getProgram(program);
1860
1861    if (!programObject || !programObject->isLinked())
1862    {
1863        context->recordError(Error(GL_INVALID_OPERATION));
1864        return false;
1865    }
1866
1867    gl::ProgramBinary *programBinary = programObject->getProgramBinary();
1868    if (!programBinary)
1869    {
1870        context->recordError(Error(GL_INVALID_OPERATION));
1871        return false;
1872    }
1873
1874    if (!programBinary->isValidUniformLocation(location))
1875    {
1876        context->recordError(Error(GL_INVALID_OPERATION));
1877        return false;
1878    }
1879
1880    return true;
1881}
1882
1883bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
1884{
1885    return ValidateGetUniformBase(context, program, location);
1886}
1887
1888bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
1889{
1890    return ValidateGetUniformBase(context, program, location);
1891}
1892
1893static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
1894{
1895    if (!ValidateGetUniformBase(context, program, location))
1896    {
1897        return false;
1898    }
1899
1900    gl::Program *programObject = context->getProgram(program);
1901    ASSERT(programObject);
1902    gl::ProgramBinary *programBinary = programObject->getProgramBinary();
1903
1904    // sized queries -- ensure the provided buffer is large enough
1905    LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1906    size_t requiredBytes = VariableExternalSize(uniform->type);
1907    if (static_cast<size_t>(bufSize) < requiredBytes)
1908    {
1909        context->recordError(Error(GL_INVALID_OPERATION));
1910        return false;
1911    }
1912
1913    return true;
1914}
1915
1916bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
1917{
1918    return ValidateSizedGetUniform(context, program, location, bufSize);
1919}
1920
1921bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
1922{
1923    return ValidateSizedGetUniform(context, program, location, bufSize);
1924}
1925
1926}
1927