fix for moebius infinite loop
[mesa.git] / src / mesa / tnl / t_imm_exec.c
1 /* $Id: t_imm_exec.c,v 1.21 2001/05/03 16:49:27 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 "colormac.h"
33 #include "context.h"
34 #include "enums.h"
35 #include "dlist.h"
36 #include "macros.h"
37 #include "mem.h"
38 #include "mmath.h"
39 #include "light.h"
40 #include "state.h"
41 #include "mtypes.h"
42
43 #include "math/m_matrix.h"
44 #include "math/m_xform.h"
45
46 #include "t_context.h"
47 #include "t_array_import.h"
48 #include "t_imm_alloc.h"
49 #include "t_imm_api.h"
50 #include "t_imm_debug.h"
51 #include "t_imm_dlist.h"
52 #include "t_imm_eval.h"
53 #include "t_imm_elt.h"
54 #include "t_imm_exec.h"
55 #include "t_imm_fixup.h"
56 #include "t_pipeline.h"
57
58
59
60 static void reset_input( GLcontext *ctx,
61 GLuint start,
62 GLuint beginstate,
63 GLuint savedbeginstate )
64 {
65 struct immediate *IM = TNL_CURRENT_IM(ctx);
66
67 /* Clear the dirty part of the flag array.
68 */
69 if (start < IM->Count+2)
70 MEMSET(IM->Flag + start, 0, sizeof(GLuint) * (IM->Count+2-start));
71
72 IM->Start = start;
73 IM->Count = start;
74 IM->LastMaterial = start;
75 IM->BeginState = beginstate;
76 IM->SavedBeginState = savedbeginstate;
77 IM->TexSize = 0;
78 IM->MaterialOrMask = 0;
79
80 if (IM->MaterialMask)
81 IM->MaterialMask[IM->Start] = 0;
82
83 IM->ArrayEltFlags = ~ctx->Array._Enabled;
84 IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0;
85 IM->ArrayEltFlush = !ctx->Array.LockCount;
86 }
87
88 void _tnl_reset_exec_input( GLcontext *ctx,
89 GLuint start,
90 GLuint beginstate,
91 GLuint savedbeginstate )
92 {
93 TNLcontext *tnl = TNL_CONTEXT(ctx);
94 struct immediate *IM = TNL_CURRENT_IM(ctx);
95
96 reset_input( ctx, start, beginstate, savedbeginstate );
97
98 IM->CopyStart = start - tnl->ExecCopyCount;
99 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
100 if (tnl->ExecParity)
101 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
102
103 IM->LastPrimitive = IM->CopyStart;
104 }
105
106
107 void _tnl_reset_compile_input( GLcontext *ctx,
108 GLuint start,
109 GLuint beginstate,
110 GLuint savedbeginstate )
111 {
112 struct immediate *IM = TNL_CURRENT_IM(ctx);
113
114 reset_input( ctx, start, beginstate, savedbeginstate );
115 IM->CopyStart = start;
116 IM->LastPrimitive = IM->Start;
117 }
118
119
120
121
122
123
124 void _tnl_copy_to_current( GLcontext *ctx, struct immediate *IM,
125 GLuint flag )
126 {
127 GLuint count = IM->LastData;
128
129 if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
130 _tnl_print_vert_flags("copy to current", flag);
131
132 if (flag & VERT_NORM)
133 COPY_3FV( ctx->Current.Normal, IM->Normal[count]);
134
135 if (flag & VERT_INDEX)
136 ctx->Current.Index = IM->Index[count];
137
138 if (flag & VERT_EDGE)
139 ctx->Current.EdgeFlag = IM->EdgeFlag[count];
140
141 if (flag & VERT_RGBA) {
142 COPY_4FV(ctx->Current.Color, IM->Color[count]);
143 if (ctx->Light.ColorMaterialEnabled) {
144 _mesa_update_color_material( ctx, ctx->Current.Color );
145 _mesa_validate_all_lighting_tables( ctx );
146 }
147 }
148
149 if (flag & VERT_SPEC_RGB)
150 COPY_4FV(ctx->Current.SecondaryColor, IM->SecondaryColor[count]);
151
152 if (flag & VERT_FOG_COORD)
153 ctx->Current.FogCoord = IM->FogCoord[count];
154
155 if (flag & VERT_TEX_ANY) {
156 GLuint i;
157 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
158 if (flag & VERT_TEX(i)) {
159 COPY_4FV( ctx->Current.Texcoord[0], IM->TexCoord[0][count]);
160 }
161 }
162 }
163
164 if (flag & VERT_MATERIAL) {
165 _mesa_update_material( ctx,
166 IM->Material[IM->LastMaterial],
167 IM->MaterialOrMask );
168
169 _mesa_validate_all_lighting_tables( ctx );
170 }
171 }
172
173
174
175 void _tnl_compute_orflag( struct immediate *IM )
176 {
177 GLuint count = IM->Count;
178 GLuint orflag = 0;
179 GLuint andflag = ~0U;
180 GLuint i;
181
182 IM->LastData = count-1;
183
184
185 /* Compute the flags for the whole buffer.
186 */
187 for (i = IM->CopyStart ; i < count ; i++) {
188 andflag &= IM->Flag[i];
189 orflag |= IM->Flag[i];
190 }
191
192 /* It is possible there will be data in the buffer arising from
193 * calls like 'glNormal', 'glMaterial' that occur after the final
194 * glVertex, glEval, etc. Additionally, a buffer can consist of
195 * eg. a single glMaterial call, in which case IM->Start ==
196 * IM->Count, but the buffer is definitely not empty.
197 */
198 if (IM->Flag[i] & VERT_DATA) {
199 IM->LastData++;
200 orflag |= IM->Flag[i];
201 }
202
203 IM->Flag[IM->LastData+1] |= VERT_END_VB;
204 IM->CopyAndFlag = IM->AndFlag = andflag;
205 IM->CopyOrFlag = IM->OrFlag = orflag;
206 }
207
208
209
210
211
212
213
214
215 /* Note: The 'start' member of the GLvector structs is now redundant
216 * because we always re-transform copied vertices, and the vectors
217 * below are set up so that the first copied vertex (if any) appears
218 * at position zero.
219 */
220 static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM )
221 {
222 TNLcontext *tnl = TNL_CONTEXT(ctx);
223 struct vertex_buffer *VB = &tnl->vb;
224 struct vertex_arrays *tmp = &tnl->imm_inputs;
225 GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */
226 GLuint start = IM->CopyStart;
227 GLuint count = IM->Count - start;
228
229 /* TODO: optimize the case where nothing has changed. (Just bind
230 * tmp to vb).
231 */
232
233 /* Setup constant data in the VB.
234 */
235 VB->Count = count;
236 VB->FirstClipped = IMM_MAXDATA - IM->CopyStart;
237 VB->import_data = 0;
238 VB->importable_data = 0;
239
240 /* Need an IM->FirstPrimitive?
241 */
242 VB->Primitive = IM->Primitive + IM->CopyStart;
243 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
244 VB->FirstPrimitive = 0;
245
246 VB->Flag = IM->Flag + start;
247
248 /* TexCoordPtr's are zeroed in loop below.
249 */
250 VB->NormalPtr = 0;
251 VB->FogCoordPtr = 0;
252 VB->EdgeFlag = 0;
253 VB->IndexPtr[0] = 0;
254 VB->IndexPtr[1] = 0;
255 VB->ColorPtr[0] = 0;
256 VB->ColorPtr[1] = 0;
257 VB->SecondaryColorPtr[0] = 0;
258 VB->SecondaryColorPtr[1] = 0;
259 VB->Elts = 0;
260 VB->MaterialMask = 0;
261 VB->Material = 0;
262
263 /* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
264 /* _tnl_print_vert_flags("orflag", IM->OrFlag); */
265 /* _tnl_print_vert_flags("inputs", inputs); */
266
267 /* Setup the initial values of array pointers in the vb.
268 */
269 if (inputs & VERT_OBJ) {
270 tmp->Obj.data = IM->Obj + start;
271 tmp->Obj.start = (GLfloat *)(IM->Obj + start);
272 tmp->Obj.count = count;
273 VB->ObjPtr = &tmp->Obj;
274 if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_234)
275 tmp->Obj.size = 4;
276 else if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_23)
277 tmp->Obj.size = 3;
278 else
279 tmp->Obj.size = 2;
280 }
281
282 if (inputs & VERT_NORM) {
283 tmp->Normal.data = IM->Normal + start;
284 tmp->Normal.start = (GLfloat *)(IM->Normal + start);
285 tmp->Normal.count = count;
286 VB->NormalPtr = &tmp->Normal;
287 }
288
289 if (inputs & VERT_INDEX) {
290 tmp->Index.count = count;
291 tmp->Index.data = IM->Index + start;
292 tmp->Index.start = IM->Index + start;
293 VB->IndexPtr[0] = &tmp->Index;
294 }
295
296 if (inputs & VERT_FOG_COORD) {
297 tmp->FogCoord.data = IM->FogCoord + start;
298 tmp->FogCoord.start = IM->FogCoord + start;
299 tmp->FogCoord.count = count;
300 VB->FogCoordPtr = &tmp->FogCoord;
301 }
302
303 if (inputs & VERT_SPEC_RGB) {
304 tmp->SecondaryColor.Ptr = IM->SecondaryColor + start;
305 VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
306 }
307
308 if (inputs & VERT_EDGE) {
309 VB->EdgeFlag = IM->EdgeFlag + start;
310 }
311
312 if (inputs & VERT_RGBA) {
313 if (IM->CopyOrFlag & VERT_RGBA) {
314 tmp->Color.Ptr = IM->Color + start;
315 tmp->Color.StrideB = 4 * sizeof(GLfloat);
316 tmp->Color.Flags = 0;
317 } else {
318 tmp->Color.Ptr = ctx->Current.Color;
319 tmp->Color.StrideB = 0;
320 tmp->Color.Flags = CA_CLIENT_DATA; /* hack */
321 VB->importable_data |= VERT_RGBA;
322 VB->import_data = _tnl_upgrade_current_data;
323 }
324 VB->ColorPtr[0] = &tmp->Color;
325 }
326
327 if (inputs & VERT_TEX_ANY) {
328 GLuint i;
329 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
330 VB->TexCoordPtr[i] = 0;
331 if (inputs & VERT_TEX(i)) {
332 tmp->TexCoord[i].count = count;
333 tmp->TexCoord[i].data = IM->TexCoord[i] + start;
334 tmp->TexCoord[i].start = (GLfloat *)(IM->TexCoord[i] + start);
335 tmp->TexCoord[i].size = 2;
336 if (IM->TexSize & TEX_SIZE_3(i)) {
337 tmp->TexCoord[i].size = 3;
338 if (IM->TexSize & TEX_SIZE_4(i))
339 tmp->TexCoord[i].size = 4;
340 }
341 VB->TexCoordPtr[i] = &tmp->TexCoord[i];
342 }
343 }
344 }
345
346 if ((inputs & VERT_MATERIAL) && IM->Material) {
347 VB->MaterialMask = IM->MaterialMask + start;
348 VB->Material = IM->Material + start;
349 }
350 }
351
352
353
354
355 /* Called by exec_cassette execute_compiled_cassette, but not
356 * exec_elt_cassette.
357 */
358 void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM )
359 {
360 TNLcontext *tnl = TNL_CONTEXT(ctx);
361
362 _tnl_vb_bind_immediate( ctx, IM );
363
364 if (IM->CopyOrFlag & VERT_EVAL_ANY)
365 _tnl_eval_immediate( ctx, IM );
366
367 /* Invalidate all stored data before and after run:
368 */
369 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
370 _tnl_run_pipeline( ctx );
371 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
372
373 _tnl_copy_to_current( ctx, IM, IM->OrFlag );
374 }
375
376 /* Called for regular vertex cassettes.
377 */
378 static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM )
379 {
380 if (IM->OrFlag & VERT_ELT) {
381 GLuint andflag = ~0;
382 GLuint i;
383 GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
384 _tnl_translate_array_elts( ctx, IM, start, IM->Count );
385
386 /* Need to recompute andflag and orflag for fixup.
387 */
388 if (IM->CopyAndFlag & VERT_ELT)
389 IM->CopyAndFlag |= ctx->Array._Enabled;
390 else {
391 for (i = IM->CopyStart ; i < IM->Count ; i++)
392 andflag &= IM->Flag[i];
393 IM->CopyAndFlag = andflag;
394 }
395 IM->CopyOrFlag |= ctx->Array._Enabled;
396 }
397
398 _tnl_fixup_input( ctx, IM );
399 /* _tnl_print_cassette( IM ); */
400 _tnl_run_cassette( ctx, IM );
401 }
402
403
404 /* Called for pure, locked VERT_ELT cassettes instead of
405 * _tnl_run_cassette.
406 */
407 static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM )
408 {
409 TNLcontext *tnl = TNL_CONTEXT(ctx);
410 struct vertex_buffer *VB = &tnl->vb;
411
412 _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
413
414 /* Take only elements and primitive information from the immediate:
415 */
416 VB->Elts = IM->Elt + IM->CopyStart;
417 VB->Primitive = IM->Primitive + IM->CopyStart;
418 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
419 VB->FirstPrimitive = 0;
420
421 /* Run the pipeline. No input changes as a result of this action.
422 */
423 _tnl_run_pipeline( ctx );
424
425 /* Still need to update current values: (TODO - copy from VB)
426 * TODO: delay this until FlushVertices
427 */
428 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
429 _tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData );
430 _tnl_copy_to_current( ctx, IM, ctx->Array._Enabled );
431 }
432 }
433
434
435 static void
436 exec_empty_cassette( GLcontext *ctx, struct immediate *IM )
437 {
438 if (IM->OrFlag & VERT_ELT)
439 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->CopyStart );
440
441 _tnl_copy_to_current( ctx, IM, IM->OrFlag );
442 }
443
444
445
446 /* Called for all cassettes when not compiling or playing a display
447 * list.
448 */
449 void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM )
450 {
451 TNLcontext *tnl = TNL_CONTEXT(ctx);
452
453 _tnl_compute_orflag( IM );
454 _tnl_copy_immediate_vertices( ctx, IM ); /* ?? flags, orflag above */
455 _tnl_get_exec_copy_verts( ctx, IM );
456
457 if (tnl->pipeline.build_state_changes)
458 _tnl_validate_pipeline( ctx );
459
460 if (IM->CopyStart == IM->Count) {
461 exec_empty_cassette( ctx, IM );
462 }
463 else if ((IM->CopyOrFlag & VERT_DATA) == VERT_ELT &&
464 ctx->Array.LockCount &&
465 ctx->Array.Vertex.Enabled) {
466 exec_elt_cassette( ctx, IM );
467 }
468 else {
469 exec_vert_cassette( ctx, IM );
470 }
471
472 /* Only reuse the immediate if there are no copied vertices living
473 * inside it:
474 */
475 {
476 GLuint begin_state = IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
477 GLuint saved_begin_state = IM->SavedBeginState;
478
479 if (--IM->ref_count != 0) {
480 IM = _tnl_alloc_immediate( ctx );
481 SET_IMMEDIATE( ctx, IM );
482 }
483
484 IM->ref_count++;
485
486 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS,
487 begin_state, saved_begin_state );
488 }
489
490 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
491 ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
492 }
493
494
495
496
497 /* Setup vector pointers that will be used to bind immediates to VB's.
498 */
499 void _tnl_imm_init( GLcontext *ctx )
500 {
501 TNLcontext *tnl = TNL_CONTEXT(ctx);
502 struct vertex_arrays *tmp = &tnl->imm_inputs;
503 GLuint i;
504 static int firsttime = 1;
505
506 if (firsttime) {
507 firsttime = 0;
508 _tnl_imm_elt_init();
509 }
510
511 ctx->swtnl_im = _tnl_alloc_immediate( ctx );
512 TNL_CURRENT_IM(ctx)->ref_count++;
513
514 tnl->ExecCopyTexSize = 0;
515 tnl->ExecCopyCount = 0;
516 tnl->ExecCopySource = 0;
517
518 TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS;
519
520 _mesa_vector4f_init( &tmp->Obj, 0, 0 );
521 _mesa_vector3f_init( &tmp->Normal, 0, 0 );
522
523 tmp->Color.Ptr = 0;
524 tmp->Color.Type = GL_FLOAT;
525 tmp->Color.Size = 4;
526 tmp->Color.Stride = 0;
527 tmp->Color.StrideB = 4 * sizeof(GLfloat);
528 tmp->Color.Flags = 0;
529
530 tmp->SecondaryColor.Ptr = 0;
531 tmp->SecondaryColor.Type = GL_FLOAT;
532 tmp->SecondaryColor.Size = 4;
533 tmp->SecondaryColor.Stride = 0;
534 tmp->SecondaryColor.StrideB = 4 * sizeof(GLfloat);
535 tmp->SecondaryColor.Flags = 0;
536
537 _mesa_vector1f_init( &tmp->FogCoord, 0, 0 );
538 _mesa_vector1ui_init( &tmp->Index, 0, 0 );
539 _mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
540
541 for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
542 _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
543
544 /* Install the first immediate. Intially outside begin/end.
545 */
546 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
547 tnl->ReplayHardBeginEnd = 0;
548
549 _tnl_imm_vtxfmt_init( ctx );
550 }
551
552
553 void _tnl_imm_destroy( GLcontext *ctx )
554 {
555 if (TNL_CURRENT_IM(ctx)) {
556 TNL_CURRENT_IM(ctx)->ref_count--;
557 _tnl_free_immediate( TNL_CURRENT_IM(ctx) );
558 SET_IMMEDIATE(ctx, 0);
559 }
560 }