Header file clean-up:
[mesa.git] / src / mesa / tnl / t_imm_exec.c
1 /* $Id: t_imm_exec.c,v 1.43 2002/10/24 23:57:25 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /**
28 * \file tnl/t_imm_exec.c
29 * \brief Setup to execute immediate-mode vertex data.
30 * \author Keith Whitwell
31 */
32
33 #include "glheader.h"
34 #include "colormac.h"
35 #include "context.h"
36 #include "enums.h"
37 #include "dlist.h"
38 #include "macros.h"
39 #include "imports.h"
40 #include "mmath.h"
41 #include "light.h"
42 #include "state.h"
43 #include "mtypes.h"
44
45 #include "math/m_matrix.h"
46 #include "math/m_xform.h"
47
48 #include "t_context.h"
49 #include "t_array_import.h"
50 #include "t_imm_alloc.h"
51 #include "t_imm_api.h"
52 #include "t_imm_debug.h"
53 #include "t_imm_dlist.h"
54 #include "t_imm_eval.h"
55 #include "t_imm_elt.h"
56 #include "t_imm_exec.h"
57 #include "t_imm_fixup.h"
58 #include "t_pipeline.h"
59
60
61
62 static void reset_input( GLcontext *ctx,
63 GLuint start,
64 GLuint beginstate,
65 GLuint savedbeginstate )
66 {
67 struct immediate *IM = TNL_CURRENT_IM(ctx);
68
69 /* Clear the dirty part of the flag array.
70 */
71 if (start < IM->Count+2)
72 MEMSET(IM->Flag + start, 0, sizeof(GLuint) * (IM->Count+2-start));
73
74 if (MESA_VERBOSE & VERBOSE_IMMEDIATE)
75 _mesa_debug(ctx, "reset_input: IM(%d) new %x\n", IM->id, beginstate);
76
77 IM->Start = start;
78 IM->Count = start;
79 IM->LastMaterial = start;
80 IM->BeginState = beginstate;
81 IM->SavedBeginState = savedbeginstate;
82 IM->TexSize = 0;
83 IM->MaterialOrMask = 0;
84
85 if (IM->MaterialMask)
86 IM->MaterialMask[IM->Start] = 0;
87
88 IM->ArrayEltFlags = ~ctx->Array._Enabled;
89 IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0;
90 IM->ArrayEltFlush = ctx->Array.LockCount ? FLUSH_ELT_LAZY : FLUSH_ELT_EAGER;
91 }
92
93 void _tnl_reset_exec_input( GLcontext *ctx,
94 GLuint start,
95 GLuint beginstate,
96 GLuint savedbeginstate )
97 {
98 TNLcontext *tnl = TNL_CONTEXT(ctx);
99 struct immediate *IM = TNL_CURRENT_IM(ctx);
100
101 reset_input( ctx, start, beginstate, savedbeginstate );
102
103 IM->CopyStart = start - tnl->ExecCopyCount;
104
105 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
106 if (tnl->ExecParity)
107 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
108
109 IM->LastPrimitive = IM->CopyStart;
110 }
111
112
113 void _tnl_reset_compile_input( GLcontext *ctx,
114 GLuint start,
115 GLuint beginstate,
116 GLuint savedbeginstate )
117 {
118 struct immediate *IM = TNL_CURRENT_IM(ctx);
119
120 reset_input( ctx, start, beginstate, savedbeginstate );
121 IM->CopyStart = start;
122 IM->LastPrimitive = IM->Start;
123 }
124
125
126 /**
127 * Copy the last specified normal, color, texcoord, edge flag, etc
128 * from the immediate struct into the ctx->Current attribute group.
129 */
130 void _tnl_copy_to_current( GLcontext *ctx, struct immediate *IM,
131 GLuint flag, GLuint count )
132 {
133 if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
134 _tnl_print_vert_flags("copy to current", flag);
135
136 /* XXX should be able to replace these conditions with a loop over
137 * the 16 vertex attributes.
138 */
139 if (flag & VERT_BIT_NORMAL)
140 COPY_4FV( ctx->Current.Attrib[VERT_ATTRIB_NORMAL],
141 IM->Attrib[VERT_ATTRIB_NORMAL][count]);
142
143 if (flag & VERT_BIT_INDEX)
144 ctx->Current.Index = IM->Index[count];
145
146 if (flag & VERT_BIT_EDGEFLAG)
147 ctx->Current.EdgeFlag = IM->EdgeFlag[count];
148
149 if (flag & VERT_BIT_COLOR0) {
150 COPY_4FV(ctx->Current.Attrib[VERT_ATTRIB_COLOR0],
151 IM->Attrib[VERT_ATTRIB_COLOR0][count]);
152 if (ctx->Light.ColorMaterialEnabled) {
153 _mesa_update_color_material( ctx,
154 ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
155 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
156 }
157 }
158
159 if (flag & VERT_BIT_COLOR1)
160 COPY_4FV(ctx->Current.Attrib[VERT_ATTRIB_COLOR1],
161 IM->Attrib[VERT_ATTRIB_COLOR1][count]);
162
163 if (flag & VERT_BIT_FOG)
164 ctx->Current.Attrib[VERT_ATTRIB_FOG][0] = IM->Attrib[VERT_ATTRIB_FOG][count][0];
165
166 if (flag & VERT_BITS_TEX_ANY) {
167 GLuint i;
168 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
169 if (flag & VERT_BIT_TEX(i)) {
170 COPY_4FV( ctx->Current.Attrib[VERT_ATTRIB_TEX0 + i],
171 IM->Attrib[VERT_ATTRIB_TEX0 + i][count]);
172 }
173 }
174 }
175
176 if (flag & VERT_BIT_MATERIAL) {
177 _mesa_update_material( ctx,
178 IM->Material[IM->LastMaterial],
179 IM->MaterialOrMask );
180
181 TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
182 }
183 }
184
185
186
187 void _tnl_compute_orflag( struct immediate *IM, GLuint start )
188 {
189 GLuint count = IM->Count;
190 GLuint orflag = 0;
191 GLuint andflag = ~0U;
192 GLuint i;
193
194 IM->LastData = count-1;
195
196
197 /* Compute the flags for the whole buffer.
198 */
199 for (i = start ; i < count ; i++) {
200 andflag &= IM->Flag[i];
201 orflag |= IM->Flag[i];
202 }
203
204 /* It is possible there will be data in the buffer arising from
205 * calls like 'glNormal', 'glMaterial' that occur after the final
206 * glVertex, glEval, etc. Additionally, a buffer can consist of
207 * eg. a single glMaterial call, in which case IM->Start ==
208 * IM->Count, but the buffer is definitely not empty.
209 */
210 if (IM->Flag[i] & VERT_BITS_DATA) {
211 IM->LastData++;
212 orflag |= IM->Flag[i];
213 }
214
215 IM->Flag[IM->LastData+1] |= VERT_BIT_END_VB;
216 IM->CopyAndFlag = IM->AndFlag = andflag;
217 IM->OrFlag = orflag;
218 IM->CopyOrFlag = orflag;
219 IM->Evaluated = 0;
220 }
221
222
223 /**
224 * This is where the vertex data is transfered from the 'struct immediate
225 * into the 'struct vertex_buffer'.
226 *
227 * Note: The 'start' member of the GLvector structs is now redundant
228 * because we always re-transform copied vertices, and the vectors
229 * below are set up so that the first copied vertex (if any) appears
230 * at position zero.
231 */
232 static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM )
233 {
234 TNLcontext *tnl = TNL_CONTEXT(ctx);
235 struct vertex_buffer *VB = &tnl->vb;
236 struct vertex_arrays *tmp = &tnl->imm_inputs;
237 GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */
238 const GLuint start = IM->CopyStart;
239 const GLuint count = IM->Count - start;
240
241 /* TODO: optimize the case where nothing has changed. (Just bind
242 * tmp to vb).
243 */
244
245 /* Setup constant data in the VB.
246 */
247 VB->Count = count;
248 VB->FirstClipped = IMM_MAXDATA - IM->CopyStart;
249 VB->import_data = NULL;
250 VB->importable_data = 0;
251
252 /* Need an IM->FirstPrimitive?
253 */
254 VB->Primitive = IM->Primitive + IM->CopyStart;
255 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
256 VB->FirstPrimitive = 0;
257
258 VB->Flag = IM->Flag + start;
259
260 /* TexCoordPtr's are zeroed in loop below.
261 */
262 VB->NormalPtr = NULL;
263 VB->NormalLengthPtr = NULL;
264 VB->EdgeFlag = NULL;
265 VB->IndexPtr[0] = NULL;
266 VB->IndexPtr[1] = NULL;
267 VB->ColorPtr[0] = NULL;
268 VB->ColorPtr[1] = NULL;
269 VB->SecondaryColorPtr[0] = NULL;
270 VB->SecondaryColorPtr[1] = NULL;
271 VB->Elts = NULL;
272 VB->MaterialMask = NULL;
273 VB->Material = NULL;
274
275 /* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
276 /* _tnl_print_vert_flags("orflag", IM->OrFlag); */
277 /* _tnl_print_vert_flags("inputs", inputs); */
278
279 /* Setup the initial values of array pointers in the vb.
280 */
281 if (inputs & VERT_BIT_POS) {
282 tmp->Obj.data = IM->Attrib[VERT_ATTRIB_POS] + start;
283 tmp->Obj.start = (GLfloat *)(IM->Attrib[VERT_ATTRIB_POS] + start);
284 tmp->Obj.count = count;
285 VB->ObjPtr = &tmp->Obj;
286 if ((IM->CopyOrFlag & VERT_BITS_OBJ_234) == VERT_BITS_OBJ_234)
287 tmp->Obj.size = 4;
288 else if ((IM->CopyOrFlag & VERT_BITS_OBJ_234) == VERT_BITS_OBJ_23)
289 tmp->Obj.size = 3;
290 else
291 tmp->Obj.size = 2;
292 }
293
294 if (inputs & VERT_BIT_NORMAL) {
295 tmp->Normal.data = IM->Attrib[VERT_ATTRIB_NORMAL] + start;
296 tmp->Normal.start = (GLfloat *) (IM->Attrib[VERT_ATTRIB_NORMAL] + start);
297 tmp->Normal.count = count;
298 tmp->Normal.size = 3; /* just to be safe */
299 VB->NormalPtr = &tmp->Normal;
300 if (IM->NormalLengthPtr)
301 VB->NormalLengthPtr = IM->NormalLengthPtr + start;
302 }
303
304 if (inputs & VERT_BIT_INDEX) {
305 tmp->Index.count = count;
306 tmp->Index.data = IM->Index + start;
307 tmp->Index.start = IM->Index + start;
308 VB->IndexPtr[0] = &tmp->Index;
309 }
310
311 if (inputs & VERT_BIT_FOG) {
312 tmp->FogCoord.data = IM->Attrib[VERT_ATTRIB_FOG] + start;
313 tmp->FogCoord.start = (GLfloat *) (IM->Attrib[VERT_ATTRIB_FOG] + start);
314 tmp->FogCoord.count = count;
315 VB->FogCoordPtr = &tmp->FogCoord;
316 }
317
318 if (inputs & VERT_BIT_COLOR1) {
319 tmp->SecondaryColor.Ptr = IM->Attrib[VERT_ATTRIB_COLOR1] + start;
320 VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
321 }
322
323 if (inputs & VERT_BIT_EDGEFLAG) {
324 VB->EdgeFlag = IM->EdgeFlag + start;
325 }
326
327 if (inputs & VERT_BIT_COLOR0) {
328 if (IM->CopyOrFlag & VERT_BIT_COLOR0) {
329 tmp->Color.Ptr = IM->Attrib[VERT_ATTRIB_COLOR0] + start;
330 tmp->Color.StrideB = 4 * sizeof(GLfloat);
331 tmp->Color.Flags = 0;
332 }
333 else {
334 tmp->Color.Ptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
335 tmp->Color.StrideB = 0;
336 tmp->Color.Flags = CA_CLIENT_DATA; /* hack */
337 VB->import_source = IM;
338 VB->importable_data |= VERT_BIT_COLOR0;
339 VB->import_data = _tnl_upgrade_current_data;
340 }
341 VB->ColorPtr[0] = &tmp->Color;
342 }
343
344 if (inputs & VERT_BITS_TEX_ANY) {
345 GLuint i;
346 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
347 VB->TexCoordPtr[i] = NULL;
348 if (inputs & VERT_BIT_TEX(i)) {
349 tmp->TexCoord[i].count = count;
350 tmp->TexCoord[i].data = IM->Attrib[VERT_ATTRIB_TEX0 + i] + start;
351 tmp->TexCoord[i].start = (GLfloat *)(IM->Attrib[VERT_ATTRIB_TEX0 + i] + start);
352 tmp->TexCoord[i].size = 2;
353 if (IM->TexSize & TEX_SIZE_3(i)) {
354 tmp->TexCoord[i].size = 3;
355 if (IM->TexSize & TEX_SIZE_4(i))
356 tmp->TexCoord[i].size = 4;
357 }
358 VB->TexCoordPtr[i] = &tmp->TexCoord[i];
359 }
360 }
361 }
362
363 if ((inputs & IM->OrFlag & VERT_BIT_MATERIAL) && IM->Material) {
364 VB->MaterialMask = IM->MaterialMask + start;
365 VB->Material = IM->Material + start;
366 }
367
368 /* GL_NV_vertex_program */
369 if (ctx->VertexProgram.Enabled) {
370 GLuint attr;
371 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
372 tmp->Attribs[attr].count = count;
373 tmp->Attribs[attr].data = IM->Attrib[attr] + start;
374 tmp->Attribs[attr].start = (GLfloat *) (IM->Attrib[attr] + start);
375 tmp->Attribs[attr].size = 4;
376 VB->AttribPtr[attr] = &(tmp->Attribs[attr]);
377 }
378 }
379 }
380
381
382
383
384 /**
385 * Called by exec_vert_cassette, execute_compiled_cassette, but not
386 * exec_elt_cassette.
387 */
388 void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM )
389 {
390 TNLcontext *tnl = TNL_CONTEXT(ctx);
391
392 _tnl_vb_bind_immediate( ctx, IM );
393
394 if (IM->OrFlag & VERT_BITS_EVAL_ANY)
395 _tnl_eval_immediate( ctx, IM );
396
397 /* Invalidate all stored data before and after run:
398 */
399 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
400 tnl->Driver.RunPipeline( ctx );
401 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
402
403 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
404 }
405
406
407 /**
408 * Called for regular vertex cassettes.
409 */
410 static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM )
411 {
412 if (IM->FlushElt) {
413 /* Orflag is computed twice, but only reach this code if app is
414 * using a mixture of glArrayElement() and glVertex() while
415 * arrays are locked (else would be in exec_elt_cassette now).
416 */
417 ASSERT(ctx->Array.LockCount);
418 ASSERT(IM->FlushElt == FLUSH_ELT_LAZY);
419 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->Count );
420 _tnl_compute_orflag( IM, IM->CopyStart );
421 }
422
423 _tnl_fixup_input( ctx, IM );
424 /* _tnl_print_cassette( IM ); */
425 _tnl_run_cassette( ctx, IM );
426 }
427
428
429 /* Called for pure, locked VERT_BIT_ELT cassettes instead of
430 * _tnl_run_cassette.
431 */
432 static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM )
433 {
434 TNLcontext *tnl = TNL_CONTEXT(ctx);
435 struct vertex_buffer *VB = &tnl->vb;
436
437 _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
438
439 /* Take only elements and primitive information from the immediate:
440 */
441 VB->Elts = IM->Elt + IM->CopyStart;
442 VB->Primitive = IM->Primitive + IM->CopyStart;
443 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
444 VB->FirstPrimitive = 0;
445
446 /* Run the pipeline. No input changes as a result of this action.
447 */
448 tnl->Driver.RunPipeline( ctx );
449
450 /* Still need to update current values:
451 */
452 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
453 _tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData );
454 _tnl_copy_to_current( ctx, IM, ctx->Array._Enabled, IM->LastData );
455 }
456 }
457
458
459 static void
460 exec_empty_cassette( GLcontext *ctx, struct immediate *IM )
461 {
462 if (IM->FlushElt)
463 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->CopyStart );
464
465 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
466 }
467
468
469
470 /**
471 * Called for all cassettes when not compiling or playing a display
472 * list.
473 */
474 void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM )
475 {
476 TNLcontext *tnl = TNL_CONTEXT(ctx);
477
478 _tnl_compute_orflag( IM, IM->Start );
479 _tnl_copy_immediate_vertices( ctx, IM );
480 _tnl_get_exec_copy_verts( ctx, IM );
481
482 if (tnl->pipeline.build_state_changes)
483 _tnl_validate_pipeline( ctx );
484
485 if (IM->CopyStart == IM->Count) {
486 exec_empty_cassette( ctx, IM );
487 }
488 else if ((IM->CopyOrFlag & VERT_BITS_DATA) == VERT_BIT_ELT &&
489 ctx->Array.LockCount &&
490 ctx->Array.Vertex.Enabled) {
491 exec_elt_cassette( ctx, IM );
492 }
493 else {
494 exec_vert_cassette( ctx, IM );
495 }
496
497 /* Only reuse the immediate if there are no copied vertices living
498 * inside it:
499 */
500 {
501 GLuint begin_state = IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
502 GLuint saved_begin_state = IM->SavedBeginState;
503
504 if (--IM->ref_count != 0) {
505 IM = _tnl_alloc_immediate( ctx );
506 SET_IMMEDIATE( ctx, IM );
507 }
508
509 IM->ref_count++;
510
511 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS,
512 begin_state, saved_begin_state );
513 }
514
515 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
516 ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
517 }
518
519
520
521
522 /**
523 * Setup vector pointers that will be used to bind immediates to VB's.
524 */
525 void _tnl_imm_init( GLcontext *ctx )
526 {
527 TNLcontext *tnl = TNL_CONTEXT(ctx);
528 struct vertex_arrays *tmp = &tnl->imm_inputs;
529 GLuint i;
530 static int firsttime = 1;
531
532 if (firsttime) {
533 firsttime = 0;
534 _tnl_imm_elt_init();
535 }
536
537 ctx->swtnl_im = _tnl_alloc_immediate( ctx );
538 TNL_CURRENT_IM(ctx)->ref_count++;
539
540 tnl->ExecCopyTexSize = 0;
541 tnl->ExecCopyCount = 0;
542 tnl->ExecCopySource = 0;
543
544 TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS;
545
546 _mesa_vector4f_init( &tmp->Obj, 0, 0 );
547 _mesa_vector4f_init( &tmp->Normal, 0, 0 );
548
549 tmp->Color.Ptr = NULL;
550 tmp->Color.Type = GL_FLOAT;
551 tmp->Color.Size = 4;
552 tmp->Color.Stride = 0;
553 tmp->Color.StrideB = 4 * sizeof(GLfloat);
554 tmp->Color.Flags = 0;
555
556 tmp->SecondaryColor.Ptr = NULL;
557 tmp->SecondaryColor.Type = GL_FLOAT;
558 tmp->SecondaryColor.Size = 4;
559 tmp->SecondaryColor.Stride = 0;
560 tmp->SecondaryColor.StrideB = 4 * sizeof(GLfloat);
561 tmp->SecondaryColor.Flags = 0;
562
563 _mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
564 _mesa_vector1ui_init( &tmp->Index, 0, 0 );
565 _mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
566
567 for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
568 _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
569
570 /* Install the first immediate. Intially outside begin/end.
571 */
572 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
573 tnl->ReplayHardBeginEnd = 0;
574
575 _tnl_imm_vtxfmt_init( ctx );
576 }
577
578
579 /**
580 * Deallocate the immediate-mode buffer for the given context, if
581 * its reference count goes to zero.
582 */
583 void _tnl_imm_destroy( GLcontext *ctx )
584 {
585 if (TNL_CURRENT_IM(ctx)) {
586 TNL_CURRENT_IM(ctx)->ref_count--;
587 if (TNL_CURRENT_IM(ctx)->ref_count == 0)
588 _tnl_free_immediate( ctx, TNL_CURRENT_IM(ctx) );
589 /*
590 * Don't use SET_IMMEDIATE here, or else we'll whack the
591 * _tnl_CurrentInput pointer - not good when another
592 * context has already been made current.
593 * So we just set the context's own tnl immediate pointer
594 * to 0.
595 */
596 ctx->swtnl_im = NULL;
597 }
598 }