blob: 3854fbb567e5fe8728af264fd0f90545a2e2ccac [file] [log] [blame]
Martin Radev66fb8202016-07-28 11:45:20 +03001//
2// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// validationES31.cpp: Validation functions for OpenGL ES 3.1 entry point parameters
8
Martin Radev66fb8202016-07-28 11:45:20 +03009#include "libANGLE/validationES31.h"
10
11#include "libANGLE/Context.h"
Geoff Lang2e43dbb2016-10-14 12:27:35 -040012#include "libANGLE/validationES.h"
13#include "libANGLE/validationES3.h"
Jiajia Qind9671222016-11-29 16:30:31 +080014#include "libANGLE/VertexArray.h"
Martin Radev66fb8202016-07-28 11:45:20 +030015
He Yunchao11b038b2016-11-22 21:24:04 +080016#include "common/utilities.h"
17
Martin Radev66fb8202016-07-28 11:45:20 +030018using namespace angle;
19
20namespace gl
21{
22
23bool ValidateGetBooleani_v(Context *context, GLenum target, GLuint index, GLboolean *data)
24{
Geoff Langeb66a6e2016-10-31 13:06:12 -040025 if (context->getClientVersion() < ES_3_1)
Martin Radev66fb8202016-07-28 11:45:20 +030026 {
27 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
28 return false;
29 }
30
Geoff Lang2e43dbb2016-10-14 12:27:35 -040031 if (!ValidateIndexedStateQuery(context, target, index, nullptr))
32 {
33 return false;
34 }
35
36 return true;
37}
38
39bool ValidateGetBooleani_vRobustANGLE(Context *context,
40 GLenum target,
41 GLuint index,
42 GLsizei bufSize,
43 GLsizei *length,
44 GLboolean *data)
45{
Geoff Langeb66a6e2016-10-31 13:06:12 -040046 if (context->getClientVersion() < ES_3_1)
Geoff Lang2e43dbb2016-10-14 12:27:35 -040047 {
48 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
49 return false;
50 }
51
52 if (!ValidateRobustEntryPoint(context, bufSize))
53 {
54 return false;
55 }
56
57 if (!ValidateIndexedStateQuery(context, target, index, length))
58 {
59 return false;
60 }
61
62 if (!ValidateRobustBufferSize(context, bufSize, *length))
Martin Radev66fb8202016-07-28 11:45:20 +030063 {
64 return false;
65 }
66
67 return true;
68}
69
Jiajia Qind9671222016-11-29 16:30:31 +080070bool ValidateDrawIndirectBase(Context *context, GLenum mode, const GLvoid *indirect)
71{
72 if (context->getClientVersion() < ES_3_1)
73 {
74 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
75 return false;
76 }
77
78 // Here the third parameter 1 is only to pass the count validation.
79 if (!ValidateDrawBase(context, mode, 1))
80 {
81 return false;
82 }
83
84 const State &state = context->getGLState();
85
86 // An INVALID_OPERATION error is generated if zero is bound to VERTEX_ARRAY_BINDING,
87 // DRAW_INDIRECT_BUFFER or to any enabled vertex array.
88 if (!state.getVertexArrayId())
89 {
90 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to VERTEX_ARRAY_BINDING"));
91 return false;
92 }
93
94 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
95 if (!drawIndirectBuffer)
96 {
97 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to DRAW_INDIRECT_BUFFER"));
98 return false;
99 }
100
101 // An INVALID_VALUE error is generated if indirect is not a multiple of the size, in basic
102 // machine units, of uint.
103 GLint64 offset = reinterpret_cast<GLint64>(indirect);
104 if ((static_cast<GLuint>(offset) % sizeof(GLuint)) != 0)
105 {
106 context->handleError(
107 Error(GL_INVALID_VALUE,
108 "indirect is not a multiple of the size, in basic machine units, of uint"));
109 return false;
110 }
111
112 return true;
113}
114
115bool ValidateDrawArraysIndirect(Context *context, GLenum mode, const GLvoid *indirect)
116{
117 const State &state = context->getGLState();
118 gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
119 if (curTransformFeedback && curTransformFeedback->isActive() &&
120 !curTransformFeedback->isPaused())
121 {
122 // An INVALID_OPERATION error is generated if transform feedback is active and not paused.
123 context->handleError(
124 Error(GL_INVALID_OPERATION, "transform feedback is active and not paused."));
125 return false;
126 }
127
128 if (!ValidateDrawIndirectBase(context, mode, indirect))
129 return false;
130
131 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
132 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
133 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawArraysIndirectCommand
134 // which's size is 4 * sizeof(uint).
135 auto checkedSum = checkedOffset + 4 * sizeof(GLuint);
136 if (!checkedSum.IsValid() ||
137 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
138 {
139 context->handleError(
140 Error(GL_INVALID_OPERATION,
141 "the command would source data beyond the end of the buffer object."));
142 return false;
143 }
144
145 return true;
146}
147
148bool ValidateDrawElementsIndirect(Context *context,
149 GLenum mode,
150 GLenum type,
151 const GLvoid *indirect)
152{
153 if (!ValidateDrawElementsBase(context, type))
154 return false;
155
156 const State &state = context->getGLState();
157 const VertexArray *vao = state.getVertexArray();
158 gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer().get();
159 if (!elementArrayBuffer)
160 {
161 context->handleError(Error(GL_INVALID_OPERATION, "zero is bound to ELEMENT_ARRAY_BUFFER"));
162 return false;
163 }
164
165 if (!ValidateDrawIndirectBase(context, mode, indirect))
166 return false;
167
168 gl::Buffer *drawIndirectBuffer = state.getDrawIndirectBuffer();
169 CheckedNumeric<size_t> checkedOffset(reinterpret_cast<size_t>(indirect));
170 // In OpenGL ES3.1 spec, session 10.5, it defines the struct of DrawElementsIndirectCommand
171 // which's size is 5 * sizeof(uint).
172 auto checkedSum = checkedOffset + 5 * sizeof(GLuint);
173 if (!checkedSum.IsValid() ||
174 checkedSum.ValueOrDie() > static_cast<size_t>(drawIndirectBuffer->getSize()))
175 {
176 context->handleError(
177 Error(GL_INVALID_OPERATION,
178 "the command would source data beyond the end of the buffer object."));
179 return false;
180 }
181
182 return true;
183}
184
He Yunchao11b038b2016-11-22 21:24:04 +0800185bool ValidateGetTexLevelParameterBase(Context *context,
186 GLenum target,
187 GLint level,
188 GLenum pname,
189 GLsizei *length)
190{
191 if (context->getClientVersion() < ES_3_1)
192 {
193 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1"));
194 return false;
195 }
196
197 if (length)
198 {
199 *length = 0;
200 }
201
202 if (!ValidTexLevelDestinationTarget(context, target))
203 {
204 context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
205 return false;
206 }
207
208 if (context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target) ==
209 nullptr)
210 {
211 context->handleError(Error(GL_INVALID_ENUM, "No texture bound."));
212 return false;
213 }
214
215 if (!ValidMipLevel(context, target, level))
216 {
217 context->handleError(Error(GL_INVALID_VALUE));
218 return false;
219 }
220
221 switch (pname)
222 {
223 case GL_TEXTURE_RED_TYPE:
224 case GL_TEXTURE_GREEN_TYPE:
225 case GL_TEXTURE_BLUE_TYPE:
226 case GL_TEXTURE_ALPHA_TYPE:
227 case GL_TEXTURE_DEPTH_TYPE:
228 break;
229 case GL_TEXTURE_RED_SIZE:
230 case GL_TEXTURE_GREEN_SIZE:
231 case GL_TEXTURE_BLUE_SIZE:
232 case GL_TEXTURE_ALPHA_SIZE:
233 case GL_TEXTURE_DEPTH_SIZE:
234 case GL_TEXTURE_STENCIL_SIZE:
235 case GL_TEXTURE_SHARED_SIZE:
236 break;
237 case GL_TEXTURE_INTERNAL_FORMAT:
238 case GL_TEXTURE_WIDTH:
239 case GL_TEXTURE_HEIGHT:
240 case GL_TEXTURE_DEPTH:
241 break;
242 case GL_TEXTURE_SAMPLES:
243 case GL_TEXTURE_FIXED_SAMPLE_LOCATIONS:
244 break;
245 case GL_TEXTURE_COMPRESSED:
246 break;
247 default:
248 context->handleError(Error(GL_INVALID_ENUM, "Unknown pname."));
249 return false;
250 }
251
252 if (length)
253 {
254 *length = 1;
255 }
256 return true;
257}
258
259bool ValidateGetTexLevelParameterfv(Context *context,
260 GLenum target,
261 GLint level,
262 GLenum pname,
263 GLfloat *params)
264{
265 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
266}
267
268bool ValidateGetTexLevelParameteriv(Context *context,
269 GLenum target,
270 GLint level,
271 GLenum pname,
272 GLint *params)
273{
274 return ValidateGetTexLevelParameterBase(context, target, level, pname, nullptr);
275}
276
JiangYizhoubddc46b2016-12-09 09:50:51 +0800277bool ValidateTexStorage2DMultiSample(Context *context,
278 GLenum target,
279 GLsizei samples,
280 GLint internalFormat,
281 GLsizei width,
282 GLsizei height,
283 GLboolean fixedSampleLocations)
284{
285 if (context->getClientVersion() < ES_3_1)
286 {
287 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
288 return false;
289 }
290
291 if (target != GL_TEXTURE_2D_MULTISAMPLE)
292 {
293 context->handleError(Error(GL_INVALID_ENUM, "Target must be TEXTURE_2D_MULTISAMPLE."));
294 return false;
295 }
296
297 if (width < 1 || height < 1)
298 {
299 context->handleError(Error(GL_INVALID_VALUE, "Width and height must be positive."));
300 return false;
301 }
302
303 const Caps &caps = context->getCaps();
304 if (static_cast<GLuint>(width) > caps.max2DTextureSize ||
305 static_cast<GLuint>(height) > caps.max2DTextureSize)
306 {
307 context->handleError(
308 Error(GL_INVALID_VALUE,
309 "Width and height must be less than or equal to GL_MAX_TEXTURE_SIZE."));
310 return false;
311 }
312
313 if (samples == 0)
314 {
315 context->handleError(Error(GL_INVALID_VALUE, "Samples may not be zero."));
316 return false;
317 }
318
319 const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
320 if (!formatCaps.renderable)
321 {
322 context->handleError(
323 Error(GL_INVALID_ENUM,
324 "SizedInternalformat must be color-renderable, depth-renderable, "
325 "or stencil-renderable."));
326 return false;
327 }
328
329 // The ES3.1 spec(section 8.8) states that an INVALID_ENUM error is generated if internalformat
330 // is one of the unsized base internalformats listed in table 8.11.
331 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
332 if (formatInfo.pixelBytes == 0)
333 {
334 context->handleError(
335 Error(GL_INVALID_ENUM,
336 "Internalformat is one of the unsupported unsized base internalformats."));
337 return false;
338 }
339
340 if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
341 {
342 context->handleError(
343 Error(GL_INVALID_OPERATION,
344 "Samples must not be greater than maximum supported value for the format."));
345 return false;
346 }
347
348 Texture *texture = context->getTargetTexture(target);
349 if (!texture || texture->id() == 0)
350 {
351 context->handleError(Error(GL_INVALID_OPERATION, "Zero is bound to target."));
352 return false;
353 }
354
355 if (texture->getImmutableFormat())
356 {
357 context->handleError(
358 Error(GL_INVALID_OPERATION,
359 "The value of TEXTURE_IMMUTABLE_FORMAT for the texture "
360 "currently bound to target on the active texture unit is true."));
361 return false;
362 }
363
364 return true;
365}
366
367bool ValidateGetMultisamplefv(Context *context, GLenum pname, GLuint index, GLfloat *val)
368{
369 if (context->getClientVersion() < ES_3_1)
370 {
371 context->handleError(Error(GL_INVALID_OPERATION, "Context does not support GLES3.1."));
372 return false;
373 }
374
375 if (pname != GL_SAMPLE_POSITION)
376 {
377 context->handleError(Error(GL_INVALID_ENUM, "Pname must be SAMPLE_POSITION."));
378 return false;
379 }
380
381 GLint maxSamples = context->getCaps().maxSamples;
382 if (index >= static_cast<GLuint>(maxSamples))
383 {
384 context->handleError(
385 Error(GL_INVALID_VALUE, "Index must be less than the value of SAMPLES."));
386 return false;
387 }
388
389 return true;
390}
Martin Radev66fb8202016-07-28 11:45:20 +0300391} // namespace gl