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