[MESA]
[reactos.git] / reactos / dll / opengl / mesa / src / mesa / main / api_validate.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "glheader.h"
26 #include "api_validate.h"
27 #include "bufferobj.h"
28 #include "context.h"
29 #include "imports.h"
30 #include "mfeatures.h"
31 #include "mtypes.h"
32 #include "vbo/vbo.h"
33
34
35 /**
36 * \return number of bytes in array [count] of type.
37 */
38 static GLsizei
39 index_bytes(GLenum type, GLsizei count)
40 {
41 if (type == GL_UNSIGNED_INT) {
42 return count * sizeof(GLuint);
43 }
44 else if (type == GL_UNSIGNED_BYTE) {
45 return count * sizeof(GLubyte);
46 }
47 else {
48 ASSERT(type == GL_UNSIGNED_SHORT);
49 return count * sizeof(GLushort);
50 }
51 }
52
53
54 /**
55 * Find the max index in the given element/index buffer
56 */
57 GLuint
58 _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type,
59 const void *indices,
60 struct gl_buffer_object *elementBuf)
61 {
62 const GLubyte *map = NULL;
63 GLuint max = 0;
64 GLuint i;
65
66 if (_mesa_is_bufferobj(elementBuf)) {
67 /* elements are in a user-defined buffer object. need to map it */
68 map = ctx->Driver.MapBufferRange(ctx, 0, elementBuf->Size,
69 GL_MAP_READ_BIT, elementBuf);
70 /* Actual address is the sum of pointers */
71 indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices);
72 }
73
74 if (type == GL_UNSIGNED_INT) {
75 for (i = 0; i < count; i++)
76 if (((GLuint *) indices)[i] > max)
77 max = ((GLuint *) indices)[i];
78 }
79 else if (type == GL_UNSIGNED_SHORT) {
80 for (i = 0; i < count; i++)
81 if (((GLushort *) indices)[i] > max)
82 max = ((GLushort *) indices)[i];
83 }
84 else {
85 ASSERT(type == GL_UNSIGNED_BYTE);
86 for (i = 0; i < count; i++)
87 if (((GLubyte *) indices)[i] > max)
88 max = ((GLubyte *) indices)[i];
89 }
90
91 if (map) {
92 ctx->Driver.UnmapBuffer(ctx, elementBuf);
93 }
94
95 return max;
96 }
97
98
99 /**
100 * Check if OK to draw arrays/elements.
101 */
102 static GLboolean
103 check_valid_to_render(struct gl_context *ctx, const char *function)
104 {
105 if (!_mesa_valid_to_render(ctx, function)) {
106 return GL_FALSE;
107 }
108
109 /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
110 * array [0]).
111 */
112 return ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled;
113 }
114
115
116 /**
117 * Do bounds checking on array element indexes. Check that the vertices
118 * pointed to by the indices don't lie outside buffer object bounds.
119 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
120 */
121 static GLboolean
122 check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
123 const GLvoid *indices)
124 {
125 struct _mesa_prim prim;
126 struct _mesa_index_buffer ib;
127 GLuint min, max;
128
129 /* Only the X Server needs to do this -- otherwise, accessing outside
130 * array/BO bounds allows application termination.
131 */
132 if (!ctx->Const.CheckArrayBounds)
133 return GL_TRUE;
134
135 memset(&prim, 0, sizeof(prim));
136 prim.count = count;
137
138 memset(&ib, 0, sizeof(ib));
139 ib.type = type;
140 ib.ptr = indices;
141 ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
142
143 vbo_get_minmax_index(ctx, &prim, &ib, &min, &max);
144
145 if (max >= ctx->Array.ArrayObj->_MaxElement) {
146 /* the max element is out of bounds of one or more enabled arrays */
147 _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
148 max, ctx->Array.ArrayObj->_MaxElement);
149 return GL_FALSE;
150 }
151
152 return GL_TRUE;
153 }
154
155
156 /**
157 * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(),
158 * etc? The set of legal values depends on whether geometry shaders/programs
159 * are supported.
160 */
161 GLboolean
162 _mesa_valid_prim_mode(const struct gl_context *ctx, GLenum mode)
163 {
164 if (mode > GL_POLYGON) {
165 return GL_FALSE;
166 }
167 else {
168 return GL_TRUE;
169 }
170 }
171
172
173 /**
174 * Error checking for glDrawElements(). Includes parameter checking
175 * and VBO bounds checking.
176 * \return GL_TRUE if OK to render, GL_FALSE if error found
177 */
178 GLboolean
179 _mesa_validate_DrawElements(struct gl_context *ctx,
180 GLenum mode, GLsizei count, GLenum type,
181 const GLvoid *indices)
182 {
183 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
184
185 if (count <= 0) {
186 if (count < 0)
187 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
188 return GL_FALSE;
189 }
190
191 if (!_mesa_valid_prim_mode(ctx, mode)) {
192 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" );
193 return GL_FALSE;
194 }
195
196 if (type != GL_UNSIGNED_INT &&
197 type != GL_UNSIGNED_BYTE &&
198 type != GL_UNSIGNED_SHORT)
199 {
200 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
201 return GL_FALSE;
202 }
203
204 if (!check_valid_to_render(ctx, "glDrawElements"))
205 return GL_FALSE;
206
207 /* Vertex buffer object tests */
208 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
209 /* use indices in the buffer object */
210 /* make sure count doesn't go outside buffer bounds */
211 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
212 _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
213 return GL_FALSE;
214 }
215 }
216 else {
217 /* not using a VBO */
218 if (!indices)
219 return GL_FALSE;
220 }
221
222 if (!check_index_bounds(ctx, count, type, indices))
223 return GL_FALSE;
224
225 return GL_TRUE;
226 }
227
228
229 /**
230 * Error checking for glDrawRangeElements(). Includes parameter checking
231 * and VBO bounds checking.
232 * \return GL_TRUE if OK to render, GL_FALSE if error found
233 */
234 GLboolean
235 _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
236 GLuint start, GLuint end,
237 GLsizei count, GLenum type,
238 const GLvoid *indices)
239 {
240 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
241
242 if (count <= 0) {
243 if (count < 0)
244 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
245 return GL_FALSE;
246 }
247
248 if (!_mesa_valid_prim_mode(ctx, mode)) {
249 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" );
250 return GL_FALSE;
251 }
252
253 if (end < start) {
254 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
255 return GL_FALSE;
256 }
257
258 if (type != GL_UNSIGNED_INT &&
259 type != GL_UNSIGNED_BYTE &&
260 type != GL_UNSIGNED_SHORT) {
261 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" );
262 return GL_FALSE;
263 }
264
265 if (!check_valid_to_render(ctx, "glDrawRangeElements"))
266 return GL_FALSE;
267
268 /* Vertex buffer object tests */
269 if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) {
270 /* use indices in the buffer object */
271 /* make sure count doesn't go outside buffer bounds */
272 if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) {
273 _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
274 return GL_FALSE;
275 }
276 }
277 else {
278 /* not using a VBO */
279 if (!indices)
280 return GL_FALSE;
281 }
282
283 if (!check_index_bounds(ctx, count, type, indices))
284 return GL_FALSE;
285
286 return GL_TRUE;
287 }
288
289
290 /**
291 * Called from the tnl module to error check the function parameters and
292 * verify that we really can draw something.
293 * \return GL_TRUE if OK to render, GL_FALSE if error found
294 */
295 GLboolean
296 _mesa_validate_DrawArrays(struct gl_context *ctx,
297 GLenum mode, GLint start, GLsizei count)
298 {
299 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
300
301 if (count <= 0) {
302 if (count < 0)
303 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
304 return GL_FALSE;
305 }
306
307 if (!_mesa_valid_prim_mode(ctx, mode)) {
308 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
309 return GL_FALSE;
310 }
311
312 if (!check_valid_to_render(ctx, "glDrawArrays"))
313 return GL_FALSE;
314
315 if (ctx->Const.CheckArrayBounds) {
316 if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
317 return GL_FALSE;
318 }
319
320 return GL_TRUE;
321 }