fix sproingies bug
[mesa.git] / src / mesa / tnl / t_imm_dlist.c
1 /* $Id: t_imm_dlist.c,v 1.3 2000/12/27 21:49:40 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999 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 * Author:
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 GLboolean have_normal_lengths;
61 } TNLvertexcassette;
62
63 static void execute_compiled_cassette( GLcontext *ctx, void *data );
64
65
66 /* Insert the active immediate struct onto the display list currently
67 * being built.
68 */
69 void
70 _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
71 {
72 struct immediate *im = TNL_CURRENT_IM(ctx);
73 TNLcontext *tnl = TNL_CONTEXT(ctx);
74 TNLvertexcassette *node;
75 GLuint new_beginstate;
76
77
78 _tnl_compute_orflag( IM );
79
80 IM->CopyStart = IM->Start;
81
82 if (IM->OrFlag & VERT_ELT) {
83 GLuint andflag = ~0;
84 GLuint i;
85 GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
86 _tnl_translate_array_elts( ctx, IM, start, IM->Count );
87
88 /* Need to recompute andflag.
89 */
90 if (IM->AndFlag & VERT_ELT)
91 IM->CopyAndFlag = IM->AndFlag |= ctx->Array._Enabled;
92 else {
93 for (i = IM->CopyStart ; i < IM->Count ; i++)
94 andflag &= IM->Flag[i];
95 IM->CopyAndFlag = IM->AndFlag = andflag;
96 }
97 }
98
99 _tnl_fixup_input( ctx, IM );
100
101 /* Mark the last primitive:
102 */
103 IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
104 ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
105
106
107 node = (TNLvertexcassette *)
108 _mesa_alloc_instruction(ctx,
109 tnl->opcode_vertex_cassette,
110 sizeof(TNLvertexcassette));
111 if (!node)
112 return;
113
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;
125
126 if (ctx->ExecuteFlag) {
127 execute_compiled_cassette( ctx, (void *)node );
128 }
129
130
131 /* Discard any errors raised in the last cassette.
132 */
133 new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
134
135 /* Decide whether this immediate struct is full, or can be used for
136 * the next batch of vertices as well.
137 */
138 if (im->Count > IMM_MAXDATA - 16) {
139 /* Call it full...
140 */
141 struct immediate *new_im = _tnl_alloc_immediate(ctx);
142 if (!new_im) return;
143 new_im->ref_count++;
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 );
149 } else {
150 /* Still some room in the current immediate.
151 */
152 _tnl_reset_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
153 new_beginstate, node->SavedBeginState);
154 }
155 }
156
157
158
159 static void calc_normal_lengths( GLfloat *dest,
160 CONST GLfloat (*data)[3],
161 GLuint *flags,
162 GLuint count )
163 {
164 GLuint i;
165 GLint tmpflag = flags[0];
166
167 flags[0] |= VERT_NORM;
168
169 for (i = 0 ; i < count ; i++ )
170 if (flags[i] & VERT_NORM) {
171 GLfloat tmp = (GLfloat) LEN_3FV( data[i] );
172 dest[i] = 0;
173 if (tmp > 0)
174 dest[i] = 1.0F / tmp;
175 } else
176 dest[i] = dest[i-1];
177
178 flags[0] = tmpflag;
179 }
180
181
182
183 static void
184 execute_compiled_cassette( GLcontext *ctx, void *data )
185 {
186 TNLcontext *tnl = TNL_CONTEXT(ctx);
187 TNLvertexcassette *node = (TNLvertexcassette *)data;
188 struct immediate *IM = node->IM;
189
190 if (ctx->NewState)
191 gl_update_state(ctx);
192
193 if (tnl->pipeline.build_state_changes)
194 _tnl_validate_pipeline( ctx );
195
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;
206
207 if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
208 (MESA_VERBOSE & VERBOSE_IMMEDIATE))
209 _tnl_print_cassette( IM );
210
211 if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
212 fprintf(stderr, "Run cassette %d, rows %d..%d, beginstate %x ",
213 IM->id,
214 IM->Start, IM->Count, IM->BeginState);
215 _tnl_print_vert_flags("orflag", IM->OrFlag);
216 }
217
218 if (IM->Count == IM->Start) {
219 _tnl_run_empty_cassette( ctx, IM );
220 return;
221 }
222
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");
228 return;
229 }
230 }
231
232
233 /* Lazy optimization of the cassette.
234 */
235 /* if (ctx->Transform.Normalize && !node->have_normal_lengths) { */
236
237 /* if (!IM->NormalLengths) */
238 /* IM->NormalLengths = (GLfloat *)MALLOC(sizeof(GLfloat) * IMM_SIZE); */
239
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); */
244
245 /* node->have_normal_lengths = GL_TRUE; */
246 /* } */
247
248
249 #if 0
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 );
253 }
254 #endif
255
256
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 );
261
262 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
263 tnl->ReplayHardBeginEnd = 0;
264 }
265
266 static void
267 destroy_compiled_cassette( GLcontext *ctx, void *data )
268 {
269 TNLvertexcassette *node = (TNLvertexcassette *)data;
270
271 if ( --node->IM->ref_count == 0 )
272 _tnl_free_immediate( node->IM );
273 }
274
275
276 static void
277 print_compiled_cassette( GLcontext *ctx, void *data )
278 {
279 TNLvertexcassette *node = (TNLvertexcassette *)data;
280 struct immediate *IM = node->IM;
281
282 fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
283 node->IM->id, node->Start, node->Count);
284
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;
293
294 _tnl_print_cassette( node->IM );
295 }
296
297 void
298 _tnl_BeginCallList( GLcontext *ctx, GLuint list )
299 {
300 (void) ctx;
301 (void) list;
302 FLUSH_CURRENT(ctx, 0);
303 }
304
305
306 /* Called at the tail of a CallList. Copy vertices out of the display
307 * list if necessary.
308 */
309 void
310 _tnl_EndCallList( GLcontext *ctx )
311 {
312 /* May have to copy vertices from a dangling begin/end inside the
313 * list to the current immediate.
314 */
315 if (ctx->CallDepth == 0) {
316 TNLcontext *tnl = TNL_CONTEXT(ctx);
317 struct immediate *IM = TNL_CURRENT_IM(ctx);
318
319 if (tnl->ExecCopySource != IM)
320 _tnl_copy_immediate_vertices( ctx, IM );
321 }
322 }
323
324
325 void
326 _tnl_EndList( GLcontext *ctx )
327 {
328 TNLcontext *tnl = TNL_CONTEXT(ctx);
329 struct immediate *IM = TNL_CURRENT_IM(ctx);
330
331 IM->ref_count--;
332 if (IM == tnl->ExecCopySource)
333 IM->ref_count--;
334
335 /* If this one isn't free, get a clean one. (Otherwise we'll be
336 * using one that's already half full).
337 */
338 if (IM->ref_count != 0)
339 IM = _tnl_alloc_immediate( ctx );
340
341 ASSERT(IM->ref_count == 0);
342
343 tnl->ExecCopySource = IM;
344 IM->ref_count++;
345
346 SET_IMMEDIATE( ctx, IM );
347 IM->ref_count++;
348
349 _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
350
351 /* outside begin/end, even in COMPILE_AND_EXEC,
352 * so no vertices to copy, right?
353 */
354 ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
355 }
356
357
358 void
359 _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
360 {
361 struct immediate *IM = TNL_CURRENT_IM(ctx);
362
363 /* Use the installed immediate struct. No vertices in the current
364 * immediate, no copied vertices in the system.
365 */
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);
370
371 /* Set current Begin/End state to unknown:
372 */
373 IM->BeginState = VERT_BEGIN_0;
374 ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
375 }
376
377
378 void
379 _tnl_dlist_init( GLcontext *ctx )
380 {
381 TNLcontext *tnl = TNL_CONTEXT(ctx);
382
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 );
389 }
390
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.
394 */
395 void
396 _tnl_save_Begin( GLenum mode )
397 {
398 GET_CURRENT_CONTEXT(ctx);
399
400 if (mode > GL_POLYGON) {
401 _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" );
402 return;
403 }
404
405 if (ctx->ExecuteFlag) {
406 /* Preserve vtxfmt invarient:
407 */
408 if (ctx->NewState)
409 gl_update_state( ctx );
410
411 /* Slot in geomexec: No need to call setdispatch as we know
412 * CurrentDispatch is Save.
413 */
414 ASSERT(ctx->CurrentDispatch == ctx->Save);
415 }
416
417 _tnl_begin( ctx, mode );
418 }