3
* Mesa 3-D graphics library
6
* Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8
* Permission is hereby granted, free of charge, to any person obtaining a
9
* copy of this software and associated documentation files (the "Software"),
10
* to deal in the Software without restriction, including without limitation
11
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
* and/or sell copies of the Software, and to permit persons to whom the
13
* Software is furnished to do so, subject to the following conditions:
15
* The above copyright notice and this permission notice shall be included
16
* in all copies or substantial portions of the Software.
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
* Keith Whitwell <keithw@valinux.com>
42
#include "math/m_matrix.h"
43
#include "math/m_xform.h"
45
#include "t_context.h"
46
#include "t_array_import.h"
47
#include "t_imm_alloc.h"
48
#include "t_imm_api.h"
49
#include "t_imm_debug.h"
50
#include "t_imm_dlist.h"
51
#include "t_imm_eval.h"
52
#include "t_imm_elt.h"
53
#include "t_imm_exec.h"
54
#include "t_imm_fixup.h"
55
#include "t_pipeline.h"
59
static void reset_input( GLcontext *ctx,
62
GLuint savedbeginstate )
64
struct immediate *IM = TNL_CURRENT_IM(ctx);
66
/* Clear the dirty part of the flag array.
68
if (start < IM->Count+2)
69
MEMSET(IM->Flag + start, 0, sizeof(GLuint) * (IM->Count+2-start));
71
if (MESA_VERBOSE & VERBOSE_IMMEDIATE)
72
fprintf(stderr, "reset_input: IM(%d) new %x\n",
77
IM->LastMaterial = start;
78
IM->BeginState = beginstate;
79
IM->SavedBeginState = savedbeginstate;
81
IM->MaterialOrMask = 0;
84
IM->MaterialMask[IM->Start] = 0;
86
IM->ArrayEltFlags = ~ctx->Array._Enabled;
87
IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0;
88
IM->ArrayEltFlush = ctx->Array.LockCount ? FLUSH_ELT_LAZY : FLUSH_ELT_EAGER;
91
void _tnl_reset_exec_input( GLcontext *ctx,
94
GLuint savedbeginstate )
96
TNLcontext *tnl = TNL_CONTEXT(ctx);
97
struct immediate *IM = TNL_CURRENT_IM(ctx);
99
reset_input( ctx, start, beginstate, savedbeginstate );
101
IM->CopyStart = start - tnl->ExecCopyCount;
102
IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive;
104
IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
106
IM->LastPrimitive = IM->CopyStart;
110
void _tnl_reset_compile_input( GLcontext *ctx,
113
GLuint savedbeginstate )
115
struct immediate *IM = TNL_CURRENT_IM(ctx);
117
reset_input( ctx, start, beginstate, savedbeginstate );
118
IM->CopyStart = start;
119
IM->LastPrimitive = IM->Start;
123
void _tnl_copy_to_current( GLcontext *ctx, struct immediate *IM,
124
GLuint flag, GLuint count )
126
if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
127
_tnl_print_vert_flags("copy to current", flag);
129
if (flag & VERT_NORM)
130
COPY_3FV( ctx->Current.Normal, IM->Normal[count]);
132
if (flag & VERT_INDEX)
133
ctx->Current.Index = IM->Index[count];
135
if (flag & VERT_EDGE)
136
ctx->Current.EdgeFlag = IM->EdgeFlag[count];
138
if (flag & VERT_RGBA) {
139
COPY_4FV(ctx->Current.Color, IM->Color[count]);
140
if (ctx->Light.ColorMaterialEnabled) {
141
_mesa_update_color_material( ctx, ctx->Current.Color );
142
TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
146
if (flag & VERT_SPEC_RGB)
147
COPY_4FV(ctx->Current.SecondaryColor, IM->SecondaryColor[count]);
149
if (flag & VERT_FOG_COORD)
150
ctx->Current.FogCoord = IM->FogCoord[count];
152
if (flag & VERT_TEX_ANY) {
154
for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
155
if (flag & VERT_TEX(i)) {
156
COPY_4FV( ctx->Current.Texcoord[0], IM->TexCoord[0][count]);
161
if (flag & VERT_MATERIAL) {
162
_mesa_update_material( ctx,
163
IM->Material[IM->LastMaterial],
164
IM->MaterialOrMask );
166
TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx );
172
void _tnl_compute_orflag( struct immediate *IM, GLuint start )
174
GLuint count = IM->Count;
176
GLuint andflag = ~0U;
179
IM->LastData = count-1;
182
/* Compute the flags for the whole buffer.
184
for (i = start ; i < count ; i++) {
185
andflag &= IM->Flag[i];
186
orflag |= IM->Flag[i];
189
/* It is possible there will be data in the buffer arising from
190
* calls like 'glNormal', 'glMaterial' that occur after the final
191
* glVertex, glEval, etc. Additionally, a buffer can consist of
192
* eg. a single glMaterial call, in which case IM->Start ==
193
* IM->Count, but the buffer is definitely not empty.
195
if (IM->Flag[i] & VERT_DATA) {
197
orflag |= IM->Flag[i];
200
IM->Flag[IM->LastData+1] |= VERT_END_VB;
201
IM->CopyAndFlag = IM->AndFlag = andflag;
203
IM->CopyOrFlag = orflag;
214
/* Note: The 'start' member of the GLvector structs is now redundant
215
* because we always re-transform copied vertices, and the vectors
216
* below are set up so that the first copied vertex (if any) appears
219
static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM )
221
TNLcontext *tnl = TNL_CONTEXT(ctx);
222
struct vertex_buffer *VB = &tnl->vb;
223
struct vertex_arrays *tmp = &tnl->imm_inputs;
224
GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */
225
GLuint start = IM->CopyStart;
226
GLuint count = IM->Count - start;
228
/* TODO: optimize the case where nothing has changed. (Just bind
232
/* Setup constant data in the VB.
235
VB->FirstClipped = IMM_MAXDATA - IM->CopyStart;
237
VB->importable_data = 0;
239
/* Need an IM->FirstPrimitive?
241
VB->Primitive = IM->Primitive + IM->CopyStart;
242
VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
243
VB->FirstPrimitive = 0;
245
VB->Flag = IM->Flag + start;
247
/* TexCoordPtr's are zeroed in loop below.
250
VB->NormalLengthPtr = 0;
257
VB->SecondaryColorPtr[0] = 0;
258
VB->SecondaryColorPtr[1] = 0;
260
VB->MaterialMask = 0;
263
/* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
264
/* _tnl_print_vert_flags("orflag", IM->OrFlag); */
265
/* _tnl_print_vert_flags("inputs", inputs); */
267
/* Setup the initial values of array pointers in the vb.
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)
276
else if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_23)
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
if (IM->NormalLengthPtr)
288
VB->NormalLengthPtr = IM->NormalLengthPtr + start;
291
if (inputs & VERT_INDEX) {
292
tmp->Index.count = count;
293
tmp->Index.data = IM->Index + start;
294
tmp->Index.start = IM->Index + start;
295
VB->IndexPtr[0] = &tmp->Index;
298
if (inputs & VERT_FOG_COORD) {
299
tmp->FogCoord.data = IM->FogCoord + start;
300
tmp->FogCoord.start = IM->FogCoord + start;
301
tmp->FogCoord.count = count;
302
VB->FogCoordPtr = &tmp->FogCoord;
305
if (inputs & VERT_SPEC_RGB) {
306
tmp->SecondaryColor.Ptr = IM->SecondaryColor + start;
307
VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
310
if (inputs & VERT_EDGE) {
311
VB->EdgeFlag = IM->EdgeFlag + start;
314
if (inputs & VERT_RGBA) {
315
if (IM->CopyOrFlag & VERT_RGBA) {
316
tmp->Color.Ptr = IM->Color + start;
317
tmp->Color.StrideB = 4 * sizeof(GLfloat);
318
tmp->Color.Flags = 0;
320
tmp->Color.Ptr = ctx->Current.Color;
321
tmp->Color.StrideB = 0;
322
tmp->Color.Flags = CA_CLIENT_DATA; /* hack */
323
VB->import_source = IM;
324
VB->importable_data |= VERT_RGBA;
325
VB->import_data = _tnl_upgrade_current_data;
327
VB->ColorPtr[0] = &tmp->Color;
330
if (inputs & VERT_TEX_ANY) {
332
for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
333
VB->TexCoordPtr[i] = 0;
334
if (inputs & VERT_TEX(i)) {
335
tmp->TexCoord[i].count = count;
336
tmp->TexCoord[i].data = IM->TexCoord[i] + start;
337
tmp->TexCoord[i].start = (GLfloat *)(IM->TexCoord[i] + start);
338
tmp->TexCoord[i].size = 2;
339
if (IM->TexSize & TEX_SIZE_3(i)) {
340
tmp->TexCoord[i].size = 3;
341
if (IM->TexSize & TEX_SIZE_4(i))
342
tmp->TexCoord[i].size = 4;
344
VB->TexCoordPtr[i] = &tmp->TexCoord[i];
349
if ((inputs & IM->OrFlag & VERT_MATERIAL) && IM->Material) {
350
VB->MaterialMask = IM->MaterialMask + start;
351
VB->Material = IM->Material + start;
358
/* Called by exec_vert_cassette, execute_compiled_cassette, but not
361
void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM )
363
TNLcontext *tnl = TNL_CONTEXT(ctx);
365
/* fprintf(stderr, "%s\n", __FUNCTION__); */
367
_tnl_vb_bind_immediate( ctx, IM );
369
if (IM->OrFlag & VERT_EVAL_ANY)
370
_tnl_eval_immediate( ctx, IM );
372
/* Invalidate all stored data before and after run:
374
tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
375
tnl->Driver.RunPipeline( ctx );
376
tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
378
_tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
382
/* Called for regular vertex cassettes.
384
static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM )
386
/* fprintf(stderr, "%s\n", __FUNCTION__); */
389
/* Orflag is computed twice, but only reach this code if app is
390
* using a mixture of glArrayElement() and glVertex() while
391
* arrays are locked (else would be in exec_elt_cassette now).
393
ASSERT(ctx->Array.LockCount);
394
ASSERT(IM->FlushElt == FLUSH_ELT_LAZY);
395
_tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->Count );
396
_tnl_compute_orflag( IM, IM->CopyStart );
399
_tnl_fixup_input( ctx, IM );
400
/* _tnl_print_cassette( IM ); */
401
_tnl_run_cassette( ctx, IM );
405
/* Called for pure, locked VERT_ELT cassettes instead of
408
static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM )
410
TNLcontext *tnl = TNL_CONTEXT(ctx);
411
struct vertex_buffer *VB = &tnl->vb;
413
/* fprintf(stderr, "%s\n", __FUNCTION__); */
415
_tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
417
/* Take only elements and primitive information from the immediate:
419
VB->Elts = IM->Elt + IM->CopyStart;
420
VB->Primitive = IM->Primitive + IM->CopyStart;
421
VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
422
VB->FirstPrimitive = 0;
424
/* Run the pipeline. No input changes as a result of this action.
426
tnl->Driver.RunPipeline( ctx );
428
/* Still need to update current values:
430
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
431
_tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData );
432
_tnl_copy_to_current( ctx, IM, ctx->Array._Enabled, IM->LastData );
438
exec_empty_cassette( GLcontext *ctx, struct immediate *IM )
441
_tnl_translate_array_elts( ctx, IM, IM->CopyStart, IM->CopyStart );
443
_tnl_copy_to_current( ctx, IM, IM->OrFlag, IM->LastData );
448
/* Called for all cassettes when not compiling or playing a display
451
void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM )
453
TNLcontext *tnl = TNL_CONTEXT(ctx);
455
_tnl_compute_orflag( IM, IM->Start );
456
_tnl_copy_immediate_vertices( ctx, IM );
457
_tnl_get_exec_copy_verts( ctx, IM );
459
if (tnl->pipeline.build_state_changes)
460
_tnl_validate_pipeline( ctx );
462
if (IM->CopyStart == IM->Count) {
463
exec_empty_cassette( ctx, IM );
465
else if ((IM->CopyOrFlag & VERT_DATA) == VERT_ELT &&
466
ctx->Array.LockCount &&
467
ctx->Array.Vertex.Enabled) {
468
exec_elt_cassette( ctx, IM );
471
exec_vert_cassette( ctx, IM );
474
/* Only reuse the immediate if there are no copied vertices living
478
GLuint begin_state = IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
479
GLuint saved_begin_state = IM->SavedBeginState;
481
if (--IM->ref_count != 0) {
482
IM = _tnl_alloc_immediate( ctx );
483
SET_IMMEDIATE( ctx, IM );
488
_tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS,
489
begin_state, saved_begin_state );
492
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
493
ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES;
495
/* fprintf(stderr, "%s: NeedFlush: %x\n", __FUNCTION__, */
496
/* ctx->Driver.NeedFlush); */
502
/* Setup vector pointers that will be used to bind immediates to VB's.
504
void _tnl_imm_init( GLcontext *ctx )
506
TNLcontext *tnl = TNL_CONTEXT(ctx);
507
struct vertex_arrays *tmp = &tnl->imm_inputs;
509
static int firsttime = 1;
516
ctx->swtnl_im = _tnl_alloc_immediate( ctx );
517
TNL_CURRENT_IM(ctx)->ref_count++;
519
tnl->ExecCopyTexSize = 0;
520
tnl->ExecCopyCount = 0;
521
tnl->ExecCopySource = 0;
523
TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS;
525
_mesa_vector4f_init( &tmp->Obj, 0, 0 );
526
_mesa_vector3f_init( &tmp->Normal, 0, 0 );
529
tmp->Color.Type = GL_FLOAT;
531
tmp->Color.Stride = 0;
532
tmp->Color.StrideB = 4 * sizeof(GLfloat);
533
tmp->Color.Flags = 0;
535
tmp->SecondaryColor.Ptr = 0;
536
tmp->SecondaryColor.Type = GL_FLOAT;
537
tmp->SecondaryColor.Size = 4;
538
tmp->SecondaryColor.Stride = 0;
539
tmp->SecondaryColor.StrideB = 4 * sizeof(GLfloat);
540
tmp->SecondaryColor.Flags = 0;
542
_mesa_vector1f_init( &tmp->FogCoord, 0, 0 );
543
_mesa_vector1ui_init( &tmp->Index, 0, 0 );
544
_mesa_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
546
for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
547
_mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
549
/* Install the first immediate. Intially outside begin/end.
551
_tnl_reset_exec_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
552
tnl->ReplayHardBeginEnd = 0;
554
_tnl_imm_vtxfmt_init( ctx );
558
void _tnl_imm_destroy( GLcontext *ctx )
560
if (TNL_CURRENT_IM(ctx)) {
561
TNL_CURRENT_IM(ctx)->ref_count--;
562
if (TNL_CURRENT_IM(ctx)->ref_count == 0)
563
_tnl_free_immediate( ctx, TNL_CURRENT_IM(ctx) );
565
* Don't use SET_IMMEDIATE here, or else we'll whack the
566
* _tnl_CurrentInput pointer - not good when another
567
* context has already been made current.
568
* So we just set the context's own tnl immediate pointer