fixes for C++ warnings/errors
[mesa.git] / src / mesa / tnl / t_array_api.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 /**
26 * \file t_array_api.c
27 * \brief Vertex array API functions (glDrawArrays, etc)
28 * \author Keith Whitwell
29 */
30
31 #include "glheader.h"
32 #include "api_validate.h"
33 #include "context.h"
34 #include "imports.h"
35 #include "macros.h"
36 #include "mtypes.h"
37 #include "state.h"
38
39 #include "array_cache/acache.h"
40
41 #include "t_array_api.h"
42 #include "t_array_import.h"
43 #include "t_save_api.h"
44 #include "t_context.h"
45 #include "t_pipeline.h"
46 #include "dispatch.h"
47
48 static void fallback_drawarrays( GLcontext *ctx, GLenum mode, GLint start,
49 GLsizei count )
50 {
51 GLint i;
52
53 assert(!ctx->CompileFlag);
54 assert(ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END);
55
56 CALL_Begin(GET_DISPATCH(), (mode));
57 for (i = 0; i < count; i++)
58 CALL_ArrayElement(GET_DISPATCH(), ( start + i ));
59 CALL_End(GET_DISPATCH(), ());
60 }
61
62
63 static void fallback_drawelements( GLcontext *ctx, GLenum mode, GLsizei count,
64 const GLuint *indices)
65 {
66 GLint i;
67
68 assert(!ctx->CompileFlag);
69 assert(ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END);
70
71 /* Here, indices will already reflect the buffer object if active */
72
73 CALL_Begin(GET_DISPATCH(), (mode));
74 for (i = 0 ; i < count ; i++) {
75 CALL_ArrayElement(GET_DISPATCH(), ( indices[i] ));
76 }
77 CALL_End(GET_DISPATCH(), ());
78 }
79
80
81 /* Note this function no longer takes a 'start' value, the range is
82 * assumed to start at zero. The old trick of subtracting 'start'
83 * from each index won't work if the indices are not in writeable
84 * memory.
85 */
86 static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
87 GLuint max_index,
88 GLsizei index_count, GLuint *indices )
89
90 {
91 TNLcontext *tnl = TNL_CONTEXT(ctx);
92 struct tnl_prim prim;
93 FLUSH_CURRENT( ctx, 0 );
94
95 _tnl_vb_bind_arrays( ctx, 0, max_index );
96
97 tnl->vb.Primitive = &prim;
98 tnl->vb.Primitive[0].mode = mode | PRIM_BEGIN | PRIM_END;
99 tnl->vb.Primitive[0].start = 0;
100 tnl->vb.Primitive[0].count = index_count;
101 tnl->vb.PrimitiveCount = 1;
102
103 tnl->vb.Elts = (GLuint *)indices;
104
105 tnl->Driver.RunPipeline( ctx );
106 }
107
108
109
110 /**
111 * Called via the GL API dispatcher.
112 */
113 void GLAPIENTRY
114 _tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
115 {
116 GET_CURRENT_CONTEXT(ctx);
117 TNLcontext *tnl = TNL_CONTEXT(ctx);
118 /* It's tempting to get rid of this threshold value because we take
119 * very different paths if 'count' is less than or greater than 'thresh'.
120 * I've found/fixed at least one bug which only occured for particular
121 * array sizes. Also, several conformance tests use very short arrays
122 * which means the long-array path doesn't get tested. -Brian
123 */
124 GLuint thresh = (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) ? 30 : 10;
125
126 if (MESA_VERBOSE & VERBOSE_API)
127 _mesa_debug(NULL, "_tnl_DrawArrays %d %d\n", start, count);
128
129 /* Check arguments, etc.
130 */
131 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
132 return;
133
134 assert(!ctx->CompileFlag);
135
136 if (!ctx->Array.LockCount && (GLuint) count < thresh) {
137 /* Small primitives: attempt to share a vb (at the expense of
138 * using the immediate interface).
139 */
140 fallback_drawarrays( ctx, mode, start, count );
141 }
142 else if (start >= (GLint) ctx->Array.LockFirst &&
143 start + count <= (GLint)(ctx->Array.LockFirst + ctx->Array.LockCount)) {
144
145 struct tnl_prim prim;
146
147 /* Locked primitives which can fit in a single vertex buffer:
148 */
149 FLUSH_CURRENT( ctx, 0 );
150
151 /* Locked drawarrays. Reuse any previously transformed data.
152 */
153 _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst,
154 ctx->Array.LockFirst + ctx->Array.LockCount );
155
156 tnl->vb.Primitive = &prim;
157 tnl->vb.Primitive[0].mode = mode | PRIM_BEGIN | PRIM_END;
158 tnl->vb.Primitive[0].start = start;
159 tnl->vb.Primitive[0].count = count;
160 tnl->vb.PrimitiveCount = 1;
161
162 tnl->Driver.RunPipeline( ctx );
163 }
164 else {
165 int bufsz = 256; /* Use a small buffer for cache goodness */
166 int j, nr;
167 int minimum, modulo, skip;
168
169 /* Large primitives requiring decomposition to multiple vertex
170 * buffers:
171 */
172 switch (mode) {
173 case GL_POINTS:
174 minimum = 0;
175 modulo = 1;
176 skip = 0;
177 break;
178 case GL_LINES:
179 minimum = 1;
180 modulo = 2;
181 skip = 1;
182 break;
183 case GL_LINE_STRIP:
184 minimum = 1;
185 modulo = 1;
186 skip = 0;
187 break;
188 case GL_TRIANGLES:
189 minimum = 2;
190 modulo = 3;
191 skip = 2;
192 break;
193 case GL_TRIANGLE_STRIP:
194 minimum = 2;
195 modulo = 1;
196 skip = 0;
197 break;
198 case GL_QUADS:
199 minimum = 3;
200 modulo = 4;
201 skip = 3;
202 break;
203 case GL_QUAD_STRIP:
204 minimum = 3;
205 modulo = 2;
206 skip = 0;
207 break;
208 case GL_LINE_LOOP:
209 case GL_TRIANGLE_FAN:
210 case GL_POLYGON:
211 default:
212 /* Primitives requiring a copied vertex (fan-like primitives)
213 * must use the slow path if they cannot fit in a single
214 * vertex buffer.
215 */
216 if (count <= (GLint) ctx->Const.MaxArrayLockSize) {
217 bufsz = ctx->Const.MaxArrayLockSize;
218 minimum = 0;
219 modulo = 1;
220 skip = 0;
221 }
222 else {
223 fallback_drawarrays( ctx, mode, start, count );
224 return;
225 }
226 }
227
228 FLUSH_CURRENT( ctx, 0 );
229
230 bufsz -= bufsz % modulo;
231 bufsz -= minimum;
232 count += start;
233
234 for (j = start + minimum ; j < count ; j += nr + skip ) {
235
236 struct tnl_prim prim;
237
238 nr = MIN2( bufsz, count - j );
239
240 /* XXX is the last parameter a count or index into the array??? */
241 _tnl_vb_bind_arrays( ctx, j - minimum, j + nr );
242
243 tnl->vb.Primitive = &prim;
244 tnl->vb.Primitive[0].mode = mode;
245
246 if (j == start + minimum)
247 tnl->vb.Primitive[0].mode |= PRIM_BEGIN;
248
249 if (j + nr + skip >= count)
250 tnl->vb.Primitive[0].mode |= PRIM_END;
251
252 tnl->vb.Primitive[0].start = 0;
253 tnl->vb.Primitive[0].count = nr + minimum;
254 tnl->vb.PrimitiveCount = 1;
255
256 tnl->Driver.RunPipeline( ctx );
257 }
258 }
259 }
260
261
262 /**
263 * Called via the GL API dispatcher.
264 */
265 void GLAPIENTRY
266 _tnl_DrawRangeElements(GLenum mode,
267 GLuint start, GLuint end,
268 GLsizei count, GLenum type, const GLvoid *indices)
269 {
270 GET_CURRENT_CONTEXT(ctx);
271 GLuint *ui_indices;
272
273 if (MESA_VERBOSE & VERBOSE_API)
274 _mesa_debug(NULL, "_tnl_DrawRangeElements %d %d %d\n", start, end, count);
275
276 if (ctx->Array.ElementArrayBufferObj->Name) {
277 /* use indices in the buffer object */
278 if (!ctx->Array.ElementArrayBufferObj->Data) {
279 _mesa_warning(ctx,
280 "DrawRangeElements with empty vertex elements buffer!");
281 return;
282 }
283 /* actual address is the sum of pointers */
284 indices = (const GLvoid *)
285 ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Data,
286 (const GLubyte *) indices);
287 }
288
289 /* Check arguments, etc.
290 */
291 if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
292 type, indices ))
293 return;
294
295 ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
296 count, type, indices );
297
298 #ifdef DEBUG
299 /* check that array indices really fall inside [start, end] range */
300 {
301 GLint i;
302 for (i = 0; i < count; i++) {
303 if (ui_indices[i] < start || ui_indices[i] > end) {
304 _mesa_warning(ctx, "Invalid array index in "
305 "glDrawRangeElements(index=%u)", ui_indices[i]);
306 }
307 }
308 }
309 #endif
310
311 assert(!ctx->CompileFlag);
312
313 if (ctx->Array.LockCount) {
314 /* Are the arrays already locked? If so we currently have to look
315 * at the whole locked range.
316 */
317
318 if (start == 0 && ctx->Array.LockFirst == 0 &&
319 end < (ctx->Array.LockFirst + ctx->Array.LockCount))
320 _tnl_draw_range_elements( ctx, mode,
321 ctx->Array.LockCount,
322 count, ui_indices );
323 else {
324 fallback_drawelements( ctx, mode, count, ui_indices );
325 }
326 }
327 else if (start == 0 && end < ctx->Const.MaxArrayLockSize) {
328 /* The arrays aren't locked but we can still fit them inside a
329 * single vertexbuffer.
330 */
331 _tnl_draw_range_elements( ctx, mode, end + 1, count, ui_indices );
332 }
333 else {
334 /* Range is too big to optimize:
335 */
336 fallback_drawelements( ctx, mode, count, ui_indices );
337 }
338 }
339
340
341
342 /**
343 * Called via the GL API dispatcher.
344 */
345 void GLAPIENTRY
346 _tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
347 const GLvoid *indices)
348 {
349 GET_CURRENT_CONTEXT(ctx);
350 GLuint *ui_indices;
351
352 if (MESA_VERBOSE & VERBOSE_API)
353 _mesa_debug(NULL, "_tnl_DrawElements %d\n", count);
354
355 /* Check arguments, etc. */
356 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
357 return;
358
359 if (ctx->Array.ElementArrayBufferObj->Name) {
360 /* actual address is the sum of pointers */
361 indices = (const GLvoid *)
362 ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Data,
363 (const GLubyte *) indices);
364 }
365
366 ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
367 count, type, indices );
368
369 assert(!ctx->CompileFlag);
370
371 if (ctx->Array.LockCount) {
372 if (ctx->Array.LockFirst == 0)
373 _tnl_draw_range_elements( ctx, mode,
374 ctx->Array.LockCount,
375 count, ui_indices );
376 else
377 fallback_drawelements( ctx, mode, count, ui_indices );
378 }
379 else {
380 /* Scan the index list and see if we can use the locked path anyway.
381 */
382 GLuint max_elt = 0;
383 GLint i;
384
385 for (i = 0 ; i < count ; i++)
386 if (ui_indices[i] > max_elt)
387 max_elt = ui_indices[i];
388
389 if (max_elt < ctx->Const.MaxArrayLockSize && /* can we use it? */
390 max_elt < (GLuint) count) /* do we want to use it? */
391 _tnl_draw_range_elements( ctx, mode, max_elt+1, count, ui_indices );
392 else
393 fallback_drawelements( ctx, mode, count, ui_indices );
394 }
395 }
396
397
398 /**
399 * Initialize context's vertex array fields. Called during T 'n L context
400 * creation.
401 */
402 void _tnl_array_init( GLcontext *ctx )
403 {
404 TNLcontext *tnl = TNL_CONTEXT(ctx);
405 struct tnl_vertex_arrays *tmp = &tnl->array_inputs;
406 GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
407 GLuint i;
408
409 vfmt->DrawArrays = _tnl_DrawArrays;
410 vfmt->DrawElements = _tnl_DrawElements;
411 vfmt->DrawRangeElements = _tnl_DrawRangeElements;
412
413 /* Setup vector pointers that will be used to bind arrays to VB's.
414 */
415 _mesa_vector4f_init( &tmp->Obj, 0, NULL);
416 _mesa_vector4f_init( &tmp->Normal, 0, NULL);
417 _mesa_vector4f_init( &tmp->FogCoord, 0, NULL);
418 _mesa_vector4f_init( &tmp->Index, 0, NULL);
419
420 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++)
421 _mesa_vector4f_init( &tmp->TexCoord[i], 0, NULL);
422 }
423
424
425 /**
426 * Destroy the context's vertex array stuff.
427 * Called during T 'n L context destruction.
428 */
429 void _tnl_array_destroy( GLcontext *ctx )
430 {
431 (void) ctx;
432 }