1 /* $Id: t_imm_exec.c,v 1.39 2002/04/19 12:32:14 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
28 * \file tnl/t_imm_exec.c
29 * \brief Setup to execute immediate-mode vertex data.
30 * \author Keith Whitwell
45 #include "math/m_matrix.h"
46 #include "math/m_xform.h"
48 #include "t_context.h"
49 #include "t_array_import.h"
50 #include "t_imm_alloc.h"
51 #include "t_imm_api.h"
52 #include "t_imm_debug.h"
53 #include "t_imm_dlist.h"
54 #include "t_imm_eval.h"
55 #include "t_imm_elt.h"
56 #include "t_imm_exec.h"
57 #include "t_imm_fixup.h"
58 #include "t_pipeline.h"
62 static void reset_input( GLcontext
*ctx
,
65 GLuint savedbeginstate
)
67 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
69 /* Clear the dirty part of the flag array.
71 if (start
< IM
->Count
+2)
72 MEMSET(IM
->Flag
+ start
, 0, sizeof(GLuint
) * (IM
->Count
+2-start
));
74 if (MESA_VERBOSE
& VERBOSE_IMMEDIATE
)
75 fprintf(stderr
, "reset_input: IM(%d) new %x\n",
80 IM
->LastMaterial
= start
;
81 IM
->BeginState
= beginstate
;
82 IM
->SavedBeginState
= savedbeginstate
;
84 IM
->MaterialOrMask
= 0;
87 IM
->MaterialMask
[IM
->Start
] = 0;
89 IM
->ArrayEltFlags
= ~ctx
->Array
._Enabled
;
90 IM
->ArrayEltIncr
= ctx
->Array
.Vertex
.Enabled
? 1 : 0;
91 IM
->ArrayEltFlush
= ctx
->Array
.LockCount
? FLUSH_ELT_LAZY
: FLUSH_ELT_EAGER
;
94 void _tnl_reset_exec_input( GLcontext
*ctx
,
97 GLuint savedbeginstate
)
99 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
100 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
102 reset_input( ctx
, start
, beginstate
, savedbeginstate
);
104 IM
->CopyStart
= start
- tnl
->ExecCopyCount
;
106 IM
->Primitive
[IM
->CopyStart
] = ctx
->Driver
.CurrentExecPrimitive
;
108 IM
->Primitive
[IM
->CopyStart
] |= PRIM_PARITY
;
110 IM
->LastPrimitive
= IM
->CopyStart
;
114 void _tnl_reset_compile_input( GLcontext
*ctx
,
117 GLuint savedbeginstate
)
119 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
121 reset_input( ctx
, start
, beginstate
, savedbeginstate
);
122 IM
->CopyStart
= start
;
123 IM
->LastPrimitive
= IM
->Start
;
128 * Copy the last specified normal, color, texcoord, edge flag, etc
129 * from the immediate struct into the ctx->Current attribute group.
131 void _tnl_copy_to_current( GLcontext
*ctx
, struct immediate
*IM
,
132 GLuint flag
, GLuint count
)
134 if (MESA_VERBOSE
&VERBOSE_IMMEDIATE
)
135 _tnl_print_vert_flags("copy to current", flag
);
137 /* XXX should be able to replace these conditions with a loop over
138 * the 16 vertex attributes.
140 if (flag
& VERT_BIT_NORMAL
)
141 COPY_4FV( ctx
->Current
.Attrib
[VERT_ATTRIB_NORMAL
],
142 IM
->Attrib
[VERT_ATTRIB_NORMAL
][count
]);
144 if (flag
& VERT_BIT_INDEX
)
145 ctx
->Current
.Index
= IM
->Index
[count
];
147 if (flag
& VERT_BIT_EDGEFLAG
)
148 ctx
->Current
.EdgeFlag
= IM
->EdgeFlag
[count
];
150 if (flag
& VERT_BIT_COLOR0
) {
151 COPY_4FV(ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
],
152 IM
->Attrib
[VERT_ATTRIB_COLOR0
][count
]);
153 if (ctx
->Light
.ColorMaterialEnabled
) {
154 _mesa_update_color_material( ctx
,
155 ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
] );
156 TNL_CONTEXT(ctx
)->Driver
.NotifyMaterialChange( ctx
);
160 if (flag
& VERT_BIT_COLOR1
)
161 COPY_4FV(ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR1
],
162 IM
->Attrib
[VERT_ATTRIB_COLOR1
][count
]);
164 if (flag
& VERT_BIT_FOG
)
165 ctx
->Current
.Attrib
[VERT_ATTRIB_FOG
][0] = IM
->Attrib
[VERT_ATTRIB_FOG
][count
][0];
167 if (flag
& VERT_BITS_TEX_ANY
) {
169 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
170 if (flag
& VERT_BIT_TEX(i
)) {
171 COPY_4FV( ctx
->Current
.Attrib
[VERT_ATTRIB_TEX0
+ i
],
172 IM
->Attrib
[VERT_ATTRIB_TEX0
+ i
][count
]);
177 if (flag
& VERT_BIT_MATERIAL
) {
178 _mesa_update_material( ctx
,
179 IM
->Material
[IM
->LastMaterial
],
180 IM
->MaterialOrMask
);
182 TNL_CONTEXT(ctx
)->Driver
.NotifyMaterialChange( ctx
);
188 void _tnl_compute_orflag( struct immediate
*IM
, GLuint start
)
190 GLuint count
= IM
->Count
;
192 GLuint andflag
= ~0U;
195 IM
->LastData
= count
-1;
198 /* Compute the flags for the whole buffer.
200 for (i
= start
; i
< count
; i
++) {
201 andflag
&= IM
->Flag
[i
];
202 orflag
|= IM
->Flag
[i
];
205 /* It is possible there will be data in the buffer arising from
206 * calls like 'glNormal', 'glMaterial' that occur after the final
207 * glVertex, glEval, etc. Additionally, a buffer can consist of
208 * eg. a single glMaterial call, in which case IM->Start ==
209 * IM->Count, but the buffer is definitely not empty.
211 if (IM
->Flag
[i
] & VERT_BITS_DATA
) {
213 orflag
|= IM
->Flag
[i
];
216 IM
->Flag
[IM
->LastData
+1] |= VERT_BIT_END_VB
;
217 IM
->CopyAndFlag
= IM
->AndFlag
= andflag
;
219 IM
->CopyOrFlag
= orflag
;
225 * This is where the vertex data is transfered from the 'struct immediate
226 * into the 'struct vertex_buffer'.
228 * Note: The 'start' member of the GLvector structs is now redundant
229 * because we always re-transform copied vertices, and the vectors
230 * below are set up so that the first copied vertex (if any) appears
233 static void _tnl_vb_bind_immediate( GLcontext
*ctx
, struct immediate
*IM
)
235 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
236 struct vertex_buffer
*VB
= &tnl
->vb
;
237 struct vertex_arrays
*tmp
= &tnl
->imm_inputs
;
238 GLuint inputs
= tnl
->pipeline
.inputs
; /* for copy-to-current */
239 const GLuint start
= IM
->CopyStart
;
240 const GLuint count
= IM
->Count
- start
;
242 /* TODO: optimize the case where nothing has changed. (Just bind
246 /* Setup constant data in the VB.
249 VB
->FirstClipped
= IMM_MAXDATA
- IM
->CopyStart
;
250 VB
->import_data
= NULL
;
251 VB
->importable_data
= 0;
253 /* Need an IM->FirstPrimitive?
255 VB
->Primitive
= IM
->Primitive
+ IM
->CopyStart
;
256 VB
->PrimitiveLength
= IM
->PrimitiveLength
+ IM
->CopyStart
;
257 VB
->FirstPrimitive
= 0;
259 VB
->Flag
= IM
->Flag
+ start
;
261 /* TexCoordPtr's are zeroed in loop below.
263 VB
->NormalPtr
= NULL
;
264 VB
->NormalLengthPtr
= NULL
;
266 VB
->IndexPtr
[0] = NULL
;
267 VB
->IndexPtr
[1] = NULL
;
268 VB
->ColorPtr
[0] = NULL
;
269 VB
->ColorPtr
[1] = NULL
;
270 VB
->SecondaryColorPtr
[0] = NULL
;
271 VB
->SecondaryColorPtr
[1] = NULL
;
273 VB
->MaterialMask
= NULL
;
276 /* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
277 /* _tnl_print_vert_flags("orflag", IM->OrFlag); */
278 /* _tnl_print_vert_flags("inputs", inputs); */
280 /* Setup the initial values of array pointers in the vb.
282 if (inputs
& VERT_BIT_POS
) {
283 tmp
->Obj
.data
= IM
->Attrib
[VERT_ATTRIB_POS
] + start
;
284 tmp
->Obj
.start
= (GLfloat
*)(IM
->Attrib
[VERT_ATTRIB_POS
] + start
);
285 tmp
->Obj
.count
= count
;
286 VB
->ObjPtr
= &tmp
->Obj
;
287 if ((IM
->CopyOrFlag
& VERT_BITS_OBJ_234
) == VERT_BITS_OBJ_234
)
289 else if ((IM
->CopyOrFlag
& VERT_BITS_OBJ_234
) == VERT_BITS_OBJ_23
)
295 if (inputs
& VERT_BIT_NORMAL
) {
296 tmp
->Normal
.data
= IM
->Attrib
[VERT_ATTRIB_NORMAL
] + start
;
297 tmp
->Normal
.start
= (GLfloat
*) (IM
->Attrib
[VERT_ATTRIB_NORMAL
] + start
);
298 tmp
->Normal
.count
= count
;
299 VB
->NormalPtr
= &tmp
->Normal
;
300 if (IM
->NormalLengthPtr
)
301 VB
->NormalLengthPtr
= IM
->NormalLengthPtr
+ start
;
304 if (inputs
& VERT_BIT_INDEX
) {
305 tmp
->Index
.count
= count
;
306 tmp
->Index
.data
= IM
->Index
+ start
;
307 tmp
->Index
.start
= IM
->Index
+ start
;
308 VB
->IndexPtr
[0] = &tmp
->Index
;
311 if (inputs
& VERT_BIT_FOG
) {
312 tmp
->FogCoord
.data
= IM
->Attrib
[VERT_ATTRIB_FOG
] + start
;
313 tmp
->FogCoord
.start
= (GLfloat
*) (IM
->Attrib
[VERT_ATTRIB_FOG
] + start
);
314 tmp
->FogCoord
.count
= count
;
315 VB
->FogCoordPtr
= &tmp
->FogCoord
;
318 if (inputs
& VERT_BIT_COLOR1
) {
319 tmp
->SecondaryColor
.Ptr
= IM
->Attrib
[VERT_ATTRIB_COLOR1
] + start
;
320 VB
->SecondaryColorPtr
[0] = &tmp
->SecondaryColor
;
323 if (inputs
& VERT_BIT_EDGEFLAG
) {
324 VB
->EdgeFlag
= IM
->EdgeFlag
+ start
;
327 if (inputs
& VERT_BIT_COLOR0
) {
328 if (IM
->CopyOrFlag
& VERT_BIT_COLOR0
) {
329 tmp
->Color
.Ptr
= IM
->Attrib
[VERT_ATTRIB_COLOR0
] + start
;
330 tmp
->Color
.StrideB
= 4 * sizeof(GLfloat
);
331 tmp
->Color
.Flags
= 0;
334 tmp
->Color
.Ptr
= ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
];
335 tmp
->Color
.StrideB
= 0;
336 tmp
->Color
.Flags
= CA_CLIENT_DATA
; /* hack */
337 VB
->import_source
= IM
;
338 VB
->importable_data
|= VERT_BIT_COLOR0
;
339 VB
->import_data
= _tnl_upgrade_current_data
;
341 VB
->ColorPtr
[0] = &tmp
->Color
;
344 if (inputs
& VERT_BITS_TEX_ANY
) {
346 for (i
= 0; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
347 VB
->TexCoordPtr
[i
] = NULL
;
348 if (inputs
& VERT_BIT_TEX(i
)) {
349 tmp
->TexCoord
[i
].count
= count
;
350 tmp
->TexCoord
[i
].data
= IM
->Attrib
[VERT_ATTRIB_TEX0
+ i
] + start
;
351 tmp
->TexCoord
[i
].start
= (GLfloat
*)(IM
->Attrib
[VERT_ATTRIB_TEX0
+ i
] + start
);
352 tmp
->TexCoord
[i
].size
= 2;
353 if (IM
->TexSize
& TEX_SIZE_3(i
)) {
354 tmp
->TexCoord
[i
].size
= 3;
355 if (IM
->TexSize
& TEX_SIZE_4(i
))
356 tmp
->TexCoord
[i
].size
= 4;
358 VB
->TexCoordPtr
[i
] = &tmp
->TexCoord
[i
];
363 if ((inputs
& IM
->OrFlag
& VERT_BIT_MATERIAL
) && IM
->Material
) {
364 VB
->MaterialMask
= IM
->MaterialMask
+ start
;
365 VB
->Material
= IM
->Material
+ start
;
368 /* GL_NV_vertex_program */
369 if (ctx
->VertexProgram
.Enabled
) {
371 for (attr
= 0; attr
< VERT_ATTRIB_MAX
; attr
++) {
372 tmp
->Attribs
[attr
].count
= count
;
373 tmp
->Attribs
[attr
].data
= IM
->Attrib
[attr
] + start
;
374 tmp
->Attribs
[attr
].start
= (GLfloat
*) (IM
->Attrib
[attr
] + start
);
375 tmp
->Attribs
[attr
].size
= 4;
376 VB
->AttribPtr
[attr
] = &(tmp
->Attribs
[attr
]);
385 * Called by exec_vert_cassette, execute_compiled_cassette, but not
388 void _tnl_run_cassette( GLcontext
*ctx
, struct immediate
*IM
)
390 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
392 _tnl_vb_bind_immediate( ctx
, IM
);
394 if (IM
->OrFlag
& VERT_BITS_EVAL_ANY
)
395 _tnl_eval_immediate( ctx
, IM
);
397 /* Invalidate all stored data before and after run:
399 tnl
->pipeline
.run_input_changes
|= tnl
->pipeline
.inputs
;
400 tnl
->Driver
.RunPipeline( ctx
);
401 tnl
->pipeline
.run_input_changes
|= tnl
->pipeline
.inputs
;
403 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
, IM
->LastData
);
408 * Called for regular vertex cassettes.
410 static void exec_vert_cassette( GLcontext
*ctx
, struct immediate
*IM
)
412 /* fprintf(stderr, "%s\n", __FUNCTION__); */
415 /* Orflag is computed twice, but only reach this code if app is
416 * using a mixture of glArrayElement() and glVertex() while
417 * arrays are locked (else would be in exec_elt_cassette now).
419 ASSERT(ctx
->Array
.LockCount
);
420 ASSERT(IM
->FlushElt
== FLUSH_ELT_LAZY
);
421 _tnl_translate_array_elts( ctx
, IM
, IM
->CopyStart
, IM
->Count
);
422 _tnl_compute_orflag( IM
, IM
->CopyStart
);
425 _tnl_fixup_input( ctx
, IM
);
426 /* _tnl_print_cassette( IM ); */
427 _tnl_run_cassette( ctx
, IM
);
431 /* Called for pure, locked VERT_BIT_ELT cassettes instead of
434 static void exec_elt_cassette( GLcontext
*ctx
, struct immediate
*IM
)
436 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
437 struct vertex_buffer
*VB
= &tnl
->vb
;
439 /* fprintf(stderr, "%s\n", __FUNCTION__); */
441 _tnl_vb_bind_arrays( ctx
, ctx
->Array
.LockFirst
, ctx
->Array
.LockCount
);
443 /* Take only elements and primitive information from the immediate:
445 VB
->Elts
= IM
->Elt
+ IM
->CopyStart
;
446 VB
->Primitive
= IM
->Primitive
+ IM
->CopyStart
;
447 VB
->PrimitiveLength
= IM
->PrimitiveLength
+ IM
->CopyStart
;
448 VB
->FirstPrimitive
= 0;
450 /* Run the pipeline. No input changes as a result of this action.
452 tnl
->Driver
.RunPipeline( ctx
);
454 /* Still need to update current values:
456 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
457 _tnl_translate_array_elts( ctx
, IM
, IM
->LastData
, IM
->LastData
);
458 _tnl_copy_to_current( ctx
, IM
, ctx
->Array
._Enabled
, IM
->LastData
);
464 exec_empty_cassette( GLcontext
*ctx
, struct immediate
*IM
)
467 _tnl_translate_array_elts( ctx
, IM
, IM
->CopyStart
, IM
->CopyStart
);
469 _tnl_copy_to_current( ctx
, IM
, IM
->OrFlag
, IM
->LastData
);
475 * Called for all cassettes when not compiling or playing a display
478 void _tnl_execute_cassette( GLcontext
*ctx
, struct immediate
*IM
)
480 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
482 _tnl_compute_orflag( IM
, IM
->Start
);
483 _tnl_copy_immediate_vertices( ctx
, IM
);
484 _tnl_get_exec_copy_verts( ctx
, IM
);
486 if (tnl
->pipeline
.build_state_changes
)
487 _tnl_validate_pipeline( ctx
);
489 if (IM
->CopyStart
== IM
->Count
) {
490 exec_empty_cassette( ctx
, IM
);
492 else if ((IM
->CopyOrFlag
& VERT_BITS_DATA
) == VERT_BIT_ELT
&&
493 ctx
->Array
.LockCount
&&
494 ctx
->Array
.Vertex
.Enabled
) {
495 exec_elt_cassette( ctx
, IM
);
498 exec_vert_cassette( ctx
, IM
);
501 /* Only reuse the immediate if there are no copied vertices living
505 GLuint begin_state
= IM
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
506 GLuint saved_begin_state
= IM
->SavedBeginState
;
508 if (--IM
->ref_count
!= 0) {
509 IM
= _tnl_alloc_immediate( ctx
);
510 SET_IMMEDIATE( ctx
, IM
);
515 _tnl_reset_exec_input( ctx
, IMM_MAX_COPIED_VERTS
,
516 begin_state
, saved_begin_state
);
519 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1)
520 ctx
->Driver
.NeedFlush
&= ~FLUSH_STORED_VERTICES
;
522 /* fprintf(stderr, "%s: NeedFlush: %x\n", __FUNCTION__, */
523 /* ctx->Driver.NeedFlush); */
530 * Setup vector pointers that will be used to bind immediates to VB's.
532 void _tnl_imm_init( GLcontext
*ctx
)
534 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
535 struct vertex_arrays
*tmp
= &tnl
->imm_inputs
;
537 static int firsttime
= 1;
544 ctx
->swtnl_im
= _tnl_alloc_immediate( ctx
);
545 TNL_CURRENT_IM(ctx
)->ref_count
++;
547 tnl
->ExecCopyTexSize
= 0;
548 tnl
->ExecCopyCount
= 0;
549 tnl
->ExecCopySource
= 0;
551 TNL_CURRENT_IM(ctx
)->CopyStart
= IMM_MAX_COPIED_VERTS
;
553 _mesa_vector4f_init( &tmp
->Obj
, 0, 0 );
554 _mesa_vector4f_init( &tmp
->Normal
, 0, 0 );
556 tmp
->Color
.Ptr
= NULL
;
557 tmp
->Color
.Type
= GL_FLOAT
;
559 tmp
->Color
.Stride
= 0;
560 tmp
->Color
.StrideB
= 4 * sizeof(GLfloat
);
561 tmp
->Color
.Flags
= 0;
563 tmp
->SecondaryColor
.Ptr
= NULL
;
564 tmp
->SecondaryColor
.Type
= GL_FLOAT
;
565 tmp
->SecondaryColor
.Size
= 4;
566 tmp
->SecondaryColor
.Stride
= 0;
567 tmp
->SecondaryColor
.StrideB
= 4 * sizeof(GLfloat
);
568 tmp
->SecondaryColor
.Flags
= 0;
570 _mesa_vector4f_init( &tmp
->FogCoord
, 0, 0 );
571 _mesa_vector1ui_init( &tmp
->Index
, 0, 0 );
572 _mesa_vector1ub_init( &tmp
->EdgeFlag
, 0, 0 );
574 for (i
= 0; i
< ctx
->Const
.MaxTextureUnits
; i
++)
575 _mesa_vector4f_init( &tmp
->TexCoord
[i
], 0, 0);
577 /* Install the first immediate. Intially outside begin/end.
579 _tnl_reset_exec_input( ctx
, IMM_MAX_COPIED_VERTS
, 0, 0 );
580 tnl
->ReplayHardBeginEnd
= 0;
582 _tnl_imm_vtxfmt_init( ctx
);
587 * Deallocate the immediate-mode buffer for the given context, if
588 * its reference count goes to zero.
590 void _tnl_imm_destroy( GLcontext
*ctx
)
592 if (TNL_CURRENT_IM(ctx
)) {
593 TNL_CURRENT_IM(ctx
)->ref_count
--;
594 if (TNL_CURRENT_IM(ctx
)->ref_count
== 0)
595 _tnl_free_immediate( ctx
, TNL_CURRENT_IM(ctx
) );
597 * Don't use SET_IMMEDIATE here, or else we'll whack the
598 * _tnl_CurrentInput pointer - not good when another
599 * context has already been made current.
600 * So we just set the context's own tnl immediate pointer
603 ctx
->swtnl_im
= NULL
;