blob: d0b233161dd9688f31f5292b6b5f62ef1284e59e [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
27namespace gl
28{
29
Geoff Lang0550d032014-01-30 11:29:07 -050030bool ValidCap(const Context *context, GLenum cap)
31{
32 switch (cap)
33 {
34 case GL_CULL_FACE:
35 case GL_POLYGON_OFFSET_FILL:
36 case GL_SAMPLE_ALPHA_TO_COVERAGE:
37 case GL_SAMPLE_COVERAGE:
38 case GL_SCISSOR_TEST:
39 case GL_STENCIL_TEST:
40 case GL_DEPTH_TEST:
41 case GL_BLEND:
42 case GL_DITHER:
43 return true;
44 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
45 case GL_RASTERIZER_DISCARD:
46 return (context->getClientVersion() >= 3);
47 default:
48 return false;
49 }
50}
51
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050052bool ValidTextureTarget(const Context *context, GLenum target)
Jamie Madill35d15012013-10-07 10:46:37 -040053{
Jamie Madilld7460c72014-01-21 16:38:14 -050054 switch (target)
Jamie Madill35d15012013-10-07 10:46:37 -040055 {
Jamie Madilld7460c72014-01-21 16:38:14 -050056 case GL_TEXTURE_2D:
57 case GL_TEXTURE_CUBE_MAP:
58 return true;
Jamie Madill35d15012013-10-07 10:46:37 -040059
Jamie Madilld7460c72014-01-21 16:38:14 -050060 case GL_TEXTURE_3D:
61 case GL_TEXTURE_2D_ARRAY:
62 return (context->getClientVersion() >= 3);
63
64 default:
65 return false;
66 }
Jamie Madill35d15012013-10-07 10:46:37 -040067}
68
Shannon Woods4dfed832014-03-17 20:03:39 -040069// This function differs from ValidTextureTarget in that the target must be
70// usable as the destination of a 2D operation-- so a cube face is valid, but
71// GL_TEXTURE_CUBE_MAP is not.
Jamie Madill560a8d82014-05-21 13:06:20 -040072// Note: duplicate of IsInternalTextureTarget
Shannon Woods4dfed832014-03-17 20:03:39 -040073bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
74{
75 switch (target)
76 {
77 case GL_TEXTURE_2D:
78 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
79 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
80 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
81 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
82 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
83 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
84 return true;
85 case GL_TEXTURE_2D_ARRAY:
86 case GL_TEXTURE_3D:
87 return (context->getClientVersion() >= 3);
88 default:
89 return false;
90 }
91}
92
Jamie Madill1fc7e2c2014-01-21 16:47:10 -050093bool ValidFramebufferTarget(GLenum target)
94{
95 META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER);
96
97 switch (target)
98 {
99 case GL_FRAMEBUFFER: return true;
100 case GL_READ_FRAMEBUFFER: return true;
101 case GL_DRAW_FRAMEBUFFER: return true;
102 default: return false;
103 }
104}
105
Jamie Madill8c96d582014-03-05 15:01:23 -0500106bool ValidBufferTarget(const Context *context, GLenum target)
107{
108 switch (target)
109 {
110 case GL_ARRAY_BUFFER:
111 case GL_ELEMENT_ARRAY_BUFFER:
112 return true;
113
Jamie Madill8c96d582014-03-05 15:01:23 -0500114 case GL_PIXEL_PACK_BUFFER:
115 case GL_PIXEL_UNPACK_BUFFER:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400116 return context->getExtensions().pixelBufferObject;
Shannon Woods158c4382014-05-06 13:00:07 -0400117
Shannon Woodsb3801742014-03-27 14:59:19 -0400118 case GL_COPY_READ_BUFFER:
119 case GL_COPY_WRITE_BUFFER:
Jamie Madill8c96d582014-03-05 15:01:23 -0500120 case GL_TRANSFORM_FEEDBACK_BUFFER:
121 case GL_UNIFORM_BUFFER:
122 return (context->getClientVersion() >= 3);
123
124 default:
125 return false;
126 }
127}
128
Jamie Madill70656a62014-03-05 15:01:26 -0500129bool ValidBufferParameter(const Context *context, GLenum pname)
130{
131 switch (pname)
132 {
133 case GL_BUFFER_USAGE:
134 case GL_BUFFER_SIZE:
135 return true;
136
137 // GL_BUFFER_MAP_POINTER is a special case, and may only be
138 // queried with GetBufferPointerv
139 case GL_BUFFER_ACCESS_FLAGS:
140 case GL_BUFFER_MAPPED:
141 case GL_BUFFER_MAP_OFFSET:
142 case GL_BUFFER_MAP_LENGTH:
143 return (context->getClientVersion() >= 3);
144
145 default:
146 return false;
147 }
148}
149
Jamie Madill8c96d582014-03-05 15:01:23 -0500150bool ValidMipLevel(const Context *context, GLenum target, GLint level)
Geoff Langce635692013-09-24 13:56:32 -0400151{
Geoff Langaae65a42014-05-26 12:43:44 -0400152 size_t maxDimension = 0;
Geoff Langce635692013-09-24 13:56:32 -0400153 switch (target)
154 {
Geoff Langaae65a42014-05-26 12:43:44 -0400155 case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400156 case GL_TEXTURE_CUBE_MAP:
157 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
158 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
159 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
160 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
161 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
Geoff Langaae65a42014-05-26 12:43:44 -0400162 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = context->getCaps().maxCubeMapTextureSize; break;
163 case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break;
164 case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break;
Geoff Langce635692013-09-24 13:56:32 -0400165 default: UNREACHABLE();
166 }
167
Geoff Langaae65a42014-05-26 12:43:44 -0400168 return level <= gl::log2(maxDimension);
Geoff Langce635692013-09-24 13:56:32 -0400169}
170
Geoff Langb1196682014-07-23 13:47:29 -0400171bool ValidImageSize(const Context *context, GLenum target, GLint level,
Jamie Madill4fd75c12014-06-23 10:53:54 -0400172 GLsizei width, GLsizei height, GLsizei depth)
Geoff Langce635692013-09-24 13:56:32 -0400173{
174 if (level < 0 || width < 0 || height < 0 || depth < 0)
175 {
176 return false;
177 }
178
Geoff Langc0b9ef42014-07-02 10:02:37 -0400179 if (!context->getExtensions().textureNPOT &&
Jamie Madill4fd75c12014-06-23 10:53:54 -0400180 (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth))))
Geoff Langce635692013-09-24 13:56:32 -0400181 {
182 return false;
183 }
184
185 if (!ValidMipLevel(context, target, level))
186 {
187 return false;
188 }
189
190 return true;
191}
192
Geoff Langb1196682014-07-23 13:47:29 -0400193bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
Geoff Langd4f180b2013-09-24 13:57:44 -0400194{
Geoff Lang5d601382014-07-22 15:14:06 -0400195 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
196 if (!formatInfo.compressed)
Geoff Langd4f180b2013-09-24 13:57:44 -0400197 {
198 return false;
199 }
200
Geoff Lang5d601382014-07-22 15:14:06 -0400201 if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
202 height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
Geoff Langd4f180b2013-09-24 13:57:44 -0400203 {
204 return false;
205 }
206
207 return true;
208}
209
Geoff Lang37dde692014-01-31 16:34:54 -0500210bool ValidQueryType(const Context *context, GLenum queryType)
211{
212 META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT);
213 META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
214
215 switch (queryType)
216 {
217 case GL_ANY_SAMPLES_PASSED:
218 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
219 return true;
220 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
221 return (context->getClientVersion() >= 3);
222 default:
223 return false;
224 }
225}
226
Geoff Langb1196682014-07-23 13:47:29 -0400227bool ValidProgram(Context *context, GLuint id)
Geoff Lang48dcae72014-02-05 16:28:24 -0500228{
229 // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
230 // error INVALID_VALUE if the provided name is not the name of either a shader or program object and
231 // INVALID_OPERATION if the provided name identifies an object that is not the expected type."
232
233 if (context->getProgram(id) != NULL)
234 {
235 return true;
236 }
237 else if (context->getShader(id) != NULL)
238 {
239 // ID is the wrong type
Geoff Langb1196682014-07-23 13:47:29 -0400240 context->recordError(Error(GL_INVALID_OPERATION));
241 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500242 }
243 else
244 {
245 // No shader/program object has this ID
Geoff Langb1196682014-07-23 13:47:29 -0400246 context->recordError(Error(GL_INVALID_VALUE));
247 return false;
Geoff Lang48dcae72014-02-05 16:28:24 -0500248 }
249}
250
Geoff Langb1196682014-07-23 13:47:29 -0400251bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
Jamie Madillb4472272014-07-03 10:38:55 -0400252{
253 if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
254 {
255 const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
256
Geoff Langaae65a42014-05-26 12:43:44 -0400257 if (colorAttachment >= context->getCaps().maxColorAttachments)
Jamie Madillb4472272014-07-03 10:38:55 -0400258 {
Geoff Langb1196682014-07-23 13:47:29 -0400259 context->recordError(Error(GL_INVALID_VALUE));
260 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400261 }
262 }
263 else
264 {
265 switch (attachment)
266 {
267 case GL_DEPTH_ATTACHMENT:
268 case GL_STENCIL_ATTACHMENT:
269 break;
270
271 case GL_DEPTH_STENCIL_ATTACHMENT:
272 if (context->getClientVersion() < 3)
273 {
Geoff Langb1196682014-07-23 13:47:29 -0400274 context->recordError(Error(GL_INVALID_ENUM));
275 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400276 }
277 break;
278
279 default:
Geoff Langb1196682014-07-23 13:47:29 -0400280 context->recordError(Error(GL_INVALID_ENUM));
281 return false;
Jamie Madillb4472272014-07-03 10:38:55 -0400282 }
283 }
284
285 return true;
286}
287
Geoff Langb1196682014-07-23 13:47:29 -0400288bool ValidateRenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400289 GLenum internalformat, GLsizei width, GLsizei height,
290 bool angleExtension)
291{
292 switch (target)
293 {
294 case GL_RENDERBUFFER:
295 break;
296 default:
Geoff Langb1196682014-07-23 13:47:29 -0400297 context->recordError(Error(GL_INVALID_ENUM));
298 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400299 }
300
301 if (width < 0 || height < 0 || samples < 0)
302 {
Geoff Langb1196682014-07-23 13:47:29 -0400303 context->recordError(Error(GL_INVALID_VALUE));
304 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400305 }
306
Geoff Langd87878e2014-09-19 15:42:59 -0400307 const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
308 if (!formatCaps.renderable)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400309 {
Geoff Langb1196682014-07-23 13:47:29 -0400310 context->recordError(Error(GL_INVALID_ENUM));
311 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400312 }
313
314 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
315 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
316 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
317 // internal format must be sized and not an integer format if samples is greater than zero.
Geoff Langd87878e2014-09-19 15:42:59 -0400318 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
Geoff Lang5d601382014-07-22 15:14:06 -0400319 if (formatInfo.pixelBytes == 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400320 {
Geoff Langb1196682014-07-23 13:47:29 -0400321 context->recordError(Error(GL_INVALID_ENUM));
322 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400323 }
324
Geoff Lang5d601382014-07-22 15:14:06 -0400325 if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400326 {
Geoff Langb1196682014-07-23 13:47:29 -0400327 context->recordError(Error(GL_INVALID_OPERATION));
328 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400329 }
330
Geoff Langaae65a42014-05-26 12:43:44 -0400331 if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400332 {
Geoff Langb1196682014-07-23 13:47:29 -0400333 context->recordError(Error(GL_INVALID_VALUE));
334 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400335 }
336
337 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
338 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
339 // states that samples must be less than or equal to the maximum samples for the specified
340 // internal format.
341 if (angleExtension)
342 {
Geoff Lang5f4c4632014-07-03 13:46:52 -0400343 ASSERT(context->getExtensions().framebufferMultisample);
344 if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400345 {
Geoff Langb1196682014-07-23 13:47:29 -0400346 context->recordError(Error(GL_INVALID_VALUE));
347 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400348 }
Geoff Lang5f4c4632014-07-03 13:46:52 -0400349
350 // Check if this specific format supports enough samples
351 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
352 {
Geoff Langb1196682014-07-23 13:47:29 -0400353 context->recordError(Error(GL_OUT_OF_MEMORY));
354 return false;
Geoff Lang5f4c4632014-07-03 13:46:52 -0400355 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400356 }
357 else
358 {
Geoff Lang5f4c4632014-07-03 13:46:52 -0400359 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400360 {
Geoff Langb1196682014-07-23 13:47:29 -0400361 context->recordError(Error(GL_INVALID_VALUE));
362 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400363 }
364 }
365
Shannon Woods53a94a82014-06-24 15:20:36 -0400366 GLuint handle = context->getState().getRenderbufferId();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400367 if (handle == 0)
368 {
Geoff Langb1196682014-07-23 13:47:29 -0400369 context->recordError(Error(GL_INVALID_OPERATION));
370 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400371 }
372
373 return true;
374}
375
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500376bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment,
377 GLenum renderbuffertarget, GLuint renderbuffer)
378{
Shannon Woods1da3cf62014-06-27 15:32:23 -0400379 if (!ValidFramebufferTarget(target))
380 {
Geoff Langb1196682014-07-23 13:47:29 -0400381 context->recordError(Error(GL_INVALID_ENUM));
382 return false;
Shannon Woods1da3cf62014-06-27 15:32:23 -0400383 }
384
Shannon Woods53a94a82014-06-24 15:20:36 -0400385 gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
386 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500387
388 if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
389 {
Geoff Langb1196682014-07-23 13:47:29 -0400390 context->recordError(Error(GL_INVALID_OPERATION));
391 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500392 }
393
Jamie Madillb4472272014-07-03 10:38:55 -0400394 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500395 {
Jamie Madillb4472272014-07-03 10:38:55 -0400396 return false;
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500397 }
398
Jamie Madillab9d82c2014-01-21 16:38:14 -0500399 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
400 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
401 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
402 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
403 if (renderbuffer != 0)
404 {
405 if (!context->getRenderbuffer(renderbuffer))
406 {
Geoff Langb1196682014-07-23 13:47:29 -0400407 context->recordError(Error(GL_INVALID_OPERATION));
408 return false;
Jamie Madillab9d82c2014-01-21 16:38:14 -0500409 }
410 }
411
Jamie Madill1fc7e2c2014-01-21 16:47:10 -0500412 return true;
413}
414
Jamie Madill3c7fa222014-06-05 13:08:51 -0400415static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer,
Geoff Lang125deab2013-08-09 13:34:16 -0400416 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
417 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
418{
419 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
420 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
421 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
422 {
423 return true;
424 }
Shannon Woods53a94a82014-06-24 15:20:36 -0400425 else if (context->getState().isScissorTestEnabled())
Geoff Lang125deab2013-08-09 13:34:16 -0400426 {
Shannon Woods53a94a82014-06-24 15:20:36 -0400427 const Rectangle &scissor = context->getState().getScissor();
Geoff Lang125deab2013-08-09 13:34:16 -0400428
Shannon Woods53a94a82014-06-24 15:20:36 -0400429 return scissor.x > 0 || scissor.y > 0 ||
430 scissor.width < writeBuffer->getWidth() ||
431 scissor.height < writeBuffer->getHeight();
Geoff Lang125deab2013-08-09 13:34:16 -0400432 }
433 else
434 {
435 return false;
436 }
437}
438
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400439bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400440 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
441 GLenum filter, bool fromAngleExtension)
442{
443 switch (filter)
444 {
445 case GL_NEAREST:
446 break;
447 case GL_LINEAR:
448 if (fromAngleExtension)
449 {
Geoff Langb1196682014-07-23 13:47:29 -0400450 context->recordError(Error(GL_INVALID_ENUM));
451 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400452 }
453 break;
454 default:
Geoff Langb1196682014-07-23 13:47:29 -0400455 context->recordError(Error(GL_INVALID_ENUM));
456 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400457 }
458
459 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
460 {
Geoff Langb1196682014-07-23 13:47:29 -0400461 context->recordError(Error(GL_INVALID_VALUE));
462 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400463 }
464
465 if (mask == 0)
466 {
467 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
468 // buffers are copied.
469 return false;
470 }
471
472 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
473 {
474 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400475 context->recordError(Error(GL_INVALID_OPERATION));
476 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400477 }
478
479 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
480 // color buffer, leaving only nearest being unfiltered from above
481 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
482 {
Geoff Langb1196682014-07-23 13:47:29 -0400483 context->recordError(Error(GL_INVALID_OPERATION));
484 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400485 }
486
Shannon Woods53a94a82014-06-24 15:20:36 -0400487 if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400488 {
489 if (fromAngleExtension)
490 {
491 ERR("Blits with the same source and destination framebuffer are not supported by this "
492 "implementation.");
493 }
Geoff Langb1196682014-07-23 13:47:29 -0400494 context->recordError(Error(GL_INVALID_OPERATION));
495 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400496 }
497
Shannon Woods53a94a82014-06-24 15:20:36 -0400498 gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
499 gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
501 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
502 {
Geoff Langb1196682014-07-23 13:47:29 -0400503 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
504 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400505 }
506
507 if (drawFramebuffer->getSamples() != 0)
508 {
Geoff Langb1196682014-07-23 13:47:29 -0400509 context->recordError(Error(GL_INVALID_OPERATION));
510 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400511 }
512
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400513 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
514
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400515 if (mask & GL_COLOR_BUFFER_BIT)
516 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400517 gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer();
518 gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400519
520 if (readColorBuffer && drawColorBuffer)
521 {
Geoff Lang005df412013-10-16 14:12:50 -0400522 GLenum readInternalFormat = readColorBuffer->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400523 const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400524
525 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
526 {
527 if (drawFramebuffer->isEnabledColorAttachment(i))
528 {
Geoff Lang005df412013-10-16 14:12:50 -0400529 GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
Geoff Lang5d601382014-07-22 15:14:06 -0400530 const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400531
Geoff Langb2f3d052013-08-13 12:49:27 -0400532 // The GL ES 3.0.2 spec (pg 193) states that:
533 // 1) If the read buffer is fixed point format, the draw buffer must be as well
534 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
535 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
Geoff Lang5d601382014-07-22 15:14:06 -0400536 if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
537 !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400538 {
Geoff Langb1196682014-07-23 13:47:29 -0400539 context->recordError(Error(GL_INVALID_OPERATION));
540 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400541 }
542
Geoff Lang5d601382014-07-22 15:14:06 -0400543 if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400544 {
Geoff Langb1196682014-07-23 13:47:29 -0400545 context->recordError(Error(GL_INVALID_OPERATION));
546 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400547 }
548
Geoff Lang5d601382014-07-22 15:14:06 -0400549 if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400550 {
Geoff Langb1196682014-07-23 13:47:29 -0400551 context->recordError(Error(GL_INVALID_OPERATION));
552 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400553 }
554
Geoff Langb2f3d052013-08-13 12:49:27 -0400555 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400556 {
Geoff Langb1196682014-07-23 13:47:29 -0400557 context->recordError(Error(GL_INVALID_OPERATION));
558 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400559 }
560 }
561 }
562
Geoff Lang5d601382014-07-22 15:14:06 -0400563 if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400564 {
Geoff Langb1196682014-07-23 13:47:29 -0400565 context->recordError(Error(GL_INVALID_OPERATION));
566 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400567 }
568
569 if (fromAngleExtension)
570 {
571 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
572 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
573 {
Geoff Langb1196682014-07-23 13:47:29 -0400574 context->recordError(Error(GL_INVALID_OPERATION));
575 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400576 }
577
578 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
579 {
580 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
581 {
Jamie Madille92a3542014-07-03 10:38:58 -0400582 FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment);
583 ASSERT(attachment);
584
585 if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400586 {
Geoff Langb1196682014-07-23 13:47:29 -0400587 context->recordError(Error(GL_INVALID_OPERATION));
588 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400589 }
590
Jamie Madillf8f18f02014-10-02 10:44:17 -0400591 // Return an error if the destination formats do not match
592 if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400593 {
Geoff Langb1196682014-07-23 13:47:29 -0400594 context->recordError(Error(GL_INVALID_OPERATION));
595 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400596 }
597 }
598 }
Geoff Lang125deab2013-08-09 13:34:16 -0400599 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
600 srcX0, srcY0, srcX1, srcY1,
601 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400602 {
Geoff Langb1196682014-07-23 13:47:29 -0400603 context->recordError(Error(GL_INVALID_OPERATION));
604 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400605 }
606 }
607 }
608 }
609
610 if (mask & GL_DEPTH_BUFFER_BIT)
611 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400612 gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer();
613 gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400614
615 if (readDepthBuffer && drawDepthBuffer)
616 {
617 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
618 {
Geoff Langb1196682014-07-23 13:47:29 -0400619 context->recordError(Error(GL_INVALID_OPERATION));
620 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400621 }
622
623 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
624 {
Geoff Langb1196682014-07-23 13:47:29 -0400625 context->recordError(Error(GL_INVALID_OPERATION));
626 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400627 }
628
629 if (fromAngleExtension)
630 {
Geoff Lang125deab2013-08-09 13:34:16 -0400631 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
632 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400633 {
634 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400635 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
636 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400637 }
638
639 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
640 {
Geoff Langb1196682014-07-23 13:47:29 -0400641 context->recordError(Error(GL_INVALID_OPERATION));
642 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400643 }
644 }
645 }
646 }
647
648 if (mask & GL_STENCIL_BUFFER_BIT)
649 {
Jamie Madill3c7fa222014-06-05 13:08:51 -0400650 gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer();
651 gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400652
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400653 if (readStencilBuffer && drawStencilBuffer)
654 {
655 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
656 {
Geoff Langb1196682014-07-23 13:47:29 -0400657 context->recordError(Error(GL_INVALID_OPERATION));
658 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400659 }
660
661 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
662 {
Geoff Langb1196682014-07-23 13:47:29 -0400663 context->recordError(Error(GL_INVALID_OPERATION));
664 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400665 }
666
667 if (fromAngleExtension)
668 {
Geoff Lang125deab2013-08-09 13:34:16 -0400669 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
670 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400671 {
672 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
Geoff Langb1196682014-07-23 13:47:29 -0400673 context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
674 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400675 }
676
677 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
678 {
Geoff Langb1196682014-07-23 13:47:29 -0400679 context->recordError(Error(GL_INVALID_OPERATION));
680 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400681 }
682 }
683 }
684 }
685
686 return true;
687}
688
Geoff Langb1196682014-07-23 13:47:29 -0400689bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400690{
691 switch (pname)
692 {
693 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
694 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
695 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
696 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
697 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
698 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
699 case GL_CURRENT_VERTEX_ATTRIB:
700 return true;
701
702 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
703 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
704 // the same constant.
705 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
706 return true;
707
708 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Geoff Langb1196682014-07-23 13:47:29 -0400709 if (context->getClientVersion() < 3)
710 {
711 context->recordError(Error(GL_INVALID_ENUM));
712 return false;
713 }
714 return true;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400715
716 default:
Geoff Langb1196682014-07-23 13:47:29 -0400717 context->recordError(Error(GL_INVALID_ENUM));
718 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400719 }
720}
721
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400722bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400723{
724 switch (pname)
725 {
726 case GL_TEXTURE_WRAP_R:
727 case GL_TEXTURE_SWIZZLE_R:
728 case GL_TEXTURE_SWIZZLE_G:
729 case GL_TEXTURE_SWIZZLE_B:
730 case GL_TEXTURE_SWIZZLE_A:
731 case GL_TEXTURE_BASE_LEVEL:
732 case GL_TEXTURE_MAX_LEVEL:
733 case GL_TEXTURE_COMPARE_MODE:
734 case GL_TEXTURE_COMPARE_FUNC:
735 case GL_TEXTURE_MIN_LOD:
736 case GL_TEXTURE_MAX_LOD:
737 if (context->getClientVersion() < 3)
738 {
Geoff Langb1196682014-07-23 13:47:29 -0400739 context->recordError(Error(GL_INVALID_ENUM));
740 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400741 }
742 break;
743
744 default: break;
745 }
746
747 switch (pname)
748 {
749 case GL_TEXTURE_WRAP_S:
750 case GL_TEXTURE_WRAP_T:
751 case GL_TEXTURE_WRAP_R:
752 switch (param)
753 {
754 case GL_REPEAT:
755 case GL_CLAMP_TO_EDGE:
756 case GL_MIRRORED_REPEAT:
757 return true;
758 default:
Geoff Langb1196682014-07-23 13:47:29 -0400759 context->recordError(Error(GL_INVALID_ENUM));
760 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400761 }
762
763 case GL_TEXTURE_MIN_FILTER:
764 switch (param)
765 {
766 case GL_NEAREST:
767 case GL_LINEAR:
768 case GL_NEAREST_MIPMAP_NEAREST:
769 case GL_LINEAR_MIPMAP_NEAREST:
770 case GL_NEAREST_MIPMAP_LINEAR:
771 case GL_LINEAR_MIPMAP_LINEAR:
772 return true;
773 default:
Geoff Langb1196682014-07-23 13:47:29 -0400774 context->recordError(Error(GL_INVALID_ENUM));
775 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400776 }
777 break;
778
779 case GL_TEXTURE_MAG_FILTER:
780 switch (param)
781 {
782 case GL_NEAREST:
783 case GL_LINEAR:
784 return true;
785 default:
Geoff Langb1196682014-07-23 13:47:29 -0400786 context->recordError(Error(GL_INVALID_ENUM));
787 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400788 }
789 break;
790
791 case GL_TEXTURE_USAGE_ANGLE:
792 switch (param)
793 {
794 case GL_NONE:
795 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
796 return true;
797 default:
Geoff Langb1196682014-07-23 13:47:29 -0400798 context->recordError(Error(GL_INVALID_ENUM));
799 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400800 }
801 break;
802
803 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Geoff Langc0b9ef42014-07-02 10:02:37 -0400804 if (!context->getExtensions().textureFilterAnisotropic)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400805 {
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
810 // we assume the parameter passed to this validation method is truncated, not rounded
811 if (param < 1)
812 {
Geoff Langb1196682014-07-23 13:47:29 -0400813 context->recordError(Error(GL_INVALID_VALUE));
814 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400815 }
816 return true;
817
818 case GL_TEXTURE_MIN_LOD:
819 case GL_TEXTURE_MAX_LOD:
820 // any value is permissible
821 return true;
822
823 case GL_TEXTURE_COMPARE_MODE:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400824 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400825 switch (param)
826 {
827 case GL_NONE:
828 case GL_COMPARE_REF_TO_TEXTURE:
829 return true;
830 default:
Geoff Langb1196682014-07-23 13:47:29 -0400831 context->recordError(Error(GL_INVALID_ENUM));
832 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400833 }
834 break;
835
836 case GL_TEXTURE_COMPARE_FUNC:
Geoff Lang63b5f1f2013-09-23 14:52:14 -0400837 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400838 switch (param)
839 {
840 case GL_LEQUAL:
841 case GL_GEQUAL:
842 case GL_LESS:
843 case GL_GREATER:
844 case GL_EQUAL:
845 case GL_NOTEQUAL:
846 case GL_ALWAYS:
847 case GL_NEVER:
848 return true;
849 default:
Geoff Langb1196682014-07-23 13:47:29 -0400850 context->recordError(Error(GL_INVALID_ENUM));
851 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400852 }
853 break;
854
855 case GL_TEXTURE_SWIZZLE_R:
856 case GL_TEXTURE_SWIZZLE_G:
857 case GL_TEXTURE_SWIZZLE_B:
858 case GL_TEXTURE_SWIZZLE_A:
Geoff Langbc90a482013-09-17 16:51:27 -0400859 switch (param)
860 {
861 case GL_RED:
862 case GL_GREEN:
863 case GL_BLUE:
864 case GL_ALPHA:
865 case GL_ZERO:
866 case GL_ONE:
867 return true;
868 default:
Geoff Langb1196682014-07-23 13:47:29 -0400869 context->recordError(Error(GL_INVALID_ENUM));
870 return false;
Geoff Langbc90a482013-09-17 16:51:27 -0400871 }
872 break;
873
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400874 case GL_TEXTURE_BASE_LEVEL:
875 case GL_TEXTURE_MAX_LEVEL:
Nicolas Capens8de68282014-04-04 11:10:27 -0400876 if (param < 0)
877 {
Geoff Langb1196682014-07-23 13:47:29 -0400878 context->recordError(Error(GL_INVALID_VALUE));
879 return false;
Nicolas Capens8de68282014-04-04 11:10:27 -0400880 }
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400881 return true;
882
883 default:
Geoff Langb1196682014-07-23 13:47:29 -0400884 context->recordError(Error(GL_INVALID_ENUM));
885 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400886 }
887}
888
Geoff Langb1196682014-07-23 13:47:29 -0400889bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400890{
891 switch (pname)
892 {
893 case GL_TEXTURE_MIN_FILTER:
894 case GL_TEXTURE_MAG_FILTER:
895 case GL_TEXTURE_WRAP_S:
896 case GL_TEXTURE_WRAP_T:
897 case GL_TEXTURE_WRAP_R:
898 case GL_TEXTURE_MIN_LOD:
899 case GL_TEXTURE_MAX_LOD:
900 case GL_TEXTURE_COMPARE_MODE:
901 case GL_TEXTURE_COMPARE_FUNC:
902 return true;
903
904 default:
Geoff Langb1196682014-07-23 13:47:29 -0400905 context->recordError(Error(GL_INVALID_ENUM));
906 return false;
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400907 }
908}
909
Jamie Madill26e91952014-03-05 15:01:27 -0500910bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height,
911 GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels)
912{
Shannon Woods53a94a82014-06-24 15:20:36 -0400913 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -0400914 ASSERT(framebuffer);
Jamie Madill26e91952014-03-05 15:01:27 -0500915
916 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
917 {
Geoff Langb1196682014-07-23 13:47:29 -0400918 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
919 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500920 }
921
Shannon Woods53a94a82014-06-24 15:20:36 -0400922 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
Jamie Madill26e91952014-03-05 15:01:27 -0500923 {
Geoff Langb1196682014-07-23 13:47:29 -0400924 context->recordError(Error(GL_INVALID_OPERATION));
925 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500926 }
927
Jamie Madill893ab082014-05-16 16:56:10 -0400928 if (!framebuffer->getReadColorbuffer())
929 {
Geoff Langb1196682014-07-23 13:47:29 -0400930 context->recordError(Error(GL_INVALID_OPERATION));
931 return false;
Jamie Madill893ab082014-05-16 16:56:10 -0400932 }
933
Jamie Madill26e91952014-03-05 15:01:27 -0500934 GLenum currentInternalFormat, currentFormat, currentType;
Geoff Lange4a492b2014-06-19 14:14:41 -0400935 GLuint clientVersion = context->getClientVersion();
Jamie Madill26e91952014-03-05 15:01:27 -0500936
Jamie Madill893ab082014-05-16 16:56:10 -0400937 context->getCurrentReadFormatType(&currentInternalFormat, &currentFormat, &currentType);
Jamie Madill26e91952014-03-05 15:01:27 -0500938
Geoff Langbdc9b2f2014-04-16 14:41:54 -0400939 bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) :
940 ValidES3ReadFormatType(context, currentInternalFormat, format, type);
Jamie Madill26e91952014-03-05 15:01:27 -0500941
942 if (!(currentFormat == format && currentType == type) && !validReadFormat)
943 {
Geoff Langb1196682014-07-23 13:47:29 -0400944 context->recordError(Error(GL_INVALID_OPERATION));
945 return false;
Jamie Madill26e91952014-03-05 15:01:27 -0500946 }
947
Geoff Lang5d601382014-07-22 15:14:06 -0400948 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
949 const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
Jamie Madill26e91952014-03-05 15:01:27 -0500950
Geoff Lang5d601382014-07-22 15:14:06 -0400951 GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
Jamie Madill26e91952014-03-05 15:01:27 -0500952 // sized query sanity check
953 if (bufSize)
954 {
955 int requiredSize = outputPitch * height;
956 if (requiredSize > *bufSize)
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 }
962
963 return true;
964}
965
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400966bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
967{
968 if (!ValidQueryType(context, target))
969 {
Geoff Langb1196682014-07-23 13:47:29 -0400970 context->recordError(Error(GL_INVALID_ENUM));
971 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400972 }
973
974 if (id == 0)
975 {
Geoff Langb1196682014-07-23 13:47:29 -0400976 context->recordError(Error(GL_INVALID_OPERATION));
977 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400978 }
979
980 // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
981 // of zero, if the active query object name for <target> is non-zero (for the
982 // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
983 // the active query for either target is non-zero), if <id> is the name of an
984 // existing query object whose type does not match <target>, or if <id> is the
985 // active query object name for any query type, the error INVALID_OPERATION is
986 // generated.
987
988 // Ensure no other queries are active
989 // NOTE: If other queries than occlusion are supported, we will need to check
990 // separately that:
991 // a) The query ID passed is not the current active query for any target/type
992 // b) There are no active queries for the requested target (and in the case
993 // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
994 // no query may be active for either if glBeginQuery targets either.
Shannon Woods53a94a82014-06-24 15:20:36 -0400995 if (context->getState().isQueryActive())
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400996 {
Geoff Langb1196682014-07-23 13:47:29 -0400997 context->recordError(Error(GL_INVALID_OPERATION));
998 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -0400999 }
1000
1001 Query *queryObject = context->getQuery(id, true, target);
1002
1003 // check that name was obtained with glGenQueries
1004 if (!queryObject)
1005 {
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 // check for type mismatch
1011 if (queryObject->getType() != target)
1012 {
Geoff Langb1196682014-07-23 13:47:29 -04001013 context->recordError(Error(GL_INVALID_OPERATION));
1014 return false;
Jamie Madilldb2f14c2014-05-13 13:56:30 -04001015 }
1016
1017 return true;
1018}
1019
Jamie Madill45c785d2014-05-13 14:09:34 -04001020bool ValidateEndQuery(gl::Context *context, GLenum target)
1021{
1022 if (!ValidQueryType(context, target))
1023 {
Geoff Langb1196682014-07-23 13:47:29 -04001024 context->recordError(Error(GL_INVALID_ENUM));
1025 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001026 }
1027
Shannon Woods53a94a82014-06-24 15:20:36 -04001028 const Query *queryObject = context->getState().getActiveQuery(target);
Jamie Madill45c785d2014-05-13 14:09:34 -04001029
1030 if (queryObject == NULL)
1031 {
Geoff Langb1196682014-07-23 13:47:29 -04001032 context->recordError(Error(GL_INVALID_OPERATION));
1033 return false;
Jamie Madill45c785d2014-05-13 14:09:34 -04001034 }
1035
Jamie Madill45c785d2014-05-13 14:09:34 -04001036 return true;
1037}
1038
Jamie Madill36398922014-05-20 14:51:53 -04001039static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType,
1040 GLint location, GLsizei count, LinkedUniform **uniformOut)
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001041{
1042 if (count < 0)
1043 {
Geoff Langb1196682014-07-23 13:47:29 -04001044 context->recordError(Error(GL_INVALID_VALUE));
1045 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001046 }
1047
Shannon Woods53a94a82014-06-24 15:20:36 -04001048 gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001049 if (!programBinary)
1050 {
Geoff Langb1196682014-07-23 13:47:29 -04001051 context->recordError(Error(GL_INVALID_OPERATION));
1052 return false;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001053 }
1054
1055 if (location == -1)
1056 {
1057 // Silently ignore the uniform command
1058 return false;
1059 }
1060
Jamie Madill36398922014-05-20 14:51:53 -04001061 if (!programBinary->isValidUniformLocation(location))
1062 {
Geoff Langb1196682014-07-23 13:47:29 -04001063 context->recordError(Error(GL_INVALID_OPERATION));
1064 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001065 }
1066
1067 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1068
1069 // attempting to write an array to a non-array uniform is an INVALID_OPERATION
1070 if (uniform->elementCount() == 1 && count > 1)
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 *uniformOut = uniform;
Jamie Madilld7c7bb22014-05-20 10:55:54 -04001077 return true;
1078}
1079
Jamie Madillaa981bd2014-05-20 10:55:55 -04001080bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count)
1081{
1082 // Check for ES3 uniform entry points
Jamie Madillf2575982014-06-25 16:04:54 -04001083 if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
Jamie Madillaa981bd2014-05-20 10:55:55 -04001084 {
Geoff Langb1196682014-07-23 13:47:29 -04001085 context->recordError(Error(GL_INVALID_OPERATION));
1086 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001087 }
1088
Jamie Madill36398922014-05-20 14:51:53 -04001089 LinkedUniform *uniform = NULL;
1090 if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform))
1091 {
1092 return false;
1093 }
1094
Jamie Madillf2575982014-06-25 16:04:54 -04001095 GLenum targetBoolType = VariableBoolVectorType(uniformType);
Jamie Madill36398922014-05-20 14:51:53 -04001096 bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
1097 if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
1098 {
Geoff Langb1196682014-07-23 13:47:29 -04001099 context->recordError(Error(GL_INVALID_OPERATION));
1100 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001101 }
1102
1103 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001104}
1105
1106bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count,
1107 GLboolean transpose)
1108{
1109 // Check for ES3 uniform entry points
1110 int rows = VariableRowCount(matrixType);
1111 int cols = VariableColumnCount(matrixType);
1112 if (rows != cols && context->getClientVersion() < 3)
1113 {
Geoff Langb1196682014-07-23 13:47:29 -04001114 context->recordError(Error(GL_INVALID_OPERATION));
1115 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001116 }
1117
1118 if (transpose != GL_FALSE && context->getClientVersion() < 3)
1119 {
Geoff Langb1196682014-07-23 13:47:29 -04001120 context->recordError(Error(GL_INVALID_VALUE));
1121 return false;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001122 }
1123
Jamie Madill36398922014-05-20 14:51:53 -04001124 LinkedUniform *uniform = NULL;
1125 if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform))
1126 {
1127 return false;
1128 }
1129
1130 if (uniform->type != matrixType)
1131 {
Geoff Langb1196682014-07-23 13:47:29 -04001132 context->recordError(Error(GL_INVALID_OPERATION));
1133 return false;
Jamie Madill36398922014-05-20 14:51:53 -04001134 }
1135
1136 return true;
Jamie Madillaa981bd2014-05-20 10:55:55 -04001137}
1138
Jamie Madill893ab082014-05-16 16:56:10 -04001139bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams)
1140{
1141 if (!context->getQueryParameterInfo(pname, nativeType, numParams))
1142 {
Geoff Langb1196682014-07-23 13:47:29 -04001143 context->recordError(Error(GL_INVALID_ENUM));
1144 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001145 }
1146
1147 if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
1148 {
1149 unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0);
1150
Geoff Langaae65a42014-05-26 12:43:44 -04001151 if (colorAttachment >= context->getCaps().maxDrawBuffers)
Jamie Madill893ab082014-05-16 16:56:10 -04001152 {
Geoff Langb1196682014-07-23 13:47:29 -04001153 context->recordError(Error(GL_INVALID_OPERATION));
1154 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001155 }
1156 }
1157
1158 switch (pname)
1159 {
1160 case GL_TEXTURE_BINDING_2D:
1161 case GL_TEXTURE_BINDING_CUBE_MAP:
1162 case GL_TEXTURE_BINDING_3D:
1163 case GL_TEXTURE_BINDING_2D_ARRAY:
Geoff Lang3a61c322014-07-10 13:01:54 -04001164 if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
Jamie Madill893ab082014-05-16 16:56:10 -04001165 {
Geoff Langb1196682014-07-23 13:47:29 -04001166 context->recordError(Error(GL_INVALID_OPERATION));
1167 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001168 }
1169 break;
1170
1171 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
1172 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
1173 {
Shannon Woods53a94a82014-06-24 15:20:36 -04001174 Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill893ab082014-05-16 16:56:10 -04001175 ASSERT(framebuffer);
1176 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1177 {
Geoff Langb1196682014-07-23 13:47:29 -04001178 context->recordError(Error(GL_INVALID_OPERATION));
1179 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001180 }
1181
Jamie Madill3c7fa222014-06-05 13:08:51 -04001182 FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
1183 if (!attachment)
Jamie Madill893ab082014-05-16 16:56:10 -04001184 {
Geoff Langb1196682014-07-23 13:47:29 -04001185 context->recordError(Error(GL_INVALID_OPERATION));
1186 return false;
Jamie Madill893ab082014-05-16 16:56:10 -04001187 }
1188 }
1189 break;
1190
1191 default:
1192 break;
1193 }
1194
1195 // pname is valid, but there are no parameters to return
1196 if (numParams == 0)
1197 {
1198 return false;
1199 }
1200
1201 return true;
1202}
1203
Jamie Madill560a8d82014-05-21 13:06:20 -04001204bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
1205 GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
1206 GLint border, GLenum *textureFormatOut)
1207{
1208
1209 if (!ValidTexture2DDestinationTarget(context, target))
1210 {
Geoff Langb1196682014-07-23 13:47:29 -04001211 context->recordError(Error(GL_INVALID_ENUM));
1212 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001213 }
1214
1215 if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
1216 {
Geoff Langb1196682014-07-23 13:47:29 -04001217 context->recordError(Error(GL_INVALID_VALUE));
1218 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001219 }
1220
1221 if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1222 {
Geoff Langb1196682014-07-23 13:47:29 -04001223 context->recordError(Error(GL_INVALID_VALUE));
1224 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001225 }
1226
1227 if (border != 0)
1228 {
Geoff Langb1196682014-07-23 13:47:29 -04001229 context->recordError(Error(GL_INVALID_VALUE));
1230 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001231 }
1232
1233 if (!ValidMipLevel(context, target, level))
1234 {
Geoff Langb1196682014-07-23 13:47:29 -04001235 context->recordError(Error(GL_INVALID_VALUE));
1236 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001237 }
1238
Shannon Woods53a94a82014-06-24 15:20:36 -04001239 gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
Jamie Madill560a8d82014-05-21 13:06:20 -04001240 if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
1241 {
Geoff Langb1196682014-07-23 13:47:29 -04001242 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1243 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001244 }
1245
Shannon Woods53a94a82014-06-24 15:20:36 -04001246 if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001247 {
Geoff Langb1196682014-07-23 13:47:29 -04001248 context->recordError(Error(GL_INVALID_OPERATION));
1249 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001250 }
1251
Geoff Langaae65a42014-05-26 12:43:44 -04001252 const gl::Caps &caps = context->getCaps();
1253
Jamie Madill560a8d82014-05-21 13:06:20 -04001254 gl::Texture *texture = NULL;
1255 GLenum textureInternalFormat = GL_NONE;
Jamie Madill560a8d82014-05-21 13:06:20 -04001256 GLint textureLevelWidth = 0;
1257 GLint textureLevelHeight = 0;
1258 GLint textureLevelDepth = 0;
Geoff Langaae65a42014-05-26 12:43:44 -04001259 GLuint maxDimension = 0;
Jamie Madill560a8d82014-05-21 13:06:20 -04001260
1261 switch (target)
1262 {
1263 case GL_TEXTURE_2D:
1264 {
1265 gl::Texture2D *texture2d = context->getTexture2D();
1266 if (texture2d)
1267 {
1268 textureInternalFormat = texture2d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001269 textureLevelWidth = texture2d->getWidth(level);
1270 textureLevelHeight = texture2d->getHeight(level);
1271 textureLevelDepth = 1;
1272 texture = texture2d;
Geoff Langaae65a42014-05-26 12:43:44 -04001273 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001274 }
1275 }
1276 break;
1277
1278 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1279 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1280 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1281 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1282 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1283 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1284 {
1285 gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
1286 if (textureCube)
1287 {
1288 textureInternalFormat = textureCube->getInternalFormat(target, level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001289 textureLevelWidth = textureCube->getWidth(target, level);
1290 textureLevelHeight = textureCube->getHeight(target, level);
1291 textureLevelDepth = 1;
1292 texture = textureCube;
Geoff Langaae65a42014-05-26 12:43:44 -04001293 maxDimension = caps.maxCubeMapTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001294 }
1295 }
1296 break;
1297
1298 case GL_TEXTURE_2D_ARRAY:
1299 {
1300 gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
1301 if (texture2dArray)
1302 {
1303 textureInternalFormat = texture2dArray->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001304 textureLevelWidth = texture2dArray->getWidth(level);
1305 textureLevelHeight = texture2dArray->getHeight(level);
1306 textureLevelDepth = texture2dArray->getLayers(level);
1307 texture = texture2dArray;
Geoff Langaae65a42014-05-26 12:43:44 -04001308 maxDimension = caps.max2DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001309 }
1310 }
1311 break;
1312
1313 case GL_TEXTURE_3D:
1314 {
1315 gl::Texture3D *texture3d = context->getTexture3D();
1316 if (texture3d)
1317 {
1318 textureInternalFormat = texture3d->getInternalFormat(level);
Jamie Madill560a8d82014-05-21 13:06:20 -04001319 textureLevelWidth = texture3d->getWidth(level);
1320 textureLevelHeight = texture3d->getHeight(level);
1321 textureLevelDepth = texture3d->getDepth(level);
1322 texture = texture3d;
Geoff Langaae65a42014-05-26 12:43:44 -04001323 maxDimension = caps.max3DTextureSize;
Jamie Madill560a8d82014-05-21 13:06:20 -04001324 }
1325 }
1326 break;
1327
1328 default:
Geoff Langb1196682014-07-23 13:47:29 -04001329 context->recordError(Error(GL_INVALID_ENUM));
1330 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001331 }
1332
1333 if (!texture)
1334 {
Geoff Langb1196682014-07-23 13:47:29 -04001335 context->recordError(Error(GL_INVALID_OPERATION));
1336 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001337 }
1338
1339 if (texture->isImmutable() && !isSubImage)
1340 {
Geoff Langb1196682014-07-23 13:47:29 -04001341 context->recordError(Error(GL_INVALID_OPERATION));
1342 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001343 }
1344
Geoff Lang5d601382014-07-22 15:14:06 -04001345 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
1346
1347 if (formatInfo.depthBits > 0)
Jamie Madill560a8d82014-05-21 13:06:20 -04001348 {
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
Geoff Lang5d601382014-07-22 15:14:06 -04001353 if (formatInfo.compressed)
Jamie Madill560a8d82014-05-21 13:06:20 -04001354 {
Geoff Lang5d601382014-07-22 15:14:06 -04001355 if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
1356 ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
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 }
1362
1363 if (isSubImage)
1364 {
1365 if (xoffset + width > textureLevelWidth ||
1366 yoffset + height > textureLevelHeight ||
1367 zoffset >= textureLevelDepth)
1368 {
Geoff Langb1196682014-07-23 13:47:29 -04001369 context->recordError(Error(GL_INVALID_VALUE));
1370 return false;
Jamie Madill560a8d82014-05-21 13:06:20 -04001371 }
1372 }
Jamie Madill6f38f822014-06-06 17:12:20 -04001373 else
1374 {
1375 if (IsCubemapTextureTarget(target) && width != height)
1376 {
Geoff Langb1196682014-07-23 13:47:29 -04001377 context->recordError(Error(GL_INVALID_VALUE));
1378 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001379 }
1380
Geoff Lang5d601382014-07-22 15:14:06 -04001381 if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
Jamie Madill6f38f822014-06-06 17:12:20 -04001382 {
Geoff Langb1196682014-07-23 13:47:29 -04001383 context->recordError(Error(GL_INVALID_ENUM));
1384 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001385 }
1386
1387 int maxLevelDimension = (maxDimension >> level);
1388 if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
1389 {
Geoff Langb1196682014-07-23 13:47:29 -04001390 context->recordError(Error(GL_INVALID_VALUE));
1391 return false;
Jamie Madill6f38f822014-06-06 17:12:20 -04001392 }
1393 }
Jamie Madill560a8d82014-05-21 13:06:20 -04001394
1395 *textureFormatOut = textureInternalFormat;
1396 return true;
1397}
1398
Geoff Langb1196682014-07-23 13:47:29 -04001399static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001400{
Jamie Madill1aeb1312014-06-20 13:21:25 -04001401 switch (mode)
1402 {
1403 case GL_POINTS:
1404 case GL_LINES:
1405 case GL_LINE_LOOP:
1406 case GL_LINE_STRIP:
1407 case GL_TRIANGLES:
1408 case GL_TRIANGLE_STRIP:
1409 case GL_TRIANGLE_FAN:
1410 break;
1411 default:
Geoff Langb1196682014-07-23 13:47:29 -04001412 context->recordError(Error(GL_INVALID_ENUM));
1413 return false;
Jamie Madill1aeb1312014-06-20 13:21:25 -04001414 }
1415
Jamie Madill250d33f2014-06-06 17:09:03 -04001416 if (count < 0)
1417 {
Geoff Langb1196682014-07-23 13:47:29 -04001418 context->recordError(Error(GL_INVALID_VALUE));
1419 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001420 }
1421
Geoff Langb1196682014-07-23 13:47:29 -04001422 const State &state = context->getState();
1423
Jamie Madill250d33f2014-06-06 17:09:03 -04001424 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001425 if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001426 {
Geoff Langb1196682014-07-23 13:47:29 -04001427 context->recordError(Error(GL_INVALID_OPERATION));
1428 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001429 }
1430
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001431 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
Jamie Madillac528012014-06-20 13:21:23 -04001432 if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001433 state.getStencilRef() != state.getStencilBackRef() ||
Jamie Madillac528012014-06-20 13:21:23 -04001434 depthStencilState.stencilMask != depthStencilState.stencilBackMask)
1435 {
1436 // Note: these separate values are not supported in WebGL, due to D3D's limitations.
1437 // See Section 6.10 of the WebGL 1.0 spec
1438 ERR("This ANGLE implementation does not support separate front/back stencil "
1439 "writemasks, reference values, or stencil mask values.");
Geoff Langb1196682014-07-23 13:47:29 -04001440 context->recordError(Error(GL_INVALID_OPERATION));
1441 return false;
Jamie Madillac528012014-06-20 13:21:23 -04001442 }
1443
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001444 const gl::Framebuffer *fbo = state.getDrawFramebuffer();
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001445 if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
1446 {
Geoff Langb1196682014-07-23 13:47:29 -04001447 context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
1448 return false;
Jamie Madill13f7d7d2014-06-20 13:21:27 -04001449 }
1450
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001451 if (state.getCurrentProgramId() == 0)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001452 {
Geoff Langb1196682014-07-23 13:47:29 -04001453 context->recordError(Error(GL_INVALID_OPERATION));
1454 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001455 }
1456
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001457 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
Brandon Jones43a53e22014-08-28 16:23:22 -07001458 if (!programBinary->validateSamplers(NULL, context->getCaps()))
Jamie Madilld4cfa572014-07-08 10:00:32 -04001459 {
Geoff Langb1196682014-07-23 13:47:29 -04001460 context->recordError(Error(GL_INVALID_OPERATION));
1461 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001462 }
1463
Jamie Madill2b976812014-08-25 15:47:49 -04001464 // Buffer validations
1465 const VertexArray *vao = state.getVertexArray();
1466 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1467 {
1468 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1469 bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
1470 if (attribActive && attrib.enabled)
1471 {
1472 gl::Buffer *buffer = attrib.buffer.get();
1473
1474 if (buffer)
1475 {
1476 GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
1477 GLint64 maxVertexElement = 0;
1478
1479 if (attrib.divisor > 0)
1480 {
1481 maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
1482 }
1483 else
1484 {
1485 maxVertexElement = static_cast<GLint64>(maxVertex);
1486 }
1487
1488 GLint64 attribDataSize = maxVertexElement * attribStride;
1489
1490 // [OpenGL ES 3.0.2] section 2.9.4 page 40:
1491 // We can return INVALID_OPERATION if our vertex attribute does not have
1492 // enough backing data.
1493 if (attribDataSize > buffer->getSize())
1494 {
Geoff Langb1196682014-07-23 13:47:29 -04001495 context->recordError(Error(GL_INVALID_OPERATION));
1496 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001497 }
1498 }
1499 else if (attrib.pointer == NULL)
1500 {
1501 // This is an application error that would normally result in a crash,
1502 // but we catch it and return an error
Geoff Langb1196682014-07-23 13:47:29 -04001503 context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
1504 return false;
Jamie Madill2b976812014-08-25 15:47:49 -04001505 }
1506 }
1507 }
1508
Jamie Madill250d33f2014-06-06 17:09:03 -04001509 // No-op if zero count
1510 return (count > 0);
1511}
1512
Geoff Langb1196682014-07-23 13:47:29 -04001513bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madill250d33f2014-06-06 17:09:03 -04001514{
Jamie Madillfd716582014-06-06 17:09:04 -04001515 if (first < 0)
Jamie Madill250d33f2014-06-06 17:09:03 -04001516 {
Geoff Langb1196682014-07-23 13:47:29 -04001517 context->recordError(Error(GL_INVALID_VALUE));
1518 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001519 }
1520
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001521 const State &state = context->getState();
1522 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madillfd716582014-06-06 17:09:04 -04001523 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
1524 curTransformFeedback->getDrawMode() != mode)
1525 {
1526 // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
1527 // that does not match the current transform feedback object's draw mode (if transform feedback
1528 // is active), (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001529 context->recordError(Error(GL_INVALID_OPERATION));
1530 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001531 }
1532
Geoff Langb1196682014-07-23 13:47:29 -04001533 if (!ValidateDrawBase(context, mode, count, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001534 {
1535 return false;
1536 }
1537
1538 return true;
1539}
1540
Geoff Langb1196682014-07-23 13:47:29 -04001541bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
Jamie Madillfd716582014-06-06 17:09:04 -04001542{
1543 if (primcount < 0)
1544 {
Geoff Langb1196682014-07-23 13:47:29 -04001545 context->recordError(Error(GL_INVALID_VALUE));
1546 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001547 }
1548
Jamie Madill2b976812014-08-25 15:47:49 -04001549 if (!ValidateDrawArrays(context, mode, first, count, primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001550 {
1551 return false;
1552 }
1553
1554 // No-op if zero primitive count
1555 return (primcount > 0);
1556}
1557
Geoff Lang87a93302014-09-16 13:29:43 -04001558static bool ValidateDrawInstancedANGLE(Context *context)
1559{
1560 // Verify there is at least one active attribute with a divisor of zero
1561 const gl::State& state = context->getState();
1562
1563 gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
1564
1565 const VertexArray *vao = state.getVertexArray();
1566 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1567 {
1568 const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
1569 bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
1570 if (active && attrib.divisor == 0)
1571 {
1572 return true;
1573 }
1574 }
1575
1576 context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
1577 "has a divisor of zero."));
1578 return false;
1579}
1580
1581bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1582{
1583 if (!ValidateDrawInstancedANGLE(context))
1584 {
1585 return false;
1586 }
1587
1588 return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
1589}
1590
Geoff Langb1196682014-07-23 13:47:29 -04001591bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
Jamie Madill2b976812014-08-25 15:47:49 -04001592 const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001593{
Jamie Madill250d33f2014-06-06 17:09:03 -04001594 switch (type)
1595 {
1596 case GL_UNSIGNED_BYTE:
1597 case GL_UNSIGNED_SHORT:
1598 break;
1599 case GL_UNSIGNED_INT:
Geoff Langc0b9ef42014-07-02 10:02:37 -04001600 if (!context->getExtensions().elementIndexUint)
Jamie Madill250d33f2014-06-06 17:09:03 -04001601 {
Geoff Langb1196682014-07-23 13:47:29 -04001602 context->recordError(Error(GL_INVALID_ENUM));
1603 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001604 }
1605 break;
1606 default:
Geoff Langb1196682014-07-23 13:47:29 -04001607 context->recordError(Error(GL_INVALID_ENUM));
1608 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001609 }
1610
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001611 const State &state = context->getState();
1612
1613 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
Jamie Madill250d33f2014-06-06 17:09:03 -04001614 if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
1615 {
1616 // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
1617 // while transform feedback is active, (3.0.2, section 2.14, pg 86)
Geoff Langb1196682014-07-23 13:47:29 -04001618 context->recordError(Error(GL_INVALID_OPERATION));
1619 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001620 }
1621
1622 // Check for mapped buffers
Jamie Madilld9ba4f72014-08-04 10:47:59 -04001623 if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
Jamie Madill250d33f2014-06-06 17:09:03 -04001624 {
Geoff Langb1196682014-07-23 13:47:29 -04001625 context->recordError(Error(GL_INVALID_OPERATION));
1626 return false;
Jamie Madill250d33f2014-06-06 17:09:03 -04001627 }
1628
Jamie Madill2b976812014-08-25 15:47:49 -04001629 const gl::VertexArray *vao = state.getVertexArray();
1630 const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1631 if (!indices && !elementArrayBuffer)
Jamie Madilld4cfa572014-07-08 10:00:32 -04001632 {
Geoff Langb1196682014-07-23 13:47:29 -04001633 context->recordError(Error(GL_INVALID_OPERATION));
1634 return false;
Jamie Madilld4cfa572014-07-08 10:00:32 -04001635 }
1636
Jamie Madillae3000b2014-08-25 15:47:51 -04001637 if (elementArrayBuffer)
1638 {
1639 const gl::Type &typeInfo = gl::GetTypeInfo(type);
1640
1641 GLint64 offset = reinterpret_cast<GLint64>(indices);
1642 GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
1643
1644 // check for integer overflows
1645 if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
1646 byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
1647 {
Geoff Langb1196682014-07-23 13:47:29 -04001648 context->recordError(Error(GL_OUT_OF_MEMORY));
1649 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001650 }
1651
1652 // Check for reading past the end of the bound buffer object
1653 if (byteCount > elementArrayBuffer->getSize())
1654 {
Geoff Langb1196682014-07-23 13:47:29 -04001655 context->recordError(Error(GL_INVALID_OPERATION));
1656 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001657 }
1658 }
1659 else if (!indices)
1660 {
1661 // Catch this programming error here
Geoff Langb1196682014-07-23 13:47:29 -04001662 context->recordError(Error(GL_INVALID_OPERATION));
1663 return false;
Jamie Madillae3000b2014-08-25 15:47:51 -04001664 }
1665
Jamie Madill2b976812014-08-25 15:47:49 -04001666 // Use max index to validate if our vertex buffers are large enough for the pull.
1667 // TODO: offer fast path, with disabled index validation.
1668 // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
1669 if (elementArrayBuffer)
1670 {
Jacek Cabana5521de2014-10-01 17:23:46 +02001671 uintptr_t offset = reinterpret_cast<uintptr_t>(indices);
Jamie Madill2b976812014-08-25 15:47:49 -04001672 if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
1673 {
Geoff Langc8d297a2014-09-19 11:09:08 -04001674 const uint8_t *dataPointer = NULL;
1675 Error error = elementArrayBuffer->getImplementation()->getData(&dataPointer);
1676 if (error.isError())
1677 {
1678 context->recordError(error);
1679 return false;
1680 }
1681
1682 const uint8_t *offsetPointer = dataPointer + offset;
Jamie Madill2b976812014-08-25 15:47:49 -04001683 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
1684 }
1685 }
1686 else
1687 {
1688 *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
1689 }
1690
Geoff Langb1196682014-07-23 13:47:29 -04001691 if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
Jamie Madillfd716582014-06-06 17:09:04 -04001692 {
1693 return false;
1694 }
1695
1696 return true;
1697}
1698
Geoff Langb1196682014-07-23 13:47:29 -04001699bool ValidateDrawElementsInstanced(Context *context,
Jamie Madill2b976812014-08-25 15:47:49 -04001700 GLenum mode, GLsizei count, GLenum type,
1701 const GLvoid *indices, GLsizei primcount,
1702 rx::RangeUI *indexRangeOut)
Jamie Madillfd716582014-06-06 17:09:04 -04001703{
1704 if (primcount < 0)
1705 {
Geoff Langb1196682014-07-23 13:47:29 -04001706 context->recordError(Error(GL_INVALID_VALUE));
1707 return false;
Jamie Madillfd716582014-06-06 17:09:04 -04001708 }
1709
Jamie Madill2b976812014-08-25 15:47:49 -04001710 if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
Jamie Madillfd716582014-06-06 17:09:04 -04001711 {
1712 return false;
1713 }
1714
1715 // No-op zero primitive count
1716 return (primcount > 0);
Jamie Madill250d33f2014-06-06 17:09:03 -04001717}
1718
Geoff Lang87a93302014-09-16 13:29:43 -04001719bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
1720 const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
1721{
1722 if (!ValidateDrawInstancedANGLE(context))
1723 {
1724 return false;
1725 }
1726
1727 return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
1728}
1729
Geoff Langb1196682014-07-23 13:47:29 -04001730bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001731 GLuint texture, GLint level)
Jamie Madill570f7c82014-07-03 10:38:54 -04001732{
Jamie Madill55ec3b12014-07-03 10:38:57 -04001733 if (!ValidFramebufferTarget(target))
1734 {
Geoff Langb1196682014-07-23 13:47:29 -04001735 context->recordError(Error(GL_INVALID_ENUM));
1736 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001737 }
1738
1739 if (!ValidateAttachmentTarget(context, attachment))
Jamie Madill570f7c82014-07-03 10:38:54 -04001740 {
1741 return false;
1742 }
1743
Jamie Madill55ec3b12014-07-03 10:38:57 -04001744 if (texture != 0)
1745 {
1746 gl::Texture *tex = context->getTexture(texture);
1747
1748 if (tex == NULL)
1749 {
Geoff Langb1196682014-07-23 13:47:29 -04001750 context->recordError(Error(GL_INVALID_OPERATION));
1751 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001752 }
1753
1754 if (level < 0)
1755 {
Geoff Langb1196682014-07-23 13:47:29 -04001756 context->recordError(Error(GL_INVALID_VALUE));
1757 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001758 }
1759 }
1760
Shannon Woods53a94a82014-06-24 15:20:36 -04001761 const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
1762 GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id();
Jamie Madill55ec3b12014-07-03 10:38:57 -04001763
1764 if (framebufferHandle == 0 || !framebuffer)
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 return true;
1771}
1772
Geoff Langb1196682014-07-23 13:47:29 -04001773bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
Jamie Madill55ec3b12014-07-03 10:38:57 -04001774 GLenum textarget, GLuint texture, GLint level)
1775{
1776 // Attachments are required to be bound to level 0 in ES2
1777 if (context->getClientVersion() < 3 && level != 0)
1778 {
Geoff Langb1196682014-07-23 13:47:29 -04001779 context->recordError(Error(GL_INVALID_VALUE));
1780 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001781 }
1782
1783 if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
Jamie Madill570f7c82014-07-03 10:38:54 -04001784 {
1785 return false;
1786 }
1787
Jamie Madill55ec3b12014-07-03 10:38:57 -04001788 if (texture != 0)
1789 {
1790 gl::Texture *tex = context->getTexture(texture);
1791 ASSERT(tex);
1792
Jamie Madill2a6564e2014-07-11 09:53:19 -04001793 const gl::Caps &caps = context->getCaps();
1794
Jamie Madill55ec3b12014-07-03 10:38:57 -04001795 switch (textarget)
1796 {
1797 case GL_TEXTURE_2D:
1798 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001799 if (level > gl::log2(caps.max2DTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001800 {
Geoff Langb1196682014-07-23 13:47:29 -04001801 context->recordError(Error(GL_INVALID_VALUE));
1802 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001803 }
1804 if (tex->getTarget() != GL_TEXTURE_2D)
1805 {
Geoff Langb1196682014-07-23 13:47:29 -04001806 context->recordError(Error(GL_INVALID_OPERATION));
1807 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001808 }
1809 gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
1810 if (tex2d->isCompressed(level))
1811 {
Geoff Langb1196682014-07-23 13:47:29 -04001812 context->recordError(Error(GL_INVALID_OPERATION));
1813 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001814 }
1815 }
1816 break;
1817
1818 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1819 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1820 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1821 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1822 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1823 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1824 {
Jamie Madill2a6564e2014-07-11 09:53:19 -04001825 if (level > gl::log2(caps.maxCubeMapTextureSize))
Jamie Madill55ec3b12014-07-03 10:38:57 -04001826 {
Geoff Langb1196682014-07-23 13:47:29 -04001827 context->recordError(Error(GL_INVALID_VALUE));
1828 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001829 }
1830 if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1831 {
Geoff Langb1196682014-07-23 13:47:29 -04001832 context->recordError(Error(GL_INVALID_OPERATION));
1833 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001834 }
1835 gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
1836 if (texcube->isCompressed(textarget, level))
1837 {
Geoff Langb1196682014-07-23 13:47:29 -04001838 context->recordError(Error(GL_INVALID_OPERATION));
1839 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001840 }
1841 }
1842 break;
1843
1844 default:
Geoff Langb1196682014-07-23 13:47:29 -04001845 context->recordError(Error(GL_INVALID_ENUM));
1846 return false;
Jamie Madill55ec3b12014-07-03 10:38:57 -04001847 }
1848 }
1849
Jamie Madill570f7c82014-07-03 10:38:54 -04001850 return true;
1851}
1852
Geoff Langb1196682014-07-23 13:47:29 -04001853bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
Jamie Madill0063c512014-08-25 15:47:53 -04001854{
1855 if (program == 0)
1856 {
Geoff Langb1196682014-07-23 13:47:29 -04001857 context->recordError(Error(GL_INVALID_VALUE));
1858 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001859 }
1860
1861 gl::Program *programObject = context->getProgram(program);
1862
1863 if (!programObject || !programObject->isLinked())
1864 {
Geoff Langb1196682014-07-23 13:47:29 -04001865 context->recordError(Error(GL_INVALID_OPERATION));
1866 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001867 }
1868
1869 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
1870 if (!programBinary)
1871 {
Geoff Langb1196682014-07-23 13:47:29 -04001872 context->recordError(Error(GL_INVALID_OPERATION));
1873 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001874 }
1875
Jamie Madill549c7fd2014-08-25 15:47:56 -04001876 if (!programBinary->isValidUniformLocation(location))
1877 {
Geoff Langb1196682014-07-23 13:47:29 -04001878 context->recordError(Error(GL_INVALID_OPERATION));
1879 return false;
Jamie Madill549c7fd2014-08-25 15:47:56 -04001880 }
1881
Jamie Madill0063c512014-08-25 15:47:53 -04001882 return true;
1883}
1884
Geoff Langb1196682014-07-23 13:47:29 -04001885bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
Jamie Madill78f41802014-08-25 15:47:55 -04001886{
1887 return ValidateGetUniformBase(context, program, location);
1888}
1889
Geoff Langb1196682014-07-23 13:47:29 -04001890bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001891{
Jamie Madill78f41802014-08-25 15:47:55 -04001892 return ValidateGetUniformBase(context, program, location);
1893}
1894
Geoff Langb1196682014-07-23 13:47:29 -04001895static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
Jamie Madill78f41802014-08-25 15:47:55 -04001896{
1897 if (!ValidateGetUniformBase(context, program, location))
Jamie Madill0063c512014-08-25 15:47:53 -04001898 {
Jamie Madill78f41802014-08-25 15:47:55 -04001899 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001900 }
1901
Jamie Madilla502c742014-08-28 17:19:13 -04001902 gl::Program *programObject = context->getProgram(program);
1903 ASSERT(programObject);
1904 gl::ProgramBinary *programBinary = programObject->getProgramBinary();
Jamie Madill0063c512014-08-25 15:47:53 -04001905
Jamie Madill78f41802014-08-25 15:47:55 -04001906 // sized queries -- ensure the provided buffer is large enough
1907 LinkedUniform *uniform = programBinary->getUniformByLocation(location);
1908 size_t requiredBytes = VariableExternalSize(uniform->type);
1909 if (static_cast<size_t>(bufSize) < requiredBytes)
Jamie Madill0063c512014-08-25 15:47:53 -04001910 {
Geoff Langb1196682014-07-23 13:47:29 -04001911 context->recordError(Error(GL_INVALID_OPERATION));
1912 return false;
Jamie Madill0063c512014-08-25 15:47:53 -04001913 }
1914
1915 return true;
1916}
1917
Geoff Langb1196682014-07-23 13:47:29 -04001918bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001919{
Jamie Madill78f41802014-08-25 15:47:55 -04001920 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001921}
1922
Geoff Langb1196682014-07-23 13:47:29 -04001923bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
Jamie Madill0063c512014-08-25 15:47:53 -04001924{
Jamie Madill78f41802014-08-25 15:47:55 -04001925 return ValidateSizedGetUniform(context, program, location, bufSize);
Jamie Madill0063c512014-08-25 15:47:53 -04001926}
1927
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001928}