Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / validationES.cpp
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7
8 // validationES.h: Validation functions for generic OpenGL ES entry point parameters
9
10 #include "libGLESv2/validationES.h"
11 #include "libGLESv2/validationES2.h"
12 #include "libGLESv2/validationES3.h"
13 #include "libGLESv2/Context.h"
14 #include "libGLESv2/Texture.h"
15 #include "libGLESv2/Framebuffer.h"
16 #include "libGLESv2/FramebufferAttachment.h"
17 #include "libGLESv2/formatutils.h"
18 #include "libGLESv2/main.h"
19 #include "libGLESv2/Query.h"
20 #include "libGLESv2/ProgramBinary.h"
21 #include "libGLESv2/TransformFeedback.h"
22 #include "libGLESv2/VertexArray.h"
23
24 #include "common/mathutil.h"
25 #include "common/utilities.h"
26
27 namespace gl
28 {
29
30 bool 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
52 bool 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
73 bool 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
93 bool 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
106 bool 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
129 bool 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
150 bool 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
171 bool ValidImageSize(const gl::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
193 bool ValidCompressedImageSize(const gl::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
210 bool 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
227 bool ValidProgram(const 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         return gl::error(GL_INVALID_OPERATION, false);
241     }
242     else
243     {
244         // No shader/program object has this ID
245         return gl::error(GL_INVALID_VALUE, false);
246     }
247 }
248
249 bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment)
250 {
251     if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
252     {
253         const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
254
255         if (colorAttachment >= context->getCaps().maxColorAttachments)
256         {
257             return gl::error(GL_INVALID_VALUE, false);
258         }
259     }
260     else
261     {
262         switch (attachment)
263         {
264           case GL_DEPTH_ATTACHMENT:
265           case GL_STENCIL_ATTACHMENT:
266             break;
267
268           case GL_DEPTH_STENCIL_ATTACHMENT:
269             if (context->getClientVersion() < 3)
270             {
271                 return gl::error(GL_INVALID_ENUM, false);
272             }
273             break;
274
275           default:
276             return gl::error(GL_INVALID_ENUM, false);
277         }
278     }
279
280     return true;
281 }
282
283 bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
284                                            GLenum internalformat, GLsizei width, GLsizei height,
285                                            bool angleExtension)
286 {
287     switch (target)
288     {
289       case GL_RENDERBUFFER:
290         break;
291       default:
292         return gl::error(GL_INVALID_ENUM, false);
293     }
294
295     if (width < 0 || height < 0 || samples < 0)
296     {
297         return gl::error(GL_INVALID_VALUE, false);
298     }
299
300     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
301     if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
302     {
303         return gl::error(GL_INVALID_ENUM, false);
304     }
305
306     // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
307     // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
308     // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
309     // internal format must be sized and not an integer format if samples is greater than zero.
310     if (formatInfo.pixelBytes == 0)
311     {
312         return gl::error(GL_INVALID_ENUM, false);
313     }
314
315     if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
316     {
317         return gl::error(GL_INVALID_OPERATION, false);
318     }
319
320     const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
321     if (!formatCaps.renderable)
322     {
323         return gl::error(GL_INVALID_ENUM, false);
324     }
325
326     if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
327     {
328         return gl::error(GL_INVALID_VALUE, false);
329     }
330
331     // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
332     // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
333     // states that samples must be less than or equal to the maximum samples for the specified
334     // internal format.
335     if (angleExtension)
336     {
337         ASSERT(context->getExtensions().framebufferMultisample);
338         if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
339         {
340             return gl::error(GL_INVALID_VALUE, false);
341         }
342
343         // Check if this specific format supports enough samples
344         if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
345         {
346             return gl::error(GL_OUT_OF_MEMORY, false);
347         }
348     }
349     else
350     {
351         if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
352         {
353             return gl::error(GL_INVALID_VALUE, false);
354         }
355     }
356
357     GLuint handle = context->getState().getRenderbufferId();
358     if (handle == 0)
359     {
360         return gl::error(GL_INVALID_OPERATION, false);
361     }
362
363     return true;
364 }
365
366 bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
367                                                GLenum renderbuffertarget, GLuint renderbuffer)
368 {
369     if (!ValidFramebufferTarget(target))
370     {
371         return gl::error(GL_INVALID_ENUM, false);
372     }
373
374     gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
375     GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
376
377     if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
378     {
379         return gl::error(GL_INVALID_OPERATION, false);
380     }
381
382     if (!ValidateAttachmentTarget(context, attachment))
383     {
384         return false;
385     }
386
387     // [OpenGL ES 2.0.25] Section 4.4.3 page 112
388     // [OpenGL ES 3.0.2] Section 4.4.2 page 201
389     // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
390     // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
391     if (renderbuffer != 0)
392     {
393         if (!context->getRenderbuffer(renderbuffer))
394         {
395             return gl::error(GL_INVALID_OPERATION, false);
396         }
397     }
398
399     return true;
400 }
401
402 static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
403                           GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
404                           GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
405 {
406     if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
407         dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
408         srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
409     {
410         return true;
411     }
412     else if (context->getState().isScissorTestEnabled())
413     {
414         const Rectangle &scissor = context->getState().getScissor();
415
416         return scissor.x > 0 || scissor.y > 0 ||
417                scissor.width < writeBuffer->getWidth() ||
418                scissor.height < writeBuffer->getHeight();
419     }
420     else
421     {
422         return false;
423     }
424 }
425
426 bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
427                                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
428                                        GLenum filter, bool fromAngleExtension)
429 {
430     switch (filter)
431     {
432       case GL_NEAREST:
433         break;
434       case GL_LINEAR:
435         if (fromAngleExtension)
436         {
437             return gl::error(GL_INVALID_ENUM, false);
438         }
439         break;
440       default:
441         return gl::error(GL_INVALID_ENUM, false);
442     }
443
444     if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
445     {
446         return gl::error(GL_INVALID_VALUE, false);
447     }
448
449     if (mask == 0)
450     {
451         // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
452         // buffers are copied.
453         return false;
454     }
455
456     if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
457     {
458         ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
459         return gl::error(GL_INVALID_OPERATION, false);
460     }
461
462     // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
463     // color buffer, leaving only nearest being unfiltered from above
464     if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
465     {
466         return gl::error(GL_INVALID_OPERATION, false);
467     }
468
469     if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
470     {
471         if (fromAngleExtension)
472         {
473             ERR("Blits with the same source and destination framebuffer are not supported by this "
474                 "implementation.");
475         }
476         return gl::error(GL_INVALID_OPERATION, false);
477     }
478
479     gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
480     gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
481     if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
482         !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
483     {
484         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
485     }
486
487     if (drawFramebuffer->getSamples() != 0)
488     {
489         return gl::error(GL_INVALID_OPERATION, false);
490     }
491
492     bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
493
494     if (mask & GL_COLOR_BUFFER_BIT)
495     {
496         gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
497         gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
498
499         if (readColorBuffer && drawColorBuffer)
500         {
501             GLenum readInternalFormat = readColorBuffer->getActualFormat();
502             const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
503
504             for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
505             {
506                 if (drawFramebuffer->isEnabledColorAttachment(i))
507                 {
508                     GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
509                     const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
510
511                     // The GL ES 3.0.2 spec (pg 193) states that:
512                     // 1) If the read buffer is fixed point format, the draw buffer must be as well
513                     // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
514                     // 3) If the read buffer is a signed integer format, the draw buffer must be as well
515                     if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
516                         !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
517                     {
518                         return gl::error(GL_INVALID_OPERATION, false);
519                     }
520
521                     if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
522                     {
523                         return gl::error(GL_INVALID_OPERATION, false);
524                     }
525
526                     if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
527                     {
528                         return gl::error(GL_INVALID_OPERATION, false);
529                     }
530
531                     if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
532                     {
533                         return gl::error(GL_INVALID_OPERATION, false);
534                     }
535                 }
536             }
537
538             if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
539             {
540                 return gl::error(GL_INVALID_OPERATION, false);
541             }
542
543             if (fromAngleExtension)
544             {
545                 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
546                 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
547                 {
548                     return gl::error(GL_INVALID_OPERATION, false);
549                 }
550
551                 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
552                 {
553                     if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
554                     {
555                         FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
556                         ASSERT(attachment);
557
558                         if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
559                         {
560                             return gl::error(GL_INVALID_OPERATION, false);
561                         }
562
563                         if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
564                         {
565                             return gl::error(GL_INVALID_OPERATION, false);
566                         }
567                     }
568                 }
569                 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
570                                                                         srcX0, srcY0, srcX1, srcY1,
571                                                                         dstX0, dstY0, dstX1, dstY1))
572                 {
573                     return gl::error(GL_INVALID_OPERATION, false);
574                 }
575             }
576         }
577     }
578
579     if (mask & GL_DEPTH_BUFFER_BIT)
580     {
581         gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
582         gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
583
584         if (readDepthBuffer && drawDepthBuffer)
585         {
586             if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
587             {
588                 return gl::error(GL_INVALID_OPERATION, false);
589             }
590
591             if (readDepthBuffer->getSamples() > 0 && !sameBounds)
592             {
593                 return gl::error(GL_INVALID_OPERATION, false);
594             }
595
596             if (fromAngleExtension)
597             {
598                 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
599                                   srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
600                 {
601                     ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
602                     return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
603                 }
604
605                 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
606                 {
607                     return gl::error(GL_INVALID_OPERATION, false);
608                 }
609             }
610         }
611     }
612
613     if (mask & GL_STENCIL_BUFFER_BIT)
614     {
615         gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
616         gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
617
618         if (readStencilBuffer && drawStencilBuffer)
619         {
620             if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
621             {
622                 return gl::error(GL_INVALID_OPERATION, false);
623             }
624
625             if (readStencilBuffer->getSamples() > 0 && !sameBounds)
626             {
627                 return gl::error(GL_INVALID_OPERATION, false);
628             }
629
630             if (fromAngleExtension)
631             {
632                 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
633                                   srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
634                 {
635                     ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
636                     return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
637                 }
638
639                 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
640                 {
641                     return gl::error(GL_INVALID_OPERATION, false);
642                 }
643             }
644         }
645     }
646
647     return true;
648 }
649
650 bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
651 {
652     switch (pname)
653     {
654       case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
655       case GL_VERTEX_ATTRIB_ARRAY_SIZE:
656       case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
657       case GL_VERTEX_ATTRIB_ARRAY_TYPE:
658       case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
659       case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
660       case GL_CURRENT_VERTEX_ATTRIB:
661         return true;
662
663       case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
664         // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
665         // the same constant.
666         META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
667         return true;
668
669       case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
670         return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
671
672       default:
673         return gl::error(GL_INVALID_ENUM, false);
674     }
675 }
676
677 bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
678 {
679     switch (pname)
680     {
681       case GL_TEXTURE_WRAP_R:
682       case GL_TEXTURE_SWIZZLE_R:
683       case GL_TEXTURE_SWIZZLE_G:
684       case GL_TEXTURE_SWIZZLE_B:
685       case GL_TEXTURE_SWIZZLE_A:
686       case GL_TEXTURE_BASE_LEVEL:
687       case GL_TEXTURE_MAX_LEVEL:
688       case GL_TEXTURE_COMPARE_MODE:
689       case GL_TEXTURE_COMPARE_FUNC:
690       case GL_TEXTURE_MIN_LOD:
691       case GL_TEXTURE_MAX_LOD:
692         if (context->getClientVersion() < 3)
693         {
694             return gl::error(GL_INVALID_ENUM, false);
695         }
696         break;
697
698       default: break;
699     }
700
701     switch (pname)
702     {
703       case GL_TEXTURE_WRAP_S:
704       case GL_TEXTURE_WRAP_T:
705       case GL_TEXTURE_WRAP_R:
706         switch (param)
707         {
708           case GL_REPEAT:
709           case GL_CLAMP_TO_EDGE:
710           case GL_MIRRORED_REPEAT:
711             return true;
712           default:
713             return gl::error(GL_INVALID_ENUM, false);
714         }
715
716       case GL_TEXTURE_MIN_FILTER:
717         switch (param)
718         {
719           case GL_NEAREST:
720           case GL_LINEAR:
721           case GL_NEAREST_MIPMAP_NEAREST:
722           case GL_LINEAR_MIPMAP_NEAREST:
723           case GL_NEAREST_MIPMAP_LINEAR:
724           case GL_LINEAR_MIPMAP_LINEAR:
725             return true;
726           default:
727             return gl::error(GL_INVALID_ENUM, false);
728         }
729         break;
730
731       case GL_TEXTURE_MAG_FILTER:
732         switch (param)
733         {
734           case GL_NEAREST:
735           case GL_LINEAR:
736             return true;
737           default:
738             return gl::error(GL_INVALID_ENUM, false);
739         }
740         break;
741
742       case GL_TEXTURE_USAGE_ANGLE:
743         switch (param)
744         {
745           case GL_NONE:
746           case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
747             return true;
748           default:
749             return gl::error(GL_INVALID_ENUM, false);
750         }
751         break;
752
753       case GL_TEXTURE_MAX_ANISOTROPY_EXT:
754         if (!context->getExtensions().textureFilterAnisotropic)
755         {
756             return gl::error(GL_INVALID_ENUM, false);
757         }
758
759         // we assume the parameter passed to this validation method is truncated, not rounded
760         if (param < 1)
761         {
762             return gl::error(GL_INVALID_VALUE, false);
763         }
764         return true;
765
766       case GL_TEXTURE_MIN_LOD:
767       case GL_TEXTURE_MAX_LOD:
768         // any value is permissible
769         return true;
770
771       case GL_TEXTURE_COMPARE_MODE:
772         // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
773         switch (param)
774         {
775           case GL_NONE:
776           case GL_COMPARE_REF_TO_TEXTURE:
777             return true;
778           default:
779             return gl::error(GL_INVALID_ENUM, false);
780         }
781         break;
782
783       case GL_TEXTURE_COMPARE_FUNC:
784         // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
785         switch (param)
786         {
787           case GL_LEQUAL:
788           case GL_GEQUAL:
789           case GL_LESS:
790           case GL_GREATER:
791           case GL_EQUAL:
792           case GL_NOTEQUAL:
793           case GL_ALWAYS:
794           case GL_NEVER:
795             return true;
796           default:
797             return gl::error(GL_INVALID_ENUM, false);
798         }
799         break;
800
801       case GL_TEXTURE_SWIZZLE_R:
802       case GL_TEXTURE_SWIZZLE_G:
803       case GL_TEXTURE_SWIZZLE_B:
804       case GL_TEXTURE_SWIZZLE_A:
805         switch (param)
806         {
807           case GL_RED:
808           case GL_GREEN:
809           case GL_BLUE:
810           case GL_ALPHA:
811           case GL_ZERO:
812           case GL_ONE:
813             return true;
814           default:
815             return gl::error(GL_INVALID_ENUM, false);
816         }
817         break;
818
819       case GL_TEXTURE_BASE_LEVEL:
820       case GL_TEXTURE_MAX_LEVEL:
821         if (param < 0)
822         {
823             return gl::error(GL_INVALID_VALUE, false);
824         }
825         return true;
826
827       default:
828         return gl::error(GL_INVALID_ENUM, false);
829     }
830 }
831
832 bool ValidateSamplerObjectParameter(GLenum pname)
833 {
834     switch (pname)
835     {
836       case GL_TEXTURE_MIN_FILTER:
837       case GL_TEXTURE_MAG_FILTER:
838       case GL_TEXTURE_WRAP_S:
839       case GL_TEXTURE_WRAP_T:
840       case GL_TEXTURE_WRAP_R:
841       case GL_TEXTURE_MIN_LOD:
842       case GL_TEXTURE_MAX_LOD:
843       case GL_TEXTURE_COMPARE_MODE:
844       case GL_TEXTURE_COMPARE_FUNC:
845         return true;
846
847       default:
848         return gl::error(GL_INVALID_ENUM, false);
849     }
850 }
851
852 bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
853                                   GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
854 {
855     gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
856     ASSERT(framebuffer);
857
858     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
859     {
860         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
861     }
862
863     if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
864     {
865         return gl::error(GL_INVALID_OPERATION, false);
866     }
867
868     if (!framebuffer->getReadColorbuffer())
869     {
870         return gl::error(GL_INVALID_OPERATION, false);
871     }
872
873     GLenum currentInternalFormat, currentFormat, currentType;
874     GLuint clientVersion = context->getClientVersion();
875
876     context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
877
878     bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
879                                                  ValidES3ReadFormatType(context, currentInternalFormat, format, type);
880
881     if (!(currentFormat == format && currentType == type) && !validReadFormat)
882     {
883         return gl::error(GL_INVALID_OPERATION, false);
884     }
885
886     GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
887     const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
888
889     GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
890     // sized query sanity check
891     if (bufSize)
892     {
893         int requiredSize = outputPitch * height;
894         if (requiredSize > *bufSize)
895         {
896             return gl::error(GL_INVALID_OPERATION, false);
897         }
898     }
899
900     return true;
901 }
902
903 bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
904 {
905     if (!ValidQueryType(context, target))
906     {
907         return gl::error(GL_INVALID_ENUM, false);
908     }
909
910     if (id == 0)
911     {
912         return gl::error(GL_INVALID_OPERATION, false);
913     }
914
915     // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
916     // of zero, if the active query object name for <target> is non-zero (for the
917     // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
918     // the active query for either target is non-zero), if <id> is the name of an
919     // existing query object whose type does not match <target>, or if <id> is the
920     // active query object name for any query type, the error INVALID_OPERATION is
921     // generated.
922
923     // Ensure no other queries are active
924     // NOTE: If other queries than occlusion are supported, we will need to check
925     // separately that:
926     //    a) The query ID passed is not the current active query for any target/type
927     //    b) There are no active queries for the requested target (and in the case
928     //       of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
929     //       no query may be active for either if glBeginQuery targets either.
930     if (context->getState().isQueryActive())
931     {
932         return gl::error(GL_INVALID_OPERATION, false);
933     }
934
935     Query *queryObject = context->getQuery(id, true, target);
936
937     // check that name was obtained with glGenQueries
938     if (!queryObject)
939     {
940         return gl::error(GL_INVALID_OPERATION, false);
941     }
942
943     // check for type mismatch
944     if (queryObject->getType() != target)
945     {
946         return gl::error(GL_INVALID_OPERATION, false);
947     }
948
949     return true;
950 }
951
952 bool ValidateEndQuery(gl::Context *context, GLenum target)
953 {
954     if (!ValidQueryType(context, target))
955     {
956         return gl::error(GL_INVALID_ENUM, false);
957     }
958
959     const Query *queryObject = context->getState().getActiveQuery(target);
960
961     if (queryObject == NULL)
962     {
963         return gl::error(GL_INVALID_OPERATION, false);
964     }
965
966     if (!queryObject->isStarted())
967     {
968         return gl::error(GL_INVALID_OPERATION, false);
969     }
970
971     return true;
972 }
973
974 static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
975                                       GLint location, GLsizei count, LinkedUniform **uniformOut)
976 {
977     if (count < 0)
978     {
979         return gl::error(GL_INVALID_VALUE, false);
980     }
981
982     gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
983     if (!programBinary)
984     {
985         return gl::error(GL_INVALID_OPERATION, false);
986     }
987
988     if (location == -1)
989     {
990         // Silently ignore the uniform command
991         return false;
992     }
993
994     if (!programBinary->isValidUniformLocation(location))
995     {
996         return gl::error(GL_INVALID_OPERATION, false);
997     }
998
999     LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1000
1001     // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1002     if (uniform->elementCount() == 1 && count > 1)
1003     {
1004         return gl::error(GL_INVALID_OPERATION, false);
1005     }
1006
1007     *uniformOut = uniform;
1008     return true;
1009 }
1010
1011 bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1012 {
1013     // Check for ES3 uniform entry points
1014     if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
1015     {
1016         return gl::error(GL_INVALID_OPERATION, false);
1017     }
1018
1019     LinkedUniform *uniform = NULL;
1020     if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1021     {
1022         return false;
1023     }
1024
1025     GLenum targetBoolType = VariableBoolVectorType(uniformType);
1026     bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1027     if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1028     {
1029         return gl::error(GL_INVALID_OPERATION, false);
1030     }
1031
1032     return true;
1033 }
1034
1035 bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1036                            GLboolean transpose)
1037 {
1038     // Check for ES3 uniform entry points
1039     int rows = VariableRowCount(matrixType);
1040     int cols = VariableColumnCount(matrixType);
1041     if (rows != cols && context->getClientVersion() < 3)
1042     {
1043         return gl::error(GL_INVALID_OPERATION, false);
1044     }
1045
1046     if (transpose != GL_FALSE && context->getClientVersion() < 3)
1047     {
1048         return gl::error(GL_INVALID_VALUE, false);
1049     }
1050
1051     LinkedUniform *uniform = NULL;
1052     if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1053     {
1054         return false;
1055     }
1056
1057     if (uniform->type != matrixType)
1058     {
1059         return gl::error(GL_INVALID_OPERATION, false);
1060     }
1061
1062     return true;
1063 }
1064
1065 bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1066 {
1067     if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1068     {
1069         return gl::error(GL_INVALID_ENUM, false);
1070     }
1071
1072     if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1073     {
1074         unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1075
1076         if (colorAttachment >= context->getCaps().maxDrawBuffers)
1077         {
1078             return gl::error(GL_INVALID_OPERATION, false);
1079         }
1080     }
1081
1082     switch (pname)
1083     {
1084       case GL_TEXTURE_BINDING_2D:
1085       case GL_TEXTURE_BINDING_CUBE_MAP:
1086       case GL_TEXTURE_BINDING_3D:
1087       case GL_TEXTURE_BINDING_2D_ARRAY:
1088         if (context->getState().getActiveSampler() >= context->getMaximumCombinedTextureImageUnits())
1089         {
1090             return gl::error(GL_INVALID_OPERATION, false);
1091         }
1092         break;
1093
1094       case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1095       case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1096         {
1097             Framebuffer *framebuffer = context->getState().getReadFramebuffer();
1098             ASSERT(framebuffer);
1099             if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1100             {
1101                 return gl::error(GL_INVALID_OPERATION, false);
1102             }
1103
1104             FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1105             if (!attachment)
1106             {
1107                 return gl::error(GL_INVALID_OPERATION, false);
1108             }
1109         }
1110         break;
1111
1112       default:
1113         break;
1114     }
1115
1116     // pname is valid, but there are no parameters to return
1117     if (numParams == 0)
1118     {
1119         return false;
1120     }
1121
1122     return true;
1123 }
1124
1125 bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1126                                         GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1127                                         GLint border, GLenum *textureFormatOut)
1128 {
1129
1130     if (!ValidTexture2DDestinationTarget(context, target))
1131     {
1132         return gl::error(GL_INVALID_ENUM, false);
1133     }
1134
1135     if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1136     {
1137         return gl::error(GL_INVALID_VALUE, false);
1138     }
1139
1140     if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1141     {
1142         return gl::error(GL_INVALID_VALUE, false);
1143     }
1144
1145     if (border != 0)
1146     {
1147         return gl::error(GL_INVALID_VALUE, false);
1148     }
1149
1150     if (!ValidMipLevel(context, target, level))
1151     {
1152         return gl::error(GL_INVALID_VALUE, false);
1153     }
1154
1155     gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
1156     if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1157     {
1158         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1159     }
1160
1161     if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
1162     {
1163         return gl::error(GL_INVALID_OPERATION, false);
1164     }
1165
1166     const gl::Caps &caps = context->getCaps();
1167
1168     gl::Texture *texture = NULL;
1169     GLenum textureInternalFormat = GL_NONE;
1170     GLint textureLevelWidth = 0;
1171     GLint textureLevelHeight = 0;
1172     GLint textureLevelDepth = 0;
1173     GLuint maxDimension = 0;
1174
1175     switch (target)
1176     {
1177       case GL_TEXTURE_2D:
1178         {
1179             gl::Texture2D *texture2d = context->getTexture2D();
1180             if (texture2d)
1181             {
1182                 textureInternalFormat = texture2d->getInternalFormat(level);
1183                 textureLevelWidth = texture2d->getWidth(level);
1184                 textureLevelHeight = texture2d->getHeight(level);
1185                 textureLevelDepth = 1;
1186                 texture = texture2d;
1187                 maxDimension = caps.max2DTextureSize;
1188             }
1189         }
1190         break;
1191
1192       case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1193       case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1194       case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1195       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1196       case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1197       case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1198         {
1199             gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1200             if (textureCube)
1201             {
1202                 textureInternalFormat = textureCube->getInternalFormat(target, level);
1203                 textureLevelWidth = textureCube->getWidth(target, level);
1204                 textureLevelHeight = textureCube->getHeight(target, level);
1205                 textureLevelDepth = 1;
1206                 texture = textureCube;
1207                 maxDimension = caps.maxCubeMapTextureSize;
1208             }
1209         }
1210         break;
1211
1212       case GL_TEXTURE_2D_ARRAY:
1213         {
1214             gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1215             if (texture2dArray)
1216             {
1217                 textureInternalFormat = texture2dArray->getInternalFormat(level);
1218                 textureLevelWidth = texture2dArray->getWidth(level);
1219                 textureLevelHeight = texture2dArray->getHeight(level);
1220                 textureLevelDepth = texture2dArray->getLayers(level);
1221                 texture = texture2dArray;
1222                 maxDimension = caps.max2DTextureSize;
1223             }
1224         }
1225         break;
1226
1227       case GL_TEXTURE_3D:
1228         {
1229             gl::Texture3D *texture3d = context->getTexture3D();
1230             if (texture3d)
1231             {
1232                 textureInternalFormat = texture3d->getInternalFormat(level);
1233                 textureLevelWidth = texture3d->getWidth(level);
1234                 textureLevelHeight = texture3d->getHeight(level);
1235                 textureLevelDepth = texture3d->getDepth(level);
1236                 texture = texture3d;
1237                 maxDimension = caps.max3DTextureSize;
1238             }
1239         }
1240         break;
1241
1242       default:
1243         return gl::error(GL_INVALID_ENUM, false);
1244     }
1245
1246     if (!texture)
1247     {
1248         return gl::error(GL_INVALID_OPERATION, false);
1249     }
1250
1251     if (texture->isImmutable() && !isSubImage)
1252     {
1253         return gl::error(GL_INVALID_OPERATION, false);
1254     }
1255
1256     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1257
1258     if (formatInfo.depthBits > 0)
1259     {
1260         return gl::error(GL_INVALID_OPERATION, false);
1261     }
1262
1263     if (formatInfo.compressed)
1264     {
1265         if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1266             ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
1267         {
1268             return gl::error(GL_INVALID_OPERATION, false);
1269         }
1270     }
1271
1272     if (isSubImage)
1273     {
1274         if (xoffset + width > textureLevelWidth ||
1275             yoffset + height > textureLevelHeight ||
1276             zoffset >= textureLevelDepth)
1277         {
1278             return gl::error(GL_INVALID_VALUE, false);
1279         }
1280     }
1281     else
1282     {
1283         if (IsCubemapTextureTarget(target) && width != height)
1284         {
1285             return gl::error(GL_INVALID_VALUE, false);
1286         }
1287
1288         if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
1289         {
1290             return gl::error(GL_INVALID_ENUM, false);
1291         }
1292
1293         int maxLevelDimension = (maxDimension >> level);
1294         if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1295         {
1296             return gl::error(GL_INVALID_VALUE, false);
1297         }
1298     }
1299
1300     *textureFormatOut = textureInternalFormat;
1301     return true;
1302 }
1303
1304 static bool ValidateDrawBase(const gl::State &state, GLenum mode, GLsizei count)
1305 {
1306     switch (mode)
1307     {
1308       case GL_POINTS:
1309       case GL_LINES:
1310       case GL_LINE_LOOP:
1311       case GL_LINE_STRIP:
1312       case GL_TRIANGLES:
1313       case GL_TRIANGLE_STRIP:
1314       case GL_TRIANGLE_FAN:
1315         break;
1316       default:
1317         return gl::error(GL_INVALID_ENUM, false);
1318     }
1319
1320     if (count < 0)
1321     {
1322         return gl::error(GL_INVALID_VALUE, false);
1323     }
1324
1325     // Check for mapped buffers
1326     if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
1327     {
1328         return gl::error(GL_INVALID_OPERATION, false);
1329     }
1330
1331     const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
1332     if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1333         state.getStencilRef() != state.getStencilBackRef() ||
1334         depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1335     {
1336         // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1337         // See Section 6.10 of the WebGL 1.0 spec
1338         ERR("This ANGLE implementation does not support separate front/back stencil "
1339             "writemasks, reference values, or stencil mask values.");
1340         return gl::error(GL_INVALID_OPERATION, false);
1341     }
1342
1343     const gl::Framebuffer *fbo = state.getDrawFramebuffer();
1344     if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1345     {
1346         return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1347     }
1348
1349     if (state.getCurrentProgramId() == 0)
1350     {
1351         return gl::error(GL_INVALID_OPERATION, false);
1352     }
1353
1354     gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1355     if (!programBinary->validateSamplers(NULL))
1356     {
1357         return gl::error(GL_INVALID_OPERATION, false);
1358     }
1359
1360     // No-op if zero count
1361     return (count > 0);
1362 }
1363
1364 bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
1365 {
1366     if (first < 0)
1367     {
1368         return gl::error(GL_INVALID_VALUE, false);
1369     }
1370
1371     const State &state = context->getState();
1372     gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1373     if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1374         curTransformFeedback->getDrawMode() != mode)
1375     {
1376         // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1377         // that does not match the current transform feedback object's draw mode (if transform feedback
1378         // is active), (3.0.2, section 2.14, pg 86)
1379         return gl::error(GL_INVALID_OPERATION, false);
1380     }
1381
1382     if (!ValidateDrawBase(state, mode, count))
1383     {
1384         return false;
1385     }
1386
1387     return true;
1388 }
1389
1390 bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1391 {
1392     if (primcount < 0)
1393     {
1394         return gl::error(GL_INVALID_VALUE, false);
1395     }
1396
1397     if (!ValidateDrawArrays(context, mode, first, count))
1398     {
1399         return false;
1400     }
1401
1402     // No-op if zero primitive count
1403     return (primcount > 0);
1404 }
1405
1406 bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
1407 {
1408     switch (type)
1409     {
1410       case GL_UNSIGNED_BYTE:
1411       case GL_UNSIGNED_SHORT:
1412         break;
1413       case GL_UNSIGNED_INT:
1414         if (!context->getExtensions().elementIndexUint)
1415         {
1416             return gl::error(GL_INVALID_ENUM, false);
1417         }
1418         break;
1419       default:
1420         return gl::error(GL_INVALID_ENUM, false);
1421     }
1422
1423     const State &state = context->getState();
1424
1425     gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
1426     if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1427     {
1428         // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1429         // while transform feedback is active, (3.0.2, section 2.14, pg 86)
1430         return gl::error(GL_INVALID_OPERATION, false);
1431     }
1432
1433     // Check for mapped buffers
1434     if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
1435     {
1436         return gl::error(GL_INVALID_OPERATION, false);
1437     }
1438
1439     gl::VertexArray *vao = state.getVertexArray();
1440     if (!indices && !vao->getElementArrayBuffer())
1441     {
1442         return gl::error(GL_INVALID_OPERATION, false);
1443     }
1444
1445     if (!ValidateDrawBase(state, mode, count))
1446     {
1447         return false;
1448     }
1449
1450     return true;
1451 }
1452
1453 bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsizei count, GLenum type,
1454                                    const GLvoid *indices, GLsizei primcount)
1455 {
1456     if (primcount < 0)
1457     {
1458         return gl::error(GL_INVALID_VALUE, false);
1459     }
1460
1461     if (!ValidateDrawElements(context, mode, count, type, indices))
1462     {
1463         return false;
1464     }
1465
1466     // No-op zero primitive count
1467     return (primcount > 0);
1468 }
1469
1470 bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, GLenum attachment,
1471                                     GLuint texture, GLint level)
1472 {
1473     if (!ValidFramebufferTarget(target))
1474     {
1475         return gl::error(GL_INVALID_ENUM, false);
1476     }
1477
1478     if (!ValidateAttachmentTarget(context, attachment))
1479     {
1480         return false;
1481     }
1482
1483     if (texture != 0)
1484     {
1485         gl::Texture *tex = context->getTexture(texture);
1486
1487         if (tex == NULL)
1488         {
1489             return gl::error(GL_INVALID_OPERATION, false);
1490         }
1491
1492         if (level < 0)
1493         {
1494             return gl::error(GL_INVALID_VALUE, false);
1495         }
1496     }
1497
1498     const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1499     GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
1500
1501     if (framebufferHandle == 0 || !framebuffer)
1502     {
1503         return gl::error(GL_INVALID_OPERATION, false);
1504     }
1505
1506     return true;
1507 }
1508
1509 bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLenum attachment,
1510                                   GLenum textarget, GLuint texture, GLint level)
1511 {
1512     // Attachments are required to be bound to level 0 in ES2
1513     if (context->getClientVersion() < 3 && level != 0)
1514     {
1515         return gl::error(GL_INVALID_VALUE, false);
1516     }
1517
1518     if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
1519     {
1520         return false;
1521     }
1522
1523     if (texture != 0)
1524     {
1525         gl::Texture *tex = context->getTexture(texture);
1526         ASSERT(tex);
1527
1528         const gl::Caps &caps = context->getCaps();
1529
1530         switch (textarget)
1531         {
1532           case GL_TEXTURE_2D:
1533             {
1534                 if (level > gl::log2(caps.max2DTextureSize))
1535                 {
1536                     return gl::error(GL_INVALID_VALUE, false);
1537                 }
1538                 if (tex->getTarget() != GL_TEXTURE_2D)
1539                 {
1540                     return gl::error(GL_INVALID_OPERATION, false);
1541                 }
1542                 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1543                 if (tex2d->isCompressed(level))
1544                 {
1545                     return gl::error(GL_INVALID_OPERATION, false);
1546                 }
1547             }
1548             break;
1549
1550           case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1551           case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1552           case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1553           case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1554           case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1555           case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1556             {
1557                 if (level > gl::log2(caps.maxCubeMapTextureSize))
1558                 {
1559                     return gl::error(GL_INVALID_VALUE, false);
1560                 }
1561                 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1562                 {
1563                     return gl::error(GL_INVALID_OPERATION, false);
1564                 }
1565                 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1566                 if (texcube->isCompressed(textarget, level))
1567                 {
1568                     return gl::error(GL_INVALID_OPERATION, false);
1569                 }
1570             }
1571             break;
1572
1573           default:
1574             return gl::error(GL_INVALID_ENUM, false);
1575         }
1576     }
1577
1578     return true;
1579 }
1580
1581 }