blob: 5afe27300c5dd2cd06851b4ff6b6ccbe0fa2d645 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#include "precompiled.h"
2//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04004// 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"
Jamie Madill26e91952014-03-05 15:01:27 -050011#include "libGLESv2/validationES2.h"
12#include "libGLESv2/validationES3.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040013#include "libGLESv2/Context.h"
14#include "libGLESv2/Texture.h"
15#include "libGLESv2/Framebuffer.h"
16#include "libGLESv2/Renderbuffer.h"
17#include "libGLESv2/formatutils.h"
18#include "libGLESv2/main.h"
Jamie Madilldb2f14c2014-05-13 13:56:30 -040019#include "libGLESv2/Query.h"
Jamie Madill36398922014-05-20 14:51:53 -040020#include "libGLESv2/ProgramBinary.h"
Jamie Madill250d33f2014-06-06 17:09:03 -040021#include "libGLESv2/TransformFeedback.h"
Jamie Madill9efa5812014-06-20 13:21:24 -040022#include "libGLESv2/VertexArray.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040023
24#include "common/mathutil.h"
25#include "common/utilities.h"
26
27namespace gl
28{
29
Geoff Lang0550d032014-01-30 11:29:07 -050030bool 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
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050052bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040053{
Jamie Madilld7460c72014-01-21 16:38:14 -050054 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040055 {
Jamie Madilld7460c72014-01-21 16:38:14 -050056 case GL_TEXTURE_2D:
57 case GL_TEXTURE_CUBE_MAP:
58 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040059
Jamie Madilld7460c72014-01-21 16:38:14 -050060 case GL_TEXTURE_3D:
61 case GL_TEXTURE_2D_ARRAY:
62 return (context->getClientVersion() >= 3);
63
64 default:
65 return false;
66 }
Jamie Madill35d15012013-10-07 10:46:37 -040067}
68
Shannon Woods4dfed832014-03-17 20:03:39 -040069// 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.
Jamie Madill560a8d82014-05-21 13:06:20 -040072// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040073bool 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
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050093bool 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
Jamie Madill8c96d582014-03-05 15:01:23 -0500106bool 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
Jamie Madill8c96d582014-03-05 15:01:23 -0500114 case GL_PIXEL_PACK_BUFFER:
115 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langcec35902014-04-16 10:52:36 -0400116 return context->getCaps().extensions.pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400117
Shannon Woodsb3801742014-03-27 14:59:19 -0400118 case GL_COPY_READ_BUFFER:
119 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500120 case GL_TRANSFORM_FEEDBACK_BUFFER:
121 case GL_UNIFORM_BUFFER:
122 return (context->getClientVersion() >= 3);
123
124 default:
125 return false;
126 }
127}
128
Jamie Madill70656a62014-03-05 15:01:26 -0500129bool 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
Jamie Madill8c96d582014-03-05 15:01:23 -0500150bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400151{
152 int maxLevel = 0;
153 switch (target)
154 {
155 case GL_TEXTURE_2D: maxLevel = context->getMaximum2DTextureLevel(); 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: maxLevel = context->getMaximumCubeTextureLevel(); break;
163 case GL_TEXTURE_3D: maxLevel = context->getMaximum3DTextureLevel(); break;
164 case GL_TEXTURE_2D_ARRAY: maxLevel = context->getMaximum2DArrayTextureLevel(); break;
165 default: UNREACHABLE();
166 }
167
168 return level < maxLevel;
169}
170
Jamie Madill4fd75c12014-06-23 10:53:54 -0400171bool ValidImageSize(const gl::Context *context, GLenum target, GLint level,
172 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400173{
174 if (level < 0 || width < 0 || height < 0 || depth < 0)
175 {
176 return false;
177 }
178
Jamie Madill4fd75c12014-06-23 10:53:54 -0400179 if (!context->getCaps().extensions.textureNPOT &&
180 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400181 {
182 return false;
183 }
184
185 if (!ValidMipLevel(context, target, level))
186 {
187 return false;
188 }
189
190 return true;
191}
192
Geoff Lang005df412013-10-16 14:12:50 -0400193bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400194{
195 GLuint clientVersion = context->getClientVersion();
196 if (!IsFormatCompressed(internalFormat, clientVersion))
197 {
198 return false;
199 }
200
201 GLint blockWidth = GetCompressedBlockWidth(internalFormat, clientVersion);
202 GLint blockHeight = GetCompressedBlockHeight(internalFormat, clientVersion);
203 if (width < 0 || (width > blockWidth && width % blockWidth != 0) ||
204 height < 0 || (height > blockHeight && height % blockHeight != 0))
205 {
206 return false;
207 }
208
209 return true;
210}
211
Geoff Lang37dde692014-01-31 16:34:54 -0500212bool ValidQueryType(const Context *context, GLenum queryType)
213{
214 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
215 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
216
217 switch (queryType)
218 {
219 case GL_ANY_SAMPLES_PASSED:
220 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
221 return true;
222 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
223 return (context->getClientVersion() >= 3);
224 default:
225 return false;
226 }
227}
228
Geoff Lang48dcae72014-02-05 16:28:24 -0500229bool ValidProgram(const Context *context, GLuint id)
230{
231 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
232 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
233 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
234
235 if (context->getProgram(id) != NULL)
236 {
237 return true;
238 }
239 else if (context->getShader(id) != NULL)
240 {
241 // ID is the wrong type
242 return gl::error(GL_INVALID_OPERATION, false);
243 }
244 else
245 {
246 // No shader/program object has this ID
247 return gl::error(GL_INVALID_VALUE, false);
248 }
249}
250
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400251bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400252 GLenum internalformat, GLsizei width, GLsizei height,
253 bool angleExtension)
254{
255 switch (target)
256 {
257 case GL_RENDERBUFFER:
258 break;
259 default:
260 return gl::error(GL_INVALID_ENUM, false);
261 }
262
263 if (width < 0 || height < 0 || samples < 0)
264 {
265 return gl::error(GL_INVALID_VALUE, false);
266 }
267
Geoff Langcec35902014-04-16 10:52:36 -0400268 const gl::Caps &caps = context->getCaps();
269 if (!gl::IsValidInternalFormat(internalformat, caps.extensions, context->getClientVersion()))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400270 {
271 return gl::error(GL_INVALID_ENUM, false);
272 }
273
274 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
275 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
276 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
277 // internal format must be sized and not an integer format if samples is greater than zero.
278 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
279 {
280 return gl::error(GL_INVALID_ENUM, false);
281 }
282
Geoff Langb2f3d052013-08-13 12:49:27 -0400283 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
284 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400285 {
286 return gl::error(GL_INVALID_OPERATION, false);
287 }
288
Geoff Langcec35902014-04-16 10:52:36 -0400289 const TextureCaps &formatCaps = caps.textureCaps.get(internalformat);
290 if (!formatCaps.colorRendering && !formatCaps.depthRendering && !formatCaps.stencilRendering)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400291 {
292 return gl::error(GL_INVALID_ENUM, false);
293 }
294
295 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
296 {
297 return gl::error(GL_INVALID_VALUE, false);
298 }
299
300 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
301 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
302 // states that samples must be less than or equal to the maximum samples for the specified
303 // internal format.
304 if (angleExtension)
305 {
306 if (samples > context->getMaxSupportedSamples())
307 {
308 return gl::error(GL_INVALID_VALUE, false);
309 }
310 }
311 else
312 {
313 if (samples > context->getMaxSupportedFormatSamples(internalformat))
314 {
315 return gl::error(GL_INVALID_VALUE, false);
316 }
317 }
318
319 GLuint handle = context->getRenderbufferHandle();
320 if (handle == 0)
321 {
322 return gl::error(GL_INVALID_OPERATION, false);
323 }
324
325 return true;
326}
327
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500328bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
329 GLenum renderbuffertarget, GLuint renderbuffer)
330{
331 gl::Framebuffer *framebuffer = context->getTargetFramebuffer(target);
332 GLuint framebufferHandle = context->getTargetFramebufferHandle(target);
333
334 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
335 {
336 return gl::error(GL_INVALID_OPERATION, false);
337 }
338
339 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
340 {
341 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
342
343 if (colorAttachment >= context->getMaximumRenderTargets())
344 {
345 return gl::error(GL_INVALID_VALUE, false);
346 }
347 }
348 else
349 {
350 switch (attachment)
351 {
352 case GL_DEPTH_ATTACHMENT:
353 break;
354 case GL_STENCIL_ATTACHMENT:
355 break;
356 case GL_DEPTH_STENCIL_ATTACHMENT:
357 if (context->getClientVersion() < 3)
358 {
359 return gl::error(GL_INVALID_ENUM, false);
360 }
361 break;
362 default:
363 return gl::error(GL_INVALID_ENUM, false);
364 }
365 }
366
Jamie Madillab9d82c2014-01-21 16:38:14 -0500367 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
368 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
369 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
370 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
371 if (renderbuffer != 0)
372 {
373 if (!context->getRenderbuffer(renderbuffer))
374 {
375 return gl::error(GL_INVALID_OPERATION, false);
376 }
377 }
378
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500379 return true;
380}
381
Jamie Madill3c7fa222014-06-05 13:08:51 -0400382static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400383 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
384 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
385{
386 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
387 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
388 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
389 {
390 return true;
391 }
392 else if (context->isScissorTestEnabled())
393 {
394 int scissorX, scissorY, scissorWidth, scissorHeight;
395 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
396
397 return scissorX > 0 || scissorY > 0 ||
398 scissorWidth < writeBuffer->getWidth() ||
399 scissorHeight < writeBuffer->getHeight();
400 }
401 else
402 {
403 return false;
404 }
405}
406
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400407bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400408 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
409 GLenum filter, bool fromAngleExtension)
410{
411 switch (filter)
412 {
413 case GL_NEAREST:
414 break;
415 case GL_LINEAR:
416 if (fromAngleExtension)
417 {
418 return gl::error(GL_INVALID_ENUM, false);
419 }
420 break;
421 default:
422 return gl::error(GL_INVALID_ENUM, false);
423 }
424
425 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
426 {
427 return gl::error(GL_INVALID_VALUE, false);
428 }
429
430 if (mask == 0)
431 {
432 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
433 // buffers are copied.
434 return false;
435 }
436
437 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
438 {
439 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
440 return gl::error(GL_INVALID_OPERATION, false);
441 }
442
443 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
444 // color buffer, leaving only nearest being unfiltered from above
445 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
446 {
447 return gl::error(GL_INVALID_OPERATION, false);
448 }
449
450 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
451 {
452 if (fromAngleExtension)
453 {
454 ERR("Blits with the same source and destination framebuffer are not supported by this "
455 "implementation.");
456 }
457 return gl::error(GL_INVALID_OPERATION, false);
458 }
459
460 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
461 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
462 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
463 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
464 {
465 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
466 }
467
468 if (drawFramebuffer->getSamples() != 0)
469 {
470 return gl::error(GL_INVALID_OPERATION, false);
471 }
472
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400473 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
474
475 GLuint clientVersion = context->getClientVersion();
476
477 if (mask & GL_COLOR_BUFFER_BIT)
478 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400479 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
480 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400481
482 if (readColorBuffer && drawColorBuffer)
483 {
Geoff Lang005df412013-10-16 14:12:50 -0400484 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400485 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400486
487 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
488 {
489 if (drawFramebuffer->isEnabledColorAttachment(i))
490 {
Geoff Lang005df412013-10-16 14:12:50 -0400491 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400492 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400493
Geoff Langb2f3d052013-08-13 12:49:27 -0400494 // The GL ES 3.0.2 spec (pg 193) states that:
495 // 1) If the read buffer is fixed point format, the draw buffer must be as well
496 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
497 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
498 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
499 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 {
501 return gl::error(GL_INVALID_OPERATION, false);
502 }
503
Geoff Langb2f3d052013-08-13 12:49:27 -0400504 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 {
506 return gl::error(GL_INVALID_OPERATION, false);
507 }
508
Geoff Langb2f3d052013-08-13 12:49:27 -0400509 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400510 {
511 return gl::error(GL_INVALID_OPERATION, false);
512 }
513
Geoff Langb2f3d052013-08-13 12:49:27 -0400514 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 {
516 return gl::error(GL_INVALID_OPERATION, false);
517 }
518 }
519 }
520
Geoff Langb2f3d052013-08-13 12:49:27 -0400521 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400522 {
523 return gl::error(GL_INVALID_OPERATION, false);
524 }
525
526 if (fromAngleExtension)
527 {
528 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
529 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
530 {
531 return gl::error(GL_INVALID_OPERATION, false);
532 }
533
534 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
535 {
536 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
537 {
538 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
539 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
540 {
541 return gl::error(GL_INVALID_OPERATION, false);
542 }
543
544 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
545 {
546 return gl::error(GL_INVALID_OPERATION, false);
547 }
548 }
549 }
Geoff Lang125deab2013-08-09 13:34:16 -0400550 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
551 srcX0, srcY0, srcX1, srcY1,
552 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 {
554 return gl::error(GL_INVALID_OPERATION, false);
555 }
556 }
557 }
558 }
559
560 if (mask & GL_DEPTH_BUFFER_BIT)
561 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400562 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
563 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564
565 if (readDepthBuffer && drawDepthBuffer)
566 {
567 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
568 {
569 return gl::error(GL_INVALID_OPERATION, false);
570 }
571
572 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
573 {
574 return gl::error(GL_INVALID_OPERATION, false);
575 }
576
577 if (fromAngleExtension)
578 {
Geoff Lang125deab2013-08-09 13:34:16 -0400579 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
580 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 {
582 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
583 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
584 }
585
586 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
587 {
588 return gl::error(GL_INVALID_OPERATION, false);
589 }
590 }
591 }
592 }
593
594 if (mask & GL_STENCIL_BUFFER_BIT)
595 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400596 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
597 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400598
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400599 if (readStencilBuffer && drawStencilBuffer)
600 {
601 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
602 {
603 return gl::error(GL_INVALID_OPERATION, false);
604 }
605
606 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
607 {
608 return gl::error(GL_INVALID_OPERATION, false);
609 }
610
611 if (fromAngleExtension)
612 {
Geoff Lang125deab2013-08-09 13:34:16 -0400613 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
614 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 {
616 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
617 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
618 }
619
620 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
621 {
622 return gl::error(GL_INVALID_OPERATION, false);
623 }
624 }
625 }
626 }
627
628 return true;
629}
630
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400631bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400632{
633 switch (pname)
634 {
635 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
636 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
637 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
638 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
639 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
640 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
641 case GL_CURRENT_VERTEX_ATTRIB:
642 return true;
643
644 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
645 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
646 // the same constant.
647 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
648 return true;
649
650 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
651 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
652
653 default:
654 return gl::error(GL_INVALID_ENUM, false);
655 }
656}
657
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400658bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659{
660 switch (pname)
661 {
662 case GL_TEXTURE_WRAP_R:
663 case GL_TEXTURE_SWIZZLE_R:
664 case GL_TEXTURE_SWIZZLE_G:
665 case GL_TEXTURE_SWIZZLE_B:
666 case GL_TEXTURE_SWIZZLE_A:
667 case GL_TEXTURE_BASE_LEVEL:
668 case GL_TEXTURE_MAX_LEVEL:
669 case GL_TEXTURE_COMPARE_MODE:
670 case GL_TEXTURE_COMPARE_FUNC:
671 case GL_TEXTURE_MIN_LOD:
672 case GL_TEXTURE_MAX_LOD:
673 if (context->getClientVersion() < 3)
674 {
675 return gl::error(GL_INVALID_ENUM, false);
676 }
677 break;
678
679 default: break;
680 }
681
682 switch (pname)
683 {
684 case GL_TEXTURE_WRAP_S:
685 case GL_TEXTURE_WRAP_T:
686 case GL_TEXTURE_WRAP_R:
687 switch (param)
688 {
689 case GL_REPEAT:
690 case GL_CLAMP_TO_EDGE:
691 case GL_MIRRORED_REPEAT:
692 return true;
693 default:
694 return gl::error(GL_INVALID_ENUM, false);
695 }
696
697 case GL_TEXTURE_MIN_FILTER:
698 switch (param)
699 {
700 case GL_NEAREST:
701 case GL_LINEAR:
702 case GL_NEAREST_MIPMAP_NEAREST:
703 case GL_LINEAR_MIPMAP_NEAREST:
704 case GL_NEAREST_MIPMAP_LINEAR:
705 case GL_LINEAR_MIPMAP_LINEAR:
706 return true;
707 default:
708 return gl::error(GL_INVALID_ENUM, false);
709 }
710 break;
711
712 case GL_TEXTURE_MAG_FILTER:
713 switch (param)
714 {
715 case GL_NEAREST:
716 case GL_LINEAR:
717 return true;
718 default:
719 return gl::error(GL_INVALID_ENUM, false);
720 }
721 break;
722
723 case GL_TEXTURE_USAGE_ANGLE:
724 switch (param)
725 {
726 case GL_NONE:
727 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
728 return true;
729 default:
730 return gl::error(GL_INVALID_ENUM, false);
731 }
732 break;
733
734 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langcec35902014-04-16 10:52:36 -0400735 if (!context->getCaps().extensions.textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400736 {
737 return gl::error(GL_INVALID_ENUM, false);
738 }
739
740 // we assume the parameter passed to this validation method is truncated, not rounded
741 if (param < 1)
742 {
743 return gl::error(GL_INVALID_VALUE, false);
744 }
745 return true;
746
747 case GL_TEXTURE_MIN_LOD:
748 case GL_TEXTURE_MAX_LOD:
749 // any value is permissible
750 return true;
751
752 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400753 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 switch (param)
755 {
756 case GL_NONE:
757 case GL_COMPARE_REF_TO_TEXTURE:
758 return true;
759 default:
760 return gl::error(GL_INVALID_ENUM, false);
761 }
762 break;
763
764 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400765 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400766 switch (param)
767 {
768 case GL_LEQUAL:
769 case GL_GEQUAL:
770 case GL_LESS:
771 case GL_GREATER:
772 case GL_EQUAL:
773 case GL_NOTEQUAL:
774 case GL_ALWAYS:
775 case GL_NEVER:
776 return true;
777 default:
778 return gl::error(GL_INVALID_ENUM, false);
779 }
780 break;
781
782 case GL_TEXTURE_SWIZZLE_R:
783 case GL_TEXTURE_SWIZZLE_G:
784 case GL_TEXTURE_SWIZZLE_B:
785 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400786 switch (param)
787 {
788 case GL_RED:
789 case GL_GREEN:
790 case GL_BLUE:
791 case GL_ALPHA:
792 case GL_ZERO:
793 case GL_ONE:
794 return true;
795 default:
796 return gl::error(GL_INVALID_ENUM, false);
797 }
798 break;
799
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 case GL_TEXTURE_BASE_LEVEL:
801 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400802 if (param < 0)
803 {
804 return gl::error(GL_INVALID_VALUE, false);
805 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400806 return true;
807
808 default:
809 return gl::error(GL_INVALID_ENUM, false);
810 }
811}
812
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400813bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400814{
815 switch (pname)
816 {
817 case GL_TEXTURE_MIN_FILTER:
818 case GL_TEXTURE_MAG_FILTER:
819 case GL_TEXTURE_WRAP_S:
820 case GL_TEXTURE_WRAP_T:
821 case GL_TEXTURE_WRAP_R:
822 case GL_TEXTURE_MIN_LOD:
823 case GL_TEXTURE_MAX_LOD:
824 case GL_TEXTURE_COMPARE_MODE:
825 case GL_TEXTURE_COMPARE_FUNC:
826 return true;
827
828 default:
829 return gl::error(GL_INVALID_ENUM, false);
830 }
831}
832
Jamie Madill26e91952014-03-05 15:01:27 -0500833bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
834 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
835{
836 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400837 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500838
839 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
840 {
841 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
842 }
843
844 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
845 {
846 return gl::error(GL_INVALID_OPERATION, false);
847 }
848
Jamie Madill893ab082014-05-16 16:56:10 -0400849 if (!framebuffer->getReadColorbuffer())
850 {
851 return gl::error(GL_INVALID_OPERATION, false);
852 }
853
Jamie Madill26e91952014-03-05 15:01:27 -0500854 GLenum currentInternalFormat, currentFormat, currentType;
855 int clientVersion = context->getClientVersion();
856
Jamie Madill893ab082014-05-16 16:56:10 -0400857 context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
Jamie Madill26e91952014-03-05 15:01:27 -0500858
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400859 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
860 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500861
862 if (!(currentFormat == format && currentType == type) && !validReadFormat)
863 {
864 return gl::error(GL_INVALID_OPERATION, false);
865 }
866
867 GLenum sizedInternalFormat = IsSizedInternalFormat(format, clientVersion) ? format :
868 GetSizedInternalFormat(format, type, clientVersion);
869
870 GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, clientVersion, width, context->getPackAlignment());
871 // sized query sanity check
872 if (bufSize)
873 {
874 int requiredSize = outputPitch * height;
875 if (requiredSize > *bufSize)
876 {
877 return gl::error(GL_INVALID_OPERATION, false);
878 }
879 }
880
881 return true;
882}
883
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400884bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
885{
886 if (!ValidQueryType(context, target))
887 {
888 return gl::error(GL_INVALID_ENUM, false);
889 }
890
891 if (id == 0)
892 {
893 return gl::error(GL_INVALID_OPERATION, false);
894 }
895
896 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
897 // of zero, if the active query object name for <target> is non-zero (for the
898 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
899 // the active query for either target is non-zero), if <id> is the name of an
900 // existing query object whose type does not match <target>, or if <id> is the
901 // active query object name for any query type, the error INVALID_OPERATION is
902 // generated.
903
904 // Ensure no other queries are active
905 // NOTE: If other queries than occlusion are supported, we will need to check
906 // separately that:
907 // a) The query ID passed is not the current active query for any target/type
908 // b) There are no active queries for the requested target (and in the case
909 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
910 // no query may be active for either if glBeginQuery targets either.
911 if (context->isQueryActive())
912 {
913 return gl::error(GL_INVALID_OPERATION, false);
914 }
915
916 Query *queryObject = context->getQuery(id, true, target);
917
918 // check that name was obtained with glGenQueries
919 if (!queryObject)
920 {
921 return gl::error(GL_INVALID_OPERATION, false);
922 }
923
924 // check for type mismatch
925 if (queryObject->getType() != target)
926 {
927 return gl::error(GL_INVALID_OPERATION, false);
928 }
929
930 return true;
931}
932
Jamie Madill45c785d2014-05-13 14:09:34 -0400933bool ValidateEndQuery(gl::Context *context, GLenum target)
934{
935 if (!ValidQueryType(context, target))
936 {
937 return gl::error(GL_INVALID_ENUM, false);
938 }
939
940 const Query *queryObject = context->getActiveQuery(target);
941
942 if (queryObject == NULL)
943 {
944 return gl::error(GL_INVALID_OPERATION, false);
945 }
946
947 if (!queryObject->isStarted())
948 {
949 return gl::error(GL_INVALID_OPERATION, false);
950 }
951
952 return true;
953}
954
Jamie Madill36398922014-05-20 14:51:53 -0400955static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
956 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -0400957{
958 if (count < 0)
959 {
960 return gl::error(GL_INVALID_VALUE, false);
961 }
962
Jamie Madilld7c7bb22014-05-20 10:55:54 -0400963 gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
964 if (!programBinary)
965 {
966 return gl::error(GL_INVALID_OPERATION, false);
967 }
968
969 if (location == -1)
970 {
971 // Silently ignore the uniform command
972 return false;
973 }
974
Jamie Madill36398922014-05-20 14:51:53 -0400975 if (!programBinary->isValidUniformLocation(location))
976 {
977 return gl::error(GL_INVALID_OPERATION, false);
978 }
979
980 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
981
982 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
983 if (uniform->elementCount() == 1 && count > 1)
984 {
985 return gl::error(GL_INVALID_OPERATION, false);
986 }
987
988 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -0400989 return true;
990}
991
Jamie Madillaa981bd2014-05-20 10:55:55 -0400992bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
993{
994 // Check for ES3 uniform entry points
995 if (UniformComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
996 {
997 return gl::error(GL_INVALID_OPERATION, false);
998 }
999
Jamie Madill36398922014-05-20 14:51:53 -04001000 LinkedUniform *uniform = NULL;
1001 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1002 {
1003 return false;
1004 }
1005
1006 GLenum targetBoolType = UniformBoolVectorType(uniformType);
1007 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1008 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1009 {
1010 return gl::error(GL_INVALID_OPERATION, false);
1011 }
1012
1013 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001014}
1015
1016bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1017 GLboolean transpose)
1018{
1019 // Check for ES3 uniform entry points
1020 int rows = VariableRowCount(matrixType);
1021 int cols = VariableColumnCount(matrixType);
1022 if (rows != cols && context->getClientVersion() < 3)
1023 {
1024 return gl::error(GL_INVALID_OPERATION, false);
1025 }
1026
1027 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1028 {
1029 return gl::error(GL_INVALID_VALUE, false);
1030 }
1031
Jamie Madill36398922014-05-20 14:51:53 -04001032 LinkedUniform *uniform = NULL;
1033 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1034 {
1035 return false;
1036 }
1037
1038 if (uniform->type != matrixType)
1039 {
1040 return gl::error(GL_INVALID_OPERATION, false);
1041 }
1042
1043 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001044}
1045
Jamie Madill893ab082014-05-16 16:56:10 -04001046bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1047{
1048 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1049 {
1050 return gl::error(GL_INVALID_ENUM, false);
1051 }
1052
1053 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1054 {
1055 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1056
1057 if (colorAttachment >= context->getMaximumRenderTargets())
1058 {
1059 return gl::error(GL_INVALID_OPERATION, false);
1060 }
1061 }
1062
1063 switch (pname)
1064 {
1065 case GL_TEXTURE_BINDING_2D:
1066 case GL_TEXTURE_BINDING_CUBE_MAP:
1067 case GL_TEXTURE_BINDING_3D:
1068 case GL_TEXTURE_BINDING_2D_ARRAY:
1069 if (context->getActiveSampler() >= context->getMaximumCombinedTextureImageUnits())
1070 {
1071 return gl::error(GL_INVALID_OPERATION, false);
1072 }
1073 break;
1074
1075 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1076 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1077 {
1078 Framebuffer *framebuffer = context->getReadFramebuffer();
1079 ASSERT(framebuffer);
1080 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1081 {
1082 return gl::error(GL_INVALID_OPERATION, false);
1083 }
1084
Jamie Madill3c7fa222014-06-05 13:08:51 -04001085 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1086 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001087 {
1088 return gl::error(GL_INVALID_OPERATION, false);
1089 }
1090 }
1091 break;
1092
1093 default:
1094 break;
1095 }
1096
1097 // pname is valid, but there are no parameters to return
1098 if (numParams == 0)
1099 {
1100 return false;
1101 }
1102
1103 return true;
1104}
1105
Jamie Madill560a8d82014-05-21 13:06:20 -04001106bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1107 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1108 GLint border, GLenum *textureFormatOut)
1109{
1110
1111 if (!ValidTexture2DDestinationTarget(context, target))
1112 {
1113 return gl::error(GL_INVALID_ENUM, false);
1114 }
1115
1116 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1117 {
1118 return gl::error(GL_INVALID_VALUE, false);
1119 }
1120
1121 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1122 {
1123 return gl::error(GL_INVALID_VALUE, false);
1124 }
1125
1126 if (border != 0)
1127 {
1128 return gl::error(GL_INVALID_VALUE, false);
1129 }
1130
1131 if (!ValidMipLevel(context, target, level))
1132 {
1133 return gl::error(GL_INVALID_VALUE, false);
1134 }
1135
1136 gl::Framebuffer *framebuffer = context->getReadFramebuffer();
1137 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1138 {
1139 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1140 }
1141
1142 if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
1143 {
1144 return gl::error(GL_INVALID_OPERATION, false);
1145 }
1146
Jamie Madill560a8d82014-05-21 13:06:20 -04001147 gl::Texture *texture = NULL;
1148 GLenum textureInternalFormat = GL_NONE;
1149 bool textureCompressed = false;
1150 bool textureIsDepth = false;
1151 GLint textureLevelWidth = 0;
1152 GLint textureLevelHeight = 0;
1153 GLint textureLevelDepth = 0;
Jamie Madill6f38f822014-06-06 17:12:20 -04001154 int maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001155
1156 switch (target)
1157 {
1158 case GL_TEXTURE_2D:
1159 {
1160 gl::Texture2D *texture2d = context->getTexture2D();
1161 if (texture2d)
1162 {
1163 textureInternalFormat = texture2d->getInternalFormat(level);
1164 textureCompressed = texture2d->isCompressed(level);
1165 textureIsDepth = texture2d->isDepth(level);
1166 textureLevelWidth = texture2d->getWidth(level);
1167 textureLevelHeight = texture2d->getHeight(level);
1168 textureLevelDepth = 1;
1169 texture = texture2d;
Jamie Madill6f38f822014-06-06 17:12:20 -04001170 maxDimension = context->getMaximum2DTextureDimension();
Jamie Madill560a8d82014-05-21 13:06:20 -04001171 }
1172 }
1173 break;
1174
1175 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1176 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1177 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1178 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1179 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1180 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1181 {
1182 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1183 if (textureCube)
1184 {
1185 textureInternalFormat = textureCube->getInternalFormat(target, level);
1186 textureCompressed = textureCube->isCompressed(target, level);
1187 textureIsDepth = false;
1188 textureLevelWidth = textureCube->getWidth(target, level);
1189 textureLevelHeight = textureCube->getHeight(target, level);
1190 textureLevelDepth = 1;
1191 texture = textureCube;
Jamie Madill6f38f822014-06-06 17:12:20 -04001192 maxDimension = context->getMaximumCubeTextureDimension();
Jamie Madill560a8d82014-05-21 13:06:20 -04001193 }
1194 }
1195 break;
1196
1197 case GL_TEXTURE_2D_ARRAY:
1198 {
1199 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1200 if (texture2dArray)
1201 {
1202 textureInternalFormat = texture2dArray->getInternalFormat(level);
1203 textureCompressed = texture2dArray->isCompressed(level);
1204 textureIsDepth = texture2dArray->isDepth(level);
1205 textureLevelWidth = texture2dArray->getWidth(level);
1206 textureLevelHeight = texture2dArray->getHeight(level);
1207 textureLevelDepth = texture2dArray->getLayers(level);
1208 texture = texture2dArray;
Jamie Madill6f38f822014-06-06 17:12:20 -04001209 maxDimension = context->getMaximum2DTextureDimension();
Jamie Madill560a8d82014-05-21 13:06:20 -04001210 }
1211 }
1212 break;
1213
1214 case GL_TEXTURE_3D:
1215 {
1216 gl::Texture3D *texture3d = context->getTexture3D();
1217 if (texture3d)
1218 {
1219 textureInternalFormat = texture3d->getInternalFormat(level);
1220 textureCompressed = texture3d->isCompressed(level);
1221 textureIsDepth = texture3d->isDepth(level);
1222 textureLevelWidth = texture3d->getWidth(level);
1223 textureLevelHeight = texture3d->getHeight(level);
1224 textureLevelDepth = texture3d->getDepth(level);
1225 texture = texture3d;
Jamie Madill6f38f822014-06-06 17:12:20 -04001226 maxDimension = context->getMaximum3DTextureDimension();
Jamie Madill560a8d82014-05-21 13:06:20 -04001227 }
1228 }
1229 break;
1230
1231 default:
1232 return gl::error(GL_INVALID_ENUM, false);
1233 }
1234
1235 if (!texture)
1236 {
1237 return gl::error(GL_INVALID_OPERATION, false);
1238 }
1239
1240 if (texture->isImmutable() && !isSubImage)
1241 {
1242 return gl::error(GL_INVALID_OPERATION, false);
1243 }
1244
1245 if (textureIsDepth)
1246 {
1247 return gl::error(GL_INVALID_OPERATION, false);
1248 }
1249
1250 if (textureCompressed)
1251 {
1252 int clientVersion = context->getClientVersion();
1253 GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat, clientVersion);
1254 GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat, clientVersion);
1255
1256 if (((width % blockWidth) != 0 && width != textureLevelWidth) ||
1257 ((height % blockHeight) != 0 && height != textureLevelHeight))
1258 {
1259 return gl::error(GL_INVALID_OPERATION, false);
1260 }
1261 }
1262
1263 if (isSubImage)
1264 {
1265 if (xoffset + width > textureLevelWidth ||
1266 yoffset + height > textureLevelHeight ||
1267 zoffset >= textureLevelDepth)
1268 {
1269 return gl::error(GL_INVALID_VALUE, false);
1270 }
1271 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001272 else
1273 {
1274 if (IsCubemapTextureTarget(target) && width != height)
1275 {
1276 return gl::error(GL_INVALID_VALUE, false);
1277 }
1278
Geoff Langcec35902014-04-16 10:52:36 -04001279 if (!IsValidInternalFormat(internalformat, context->getCaps().extensions, context->getClientVersion()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001280 {
1281 return gl::error(GL_INVALID_ENUM, false);
1282 }
1283
1284 int maxLevelDimension = (maxDimension >> level);
1285 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1286 {
1287 return gl::error(GL_INVALID_VALUE, false);
1288 }
1289 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001290
1291 *textureFormatOut = textureInternalFormat;
1292 return true;
1293}
1294
Jamie Madill1aeb1312014-06-20 13:21:25 -04001295static bool ValidateDrawBase(const gl::Context *context, GLenum mode, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04001296{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001297 switch (mode)
1298 {
1299 case GL_POINTS:
1300 case GL_LINES:
1301 case GL_LINE_LOOP:
1302 case GL_LINE_STRIP:
1303 case GL_TRIANGLES:
1304 case GL_TRIANGLE_STRIP:
1305 case GL_TRIANGLE_FAN:
1306 break;
1307 default:
1308 return gl::error(GL_INVALID_ENUM, false);
1309 }
1310
Jamie Madill250d33f2014-06-06 17:09:03 -04001311 if (count < 0)
1312 {
1313 return gl::error(GL_INVALID_VALUE, false);
1314 }
1315
Jamie Madill250d33f2014-06-06 17:09:03 -04001316 // Check for mapped buffers
Jamie Madillfd716582014-06-06 17:09:04 -04001317 if (context->hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001318 {
1319 return gl::error(GL_INVALID_OPERATION, false);
1320 }
1321
Jamie Madillac528012014-06-20 13:21:23 -04001322 const gl::DepthStencilState &depthStencilState = context->getDepthStencilState();
1323 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
1324 context->getStencilRef() != context->getStencilBackRef() ||
1325 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1326 {
1327 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1328 // See Section 6.10 of the WebGL 1.0 spec
1329 ERR("This ANGLE implementation does not support separate front/back stencil "
1330 "writemasks, reference values, or stencil mask values.");
1331 return gl::error(GL_INVALID_OPERATION, false);
1332 }
1333
Jamie Madill9efa5812014-06-20 13:21:24 -04001334 if (!context->getCurrentProgram())
1335 {
1336 return gl::error(GL_INVALID_OPERATION, false);
1337 }
1338
1339 gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
1340 if (!programBinary->validateSamplers(NULL))
1341 {
1342 return gl::error(GL_INVALID_OPERATION, false);
1343 }
1344
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001345 const gl::Framebuffer *fbo = context->getDrawFramebuffer();
1346 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1347 {
1348 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
1349 }
1350
Jamie Madill250d33f2014-06-06 17:09:03 -04001351 // No-op if zero count
1352 return (count > 0);
1353}
1354
Jamie Madillfd716582014-06-06 17:09:04 -04001355bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
Jamie Madill250d33f2014-06-06 17:09:03 -04001356{
Jamie Madillfd716582014-06-06 17:09:04 -04001357 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001358 {
1359 return gl::error(GL_INVALID_VALUE, false);
1360 }
1361
Jamie Madillfd716582014-06-06 17:09:04 -04001362 gl::TransformFeedback *curTransformFeedback = context->getCurrentTransformFeedback();
1363 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1364 curTransformFeedback->getDrawMode() != mode)
1365 {
1366 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1367 // that does not match the current transform feedback object's draw mode (if transform feedback
1368 // is active), (3.0.2, section 2.14, pg 86)
1369 return gl::error(GL_INVALID_OPERATION, false);
1370 }
1371
Jamie Madill1aeb1312014-06-20 13:21:25 -04001372 if (!ValidateDrawBase(context, mode, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001373 {
1374 return false;
1375 }
1376
1377 return true;
1378}
1379
1380bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1381{
1382 if (primcount < 0)
1383 {
1384 return gl::error(GL_INVALID_VALUE, false);
1385 }
1386
1387 if (!ValidateDrawArrays(context, mode, first, count))
1388 {
1389 return false;
1390 }
1391
1392 // No-op if zero primitive count
1393 return (primcount > 0);
1394}
1395
1396bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
1397{
Jamie Madill250d33f2014-06-06 17:09:03 -04001398 switch (type)
1399 {
1400 case GL_UNSIGNED_BYTE:
1401 case GL_UNSIGNED_SHORT:
1402 break;
1403 case GL_UNSIGNED_INT:
1404 if (!context->getCaps().extensions.elementIndexUint)
1405 {
1406 return gl::error(GL_INVALID_ENUM, false);
1407 }
1408 break;
1409 default:
1410 return gl::error(GL_INVALID_ENUM, false);
1411 }
1412
1413 gl::TransformFeedback *curTransformFeedback = context->getCurrentTransformFeedback();
1414 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1415 {
1416 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1417 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
1418 return gl::error(GL_INVALID_OPERATION, false);
1419 }
1420
1421 // Check for mapped buffers
Jamie Madillfd716582014-06-06 17:09:04 -04001422 if (context->hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001423 {
1424 return gl::error(GL_INVALID_OPERATION, false);
1425 }
1426
Jamie Madill9efa5812014-06-20 13:21:24 -04001427 gl::VertexArray *vao = context->getCurrentVertexArray();
1428 if (!indices && !vao->getElementArrayBuffer())
1429 {
1430 return gl::error(GL_INVALID_OPERATION, false);
1431 }
1432
Jamie Madill1aeb1312014-06-20 13:21:25 -04001433 if (!ValidateDrawBase(context, mode, count))
Jamie Madillfd716582014-06-06 17:09:04 -04001434 {
1435 return false;
1436 }
1437
1438 return true;
1439}
1440
1441bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsizei count, GLenum type,
1442 const GLvoid *indices, GLsizei primcount)
1443{
1444 if (primcount < 0)
1445 {
1446 return gl::error(GL_INVALID_VALUE, false);
1447 }
1448
1449 if (!ValidateDrawElements(context, mode, count, type, indices))
1450 {
1451 return false;
1452 }
1453
1454 // No-op zero primitive count
1455 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001456}
1457
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001458}