54f7132e0ea01447145db43c674f4094991ded97
[mesa.git] / src / mesa / tnl / t_imm_dlist.c
1 /* $Id: t_imm_dlist.c,v 1.13 2001/04/26 14:53:48 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
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.
25 *
26 * Authors:
27 * Keith Whitwell <keithw@valinux.com>
28 */
29
30
31 #include "glheader.h"
32 #include "context.h"
33 #include "dlist.h"
34 #include "debug.h"
35 #include "mmath.h"
36 #include "mem.h"
37 #include "state.h"
38
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"
48
49 typedef struct {
50 struct immediate *IM;
51 GLuint Start;
52 GLuint Count;
53 GLuint BeginState;
54 GLuint SavedBeginState;
55 GLuint OrFlag;
56 GLuint AndFlag;
57 GLuint TexSize;
58 GLuint LastData;
59 GLuint LastPrimitive;
60 GLuint LastMaterial;
61 GLuint MaterialOrMask;
62 GLuint MaterialAndMask;
63 } TNLvertexcassette;
64
65 static void execute_compiled_cassette( GLcontext *ctx, void *data );
66
67
68 /* Insert the active immediate struct onto the display list currently
69 * being built.
70 */
71 void
72 _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
73 {
74 struct immediate *im = TNL_CURRENT_IM(ctx);
75 TNLcontext *tnl = TNL_CONTEXT(ctx);
76 TNLvertexcassette *node;
77 GLuint new_beginstate;
78
79 _tnl_compute_orflag( IM );
80
81 IM->CopyStart = IM->Start;
82
83 if (IM->OrFlag & VERT_ELT) {
84 GLuint andflag = ~0;
85 GLuint i;
86 GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
87 _tnl_translate_array_elts( ctx, IM, start, IM->Count );
88
89 /* Need to recompute andflag.
90 */
91 if (IM->AndFlag & VERT_ELT)
92 IM->CopyAndFlag = IM->AndFlag |= ctx->Array._Enabled;
93 else {
94 for (i = IM->CopyStart ; i < IM->Count ; i++)
95 andflag &= IM->Flag[i];
96 IM->CopyAndFlag = IM->AndFlag = andflag;
97 }
98 }
99
100 _tnl_fixup_input( ctx, IM );
101
102 /* Mark the last primitive:
103 */
104 IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
105 ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
106
107
108 /* _tnl_print_cassette( IM ); */
109
110
111 node = (TNLvertexcassette *)
112 _mesa_alloc_instruction(ctx,
113 tnl->opcode_vertex_cassette,
114 sizeof(TNLvertexcassette));
115 if (!node)
116 return;
117
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;
131
132 if (ctx->ExecuteFlag) {
133 execute_compiled_cassette( ctx, (void *)node );
134 }
135
136
137 /* Discard any errors raised in the last cassette.
138 */
139 new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
140
141 /* Decide whether this immediate struct is full, or can be used for
142 * the next batch of vertices as well.
143 */
144 if (im->Count > IMM_MAXDATA - 16) {
145 /* Call it full...
146 */
147 struct immediate *new_im = _tnl_alloc_immediate(ctx);
148 if (!new_im) return;
149 new_im->ref_count++;
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 );
155 } else {
156 /* Still some room in the current immediate.
157 */
158 _tnl_reset_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
159 new_beginstate, node->SavedBeginState);
160 }
161 }
162
163
164 static void
165 execute_compiled_cassette( GLcontext *ctx, void *data )
166 {
167 TNLcontext *tnl = TNL_CONTEXT(ctx);
168 TNLvertexcassette *node = (TNLvertexcassette *)data;
169 struct immediate *IM = node->IM;
170
171 if (ctx->NewState)
172 _mesa_update_state(ctx);
173
174 if (tnl->pipeline.build_state_changes)
175 _tnl_validate_pipeline( ctx );
176
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;
190
191 if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
192 (MESA_VERBOSE & VERBOSE_IMMEDIATE))
193 _tnl_print_cassette( IM );
194
195 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
196 fprintf(stderr, "Run cassette %d, rows %d..%d, beginstate %x ",
197 IM->id,
198 IM->Start, IM->Count, IM->BeginState);
199 _tnl_print_vert_flags("orflag", IM->OrFlag);
200 }
201
202 if (IM->Count == IM->Start) {
203 _tnl_copy_to_current( ctx, IM, IM->OrFlag );
204 return;
205 }
206
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
214 * raise an error.
215 */
216 _mesa_error(ctx, GL_INVALID_OPERATION, "hard replay");
217 return;
218 }
219 }
220
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 );
225
226 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
227 tnl->ReplayHardBeginEnd = 0;
228 }
229
230 static void
231 destroy_compiled_cassette( GLcontext *ctx, void *data )
232 {
233 TNLvertexcassette *node = (TNLvertexcassette *)data;
234
235 if ( --node->IM->ref_count == 0 )
236 _tnl_free_immediate( node->IM );
237 }
238
239
240 static void
241 print_compiled_cassette( GLcontext *ctx, void *data )
242 {
243 TNLvertexcassette *node = (TNLvertexcassette *)data;
244 struct immediate *IM = node->IM;
245
246 fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
247 node->IM->id, node->Start, node->Count);
248
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;
260
261 _tnl_print_cassette( node->IM );
262 }
263
264 void
265 _tnl_BeginCallList( GLcontext *ctx, GLuint list )
266 {
267 (void) ctx;
268 (void) list;
269 FLUSH_CURRENT(ctx, 0);
270 }
271
272
273 /* Called at the tail of a CallList. Copy vertices out of the display
274 * list if necessary.
275 */
276 void
277 _tnl_EndCallList( GLcontext *ctx )
278 {
279 /* May have to copy vertices from a dangling begin/end inside the
280 * list to the current immediate.
281 */
282 if (ctx->CallDepth == 0) {
283 TNLcontext *tnl = TNL_CONTEXT(ctx);
284 struct immediate *IM = TNL_CURRENT_IM(ctx);
285
286 if (tnl->ExecCopySource != IM)
287 _tnl_copy_immediate_vertices( ctx, IM );
288 }
289 }
290
291
292 void
293 _tnl_EndList( GLcontext *ctx )
294 {
295 TNLcontext *tnl = TNL_CONTEXT(ctx);
296 struct immediate *IM = TNL_CURRENT_IM(ctx);
297
298 /* fprintf(stderr, "%s\n", __FUNCTION__); */
299
300 ctx->swtnl_im = 0;
301 IM->ref_count--;
302 if (IM == tnl->ExecCopySource) {
303 IM->ref_count--;
304 } else {
305 if ( --tnl->ExecCopySource->ref_count == 0 )
306 _tnl_free_immediate( tnl->ExecCopySource );
307 }
308
309 /* If this one isn't free, get a clean one. (Otherwise we'll be
310 * using one that's already half full).
311 */
312 if (IM->ref_count != 0)
313 IM = _tnl_alloc_immediate( ctx );
314
315 ASSERT(IM->ref_count == 0);
316
317 tnl->ExecCopySource = IM;
318 IM->ref_count++;
319
320 SET_IMMEDIATE( ctx, IM );
321 IM->ref_count++;
322
323 _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
324
325 /* outside begin/end, even in COMPILE_AND_EXEC,
326 * so no vertices to copy, right?
327 */
328 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
329 }
330
331
332 void
333 _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
334 {
335 struct immediate *IM = TNL_CURRENT_IM(ctx);
336
337 /* Use the installed immediate struct. No vertices in the current
338 * immediate, no copied vertices in the system.
339 */
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);
344
345 /* Set current Begin/End state to unknown:
346 */
347 IM->BeginState = VERT_BEGIN_0;
348 ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
349 }
350
351
352 void
353 _tnl_dlist_init( GLcontext *ctx )
354 {
355 TNLcontext *tnl = TNL_CONTEXT(ctx);
356
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 );
363 }