1 /* $Id: t_pipeline.c,v 1.6 2000/11/27 09:05:52 joukj Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 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.
27 /* Dynamic pipelines, support for CVA.
28 * Copyright (C) 1999 Keith Whitwell.
38 #include "math/m_translate.h"
39 #include "math/m_xform.h"
47 #include "t_pipeline.h"
51 #include "t_vbindirect.h"
52 #include "t_vbrender.h"
53 #include "t_vbxform.h"
59 void _tnl_print_pipe_ops( const char *msg
, GLuint flags
)
62 "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n",
65 (flags
& PIPE_OP_CVA_PREPARE
) ? "cva-prepare, " : "",
66 (flags
& PIPE_OP_VERT_XFORM
) ? "vert-xform, " : "",
67 (flags
& PIPE_OP_NORM_XFORM
) ? "norm-xform, " : "",
68 (flags
& PIPE_OP_LIGHT
) ? "light, " : "",
69 (flags
& PIPE_OP_FOG
) ? "fog, " : "",
70 (flags
& PIPE_OP_TEX
) ? "tex-gen/tex-mat, " : "",
71 (flags
& PIPE_OP_RAST_SETUP_0
) ? "rast-0, " : "",
72 (flags
& PIPE_OP_RAST_SETUP_1
) ? "rast-1, " : "",
73 (flags
& PIPE_OP_RENDER
) ? "render, " : "");
79 /* Have to reset only those parts of the vb which are being recalculated.
81 void _tnl_reset_cva_vb( struct vertex_buffer
*VB
, GLuint stages
)
83 GLcontext
*ctx
= VB
->ctx
;
84 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
86 if (MESA_VERBOSE
&VERBOSE_PIPELINE
)
87 _tnl_print_pipe_ops( "reset cva vb", stages
);
89 if (stages
& PIPE_OP_VERT_XFORM
)
91 if (VB
->ClipOrMask
& CLIP_USER_BIT
)
92 MEMSET(VB
->UserClipMask
, 0, VB
->Count
);
95 VB
->ClipAndMask
= CLIP_ALL_BITS
;
97 VB
->CullFlag
[0] = VB
->CullFlag
[1] = 0;
101 if (stages
& PIPE_OP_NORM_XFORM
) {
102 VB
->NormalPtr
= &tnl
->CVA
.v
.Normal
;
105 if (stages
& PIPE_OP_LIGHT
)
107 VB
->ColorPtr
= VB
->Color
[0] = VB
->Color
[1] = &tnl
->CVA
.v
.Color
;
108 VB
->IndexPtr
= VB
->Index
[0] = VB
->Index
[1] = &tnl
->CVA
.v
.Index
;
110 else if (stages
& PIPE_OP_FOG
)
112 if (ctx
->Light
.Enabled
) {
113 VB
->Color
[0] = VB
->LitColor
[0];
114 VB
->Color
[1] = VB
->LitColor
[1];
115 VB
->Index
[0] = VB
->LitIndex
[0];
116 VB
->Index
[1] = VB
->LitIndex
[1];
118 VB
->Color
[0] = VB
->Color
[1] = &tnl
->CVA
.v
.Color
;
119 VB
->Index
[0] = VB
->Index
[1] = &tnl
->CVA
.v
.Index
;
121 VB
->ColorPtr
= VB
->Color
[0];
122 VB
->IndexPtr
= VB
->Index
[0];
131 static void pipeline_ctr( struct gl_pipeline
*p
, GLcontext
*ctx
, GLuint type
)
137 p
->cva_state_change
= 0;
143 for (i
= 0 ; i
< _tnl_default_nr_stages
; i
++)
144 p
->state_change
|= _tnl_default_pipeline
[i
].state_change
;
148 void _tnl_pipeline_init( GLcontext
*ctx
)
150 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
152 MEMCPY( tnl
->PipelineStage
,
153 _tnl_default_pipeline
,
154 sizeof(*_tnl_default_pipeline
) * _tnl_default_nr_stages
);
156 tnl
->NrPipelineStages
= _tnl_default_nr_stages
;
158 pipeline_ctr( &tnl
->CVA
.elt
, ctx
, PIPE_IMMEDIATE
);
159 pipeline_ctr( &tnl
->CVA
.pre
, ctx
, PIPE_PRECALC
);
164 #define MINIMAL_VERT_DATA (VERT_DATA & ~VERT_EVAL_ANY)
166 #define VERT_CURRENT_DATA (VERT_TEX_ANY | \
175 /* Called prior to every recomputation of the CVA precalc data, except where
176 * the driver is able to calculate the pipeline unassisted.
178 static void build_full_precalc_pipeline( GLcontext
*ctx
)
180 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
181 struct gl_pipeline_stage
*pipeline
= tnl
->PipelineStage
;
182 struct gl_cva
*cva
= &tnl
->CVA
;
183 struct gl_pipeline
*pre
= &cva
->pre
;
184 struct gl_pipeline_stage
**stages
= pre
->stages
;
186 GLuint newstate
= pre
->new_state
;
187 GLuint changed_ops
= 0;
188 GLuint oldoutputs
= pre
->outputs
;
189 GLuint oldinputs
= pre
->inputs
;
190 GLuint fallback
= (VERT_CURRENT_DATA
&
191 ~tnl
->_ArraySummary
);
192 GLuint changed_outputs
= (tnl
->_ArrayNewState
|
193 (fallback
& cva
->orflag
));
194 GLuint available
= fallback
| tnl
->_ArrayFlags
;
196 pre
->cva_state_change
= 0;
200 pre
->forbidden_inputs
= 0;
203 /* KW: Disable data reuse during Mesa reorg. Make this more readable...
207 if (tnl
->_ArraySummary
& VERT_ELT
)
208 cva
->orflag
&= VERT_MATERIAL
;
210 cva
->orflag
&= ~(tnl
->_ArraySummary
& ~VERT_OBJ_ANY
);
211 available
&= ~cva
->orflag
;
213 pre
->outputs
= available
;
214 pre
->inputs
= available
;
216 if (MESA_VERBOSE
& VERBOSE_PIPELINE
) {
217 fprintf(stderr
, ": Rebuild pipeline\n");
218 _tnl_print_vert_flags("orflag", cva
->orflag
);
223 /* If something changes in the pipeline, tag all subsequent stages
224 * using this value for recalcuation. Also used to build the full
225 * pipeline by setting newstate and newinputs to ~0.
227 * Because all intermediate values are buffered, the new inputs
228 * are enough to fully specify what needs to be calculated, and a
229 * single pass identifies all stages requiring recalculation.
231 for (i
= 0 ; i
< tnl
->NrPipelineStages
; i
++)
233 pipeline
[i
].check(ctx
, &pipeline
[i
]);
235 if (pipeline
[i
].type
& PIPE_PRECALC
)
237 if ((newstate
& pipeline
[i
].cva_state_change
) ||
238 (changed_outputs
& pipeline
[i
].inputs
) ||
241 changed_ops
|= pipeline
[i
].ops
;
242 changed_outputs
|= pipeline
[i
].outputs
;
243 pipeline
[i
].active
&= ~PIPE_PRECALC
;
245 if ((pipeline
[i
].inputs
& ~available
) == 0 &&
246 (pipeline
[i
].ops
& pre
->ops
) == 0)
248 pipeline
[i
].active
|= PIPE_PRECALC
;
249 *stages
++ = &pipeline
[i
];
253 /* Incompatible with multiple stages structs implementing
256 available
&= ~pipeline
[i
].outputs
;
257 pre
->outputs
&= ~pipeline
[i
].outputs
;
259 if (pipeline
[i
].active
& PIPE_PRECALC
) {
260 pre
->ops
|= pipeline
[i
].ops
;
261 pre
->outputs
|= pipeline
[i
].outputs
;
262 available
|= pipeline
[i
].outputs
;
263 pre
->forbidden_inputs
|= pipeline
[i
].pre_forbidden_inputs
;
266 else if (pipeline
[i
].active
& PIPE_PRECALC
)
268 pipeline
[i
].active
&= ~PIPE_PRECALC
;
269 changed_outputs
|= pipeline
[i
].outputs
;
270 changed_ops
|= pipeline
[i
].ops
;
276 pre
->new_outputs
= pre
->outputs
& (changed_outputs
| ~oldoutputs
);
277 pre
->new_inputs
= pre
->inputs
& ~oldinputs
;
278 pre
->fallback
= pre
->inputs
& fallback
;
279 pre
->forbidden_inputs
|= pre
->inputs
& fallback
;
281 pre
->changed_ops
= changed_ops
;
284 void _tnl_build_precalc_pipeline( GLcontext
*ctx
)
286 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
287 struct gl_pipeline
*pre
= &tnl
->CVA
.pre
;
288 struct gl_pipeline
*elt
= &tnl
->CVA
.elt
;
290 if (!ctx
->Driver
.BuildPrecalcPipeline
||
291 !ctx
->Driver
.BuildPrecalcPipeline( ctx
))
292 build_full_precalc_pipeline( ctx
);
295 pre
->pipeline_valid
= 1;
296 elt
->pipeline_valid
= 0;
300 if (MESA_VERBOSE
&VERBOSE_PIPELINE
)
301 _tnl_print_pipeline( ctx
, pre
);
305 static void build_full_immediate_pipeline( GLcontext
*ctx
)
307 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
308 struct gl_pipeline_stage
*pipeline
= tnl
->PipelineStage
;
309 struct gl_cva
*cva
= &tnl
->CVA
;
310 struct gl_pipeline
*pre
= &cva
->pre
;
311 struct gl_pipeline
*elt
= &cva
->elt
;
312 struct gl_pipeline_stage
**stages
= elt
->stages
;
314 GLuint newstate
= elt
->new_state
;
315 GLuint active_ops
= 0;
316 GLuint available
= cva
->orflag
| MINIMAL_VERT_DATA
;
317 GLuint generated
= 0;
320 if (pre
->data_valid
&& tnl
->CompileCVAFlag
) {
322 active_ops
= cva
->pre
.ops
;
323 available
|= pre
->outputs
| VERT_PRECALC_DATA
;
327 elt
->outputs
= 0; /* not used */
330 for (i
= 0 ; i
< tnl
->NrPipelineStages
; i
++) {
331 pipeline
[i
].active
&= ~PIPE_IMMEDIATE
;
333 if ((pipeline
[i
].state_change
& newstate
) ||
334 (pipeline
[i
].elt_forbidden_inputs
& available
))
336 pipeline
[i
].check(ctx
, &pipeline
[i
]);
339 if ((pipeline
[i
].type
& PIPE_IMMEDIATE
) &&
340 (pipeline
[i
].ops
& active_ops
) == 0 &&
341 (pipeline
[i
].elt_forbidden_inputs
& available
) == 0
344 if (pipeline
[i
].inputs
& ~available
)
345 elt
->forbidden_inputs
|= pipeline
[i
].inputs
& ~available
;
348 elt
->inputs
|= pipeline
[i
].inputs
& ~generated
;
349 elt
->forbidden_inputs
|= pipeline
[i
].elt_forbidden_inputs
;
350 pipeline
[i
].active
|= PIPE_IMMEDIATE
;
351 *stages
++ = &pipeline
[i
];
352 generated
|= pipeline
[i
].outputs
;
353 available
|= pipeline
[i
].outputs
;
354 active_ops
|= pipeline
[i
].ops
;
361 elt
->copy_transformed_data
= 1;
362 elt
->replay_copied_vertices
= 0;
365 cva
->merge
= elt
->inputs
& pre
->outputs
;
366 elt
->ops
= active_ops
& ~pre
->ops
;
372 void _tnl_build_immediate_pipeline( GLcontext
*ctx
)
374 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
375 struct gl_pipeline
*elt
= &tnl
->CVA
.elt
;
377 if (!ctx
->Driver
.BuildEltPipeline
||
378 !ctx
->Driver
.BuildEltPipeline( ctx
)) {
379 build_full_immediate_pipeline( ctx
);
382 elt
->pipeline_valid
= 1;
385 if (MESA_VERBOSE
&VERBOSE_PIPELINE
)
386 _tnl_print_pipeline( ctx
, elt
);
389 #define INTERESTED ~0
391 void _tnl_update_pipelines( GLcontext
*ctx
)
393 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
394 GLuint newstate
= ctx
->NewState
;
395 struct gl_cva
*cva
= &tnl
->CVA
;
397 newstate
&= INTERESTED
;
399 if (MESA_VERBOSE
& (VERBOSE_API
|VERBOSE_STATE
))
400 gl_print_enable_flags("enabled", ctx
->_Enabled
);
404 cva
->orflag
!= cva
->last_orflag
||
405 tnl
->_ArrayFlags
!= cva
->last_array_flags
)
408 GLuint flags
= VERT_WIN
;
410 if (ctx
->Visual
.RGBAflag
) {
412 if (ctx
->_TriangleCaps
&& DD_SEPERATE_SPECULAR
)
413 flags
|= VERT_SPEC_RGB
;
417 for (j
= 0 ; j
< ctx
->Const
.MaxTextureUnits
; j
++) {
418 if (ctx
->Texture
.Unit
[j
]._ReallyEnabled
)
419 flags
|= VERT_TEX(j
);
422 if (ctx
->Polygon
._Unfilled
)
425 if (ctx
->Fog
.FogCoordinateSource
== GL_FOG_COORDINATE_EXT
)
426 flags
|= VERT_FOG_COORD
;
428 if (ctx
->RenderMode
==GL_FEEDBACK
) {
429 flags
= (VERT_WIN
| VERT_RGBA
| VERT_INDEX
| VERT_NORM
|
430 VERT_EDGE
| VERT_TEX_ANY
);
433 tnl
->_RenderFlags
= flags
;
435 cva
->elt
.new_state
|= newstate
;
436 cva
->elt
.pipeline_valid
= 0;
438 cva
->pre
.new_state
|= newstate
;
439 cva
->pre
.forbidden_inputs
= 0;
440 cva
->pre
.pipeline_valid
= 0;
441 cva
->lock_changed
= 0;
444 if (tnl
->_ArrayNewState
!= cva
->last_array_new_state
)
445 cva
->pre
.pipeline_valid
= 0;
447 cva
->pre
.data_valid
= 0;
448 cva
->last_array_new_state
= tnl
->_ArrayNewState
;
449 cva
->last_orflag
= cva
->orflag
;
450 cva
->last_array_flags
= tnl
->_ArrayFlags
;
453 void _tnl_run_pipeline( struct vertex_buffer
*VB
)
455 struct gl_pipeline
*pipe
= VB
->pipeline
;
456 struct gl_pipeline_stage
**stages
= pipe
->stages
;
459 pipe
->data_valid
= 1; /* optimized stages might want to reset this. */
461 if (0) _tnl_print_pipeline( VB
->ctx
, pipe
);
465 for ( VB
->Culled
= 0; *stages
&& !VB
->Culled
; stages
++ )
466 (*stages
)->run( VB
);