blob: 3f144bda77434e168ed8daa218df4d978e559370 [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
Geoff Lange8ebe7f2013-08-05 15:03:13 -04003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES.h: Validation functions for generic OpenGL ES entry point parameters
8
Geoff Lang2b5420c2014-11-19 14:20:15 -05009#include "libANGLE/validationES.h"
10#include "libANGLE/validationES2.h"
11#include "libANGLE/validationES3.h"
12#include "libANGLE/Context.h"
13#include "libANGLE/Texture.h"
14#include "libANGLE/Framebuffer.h"
15#include "libANGLE/FramebufferAttachment.h"
16#include "libANGLE/formatutils.h"
17#include "libANGLE/Query.h"
Geoff Lang7dd2e102014-11-10 15:19:26 -050018#include "libANGLE/Program.h"
19#include "libANGLE/Uniform.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/TransformFeedback.h"
21#include "libANGLE/VertexArray.h"
22#include "libANGLE/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
Geoff Lang2b5420c2014-11-19 14:20:15 -050028#include "libANGLE/renderer/d3d/BufferD3D.h"
Jamie Madill9ae396b2014-10-21 17:46:30 -040029
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 {
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500576 FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer();
577 if (!readColorAttachment ||
578 (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
579 readColorAttachment->type() != GL_RENDERBUFFER &&
580 readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400581 {
Geoff Langb1196682014-07-23 13:47:29 -0400582 context->recordError(Error(GL_INVALID_OPERATION));
583 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400584 }
585
586 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
587 {
588 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
589 {
Jamie Madille92a3542014-07-03 10:38:58 -0400590 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
591 ASSERT(attachment);
592
Geoff Lang6a1e6b92014-11-06 10:42:45 -0500593 if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex()->type == GL_TEXTURE_2D) &&
594 attachment->type() != GL_RENDERBUFFER &&
595 attachment->type() != GL_FRAMEBUFFER_DEFAULT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 {
Geoff Langb1196682014-07-23 13:47:29 -0400597 context->recordError(Error(GL_INVALID_OPERATION));
598 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400599 }
600
Jamie Madillf8f18f02014-10-02 10:44:17 -0400601 // Return an error if the destination formats do not match
602 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400603 {
Geoff Langb1196682014-07-23 13:47:29 -0400604 context->recordError(Error(GL_INVALID_OPERATION));
605 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400606 }
607 }
608 }
Jamie Madill48faf802014-11-06 15:27:22 -0500609
610 int readSamples = readFramebuffer->getSamples(context->getData());
611
612 if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
613 srcX0, srcY0, srcX1, srcY1,
614 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400615 {
Geoff Langb1196682014-07-23 13:47:29 -0400616 context->recordError(Error(GL_INVALID_OPERATION));
617 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400618 }
619 }
620 }
621 }
622
623 if (mask & GL_DEPTH_BUFFER_BIT)
624 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400625 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
626 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627
628 if (readDepthBuffer && drawDepthBuffer)
629 {
630 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
631 {
Geoff Langb1196682014-07-23 13:47:29 -0400632 context->recordError(Error(GL_INVALID_OPERATION));
633 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400634 }
635
636 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
637 {
Geoff Langb1196682014-07-23 13:47:29 -0400638 context->recordError(Error(GL_INVALID_OPERATION));
639 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400640 }
641
642 if (fromAngleExtension)
643 {
Geoff Lang125deab2013-08-09 13:34:16 -0400644 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
645 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400646 {
647 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400648 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
649 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400650 }
651
652 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
653 {
Geoff Langb1196682014-07-23 13:47:29 -0400654 context->recordError(Error(GL_INVALID_OPERATION));
655 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400656 }
657 }
658 }
659 }
660
661 if (mask & GL_STENCIL_BUFFER_BIT)
662 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400663 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
664 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400666 if (readStencilBuffer && drawStencilBuffer)
667 {
668 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
669 {
Geoff Langb1196682014-07-23 13:47:29 -0400670 context->recordError(Error(GL_INVALID_OPERATION));
671 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400672 }
673
674 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
675 {
Geoff Langb1196682014-07-23 13:47:29 -0400676 context->recordError(Error(GL_INVALID_OPERATION));
677 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400678 }
679
680 if (fromAngleExtension)
681 {
Geoff Lang125deab2013-08-09 13:34:16 -0400682 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
683 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400684 {
685 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400686 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
687 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400688 }
689
690 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
691 {
Geoff Langb1196682014-07-23 13:47:29 -0400692 context->recordError(Error(GL_INVALID_OPERATION));
693 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400694 }
695 }
696 }
697 }
698
699 return true;
700}
701
Geoff Langb1196682014-07-23 13:47:29 -0400702bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400703{
704 switch (pname)
705 {
706 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
707 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
708 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
709 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
710 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
711 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
712 case GL_CURRENT_VERTEX_ATTRIB:
713 return true;
714
715 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
716 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
717 // the same constant.
718 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
719 return true;
720
721 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400722 if (context->getClientVersion() < 3)
723 {
724 context->recordError(Error(GL_INVALID_ENUM));
725 return false;
726 }
727 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400728
729 default:
Geoff Langb1196682014-07-23 13:47:29 -0400730 context->recordError(Error(GL_INVALID_ENUM));
731 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400732 }
733}
734
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400735bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400736{
737 switch (pname)
738 {
739 case GL_TEXTURE_WRAP_R:
740 case GL_TEXTURE_SWIZZLE_R:
741 case GL_TEXTURE_SWIZZLE_G:
742 case GL_TEXTURE_SWIZZLE_B:
743 case GL_TEXTURE_SWIZZLE_A:
744 case GL_TEXTURE_BASE_LEVEL:
745 case GL_TEXTURE_MAX_LEVEL:
746 case GL_TEXTURE_COMPARE_MODE:
747 case GL_TEXTURE_COMPARE_FUNC:
748 case GL_TEXTURE_MIN_LOD:
749 case GL_TEXTURE_MAX_LOD:
750 if (context->getClientVersion() < 3)
751 {
Geoff Langb1196682014-07-23 13:47:29 -0400752 context->recordError(Error(GL_INVALID_ENUM));
753 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400754 }
755 break;
756
757 default: break;
758 }
759
760 switch (pname)
761 {
762 case GL_TEXTURE_WRAP_S:
763 case GL_TEXTURE_WRAP_T:
764 case GL_TEXTURE_WRAP_R:
765 switch (param)
766 {
767 case GL_REPEAT:
768 case GL_CLAMP_TO_EDGE:
769 case GL_MIRRORED_REPEAT:
770 return true;
771 default:
Geoff Langb1196682014-07-23 13:47:29 -0400772 context->recordError(Error(GL_INVALID_ENUM));
773 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400774 }
775
776 case GL_TEXTURE_MIN_FILTER:
777 switch (param)
778 {
779 case GL_NEAREST:
780 case GL_LINEAR:
781 case GL_NEAREST_MIPMAP_NEAREST:
782 case GL_LINEAR_MIPMAP_NEAREST:
783 case GL_NEAREST_MIPMAP_LINEAR:
784 case GL_LINEAR_MIPMAP_LINEAR:
785 return true;
786 default:
Geoff Langb1196682014-07-23 13:47:29 -0400787 context->recordError(Error(GL_INVALID_ENUM));
788 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400789 }
790 break;
791
792 case GL_TEXTURE_MAG_FILTER:
793 switch (param)
794 {
795 case GL_NEAREST:
796 case GL_LINEAR:
797 return true;
798 default:
Geoff Langb1196682014-07-23 13:47:29 -0400799 context->recordError(Error(GL_INVALID_ENUM));
800 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400801 }
802 break;
803
804 case GL_TEXTURE_USAGE_ANGLE:
805 switch (param)
806 {
807 case GL_NONE:
808 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
809 return true;
810 default:
Geoff Langb1196682014-07-23 13:47:29 -0400811 context->recordError(Error(GL_INVALID_ENUM));
812 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400813 }
814 break;
815
816 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400817 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400818 {
Geoff Langb1196682014-07-23 13:47:29 -0400819 context->recordError(Error(GL_INVALID_ENUM));
820 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400821 }
822
823 // we assume the parameter passed to this validation method is truncated, not rounded
824 if (param < 1)
825 {
Geoff Langb1196682014-07-23 13:47:29 -0400826 context->recordError(Error(GL_INVALID_VALUE));
827 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400828 }
829 return true;
830
831 case GL_TEXTURE_MIN_LOD:
832 case GL_TEXTURE_MAX_LOD:
833 // any value is permissible
834 return true;
835
836 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400837 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838 switch (param)
839 {
840 case GL_NONE:
841 case GL_COMPARE_REF_TO_TEXTURE:
842 return true;
843 default:
Geoff Langb1196682014-07-23 13:47:29 -0400844 context->recordError(Error(GL_INVALID_ENUM));
845 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400846 }
847 break;
848
849 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400850 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400851 switch (param)
852 {
853 case GL_LEQUAL:
854 case GL_GEQUAL:
855 case GL_LESS:
856 case GL_GREATER:
857 case GL_EQUAL:
858 case GL_NOTEQUAL:
859 case GL_ALWAYS:
860 case GL_NEVER:
861 return true;
862 default:
Geoff Langb1196682014-07-23 13:47:29 -0400863 context->recordError(Error(GL_INVALID_ENUM));
864 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400865 }
866 break;
867
868 case GL_TEXTURE_SWIZZLE_R:
869 case GL_TEXTURE_SWIZZLE_G:
870 case GL_TEXTURE_SWIZZLE_B:
871 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400872 switch (param)
873 {
874 case GL_RED:
875 case GL_GREEN:
876 case GL_BLUE:
877 case GL_ALPHA:
878 case GL_ZERO:
879 case GL_ONE:
880 return true;
881 default:
Geoff Langb1196682014-07-23 13:47:29 -0400882 context->recordError(Error(GL_INVALID_ENUM));
883 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400884 }
885 break;
886
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400887 case GL_TEXTURE_BASE_LEVEL:
888 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400889 if (param < 0)
890 {
Geoff Langb1196682014-07-23 13:47:29 -0400891 context->recordError(Error(GL_INVALID_VALUE));
892 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400893 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400894 return true;
895
896 default:
Geoff Langb1196682014-07-23 13:47:29 -0400897 context->recordError(Error(GL_INVALID_ENUM));
898 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400899 }
900}
901
Geoff Langb1196682014-07-23 13:47:29 -0400902bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400903{
904 switch (pname)
905 {
906 case GL_TEXTURE_MIN_FILTER:
907 case GL_TEXTURE_MAG_FILTER:
908 case GL_TEXTURE_WRAP_S:
909 case GL_TEXTURE_WRAP_T:
910 case GL_TEXTURE_WRAP_R:
911 case GL_TEXTURE_MIN_LOD:
912 case GL_TEXTURE_MAX_LOD:
913 case GL_TEXTURE_COMPARE_MODE:
914 case GL_TEXTURE_COMPARE_FUNC:
915 return true;
916
917 default:
Geoff Langb1196682014-07-23 13:47:29 -0400918 context->recordError(Error(GL_INVALID_ENUM));
919 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400920 }
921}
922
Jamie Madill26e91952014-03-05 15:01:27 -0500923bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
924 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
925{
Shannon Woods53a94a82014-06-24 15:20:36 -0400926 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400927 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500928
Jamie Madill48faf802014-11-06 15:27:22 -0500929 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill26e91952014-03-05 15:01:27 -0500930 {
Geoff Langb1196682014-07-23 13:47:29 -0400931 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
932 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500933 }
934
Jamie Madill48faf802014-11-06 15:27:22 -0500935 if (context->getState().getReadFramebuffer()->id() != 0 &&
936 framebuffer->getSamples(context->getData()) != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500937 {
Geoff Langb1196682014-07-23 13:47:29 -0400938 context->recordError(Error(GL_INVALID_OPERATION));
939 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500940 }
941
Jamie Madill893ab082014-05-16 16:56:10 -0400942 if (!framebuffer->getReadColorbuffer())
943 {
Geoff Langb1196682014-07-23 13:47:29 -0400944 context->recordError(Error(GL_INVALID_OPERATION));
945 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400946 }
947
Jamie Madill26e91952014-03-05 15:01:27 -0500948 GLenum currentInternalFormat, currentFormat, currentType;
Geoff Lange4a492b2014-06-19 14:14:41 -0400949 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500950
Jamie Madill893ab082014-05-16 16:56:10 -0400951 context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
Jamie Madill26e91952014-03-05 15:01:27 -0500952
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400953 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
954 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500955
956 if (!(currentFormat == format && currentType == type) && !validReadFormat)
957 {
Geoff Langb1196682014-07-23 13:47:29 -0400958 context->recordError(Error(GL_INVALID_OPERATION));
959 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500960 }
961
Geoff Lang5d601382014-07-22 15:14:06 -0400962 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
963 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500964
Geoff Lang5d601382014-07-22 15:14:06 -0400965 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
Jamie Madill26e91952014-03-05 15:01:27 -0500966 // sized query sanity check
967 if (bufSize)
968 {
969 int requiredSize = outputPitch * height;
970 if (requiredSize > *bufSize)
971 {
Geoff Langb1196682014-07-23 13:47:29 -0400972 context->recordError(Error(GL_INVALID_OPERATION));
973 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500974 }
975 }
976
977 return true;
978}
979
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400980bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
981{
982 if (!ValidQueryType(context, target))
983 {
Geoff Langb1196682014-07-23 13:47:29 -0400984 context->recordError(Error(GL_INVALID_ENUM));
985 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400986 }
987
988 if (id == 0)
989 {
Geoff Langb1196682014-07-23 13:47:29 -0400990 context->recordError(Error(GL_INVALID_OPERATION));
991 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400992 }
993
994 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
995 // of zero, if the active query object name for <target> is non-zero (for the
996 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
997 // the active query for either target is non-zero), if <id> is the name of an
998 // existing query object whose type does not match <target>, or if <id> is the
999 // active query object name for any query type, the error INVALID_OPERATION is
1000 // generated.
1001
1002 // Ensure no other queries are active
1003 // NOTE: If other queries than occlusion are supported, we will need to check
1004 // separately that:
1005 // a) The query ID passed is not the current active query for any target/type
1006 // b) There are no active queries for the requested target (and in the case
1007 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
1008 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -04001009 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001010 {
Geoff Langb1196682014-07-23 13:47:29 -04001011 context->recordError(Error(GL_INVALID_OPERATION));
1012 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001013 }
1014
1015 Query *queryObject = context->getQuery(id, true, target);
1016
1017 // check that name was obtained with glGenQueries
1018 if (!queryObject)
1019 {
Geoff Langb1196682014-07-23 13:47:29 -04001020 context->recordError(Error(GL_INVALID_OPERATION));
1021 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001022 }
1023
1024 // check for type mismatch
1025 if (queryObject->getType() != target)
1026 {
Geoff Langb1196682014-07-23 13:47:29 -04001027 context->recordError(Error(GL_INVALID_OPERATION));
1028 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001029 }
1030
1031 return true;
1032}
1033
Jamie Madill45c785d2014-05-13 14:09:34 -04001034bool ValidateEndQuery(gl::Context *context, GLenum target)
1035{
1036 if (!ValidQueryType(context, target))
1037 {
Geoff Langb1196682014-07-23 13:47:29 -04001038 context->recordError(Error(GL_INVALID_ENUM));
1039 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001040 }
1041
Shannon Woods53a94a82014-06-24 15:20:36 -04001042 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001043
1044 if (queryObject == NULL)
1045 {
Geoff Langb1196682014-07-23 13:47:29 -04001046 context->recordError(Error(GL_INVALID_OPERATION));
1047 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001048 }
1049
Jamie Madill45c785d2014-05-13 14:09:34 -04001050 return true;
1051}
1052
Jamie Madill36398922014-05-20 14:51:53 -04001053static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1054 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001055{
1056 if (count < 0)
1057 {
Geoff Langb1196682014-07-23 13:47:29 -04001058 context->recordError(Error(GL_INVALID_VALUE));
1059 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001060 }
1061
Geoff Lang7dd2e102014-11-10 15:19:26 -05001062 gl::Program *program = context->getState().getProgram();
1063 if (!program)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001064 {
Geoff Langb1196682014-07-23 13:47:29 -04001065 context->recordError(Error(GL_INVALID_OPERATION));
1066 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001067 }
1068
1069 if (location == -1)
1070 {
1071 // Silently ignore the uniform command
1072 return false;
1073 }
1074
Geoff Lang7dd2e102014-11-10 15:19:26 -05001075 if (!program->isValidUniformLocation(location))
Jamie Madill36398922014-05-20 14:51:53 -04001076 {
Geoff Langb1196682014-07-23 13:47:29 -04001077 context->recordError(Error(GL_INVALID_OPERATION));
1078 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001079 }
1080
Geoff Lang7dd2e102014-11-10 15:19:26 -05001081 LinkedUniform *uniform = program->getUniformByLocation(location);
Jamie Madill36398922014-05-20 14:51:53 -04001082
1083 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1084 if (uniform->elementCount() == 1 && count > 1)
1085 {
Geoff Langb1196682014-07-23 13:47:29 -04001086 context->recordError(Error(GL_INVALID_OPERATION));
1087 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001088 }
1089
1090 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001091 return true;
1092}
1093
Jamie Madillaa981bd2014-05-20 10:55:55 -04001094bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1095{
1096 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001097 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001098 {
Geoff Langb1196682014-07-23 13:47:29 -04001099 context->recordError(Error(GL_INVALID_OPERATION));
1100 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001101 }
1102
Jamie Madill36398922014-05-20 14:51:53 -04001103 LinkedUniform *uniform = NULL;
1104 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1105 {
1106 return false;
1107 }
1108
Jamie Madillf2575982014-06-25 16:04:54 -04001109 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Geoff Lang2ec386b2014-12-03 14:44:38 -05001110 bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT);
Jamie Madill36398922014-05-20 14:51:53 -04001111 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1112 {
Geoff Langb1196682014-07-23 13:47:29 -04001113 context->recordError(Error(GL_INVALID_OPERATION));
1114 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001115 }
1116
1117 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001118}
1119
1120bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1121 GLboolean transpose)
1122{
1123 // Check for ES3 uniform entry points
1124 int rows = VariableRowCount(matrixType);
1125 int cols = VariableColumnCount(matrixType);
1126 if (rows != cols && context->getClientVersion() < 3)
1127 {
Geoff Langb1196682014-07-23 13:47:29 -04001128 context->recordError(Error(GL_INVALID_OPERATION));
1129 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001130 }
1131
1132 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1133 {
Geoff Langb1196682014-07-23 13:47:29 -04001134 context->recordError(Error(GL_INVALID_VALUE));
1135 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001136 }
1137
Jamie Madill36398922014-05-20 14:51:53 -04001138 LinkedUniform *uniform = NULL;
1139 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1140 {
1141 return false;
1142 }
1143
1144 if (uniform->type != matrixType)
1145 {
Geoff Langb1196682014-07-23 13:47:29 -04001146 context->recordError(Error(GL_INVALID_OPERATION));
1147 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001148 }
1149
1150 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001151}
1152
Jamie Madill893ab082014-05-16 16:56:10 -04001153bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1154{
1155 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1156 {
Geoff Langb1196682014-07-23 13:47:29 -04001157 context->recordError(Error(GL_INVALID_ENUM));
1158 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001159 }
1160
1161 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1162 {
1163 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1164
Geoff Langaae65a42014-05-26 12:43:44 -04001165 if (colorAttachment >= context->getCaps().maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001166 {
Geoff Langb1196682014-07-23 13:47:29 -04001167 context->recordError(Error(GL_INVALID_OPERATION));
1168 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001169 }
1170 }
1171
1172 switch (pname)
1173 {
1174 case GL_TEXTURE_BINDING_2D:
1175 case GL_TEXTURE_BINDING_CUBE_MAP:
1176 case GL_TEXTURE_BINDING_3D:
1177 case GL_TEXTURE_BINDING_2D_ARRAY:
Geoff Lang3a61c322014-07-10 13:01:54 -04001178 if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001179 {
Geoff Langb1196682014-07-23 13:47:29 -04001180 context->recordError(Error(GL_INVALID_OPERATION));
1181 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001182 }
1183 break;
1184
1185 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1186 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1187 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001188 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001189 ASSERT(framebuffer);
Jamie Madill48faf802014-11-06 15:27:22 -05001190 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill893ab082014-05-16 16:56:10 -04001191 {
Geoff Langb1196682014-07-23 13:47:29 -04001192 context->recordError(Error(GL_INVALID_OPERATION));
1193 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001194 }
1195
Jamie Madill3c7fa222014-06-05 13:08:51 -04001196 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1197 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001198 {
Geoff Langb1196682014-07-23 13:47:29 -04001199 context->recordError(Error(GL_INVALID_OPERATION));
1200 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001201 }
1202 }
1203 break;
1204
1205 default:
1206 break;
1207 }
1208
1209 // pname is valid, but there are no parameters to return
1210 if (numParams == 0)
1211 {
1212 return false;
1213 }
1214
1215 return true;
1216}
1217
Jamie Madill560a8d82014-05-21 13:06:20 -04001218bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1219 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1220 GLint border, GLenum *textureFormatOut)
1221{
1222
1223 if (!ValidTexture2DDestinationTarget(context, target))
1224 {
Geoff Langb1196682014-07-23 13:47:29 -04001225 context->recordError(Error(GL_INVALID_ENUM));
1226 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001227 }
1228
1229 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1230 {
Geoff Langb1196682014-07-23 13:47:29 -04001231 context->recordError(Error(GL_INVALID_VALUE));
1232 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001233 }
1234
1235 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1236 {
Geoff Langb1196682014-07-23 13:47:29 -04001237 context->recordError(Error(GL_INVALID_VALUE));
1238 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001239 }
1240
1241 if (border != 0)
1242 {
Geoff Langb1196682014-07-23 13:47:29 -04001243 context->recordError(Error(GL_INVALID_VALUE));
1244 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001245 }
1246
1247 if (!ValidMipLevel(context, target, level))
1248 {
Geoff Langb1196682014-07-23 13:47:29 -04001249 context->recordError(Error(GL_INVALID_VALUE));
1250 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001251 }
1252
Shannon Woods53a94a82014-06-24 15:20:36 -04001253 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001254 if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill560a8d82014-05-21 13:06:20 -04001255 {
Geoff Langb1196682014-07-23 13:47:29 -04001256 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1257 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001258 }
1259
Jamie Madill48faf802014-11-06 15:27:22 -05001260 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001261 {
Geoff Langb1196682014-07-23 13:47:29 -04001262 context->recordError(Error(GL_INVALID_OPERATION));
1263 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001264 }
1265
Geoff Langaae65a42014-05-26 12:43:44 -04001266 const gl::Caps &caps = context->getCaps();
1267
Jamie Madill560a8d82014-05-21 13:06:20 -04001268 gl::Texture *texture = NULL;
1269 GLenum textureInternalFormat = GL_NONE;
Jamie Madill560a8d82014-05-21 13:06:20 -04001270 GLint textureLevelWidth = 0;
1271 GLint textureLevelHeight = 0;
1272 GLint textureLevelDepth = 0;
Geoff Langaae65a42014-05-26 12:43:44 -04001273 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001274
1275 switch (target)
1276 {
1277 case GL_TEXTURE_2D:
1278 {
1279 gl::Texture2D *texture2d = context->getTexture2D();
1280 if (texture2d)
1281 {
1282 textureInternalFormat = texture2d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001283 textureLevelWidth = texture2d->getWidth(level);
1284 textureLevelHeight = texture2d->getHeight(level);
1285 textureLevelDepth = 1;
1286 texture = texture2d;
Geoff Langaae65a42014-05-26 12:43:44 -04001287 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001288 }
1289 }
1290 break;
1291
1292 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1293 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1294 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1295 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1296 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1297 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1298 {
1299 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1300 if (textureCube)
1301 {
1302 textureInternalFormat = textureCube->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001303 textureLevelWidth = textureCube->getWidth(target, level);
1304 textureLevelHeight = textureCube->getHeight(target, level);
1305 textureLevelDepth = 1;
1306 texture = textureCube;
Geoff Langaae65a42014-05-26 12:43:44 -04001307 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001308 }
1309 }
1310 break;
1311
1312 case GL_TEXTURE_2D_ARRAY:
1313 {
1314 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1315 if (texture2dArray)
1316 {
1317 textureInternalFormat = texture2dArray->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001318 textureLevelWidth = texture2dArray->getWidth(level);
1319 textureLevelHeight = texture2dArray->getHeight(level);
1320 textureLevelDepth = texture2dArray->getLayers(level);
1321 texture = texture2dArray;
Geoff Langaae65a42014-05-26 12:43:44 -04001322 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001323 }
1324 }
1325 break;
1326
1327 case GL_TEXTURE_3D:
1328 {
1329 gl::Texture3D *texture3d = context->getTexture3D();
1330 if (texture3d)
1331 {
1332 textureInternalFormat = texture3d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001333 textureLevelWidth = texture3d->getWidth(level);
1334 textureLevelHeight = texture3d->getHeight(level);
1335 textureLevelDepth = texture3d->getDepth(level);
1336 texture = texture3d;
Geoff Langaae65a42014-05-26 12:43:44 -04001337 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001338 }
1339 }
1340 break;
1341
1342 default:
Geoff Langb1196682014-07-23 13:47:29 -04001343 context->recordError(Error(GL_INVALID_ENUM));
1344 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001345 }
1346
1347 if (!texture)
1348 {
Geoff Langb1196682014-07-23 13:47:29 -04001349 context->recordError(Error(GL_INVALID_OPERATION));
1350 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001351 }
1352
1353 if (texture->isImmutable() && !isSubImage)
1354 {
Geoff Langb1196682014-07-23 13:47:29 -04001355 context->recordError(Error(GL_INVALID_OPERATION));
1356 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001357 }
1358
Geoff Lang5d601382014-07-22 15:14:06 -04001359 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1360
1361 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001362 {
Geoff Langb1196682014-07-23 13:47:29 -04001363 context->recordError(Error(GL_INVALID_OPERATION));
1364 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001365 }
1366
Geoff Lang5d601382014-07-22 15:14:06 -04001367 if (formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04001368 {
Geoff Lang5d601382014-07-22 15:14:06 -04001369 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1370 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
Jamie Madill560a8d82014-05-21 13:06:20 -04001371 {
Geoff Langb1196682014-07-23 13:47:29 -04001372 context->recordError(Error(GL_INVALID_OPERATION));
1373 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001374 }
1375 }
1376
1377 if (isSubImage)
1378 {
1379 if (xoffset + width > textureLevelWidth ||
1380 yoffset + height > textureLevelHeight ||
1381 zoffset >= textureLevelDepth)
1382 {
Geoff Langb1196682014-07-23 13:47:29 -04001383 context->recordError(Error(GL_INVALID_VALUE));
1384 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001385 }
1386 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001387 else
1388 {
1389 if (IsCubemapTextureTarget(target) && width != height)
1390 {
Geoff Langb1196682014-07-23 13:47:29 -04001391 context->recordError(Error(GL_INVALID_VALUE));
1392 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001393 }
1394
Geoff Lang5d601382014-07-22 15:14:06 -04001395 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001396 {
Geoff Langb1196682014-07-23 13:47:29 -04001397 context->recordError(Error(GL_INVALID_ENUM));
1398 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001399 }
1400
1401 int maxLevelDimension = (maxDimension >> level);
1402 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1403 {
Geoff Langb1196682014-07-23 13:47:29 -04001404 context->recordError(Error(GL_INVALID_VALUE));
1405 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001406 }
1407 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001408
1409 *textureFormatOut = textureInternalFormat;
1410 return true;
1411}
1412
Geoff Langb1196682014-07-23 13:47:29 -04001413static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001414{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001415 switch (mode)
1416 {
1417 case GL_POINTS:
1418 case GL_LINES:
1419 case GL_LINE_LOOP:
1420 case GL_LINE_STRIP:
1421 case GL_TRIANGLES:
1422 case GL_TRIANGLE_STRIP:
1423 case GL_TRIANGLE_FAN:
1424 break;
1425 default:
Geoff Langb1196682014-07-23 13:47:29 -04001426 context->recordError(Error(GL_INVALID_ENUM));
1427 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001428 }
1429
Jamie Madill250d33f2014-06-06 17:09:03 -04001430 if (count < 0)
1431 {
Geoff Langb1196682014-07-23 13:47:29 -04001432 context->recordError(Error(GL_INVALID_VALUE));
1433 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001434 }
1435
Geoff Langb1196682014-07-23 13:47:29 -04001436 const State &state = context->getState();
1437
Jamie Madill250d33f2014-06-06 17:09:03 -04001438 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001439 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001440 {
Geoff Langb1196682014-07-23 13:47:29 -04001441 context->recordError(Error(GL_INVALID_OPERATION));
1442 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001443 }
1444
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001445 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001446 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001447 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001448 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1449 {
1450 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1451 // See Section 6.10 of the WebGL 1.0 spec
1452 ERR("This ANGLE implementation does not support separate front/back stencil "
1453 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001454 context->recordError(Error(GL_INVALID_OPERATION));
1455 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001456 }
1457
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001458 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Jamie Madill48faf802014-11-06 15:27:22 -05001459 if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE)
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001460 {
Geoff Langb1196682014-07-23 13:47:29 -04001461 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1462 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001463 }
1464
Geoff Lang7dd2e102014-11-10 15:19:26 -05001465 gl::Program *program = state.getProgram();
1466 if (!program)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001467 {
Geoff Langb1196682014-07-23 13:47:29 -04001468 context->recordError(Error(GL_INVALID_OPERATION));
1469 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001470 }
1471
Geoff Lang7dd2e102014-11-10 15:19:26 -05001472 if (!program->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001473 {
Geoff Langb1196682014-07-23 13:47:29 -04001474 context->recordError(Error(GL_INVALID_OPERATION));
1475 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001476 }
1477
Jamie Madill2b976812014-08-25 15:47:49 -04001478 // Buffer validations
1479 const VertexArray *vao = state.getVertexArray();
1480 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1481 {
1482 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001483 bool attribActive = (program->getSemanticIndex(attributeIndex) != -1);
Jamie Madill2b976812014-08-25 15:47:49 -04001484 if (attribActive && attrib.enabled)
1485 {
1486 gl::Buffer *buffer = attrib.buffer.get();
1487
1488 if (buffer)
1489 {
1490 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1491 GLint64 maxVertexElement = 0;
1492
1493 if (attrib.divisor > 0)
1494 {
1495 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1496 }
1497 else
1498 {
1499 maxVertexElement = static_cast<GLint64>(maxVertex);
1500 }
1501
1502 GLint64 attribDataSize = maxVertexElement * attribStride;
1503
1504 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1505 // We can return INVALID_OPERATION if our vertex attribute does not have
1506 // enough backing data.
1507 if (attribDataSize > buffer->getSize())
1508 {
Geoff Langb1196682014-07-23 13:47:29 -04001509 context->recordError(Error(GL_INVALID_OPERATION));
1510 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001511 }
1512 }
1513 else if (attrib.pointer == NULL)
1514 {
1515 // This is an application error that would normally result in a crash,
1516 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001517 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1518 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001519 }
1520 }
1521 }
1522
Jamie Madill250d33f2014-06-06 17:09:03 -04001523 // No-op if zero count
1524 return (count > 0);
1525}
1526
Geoff Langb1196682014-07-23 13:47:29 -04001527bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001528{
Jamie Madillfd716582014-06-06 17:09:04 -04001529 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001530 {
Geoff Langb1196682014-07-23 13:47:29 -04001531 context->recordError(Error(GL_INVALID_VALUE));
1532 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001533 }
1534
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001535 const State &state = context->getState();
1536 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001537 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1538 curTransformFeedback->getDrawMode() != mode)
1539 {
1540 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1541 // that does not match the current transform feedback object's draw mode (if transform feedback
1542 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001543 context->recordError(Error(GL_INVALID_OPERATION));
1544 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001545 }
1546
Geoff Langb1196682014-07-23 13:47:29 -04001547 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001548 {
1549 return false;
1550 }
1551
1552 return true;
1553}
1554
Geoff Langb1196682014-07-23 13:47:29 -04001555bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001556{
1557 if (primcount < 0)
1558 {
Geoff Langb1196682014-07-23 13:47:29 -04001559 context->recordError(Error(GL_INVALID_VALUE));
1560 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001561 }
1562
Jamie Madill2b976812014-08-25 15:47:49 -04001563 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001564 {
1565 return false;
1566 }
1567
1568 // No-op if zero primitive count
1569 return (primcount > 0);
1570}
1571
Geoff Lang87a93302014-09-16 13:29:43 -04001572static bool ValidateDrawInstancedANGLE(Context *context)
1573{
1574 // Verify there is at least one active attribute with a divisor of zero
1575 const gl::State& state = context->getState();
1576
Geoff Lang7dd2e102014-11-10 15:19:26 -05001577 gl::Program *program = state.getProgram();
Geoff Lang87a93302014-09-16 13:29:43 -04001578
1579 const VertexArray *vao = state.getVertexArray();
1580 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1581 {
1582 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
Geoff Lang7dd2e102014-11-10 15:19:26 -05001583 bool active = (program->getSemanticIndex(attributeIndex) != -1);
Geoff Lang87a93302014-09-16 13:29:43 -04001584 if (active && attrib.divisor == 0)
1585 {
1586 return true;
1587 }
1588 }
1589
1590 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1591 "has a divisor of zero."));
1592 return false;
1593}
1594
1595bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1596{
1597 if (!ValidateDrawInstancedANGLE(context))
1598 {
1599 return false;
1600 }
1601
1602 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1603}
1604
Geoff Langb1196682014-07-23 13:47:29 -04001605bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001606 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001607{
Jamie Madill250d33f2014-06-06 17:09:03 -04001608 switch (type)
1609 {
1610 case GL_UNSIGNED_BYTE:
1611 case GL_UNSIGNED_SHORT:
1612 break;
1613 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001614 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001615 {
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 break;
1620 default:
Geoff Langb1196682014-07-23 13:47:29 -04001621 context->recordError(Error(GL_INVALID_ENUM));
1622 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001623 }
1624
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001625 const State &state = context->getState();
1626
1627 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001628 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1629 {
1630 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1631 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001632 context->recordError(Error(GL_INVALID_OPERATION));
1633 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001634 }
1635
1636 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001637 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001638 {
Geoff Langb1196682014-07-23 13:47:29 -04001639 context->recordError(Error(GL_INVALID_OPERATION));
1640 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001641 }
1642
Jamie Madill2b976812014-08-25 15:47:49 -04001643 const gl::VertexArray *vao = state.getVertexArray();
1644 const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1645 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001646 {
Geoff Langb1196682014-07-23 13:47:29 -04001647 context->recordError(Error(GL_INVALID_OPERATION));
1648 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001649 }
1650
Jamie Madillae3000b2014-08-25 15:47:51 -04001651 if (elementArrayBuffer)
1652 {
1653 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1654
1655 GLint64 offset = reinterpret_cast<GLint64>(indices);
1656 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1657
1658 // check for integer overflows
1659 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1660 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1661 {
Geoff Langb1196682014-07-23 13:47:29 -04001662 context->recordError(Error(GL_OUT_OF_MEMORY));
1663 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001664 }
1665
1666 // Check for reading past the end of the bound buffer object
1667 if (byteCount > elementArrayBuffer->getSize())
1668 {
Geoff Langb1196682014-07-23 13:47:29 -04001669 context->recordError(Error(GL_INVALID_OPERATION));
1670 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001671 }
1672 }
1673 else if (!indices)
1674 {
1675 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001676 context->recordError(Error(GL_INVALID_OPERATION));
1677 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001678 }
1679
Jamie Madill2b976812014-08-25 15:47:49 -04001680 // Use max index to validate if our vertex buffers are large enough for the pull.
1681 // TODO: offer fast path, with disabled index validation.
1682 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1683 if (elementArrayBuffer)
1684 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001685 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Jamie Madill2b976812014-08-25 15:47:49 -04001686 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1687 {
Jamie Madill9ae396b2014-10-21 17:46:30 -04001688 // FIXME(jmadill): Use buffer data caching instead of the D3D back-end
1689 rx::BufferD3D *bufferD3D = rx::BufferD3D::makeBufferD3D(elementArrayBuffer->getImplementation());
Geoff Langc8d297a2014-09-19 11:09:08 -04001690 const uint8_t *dataPointer = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -04001691 Error error = bufferD3D->getData(&dataPointer);
Geoff Langc8d297a2014-09-19 11:09:08 -04001692 if (error.isError())
1693 {
1694 context->recordError(error);
1695 return false;
1696 }
1697
1698 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001699 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1700 }
1701 }
1702 else
1703 {
1704 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1705 }
1706
Geoff Langb1196682014-07-23 13:47:29 -04001707 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001708 {
1709 return false;
1710 }
1711
1712 return true;
1713}
1714
Geoff Langb1196682014-07-23 13:47:29 -04001715bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001716 GLenum mode, GLsizei count, GLenum type,
1717 const GLvoid *indices, GLsizei primcount,
1718 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001719{
1720 if (primcount < 0)
1721 {
Geoff Langb1196682014-07-23 13:47:29 -04001722 context->recordError(Error(GL_INVALID_VALUE));
1723 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001724 }
1725
Jamie Madill2b976812014-08-25 15:47:49 -04001726 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001727 {
1728 return false;
1729 }
1730
1731 // No-op zero primitive count
1732 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001733}
1734
Geoff Lang87a93302014-09-16 13:29:43 -04001735bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1736 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1737{
1738 if (!ValidateDrawInstancedANGLE(context))
1739 {
1740 return false;
1741 }
1742
1743 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1744}
1745
Geoff Langb1196682014-07-23 13:47:29 -04001746bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001747 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001748{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001749 if (!ValidFramebufferTarget(target))
1750 {
Geoff Langb1196682014-07-23 13:47:29 -04001751 context->recordError(Error(GL_INVALID_ENUM));
1752 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001753 }
1754
1755 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001756 {
1757 return false;
1758 }
1759
Jamie Madill55ec3b12014-07-03 10:38:57 -04001760 if (texture != 0)
1761 {
1762 gl::Texture *tex = context->getTexture(texture);
1763
1764 if (tex == NULL)
1765 {
Geoff Langb1196682014-07-23 13:47:29 -04001766 context->recordError(Error(GL_INVALID_OPERATION));
1767 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001768 }
1769
1770 if (level < 0)
1771 {
Geoff Langb1196682014-07-23 13:47:29 -04001772 context->recordError(Error(GL_INVALID_VALUE));
1773 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001774 }
1775 }
1776
Shannon Woods53a94a82014-06-24 15:20:36 -04001777 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1778 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001779
1780 if (framebufferHandle == 0 || !framebuffer)
1781 {
Geoff Langb1196682014-07-23 13:47:29 -04001782 context->recordError(Error(GL_INVALID_OPERATION));
1783 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001784 }
1785
1786 return true;
1787}
1788
Geoff Langb1196682014-07-23 13:47:29 -04001789bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001790 GLenum textarget, GLuint texture, GLint level)
1791{
1792 // Attachments are required to be bound to level 0 in ES2
1793 if (context->getClientVersion() < 3 && level != 0)
1794 {
Geoff Langb1196682014-07-23 13:47:29 -04001795 context->recordError(Error(GL_INVALID_VALUE));
1796 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001797 }
1798
1799 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001800 {
1801 return false;
1802 }
1803
Jamie Madill55ec3b12014-07-03 10:38:57 -04001804 if (texture != 0)
1805 {
1806 gl::Texture *tex = context->getTexture(texture);
1807 ASSERT(tex);
1808
Jamie Madill2a6564e2014-07-11 09:53:19 -04001809 const gl::Caps &caps = context->getCaps();
1810
Jamie Madill55ec3b12014-07-03 10:38:57 -04001811 switch (textarget)
1812 {
1813 case GL_TEXTURE_2D:
1814 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001815 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001816 {
Geoff Langb1196682014-07-23 13:47:29 -04001817 context->recordError(Error(GL_INVALID_VALUE));
1818 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001819 }
1820 if (tex->getTarget() != GL_TEXTURE_2D)
1821 {
Geoff Langb1196682014-07-23 13:47:29 -04001822 context->recordError(Error(GL_INVALID_OPERATION));
1823 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001824 }
1825 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1826 if (tex2d->isCompressed(level))
1827 {
Geoff Langb1196682014-07-23 13:47:29 -04001828 context->recordError(Error(GL_INVALID_OPERATION));
1829 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001830 }
1831 }
1832 break;
1833
1834 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1835 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1836 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1837 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1838 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1839 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1840 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001841 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001842 {
Geoff Langb1196682014-07-23 13:47:29 -04001843 context->recordError(Error(GL_INVALID_VALUE));
1844 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001845 }
1846 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1847 {
Geoff Langb1196682014-07-23 13:47:29 -04001848 context->recordError(Error(GL_INVALID_OPERATION));
1849 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001850 }
1851 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1852 if (texcube->isCompressed(textarget, level))
1853 {
Geoff Langb1196682014-07-23 13:47:29 -04001854 context->recordError(Error(GL_INVALID_OPERATION));
1855 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001856 }
1857 }
1858 break;
1859
1860 default:
Geoff Langb1196682014-07-23 13:47:29 -04001861 context->recordError(Error(GL_INVALID_ENUM));
1862 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001863 }
1864 }
1865
Jamie Madill570f7c82014-07-03 10:38:54 -04001866 return true;
1867}
1868
Geoff Langb1196682014-07-23 13:47:29 -04001869bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001870{
1871 if (program == 0)
1872 {
Geoff Langb1196682014-07-23 13:47:29 -04001873 context->recordError(Error(GL_INVALID_VALUE));
1874 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001875 }
1876
Shannon Woods4de4fd62014-11-07 16:22:02 -05001877 if (!ValidProgram(context, program))
1878 {
1879 return false;
1880 }
1881
Jamie Madill0063c512014-08-25 15:47:53 -04001882 gl::Program *programObject = context->getProgram(program);
1883
1884 if (!programObject || !programObject->isLinked())
1885 {
Geoff Langb1196682014-07-23 13:47:29 -04001886 context->recordError(Error(GL_INVALID_OPERATION));
1887 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001888 }
1889
Geoff Lang7dd2e102014-11-10 15:19:26 -05001890 if (!programObject->isValidUniformLocation(location))
Jamie Madill549c7fd2014-08-25 15:47:56 -04001891 {
Geoff Langb1196682014-07-23 13:47:29 -04001892 context->recordError(Error(GL_INVALID_OPERATION));
1893 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001894 }
1895
Jamie Madill0063c512014-08-25 15:47:53 -04001896 return true;
1897}
1898
Geoff Langb1196682014-07-23 13:47:29 -04001899bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001900{
1901 return ValidateGetUniformBase(context, program, location);
1902}
1903
Geoff Langb1196682014-07-23 13:47:29 -04001904bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001905{
Jamie Madill78f41802014-08-25 15:47:55 -04001906 return ValidateGetUniformBase(context, program, location);
1907}
1908
Geoff Langb1196682014-07-23 13:47:29 -04001909static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001910{
1911 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001912 {
Jamie Madill78f41802014-08-25 15:47:55 -04001913 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001914 }
1915
Jamie Madilla502c742014-08-28 17:19:13 -04001916 gl::Program *programObject = context->getProgram(program);
1917 ASSERT(programObject);
Jamie Madill0063c512014-08-25 15:47:53 -04001918
Jamie Madill78f41802014-08-25 15:47:55 -04001919 // sized queries -- ensure the provided buffer is large enough
Geoff Lang7dd2e102014-11-10 15:19:26 -05001920 LinkedUniform *uniform = programObject->getUniformByLocation(location);
Jamie Madill78f41802014-08-25 15:47:55 -04001921 size_t requiredBytes = VariableExternalSize(uniform->type);
1922 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001923 {
Geoff Langb1196682014-07-23 13:47:29 -04001924 context->recordError(Error(GL_INVALID_OPERATION));
1925 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001926 }
1927
1928 return true;
1929}
1930
Geoff Langb1196682014-07-23 13:47:29 -04001931bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001932{
Jamie Madill78f41802014-08-25 15:47:55 -04001933 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001934}
1935
Geoff Langb1196682014-07-23 13:47:29 -04001936bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001937{
Jamie Madill78f41802014-08-25 15:47:55 -04001938 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001939}
1940
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001941}