1 /* $Id: t_imm_dlist.c,v 1.3 2000/12/27 21:49:40 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
;
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
);
159 static void calc_normal_lengths( GLfloat
*dest
,
160 CONST
GLfloat (*data
)[3],
165 GLint tmpflag
= flags
[0];
167 flags
[0] |= VERT_NORM
;
169 for (i
= 0 ; i
< count
; i
++ )
170 if (flags
[i
] & VERT_NORM
) {
171 GLfloat tmp
= (GLfloat
) LEN_3FV( data
[i
] );
174 dest
[i
] = 1.0F
/ tmp
;
184 execute_compiled_cassette( GLcontext
*ctx
, void *data
)
186 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
187 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
188 struct immediate
*IM
= node
->IM
;
191 gl_update_state(ctx
);
193 if (tnl
->pipeline
.build_state_changes
)
194 _tnl_validate_pipeline( ctx
);
196 IM
->Start
= node
->Start
;
197 IM
->CopyStart
= node
->Start
;
198 IM
->Count
= node
->Count
;
199 IM
->BeginState
= node
->BeginState
;
200 IM
->SavedBeginState
= node
->SavedBeginState
;
201 IM
->OrFlag
= node
->OrFlag
;
202 IM
->TexSize
= node
->TexSize
;
203 IM
->AndFlag
= node
->AndFlag
;
204 IM
->LastData
= node
->LastData
;
205 IM
->LastPrimitive
= node
->LastPrimitive
;
207 if ((MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) &&
208 (MESA_VERBOSE
& VERBOSE_IMMEDIATE
))
209 _tnl_print_cassette( IM
);
211 if (MESA_VERBOSE
& VERBOSE_DISPLAY_LIST
) {
212 fprintf(stderr
, "Run cassette %d, rows %d..%d, beginstate %x ",
214 IM
->Start
, IM
->Count
, IM
->BeginState
);
215 _tnl_print_vert_flags("orflag", IM
->OrFlag
);
218 if (IM
->Count
== IM
->Start
) {
219 _tnl_run_empty_cassette( ctx
, IM
);
223 if (IM
->SavedBeginState
) {
224 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
225 tnl
->ReplayHardBeginEnd
= 1;
226 if (!tnl
->ReplayHardBeginEnd
) {
227 gl_error(ctx
, GL_INVALID_OPERATION
, "hard replay");
233 /* Lazy optimization of the cassette.
235 /* if (ctx->Transform.Normalize && !node->have_normal_lengths) { */
237 /* if (!IM->NormalLengths) */
238 /* IM->NormalLengths = (GLfloat *)MALLOC(sizeof(GLfloat) * IMM_SIZE); */
240 /* calc_normal_lengths( IM->NormalLengths + IM->Start, */
241 /* (const GLfloat (*)[3])(IM->Normal + IM->Start), */
242 /* IM->Flag + IM->Start, */
243 /* IM->Count - IM->Start); */
245 /* node->have_normal_lengths = GL_TRUE; */
250 if (0 && im
->v
.Obj
.size
< 4 && im
->Count
> 15) {
251 im
->Bounds
= (GLfloat (*)[3]) MALLOC(6 * sizeof(GLfloat
));
252 (_tnl_calc_bound_tab
[im
->v
.Obj
.size
])( im
->Bounds
, &im
->v
.Obj
);
257 _tnl_fixup_compiled_cassette( ctx
, IM
);
258 _tnl_get_exec_copy_verts( ctx
, IM
);
259 _tnl_run_cassette( ctx
, IM
);
260 _tnl_restore_compiled_cassette( ctx
, IM
);
262 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
263 tnl
->ReplayHardBeginEnd
= 0;
267 destroy_compiled_cassette( GLcontext
*ctx
, void *data
)
269 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
271 if ( --node
->IM
->ref_count
== 0 )
272 _tnl_free_immediate( node
->IM
);
277 print_compiled_cassette( GLcontext
*ctx
, void *data
)
279 TNLvertexcassette
*node
= (TNLvertexcassette
*)data
;
280 struct immediate
*IM
= node
->IM
;
282 fprintf(stderr
, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
283 node
->IM
->id
, node
->Start
, node
->Count
);
285 IM
->Start
= node
->Start
;
286 IM
->Count
= node
->Count
;
287 IM
->BeginState
= node
->BeginState
;
288 IM
->OrFlag
= node
->OrFlag
;
289 IM
->TexSize
= node
->TexSize
;
290 IM
->AndFlag
= node
->AndFlag
;
291 IM
->LastData
= node
->LastData
;
292 IM
->LastPrimitive
= node
->LastPrimitive
;
294 _tnl_print_cassette( node
->IM
);
298 _tnl_BeginCallList( GLcontext
*ctx
, GLuint list
)
302 FLUSH_CURRENT(ctx
, 0);
306 /* Called at the tail of a CallList. Copy vertices out of the display
310 _tnl_EndCallList( GLcontext
*ctx
)
312 /* May have to copy vertices from a dangling begin/end inside the
313 * list to the current immediate.
315 if (ctx
->CallDepth
== 0) {
316 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
317 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
319 if (tnl
->ExecCopySource
!= IM
)
320 _tnl_copy_immediate_vertices( ctx
, IM
);
326 _tnl_EndList( GLcontext
*ctx
)
328 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
329 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
332 if (IM
== tnl
->ExecCopySource
)
335 /* If this one isn't free, get a clean one. (Otherwise we'll be
336 * using one that's already half full).
338 if (IM
->ref_count
!= 0)
339 IM
= _tnl_alloc_immediate( ctx
);
341 ASSERT(IM
->ref_count
== 0);
343 tnl
->ExecCopySource
= IM
;
346 SET_IMMEDIATE( ctx
, IM
);
349 _tnl_reset_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
351 /* outside begin/end, even in COMPILE_AND_EXEC,
352 * so no vertices to copy, right?
354 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
359 _tnl_NewList( GLcontext
*ctx
, GLuint list
, GLenum mode
)
361 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
363 /* Use the installed immediate struct. No vertices in the current
364 * immediate, no copied vertices in the system.
366 ASSERT(TNL_CURRENT_IM(ctx
));
367 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== IMM_MAX_COPIED_VERTS
);
368 ASSERT(TNL_CURRENT_IM(ctx
)->Start
== TNL_CURRENT_IM(ctx
)->Count
);
369 ASSERT(TNL_CONTEXT(ctx
)->ExecCopyCount
== 0);
371 /* Set current Begin/End state to unknown:
373 IM
->BeginState
= VERT_BEGIN_0
;
374 ctx
->Driver
.CurrentSavePrimitive
= PRIM_UNKNOWN
;
379 _tnl_dlist_init( GLcontext
*ctx
)
381 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
383 tnl
->opcode_vertex_cassette
=
384 _mesa_alloc_opcode( ctx
,
385 sizeof(TNLvertexcassette
),
386 execute_compiled_cassette
,
387 destroy_compiled_cassette
,
388 print_compiled_cassette
);
391 /* Need to do this to get the correct begin/end error behaviour from
392 * functions like ColorPointerEXT which are still active in
393 * SAVE_AND_EXEC modes.
396 _tnl_save_Begin( GLenum mode
)
398 GET_CURRENT_CONTEXT(ctx
);
400 if (mode
> GL_POLYGON
) {
401 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "glBegin" );
405 if (ctx
->ExecuteFlag
) {
406 /* Preserve vtxfmt invarient:
409 gl_update_state( ctx
);
411 /* Slot in geomexec: No need to call setdispatch as we know
412 * CurrentDispatch is Save.
414 ASSERT(ctx
->CurrentDispatch
== ctx
->Save
);
417 _tnl_begin( ctx
, mode
);