diff options
Diffstat (limited to 'src/mesa/tnl/t_pipeline.c')
-rw-r--r-- | src/mesa/tnl/t_pipeline.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c new file mode 100644 index 00000000000..03c93911b93 --- /dev/null +++ b/src/mesa/tnl/t_pipeline.c @@ -0,0 +1,496 @@ +/* $Id: t_pipeline.c,v 1.1 2000/11/16 21:05:42 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* Dynamic pipelines, support for CVA. + * Copyright (C) 1999 Keith Whitwell. + */ + +#include "glheader.h" +#include "context.h" +#include "mem.h" +#include "mmath.h" +#include "state.h" +#include "types.h" + +#include "math/m_translate.h" +#include "math/m_xform.h" + +#include "t_bbox.h" +#include "t_clip.h" +#include "t_cva.h" +#include "t_fog.h" +#include "t_light.h" +#include "t_pipeline.h" +#include "t_shade.h" +#include "t_stages.h" +#include "t_vbcull.h" +#include "t_vbindirect.h" +#include "t_vbrender.h" +#include "t_vbxform.h" + + + + + +void gl_print_pipe_ops( const char *msg, GLuint flags ) +{ + fprintf(stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s\n", + msg, + flags, + (flags & PIPE_OP_CVA_PREPARE) ? "cva-prepare, " : "", + (flags & PIPE_OP_VERT_XFORM) ? "vert-xform, " : "", + (flags & PIPE_OP_NORM_XFORM) ? "norm-xform, " : "", + (flags & PIPE_OP_LIGHT) ? "light, " : "", + (flags & PIPE_OP_FOG) ? "fog, " : "", + (flags & PIPE_OP_TEX0) ? "tex-0, " : "", + (flags & PIPE_OP_TEX1) ? "tex-1, " : "", + (flags & PIPE_OP_RAST_SETUP_0) ? "rast-0, " : "", + (flags & PIPE_OP_RAST_SETUP_1) ? "rast-1, " : "", + (flags & PIPE_OP_RENDER) ? "render, " : ""); + +} + + + +/* Have to reset only those parts of the vb which are being recalculated. + */ +void gl_reset_cva_vb( struct vertex_buffer *VB, GLuint stages ) +{ + GLcontext *ctx = VB->ctx; + TNLcontext *tnl = TNL_CONTEXT(ctx); + + if (MESA_VERBOSE&VERBOSE_PIPELINE) + gl_print_pipe_ops( "reset cva vb", stages ); + + if (stages & PIPE_OP_VERT_XFORM) + { + if (VB->ClipOrMask & CLIP_USER_BIT) + MEMSET(VB->UserClipMask, 0, VB->Count); + + VB->ClipOrMask = 0; + VB->ClipAndMask = CLIP_ALL_BITS; + VB->CullMode = 0; + VB->CullFlag[0] = VB->CullFlag[1] = 0; + VB->Culled = 0; + } + + if (stages & PIPE_OP_NORM_XFORM) { + VB->NormalPtr = &tnl->CVA.v.Normal; + } + + if (stages & PIPE_OP_LIGHT) + { + VB->ColorPtr = VB->Color[0] = VB->Color[1] = &tnl->CVA.v.Color; + VB->IndexPtr = VB->Index[0] = VB->Index[1] = &tnl->CVA.v.Index; + } + else if (stages & PIPE_OP_FOG) + { + if (ctx->Light.Enabled) { + VB->Color[0] = VB->LitColor[0]; + VB->Color[1] = VB->LitColor[1]; + VB->Index[0] = VB->LitIndex[0]; + VB->Index[1] = VB->LitIndex[1]; + } else { + VB->Color[0] = VB->Color[1] = &tnl->CVA.v.Color; + VB->Index[0] = VB->Index[1] = &tnl->CVA.v.Index; + } + VB->ColorPtr = VB->Color[0]; + VB->IndexPtr = VB->Index[0]; + } +} + + + + + + +static void pipeline_ctr( struct gl_pipeline *p, GLcontext *ctx, GLuint type ) +{ + GLuint i; + (void) ctx; + + p->state_change = 0; + p->cva_state_change = 0; + p->inputs = 0; + p->outputs = 0; + p->type = type; + p->ops = 0; + + for (i = 0 ; i < gl_default_nr_stages ; i++) + p->state_change |= gl_default_pipeline[i].state_change; +} + + +void _tnl_pipeline_init( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + + MEMCPY( tnl->PipelineStage, + gl_default_pipeline, + sizeof(*gl_default_pipeline) * gl_default_nr_stages ); + + tnl->NrPipelineStages = gl_default_nr_stages; + + pipeline_ctr( &tnl->CVA.elt, ctx, PIPE_IMMEDIATE); + pipeline_ctr( &tnl->CVA.pre, ctx, PIPE_PRECALC ); +} + + + +#define MINIMAL_VERT_DATA (VERT_DATA & ~(VERT_TEX0_4 | \ + VERT_TEX1_4 | \ + VERT_TEX2_4 | \ + VERT_TEX3_4 | \ + VERT_EVAL_ANY)) + +#define VERT_CURRENT_DATA (VERT_TEX0_1234 | \ + VERT_TEX1_1234 | \ + VERT_TEX2_1234 | \ + VERT_TEX3_1234 | \ + VERT_RGBA | \ + VERT_SPEC_RGB | \ + VERT_FOG_COORD | \ + VERT_INDEX | \ + VERT_EDGE | \ + VERT_NORM | \ + VERT_MATERIAL) + +/* Called prior to every recomputation of the CVA precalc data, except where + * the driver is able to calculate the pipeline unassisted. + */ +static void build_full_precalc_pipeline( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct gl_pipeline_stage *pipeline = tnl->PipelineStage; + struct gl_cva *cva = &tnl->CVA; + struct gl_pipeline *pre = &cva->pre; + struct gl_pipeline_stage **stages = pre->stages; + GLuint i; + GLuint newstate = pre->new_state; + GLuint changed_ops = 0; + GLuint oldoutputs = pre->outputs; + GLuint oldinputs = pre->inputs; + GLuint fallback = (VERT_CURRENT_DATA & tnl->_CurrentFlag & + ~tnl->_ArraySummary); + GLuint changed_outputs = (tnl->_ArrayNewState | + (fallback & cva->orflag)); + GLuint available = fallback | tnl->_ArrayFlags; + + pre->cva_state_change = 0; + pre->ops = 0; + pre->outputs = 0; + pre->inputs = 0; + pre->forbidden_inputs = 0; + pre->fallback = 0; + + /* KW: Disable data reuse during Mesa reorg. Make this more readable... + */ + newstate = ~0; + + if (tnl->_ArraySummary & VERT_ELT) + cva->orflag &= VERT_MATERIAL; + + cva->orflag &= ~(tnl->_ArraySummary & ~VERT_OBJ_ANY); + available &= ~cva->orflag; + + pre->outputs = available; + pre->inputs = available; + + if (MESA_VERBOSE & VERBOSE_PIPELINE) { + fprintf(stderr, ": Rebuild pipeline\n"); + gl_print_vert_flags("orflag", cva->orflag); + } + + + + /* If something changes in the pipeline, tag all subsequent stages + * using this value for recalcuation. Also used to build the full + * pipeline by setting newstate and newinputs to ~0. + * + * Because all intermediate values are buffered, the new inputs + * are enough to fully specify what needs to be calculated, and a + * single pass identifies all stages requiring recalculation. + */ + for (i = 0 ; i < tnl->NrPipelineStages ; i++) + { + pipeline[i].check(ctx, &pipeline[i]); + + if (pipeline[i].type & PIPE_PRECALC) + { + if ((newstate & pipeline[i].cva_state_change) || + (changed_outputs & pipeline[i].inputs) || + !pipeline[i].inputs) + { + changed_ops |= pipeline[i].ops; + changed_outputs |= pipeline[i].outputs; + pipeline[i].active &= ~PIPE_PRECALC; + + if ((pipeline[i].inputs & ~available) == 0 && + (pipeline[i].ops & pre->ops) == 0) + { + pipeline[i].active |= PIPE_PRECALC; + *stages++ = &pipeline[i]; + } + } + + /* Incompatible with multiple stages structs implementing + * the same stage. + */ + available &= ~pipeline[i].outputs; + pre->outputs &= ~pipeline[i].outputs; + + if (pipeline[i].active & PIPE_PRECALC) { + pre->ops |= pipeline[i].ops; + pre->outputs |= pipeline[i].outputs; + available |= pipeline[i].outputs; + pre->forbidden_inputs |= pipeline[i].pre_forbidden_inputs; + } + } + else if (pipeline[i].active & PIPE_PRECALC) + { + pipeline[i].active &= ~PIPE_PRECALC; + changed_outputs |= pipeline[i].outputs; + changed_ops |= pipeline[i].ops; + } + } + + *stages = 0; + + pre->new_outputs = pre->outputs & (changed_outputs | ~oldoutputs); + pre->new_inputs = pre->inputs & ~oldinputs; + pre->fallback = pre->inputs & fallback; + pre->forbidden_inputs |= pre->inputs & fallback; + + pre->changed_ops = changed_ops; +} + +void gl_build_precalc_pipeline( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct gl_pipeline *pre = &tnl->CVA.pre; + struct gl_pipeline *elt = &tnl->CVA.elt; + + if (!ctx->Driver.BuildPrecalcPipeline || + !ctx->Driver.BuildPrecalcPipeline( ctx )) + build_full_precalc_pipeline( ctx ); + + pre->data_valid = 0; + pre->pipeline_valid = 1; + elt->pipeline_valid = 0; + + tnl->CVA.orflag = 0; + + if (MESA_VERBOSE&VERBOSE_PIPELINE) + gl_print_pipeline( ctx, pre ); +} + + +static void build_full_immediate_pipeline( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct gl_pipeline_stage *pipeline = tnl->PipelineStage; + struct gl_cva *cva = &tnl->CVA; + struct gl_pipeline *pre = &cva->pre; + struct gl_pipeline *elt = &cva->elt; + struct gl_pipeline_stage **stages = elt->stages; + GLuint i; + GLuint newstate = elt->new_state; + GLuint active_ops = 0; + GLuint available = cva->orflag | MINIMAL_VERT_DATA; + GLuint generated = 0; + GLuint is_elt = 0; + + if (pre->data_valid && tnl->CompileCVAFlag) { + is_elt = 1; + active_ops = cva->pre.ops; + available |= pre->outputs | VERT_PRECALC_DATA; + } + + + elt->outputs = 0; /* not used */ + elt->inputs = 0; + + for (i = 0 ; i < tnl->NrPipelineStages ; i++) { + pipeline[i].active &= ~PIPE_IMMEDIATE; + + if ((pipeline[i].state_change & newstate) || + (pipeline[i].elt_forbidden_inputs & available)) + { + pipeline[i].check(ctx, &pipeline[i]); + } + + if ((pipeline[i].type & PIPE_IMMEDIATE) && + (pipeline[i].ops & active_ops) == 0 && + (pipeline[i].elt_forbidden_inputs & available) == 0 + ) + { + if (pipeline[i].inputs & ~available) + elt->forbidden_inputs |= pipeline[i].inputs & ~available; + else + { + elt->inputs |= pipeline[i].inputs & ~generated; + elt->forbidden_inputs |= pipeline[i].elt_forbidden_inputs; + pipeline[i].active |= PIPE_IMMEDIATE; + *stages++ = &pipeline[i]; + generated |= pipeline[i].outputs; + available |= pipeline[i].outputs; + active_ops |= pipeline[i].ops; + } + } + } + + *stages = 0; + + elt->copy_transformed_data = 1; + elt->replay_copied_vertices = 0; + + if (is_elt) { + cva->merge = elt->inputs & pre->outputs; + elt->ops = active_ops & ~pre->ops; + } +} + + + +void gl_build_immediate_pipeline( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct gl_pipeline *elt = &tnl->CVA.elt; + + if (!ctx->Driver.BuildEltPipeline || + !ctx->Driver.BuildEltPipeline( ctx )) { + build_full_immediate_pipeline( ctx ); + } + + elt->pipeline_valid = 1; + tnl->CVA.orflag = 0; + + if (MESA_VERBOSE&VERBOSE_PIPELINE) + gl_print_pipeline( ctx, elt ); +} + +#define INTERESTED ~0 + +void gl_update_pipelines( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint newstate = ctx->NewState; + struct gl_cva *cva = &tnl->CVA; + + newstate &= INTERESTED; + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_STATE)) + gl_print_enable_flags("enabled", ctx->_Enabled); + + if (newstate || + cva->lock_changed || + cva->orflag != cva->last_orflag || + tnl->_ArrayFlags != cva->last_array_flags) + { + GLuint flags = VERT_WIN; + + if (ctx->Visual.RGBAflag) { + flags |= VERT_RGBA; + if (ctx->_TriangleCaps && DD_SEPERATE_SPECULAR) + flags |= VERT_SPEC_RGB; + } else + flags |= VERT_INDEX; + + if (ctx->Texture._ReallyEnabled & TEXTURE0_ANY) + flags |= VERT_TEX0_ANY; + + if (ctx->Texture._ReallyEnabled & TEXTURE1_ANY) + flags |= VERT_TEX1_ANY; + +#if MAX_TEXTURE_UNITS > 2 + if (ctx->Texture._ReallyEnabled & TEXTURE2_ANY) + flags |= VERT_TEX2_ANY; +#endif +#if MAX_TEXTURE_UNITS > 3 + if (ctx->Texture._ReallyEnabled & TEXTURE3_ANY) + flags |= VERT_TEX3_ANY; +#endif + + if (ctx->Polygon._Unfilled) + flags |= VERT_EDGE; + + if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) + flags |= VERT_FOG_COORD; + + if (ctx->RenderMode==GL_FEEDBACK) { + flags = (VERT_WIN | VERT_RGBA | VERT_INDEX | VERT_NORM | VERT_EDGE + | VERT_TEX0_ANY + | VERT_TEX1_ANY +#if MAX_TEXTURE_UNITS > 2 + | VERT_TEX2_ANY +#endif +#if MAX_TEXTURE_UNITS > 3 + | VERT_TEX3_ANY +#endif + ); + } + + tnl->_RenderFlags = flags; + + cva->elt.new_state |= newstate; + cva->elt.pipeline_valid = 0; + + cva->pre.new_state |= newstate; + cva->pre.forbidden_inputs = 0; + cva->pre.pipeline_valid = 0; + cva->lock_changed = 0; + } + + if (tnl->_ArrayNewState != cva->last_array_new_state) + cva->pre.pipeline_valid = 0; + + cva->pre.data_valid = 0; + cva->last_array_new_state = tnl->_ArrayNewState; + cva->last_orflag = cva->orflag; + cva->last_array_flags = tnl->_ArrayFlags; +} + +void gl_run_pipeline( struct vertex_buffer *VB ) +{ + struct gl_pipeline *pipe = VB->pipeline; + struct gl_pipeline_stage **stages = pipe->stages; + unsigned short x; + + pipe->data_valid = 1; /* optimized stages might want to reset this. */ + + if (0) gl_print_pipeline( VB->ctx, pipe ); + + START_FAST_MATH(x); + + for ( VB->Culled = 0; *stages && !VB->Culled ; stages++ ) + (*stages)->run( VB ); + + END_FAST_MATH(x); + + pipe->new_state = 0; +} + |