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