1 /* $Id: t_imm_dlist.c,v 1.20 2001/06/04 16:09:28 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>
39 #include "t_context.h"
40 #include "t_imm_api.h"
41 #include "t_imm_elt.h"
42 #include "t_imm_alloc.h"
43 #include "t_imm_dlist.h"
44 #include "t_imm_debug.h"
45 #include "t_imm_exec.h"
46 #include "t_imm_fixup.h"
47 #include "t_pipeline.h"
54 GLuint SavedBeginState
;
61 GLuint MaterialOrMask
;
62 GLuint MaterialAndMask
;
65 static void execute_compiled_cassette( GLcontext
*ctx
, void *data
);
66 static void loopback_compiled_cassette( GLcontext
*ctx
, struct immediate
*IM
);
69 /* Insert the active immediate struct onto the display list currently
73 _tnl_compile_cassette( GLcontext
*ctx
, struct immediate
*IM
)
75 struct immediate
*im
= TNL_CURRENT_IM(ctx
);
76 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
77 TNLvertexcassette
*node
;
78 GLuint new_beginstate
;
81 ASSERT (IM
->FlushElt
== FLUSH_ELT_LAZY
);
82 _tnl_translate_array_elts( ctx
, IM
, IM
->Start
, IM
->Count
);
85 _tnl_compute_orflag( IM
, IM
->Start
);
87 /* Need to clear this flag, or fixup gets confused. (The elements
88 * have been translated away by now.)
90 IM
->OrFlag
&= ~VERT_ELT
;
91 IM
->AndFlag
&= ~VERT_ELT
;
93 _tnl_fixup_input( ctx
, IM
);
94 /* _tnl_print_cassette( IM ); */
96 node
= (TNLvertexcassette
*)
97 _mesa_alloc_instruction(ctx
,
98 tnl
->opcode_vertex_cassette
,
99 sizeof(TNLvertexcassette
));
103 node
->IM
= im
; im
->ref_count
++;
104 node
->Start
= im
->Start
;
105 node
->Count
= im
->Count
;
106 node
->BeginState
= im
->BeginState
;
107 node
->SavedBeginState
= im
->SavedBeginState
;
108 node
->OrFlag
= im
->OrFlag
;
109 node
->TexSize
= im
->TexSize
;
110 node
->AndFlag
= im
->AndFlag
;
111 node
->LastData
= im
->LastData
;
112 node
->LastPrimitive
= im
->LastPrimitive
;
113 node
->LastMaterial
= im
->LastMaterial
;
114 node
->MaterialOrMask
= im
->MaterialOrMask
;
115 node
->MaterialAndMask
= im
->MaterialAndMask
;
117 if (ctx
->ExecuteFlag
) {
118 execute_compiled_cassette( ctx
, (void *)node
);
121 /* Discard any errors raised in the last cassette.
123 new_beginstate
= node
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
125 /* Decide whether this immediate struct is full, or can be used for
126 * the next batch of vertices as well.
128 if (im
->Count
> IMM_MAXDATA
- 16) {
131 struct immediate
*new_im
= _tnl_alloc_immediate(ctx
);
133 im
->ref_count
--; /* remove CURRENT_IM reference */
134 ASSERT(im
->ref_count
> 0); /* it is compiled into a display list */
135 SET_IMMEDIATE( ctx
, new_im
);
136 _tnl_reset_compile_input( ctx
, IMM_MAX_COPIED_VERTS
,
137 new_beginstate
, node
->SavedBeginState
);
139 /* Still some room in the current immediate.
141 _tnl_reset_compile_input( ctx
, im
->Count
+1+IMM_MAX_COPIED_VERTS
,
142 new_beginstate
, node
->SavedBeginState
);
147 static void fixup_compiled_primitives( GLcontext
*ctx
, struct immediate
*IM
)
149 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
151 /* Can potentially overwrite primitive details - need to save the
154 tnl
->DlistPrimitive
= IM
->Primitive
[IM
->Start
];
155 tnl
->DlistPrimitiveLength
= IM
->PrimitiveLength
[IM
->Start
];
156 tnl
->DlistLastPrimitive
= IM
->LastPrimitive
;
158 /* The first primitive may be different from what was recorded in
159 * the immediate struct. Consider an immediate that starts with a
160 * glBegin, compiled in a display list, which is called from within
161 * an existing Begin/End object.
163 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
166 if (IM
->BeginState
& VERT_ERROR_1
)
167 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin/glEnd");
169 for (i
= IM
->Start
; i
<= IM
->Count
; i
+= IM
->PrimitiveLength
[i
])
170 if (IM
->Flag
[i
] & (VERT_BEGIN
|VERT_END_VB
))
173 /* Would like to just ignore vertices upto this point. Can't
174 * set copystart because it might skip materials?
176 ASSERT(IM
->Start
== IM
->CopyStart
);
177 if (i
> IM
->CopyStart
) {
178 IM
->Primitive
[IM
->CopyStart
] = GL_POLYGON
+1;
179 IM
->PrimitiveLength
[IM
->CopyStart
] = i
- IM
->CopyStart
;
180 if (IM
->Flag
[i
] & VERT_END_VB
) {
181 IM
->Primitive
[IM
->CopyStart
] |= PRIM_LAST
;
182 IM
->LastPrimitive
= IM
->CopyStart
;
188 if (IM
->BeginState
& VERT_ERROR_0
)
189 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin/glEnd");
191 if (IM
->CopyStart
== IM
->Start
&&
192 IM
->Flag
[IM
->Start
] & (VERT_END
|VERT_END_VB
))
197 IM
->Primitive
[IM
->CopyStart
] = ctx
->Driver
.CurrentExecPrimitive
;
199 IM
->Primitive
[IM
->CopyStart
] |= PRIM_PARITY
;
201 /* one of these should be true, else we'll be in an infinite loop
203 ASSERT(IM
->PrimitiveLength
[IM
->Start
] > 0 ||
204 IM
->Flag
[IM
->Start
] & (VERT_END
|VERT_END_VB
));
206 for (i
= IM
->Start
; i
<= IM
->Count
; i
+= IM
->PrimitiveLength
[i
])
207 if (IM
->Flag
[i
] & (VERT_END
|VERT_END_VB
)) {
208 IM
->PrimitiveLength
[IM
->CopyStart
] = i
- IM
->CopyStart
;
209 if (IM
->Flag
[i
] & VERT_END_VB
) {
210 IM
->Primitive
[IM
->CopyStart
] |= PRIM_LAST
;
211 IM
->LastPrimitive
= IM
->CopyStart
;
213 if (IM
->Flag
[i
] & VERT_END
) {
214 IM
->Primitive
[IM
->CopyStart
] |= PRIM_END
;
222 /* Undo any changes potentially made to the immediate in the range
223 * IM->Start..IM->Count above.
225 static void restore_compiled_primitives( GLcontext
*ctx
, struct immediate
*IM
)
227 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
228 IM
->Primitive
[IM
->Start
] = tnl
->DlistPrimitive
;
229 IM
->PrimitiveLength
[IM
->Start
] = tnl
->DlistPrimitiveLength
;
235 execute_compiled_cassette( GLcontext
*ctx
, void *data
)
237 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
238 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
239 struct immediate
*IM
= node
->IM
;
241 /* fprintf(stderr, "%s\n", __FUNCTION__); */
243 IM
->Start
= node
->Start
;
244 IM
->CopyStart
= node
->Start
;
245 IM
->Count
= node
->Count
;
246 IM
->BeginState
= node
->BeginState
;
247 IM
->SavedBeginState
= node
->SavedBeginState
;
248 IM
->OrFlag
= node
->OrFlag
;
249 IM
->TexSize
= node
->TexSize
;
250 IM
->AndFlag
= node
->AndFlag
;
251 IM
->LastData
= node
->LastData
;
252 IM
->LastPrimitive
= node
->LastPrimitive
;
253 IM
->LastMaterial
= node
->LastMaterial
;
254 IM
->MaterialOrMask
= node
->MaterialOrMask
;
255 IM
->MaterialAndMask
= node
->MaterialAndMask
;
257 if ((MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) &&
258 (MESA_VERBOSE
& VERBOSE_IMMEDIATE
))
259 _tnl_print_cassette( IM
);
261 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) {
262 fprintf(stderr
, "Run cassette %d, rows %d..%d, beginstate %x ",
264 IM
->Start
, IM
->Count
, IM
->BeginState
);
265 _tnl_print_vert_flags("orflag", IM
->OrFlag
);
269 /* Need to respect 'HardBeginEnd' even if the commands are looped
270 * back to a driver tnl module.
272 if (IM
->SavedBeginState
) {
273 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
274 tnl
->ReplayHardBeginEnd
= 1;
275 if (!tnl
->ReplayHardBeginEnd
) {
276 /* This is a user error. Whatever operation (like glRectf)
277 * decomposed to this hard begin/end pair is now being run
278 * inside a begin/end object -- illegally. Reject it and
281 _mesa_error(ctx
, GL_INVALID_OPERATION
, "hard replay");
286 if (tnl
->LoopbackDListCassettes
) {
287 fixup_compiled_primitives( ctx
, IM
);
288 loopback_compiled_cassette( ctx
, IM
);
289 restore_compiled_primitives( ctx
, IM
);
291 else if (IM
->Count
== IM
->Start
) {
292 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
);
296 _mesa_update_state(ctx
);
298 if (tnl
->pipeline
.build_state_changes
)
299 _tnl_validate_pipeline( ctx
);
301 _tnl_fixup_compiled_cassette( ctx
, IM
);
302 fixup_compiled_primitives( ctx
, IM
);
304 if (IM
->Primitive
[IM
->LastPrimitive
] & PRIM_END
)
305 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
307 ctx
->Driver
.CurrentExecPrimitive
=
308 IM
->Primitive
[IM
->LastPrimitive
] & PRIM_MODE_MASK
;
310 _tnl_get_exec_copy_verts( ctx
, IM
);
311 _tnl_run_cassette( ctx
, IM
);
313 restore_compiled_primitives( ctx
, IM
);
316 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
317 tnl
->ReplayHardBeginEnd
= 0;
321 destroy_compiled_cassette( GLcontext
*ctx
, void *data
)
323 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
325 if ( --node
->IM
->ref_count
== 0 )
326 _tnl_free_immediate( node
->IM
);
331 print_compiled_cassette( GLcontext
*ctx
, void *data
)
333 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
334 struct immediate
*IM
= node
->IM
;
336 fprintf(stderr
, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
337 node
->IM
->id
, node
->Start
, node
->Count
);
339 IM
->Start
= node
->Start
;
340 IM
->Count
= node
->Count
;
341 IM
->BeginState
= node
->BeginState
;
342 IM
->OrFlag
= node
->OrFlag
;
343 IM
->TexSize
= node
->TexSize
;
344 IM
->AndFlag
= node
->AndFlag
;
345 IM
->LastData
= node
->LastData
;
346 IM
->LastPrimitive
= node
->LastPrimitive
;
347 IM
->LastMaterial
= node
->LastMaterial
;
348 IM
->MaterialOrMask
= node
->MaterialOrMask
;
349 IM
->MaterialAndMask
= node
->MaterialAndMask
;
351 _tnl_print_cassette( node
->IM
);
355 _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
359 FLUSH_CURRENT(ctx
, 0);
363 /* Called at the tail of a CallList. Nothing to do.
366 _tnl_EndCallList( GLcontext
*ctx
)
372 _tnl_EndList( GLcontext
*ctx
)
374 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
379 /* outside begin/end, even in COMPILE_AND_EXEC,
380 * so no vertices to copy, right?
382 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
384 /* If this one isn't free, get a clean one. (Otherwise we'll be
385 * using one that's already half full).
387 if (IM
->ref_count
!= 0)
388 IM
= _tnl_alloc_immediate( ctx
);
390 ASSERT(IM
->ref_count
== 0);
392 SET_IMMEDIATE( ctx
, IM
);
395 _tnl_reset_exec_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
400 _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
402 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
404 /* Use the installed immediate struct. No vertices in the current
405 * immediate, no copied vertices in the system.
407 ASSERT(TNL_CURRENT_IM(ctx
));
408 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== IMM_MAX_COPIED_VERTS
);
409 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== TNL_CURRENT_IM(ctx
)->Count
);
410 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
412 /* Set current Begin/End state to unknown:
414 IM
->BeginState
= VERT_BEGIN_0
;
415 ctx
->Driver
.CurrentSavePrimitive
= PRIM_UNKNOWN
;
420 _tnl_dlist_init( GLcontext
*ctx
)
422 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
424 tnl
->opcode_vertex_cassette
=
425 _mesa_alloc_opcode( ctx
,
426 sizeof(TNLvertexcassette
),
427 execute_compiled_cassette
,
428 destroy_compiled_cassette
,
429 print_compiled_cassette
);
433 static void emit_material( struct gl_material
*src
, GLuint bitmask
)
435 if (bitmask
& FRONT_EMISSION_BIT
)
436 glMaterialfv( GL_FRONT
, GL_EMISSION
, src
[0].Emission
);
438 if (bitmask
& BACK_EMISSION_BIT
)
439 glMaterialfv( GL_BACK
, GL_EMISSION
, src
[1].Emission
);
441 if (bitmask
& FRONT_AMBIENT_BIT
)
442 glMaterialfv( GL_FRONT
, GL_AMBIENT
, src
[0].Ambient
);
444 if (bitmask
& BACK_AMBIENT_BIT
)
445 glMaterialfv( GL_BACK
, GL_AMBIENT
, src
[1].Ambient
);
447 if (bitmask
& FRONT_DIFFUSE_BIT
)
448 glMaterialfv( GL_FRONT
, GL_DIFFUSE
, src
[0].Diffuse
);
450 if (bitmask
& BACK_DIFFUSE_BIT
)
451 glMaterialfv( GL_BACK
, GL_DIFFUSE
, src
[1].Diffuse
);
453 if (bitmask
& FRONT_SPECULAR_BIT
)
454 glMaterialfv( GL_FRONT
, GL_SPECULAR
, src
[0].Specular
);
456 if (bitmask
& BACK_SPECULAR_BIT
)
457 glMaterialfv( GL_BACK
, GL_SPECULAR
, src
[1].Specular
);
459 if (bitmask
& FRONT_SHININESS_BIT
)
460 glMaterialfv( GL_FRONT
, GL_SHININESS
, &src
[0].Shininess
);
462 if (bitmask
& BACK_SHININESS_BIT
)
463 glMaterialfv( GL_BACK
, GL_SHININESS
, &src
[1].Shininess
);
465 if (bitmask
& FRONT_INDEXES_BIT
) {
467 ind
[0] = src
[0].AmbientIndex
;
468 ind
[1] = src
[0].DiffuseIndex
;
469 ind
[2] = src
[0].SpecularIndex
;
470 glMaterialfv( GL_FRONT
, GL_COLOR_INDEXES
, ind
);
473 if (bitmask
& BACK_INDEXES_BIT
) {
475 ind
[0] = src
[1].AmbientIndex
;
476 ind
[1] = src
[1].DiffuseIndex
;
477 ind
[2] = src
[1].SpecularIndex
;
478 glMaterialfv( GL_BACK
, GL_COLOR_INDEXES
, ind
);
483 /* Low-performance helper function to allow driver-supplied tnl
484 * modules to process tnl display lists. This is primarily supplied
485 * to avoid fallbacks if CallList is invoked inside a Begin/End pair.
486 * For higher performance, drivers should fallback to tnl (if outside
487 * begin/end), or (for tnl hardware) implement their own display list
490 static void loopback_compiled_cassette( GLcontext
*ctx
, struct immediate
*IM
)
493 GLuint
*flags
= IM
->Flag
;
494 GLuint orflag
= IM
->OrFlag
;
496 void (*vertex
)( const GLfloat
* );
497 void (*texcoordfv
[MAX_TEXTURE_UNITS
])( GLuint
, const GLfloat
* );
499 GLuint p
, length
, prim
= 0;
501 if (orflag
& VERT_OBJ_234
)
502 vertex
= glVertex4fv
;
504 vertex
= glVertex3fv
;
506 if (orflag
& VERT_TEX_ANY
) {
507 for (j
= 0 ; j
< ctx
->Const
.MaxTextureUnits
; j
++) {
508 if (orflag
& VERT_TEX(j
)) {
510 if ((IM
->TexSize
& TEX_SIZE_4(j
)) == TEX_SIZE_4(j
))
511 texcoordfv
[j
] = glMultiTexCoord4fvARB
;
512 else if (IM
->TexSize
& TEX_SIZE_3(j
))
513 texcoordfv
[j
] = glMultiTexCoord3fvARB
;
515 texcoordfv
[j
] = glMultiTexCoord2fvARB
;
520 for (p
= IM
->Start
; !(prim
& PRIM_LAST
) ; p
+= length
)
522 prim
= IM
->Primitive
[p
];
523 length
= IM
->PrimitiveLength
[p
];
524 ASSERT(length
|| (prim
& PRIM_LAST
));
525 ASSERT((prim
& PRIM_MODE_MASK
) <= GL_POLYGON
+1);
527 if (prim
& PRIM_BEGIN
) {
528 /* fprintf(stderr, "begin %s\n", _mesa_prim_name[prim&PRIM_MODE_MASK]); */
529 glBegin(prim
& PRIM_MODE_MASK
);
532 for ( i
= p
; i
<= p
+length
; i
++) {
533 if (flags
[i
] & VERT_TEX_ANY
) {
535 for (k
= 0 ; k
< maxtex
; k
++) {
536 if (flags
[i
] & VERT_TEX(k
)) {
537 texcoordfv
[k
]( GL_TEXTURE0_ARB
+ k
, IM
->TexCoord
[k
][i
] );
542 if (flags
[i
] & VERT_NORM
) {
543 /* fprintf(stderr, "normal %d: %f %f %f\n", i, */
544 /* IM->Normal[i][0], IM->Normal[i][1], IM->Normal[i][2]); */
545 glNormal3fv(IM
->Normal
[i
]);
548 if (flags
[i
] & VERT_RGBA
) {
549 /* fprintf(stderr, "color %d: %f %f %f\n", i, */
550 /* IM->Color[i][0], IM->Color[i][1], IM->Color[i][2]); */
551 glColor4fv( IM
->Color
[i
] );
554 if (flags
[i
] & VERT_SPEC_RGB
)
555 glSecondaryColor3fvEXT( IM
->SecondaryColor
[i
] );
557 if (flags
[i
] & VERT_FOG_COORD
)
558 glFogCoordfEXT( IM
->FogCoord
[i
] );
560 if (flags
[i
] & VERT_INDEX
)
561 glIndexi( IM
->Index
[i
] );
563 if (flags
[i
] & VERT_EDGE
)
564 glEdgeFlag( IM
->EdgeFlag
[i
] );
566 if (flags
[i
] & VERT_MATERIAL
)
567 emit_material( IM
->Material
[i
], IM
->MaterialMask
[i
] );
569 if (flags
[i
]&VERT_OBJ_234
) {
570 /* fprintf(stderr, "vertex %d: %f %f %f\n", i, */
571 /* IM->Obj[i][0], IM->Obj[i][1], IM->Obj[i][2]); */
572 vertex( IM
->Obj
[i
] );
574 else if (flags
[i
] & VERT_EVAL_C1
)
575 glEvalCoord1f(IM
->Obj
[i
][0]);
576 else if (flags
[i
] & VERT_EVAL_P1
)
577 glEvalPoint1(IM
->Obj
[i
][0]);
578 else if (flags
[i
] & VERT_EVAL_C2
)
579 glEvalCoord2f( IM
->Obj
[i
][0], IM
->Obj
[i
][1]);
580 else if (flags
[i
] & VERT_EVAL_P2
)
581 glEvalPoint2( IM
->Obj
[i
][0], IM
->Obj
[i
][1]);
584 if (prim
& PRIM_END
) {
585 /* fprintf(stderr, "end\n"); */