1 /* $Id: t_imm_dlist.c,v 1.9 2001/02/16 00:35:35 keithw 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
;
61 GLuint MaterialOrMask
;
64 static void execute_compiled_cassette( GLcontext
*ctx
, void *data
);
67 /* Insert the active immediate struct onto the display list currently
71 _tnl_compile_cassette( GLcontext
*ctx
, struct immediate
*IM
)
73 struct immediate
*im
= TNL_CURRENT_IM(ctx
);
74 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
75 TNLvertexcassette
*node
;
76 GLuint new_beginstate
;
79 _tnl_compute_orflag( IM
);
81 IM
->CopyStart
= IM
->Start
;
83 if (IM
->OrFlag
& VERT_ELT
) {
86 GLuint start
= IM
->FlushElt
? IM
->LastPrimitive
: IM
->CopyStart
;
87 _tnl_translate_array_elts( ctx
, IM
, start
, IM
->Count
);
89 /* Need to recompute andflag.
91 if (IM
->AndFlag
& VERT_ELT
)
92 IM
->CopyAndFlag
= IM
->AndFlag
|= ctx
->Array
._Enabled
;
94 for (i
= IM
->CopyStart
; i
< IM
->Count
; i
++)
95 andflag
&= IM
->Flag
[i
];
96 IM
->CopyAndFlag
= IM
->AndFlag
= andflag
;
100 _tnl_fixup_input( ctx
, IM
);
102 /* Mark the last primitive:
104 IM
->PrimitiveLength
[IM
->LastPrimitive
] = IM
->Count
- IM
->LastPrimitive
;
105 ASSERT(IM
->Primitive
[IM
->LastPrimitive
] & PRIM_LAST
);
108 node
= (TNLvertexcassette
*)
109 _mesa_alloc_instruction(ctx
,
110 tnl
->opcode_vertex_cassette
,
111 sizeof(TNLvertexcassette
));
115 node
->IM
= im
; im
->ref_count
++;
116 node
->Start
= im
->Start
;
117 node
->Count
= im
->Count
;
118 node
->BeginState
= im
->BeginState
;
119 node
->SavedBeginState
= im
->SavedBeginState
;
120 node
->OrFlag
= im
->OrFlag
;
121 node
->TexSize
= im
->TexSize
;
122 node
->AndFlag
= im
->AndFlag
;
123 node
->LastData
= im
->LastData
;
124 node
->LastPrimitive
= im
->LastPrimitive
;
125 node
->LastMaterial
= im
->LastMaterial
;
126 node
->MaterialOrMask
= im
->MaterialOrMask
;
128 if (ctx
->ExecuteFlag
) {
129 execute_compiled_cassette( ctx
, (void *)node
);
133 /* Discard any errors raised in the last cassette.
135 new_beginstate
= node
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
137 /* Decide whether this immediate struct is full, or can be used for
138 * the next batch of vertices as well.
140 if (im
->Count
> IMM_MAXDATA
- 16) {
143 struct immediate
*new_im
= _tnl_alloc_immediate(ctx
);
146 im
->ref_count
--; /* remove CURRENT_IM reference */
147 ASSERT(im
->ref_count
> 0);
148 SET_IMMEDIATE( ctx
, new_im
);
149 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
,
150 new_beginstate
, node
->SavedBeginState
);
152 /* Still some room in the current immediate.
154 _tnl_reset_input( ctx
, im
->Count
+1+IMM_MAX_COPIED_VERTS
,
155 new_beginstate
, node
->SavedBeginState
);
161 execute_compiled_cassette( GLcontext
*ctx
, void *data
)
163 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
164 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
165 struct immediate
*IM
= node
->IM
;
168 gl_update_state(ctx
);
170 if (tnl
->pipeline
.build_state_changes
)
171 _tnl_validate_pipeline( ctx
);
173 IM
->Start
= node
->Start
;
174 IM
->CopyStart
= node
->Start
;
175 IM
->Count
= node
->Count
;
176 IM
->BeginState
= node
->BeginState
;
177 IM
->SavedBeginState
= node
->SavedBeginState
;
178 IM
->OrFlag
= node
->OrFlag
;
179 IM
->TexSize
= node
->TexSize
;
180 IM
->AndFlag
= node
->AndFlag
;
181 IM
->LastData
= node
->LastData
;
182 IM
->LastPrimitive
= node
->LastPrimitive
;
183 IM
->LastMaterial
= node
->LastMaterial
;
184 IM
->MaterialOrMask
= node
->MaterialOrMask
;
186 if ((MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) &&
187 (MESA_VERBOSE
& VERBOSE_IMMEDIATE
))
188 _tnl_print_cassette( IM
);
190 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) {
191 fprintf(stderr
, "Run cassette %d, rows %d..%d, beginstate %x ",
193 IM
->Start
, IM
->Count
, IM
->BeginState
);
194 _tnl_print_vert_flags("orflag", IM
->OrFlag
);
197 if (IM
->Count
== IM
->Start
) {
198 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
);
202 if (IM
->SavedBeginState
) {
203 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
204 tnl
->ReplayHardBeginEnd
= 1;
205 if (!tnl
->ReplayHardBeginEnd
) {
206 /* This is a user error. Whatever operation (like glRectf)
207 * decomposed to this hard begin/end pair is now being run
208 * inside a begin/end object -- illegally. Reject it and
211 gl_error(ctx
, GL_INVALID_OPERATION
, "hard replay");
216 _tnl_fixup_compiled_cassette( ctx
, IM
);
217 _tnl_get_exec_copy_verts( ctx
, IM
);
218 _tnl_run_cassette( ctx
, IM
);
219 _tnl_restore_compiled_cassette( ctx
, IM
);
221 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
222 tnl
->ReplayHardBeginEnd
= 0;
226 destroy_compiled_cassette( GLcontext
*ctx
, void *data
)
228 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
230 if ( --node
->IM
->ref_count
== 0 )
231 _tnl_free_immediate( node
->IM
);
236 print_compiled_cassette( GLcontext
*ctx
, void *data
)
238 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
239 struct immediate
*IM
= node
->IM
;
241 fprintf(stderr
, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
242 node
->IM
->id
, node
->Start
, node
->Count
);
244 IM
->Start
= node
->Start
;
245 IM
->Count
= node
->Count
;
246 IM
->BeginState
= node
->BeginState
;
247 IM
->OrFlag
= node
->OrFlag
;
248 IM
->TexSize
= node
->TexSize
;
249 IM
->AndFlag
= node
->AndFlag
;
250 IM
->LastData
= node
->LastData
;
251 IM
->LastPrimitive
= node
->LastPrimitive
;
252 IM
->LastMaterial
= node
->LastMaterial
;
253 IM
->MaterialOrMask
= node
->MaterialOrMask
;
255 _tnl_print_cassette( node
->IM
);
259 _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
263 FLUSH_CURRENT(ctx
, 0);
267 /* Called at the tail of a CallList. Copy vertices out of the display
271 _tnl_EndCallList( GLcontext
*ctx
)
273 /* May have to copy vertices from a dangling begin/end inside the
274 * list to the current immediate.
276 if (ctx
->CallDepth
== 0) {
277 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
278 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
280 if (tnl
->ExecCopySource
!= IM
)
281 _tnl_copy_immediate_vertices( ctx
, IM
);
287 _tnl_EndList( GLcontext
*ctx
)
289 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
290 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
294 if (IM
== tnl
->ExecCopySource
) {
297 if ( --tnl
->ExecCopySource
->ref_count
== 0 )
298 _tnl_free_immediate( tnl
->ExecCopySource
);
301 /* If this one isn't free, get a clean one. (Otherwise we'll be
302 * using one that's already half full).
304 if (IM
->ref_count
!= 0)
305 IM
= _tnl_alloc_immediate( ctx
);
307 ASSERT(IM
->ref_count
== 0);
309 tnl
->ExecCopySource
= IM
;
312 SET_IMMEDIATE( ctx
, IM
);
315 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
317 /* outside begin/end, even in COMPILE_AND_EXEC,
318 * so no vertices to copy, right?
320 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
325 _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
327 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
329 /* Use the installed immediate struct. No vertices in the current
330 * immediate, no copied vertices in the system.
332 ASSERT(TNL_CURRENT_IM(ctx
));
333 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== IMM_MAX_COPIED_VERTS
);
334 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== TNL_CURRENT_IM(ctx
)->Count
);
335 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
337 /* Set current Begin/End state to unknown:
339 IM
->BeginState
= VERT_BEGIN_0
;
340 ctx
->Driver
.CurrentSavePrimitive
= PRIM_UNKNOWN
;
345 _tnl_dlist_init( GLcontext
*ctx
)
347 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
349 tnl
->opcode_vertex_cassette
=
350 _mesa_alloc_opcode( ctx
,
351 sizeof(TNLvertexcassette
),
352 execute_compiled_cassette
,
353 destroy_compiled_cassette
,
354 print_compiled_cassette
);