1 /* $Id: t_imm_exec.c,v 1.18 2001/04/28 08:39:18 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
27 * Keith Whitwell <keithw@valinux.com>
43 #include "math/m_matrix.h"
44 #include "math/m_xform.h"
46 #include "t_context.h"
47 #include "t_array_import.h"
48 #include "t_imm_alloc.h"
49 #include "t_imm_api.h"
50 #include "t_imm_debug.h"
51 #include "t_imm_dlist.h"
52 #include "t_imm_eval.h"
53 #include "t_imm_elt.h"
54 #include "t_imm_exec.h"
55 #include "t_imm_fixup.h"
56 #include "t_pipeline.h"
60 /* Called to initialize new buffers, and to recycle old ones.
62 void _tnl_reset_input( GLcontext
*ctx
,
65 GLuint savedbeginstate
)
67 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
69 /* Clear the dirty part of the flag array.
71 if (start
< IM
->Count
+2)
72 MEMSET(IM
->Flag
+ start
, 0, sizeof(GLuint
) * (IM
->Count
+2-start
));
74 IM
->CopyStart
= IM
->Start
= IM
->Count
= start
;
75 IM
->Primitive
[IM
->Start
] = (ctx
->Driver
.CurrentExecPrimitive
| PRIM_LAST
);
76 IM
->LastPrimitive
= IM
->Start
;
77 IM
->BeginState
= beginstate
;
78 IM
->SavedBeginState
= savedbeginstate
;
80 IM
->LastMaterial
= IM
->Start
;
81 IM
->MaterialOrMask
= 0;
84 IM
->MaterialMask
[IM
->Start
] = 0;
87 IM
->ArrayEltFlags
= ~ctx
->Array
._Enabled
;
88 IM
->ArrayEltIncr
= ctx
->Array
.Vertex
.Enabled
? 1 : 0;
89 IM
->ArrayEltFlush
= !ctx
->Array
.LockCount
;
94 void _tnl_copy_to_current( GLcontext
*ctx
, struct immediate
*IM
,
97 GLuint count
= IM
->LastData
;
99 if (MESA_VERBOSE
&VERBOSE_IMMEDIATE
)
100 _tnl_print_vert_flags("copy to current", flag
);
102 if (flag
& VERT_NORM
)
103 COPY_3FV( ctx
->Current
.Normal
, IM
->Normal
[count
]);
105 if (flag
& VERT_INDEX
)
106 ctx
->Current
.Index
= IM
->Index
[count
];
108 if (flag
& VERT_EDGE
)
109 ctx
->Current
.EdgeFlag
= IM
->EdgeFlag
[count
];
111 if (flag
& VERT_RGBA
) {
112 COPY_4FV(ctx
->Current
.Color
, IM
->Color
[count
]);
113 if (ctx
->Light
.ColorMaterialEnabled
) {
114 _mesa_update_color_material( ctx
, ctx
->Current
.Color
);
115 _mesa_validate_all_lighting_tables( ctx
);
119 if (flag
& VERT_SPEC_RGB
)
120 COPY_4FV(ctx
->Current
.SecondaryColor
, IM
->SecondaryColor
[count
]);
122 if (flag
& VERT_FOG_COORD
)
123 ctx
->Current
.FogCoord
= IM
->FogCoord
[count
];
125 if (flag
& VERT_TEX_ANY
) {
127 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
128 if (flag
& VERT_TEX(i
)) {
129 COPY_4FV( ctx
->Current
.Texcoord
[0], IM
->TexCoord
[0][count
]);
134 if (flag
& VERT_MATERIAL
) {
135 _mesa_update_material( ctx
,
136 IM
->Material
[IM
->LastMaterial
],
137 IM
->MaterialOrMask
);
139 _mesa_validate_all_lighting_tables( ctx
);
145 void _tnl_compute_orflag( struct immediate
*IM
)
147 GLuint count
= IM
->Count
;
149 GLuint andflag
= ~0U;
152 IM
->LastData
= count
-1;
155 /* Compute the flags for the whole buffer.
157 for (i
= IM
->CopyStart
; i
< count
; i
++) {
158 andflag
&= IM
->Flag
[i
];
159 orflag
|= IM
->Flag
[i
];
162 /* It is possible there will be data in the buffer arising from
163 * calls like 'glNormal', 'glMaterial' that occur after the final
164 * glVertex, glEval, etc. Additionally, a buffer can consist of
165 * eg. a single glMaterial call, in which case IM->Start ==
166 * IM->Count, but the buffer is definitely not empty.
168 if (IM
->Flag
[i
] & VERT_DATA
) {
170 orflag
|= IM
->Flag
[i
];
173 IM
->Flag
[IM
->LastData
+1] |= VERT_END_VB
;
174 IM
->CopyAndFlag
= IM
->AndFlag
= andflag
;
175 IM
->CopyOrFlag
= IM
->OrFlag
= orflag
;
185 /* Note: The 'start' member of the GLvector structs is now redundant
186 * because we always re-transform copied vertices, and the vectors
187 * below are set up so that the first copied vertex (if any) appears
190 static void _tnl_vb_bind_immediate( GLcontext
*ctx
, struct immediate
*IM
)
192 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
193 struct vertex_buffer
*VB
= &tnl
->vb
;
194 struct vertex_arrays
*tmp
= &tnl
->imm_inputs
;
195 GLuint inputs
= tnl
->pipeline
.inputs
; /* for copy-to-current */
196 GLuint start
= IM
->CopyStart
;
197 GLuint count
= IM
->Count
- start
;
199 /* TODO: optimize the case where nothing has changed. (Just bind
203 /* Setup constant data in the VB.
206 VB
->FirstClipped
= IMM_MAXDATA
- IM
->CopyStart
;
208 VB
->importable_data
= 0;
210 /* Need an IM->FirstPrimitive?
212 VB
->Primitive
= IM
->Primitive
+ IM
->CopyStart
;
213 VB
->PrimitiveLength
= IM
->PrimitiveLength
+ IM
->CopyStart
;
214 VB
->FirstPrimitive
= 0;
216 VB
->Flag
= IM
->Flag
+ start
;
218 /* TexCoordPtr's are zeroed in loop below.
227 VB
->SecondaryColorPtr
[0] = 0;
228 VB
->SecondaryColorPtr
[1] = 0;
230 VB
->MaterialMask
= 0;
233 /* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
234 /* _tnl_print_vert_flags("orflag", IM->OrFlag); */
235 /* _tnl_print_vert_flags("inputs", inputs); */
237 /* Setup the initial values of array pointers in the vb.
239 if (inputs
& VERT_OBJ
) {
240 tmp
->Obj
.data
= IM
->Obj
+ start
;
241 tmp
->Obj
.start
= (GLfloat
*)(IM
->Obj
+ start
);
242 tmp
->Obj
.count
= count
;
243 VB
->ObjPtr
= &tmp
->Obj
;
244 if ((IM
->CopyOrFlag
& VERT_OBJ_234
) == VERT_OBJ_234
)
246 else if ((IM
->CopyOrFlag
& VERT_OBJ_234
) == VERT_OBJ_23
)
252 if (inputs
& VERT_NORM
) {
253 tmp
->Normal
.data
= IM
->Normal
+ start
;
254 tmp
->Normal
.start
= (GLfloat
*)(IM
->Normal
+ start
);
255 tmp
->Normal
.count
= count
;
256 VB
->NormalPtr
= &tmp
->Normal
;
259 if (inputs
& VERT_INDEX
) {
260 tmp
->Index
.count
= count
;
261 tmp
->Index
.data
= IM
->Index
+ start
;
262 tmp
->Index
.start
= IM
->Index
+ start
;
263 VB
->IndexPtr
[0] = &tmp
->Index
;
266 if (inputs
& VERT_FOG_COORD
) {
267 tmp
->FogCoord
.data
= IM
->FogCoord
+ start
;
268 tmp
->FogCoord
.start
= IM
->FogCoord
+ start
;
269 tmp
->FogCoord
.count
= count
;
270 VB
->FogCoordPtr
= &tmp
->FogCoord
;
273 if (inputs
& VERT_SPEC_RGB
) {
274 tmp
->SecondaryColor
.Ptr
= IM
->SecondaryColor
+ start
;
275 VB
->SecondaryColorPtr
[0] = &tmp
->SecondaryColor
;
278 if (inputs
& VERT_EDGE
) {
279 VB
->EdgeFlag
= IM
->EdgeFlag
+ start
;
282 if (inputs
& VERT_RGBA
) {
283 if (IM
->CopyOrFlag
& VERT_RGBA
) {
284 tmp
->Color
.Ptr
= IM
->Color
+ start
;
285 tmp
->Color
.StrideB
= 4 * sizeof(GLfloat
);
286 tmp
->Color
.Flags
= 0;
288 tmp
->Color
.Ptr
= ctx
->Current
.Color
;
289 tmp
->Color
.StrideB
= 0;
290 tmp
->Color
.Flags
= CA_CLIENT_DATA
; /* hack */
291 VB
->importable_data
|= VERT_RGBA
;
292 VB
->import_data
= _tnl_upgrade_current_data
;
294 VB
->ColorPtr
[0] = &tmp
->Color
;
297 if (inputs
& VERT_TEX_ANY
) {
299 for (i
= 0; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
300 VB
->TexCoordPtr
[i
] = 0;
301 if (inputs
& VERT_TEX(i
)) {
302 tmp
->TexCoord
[i
].count
= count
;
303 tmp
->TexCoord
[i
].data
= IM
->TexCoord
[i
] + start
;
304 tmp
->TexCoord
[i
].start
= (GLfloat
*)(IM
->TexCoord
[i
] + start
);
305 tmp
->TexCoord
[i
].size
= 2;
306 if (IM
->TexSize
& TEX_SIZE_3(i
)) {
307 tmp
->TexCoord
[i
].size
= 3;
308 if (IM
->TexSize
& TEX_SIZE_4(i
))
309 tmp
->TexCoord
[i
].size
= 4;
311 VB
->TexCoordPtr
[i
] = &tmp
->TexCoord
[i
];
316 if ((inputs
& VERT_MATERIAL
) && IM
->Material
) {
317 VB
->MaterialMask
= IM
->MaterialMask
+ start
;
318 VB
->Material
= IM
->Material
+ start
;
321 /* _tnl_print_vert_flags("_tnl_vb_bind_immediate: importable", */
322 /* VB->importable_data); */
329 /* Called by exec_cassette and execute_compiled_cassette.
331 void _tnl_run_cassette( GLcontext
*ctx
, struct immediate
*IM
)
333 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
335 _tnl_vb_bind_immediate( ctx
, IM
);
337 if (IM
->CopyOrFlag
& VERT_EVAL_ANY
)
339 IM
->Obj
+ IM
->CopyStart
,
344 /* Invalidate all stored data before and after run:
346 tnl
->pipeline
.run_input_changes
|= tnl
->pipeline
.inputs
;
347 _tnl_run_pipeline( ctx
);
348 tnl
->pipeline
.run_input_changes
|= tnl
->pipeline
.inputs
;
350 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
);
356 /* Called for pure, locked VERT_ELT cassettes instead of
359 static void exec_elt_cassette( GLcontext
*ctx
, struct immediate
*IM
)
361 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
362 struct vertex_buffer
*VB
= &tnl
->vb
;
364 _tnl_vb_bind_arrays( ctx
, ctx
->Array
.LockFirst
, ctx
->Array
.LockCount
);
366 VB
->Elts
= IM
->Elt
+ IM
->CopyStart
;
367 VB
->Primitive
= IM
->Primitive
+ IM
->CopyStart
;
368 VB
->PrimitiveLength
= IM
->PrimitiveLength
+ IM
->CopyStart
;
369 VB
->FirstPrimitive
= 0;
371 /* Run the pipeline. No input changes as a result of this action.
373 _tnl_run_pipeline( ctx
);
375 /* Still need to update current values: (TODO - copy from VB)
376 * TODO: delay this until FlushVertices
378 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
379 _tnl_translate_array_elts( ctx
, IM
, IM
->LastData
, IM
->LastData
);
380 _tnl_copy_to_current( ctx
, IM
, ctx
->Array
._Enabled
);
386 /* Called for regular vertex cassettes.
388 static void exec_vert_cassette( GLcontext
*ctx
, struct immediate
*IM
)
390 if (IM
->OrFlag
& VERT_ELT
) {
393 GLuint start
= IM
->FlushElt
? IM
->LastPrimitive
: IM
->CopyStart
;
394 _tnl_translate_array_elts( ctx
, IM
, start
, IM
->Count
);
396 /* Need to recompute andflag.
398 if (IM
->CopyAndFlag
& VERT_ELT
)
399 IM
->CopyAndFlag
|= ctx
->Array
._Enabled
;
401 for (i
= IM
->CopyStart
; i
< IM
->Count
; i
++)
402 andflag
&= IM
->Flag
[i
];
403 IM
->CopyAndFlag
= andflag
;
407 _tnl_fixup_input( ctx
, IM
);
408 /* _tnl_print_cassette( IM ); */
409 _tnl_run_cassette( ctx
, IM
);
414 /* Called for all cassettes when not compiling or playing a display
417 void _tnl_execute_cassette( GLcontext
*ctx
, struct immediate
*IM
)
419 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
421 ASSERT(tnl
->ExecCopySource
== IM
);
423 _tnl_compute_orflag( IM
);
425 /* Mark the last primitive:
427 IM
->PrimitiveLength
[IM
->LastPrimitive
] = IM
->Count
- IM
->LastPrimitive
;
428 ASSERT(IM
->Primitive
[IM
->LastPrimitive
] & PRIM_LAST
);
430 if (tnl
->pipeline
.build_state_changes
)
431 _tnl_validate_pipeline( ctx
);
433 _tnl_get_exec_copy_verts( ctx
, IM
);
435 if (IM
->CopyStart
== IM
->Count
) {
436 if (IM
->OrFlag
& VERT_ELT
)
437 _tnl_translate_array_elts( ctx
, IM
, IM
->CopyStart
, IM
->CopyStart
);
439 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
);
441 else if ((IM
->OrFlag
& VERT_DATA
) == VERT_ELT
&&
442 ctx
->Array
.LockCount
&&
443 ctx
->Array
.Vertex
.Enabled
) {
444 exec_elt_cassette( ctx
, IM
);
447 exec_vert_cassette( ctx
, IM
);
450 _tnl_reset_input( ctx
,
451 IMM_MAX_COPIED_VERTS
,
452 IM
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
),
453 IM
->SavedBeginState
);
455 /* Copy vertices and primitive information to immediate before it
456 * can be overwritten.
458 _tnl_copy_immediate_vertices( ctx
, IM
);
460 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
461 ctx
->Driver
.NeedFlush
&= ~FLUSH_STORED_VERTICES
;
467 /* Setup vector pointers that will be used to bind immediates to VB's.
469 void _tnl_imm_init( GLcontext
*ctx
)
471 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
472 struct vertex_arrays
*tmp
= &tnl
->imm_inputs
;
474 static int firsttime
= 1;
481 ctx
->swtnl_im
= _tnl_alloc_immediate( ctx
);
482 TNL_CURRENT_IM(ctx
)->ref_count
++;
484 tnl
->ExecCopyTexSize
= 0;
485 tnl
->ExecCopyCount
= 0;
486 tnl
->ExecCopySource
= TNL_CURRENT_IM(ctx
);
487 TNL_CURRENT_IM(ctx
)->ref_count
++;
489 TNL_CURRENT_IM(ctx
)->CopyStart
= IMM_MAX_COPIED_VERTS
;
491 _mesa_vector4f_init( &tmp
->Obj
, 0, 0 );
492 _mesa_vector3f_init( &tmp
->Normal
, 0, 0 );
495 tmp
->Color
.Type
= GL_FLOAT
;
497 tmp
->Color
.Stride
= 0;
498 tmp
->Color
.StrideB
= 4 * sizeof(GLfloat
);
499 tmp
->Color
.Flags
= 0;
501 tmp
->SecondaryColor
.Ptr
= 0;
502 tmp
->SecondaryColor
.Type
= GL_FLOAT
;
503 tmp
->SecondaryColor
.Size
= 4;
504 tmp
->SecondaryColor
.Stride
= 0;
505 tmp
->SecondaryColor
.StrideB
= 4 * sizeof(GLfloat
);
506 tmp
->SecondaryColor
.Flags
= 0;
508 _mesa_vector1f_init( &tmp
->FogCoord
, 0, 0 );
509 _mesa_vector1ui_init( &tmp
->Index
, 0, 0 );
510 _mesa_vector1ub_init( &tmp
->EdgeFlag
, 0, 0 );
512 for (i
= 0; i
< ctx
->Const
.MaxTextureUnits
; i
++)
513 _mesa_vector4f_init( &tmp
->TexCoord
[i
], 0, 0);
515 /* Install the first immediate. Intially outside begin/end.
517 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
518 tnl
->ReplayHardBeginEnd
= 0;
520 _tnl_imm_vtxfmt_init( ctx
);
524 void _tnl_imm_destroy( GLcontext
*ctx
)
526 if (TNL_CURRENT_IM(ctx
))
527 _tnl_free_immediate( TNL_CURRENT_IM(ctx
) );