1 /* $Id: t_imm_dlist.c,v 1.7 2001/02/13 23:51:34 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 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
;
60 GLboolean have_normal_lengths
;
63 static void execute_compiled_cassette( GLcontext
*ctx
, void *data
);
66 /* Insert the active immediate struct onto the display list currently
70 _tnl_compile_cassette( GLcontext
*ctx
, struct immediate
*IM
)
72 struct immediate
*im
= TNL_CURRENT_IM(ctx
);
73 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
74 TNLvertexcassette
*node
;
75 GLuint new_beginstate
;
78 _tnl_compute_orflag( IM
);
80 IM
->CopyStart
= IM
->Start
;
82 if (IM
->OrFlag
& VERT_ELT
) {
85 GLuint start
= IM
->FlushElt
? IM
->LastPrimitive
: IM
->CopyStart
;
86 _tnl_translate_array_elts( ctx
, IM
, start
, IM
->Count
);
88 /* Need to recompute andflag.
90 if (IM
->AndFlag
& VERT_ELT
)
91 IM
->CopyAndFlag
= IM
->AndFlag
|= ctx
->Array
._Enabled
;
93 for (i
= IM
->CopyStart
; i
< IM
->Count
; i
++)
94 andflag
&= IM
->Flag
[i
];
95 IM
->CopyAndFlag
= IM
->AndFlag
= andflag
;
99 _tnl_fixup_input( ctx
, IM
);
101 /* Mark the last primitive:
103 IM
->PrimitiveLength
[IM
->LastPrimitive
] = IM
->Count
- IM
->LastPrimitive
;
104 ASSERT(IM
->Primitive
[IM
->LastPrimitive
] & PRIM_LAST
);
107 node
= (TNLvertexcassette
*)
108 _mesa_alloc_instruction(ctx
,
109 tnl
->opcode_vertex_cassette
,
110 sizeof(TNLvertexcassette
));
114 node
->IM
= im
; im
->ref_count
++;
115 node
->Start
= im
->Start
;
116 node
->Count
= im
->Count
;
117 node
->BeginState
= im
->BeginState
;
118 node
->SavedBeginState
= im
->SavedBeginState
;
119 node
->OrFlag
= im
->OrFlag
;
120 node
->TexSize
= im
->TexSize
;
121 node
->AndFlag
= im
->AndFlag
;
122 node
->LastData
= im
->LastData
;
123 node
->LastPrimitive
= im
->LastPrimitive
;
124 node
->have_normal_lengths
= GL_FALSE
;
126 if (ctx
->ExecuteFlag
) {
127 execute_compiled_cassette( ctx
, (void *)node
);
131 /* Discard any errors raised in the last cassette.
133 new_beginstate
= node
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
135 /* Decide whether this immediate struct is full, or can be used for
136 * the next batch of vertices as well.
138 if (im
->Count
> IMM_MAXDATA
- 16) {
141 struct immediate
*new_im
= _tnl_alloc_immediate(ctx
);
144 im
->ref_count
--; /* remove CURRENT_IM reference */
145 ASSERT(im
->ref_count
> 0);
146 SET_IMMEDIATE( ctx
, new_im
);
147 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
,
148 new_beginstate
, node
->SavedBeginState
);
150 /* Still some room in the current immediate.
152 _tnl_reset_input( ctx
, im
->Count
+1+IMM_MAX_COPIED_VERTS
,
153 new_beginstate
, node
->SavedBeginState
);
160 /* Drivers to turn this on?
162 static void calc_normal_lengths( GLfloat
*dest
,
163 CONST
GLfloat (*data
)[3],
168 GLint tmpflag
= flags
[0];
170 flags
[0] |= VERT_NORM
;
172 for (i
= 0 ; i
< count
; i
++ )
173 if (flags
[i
] & VERT_NORM
) {
174 GLfloat tmp
= (GLfloat
) LEN_3FV( data
[i
] );
177 dest
[i
] = 1.0F
/ tmp
;
187 execute_compiled_cassette( GLcontext
*ctx
, void *data
)
189 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
190 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
191 struct immediate
*IM
= node
->IM
;
194 gl_update_state(ctx
);
196 if (tnl
->pipeline
.build_state_changes
)
197 _tnl_validate_pipeline( ctx
);
199 IM
->Start
= node
->Start
;
200 IM
->CopyStart
= node
->Start
;
201 IM
->Count
= node
->Count
;
202 IM
->BeginState
= node
->BeginState
;
203 IM
->SavedBeginState
= node
->SavedBeginState
;
204 IM
->OrFlag
= node
->OrFlag
;
205 IM
->TexSize
= node
->TexSize
;
206 IM
->AndFlag
= node
->AndFlag
;
207 IM
->LastData
= node
->LastData
;
208 IM
->LastPrimitive
= node
->LastPrimitive
;
210 if ((MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) &&
211 (MESA_VERBOSE
& VERBOSE_IMMEDIATE
))
212 _tnl_print_cassette( IM
);
214 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) {
215 fprintf(stderr
, "Run cassette %d, rows %d..%d, beginstate %x ",
217 IM
->Start
, IM
->Count
, IM
->BeginState
);
218 _tnl_print_vert_flags("orflag", IM
->OrFlag
);
221 if (IM
->Count
== IM
->Start
) {
222 _tnl_run_empty_cassette( ctx
, IM
);
226 if (IM
->SavedBeginState
) {
227 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
228 tnl
->ReplayHardBeginEnd
= 1;
229 if (!tnl
->ReplayHardBeginEnd
) {
230 /* XXX is this really an OpenGL error or an implementation problem? */
231 gl_error(ctx
, GL_INVALID_OPERATION
, "hard replay");
237 /* Lazy optimization of the cassette. Need to make these switchable
238 * or otherwise more useful for t&l cards.
241 if (ctx
->Transform
.Normalize
&& !node
->have_normal_lengths
) {
243 if (!IM
->NormalLengths
)
244 IM
->NormalLengths
= (GLfloat
*)MALLOC(sizeof(GLfloat
) * IMM_SIZE
);
246 calc_normal_lengths( IM
->NormalLengths
+ IM
->Start
,
247 (const GLfloat (*)[3])(IM
->Normal
+ IM
->Start
),
248 IM
->Flag
+ IM
->Start
,
249 IM
->Count
- IM
->Start
);
251 node
->have_normal_lengths
= GL_TRUE
;
257 if (0 && im
->v
.Obj
.size
< 4 && im
->Count
> 15) {
258 im
->Bounds
= (GLfloat (*)[3]) MALLOC(6 * sizeof(GLfloat
));
259 (_tnl_calc_bound_tab
[im
->v
.Obj
.size
])( im
->Bounds
, &im
->v
.Obj
);
264 _tnl_fixup_compiled_cassette( ctx
, IM
);
265 _tnl_get_exec_copy_verts( ctx
, IM
);
266 _tnl_run_cassette( ctx
, IM
);
267 _tnl_restore_compiled_cassette( ctx
, IM
);
269 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
270 tnl
->ReplayHardBeginEnd
= 0;
274 destroy_compiled_cassette( GLcontext
*ctx
, void *data
)
276 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
278 /* fprintf(stderr, "destroy_compiled_cassette node->IM id %d ref_count: %d\n", */
280 /* node->IM->ref_count-1); */
282 if ( --node
->IM
->ref_count
== 0 )
283 _tnl_free_immediate( node
->IM
);
288 print_compiled_cassette( GLcontext
*ctx
, void *data
)
290 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
291 struct immediate
*IM
= node
->IM
;
293 fprintf(stderr
, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
294 node
->IM
->id
, node
->Start
, node
->Count
);
296 IM
->Start
= node
->Start
;
297 IM
->Count
= node
->Count
;
298 IM
->BeginState
= node
->BeginState
;
299 IM
->OrFlag
= node
->OrFlag
;
300 IM
->TexSize
= node
->TexSize
;
301 IM
->AndFlag
= node
->AndFlag
;
302 IM
->LastData
= node
->LastData
;
303 IM
->LastPrimitive
= node
->LastPrimitive
;
305 _tnl_print_cassette( node
->IM
);
309 _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
313 FLUSH_CURRENT(ctx
, 0);
317 /* Called at the tail of a CallList. Copy vertices out of the display
321 _tnl_EndCallList( GLcontext
*ctx
)
323 /* May have to copy vertices from a dangling begin/end inside the
324 * list to the current immediate.
326 if (ctx
->CallDepth
== 0) {
327 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
328 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
330 if (tnl
->ExecCopySource
!= IM
)
331 _tnl_copy_immediate_vertices( ctx
, IM
);
337 _tnl_EndList( GLcontext
*ctx
)
339 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
340 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
344 if (IM
== tnl
->ExecCopySource
) {
347 if ( --tnl
->ExecCopySource
->ref_count
== 0 )
348 _tnl_free_immediate( tnl
->ExecCopySource
);
351 /* If this one isn't free, get a clean one. (Otherwise we'll be
352 * using one that's already half full).
354 if (IM
->ref_count
!= 0)
355 IM
= _tnl_alloc_immediate( ctx
);
357 ASSERT(IM
->ref_count
== 0);
359 tnl
->ExecCopySource
= IM
;
363 SET_IMMEDIATE( ctx
, IM
);
366 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
368 /* outside begin/end, even in COMPILE_AND_EXEC,
369 * so no vertices to copy, right?
371 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
376 _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
378 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
380 /* Use the installed immediate struct. No vertices in the current
381 * immediate, no copied vertices in the system.
383 ASSERT(TNL_CURRENT_IM(ctx
));
384 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== IMM_MAX_COPIED_VERTS
);
385 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== TNL_CURRENT_IM(ctx
)->Count
);
386 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
388 /* Set current Begin/End state to unknown:
390 IM
->BeginState
= VERT_BEGIN_0
;
391 ctx
->Driver
.CurrentSavePrimitive
= PRIM_UNKNOWN
;
396 _tnl_dlist_init( GLcontext
*ctx
)
398 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
400 tnl
->opcode_vertex_cassette
=
401 _mesa_alloc_opcode( ctx
,
402 sizeof(TNLvertexcassette
),
403 execute_compiled_cassette
,
404 destroy_compiled_cassette
,
405 print_compiled_cassette
);