Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 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.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER,
69
                                  GL_READ_ONLY, 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, GL_ELEMENT_ARRAY_BUFFER_ARB, 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
   switch (ctx->API) {
110
#if FEATURE_es2_glsl
111
   case API_OPENGLES2:
112
      /* For ES2, we can draw if any vertex array is enabled (and we
113
       * should always have a vertex program/shader). */
114
      if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current)
115
	 return GL_FALSE;
116
      break;
117
#endif
118
 
119
#if FEATURE_ES1 || FEATURE_GL
120
   case API_OPENGLES:
121
   case API_OPENGL:
122
      /* For regular OpenGL, only draw if we have vertex positions
123
       * (regardless of whether or not we have a vertex program/shader). */
124
      if (!ctx->Array.ArrayObj->Vertex.Enabled &&
125
	  !ctx->Array.ArrayObj->VertexAttrib[0].Enabled)
126
	 return GL_FALSE;
127
      break;
128
#endif
129
 
130
   default:
131
      ASSERT_NO_FEATURE();
132
   }
133
 
134
   return GL_TRUE;
135
}
136
 
137
 
138
/**
139
 * Do bounds checking on array element indexes.  Check that the vertices
140
 * pointed to by the indices don't lie outside buffer object bounds.
141
 * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
142
 */
143
static GLboolean
144
check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
145
		   const GLvoid *indices, GLint basevertex)
146
{
147
   struct _mesa_prim prim;
148
   struct _mesa_index_buffer ib;
149
   GLuint min, max;
150
 
151
   /* Only the X Server needs to do this -- otherwise, accessing outside
152
    * array/BO bounds allows application termination.
153
    */
154
   if (!ctx->Const.CheckArrayBounds)
155
      return GL_TRUE;
156
 
157
   memset(&prim, 0, sizeof(prim));
158
   prim.count = count;
159
 
160
   memset(&ib, 0, sizeof(ib));
161
   ib.type = type;
162
   ib.ptr = indices;
163
   ib.obj = ctx->Array.ElementArrayBufferObj;
164
 
165
   vbo_get_minmax_index(ctx, &prim, &ib, &min, &max);
166
 
167
   if ((int)(min + basevertex) < 0 ||
168
       max + basevertex > ctx->Array.ArrayObj->_MaxElement) {
169
      /* the max element is out of bounds of one or more enabled arrays */
170
      _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)",
171
                    max, ctx->Array.ArrayObj->_MaxElement);
172
      return GL_FALSE;
173
   }
174
 
175
   return GL_TRUE;
176
}
177
 
178
 
179
/**
180
 * Error checking for glDrawElements().  Includes parameter checking
181
 * and VBO bounds checking.
182
 * \return GL_TRUE if OK to render, GL_FALSE if error found
183
 */
184
GLboolean
185
_mesa_validate_DrawElements(struct gl_context *ctx,
186
			    GLenum mode, GLsizei count, GLenum type,
187
			    const GLvoid *indices, GLint basevertex)
188
{
189
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
190
 
191
   if (count <= 0) {
192
      if (count < 0)
193
	 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
194
      return GL_FALSE;
195
   }
196
 
197
   if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
198
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" );
199
      return GL_FALSE;
200
   }
201
 
202
   if (type != GL_UNSIGNED_INT &&
203
       type != GL_UNSIGNED_BYTE &&
204
       type != GL_UNSIGNED_SHORT)
205
   {
206
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
207
      return GL_FALSE;
208
   }
209
 
210
   if (!check_valid_to_render(ctx, "glDrawElements"))
211
      return GL_FALSE;
212
 
213
   /* Vertex buffer object tests */
214
   if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
215
      /* use indices in the buffer object */
216
      /* make sure count doesn't go outside buffer bounds */
217
      if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) {
218
         _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
219
         return GL_FALSE;
220
      }
221
   }
222
   else {
223
      /* not using a VBO */
224
      if (!indices)
225
         return GL_FALSE;
226
   }
227
 
228
   if (!check_index_bounds(ctx, count, type, indices, basevertex))
229
      return GL_FALSE;
230
 
231
   return GL_TRUE;
232
}
233
 
234
 
235
/**
236
 * Error checking for glDrawRangeElements().  Includes parameter checking
237
 * and VBO bounds checking.
238
 * \return GL_TRUE if OK to render, GL_FALSE if error found
239
 */
240
GLboolean
241
_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
242
				 GLuint start, GLuint end,
243
				 GLsizei count, GLenum type,
244
				 const GLvoid *indices, GLint basevertex)
245
{
246
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
247
 
248
   if (count <= 0) {
249
      if (count < 0)
250
	 _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
251
      return GL_FALSE;
252
   }
253
 
254
   if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
255
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" );
256
      return GL_FALSE;
257
   }
258
 
259
   if (end < start) {
260
      _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end
261
      return GL_FALSE;
262
   }
263
 
264
   if (type != GL_UNSIGNED_INT &&
265
       type != GL_UNSIGNED_BYTE &&
266
       type != GL_UNSIGNED_SHORT) {
267
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" );
268
      return GL_FALSE;
269
   }
270
 
271
   if (!check_valid_to_render(ctx, "glDrawRangeElements"))
272
      return GL_FALSE;
273
 
274
   /* Vertex buffer object tests */
275
   if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
276
      /* use indices in the buffer object */
277
      /* make sure count doesn't go outside buffer bounds */
278
      if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) {
279
         _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
280
         return GL_FALSE;
281
      }
282
   }
283
   else {
284
      /* not using a VBO */
285
      if (!indices)
286
         return GL_FALSE;
287
   }
288
 
289
   if (!check_index_bounds(ctx, count, type, indices, basevertex))
290
      return GL_FALSE;
291
 
292
   return GL_TRUE;
293
}
294
 
295
 
296
/**
297
 * Called from the tnl module to error check the function parameters and
298
 * verify that we really can draw something.
299
 * \return GL_TRUE if OK to render, GL_FALSE if error found
300
 */
301
GLboolean
302
_mesa_validate_DrawArrays(struct gl_context *ctx,
303
			  GLenum mode, GLint start, GLsizei count)
304
{
305
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
306
 
307
   if (count <= 0) {
308
      if (count < 0)
309
         _mesa_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count)" );
310
      return GL_FALSE;
311
   }
312
 
313
   if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
314
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" );
315
      return GL_FALSE;
316
   }
317
 
318
   if (!check_valid_to_render(ctx, "glDrawArrays"))
319
      return GL_FALSE;
320
 
321
   if (ctx->Const.CheckArrayBounds) {
322
      if (start + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
323
         return GL_FALSE;
324
   }
325
 
326
   return GL_TRUE;
327
}
328
 
329
 
330
GLboolean
331
_mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first,
332
                                   GLsizei count, GLsizei primcount)
333
{
334
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
335
 
336
   if (count <= 0) {
337
      if (count < 0)
338
         _mesa_error(ctx, GL_INVALID_VALUE,
339
                     "glDrawArraysInstanced(count=%d)", count);
340
      return GL_FALSE;
341
   }
342
 
343
   if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
344
      _mesa_error(ctx, GL_INVALID_ENUM,
345
                  "glDrawArraysInstanced(mode=0x%x)", mode);
346
      return GL_FALSE;
347
   }
348
 
349
   if (primcount <= 0) {
350
      if (primcount < 0)
351
         _mesa_error(ctx, GL_INVALID_VALUE,
352
                     "glDrawArraysInstanced(primcount=%d)", primcount);
353
      return GL_FALSE;
354
   }
355
 
356
   if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
357
      return GL_FALSE;
358
 
359
   if (ctx->CompileFlag) {
360
      _mesa_error(ctx, GL_INVALID_OPERATION,
361
                  "glDrawArraysInstanced(display list");
362
      return GL_FALSE;
363
   }
364
 
365
   if (ctx->Const.CheckArrayBounds) {
366
      if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement)
367
         return GL_FALSE;
368
   }
369
 
370
   return GL_TRUE;
371
}
372
 
373
 
374
GLboolean
375
_mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
376
                                     GLenum mode, GLsizei count, GLenum type,
377
                                     const GLvoid *indices, GLsizei primcount)
378
{
379
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
380
 
381
   if (count <= 0) {
382
      if (count < 0)
383
	 _mesa_error(ctx, GL_INVALID_VALUE,
384
                     "glDrawElementsInstanced(count=%d)", count);
385
      return GL_FALSE;
386
   }
387
 
388
   if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) {
389
      _mesa_error(ctx, GL_INVALID_ENUM,
390
                  "glDrawElementsInstanced(mode = 0x%x)", mode);
391
      return GL_FALSE;
392
   }
393
 
394
   if (type != GL_UNSIGNED_INT &&
395
       type != GL_UNSIGNED_BYTE &&
396
       type != GL_UNSIGNED_SHORT) {
397
      _mesa_error(ctx, GL_INVALID_ENUM,
398
                  "glDrawElementsInstanced(type=0x%x)", type);
399
      return GL_FALSE;
400
   }
401
 
402
   if (primcount <= 0) {
403
      if (primcount < 0)
404
         _mesa_error(ctx, GL_INVALID_VALUE,
405
                     "glDrawElementsInstanced(primcount=%d)", primcount);
406
      return GL_FALSE;
407
   }
408
 
409
   if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
410
      return GL_FALSE;
411
 
412
   /* Vertex buffer object tests */
413
   if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
414
      /* use indices in the buffer object */
415
      /* make sure count doesn't go outside buffer bounds */
416
      if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) {
417
         _mesa_warning(ctx,
418
                       "glDrawElementsInstanced index out of buffer bounds");
419
         return GL_FALSE;
420
      }
421
   }
422
   else {
423
      /* not using a VBO */
424
      if (!indices)
425
         return GL_FALSE;
426
   }
427
 
428
   if (!check_index_bounds(ctx, count, type, indices, 0))
429
      return GL_FALSE;
430
 
431
   return GL_TRUE;
432
}