Another vertex program checkpoint: clean-up of vertex attribute storage
[mesa.git] / src / mesa / tnl / t_imm_exec.c
1 /* $Id: t_imm_exec.c,v 1.34 2002/01/06 03:54:12 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 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 ? FLUSH_ELT_LAZY : FLUSH_ELT_EAGER;
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
100 IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
101 if (tnl->ExecParity)
102 IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
103
104 IM->LastPrimitive = IM->CopyStart;
105 }
106
107
108 void _tnl_reset_compile_input( GLcontext *ctx,
109 GLuint start,
110 GLuint beginstate,
111 GLuint savedbeginstate )
112 {
113 struct immediate *IM = TNL_CURRENT_IM(ctx);
114
115 reset_input( ctx, start, beginstate, savedbeginstate );
116 IM->CopyStart = start;
117 IM->LastPrimitive = IM->Start;
118 }
119
120
121 /*
122 * Copy the last specified normal, color, texcoord, edge flag, etc
123 * from the immediate struct into the ctx->Current attribute group.
124 */
125 void _tnl_copy_to_current( GLcontext *ctx, struct immediate *IM,
126 GLuint flag, GLuint count )
127 {
128 if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
129 _tnl_print_vert_flags("copy to current", flag);
130
131 /* XXX should be able t replace these conditions with a loop over
132 * the 16 vertex attributes.
133 */
134 if (flag & VERT_NORMAL_BIT)
135 COPY_4FV( ctx->Current.Attrib[VERT_ATTRIB_NORMAL],
136 IM->Attrib[VERT_ATTRIB_NORMAL][count]);
137
138 if (flag & VERT_INDEX_BIT)
139 ctx->Current.Index = IM->Index[count];
140
141 if (flag & VERT_EDGEFLAG_BIT)
142 ctx->Current.EdgeFlag = IM->EdgeFlag[count];
143
144 if (flag & VERT_COLOR0_BIT) {
145 COPY_4FV(ctx->Current.Attrib[VERT_ATTRIB_COLOR0],
146 IM->Attrib[VERT_ATTRIB_COLOR0][count]);
147 if (ctx->Light.ColorMaterialEnabled) {
148 _mesa_update_color_material( ctx,
149 ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
150 _mesa_validate_all_lighting_tables( ctx );
151 }
152 }
153
154 if (flag & VERT_COLOR1_BIT)
155 COPY_4FV(ctx->Current.Attrib[VERT_ATTRIB_COLOR1],
156 IM->Attrib[VERT_ATTRIB_COLOR1][count]);
157
158 if (flag & VERT_FOG_BIT)
159 ctx->Current.Attrib[VERT_ATTRIB_FOG][0] = IM->Attrib[VERT_ATTRIB_FOG][count][0];
160
161 if (flag & VERT_TEX_ANY) {
162 GLuint i;
163 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
164 if (flag & VERT_TEX(i)) {
165 COPY_4FV( ctx->Current.Attrib[VERT_ATTRIB_TEX0 + i],
166 IM->Attrib[VERT_ATTRIB_TEX0 + i][count]);
167 }
168 }
169 }
170
171 if (flag & VERT_MATERIAL) {
172 _mesa_update_material( ctx,
173 IM->Material[IM->LastMaterial],
174 IM->MaterialOrMask );
175
176 _mesa_validate_all_lighting_tables( ctx );
177 }
178 }
179
180
181
182 void _tnl_compute_orflag( struct immediate *IM, GLuint start )
183 {
184 GLuint count = IM->Count;
185 GLuint orflag = 0;
186 GLuint andflag = ~0U;
187 GLuint i;
188
189 IM->LastData = count-1;
190
191
192 /* Compute the flags for the whole buffer.
193 */
194 for (i = start ; i < count ; i++) {
195 andflag &= IM->Flag[i];
196 orflag |= IM->Flag[i];
197 }
198
199 /* It is possible there will be data in the buffer arising from
200 * calls like 'glNormal', 'glMaterial' that occur after the final
201 * glVertex, glEval, etc. Additionally, a buffer can consist of
202 * eg. a single glMaterial call, in which case IM->Start ==
203 * IM->Count, but the buffer is definitely not empty.
204 */
205 if (IM->Flag[i] & VERT_DATA) {
206 IM->LastData++;
207 orflag |= IM->Flag[i];
208 }
209
210 IM->Flag[IM->LastData+1] |= VERT_END_VB;
211 IM->CopyAndFlag = IM->AndFlag = andflag;
212 IM->OrFlag = orflag;
213 IM->CopyOrFlag = orflag;
214 IM->Evaluated = 0;
215 }
216
217
218 /*
219 * This is where the vertex data is transfered from the 'struct immediate
220 * into the 'struct vertex_buffer'.
221 *
222 * Note: The 'start' member of the GLvector structs is now redundant
223 * because we always re-transform copied vertices, and the vectors
224 * below are set up so that the first copied vertex (if any) appears
225 * at position zero.
226 */
227 static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM )
228 {
229 TNLcontext *tnl = TNL_CONTEXT(ctx);
230 struct vertex_buffer *VB = &tnl->vb;
231 struct vertex_arrays *tmp = &tnl->imm_inputs;
232 GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */
233 const GLuint start = IM->CopyStart;
234 const GLuint count = IM->Count - start;
235
236 /* TODO: optimize the case where nothing has changed. (Just bind
237 * tmp to vb).
238 */
239
240 /* Setup constant data in the VB.
241 */
242 VB->Count = count;
243 VB->FirstClipped = IMM_MAXDATA - IM->CopyStart;
244 VB->import_data = 0;
245 VB->importable_data = 0;
246
247 /* Need an IM->FirstPrimitive?
248 */
249 VB->Primitive = IM->Primitive + IM->CopyStart;
250 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
251 VB->FirstPrimitive = 0;
252
253 VB->Flag = IM->Flag + start;
254
255 /* TexCoordPtr's are zeroed in loop below.
256 */
257 VB->NormalPtr = 0;
258 VB->NormalLengthPtr = 0;
259 VB->EdgeFlag = 0;
260 VB->IndexPtr[0] = 0;
261 VB->IndexPtr[1] = 0;
262 VB->ColorPtr[0] = 0;
263 VB->ColorPtr[1] = 0;
264 VB->SecondaryColorPtr[0] = 0;
265 VB->SecondaryColorPtr[1] = 0;
266 VB->Elts = 0;
267 VB->MaterialMask = 0;
268 VB->Material = 0;
269
270 /* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
271 /* _tnl_print_vert_flags("orflag", IM->OrFlag); */
272 /* _tnl_print_vert_flags("inputs", inputs); */
273
274 /* Setup the initial values of array pointers in the vb.
275 */
276 if (inputs & VERT_OBJ_BIT) {
277 tmp->Obj.data = IM->Attrib[VERT_ATTRIB_POS] + start;
278 tmp->Obj.start = (GLfloat *)(IM->Attrib[VERT_ATTRIB_POS] + start);
279 tmp->Obj.count = count;
280 VB->ObjPtr = &tmp->Obj;
281 if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_234)
282 tmp->Obj.size = 4;
283 else if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_23)
284 tmp->Obj.size = 3;
285 else
286 tmp->Obj.size = 2;
287 }
288
289 if (inputs & VERT_NORMAL_BIT) {
290 tmp->Normal.data = IM->Attrib[VERT_ATTRIB_NORMAL] + start;
291 tmp->Normal.start = (GLfloat *) (IM->Attrib[VERT_ATTRIB_NORMAL] + start);
292 tmp->Normal.count = count;
293 VB->NormalPtr = &tmp->Normal;
294 if (IM->NormalLengthPtr)
295 VB->NormalLengthPtr = IM->NormalLengthPtr + start;
296 }
297
298 if (inputs & VERT_INDEX_BIT) {
299 tmp->Index.count = count;
300 tmp->Index.data = IM->Index + start;
301 tmp->Index.start = IM->Index + start;
302 VB->IndexPtr[0] = &tmp->Index;
303 }
304
305 if (inputs & VERT_FOG_BIT) {
306 tmp->FogCoord.data = IM->Attrib[VERT_ATTRIB_FOG] + start;
307 tmp->FogCoord.start = (GLfloat *) (IM->Attrib[VERT_ATTRIB_FOG] + start);
308 tmp->FogCoord.count = count;
309 VB->FogCoordPtr = &tmp->FogCoord;
310 }
311
312 if (inputs & VERT_COLOR1_BIT) {
313 tmp->SecondaryColor.Ptr = IM->Attrib[VERT_ATTRIB_COLOR1] + start;
314 VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
315 }
316
317 if (inputs & VERT_EDGEFLAG_BIT) {
318 VB->EdgeFlag = IM->EdgeFlag + start;
319 }
320
321 if (inputs & VERT_COLOR0_BIT) {
322 if (IM->CopyOrFlag & VERT_COLOR0_BIT) {
323 tmp->Color.Ptr = IM->Attrib[VERT_ATTRIB_COLOR0] + start;
324 tmp->Color.StrideB = 4 * sizeof(GLfloat);
325 tmp->Color.Flags = 0;
326 }
327 else {
328 tmp->Color.Ptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
329 tmp->Color.StrideB = 0;
330 tmp->Color.Flags = CA_CLIENT_DATA; /* hack */
331 VB->import_source = IM;
332 VB->importable_data |= VERT_COLOR0_BIT;
333 VB->import_data = _tnl_upgrade_current_data;
334 }
335 VB->ColorPtr[0] = &tmp->Color;
336 }
337
338 if (inputs & VERT_TEX_ANY) {
339 GLuint i;
340 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
341 VB->TexCoordPtr[i] = 0;
342 if (inputs & VERT_TEX(i)) {
343 tmp->TexCoord[i].count = count;
344 tmp->TexCoord[i].data = IM->Attrib[VERT_ATTRIB_TEX0 + i] + start;
345 tmp->TexCoord[i].start = (GLfloat *)(IM->Attrib[VERT_ATTRIB_TEX0 + i] + start);
346 tmp->TexCoord[i].size = 2;
347 if (IM->TexSize & TEX_SIZE_3(i)) {
348 tmp->TexCoord[i].size = 3;
349 if (IM->TexSize & TEX_SIZE_4(i))
350 tmp->TexCoord[i].size = 4;
351 }
352 VB->TexCoordPtr[i] = &tmp->TexCoord[i];
353 }
354 }
355 }
356
357 if ((inputs & VERT_MATERIAL) && IM->Material) {
358 VB->MaterialMask = IM->MaterialMask + start;
359 VB->Material = IM->Material + start;
360 }
361
362 /* GL_NV_vertex_program */
363 if (ctx->VertexProgram.Enabled) {
364 GLuint attr;
365 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
366 tmp->Attribs[attr].count = count;
367 tmp->Attribs[attr].data = IM->Attrib[attr] + start;
368 tmp->Attribs[attr].start = (GLfloat *) (IM->Attrib[attr] + start);
369 tmp->Attribs[attr].size = 4;
370 VB->AttribPtr[attr] = &(tmp->Attribs[attr]);
371 }
372 }
373 }
374
375
376
377
378 /* Called by exec_vert_cassette, execute_compiled_cassette, but not
379 * exec_elt_cassette.
380 */
381 void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM )
382 {
383 TNLcontext *tnl = TNL_CONTEXT(ctx);
384
385 _tnl_vb_bind_immediate( ctx, IM );
386
387 if (IM->OrFlag & VERT_EVAL_ANY)
388 _tnl_eval_immediate( ctx, IM );
389
390 /* Invalidate all stored data before and after run:
391 */
392 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
393 tnl->Driver.RunPipeline( ctx );
394 tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
395
396 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
397 }
398
399
400 /* Called for regular vertex cassettes.
401 */
402 static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM )
403 {
404 /* fprintf(stderr, "%s\n", __FUNCTION__); */
405
406 if (IM->FlushElt) {
407 /* Orflag is computed twice, but only reach this code if app is
408 * using a mixture of glArrayElement() and glVertex() while
409 * arrays are locked (else would be in exec_elt_cassette now).
410 */
411 ASSERT(ctx->Array.LockCount);
412 ASSERT(IM->FlushElt == FLUSH_ELT_LAZY);
413 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->Count );
414 _tnl_compute_orflag( IM, IM->CopyStart );
415 }
416
417 _tnl_fixup_input( ctx, IM );
418 /* _tnl_print_cassette( IM ); */
419 _tnl_run_cassette( ctx, IM );
420 }
421
422
423 /* Called for pure, locked VERT_ELT cassettes instead of
424 * _tnl_run_cassette.
425 */
426 static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM )
427 {
428 TNLcontext *tnl = TNL_CONTEXT(ctx);
429 struct vertex_buffer *VB = &tnl->vb;
430
431 /* fprintf(stderr, "%s\n", __FUNCTION__); */
432
433 _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
434
435 /* Take only elements and primitive information from the immediate:
436 */
437 VB->Elts = IM->Elt + IM->CopyStart;
438 VB->Primitive = IM->Primitive + IM->CopyStart;
439 VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
440 VB->FirstPrimitive = 0;
441
442 /* Run the pipeline. No input changes as a result of this action.
443 */
444 tnl->Driver.RunPipeline( ctx );
445
446 /* Still need to update current values:
447 */
448 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
449 _tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData );
450 _tnl_copy_to_current( ctx, IM, ctx->Array._Enabled, IM->LastData );
451 }
452 }
453
454
455 static void
456 exec_empty_cassette( GLcontext *ctx, struct immediate *IM )
457 {
458 if (IM->FlushElt)
459 _tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->CopyStart );
460
461 _tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
462 }
463
464
465
466 /* Called for all cassettes when not compiling or playing a display
467 * list.
468 */
469 void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM )
470 {
471 TNLcontext *tnl = TNL_CONTEXT(ctx);
472
473 _tnl_compute_orflag( IM, IM->Start );
474 _tnl_copy_immediate_vertices( ctx, IM );
475 _tnl_get_exec_copy_verts( ctx, IM );
476
477 if (tnl->pipeline.build_state_changes)
478 _tnl_validate_pipeline( ctx );
479
480 if (IM->CopyStart == IM->Count) {
481 exec_empty_cassette( ctx, IM );
482 }
483 else if ((IM->CopyOrFlag & VERT_DATA) == VERT_ELT &&
484 ctx->Array.LockCount &&
485 ctx->Array.Vertex.Enabled) {
486 exec_elt_cassette( ctx, IM );
487 }
488 else {
489 exec_vert_cassette( ctx, IM );
490 }
491
492 /* Only reuse the immediate if there are no copied vertices living
493 * inside it:
494 */
495 {
496 GLuint begin_state = IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
497 GLuint saved_begin_state = IM->SavedBeginState;
498
499 if (--IM->ref_count != 0) {
500 IM = _tnl_alloc_immediate( ctx );
501 SET_IMMEDIATE( ctx, IM );
502 }
503
504 IM->ref_count++;
505
506 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS,
507 begin_state, saved_begin_state );
508 }
509
510 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
511 ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
512 }
513
514
515
516
517 /* Setup vector pointers that will be used to bind immediates to VB's.
518 */
519 void _tnl_imm_init( GLcontext *ctx )
520 {
521 TNLcontext *tnl = TNL_CONTEXT(ctx);
522 struct vertex_arrays *tmp = &tnl->imm_inputs;
523 GLuint i;
524 static int firsttime = 1;
525
526 if (firsttime) {
527 firsttime = 0;
528 _tnl_imm_elt_init();
529 }
530
531 ctx->swtnl_im = _tnl_alloc_immediate( ctx );
532 TNL_CURRENT_IM(ctx)->ref_count++;
533
534 tnl->ExecCopyTexSize = 0;
535 tnl->ExecCopyCount = 0;
536 tnl->ExecCopySource = 0;
537
538 TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS;
539
540 _mesa_vector4f_init( &tmp->Obj, 0, 0 );
541 _mesa_vector4f_init( &tmp->Normal, 0, 0 );
542
543 tmp->Color.Ptr = 0;
544 tmp->Color.Type = GL_FLOAT;
545 tmp->Color.Size = 4;
546 tmp->Color.Stride = 0;
547 tmp->Color.StrideB = 4 * sizeof(GLfloat);
548 tmp->Color.Flags = 0;
549
550 tmp->SecondaryColor.Ptr = 0;
551 tmp->SecondaryColor.Type = GL_FLOAT;
552 tmp->SecondaryColor.Size = 4;
553 tmp->SecondaryColor.Stride = 0;
554 tmp->SecondaryColor.StrideB = 4 * sizeof(GLfloat);
555 tmp->SecondaryColor.Flags = 0;
556
557 _mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
558 _mesa_vector1ui_init( &tmp->Index, 0, 0 );
559 _mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
560
561 for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
562 _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
563
564 /* Install the first immediate. Intially outside begin/end.
565 */
566 _tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
567 tnl->ReplayHardBeginEnd = 0;
568
569 _tnl_imm_vtxfmt_init( ctx );
570 }
571
572
573 void _tnl_imm_destroy( GLcontext *ctx )
574 {
575 if (TNL_CURRENT_IM(ctx)) {
576 TNL_CURRENT_IM(ctx)->ref_count--;
577 if (TNL_CURRENT_IM(ctx)->ref_count == 0)
578 _tnl_free_immediate( TNL_CURRENT_IM(ctx) );
579 /*
580 * Don't use SET_IMMEDIATE here, or else we'll whack the
581 * _tnl_CurrentInput pointer - not good when another
582 * context has already been made current.
583 * So we just set the context's own tnl immediate pointer
584 * to 0.
585 */
586 ctx->swtnl_im = 0;
587 }
588 }