1 /* $Id: t_imm_dlist.c,v 1.13 2001/04/26 14:53:48 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
);
68 /* Insert the active immediate struct onto the display list currently
72 _tnl_compile_cassette( GLcontext
*ctx
, struct immediate
*IM
)
74 struct immediate
*im
= TNL_CURRENT_IM(ctx
);
75 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
76 TNLvertexcassette
*node
;
77 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 /* _tnl_print_cassette( IM ); */
111 node
= (TNLvertexcassette
*)
112 _mesa_alloc_instruction(ctx
,
113 tnl
->opcode_vertex_cassette
,
114 sizeof(TNLvertexcassette
));
118 node
->IM
= im
; im
->ref_count
++;
119 node
->Start
= im
->Start
;
120 node
->Count
= im
->Count
;
121 node
->BeginState
= im
->BeginState
;
122 node
->SavedBeginState
= im
->SavedBeginState
;
123 node
->OrFlag
= im
->OrFlag
;
124 node
->TexSize
= im
->TexSize
;
125 node
->AndFlag
= im
->AndFlag
;
126 node
->LastData
= im
->LastData
;
127 node
->LastPrimitive
= im
->LastPrimitive
;
128 node
->LastMaterial
= im
->LastMaterial
;
129 node
->MaterialOrMask
= im
->MaterialOrMask
;
130 node
->MaterialAndMask
= im
->MaterialAndMask
;
132 if (ctx
->ExecuteFlag
) {
133 execute_compiled_cassette( ctx
, (void *)node
);
137 /* Discard any errors raised in the last cassette.
139 new_beginstate
= node
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
141 /* Decide whether this immediate struct is full, or can be used for
142 * the next batch of vertices as well.
144 if (im
->Count
> IMM_MAXDATA
- 16) {
147 struct immediate
*new_im
= _tnl_alloc_immediate(ctx
);
150 im
->ref_count
--; /* remove CURRENT_IM reference */
151 ASSERT(im
->ref_count
> 0);
152 SET_IMMEDIATE( ctx
, new_im
);
153 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
,
154 new_beginstate
, node
->SavedBeginState
);
156 /* Still some room in the current immediate.
158 _tnl_reset_input( ctx
, im
->Count
+1+IMM_MAX_COPIED_VERTS
,
159 new_beginstate
, node
->SavedBeginState
);
165 execute_compiled_cassette( GLcontext
*ctx
, void *data
)
167 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
168 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
169 struct immediate
*IM
= node
->IM
;
172 _mesa_update_state(ctx
);
174 if (tnl
->pipeline
.build_state_changes
)
175 _tnl_validate_pipeline( ctx
);
177 IM
->Start
= node
->Start
;
178 IM
->CopyStart
= node
->Start
;
179 IM
->Count
= node
->Count
;
180 IM
->BeginState
= node
->BeginState
;
181 IM
->SavedBeginState
= node
->SavedBeginState
;
182 IM
->OrFlag
= node
->OrFlag
;
183 IM
->TexSize
= node
->TexSize
;
184 IM
->AndFlag
= node
->AndFlag
;
185 IM
->LastData
= node
->LastData
;
186 IM
->LastPrimitive
= node
->LastPrimitive
;
187 IM
->LastMaterial
= node
->LastMaterial
;
188 IM
->MaterialOrMask
= node
->MaterialOrMask
;
189 IM
->MaterialAndMask
= node
->MaterialAndMask
;
191 if ((MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) &&
192 (MESA_VERBOSE
& VERBOSE_IMMEDIATE
))
193 _tnl_print_cassette( IM
);
195 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) {
196 fprintf(stderr
, "Run cassette %d, rows %d..%d, beginstate %x ",
198 IM
->Start
, IM
->Count
, IM
->BeginState
);
199 _tnl_print_vert_flags("orflag", IM
->OrFlag
);
202 if (IM
->Count
== IM
->Start
) {
203 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
);
207 if (IM
->SavedBeginState
) {
208 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
209 tnl
->ReplayHardBeginEnd
= 1;
210 if (!tnl
->ReplayHardBeginEnd
) {
211 /* This is a user error. Whatever operation (like glRectf)
212 * decomposed to this hard begin/end pair is now being run
213 * inside a begin/end object -- illegally. Reject it and
216 _mesa_error(ctx
, GL_INVALID_OPERATION
, "hard replay");
221 _tnl_fixup_compiled_cassette( ctx
, IM
);
222 _tnl_get_exec_copy_verts( ctx
, IM
);
223 _tnl_run_cassette( ctx
, IM
);
224 _tnl_restore_compiled_cassette( ctx
, IM
);
226 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
227 tnl
->ReplayHardBeginEnd
= 0;
231 destroy_compiled_cassette( GLcontext
*ctx
, void *data
)
233 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
235 if ( --node
->IM
->ref_count
== 0 )
236 _tnl_free_immediate( node
->IM
);
241 print_compiled_cassette( GLcontext
*ctx
, void *data
)
243 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
244 struct immediate
*IM
= node
->IM
;
246 fprintf(stderr
, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
247 node
->IM
->id
, node
->Start
, node
->Count
);
249 IM
->Start
= node
->Start
;
250 IM
->Count
= node
->Count
;
251 IM
->BeginState
= node
->BeginState
;
252 IM
->OrFlag
= node
->OrFlag
;
253 IM
->TexSize
= node
->TexSize
;
254 IM
->AndFlag
= node
->AndFlag
;
255 IM
->LastData
= node
->LastData
;
256 IM
->LastPrimitive
= node
->LastPrimitive
;
257 IM
->LastMaterial
= node
->LastMaterial
;
258 IM
->MaterialOrMask
= node
->MaterialOrMask
;
259 IM
->MaterialAndMask
= node
->MaterialAndMask
;
261 _tnl_print_cassette( node
->IM
);
265 _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
269 FLUSH_CURRENT(ctx
, 0);
273 /* Called at the tail of a CallList. Copy vertices out of the display
277 _tnl_EndCallList( GLcontext
*ctx
)
279 /* May have to copy vertices from a dangling begin/end inside the
280 * list to the current immediate.
282 if (ctx
->CallDepth
== 0) {
283 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
284 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
286 if (tnl
->ExecCopySource
!= IM
)
287 _tnl_copy_immediate_vertices( ctx
, IM
);
293 _tnl_EndList( GLcontext
*ctx
)
295 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
296 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
298 /* fprintf(stderr, "%s\n", __FUNCTION__); */
302 if (IM
== tnl
->ExecCopySource
) {
305 if ( --tnl
->ExecCopySource
->ref_count
== 0 )
306 _tnl_free_immediate( tnl
->ExecCopySource
);
309 /* If this one isn't free, get a clean one. (Otherwise we'll be
310 * using one that's already half full).
312 if (IM
->ref_count
!= 0)
313 IM
= _tnl_alloc_immediate( ctx
);
315 ASSERT(IM
->ref_count
== 0);
317 tnl
->ExecCopySource
= IM
;
320 SET_IMMEDIATE( ctx
, IM
);
323 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
325 /* outside begin/end, even in COMPILE_AND_EXEC,
326 * so no vertices to copy, right?
328 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
333 _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
335 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
337 /* Use the installed immediate struct. No vertices in the current
338 * immediate, no copied vertices in the system.
340 ASSERT(TNL_CURRENT_IM(ctx
));
341 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== IMM_MAX_COPIED_VERTS
);
342 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== TNL_CURRENT_IM(ctx
)->Count
);
343 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
345 /* Set current Begin/End state to unknown:
347 IM
->BeginState
= VERT_BEGIN_0
;
348 ctx
->Driver
.CurrentSavePrimitive
= PRIM_UNKNOWN
;
353 _tnl_dlist_init( GLcontext
*ctx
)
355 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
357 tnl
->opcode_vertex_cassette
=
358 _mesa_alloc_opcode( ctx
,
359 sizeof(TNLvertexcassette
),
360 execute_compiled_cassette
,
361 destroy_compiled_cassette
,
362 print_compiled_cassette
);