blob: 382653fb6099aef3098adef3dd48d2146d064e9c [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
9#include "libGLESv2/validationES.h"
Jamie Madill26e91952014-03-05 15:01:27 -050010#include "libGLESv2/validationES2.h"
11#include "libGLESv2/validationES3.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040012#include "libGLESv2/Context.h"
13#include "libGLESv2/Texture.h"
14#include "libGLESv2/Framebuffer.h"
Jamie Madille261b442014-06-25 12:42:21 -040015#include "libGLESv2/FramebufferAttachment.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040016#include "libGLESv2/formatutils.h"
17#include "libGLESv2/main.h"
Jamie Madilldb2f14c2014-05-13 13:56:30 -040018#include "libGLESv2/Query.h"
Jamie Madill36398922014-05-20 14:51:53 -040019#include "libGLESv2/ProgramBinary.h"
Jamie Madill250d33f2014-06-06 17:09:03 -040020#include "libGLESv2/TransformFeedback.h"
Jamie Madilld4cfa572014-07-08 10:00:32 -040021#include "libGLESv2/VertexArray.h"
Jamie Madill2b976812014-08-25 15:47:49 -040022#include "libGLESv2/renderer/BufferImpl.h"
Geoff Lange8ebe7f2013-08-05 15:03:13 -040023
24#include "common/mathutil.h"
25#include "common/utilities.h"
26
Jamie Madill9ae396b2014-10-21 17:46:30 -040027// FIXME(jmadill): remove this when we support buffer data caching
28#include "libGLESv2/renderer/d3d/BufferD3D.h"
29
Geoff Lange8ebe7f2013-08-05 15:03:13 -040030namespace gl
31{
32
Geoff Lang0550d032014-01-30 11:29:07 -050033bool ValidCap(const Context *context, GLenum cap)
34{
35 switch (cap)
36 {
37 case GL_CULL_FACE:
38 case GL_POLYGON_OFFSET_FILL:
39 case GL_SAMPLE_ALPHA_TO_COVERAGE:
40 case GL_SAMPLE_COVERAGE:
41 case GL_SCISSOR_TEST:
42 case GL_STENCIL_TEST:
43 case GL_DEPTH_TEST:
44 case GL_BLEND:
45 case GL_DITHER:
46 return true;
47 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
48 case GL_RASTERIZER_DISCARD:
49 return (context->getClientVersion() >= 3);
50 default:
51 return false;
52 }
53}
54
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050055bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040056{
Jamie Madilld7460c72014-01-21 16:38:14 -050057 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040058 {
Jamie Madilld7460c72014-01-21 16:38:14 -050059 case GL_TEXTURE_2D:
60 case GL_TEXTURE_CUBE_MAP:
61 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040062
Jamie Madilld7460c72014-01-21 16:38:14 -050063 case GL_TEXTURE_3D:
64 case GL_TEXTURE_2D_ARRAY:
65 return (context->getClientVersion() >= 3);
66
67 default:
68 return false;
69 }
Jamie Madill35d15012013-10-07 10:46:37 -040070}
71
Shannon Woods4dfed832014-03-17 20:03:39 -040072// This function differs from ValidTextureTarget in that the target must be
73// usable as the destination of a 2D operation-- so a cube face is valid, but
74// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040075// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040076bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
77{
78 switch (target)
79 {
80 case GL_TEXTURE_2D:
81 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
82 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
83 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
84 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
85 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
86 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
87 return true;
88 case GL_TEXTURE_2D_ARRAY:
89 case GL_TEXTURE_3D:
90 return (context->getClientVersion() >= 3);
91 default:
92 return false;
93 }
94}
95
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050096bool ValidFramebufferTarget(GLenum target)
97{
98 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
99
100 switch (target)
101 {
102 case GL_FRAMEBUFFER: return true;
103 case GL_READ_FRAMEBUFFER: return true;
104 case GL_DRAW_FRAMEBUFFER: return true;
105 default: return false;
106 }
107}
108
Jamie Madill8c96d582014-03-05 15:01:23 -0500109bool ValidBufferTarget(const Context *context, GLenum target)
110{
111 switch (target)
112 {
113 case GL_ARRAY_BUFFER:
114 case GL_ELEMENT_ARRAY_BUFFER:
115 return true;
116
Jamie Madill8c96d582014-03-05 15:01:23 -0500117 case GL_PIXEL_PACK_BUFFER:
118 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400119 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400120
Shannon Woodsb3801742014-03-27 14:59:19 -0400121 case GL_COPY_READ_BUFFER:
122 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500123 case GL_TRANSFORM_FEEDBACK_BUFFER:
124 case GL_UNIFORM_BUFFER:
125 return (context->getClientVersion() >= 3);
126
127 default:
128 return false;
129 }
130}
131
Jamie Madill70656a62014-03-05 15:01:26 -0500132bool ValidBufferParameter(const Context *context, GLenum pname)
133{
134 switch (pname)
135 {
136 case GL_BUFFER_USAGE:
137 case GL_BUFFER_SIZE:
138 return true;
139
140 // GL_BUFFER_MAP_POINTER is a special case, and may only be
141 // queried with GetBufferPointerv
142 case GL_BUFFER_ACCESS_FLAGS:
143 case GL_BUFFER_MAPPED:
144 case GL_BUFFER_MAP_OFFSET:
145 case GL_BUFFER_MAP_LENGTH:
146 return (context->getClientVersion() >= 3);
147
148 default:
149 return false;
150 }
151}
152
Jamie Madill8c96d582014-03-05 15:01:23 -0500153bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400154{
Geoff Langaae65a42014-05-26 12:43:44 -0400155 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400156 switch (target)
157 {
Geoff Langaae65a42014-05-26 12:43:44 -0400158 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400159 case GL_TEXTURE_CUBE_MAP:
160 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
161 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
162 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
163 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
164 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400165 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
166 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
167 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400168 default: UNREACHABLE();
169 }
170
Geoff Langaae65a42014-05-26 12:43:44 -0400171 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400172}
173
Geoff Langb1196682014-07-23 13:47:29 -0400174bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400175 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400176{
177 if (level < 0 || width < 0 || height < 0 || depth < 0)
178 {
179 return false;
180 }
181
Geoff Langc0b9ef42014-07-02 10:02:37 -0400182 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400183 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400184 {
185 return false;
186 }
187
188 if (!ValidMipLevel(context, target, level))
189 {
190 return false;
191 }
192
193 return true;
194}
195
Geoff Langb1196682014-07-23 13:47:29 -0400196bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400197{
Geoff Lang5d601382014-07-22 15:14:06 -0400198 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
199 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400200 {
201 return false;
202 }
203
Geoff Lang5d601382014-07-22 15:14:06 -0400204 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
205 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400206 {
207 return false;
208 }
209
210 return true;
211}
212
Geoff Lang37dde692014-01-31 16:34:54 -0500213bool ValidQueryType(const Context *context, GLenum queryType)
214{
215 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
216 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
217
218 switch (queryType)
219 {
220 case GL_ANY_SAMPLES_PASSED:
221 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
222 return true;
223 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
224 return (context->getClientVersion() >= 3);
225 default:
226 return false;
227 }
228}
229
Geoff Langb1196682014-07-23 13:47:29 -0400230bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500231{
232 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
233 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
234 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
235
236 if (context->getProgram(id) != NULL)
237 {
238 return true;
239 }
240 else if (context->getShader(id) != NULL)
241 {
242 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400243 context->recordError(Error(GL_INVALID_OPERATION));
244 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500245 }
246 else
247 {
248 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400249 context->recordError(Error(GL_INVALID_VALUE));
250 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500251 }
252}
253
Geoff Langb1196682014-07-23 13:47:29 -0400254bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400255{
256 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
257 {
258 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
259
Geoff Langaae65a42014-05-26 12:43:44 -0400260 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400261 {
Geoff Langb1196682014-07-23 13:47:29 -0400262 context->recordError(Error(GL_INVALID_VALUE));
263 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400264 }
265 }
266 else
267 {
268 switch (attachment)
269 {
270 case GL_DEPTH_ATTACHMENT:
271 case GL_STENCIL_ATTACHMENT:
272 break;
273
274 case GL_DEPTH_STENCIL_ATTACHMENT:
275 if (context->getClientVersion() < 3)
276 {
Geoff Langb1196682014-07-23 13:47:29 -0400277 context->recordError(Error(GL_INVALID_ENUM));
278 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400279 }
280 break;
281
282 default:
Geoff Langb1196682014-07-23 13:47:29 -0400283 context->recordError(Error(GL_INVALID_ENUM));
284 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400285 }
286 }
287
288 return true;
289}
290
Corentin Walleze0902642014-11-04 12:32:15 -0800291bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples,
292 GLenum internalformat, GLsizei width, GLsizei height)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400293{
294 switch (target)
295 {
296 case GL_RENDERBUFFER:
297 break;
298 default:
Geoff Langb1196682014-07-23 13:47:29 -0400299 context->recordError(Error(GL_INVALID_ENUM));
300 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400301 }
302
303 if (width < 0 || height < 0 || samples < 0)
304 {
Geoff Langb1196682014-07-23 13:47:29 -0400305 context->recordError(Error(GL_INVALID_VALUE));
306 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400307 }
308
Geoff Langd87878e2014-09-19 15:42:59 -0400309 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
310 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400311 {
Geoff Langb1196682014-07-23 13:47:29 -0400312 context->recordError(Error(GL_INVALID_ENUM));
313 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400314 }
315
316 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
317 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
Corentin Walleze0902642014-11-04 12:32:15 -0800318 // only sized internal formats.
Geoff Langd87878e2014-09-19 15:42:59 -0400319 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400320 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400321 {
Geoff Langb1196682014-07-23 13:47:29 -0400322 context->recordError(Error(GL_INVALID_ENUM));
323 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400324 }
325
Geoff Langaae65a42014-05-26 12:43:44 -0400326 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400327 {
Geoff Langb1196682014-07-23 13:47:29 -0400328 context->recordError(Error(GL_INVALID_VALUE));
329 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400330 }
331
Shannon Woods53a94a82014-06-24 15:20:36 -0400332 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400333 if (handle == 0)
334 {
Geoff Langb1196682014-07-23 13:47:29 -0400335 context->recordError(Error(GL_INVALID_OPERATION));
336 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400337 }
338
339 return true;
340}
341
Corentin Walleze0902642014-11-04 12:32:15 -0800342bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples,
343 GLenum internalformat, GLsizei width, GLsizei height)
344{
345 ASSERT(context->getExtensions().framebufferMultisample);
346
347 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
348 // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is
349 // generated.
350 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
351 {
352 context->recordError(Error(GL_INVALID_VALUE));
353 return false;
354 }
355
356 // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
357 // the specified storage. This is different than ES 3.0 in which a sample number higher
358 // than the maximum sample number supported by this format generates a GL_INVALID_VALUE.
359 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
360 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
361 {
362 context->recordError(Error(GL_OUT_OF_MEMORY));
363 return false;
364 }
365
366 return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);
367}
368
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500369bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
370 GLenum renderbuffertarget, GLuint renderbuffer)
371{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400372 if (!ValidFramebufferTarget(target))
373 {
Geoff Langb1196682014-07-23 13:47:29 -0400374 context->recordError(Error(GL_INVALID_ENUM));
375 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400376 }
377
Shannon Woods53a94a82014-06-24 15:20:36 -0400378 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
379 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500380
381 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
382 {
Geoff Langb1196682014-07-23 13:47:29 -0400383 context->recordError(Error(GL_INVALID_OPERATION));
384 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500385 }
386
Jamie Madillb4472272014-07-03 10:38:55 -0400387 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500388 {
Jamie Madillb4472272014-07-03 10:38:55 -0400389 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500390 }
391
Jamie Madillab9d82c2014-01-21 16:38:14 -0500392 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
393 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
394 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
395 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
396 if (renderbuffer != 0)
397 {
398 if (!context->getRenderbuffer(renderbuffer))
399 {
Geoff Langb1196682014-07-23 13:47:29 -0400400 context->recordError(Error(GL_INVALID_OPERATION));
401 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500402 }
403 }
404
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500405 return true;
406}
407
Jamie Madill3c7fa222014-06-05 13:08:51 -0400408static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400409 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
410 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
411{
412 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
413 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
414 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
415 {
416 return true;
417 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400418 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400419 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400420 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400421
Shannon Woods53a94a82014-06-24 15:20:36 -0400422 return scissor.x > 0 || scissor.y > 0 ||
423 scissor.width < writeBuffer->getWidth() ||
424 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400425 }
426 else
427 {
428 return false;
429 }
430}
431
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400432bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400433 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
434 GLenum filter, bool fromAngleExtension)
435{
436 switch (filter)
437 {
438 case GL_NEAREST:
439 break;
440 case GL_LINEAR:
441 if (fromAngleExtension)
442 {
Geoff Langb1196682014-07-23 13:47:29 -0400443 context->recordError(Error(GL_INVALID_ENUM));
444 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400445 }
446 break;
447 default:
Geoff Langb1196682014-07-23 13:47:29 -0400448 context->recordError(Error(GL_INVALID_ENUM));
449 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400450 }
451
452 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
453 {
Geoff Langb1196682014-07-23 13:47:29 -0400454 context->recordError(Error(GL_INVALID_VALUE));
455 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400456 }
457
458 if (mask == 0)
459 {
460 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
461 // buffers are copied.
462 return false;
463 }
464
465 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
466 {
467 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400468 context->recordError(Error(GL_INVALID_OPERATION));
469 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400470 }
471
472 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
473 // color buffer, leaving only nearest being unfiltered from above
474 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
475 {
Geoff Langb1196682014-07-23 13:47:29 -0400476 context->recordError(Error(GL_INVALID_OPERATION));
477 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400478 }
479
Shannon Woods53a94a82014-06-24 15:20:36 -0400480 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400481 {
482 if (fromAngleExtension)
483 {
484 ERR("Blits with the same source and destination framebuffer are not supported by this "
485 "implementation.");
486 }
Geoff Langb1196682014-07-23 13:47:29 -0400487 context->recordError(Error(GL_INVALID_OPERATION));
488 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400489 }
490
Shannon Woods53a94a82014-06-24 15:20:36 -0400491 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
492 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -0500493
494 if (!readFramebuffer || !drawFramebuffer)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400495 {
Geoff Langb1196682014-07-23 13:47:29 -0400496 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
497 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400498 }
499
Jamie Madill48faf802014-11-06 15:27:22 -0500500 if (!readFramebuffer->completeness(context->getData()))
501 {
502 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
503 return false;
504 }
505
506 if (!drawFramebuffer->completeness(context->getData()))
507 {
508 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
509 return false;
510 }
511
512 if (drawFramebuffer->getSamples(context->getData()) != 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 {
Geoff Langb1196682014-07-23 13:47:29 -0400514 context->recordError(Error(GL_INVALID_OPERATION));
515 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400516 }
517
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400518 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
519
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400520 if (mask & GL_COLOR_BUFFER_BIT)
521 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400522 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
523 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524
525 if (readColorBuffer && drawColorBuffer)
526 {
Geoff Lang005df412013-10-16 14:12:50 -0400527 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400528 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400529
530 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
531 {
532 if (drawFramebuffer->isEnabledColorAttachment(i))
533 {
Geoff Lang005df412013-10-16 14:12:50 -0400534 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400535 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400536
Geoff Langb2f3d052013-08-13 12:49:27 -0400537 // The GL ES 3.0.2 spec (pg 193) states that:
538 // 1) If the read buffer is fixed point format, the draw buffer must be as well
539 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
540 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400541 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
542 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400543 {
Geoff Langb1196682014-07-23 13:47:29 -0400544 context->recordError(Error(GL_INVALID_OPERATION));
545 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400546 }
547
Geoff Lang5d601382014-07-22 15:14:06 -0400548 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400549 {
Geoff Langb1196682014-07-23 13:47:29 -0400550 context->recordError(Error(GL_INVALID_OPERATION));
551 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400552 }
553
Geoff Lang5d601382014-07-22 15:14:06 -0400554 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400555 {
Geoff Langb1196682014-07-23 13:47:29 -0400556 context->recordError(Error(GL_INVALID_OPERATION));
557 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400558 }
559
Geoff Langb2f3d052013-08-13 12:49:27 -0400560 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400561 {
Geoff Langb1196682014-07-23 13:47:29 -0400562 context->recordError(Error(GL_INVALID_OPERATION));
563 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564 }
565 }
566 }
567
Geoff Lang5d601382014-07-22 15:14:06 -0400568 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400569 {
Geoff Langb1196682014-07-23 13:47:29 -0400570 context->recordError(Error(GL_INVALID_OPERATION));
571 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400572 }
573
574 if (fromAngleExtension)
575 {
576 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
577 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
578 {
Geoff Langb1196682014-07-23 13:47:29 -0400579 context->recordError(Error(GL_INVALID_OPERATION));
580 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 }
582
583 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
584 {
585 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
586 {
Jamie Madille92a3542014-07-03 10:38:58 -0400587 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
588 ASSERT(attachment);
589
590 if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400591 {
Geoff Langb1196682014-07-23 13:47:29 -0400592 context->recordError(Error(GL_INVALID_OPERATION));
593 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400594 }
595
Jamie Madillf8f18f02014-10-02 10:44:17 -0400596 // Return an error if the destination formats do not match
597 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400598 {
Geoff Langb1196682014-07-23 13:47:29 -0400599 context->recordError(Error(GL_INVALID_OPERATION));
600 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400601 }
602 }
603 }
Jamie Madill48faf802014-11-06 15:27:22 -0500604
605 int readSamples = readFramebuffer->getSamples(context->getData());
606
607 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
608 srcX0, srcY0, srcX1, srcY1,
609 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400610 {
Geoff Langb1196682014-07-23 13:47:29 -0400611 context->recordError(Error(GL_INVALID_OPERATION));
612 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400613 }
614 }
615 }
616 }
617
618 if (mask & GL_DEPTH_BUFFER_BIT)
619 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400620 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
621 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400622
623 if (readDepthBuffer && drawDepthBuffer)
624 {
625 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
626 {
Geoff Langb1196682014-07-23 13:47:29 -0400627 context->recordError(Error(GL_INVALID_OPERATION));
628 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400629 }
630
631 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
632 {
Geoff Langb1196682014-07-23 13:47:29 -0400633 context->recordError(Error(GL_INVALID_OPERATION));
634 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400635 }
636
637 if (fromAngleExtension)
638 {
Geoff Lang125deab2013-08-09 13:34:16 -0400639 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
640 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400641 {
642 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400643 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
644 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400645 }
646
647 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
648 {
Geoff Langb1196682014-07-23 13:47:29 -0400649 context->recordError(Error(GL_INVALID_OPERATION));
650 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400651 }
652 }
653 }
654 }
655
656 if (mask & GL_STENCIL_BUFFER_BIT)
657 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400658 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
659 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400660
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400661 if (readStencilBuffer && drawStencilBuffer)
662 {
663 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
664 {
Geoff Langb1196682014-07-23 13:47:29 -0400665 context->recordError(Error(GL_INVALID_OPERATION));
666 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400667 }
668
669 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
670 {
Geoff Langb1196682014-07-23 13:47:29 -0400671 context->recordError(Error(GL_INVALID_OPERATION));
672 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400673 }
674
675 if (fromAngleExtension)
676 {
Geoff Lang125deab2013-08-09 13:34:16 -0400677 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
678 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400679 {
680 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400681 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
682 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400683 }
684
685 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
686 {
Geoff Langb1196682014-07-23 13:47:29 -0400687 context->recordError(Error(GL_INVALID_OPERATION));
688 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400689 }
690 }
691 }
692 }
693
694 return true;
695}
696
Geoff Langb1196682014-07-23 13:47:29 -0400697bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400698{
699 switch (pname)
700 {
701 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
702 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
703 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
704 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
705 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
706 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
707 case GL_CURRENT_VERTEX_ATTRIB:
708 return true;
709
710 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
711 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
712 // the same constant.
713 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
714 return true;
715
716 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400717 if (context->getClientVersion() < 3)
718 {
719 context->recordError(Error(GL_INVALID_ENUM));
720 return false;
721 }
722 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723
724 default:
Geoff Langb1196682014-07-23 13:47:29 -0400725 context->recordError(Error(GL_INVALID_ENUM));
726 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400727 }
728}
729
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400730bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400731{
732 switch (pname)
733 {
734 case GL_TEXTURE_WRAP_R:
735 case GL_TEXTURE_SWIZZLE_R:
736 case GL_TEXTURE_SWIZZLE_G:
737 case GL_TEXTURE_SWIZZLE_B:
738 case GL_TEXTURE_SWIZZLE_A:
739 case GL_TEXTURE_BASE_LEVEL:
740 case GL_TEXTURE_MAX_LEVEL:
741 case GL_TEXTURE_COMPARE_MODE:
742 case GL_TEXTURE_COMPARE_FUNC:
743 case GL_TEXTURE_MIN_LOD:
744 case GL_TEXTURE_MAX_LOD:
745 if (context->getClientVersion() < 3)
746 {
Geoff Langb1196682014-07-23 13:47:29 -0400747 context->recordError(Error(GL_INVALID_ENUM));
748 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400749 }
750 break;
751
752 default: break;
753 }
754
755 switch (pname)
756 {
757 case GL_TEXTURE_WRAP_S:
758 case GL_TEXTURE_WRAP_T:
759 case GL_TEXTURE_WRAP_R:
760 switch (param)
761 {
762 case GL_REPEAT:
763 case GL_CLAMP_TO_EDGE:
764 case GL_MIRRORED_REPEAT:
765 return true;
766 default:
Geoff Langb1196682014-07-23 13:47:29 -0400767 context->recordError(Error(GL_INVALID_ENUM));
768 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400769 }
770
771 case GL_TEXTURE_MIN_FILTER:
772 switch (param)
773 {
774 case GL_NEAREST:
775 case GL_LINEAR:
776 case GL_NEAREST_MIPMAP_NEAREST:
777 case GL_LINEAR_MIPMAP_NEAREST:
778 case GL_NEAREST_MIPMAP_LINEAR:
779 case GL_LINEAR_MIPMAP_LINEAR:
780 return true;
781 default:
Geoff Langb1196682014-07-23 13:47:29 -0400782 context->recordError(Error(GL_INVALID_ENUM));
783 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400784 }
785 break;
786
787 case GL_TEXTURE_MAG_FILTER:
788 switch (param)
789 {
790 case GL_NEAREST:
791 case GL_LINEAR:
792 return true;
793 default:
Geoff Langb1196682014-07-23 13:47:29 -0400794 context->recordError(Error(GL_INVALID_ENUM));
795 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400796 }
797 break;
798
799 case GL_TEXTURE_USAGE_ANGLE:
800 switch (param)
801 {
802 case GL_NONE:
803 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
804 return true;
805 default:
Geoff Langb1196682014-07-23 13:47:29 -0400806 context->recordError(Error(GL_INVALID_ENUM));
807 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400808 }
809 break;
810
811 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400812 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400813 {
Geoff Langb1196682014-07-23 13:47:29 -0400814 context->recordError(Error(GL_INVALID_ENUM));
815 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400816 }
817
818 // we assume the parameter passed to this validation method is truncated, not rounded
819 if (param < 1)
820 {
Geoff Langb1196682014-07-23 13:47:29 -0400821 context->recordError(Error(GL_INVALID_VALUE));
822 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400823 }
824 return true;
825
826 case GL_TEXTURE_MIN_LOD:
827 case GL_TEXTURE_MAX_LOD:
828 // any value is permissible
829 return true;
830
831 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400832 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833 switch (param)
834 {
835 case GL_NONE:
836 case GL_COMPARE_REF_TO_TEXTURE:
837 return true;
838 default:
Geoff Langb1196682014-07-23 13:47:29 -0400839 context->recordError(Error(GL_INVALID_ENUM));
840 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400841 }
842 break;
843
844 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400845 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846 switch (param)
847 {
848 case GL_LEQUAL:
849 case GL_GEQUAL:
850 case GL_LESS:
851 case GL_GREATER:
852 case GL_EQUAL:
853 case GL_NOTEQUAL:
854 case GL_ALWAYS:
855 case GL_NEVER:
856 return true;
857 default:
Geoff Langb1196682014-07-23 13:47:29 -0400858 context->recordError(Error(GL_INVALID_ENUM));
859 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400860 }
861 break;
862
863 case GL_TEXTURE_SWIZZLE_R:
864 case GL_TEXTURE_SWIZZLE_G:
865 case GL_TEXTURE_SWIZZLE_B:
866 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400867 switch (param)
868 {
869 case GL_RED:
870 case GL_GREEN:
871 case GL_BLUE:
872 case GL_ALPHA:
873 case GL_ZERO:
874 case GL_ONE:
875 return true;
876 default:
Geoff Langb1196682014-07-23 13:47:29 -0400877 context->recordError(Error(GL_INVALID_ENUM));
878 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400879 }
880 break;
881
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400882 case GL_TEXTURE_BASE_LEVEL:
883 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400884 if (param < 0)
885 {
Geoff Langb1196682014-07-23 13:47:29 -0400886 context->recordError(Error(GL_INVALID_VALUE));
887 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400888 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400889 return true;
890
891 default:
Geoff Langb1196682014-07-23 13:47:29 -0400892 context->recordError(Error(GL_INVALID_ENUM));
893 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 }
895}
896
Geoff Langb1196682014-07-23 13:47:29 -0400897bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400898{
899 switch (pname)
900 {
901 case GL_TEXTURE_MIN_FILTER:
902 case GL_TEXTURE_MAG_FILTER:
903 case GL_TEXTURE_WRAP_S:
904 case GL_TEXTURE_WRAP_T:
905 case GL_TEXTURE_WRAP_R:
906 case GL_TEXTURE_MIN_LOD:
907 case GL_TEXTURE_MAX_LOD:
908 case GL_TEXTURE_COMPARE_MODE:
909 case GL_TEXTURE_COMPARE_FUNC:
910 return true;
911
912 default:
Geoff Langb1196682014-07-23 13:47:29 -0400913 context->recordError(Error(GL_INVALID_ENUM));
914 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400915 }
916}
917
Jamie Madill26e91952014-03-05 15:01:27 -0500918bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
919 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
920{
Shannon Woods53a94a82014-06-24 15:20:36 -0400921 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400922 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500923
Jamie Madill48faf802014-11-06 15:27:22 -0500924 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500925 {
Geoff Langb1196682014-07-23 13:47:29 -0400926 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
927 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500928 }
929
Jamie Madill48faf802014-11-06 15:27:22 -0500930 if (context->getState().getReadFramebuffer()->id() != 0 &&
931 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500932 {
Geoff Langb1196682014-07-23 13:47:29 -0400933 context->recordError(Error(GL_INVALID_OPERATION));
934 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500935 }
936
Jamie Madill893ab082014-05-16 16:56:10 -0400937 if (!framebuffer->getReadColorbuffer())
938 {
Geoff Langb1196682014-07-23 13:47:29 -0400939 context->recordError(Error(GL_INVALID_OPERATION));
940 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400941 }
942
Jamie Madill26e91952014-03-05 15:01:27 -0500943 GLenum currentInternalFormat, currentFormat, currentType;
Geoff Lange4a492b2014-06-19 14:14:41 -0400944 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500945
Jamie Madill893ab082014-05-16 16:56:10 -0400946 context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
Jamie Madill26e91952014-03-05 15:01:27 -0500947
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400948 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
949 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500950
951 if (!(currentFormat == format && currentType == type) && !validReadFormat)
952 {
Geoff Langb1196682014-07-23 13:47:29 -0400953 context->recordError(Error(GL_INVALID_OPERATION));
954 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500955 }
956
Geoff Lang5d601382014-07-22 15:14:06 -0400957 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
958 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500959
Geoff Lang5d601382014-07-22 15:14:06 -0400960 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
Jamie Madill26e91952014-03-05 15:01:27 -0500961 // sized query sanity check
962 if (bufSize)
963 {
964 int requiredSize = outputPitch * height;
965 if (requiredSize > *bufSize)
966 {
Geoff Langb1196682014-07-23 13:47:29 -0400967 context->recordError(Error(GL_INVALID_OPERATION));
968 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500969 }
970 }
971
972 return true;
973}
974
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400975bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
976{
977 if (!ValidQueryType(context, target))
978 {
Geoff Langb1196682014-07-23 13:47:29 -0400979 context->recordError(Error(GL_INVALID_ENUM));
980 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400981 }
982
983 if (id == 0)
984 {
Geoff Langb1196682014-07-23 13:47:29 -0400985 context->recordError(Error(GL_INVALID_OPERATION));
986 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400987 }
988
989 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
990 // of zero, if the active query object name for <target> is non-zero (for the
991 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
992 // the active query for either target is non-zero), if <id> is the name of an
993 // existing query object whose type does not match <target>, or if <id> is the
994 // active query object name for any query type, the error INVALID_OPERATION is
995 // generated.
996
997 // Ensure no other queries are active
998 // NOTE: If other queries than occlusion are supported, we will need to check
999 // separately that:
1000 // a) The query ID passed is not the current active query for any target/type
1001 // b) There are no active queries for the requested target (and in the case
1002 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1003 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001004 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001005 {
Geoff Langb1196682014-07-23 13:47:29 -04001006 context->recordError(Error(GL_INVALID_OPERATION));
1007 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001008 }
1009
1010 Query *queryObject = context->getQuery(id, true, target);
1011
1012 // check that name was obtained with glGenQueries
1013 if (!queryObject)
1014 {
Geoff Langb1196682014-07-23 13:47:29 -04001015 context->recordError(Error(GL_INVALID_OPERATION));
1016 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001017 }
1018
1019 // check for type mismatch
1020 if (queryObject->getType() != target)
1021 {
Geoff Langb1196682014-07-23 13:47:29 -04001022 context->recordError(Error(GL_INVALID_OPERATION));
1023 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001024 }
1025
1026 return true;
1027}
1028
Jamie Madill45c785d2014-05-13 14:09:34 -04001029bool ValidateEndQuery(gl::Context *context, GLenum target)
1030{
1031 if (!ValidQueryType(context, target))
1032 {
Geoff Langb1196682014-07-23 13:47:29 -04001033 context->recordError(Error(GL_INVALID_ENUM));
1034 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001035 }
1036
Shannon Woods53a94a82014-06-24 15:20:36 -04001037 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001038
1039 if (queryObject == NULL)
1040 {
Geoff Langb1196682014-07-23 13:47:29 -04001041 context->recordError(Error(GL_INVALID_OPERATION));
1042 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001043 }
1044
Jamie Madill45c785d2014-05-13 14:09:34 -04001045 return true;
1046}
1047
Jamie Madill36398922014-05-20 14:51:53 -04001048static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1049 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001050{
1051 if (count < 0)
1052 {
Geoff Langb1196682014-07-23 13:47:29 -04001053 context->recordError(Error(GL_INVALID_VALUE));
1054 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001055 }
1056
Shannon Woods53a94a82014-06-24 15:20:36 -04001057 gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001058 if (!programBinary)
1059 {
Geoff Langb1196682014-07-23 13:47:29 -04001060 context->recordError(Error(GL_INVALID_OPERATION));
1061 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001062 }
1063
1064 if (location == -1)
1065 {
1066 // Silently ignore the uniform command
1067 return false;
1068 }
1069
Jamie Madill36398922014-05-20 14:51:53 -04001070 if (!programBinary->isValidUniformLocation(location))
1071 {
Geoff Langb1196682014-07-23 13:47:29 -04001072 context->recordError(Error(GL_INVALID_OPERATION));
1073 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001074 }
1075
1076 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1077
1078 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1079 if (uniform->elementCount() == 1 && count > 1)
1080 {
Geoff Langb1196682014-07-23 13:47:29 -04001081 context->recordError(Error(GL_INVALID_OPERATION));
1082 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001083 }
1084
1085 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001086 return true;
1087}
1088
Jamie Madillaa981bd2014-05-20 10:55:55 -04001089bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1090{
1091 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001092 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001093 {
Geoff Langb1196682014-07-23 13:47:29 -04001094 context->recordError(Error(GL_INVALID_OPERATION));
1095 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001096 }
1097
Jamie Madill36398922014-05-20 14:51:53 -04001098 LinkedUniform *uniform = NULL;
1099 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1100 {
1101 return false;
1102 }
1103
Jamie Madillf2575982014-06-25 16:04:54 -04001104 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Jamie Madill36398922014-05-20 14:51:53 -04001105 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1106 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1107 {
Geoff Langb1196682014-07-23 13:47:29 -04001108 context->recordError(Error(GL_INVALID_OPERATION));
1109 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001110 }
1111
1112 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001113}
1114
1115bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1116 GLboolean transpose)
1117{
1118 // Check for ES3 uniform entry points
1119 int rows = VariableRowCount(matrixType);
1120 int cols = VariableColumnCount(matrixType);
1121 if (rows != cols && context->getClientVersion() < 3)
1122 {
Geoff Langb1196682014-07-23 13:47:29 -04001123 context->recordError(Error(GL_INVALID_OPERATION));
1124 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001125 }
1126
1127 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1128 {
Geoff Langb1196682014-07-23 13:47:29 -04001129 context->recordError(Error(GL_INVALID_VALUE));
1130 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001131 }
1132
Jamie Madill36398922014-05-20 14:51:53 -04001133 LinkedUniform *uniform = NULL;
1134 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1135 {
1136 return false;
1137 }
1138
1139 if (uniform->type != matrixType)
1140 {
Geoff Langb1196682014-07-23 13:47:29 -04001141 context->recordError(Error(GL_INVALID_OPERATION));
1142 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001143 }
1144
1145 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001146}
1147
Jamie Madill893ab082014-05-16 16:56:10 -04001148bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1149{
1150 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1151 {
Geoff Langb1196682014-07-23 13:47:29 -04001152 context->recordError(Error(GL_INVALID_ENUM));
1153 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001154 }
1155
1156 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1157 {
1158 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1159
Geoff Langaae65a42014-05-26 12:43:44 -04001160 if (colorAttachment >= context->getCaps().maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001161 {
Geoff Langb1196682014-07-23 13:47:29 -04001162 context->recordError(Error(GL_INVALID_OPERATION));
1163 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001164 }
1165 }
1166
1167 switch (pname)
1168 {
1169 case GL_TEXTURE_BINDING_2D:
1170 case GL_TEXTURE_BINDING_CUBE_MAP:
1171 case GL_TEXTURE_BINDING_3D:
1172 case GL_TEXTURE_BINDING_2D_ARRAY:
Geoff Lang3a61c322014-07-10 13:01:54 -04001173 if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001174 {
Geoff Langb1196682014-07-23 13:47:29 -04001175 context->recordError(Error(GL_INVALID_OPERATION));
1176 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001177 }
1178 break;
1179
1180 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1181 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1182 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001183 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001184 ASSERT(framebuffer);
Jamie Madill48faf802014-11-06 15:27:22 -05001185 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001186 {
Geoff Langb1196682014-07-23 13:47:29 -04001187 context->recordError(Error(GL_INVALID_OPERATION));
1188 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001189 }
1190
Jamie Madill3c7fa222014-06-05 13:08:51 -04001191 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1192 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001193 {
Geoff Langb1196682014-07-23 13:47:29 -04001194 context->recordError(Error(GL_INVALID_OPERATION));
1195 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001196 }
1197 }
1198 break;
1199
1200 default:
1201 break;
1202 }
1203
1204 // pname is valid, but there are no parameters to return
1205 if (numParams == 0)
1206 {
1207 return false;
1208 }
1209
1210 return true;
1211}
1212
Jamie Madill560a8d82014-05-21 13:06:20 -04001213bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1214 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1215 GLint border, GLenum *textureFormatOut)
1216{
1217
1218 if (!ValidTexture2DDestinationTarget(context, target))
1219 {
Geoff Langb1196682014-07-23 13:47:29 -04001220 context->recordError(Error(GL_INVALID_ENUM));
1221 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001222 }
1223
1224 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1225 {
Geoff Langb1196682014-07-23 13:47:29 -04001226 context->recordError(Error(GL_INVALID_VALUE));
1227 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001228 }
1229
1230 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1231 {
Geoff Langb1196682014-07-23 13:47:29 -04001232 context->recordError(Error(GL_INVALID_VALUE));
1233 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001234 }
1235
1236 if (border != 0)
1237 {
Geoff Langb1196682014-07-23 13:47:29 -04001238 context->recordError(Error(GL_INVALID_VALUE));
1239 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001240 }
1241
1242 if (!ValidMipLevel(context, target, level))
1243 {
Geoff Langb1196682014-07-23 13:47:29 -04001244 context->recordError(Error(GL_INVALID_VALUE));
1245 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001246 }
1247
Shannon Woods53a94a82014-06-24 15:20:36 -04001248 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001249 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001250 {
Geoff Langb1196682014-07-23 13:47:29 -04001251 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1252 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001253 }
1254
Jamie Madill48faf802014-11-06 15:27:22 -05001255 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001256 {
Geoff Langb1196682014-07-23 13:47:29 -04001257 context->recordError(Error(GL_INVALID_OPERATION));
1258 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001259 }
1260
Geoff Langaae65a42014-05-26 12:43:44 -04001261 const gl::Caps &caps = context->getCaps();
1262
Jamie Madill560a8d82014-05-21 13:06:20 -04001263 gl::Texture *texture = NULL;
1264 GLenum textureInternalFormat = GL_NONE;
Jamie Madill560a8d82014-05-21 13:06:20 -04001265 GLint textureLevelWidth = 0;
1266 GLint textureLevelHeight = 0;
1267 GLint textureLevelDepth = 0;
Geoff Langaae65a42014-05-26 12:43:44 -04001268 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001269
1270 switch (target)
1271 {
1272 case GL_TEXTURE_2D:
1273 {
1274 gl::Texture2D *texture2d = context->getTexture2D();
1275 if (texture2d)
1276 {
1277 textureInternalFormat = texture2d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001278 textureLevelWidth = texture2d->getWidth(level);
1279 textureLevelHeight = texture2d->getHeight(level);
1280 textureLevelDepth = 1;
1281 texture = texture2d;
Geoff Langaae65a42014-05-26 12:43:44 -04001282 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001283 }
1284 }
1285 break;
1286
1287 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1288 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1289 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1290 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1291 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1292 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1293 {
1294 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1295 if (textureCube)
1296 {
1297 textureInternalFormat = textureCube->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001298 textureLevelWidth = textureCube->getWidth(target, level);
1299 textureLevelHeight = textureCube->getHeight(target, level);
1300 textureLevelDepth = 1;
1301 texture = textureCube;
Geoff Langaae65a42014-05-26 12:43:44 -04001302 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001303 }
1304 }
1305 break;
1306
1307 case GL_TEXTURE_2D_ARRAY:
1308 {
1309 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1310 if (texture2dArray)
1311 {
1312 textureInternalFormat = texture2dArray->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001313 textureLevelWidth = texture2dArray->getWidth(level);
1314 textureLevelHeight = texture2dArray->getHeight(level);
1315 textureLevelDepth = texture2dArray->getLayers(level);
1316 texture = texture2dArray;
Geoff Langaae65a42014-05-26 12:43:44 -04001317 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001318 }
1319 }
1320 break;
1321
1322 case GL_TEXTURE_3D:
1323 {
1324 gl::Texture3D *texture3d = context->getTexture3D();
1325 if (texture3d)
1326 {
1327 textureInternalFormat = texture3d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001328 textureLevelWidth = texture3d->getWidth(level);
1329 textureLevelHeight = texture3d->getHeight(level);
1330 textureLevelDepth = texture3d->getDepth(level);
1331 texture = texture3d;
Geoff Langaae65a42014-05-26 12:43:44 -04001332 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001333 }
1334 }
1335 break;
1336
1337 default:
Geoff Langb1196682014-07-23 13:47:29 -04001338 context->recordError(Error(GL_INVALID_ENUM));
1339 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001340 }
1341
1342 if (!texture)
1343 {
Geoff Langb1196682014-07-23 13:47:29 -04001344 context->recordError(Error(GL_INVALID_OPERATION));
1345 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001346 }
1347
1348 if (texture->isImmutable() && !isSubImage)
1349 {
Geoff Langb1196682014-07-23 13:47:29 -04001350 context->recordError(Error(GL_INVALID_OPERATION));
1351 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001352 }
1353
Geoff Lang5d601382014-07-22 15:14:06 -04001354 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1355
1356 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 {
Geoff Langb1196682014-07-23 13:47:29 -04001358 context->recordError(Error(GL_INVALID_OPERATION));
1359 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001360 }
1361
Geoff Lang5d601382014-07-22 15:14:06 -04001362 if (formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04001363 {
Geoff Lang5d601382014-07-22 15:14:06 -04001364 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1365 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
Jamie Madill560a8d82014-05-21 13:06:20 -04001366 {
Geoff Langb1196682014-07-23 13:47:29 -04001367 context->recordError(Error(GL_INVALID_OPERATION));
1368 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001369 }
1370 }
1371
1372 if (isSubImage)
1373 {
1374 if (xoffset + width > textureLevelWidth ||
1375 yoffset + height > textureLevelHeight ||
1376 zoffset >= textureLevelDepth)
1377 {
Geoff Langb1196682014-07-23 13:47:29 -04001378 context->recordError(Error(GL_INVALID_VALUE));
1379 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001380 }
1381 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001382 else
1383 {
1384 if (IsCubemapTextureTarget(target) && width != height)
1385 {
Geoff Langb1196682014-07-23 13:47:29 -04001386 context->recordError(Error(GL_INVALID_VALUE));
1387 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001388 }
1389
Geoff Lang5d601382014-07-22 15:14:06 -04001390 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001391 {
Geoff Langb1196682014-07-23 13:47:29 -04001392 context->recordError(Error(GL_INVALID_ENUM));
1393 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001394 }
1395
1396 int maxLevelDimension = (maxDimension >> level);
1397 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1398 {
Geoff Langb1196682014-07-23 13:47:29 -04001399 context->recordError(Error(GL_INVALID_VALUE));
1400 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001401 }
1402 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001403
1404 *textureFormatOut = textureInternalFormat;
1405 return true;
1406}
1407
Geoff Langb1196682014-07-23 13:47:29 -04001408static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001409{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001410 switch (mode)
1411 {
1412 case GL_POINTS:
1413 case GL_LINES:
1414 case GL_LINE_LOOP:
1415 case GL_LINE_STRIP:
1416 case GL_TRIANGLES:
1417 case GL_TRIANGLE_STRIP:
1418 case GL_TRIANGLE_FAN:
1419 break;
1420 default:
Geoff Langb1196682014-07-23 13:47:29 -04001421 context->recordError(Error(GL_INVALID_ENUM));
1422 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001423 }
1424
Jamie Madill250d33f2014-06-06 17:09:03 -04001425 if (count < 0)
1426 {
Geoff Langb1196682014-07-23 13:47:29 -04001427 context->recordError(Error(GL_INVALID_VALUE));
1428 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001429 }
1430
Geoff Langb1196682014-07-23 13:47:29 -04001431 const State &state = context->getState();
1432
Jamie Madill250d33f2014-06-06 17:09:03 -04001433 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001434 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001435 {
Geoff Langb1196682014-07-23 13:47:29 -04001436 context->recordError(Error(GL_INVALID_OPERATION));
1437 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001438 }
1439
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001440 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001441 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001442 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001443 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1444 {
1445 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1446 // See Section 6.10 of the WebGL 1.0 spec
1447 ERR("This ANGLE implementation does not support separate front/back stencil "
1448 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001449 context->recordError(Error(GL_INVALID_OPERATION));
1450 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001451 }
1452
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001453 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001454 if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001455 {
Geoff Langb1196682014-07-23 13:47:29 -04001456 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1457 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001458 }
1459
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001460 if (state.getCurrentProgramId() == 0)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001461 {
Geoff Langb1196682014-07-23 13:47:29 -04001462 context->recordError(Error(GL_INVALID_OPERATION));
1463 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001464 }
1465
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001466 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
Brandon Jones43a53e22014-08-28 16:23:22 -07001467 if (!programBinary->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001468 {
Geoff Langb1196682014-07-23 13:47:29 -04001469 context->recordError(Error(GL_INVALID_OPERATION));
1470 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001471 }
1472
Jamie Madill2b976812014-08-25 15:47:49 -04001473 // Buffer validations
1474 const VertexArray *vao = state.getVertexArray();
1475 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1476 {
1477 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1478 bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
1479 if (attribActive && attrib.enabled)
1480 {
1481 gl::Buffer *buffer = attrib.buffer.get();
1482
1483 if (buffer)
1484 {
1485 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1486 GLint64 maxVertexElement = 0;
1487
1488 if (attrib.divisor > 0)
1489 {
1490 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1491 }
1492 else
1493 {
1494 maxVertexElement = static_cast<GLint64>(maxVertex);
1495 }
1496
1497 GLint64 attribDataSize = maxVertexElement * attribStride;
1498
1499 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1500 // We can return INVALID_OPERATION if our vertex attribute does not have
1501 // enough backing data.
1502 if (attribDataSize > buffer->getSize())
1503 {
Geoff Langb1196682014-07-23 13:47:29 -04001504 context->recordError(Error(GL_INVALID_OPERATION));
1505 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001506 }
1507 }
1508 else if (attrib.pointer == NULL)
1509 {
1510 // This is an application error that would normally result in a crash,
1511 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001512 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1513 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001514 }
1515 }
1516 }
1517
Jamie Madill250d33f2014-06-06 17:09:03 -04001518 // No-op if zero count
1519 return (count > 0);
1520}
1521
Geoff Langb1196682014-07-23 13:47:29 -04001522bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001523{
Jamie Madillfd716582014-06-06 17:09:04 -04001524 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001525 {
Geoff Langb1196682014-07-23 13:47:29 -04001526 context->recordError(Error(GL_INVALID_VALUE));
1527 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001528 }
1529
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001530 const State &state = context->getState();
1531 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001532 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1533 curTransformFeedback->getDrawMode() != mode)
1534 {
1535 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1536 // that does not match the current transform feedback object's draw mode (if transform feedback
1537 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001538 context->recordError(Error(GL_INVALID_OPERATION));
1539 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001540 }
1541
Geoff Langb1196682014-07-23 13:47:29 -04001542 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001543 {
1544 return false;
1545 }
1546
1547 return true;
1548}
1549
Geoff Langb1196682014-07-23 13:47:29 -04001550bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001551{
1552 if (primcount < 0)
1553 {
Geoff Langb1196682014-07-23 13:47:29 -04001554 context->recordError(Error(GL_INVALID_VALUE));
1555 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001556 }
1557
Jamie Madill2b976812014-08-25 15:47:49 -04001558 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001559 {
1560 return false;
1561 }
1562
1563 // No-op if zero primitive count
1564 return (primcount > 0);
1565}
1566
Geoff Lang87a93302014-09-16 13:29:43 -04001567static bool ValidateDrawInstancedANGLE(Context *context)
1568{
1569 // Verify there is at least one active attribute with a divisor of zero
1570 const gl::State& state = context->getState();
1571
1572 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1573
1574 const VertexArray *vao = state.getVertexArray();
1575 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1576 {
1577 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1578 bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
1579 if (active && attrib.divisor == 0)
1580 {
1581 return true;
1582 }
1583 }
1584
1585 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1586 "has a divisor of zero."));
1587 return false;
1588}
1589
1590bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1591{
1592 if (!ValidateDrawInstancedANGLE(context))
1593 {
1594 return false;
1595 }
1596
1597 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1598}
1599
Geoff Langb1196682014-07-23 13:47:29 -04001600bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001601 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001602{
Jamie Madill250d33f2014-06-06 17:09:03 -04001603 switch (type)
1604 {
1605 case GL_UNSIGNED_BYTE:
1606 case GL_UNSIGNED_SHORT:
1607 break;
1608 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001609 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001610 {
Geoff Langb1196682014-07-23 13:47:29 -04001611 context->recordError(Error(GL_INVALID_ENUM));
1612 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001613 }
1614 break;
1615 default:
Geoff Langb1196682014-07-23 13:47:29 -04001616 context->recordError(Error(GL_INVALID_ENUM));
1617 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001618 }
1619
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001620 const State &state = context->getState();
1621
1622 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001623 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1624 {
1625 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1626 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001627 context->recordError(Error(GL_INVALID_OPERATION));
1628 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001629 }
1630
1631 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001632 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001633 {
Geoff Langb1196682014-07-23 13:47:29 -04001634 context->recordError(Error(GL_INVALID_OPERATION));
1635 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001636 }
1637
Jamie Madill2b976812014-08-25 15:47:49 -04001638 const gl::VertexArray *vao = state.getVertexArray();
1639 const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1640 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001641 {
Geoff Langb1196682014-07-23 13:47:29 -04001642 context->recordError(Error(GL_INVALID_OPERATION));
1643 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001644 }
1645
Jamie Madillae3000b2014-08-25 15:47:51 -04001646 if (elementArrayBuffer)
1647 {
1648 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1649
1650 GLint64 offset = reinterpret_cast<GLint64>(indices);
1651 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1652
1653 // check for integer overflows
1654 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1655 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1656 {
Geoff Langb1196682014-07-23 13:47:29 -04001657 context->recordError(Error(GL_OUT_OF_MEMORY));
1658 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001659 }
1660
1661 // Check for reading past the end of the bound buffer object
1662 if (byteCount > elementArrayBuffer->getSize())
1663 {
Geoff Langb1196682014-07-23 13:47:29 -04001664 context->recordError(Error(GL_INVALID_OPERATION));
1665 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001666 }
1667 }
1668 else if (!indices)
1669 {
1670 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001671 context->recordError(Error(GL_INVALID_OPERATION));
1672 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001673 }
1674
Jamie Madill2b976812014-08-25 15:47:49 -04001675 // Use max index to validate if our vertex buffers are large enough for the pull.
1676 // TODO: offer fast path, with disabled index validation.
1677 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1678 if (elementArrayBuffer)
1679 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001680 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Jamie Madill2b976812014-08-25 15:47:49 -04001681 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1682 {
Jamie Madill9ae396b2014-10-21 17:46:30 -04001683 // FIXME(jmadill): Use buffer data caching instead of the D3D back-end
1684 rx::BufferD3D *bufferD3D = rx::BufferD3D::makeBufferD3D(elementArrayBuffer->getImplementation());
Geoff Langc8d297a2014-09-19 11:09:08 -04001685 const uint8_t *dataPointer = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -04001686 Error error = bufferD3D->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001687 if (error.isError())
1688 {
1689 context->recordError(error);
1690 return false;
1691 }
1692
1693 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001694 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1695 }
1696 }
1697 else
1698 {
1699 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1700 }
1701
Geoff Langb1196682014-07-23 13:47:29 -04001702 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001703 {
1704 return false;
1705 }
1706
1707 return true;
1708}
1709
Geoff Langb1196682014-07-23 13:47:29 -04001710bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001711 GLenum mode, GLsizei count, GLenum type,
1712 const GLvoid *indices, GLsizei primcount,
1713 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001714{
1715 if (primcount < 0)
1716 {
Geoff Langb1196682014-07-23 13:47:29 -04001717 context->recordError(Error(GL_INVALID_VALUE));
1718 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001719 }
1720
Jamie Madill2b976812014-08-25 15:47:49 -04001721 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001722 {
1723 return false;
1724 }
1725
1726 // No-op zero primitive count
1727 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001728}
1729
Geoff Lang87a93302014-09-16 13:29:43 -04001730bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1731 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1732{
1733 if (!ValidateDrawInstancedANGLE(context))
1734 {
1735 return false;
1736 }
1737
1738 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1739}
1740
Geoff Langb1196682014-07-23 13:47:29 -04001741bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001742 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001743{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001744 if (!ValidFramebufferTarget(target))
1745 {
Geoff Langb1196682014-07-23 13:47:29 -04001746 context->recordError(Error(GL_INVALID_ENUM));
1747 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001748 }
1749
1750 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001751 {
1752 return false;
1753 }
1754
Jamie Madill55ec3b12014-07-03 10:38:57 -04001755 if (texture != 0)
1756 {
1757 gl::Texture *tex = context->getTexture(texture);
1758
1759 if (tex == NULL)
1760 {
Geoff Langb1196682014-07-23 13:47:29 -04001761 context->recordError(Error(GL_INVALID_OPERATION));
1762 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001763 }
1764
1765 if (level < 0)
1766 {
Geoff Langb1196682014-07-23 13:47:29 -04001767 context->recordError(Error(GL_INVALID_VALUE));
1768 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001769 }
1770 }
1771
Shannon Woods53a94a82014-06-24 15:20:36 -04001772 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1773 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001774
1775 if (framebufferHandle == 0 || !framebuffer)
1776 {
Geoff Langb1196682014-07-23 13:47:29 -04001777 context->recordError(Error(GL_INVALID_OPERATION));
1778 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001779 }
1780
1781 return true;
1782}
1783
Geoff Langb1196682014-07-23 13:47:29 -04001784bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001785 GLenum textarget, GLuint texture, GLint level)
1786{
1787 // Attachments are required to be bound to level 0 in ES2
1788 if (context->getClientVersion() < 3 && level != 0)
1789 {
Geoff Langb1196682014-07-23 13:47:29 -04001790 context->recordError(Error(GL_INVALID_VALUE));
1791 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001792 }
1793
1794 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001795 {
1796 return false;
1797 }
1798
Jamie Madill55ec3b12014-07-03 10:38:57 -04001799 if (texture != 0)
1800 {
1801 gl::Texture *tex = context->getTexture(texture);
1802 ASSERT(tex);
1803
Jamie Madill2a6564e2014-07-11 09:53:19 -04001804 const gl::Caps &caps = context->getCaps();
1805
Jamie Madill55ec3b12014-07-03 10:38:57 -04001806 switch (textarget)
1807 {
1808 case GL_TEXTURE_2D:
1809 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001810 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001811 {
Geoff Langb1196682014-07-23 13:47:29 -04001812 context->recordError(Error(GL_INVALID_VALUE));
1813 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001814 }
1815 if (tex->getTarget() != GL_TEXTURE_2D)
1816 {
Geoff Langb1196682014-07-23 13:47:29 -04001817 context->recordError(Error(GL_INVALID_OPERATION));
1818 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001819 }
1820 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1821 if (tex2d->isCompressed(level))
1822 {
Geoff Langb1196682014-07-23 13:47:29 -04001823 context->recordError(Error(GL_INVALID_OPERATION));
1824 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001825 }
1826 }
1827 break;
1828
1829 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1830 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1831 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1832 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1833 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1834 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1835 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001836 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001837 {
Geoff Langb1196682014-07-23 13:47:29 -04001838 context->recordError(Error(GL_INVALID_VALUE));
1839 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001840 }
1841 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1842 {
Geoff Langb1196682014-07-23 13:47:29 -04001843 context->recordError(Error(GL_INVALID_OPERATION));
1844 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001845 }
1846 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1847 if (texcube->isCompressed(textarget, level))
1848 {
Geoff Langb1196682014-07-23 13:47:29 -04001849 context->recordError(Error(GL_INVALID_OPERATION));
1850 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001851 }
1852 }
1853 break;
1854
1855 default:
Geoff Langb1196682014-07-23 13:47:29 -04001856 context->recordError(Error(GL_INVALID_ENUM));
1857 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001858 }
1859 }
1860
Jamie Madill570f7c82014-07-03 10:38:54 -04001861 return true;
1862}
1863
Geoff Langb1196682014-07-23 13:47:29 -04001864bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001865{
1866 if (program == 0)
1867 {
Geoff Langb1196682014-07-23 13:47:29 -04001868 context->recordError(Error(GL_INVALID_VALUE));
1869 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001870 }
1871
Shannon Woods4de4fd62014-11-07 16:22:02 -05001872 if (!ValidProgram(context, program))
1873 {
1874 return false;
1875 }
1876
Jamie Madill0063c512014-08-25 15:47:53 -04001877 gl::Program *programObject = context->getProgram(program);
1878
1879 if (!programObject || !programObject->isLinked())
1880 {
Geoff Langb1196682014-07-23 13:47:29 -04001881 context->recordError(Error(GL_INVALID_OPERATION));
1882 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001883 }
1884
1885 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
1886 if (!programBinary)
1887 {
Geoff Langb1196682014-07-23 13:47:29 -04001888 context->recordError(Error(GL_INVALID_OPERATION));
1889 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001890 }
1891
Jamie Madill549c7fd2014-08-25 15:47:56 -04001892 if (!programBinary->isValidUniformLocation(location))
1893 {
Geoff Langb1196682014-07-23 13:47:29 -04001894 context->recordError(Error(GL_INVALID_OPERATION));
1895 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001896 }
1897
Jamie Madill0063c512014-08-25 15:47:53 -04001898 return true;
1899}
1900
Geoff Langb1196682014-07-23 13:47:29 -04001901bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001902{
1903 return ValidateGetUniformBase(context, program, location);
1904}
1905
Geoff Langb1196682014-07-23 13:47:29 -04001906bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001907{
Jamie Madill78f41802014-08-25 15:47:55 -04001908 return ValidateGetUniformBase(context, program, location);
1909}
1910
Geoff Langb1196682014-07-23 13:47:29 -04001911static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001912{
1913 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001914 {
Jamie Madill78f41802014-08-25 15:47:55 -04001915 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001916 }
1917
Jamie Madilla502c742014-08-28 17:19:13 -04001918 gl::Program *programObject = context->getProgram(program);
1919 ASSERT(programObject);
1920 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
Jamie Madill0063c512014-08-25 15:47:53 -04001921
Jamie Madill78f41802014-08-25 15:47:55 -04001922 // sized queries -- ensure the provided buffer is large enough
1923 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1924 size_t requiredBytes = VariableExternalSize(uniform->type);
1925 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001926 {
Geoff Langb1196682014-07-23 13:47:29 -04001927 context->recordError(Error(GL_INVALID_OPERATION));
1928 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001929 }
1930
1931 return true;
1932}
1933
Geoff Langb1196682014-07-23 13:47:29 -04001934bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001935{
Jamie Madill78f41802014-08-25 15:47:55 -04001936 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001937}
1938
Geoff Langb1196682014-07-23 13:47:29 -04001939bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001940{
Jamie Madill78f41802014-08-25 15:47:55 -04001941 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001942}
1943
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001944}