blob: 93edd45ed242064e702df7bbb76518a108f4ee9b [file] [log] [blame]
Geoff Lange8ebe7f2013-08-05 15:03:13 -04001#include "precompiled.h"
2//
3// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// validationES.h: Validation functions for generic OpenGL ES entry point parameters
9
10#include "libGLESv2/validationES.h"
11#include "libGLESv2/Context.h"
12#include "libGLESv2/Texture.h"
13#include "libGLESv2/Framebuffer.h"
14#include "libGLESv2/Renderbuffer.h"
15#include "libGLESv2/formatutils.h"
16#include "libGLESv2/main.h"
17
18#include "common/mathutil.h"
19#include "common/utilities.h"
20
21namespace gl
22{
23
Geoff Lang34dbb6f2013-08-05 15:05:47 -040024bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
Geoff Lange8ebe7f2013-08-05 15:03:13 -040025 GLenum internalformat, GLsizei width, GLsizei height,
26 bool angleExtension)
27{
28 switch (target)
29 {
30 case GL_RENDERBUFFER:
31 break;
32 default:
33 return gl::error(GL_INVALID_ENUM, false);
34 }
35
36 if (width < 0 || height < 0 || samples < 0)
37 {
38 return gl::error(GL_INVALID_VALUE, false);
39 }
40
41 if (!gl::IsValidInternalFormat(internalformat, context))
42 {
43 return gl::error(GL_INVALID_ENUM, false);
44 }
45
46 // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
47 // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
48 // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
49 // internal format must be sized and not an integer format if samples is greater than zero.
50 if (!gl::IsSizedInternalFormat(internalformat, context->getClientVersion()))
51 {
52 return gl::error(GL_INVALID_ENUM, false);
53 }
54
Geoff Langb2f3d052013-08-13 12:49:27 -040055 GLenum componentType = gl::GetComponentType(internalformat, context->getClientVersion());
56 if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
Geoff Lange8ebe7f2013-08-05 15:03:13 -040057 {
58 return gl::error(GL_INVALID_OPERATION, false);
59 }
60
61 if (!gl::IsColorRenderingSupported(internalformat, context) &&
62 !gl::IsDepthRenderingSupported(internalformat, context) &&
63 !gl::IsStencilRenderingSupported(internalformat, context))
64 {
65 return gl::error(GL_INVALID_ENUM, false);
66 }
67
68 if (std::max(width, height) > context->getMaximumRenderbufferDimension())
69 {
70 return gl::error(GL_INVALID_VALUE, false);
71 }
72
73 // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
74 // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2)
75 // states that samples must be less than or equal to the maximum samples for the specified
76 // internal format.
77 if (angleExtension)
78 {
79 if (samples > context->getMaxSupportedSamples())
80 {
81 return gl::error(GL_INVALID_VALUE, false);
82 }
83 }
84 else
85 {
86 if (samples > context->getMaxSupportedFormatSamples(internalformat))
87 {
88 return gl::error(GL_INVALID_VALUE, false);
89 }
90 }
91
92 GLuint handle = context->getRenderbufferHandle();
93 if (handle == 0)
94 {
95 return gl::error(GL_INVALID_OPERATION, false);
96 }
97
98 return true;
99}
100
Geoff Lang125deab2013-08-09 13:34:16 -0400101static bool IsPartialBlit(gl::Context *context, gl::Renderbuffer *readBuffer, gl::Renderbuffer *writeBuffer,
102 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
103 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
104{
105 if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 ||
106 dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() ||
107 srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight())
108 {
109 return true;
110 }
111 else if (context->isScissorTestEnabled())
112 {
113 int scissorX, scissorY, scissorWidth, scissorHeight;
114 context->getScissorParams(&scissorX, &scissorY, &scissorWidth, &scissorHeight);
115
116 return scissorX > 0 || scissorY > 0 ||
117 scissorWidth < writeBuffer->getWidth() ||
118 scissorHeight < writeBuffer->getHeight();
119 }
120 else
121 {
122 return false;
123 }
124}
125
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400126bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400127 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
128 GLenum filter, bool fromAngleExtension)
129{
130 switch (filter)
131 {
132 case GL_NEAREST:
133 break;
134 case GL_LINEAR:
135 if (fromAngleExtension)
136 {
137 return gl::error(GL_INVALID_ENUM, false);
138 }
139 break;
140 default:
141 return gl::error(GL_INVALID_ENUM, false);
142 }
143
144 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
145 {
146 return gl::error(GL_INVALID_VALUE, false);
147 }
148
149 if (mask == 0)
150 {
151 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
152 // buffers are copied.
153 return false;
154 }
155
156 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
157 {
158 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
159 return gl::error(GL_INVALID_OPERATION, false);
160 }
161
162 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
163 // color buffer, leaving only nearest being unfiltered from above
164 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
165 {
166 return gl::error(GL_INVALID_OPERATION, false);
167 }
168
169 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
170 {
171 if (fromAngleExtension)
172 {
173 ERR("Blits with the same source and destination framebuffer are not supported by this "
174 "implementation.");
175 }
176 return gl::error(GL_INVALID_OPERATION, false);
177 }
178
179 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
180 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
181 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
182 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
183 {
184 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
185 }
186
187 if (drawFramebuffer->getSamples() != 0)
188 {
189 return gl::error(GL_INVALID_OPERATION, false);
190 }
191
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400192 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
193
194 GLuint clientVersion = context->getClientVersion();
195
196 if (mask & GL_COLOR_BUFFER_BIT)
197 {
198 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
199 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
200
201 if (readColorBuffer && drawColorBuffer)
202 {
203 GLint readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400204 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400205
206 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
207 {
208 if (drawFramebuffer->isEnabledColorAttachment(i))
209 {
Geoff Langb2f3d052013-08-13 12:49:27 -0400210 GLint drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
211 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400212
Geoff Langb2f3d052013-08-13 12:49:27 -0400213 // The GL ES 3.0.2 spec (pg 193) states that:
214 // 1) If the read buffer is fixed point format, the draw buffer must be as well
215 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
216 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
217 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
218 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400219 {
220 return gl::error(GL_INVALID_OPERATION, false);
221 }
222
Geoff Langb2f3d052013-08-13 12:49:27 -0400223 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400224 {
225 return gl::error(GL_INVALID_OPERATION, false);
226 }
227
Geoff Langb2f3d052013-08-13 12:49:27 -0400228 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400229 {
230 return gl::error(GL_INVALID_OPERATION, false);
231 }
232
Geoff Langb2f3d052013-08-13 12:49:27 -0400233 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400234 {
235 return gl::error(GL_INVALID_OPERATION, false);
236 }
237 }
238 }
239
Geoff Langb2f3d052013-08-13 12:49:27 -0400240 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400241 {
242 return gl::error(GL_INVALID_OPERATION, false);
243 }
244
245 if (fromAngleExtension)
246 {
247 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
248 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
249 {
250 return gl::error(GL_INVALID_OPERATION, false);
251 }
252
253 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
254 {
255 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
256 {
257 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
258 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
259 {
260 return gl::error(GL_INVALID_OPERATION, false);
261 }
262
263 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
264 {
265 return gl::error(GL_INVALID_OPERATION, false);
266 }
267 }
268 }
Geoff Lang125deab2013-08-09 13:34:16 -0400269 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
270 srcX0, srcY0, srcX1, srcY1,
271 dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400272 {
273 return gl::error(GL_INVALID_OPERATION, false);
274 }
275 }
276 }
277 }
278
279 if (mask & GL_DEPTH_BUFFER_BIT)
280 {
281 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
282 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
283
284 if (readDepthBuffer && drawDepthBuffer)
285 {
286 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
287 {
288 return gl::error(GL_INVALID_OPERATION, false);
289 }
290
291 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
292 {
293 return gl::error(GL_INVALID_OPERATION, false);
294 }
295
296 if (fromAngleExtension)
297 {
Geoff Lang125deab2013-08-09 13:34:16 -0400298 if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer,
299 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400300 {
301 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
302 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
303 }
304
305 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
306 {
307 return gl::error(GL_INVALID_OPERATION, false);
308 }
309 }
310 }
311 }
312
313 if (mask & GL_STENCIL_BUFFER_BIT)
314 {
315 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
316 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
317
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400318 if (readStencilBuffer && drawStencilBuffer)
319 {
320 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
321 {
322 return gl::error(GL_INVALID_OPERATION, false);
323 }
324
325 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
326 {
327 return gl::error(GL_INVALID_OPERATION, false);
328 }
329
330 if (fromAngleExtension)
331 {
Geoff Lang125deab2013-08-09 13:34:16 -0400332 if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer,
333 srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400334 {
335 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
336 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
337 }
338
339 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
340 {
341 return gl::error(GL_INVALID_OPERATION, false);
342 }
343 }
344 }
345 }
346
347 return true;
348}
349
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400350bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400351{
352 switch (pname)
353 {
354 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
355 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
356 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
357 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
358 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
359 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
360 case GL_CURRENT_VERTEX_ATTRIB:
361 return true;
362
363 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
364 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
365 // the same constant.
366 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
367 return true;
368
369 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
370 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
371
372 default:
373 return gl::error(GL_INVALID_ENUM, false);
374 }
375}
376
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400377bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400378{
379 switch (pname)
380 {
381 case GL_TEXTURE_WRAP_R:
382 case GL_TEXTURE_SWIZZLE_R:
383 case GL_TEXTURE_SWIZZLE_G:
384 case GL_TEXTURE_SWIZZLE_B:
385 case GL_TEXTURE_SWIZZLE_A:
386 case GL_TEXTURE_BASE_LEVEL:
387 case GL_TEXTURE_MAX_LEVEL:
388 case GL_TEXTURE_COMPARE_MODE:
389 case GL_TEXTURE_COMPARE_FUNC:
390 case GL_TEXTURE_MIN_LOD:
391 case GL_TEXTURE_MAX_LOD:
392 if (context->getClientVersion() < 3)
393 {
394 return gl::error(GL_INVALID_ENUM, false);
395 }
396 break;
397
398 default: break;
399 }
400
401 switch (pname)
402 {
403 case GL_TEXTURE_WRAP_S:
404 case GL_TEXTURE_WRAP_T:
405 case GL_TEXTURE_WRAP_R:
406 switch (param)
407 {
408 case GL_REPEAT:
409 case GL_CLAMP_TO_EDGE:
410 case GL_MIRRORED_REPEAT:
411 return true;
412 default:
413 return gl::error(GL_INVALID_ENUM, false);
414 }
415
416 case GL_TEXTURE_MIN_FILTER:
417 switch (param)
418 {
419 case GL_NEAREST:
420 case GL_LINEAR:
421 case GL_NEAREST_MIPMAP_NEAREST:
422 case GL_LINEAR_MIPMAP_NEAREST:
423 case GL_NEAREST_MIPMAP_LINEAR:
424 case GL_LINEAR_MIPMAP_LINEAR:
425 return true;
426 default:
427 return gl::error(GL_INVALID_ENUM, false);
428 }
429 break;
430
431 case GL_TEXTURE_MAG_FILTER:
432 switch (param)
433 {
434 case GL_NEAREST:
435 case GL_LINEAR:
436 return true;
437 default:
438 return gl::error(GL_INVALID_ENUM, false);
439 }
440 break;
441
442 case GL_TEXTURE_USAGE_ANGLE:
443 switch (param)
444 {
445 case GL_NONE:
446 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
447 return true;
448 default:
449 return gl::error(GL_INVALID_ENUM, false);
450 }
451 break;
452
453 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
454 if (!context->supportsTextureFilterAnisotropy())
455 {
456 return gl::error(GL_INVALID_ENUM, false);
457 }
458
459 // we assume the parameter passed to this validation method is truncated, not rounded
460 if (param < 1)
461 {
462 return gl::error(GL_INVALID_VALUE, false);
463 }
464 return true;
465
466 case GL_TEXTURE_MIN_LOD:
467 case GL_TEXTURE_MAX_LOD:
468 // any value is permissible
469 return true;
470
471 case GL_TEXTURE_COMPARE_MODE:
472 switch (param)
473 {
474 case GL_NONE:
475 case GL_COMPARE_REF_TO_TEXTURE:
476 return true;
477 default:
478 return gl::error(GL_INVALID_ENUM, false);
479 }
480 break;
481
482 case GL_TEXTURE_COMPARE_FUNC:
483 switch (param)
484 {
485 case GL_LEQUAL:
486 case GL_GEQUAL:
487 case GL_LESS:
488 case GL_GREATER:
489 case GL_EQUAL:
490 case GL_NOTEQUAL:
491 case GL_ALWAYS:
492 case GL_NEVER:
493 return true;
494 default:
495 return gl::error(GL_INVALID_ENUM, false);
496 }
497 break;
498
499 case GL_TEXTURE_SWIZZLE_R:
500 case GL_TEXTURE_SWIZZLE_G:
501 case GL_TEXTURE_SWIZZLE_B:
502 case GL_TEXTURE_SWIZZLE_A:
503 case GL_TEXTURE_BASE_LEVEL:
504 case GL_TEXTURE_MAX_LEVEL:
505 UNIMPLEMENTED();
506 return true;
507
508 default:
509 return gl::error(GL_INVALID_ENUM, false);
510 }
511}
512
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400513bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400514{
515 switch (pname)
516 {
517 case GL_TEXTURE_MIN_FILTER:
518 case GL_TEXTURE_MAG_FILTER:
519 case GL_TEXTURE_WRAP_S:
520 case GL_TEXTURE_WRAP_T:
521 case GL_TEXTURE_WRAP_R:
522 case GL_TEXTURE_MIN_LOD:
523 case GL_TEXTURE_MAX_LOD:
524 case GL_TEXTURE_COMPARE_MODE:
525 case GL_TEXTURE_COMPARE_FUNC:
526 return true;
527
528 default:
529 return gl::error(GL_INVALID_ENUM, false);
530 }
531}
532
533}