blob: eacdd9b3e969c244007184d335202b9ec6304152 [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 Lang34dbb6f2013-08-05 15:05:47 -0400101bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400102 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
103 GLenum filter, bool fromAngleExtension)
104{
105 switch (filter)
106 {
107 case GL_NEAREST:
108 break;
109 case GL_LINEAR:
110 if (fromAngleExtension)
111 {
112 return gl::error(GL_INVALID_ENUM, false);
113 }
114 break;
115 default:
116 return gl::error(GL_INVALID_ENUM, false);
117 }
118
119 if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
120 {
121 return gl::error(GL_INVALID_VALUE, false);
122 }
123
124 if (mask == 0)
125 {
126 // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no
127 // buffers are copied.
128 return false;
129 }
130
131 if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
132 {
133 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
134 return gl::error(GL_INVALID_OPERATION, false);
135 }
136
137 // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
138 // color buffer, leaving only nearest being unfiltered from above
139 if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
140 {
141 return gl::error(GL_INVALID_OPERATION, false);
142 }
143
144 if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
145 {
146 if (fromAngleExtension)
147 {
148 ERR("Blits with the same source and destination framebuffer are not supported by this "
149 "implementation.");
150 }
151 return gl::error(GL_INVALID_OPERATION, false);
152 }
153
154 gl::Framebuffer *readFramebuffer = context->getReadFramebuffer();
155 gl::Framebuffer *drawFramebuffer = context->getDrawFramebuffer();
156 if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
157 !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
158 {
159 return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
160 }
161
162 if (drawFramebuffer->getSamples() != 0)
163 {
164 return gl::error(GL_INVALID_OPERATION, false);
165 }
166
167 gl::Rectangle sourceClippedRect, destClippedRect;
168 bool partialCopy;
169 if (!context->clipBlitFramebufferCoordinates(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
170 &sourceClippedRect, &destClippedRect, &partialCopy))
171 {
172 return gl::error(GL_INVALID_OPERATION, false);
173 }
174
175 bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
176
177 GLuint clientVersion = context->getClientVersion();
178
179 if (mask & GL_COLOR_BUFFER_BIT)
180 {
181 gl::Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
182 gl::Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
183
184 if (readColorBuffer && drawColorBuffer)
185 {
186 GLint readInternalFormat = readColorBuffer->getActualFormat();
Geoff Langb2f3d052013-08-13 12:49:27 -0400187 GLenum readComponentType = gl::GetComponentType(readInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400188
189 for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
190 {
191 if (drawFramebuffer->isEnabledColorAttachment(i))
192 {
Geoff Langb2f3d052013-08-13 12:49:27 -0400193 GLint drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
194 GLenum drawComponentType = gl::GetComponentType(drawInternalFormat, clientVersion);
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400195
Geoff Langb2f3d052013-08-13 12:49:27 -0400196 // The GL ES 3.0.2 spec (pg 193) states that:
197 // 1) If the read buffer is fixed point format, the draw buffer must be as well
198 // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
199 // 3) If the read buffer is a signed integer format, the draw buffer must be as well
200 if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
201 !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400202 {
203 return gl::error(GL_INVALID_OPERATION, false);
204 }
205
Geoff Langb2f3d052013-08-13 12:49:27 -0400206 if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400207 {
208 return gl::error(GL_INVALID_OPERATION, false);
209 }
210
Geoff Langb2f3d052013-08-13 12:49:27 -0400211 if (readComponentType == GL_INT && drawComponentType != GL_INT)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400212 {
213 return gl::error(GL_INVALID_OPERATION, false);
214 }
215
Geoff Langb2f3d052013-08-13 12:49:27 -0400216 if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400217 {
218 return gl::error(GL_INVALID_OPERATION, false);
219 }
220 }
221 }
222
Geoff Langb2f3d052013-08-13 12:49:27 -0400223 if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400224 {
225 return gl::error(GL_INVALID_OPERATION, false);
226 }
227
228 if (fromAngleExtension)
229 {
230 const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
231 if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
232 {
233 return gl::error(GL_INVALID_OPERATION, false);
234 }
235
236 for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
237 {
238 if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
239 {
240 if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
241 drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
242 {
243 return gl::error(GL_INVALID_OPERATION, false);
244 }
245
246 if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
247 {
248 return gl::error(GL_INVALID_OPERATION, false);
249 }
250 }
251 }
252
253 if (partialCopy && readFramebuffer->getSamples() != 0)
254 {
255 return gl::error(GL_INVALID_OPERATION, false);
256 }
257 }
258 }
259 }
260
261 if (mask & GL_DEPTH_BUFFER_BIT)
262 {
263 gl::Renderbuffer *readDepthBuffer = readFramebuffer->getDepthbuffer();
264 gl::Renderbuffer *drawDepthBuffer = drawFramebuffer->getDepthbuffer();
265
266 if (readDepthBuffer && drawDepthBuffer)
267 {
268 if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
269 {
270 return gl::error(GL_INVALID_OPERATION, false);
271 }
272
273 if (readDepthBuffer->getSamples() > 0 && !sameBounds)
274 {
275 return gl::error(GL_INVALID_OPERATION, false);
276 }
277
278 if (fromAngleExtension)
279 {
280 if (partialCopy)
281 {
282 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
283 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
284 }
285
286 if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
287 {
288 return gl::error(GL_INVALID_OPERATION, false);
289 }
290 }
291 }
292 }
293
294 if (mask & GL_STENCIL_BUFFER_BIT)
295 {
296 gl::Renderbuffer *readStencilBuffer = readFramebuffer->getStencilbuffer();
297 gl::Renderbuffer *drawStencilBuffer = drawFramebuffer->getStencilbuffer();
298
299 if (fromAngleExtension && partialCopy)
300 {
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 (readStencilBuffer && drawStencilBuffer)
306 {
307 if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
308 {
309 return gl::error(GL_INVALID_OPERATION, false);
310 }
311
312 if (readStencilBuffer->getSamples() > 0 && !sameBounds)
313 {
314 return gl::error(GL_INVALID_OPERATION, false);
315 }
316
317 if (fromAngleExtension)
318 {
319 if (partialCopy)
320 {
321 ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
322 return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
323 }
324
325 if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
326 {
327 return gl::error(GL_INVALID_OPERATION, false);
328 }
329 }
330 }
331 }
332
333 return true;
334}
335
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400336bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400337{
338 switch (pname)
339 {
340 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
341 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
342 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
343 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
344 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
345 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
346 case GL_CURRENT_VERTEX_ATTRIB:
347 return true;
348
349 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
350 // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses
351 // the same constant.
352 META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
353 return true;
354
355 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
356 return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
357
358 default:
359 return gl::error(GL_INVALID_ENUM, false);
360 }
361}
362
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400363bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400364{
365 switch (pname)
366 {
367 case GL_TEXTURE_WRAP_R:
368 case GL_TEXTURE_SWIZZLE_R:
369 case GL_TEXTURE_SWIZZLE_G:
370 case GL_TEXTURE_SWIZZLE_B:
371 case GL_TEXTURE_SWIZZLE_A:
372 case GL_TEXTURE_BASE_LEVEL:
373 case GL_TEXTURE_MAX_LEVEL:
374 case GL_TEXTURE_COMPARE_MODE:
375 case GL_TEXTURE_COMPARE_FUNC:
376 case GL_TEXTURE_MIN_LOD:
377 case GL_TEXTURE_MAX_LOD:
378 if (context->getClientVersion() < 3)
379 {
380 return gl::error(GL_INVALID_ENUM, false);
381 }
382 break;
383
384 default: break;
385 }
386
387 switch (pname)
388 {
389 case GL_TEXTURE_WRAP_S:
390 case GL_TEXTURE_WRAP_T:
391 case GL_TEXTURE_WRAP_R:
392 switch (param)
393 {
394 case GL_REPEAT:
395 case GL_CLAMP_TO_EDGE:
396 case GL_MIRRORED_REPEAT:
397 return true;
398 default:
399 return gl::error(GL_INVALID_ENUM, false);
400 }
401
402 case GL_TEXTURE_MIN_FILTER:
403 switch (param)
404 {
405 case GL_NEAREST:
406 case GL_LINEAR:
407 case GL_NEAREST_MIPMAP_NEAREST:
408 case GL_LINEAR_MIPMAP_NEAREST:
409 case GL_NEAREST_MIPMAP_LINEAR:
410 case GL_LINEAR_MIPMAP_LINEAR:
411 return true;
412 default:
413 return gl::error(GL_INVALID_ENUM, false);
414 }
415 break;
416
417 case GL_TEXTURE_MAG_FILTER:
418 switch (param)
419 {
420 case GL_NEAREST:
421 case GL_LINEAR:
422 return true;
423 default:
424 return gl::error(GL_INVALID_ENUM, false);
425 }
426 break;
427
428 case GL_TEXTURE_USAGE_ANGLE:
429 switch (param)
430 {
431 case GL_NONE:
432 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
433 return true;
434 default:
435 return gl::error(GL_INVALID_ENUM, false);
436 }
437 break;
438
439 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
440 if (!context->supportsTextureFilterAnisotropy())
441 {
442 return gl::error(GL_INVALID_ENUM, false);
443 }
444
445 // we assume the parameter passed to this validation method is truncated, not rounded
446 if (param < 1)
447 {
448 return gl::error(GL_INVALID_VALUE, false);
449 }
450 return true;
451
452 case GL_TEXTURE_MIN_LOD:
453 case GL_TEXTURE_MAX_LOD:
454 // any value is permissible
455 return true;
456
457 case GL_TEXTURE_COMPARE_MODE:
458 switch (param)
459 {
460 case GL_NONE:
461 case GL_COMPARE_REF_TO_TEXTURE:
462 return true;
463 default:
464 return gl::error(GL_INVALID_ENUM, false);
465 }
466 break;
467
468 case GL_TEXTURE_COMPARE_FUNC:
469 switch (param)
470 {
471 case GL_LEQUAL:
472 case GL_GEQUAL:
473 case GL_LESS:
474 case GL_GREATER:
475 case GL_EQUAL:
476 case GL_NOTEQUAL:
477 case GL_ALWAYS:
478 case GL_NEVER:
479 return true;
480 default:
481 return gl::error(GL_INVALID_ENUM, false);
482 }
483 break;
484
485 case GL_TEXTURE_SWIZZLE_R:
486 case GL_TEXTURE_SWIZZLE_G:
487 case GL_TEXTURE_SWIZZLE_B:
488 case GL_TEXTURE_SWIZZLE_A:
489 case GL_TEXTURE_BASE_LEVEL:
490 case GL_TEXTURE_MAX_LEVEL:
491 UNIMPLEMENTED();
492 return true;
493
494 default:
495 return gl::error(GL_INVALID_ENUM, false);
496 }
497}
498
Geoff Lang34dbb6f2013-08-05 15:05:47 -0400499bool ValidateSamplerObjectParameter(GLenum pname)
Geoff Lange8ebe7f2013-08-05 15:03:13 -0400500{
501 switch (pname)
502 {
503 case GL_TEXTURE_MIN_FILTER:
504 case GL_TEXTURE_MAG_FILTER:
505 case GL_TEXTURE_WRAP_S:
506 case GL_TEXTURE_WRAP_T:
507 case GL_TEXTURE_WRAP_R:
508 case GL_TEXTURE_MIN_LOD:
509 case GL_TEXTURE_MAX_LOD:
510 case GL_TEXTURE_COMPARE_MODE:
511 case GL_TEXTURE_COMPARE_FUNC:
512 return true;
513
514 default:
515 return gl::error(GL_INVALID_ENUM, false);
516 }
517}
518
519}