1 /* $Id: t_pipeline.c,v 1.1 2000/11/16 21:05:42 keithw 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"
46 #include "t_pipeline.h"
50 #include "t_vbindirect.h"
51 #include "t_vbrender.h"
52 #include "t_vbxform.h"
58 void gl_print_pipe_ops( const char *msg
, GLuint flags
)
61 "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s\n",
64 (flags
& PIPE_OP_CVA_PREPARE
) ? "cva-prepare, " : "",
65 (flags
& PIPE_OP_VERT_XFORM
) ? "vert-xform, " : "",
66 (flags
& PIPE_OP_NORM_XFORM
) ? "norm-xform, " : "",
67 (flags
& PIPE_OP_LIGHT
) ? "light, " : "",
68 (flags
& PIPE_OP_FOG
) ? "fog, " : "",
69 (flags
& PIPE_OP_TEX0
) ? "tex-0, " : "",
70 (flags
& PIPE_OP_TEX1
) ? "tex-1, " : "",
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 gl_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 gl_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
< gl_default_nr_stages
; i
++)
144 p
->state_change
|= gl_default_pipeline
[i
].state_change
;
148 void _tnl_pipeline_init( GLcontext
*ctx
)
150 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
152 MEMCPY( tnl
->PipelineStage
,
154 sizeof(*gl_default_pipeline
) * gl_default_nr_stages
);
156 tnl
->NrPipelineStages
= gl_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_TEX0_4 | \
170 #define VERT_CURRENT_DATA (VERT_TEX0_1234 | \
182 /* Called prior to every recomputation of the CVA precalc data, except where
183 * the driver is able to calculate the pipeline unassisted.
185 static void build_full_precalc_pipeline( GLcontext
*ctx
)
187 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
188 struct gl_pipeline_stage
*pipeline
= tnl
->PipelineStage
;
189 struct gl_cva
*cva
= &tnl
->CVA
;
190 struct gl_pipeline
*pre
= &cva
->pre
;
191 struct gl_pipeline_stage
**stages
= pre
->stages
;
193 GLuint newstate
= pre
->new_state
;
194 GLuint changed_ops
= 0;
195 GLuint oldoutputs
= pre
->outputs
;
196 GLuint oldinputs
= pre
->inputs
;
197 GLuint fallback
= (VERT_CURRENT_DATA
& tnl
->_CurrentFlag
&
198 ~tnl
->_ArraySummary
);
199 GLuint changed_outputs
= (tnl
->_ArrayNewState
|
200 (fallback
& cva
->orflag
));
201 GLuint available
= fallback
| tnl
->_ArrayFlags
;
203 pre
->cva_state_change
= 0;
207 pre
->forbidden_inputs
= 0;
210 /* KW: Disable data reuse during Mesa reorg. Make this more readable...
214 if (tnl
->_ArraySummary
& VERT_ELT
)
215 cva
->orflag
&= VERT_MATERIAL
;
217 cva
->orflag
&= ~(tnl
->_ArraySummary
& ~VERT_OBJ_ANY
);
218 available
&= ~cva
->orflag
;
220 pre
->outputs
= available
;
221 pre
->inputs
= available
;
223 if (MESA_VERBOSE
& VERBOSE_PIPELINE
) {
224 fprintf(stderr
, ": Rebuild pipeline\n");
225 gl_print_vert_flags("orflag", cva
->orflag
);
230 /* If something changes in the pipeline, tag all subsequent stages
231 * using this value for recalcuation. Also used to build the full
232 * pipeline by setting newstate and newinputs to ~0.
234 * Because all intermediate values are buffered, the new inputs
235 * are enough to fully specify what needs to be calculated, and a
236 * single pass identifies all stages requiring recalculation.
238 for (i
= 0 ; i
< tnl
->NrPipelineStages
; i
++)
240 pipeline
[i
].check(ctx
, &pipeline
[i
]);
242 if (pipeline
[i
].type
& PIPE_PRECALC
)
244 if ((newstate
& pipeline
[i
].cva_state_change
) ||
245 (changed_outputs
& pipeline
[i
].inputs
) ||
248 changed_ops
|= pipeline
[i
].ops
;
249 changed_outputs
|= pipeline
[i
].outputs
;
250 pipeline
[i
].active
&= ~PIPE_PRECALC
;
252 if ((pipeline
[i
].inputs
& ~available
) == 0 &&
253 (pipeline
[i
].ops
& pre
->ops
) == 0)
255 pipeline
[i
].active
|= PIPE_PRECALC
;
256 *stages
++ = &pipeline
[i
];
260 /* Incompatible with multiple stages structs implementing
263 available
&= ~pipeline
[i
].outputs
;
264 pre
->outputs
&= ~pipeline
[i
].outputs
;
266 if (pipeline
[i
].active
& PIPE_PRECALC
) {
267 pre
->ops
|= pipeline
[i
].ops
;
268 pre
->outputs
|= pipeline
[i
].outputs
;
269 available
|= pipeline
[i
].outputs
;
270 pre
->forbidden_inputs
|= pipeline
[i
].pre_forbidden_inputs
;
273 else if (pipeline
[i
].active
& PIPE_PRECALC
)
275 pipeline
[i
].active
&= ~PIPE_PRECALC
;
276 changed_outputs
|= pipeline
[i
].outputs
;
277 changed_ops
|= pipeline
[i
].ops
;
283 pre
->new_outputs
= pre
->outputs
& (changed_outputs
| ~oldoutputs
);
284 pre
->new_inputs
= pre
->inputs
& ~oldinputs
;
285 pre
->fallback
= pre
->inputs
& fallback
;
286 pre
->forbidden_inputs
|= pre
->inputs
& fallback
;
288 pre
->changed_ops
= changed_ops
;
291 void gl_build_precalc_pipeline( GLcontext
*ctx
)
293 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
294 struct gl_pipeline
*pre
= &tnl
->CVA
.pre
;
295 struct gl_pipeline
*elt
= &tnl
->CVA
.elt
;
297 if (!ctx
->Driver
.BuildPrecalcPipeline
||
298 !ctx
->Driver
.BuildPrecalcPipeline( ctx
))
299 build_full_precalc_pipeline( ctx
);
302 pre
->pipeline_valid
= 1;
303 elt
->pipeline_valid
= 0;
307 if (MESA_VERBOSE
&VERBOSE_PIPELINE
)
308 gl_print_pipeline( ctx
, pre
);
312 static void build_full_immediate_pipeline( GLcontext
*ctx
)
314 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
315 struct gl_pipeline_stage
*pipeline
= tnl
->PipelineStage
;
316 struct gl_cva
*cva
= &tnl
->CVA
;
317 struct gl_pipeline
*pre
= &cva
->pre
;
318 struct gl_pipeline
*elt
= &cva
->elt
;
319 struct gl_pipeline_stage
**stages
= elt
->stages
;
321 GLuint newstate
= elt
->new_state
;
322 GLuint active_ops
= 0;
323 GLuint available
= cva
->orflag
| MINIMAL_VERT_DATA
;
324 GLuint generated
= 0;
327 if (pre
->data_valid
&& tnl
->CompileCVAFlag
) {
329 active_ops
= cva
->pre
.ops
;
330 available
|= pre
->outputs
| VERT_PRECALC_DATA
;
334 elt
->outputs
= 0; /* not used */
337 for (i
= 0 ; i
< tnl
->NrPipelineStages
; i
++) {
338 pipeline
[i
].active
&= ~PIPE_IMMEDIATE
;
340 if ((pipeline
[i
].state_change
& newstate
) ||
341 (pipeline
[i
].elt_forbidden_inputs
& available
))
343 pipeline
[i
].check(ctx
, &pipeline
[i
]);
346 if ((pipeline
[i
].type
& PIPE_IMMEDIATE
) &&
347 (pipeline
[i
].ops
& active_ops
) == 0 &&
348 (pipeline
[i
].elt_forbidden_inputs
& available
) == 0
351 if (pipeline
[i
].inputs
& ~available
)
352 elt
->forbidden_inputs
|= pipeline
[i
].inputs
& ~available
;
355 elt
->inputs
|= pipeline
[i
].inputs
& ~generated
;
356 elt
->forbidden_inputs
|= pipeline
[i
].elt_forbidden_inputs
;
357 pipeline
[i
].active
|= PIPE_IMMEDIATE
;
358 *stages
++ = &pipeline
[i
];
359 generated
|= pipeline
[i
].outputs
;
360 available
|= pipeline
[i
].outputs
;
361 active_ops
|= pipeline
[i
].ops
;
368 elt
->copy_transformed_data
= 1;
369 elt
->replay_copied_vertices
= 0;
372 cva
->merge
= elt
->inputs
& pre
->outputs
;
373 elt
->ops
= active_ops
& ~pre
->ops
;
379 void gl_build_immediate_pipeline( GLcontext
*ctx
)
381 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
382 struct gl_pipeline
*elt
= &tnl
->CVA
.elt
;
384 if (!ctx
->Driver
.BuildEltPipeline
||
385 !ctx
->Driver
.BuildEltPipeline( ctx
)) {
386 build_full_immediate_pipeline( ctx
);
389 elt
->pipeline_valid
= 1;
392 if (MESA_VERBOSE
&VERBOSE_PIPELINE
)
393 gl_print_pipeline( ctx
, elt
);
396 #define INTERESTED ~0
398 void gl_update_pipelines( GLcontext
*ctx
)
400 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
401 GLuint newstate
= ctx
->NewState
;
402 struct gl_cva
*cva
= &tnl
->CVA
;
404 newstate
&= INTERESTED
;
406 if (MESA_VERBOSE
& (VERBOSE_API
|VERBOSE_STATE
))
407 gl_print_enable_flags("enabled", ctx
->_Enabled
);
411 cva
->orflag
!= cva
->last_orflag
||
412 tnl
->_ArrayFlags
!= cva
->last_array_flags
)
414 GLuint flags
= VERT_WIN
;
416 if (ctx
->Visual
.RGBAflag
) {
418 if (ctx
->_TriangleCaps
&& DD_SEPERATE_SPECULAR
)
419 flags
|= VERT_SPEC_RGB
;
423 if (ctx
->Texture
._ReallyEnabled
& TEXTURE0_ANY
)
424 flags
|= VERT_TEX0_ANY
;
426 if (ctx
->Texture
._ReallyEnabled
& TEXTURE1_ANY
)
427 flags
|= VERT_TEX1_ANY
;
429 #if MAX_TEXTURE_UNITS > 2
430 if (ctx
->Texture
._ReallyEnabled
& TEXTURE2_ANY
)
431 flags
|= VERT_TEX2_ANY
;
433 #if MAX_TEXTURE_UNITS > 3
434 if (ctx
->Texture
._ReallyEnabled
& TEXTURE3_ANY
)
435 flags
|= VERT_TEX3_ANY
;
438 if (ctx
->Polygon
._Unfilled
)
441 if (ctx
->Fog
.FogCoordinateSource
== GL_FOG_COORDINATE_EXT
)
442 flags
|= VERT_FOG_COORD
;
444 if (ctx
->RenderMode
==GL_FEEDBACK
) {
445 flags
= (VERT_WIN
| VERT_RGBA
| VERT_INDEX
| VERT_NORM
| VERT_EDGE
448 #if MAX_TEXTURE_UNITS > 2
451 #if MAX_TEXTURE_UNITS > 3
457 tnl
->_RenderFlags
= flags
;
459 cva
->elt
.new_state
|= newstate
;
460 cva
->elt
.pipeline_valid
= 0;
462 cva
->pre
.new_state
|= newstate
;
463 cva
->pre
.forbidden_inputs
= 0;
464 cva
->pre
.pipeline_valid
= 0;
465 cva
->lock_changed
= 0;
468 if (tnl
->_ArrayNewState
!= cva
->last_array_new_state
)
469 cva
->pre
.pipeline_valid
= 0;
471 cva
->pre
.data_valid
= 0;
472 cva
->last_array_new_state
= tnl
->_ArrayNewState
;
473 cva
->last_orflag
= cva
->orflag
;
474 cva
->last_array_flags
= tnl
->_ArrayFlags
;
477 void gl_run_pipeline( struct vertex_buffer
*VB
)
479 struct gl_pipeline
*pipe
= VB
->pipeline
;
480 struct gl_pipeline_stage
**stages
= pipe
->stages
;
483 pipe
->data_valid
= 1; /* optimized stages might want to reset this. */
485 if (0) gl_print_pipeline( VB
->ctx
, pipe
);
489 for ( VB
->Culled
= 0; *stages
&& !VB
->Culled
; stages
++ )
490 (*stages
)->run( VB
);