X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Ftnl%2Ft_pipeline.c;h=357ef1e24b5bf4914fe2b3e3b4e31d86eb314ae3;hb=205e0e3e38b99c2fb0298755d99a38f111f0b96f;hp=60e375d753042a90554b54a1bdf31709940172e0;hpb=33b2dcf0dad710ddfb92bf63ca69fa4f67684518;p=mesa.git diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c index 60e375d7530..357ef1e24b5 100644 --- a/src/mesa/tnl/t_pipeline.c +++ b/src/mesa/tnl/t_pipeline.c @@ -1,10 +1,8 @@ -/* $Id: t_pipeline.c,v 1.6 2000/11/27 09:05:52 joukj Exp $ */ - /* * Mesa 3-D graphics library - * Version: 3.5 + * Version: 6.5.3 * - * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2007 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"), @@ -22,451 +20,196 @@ * 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. + * + * Authors: + * Keith Whitwell */ -/* 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 "mtypes.h" +#include "main/glheader.h" +#include "main/context.h" +#include "main/imports.h" +#include "main/state.h" +#include "main/mtypes.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_debug.h" -#include "t_fog.h" -#include "t_light.h" +#include "t_context.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 _tnl_print_pipe_ops( const char *msg, GLuint flags ) -{ - fprintf(stderr, - "%s: (0x%x) %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_TEX) ? "tex-gen/tex-mat, " : "", - (flags & PIPE_OP_RAST_SETUP_0) ? "rast-0, " : "", - (flags & PIPE_OP_RAST_SETUP_1) ? "rast-1, " : "", - (flags & PIPE_OP_RENDER) ? "render, " : ""); - -} - - +#include "t_vp_build.h" +#include "t_vertex.h" -/* Have to reset only those parts of the vb which are being recalculated. - */ -void _tnl_reset_cva_vb( struct vertex_buffer *VB, GLuint stages ) +void _tnl_install_pipeline( GLcontext *ctx, + const struct tnl_pipeline_stage **stages ) { - GLcontext *ctx = VB->ctx; TNLcontext *tnl = TNL_CONTEXT(ctx); - - if (MESA_VERBOSE&VERBOSE_PIPELINE) - _tnl_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; + tnl->pipeline.new_state = ~0; - for (i = 0 ; i < _tnl_default_nr_stages ; i++) - p->state_change |= _tnl_default_pipeline[i].state_change; -} - - -void _tnl_pipeline_init( GLcontext *ctx ) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); + /* Create a writeable copy of each stage. + */ + for (i = 0 ; i < MAX_PIPELINE_STAGES && stages[i] ; i++) { + struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; + MEMCPY(s, stages[i], sizeof(*s)); + if (s->create) + s->create(ctx, s); + } - MEMCPY( tnl->PipelineStage, - _tnl_default_pipeline, - sizeof(*_tnl_default_pipeline) * _tnl_default_nr_stages ); - - tnl->NrPipelineStages = _tnl_default_nr_stages; - - pipeline_ctr( &tnl->CVA.elt, ctx, PIPE_IMMEDIATE); - pipeline_ctr( &tnl->CVA.pre, ctx, PIPE_PRECALC ); + tnl->pipeline.nr_stages = i; } - - -#define MINIMAL_VERT_DATA (VERT_DATA & ~VERT_EVAL_ANY) - -#define VERT_CURRENT_DATA (VERT_TEX_ANY | \ - 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 ) +void _tnl_destroy_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->_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"); - _tnl_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; - } + for (i = 0 ; i < tnl->pipeline.nr_stages ; i++) { + struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; + if (s->destroy) + s->destroy(s); } - *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; + tnl->pipeline.nr_stages = 0; } -void _tnl_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) - _tnl_print_pipeline( ctx, pre ); -} -static void build_full_immediate_pipeline( GLcontext *ctx ) +static GLuint check_input_changes( 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; - } + + for (i = 0; i <= _TNL_LAST_MAT; i++) { + if (tnl->vb.AttribPtr[i]->size != tnl->pipeline.last_attrib_size[i] || + tnl->vb.AttribPtr[i]->stride != tnl->pipeline.last_attrib_stride[i]) { + tnl->pipeline.last_attrib_size[i] = tnl->vb.AttribPtr[i]->size; + tnl->pipeline.last_attrib_stride[i] = tnl->vb.AttribPtr[i]->stride; + tnl->pipeline.input_changes |= 1<copy_transformed_data = 1; - elt->replay_copied_vertices = 0; + if (tnl->pipeline.input_changes && + tnl->Driver.NotifyInputChanges) + tnl->Driver.NotifyInputChanges( ctx, tnl->pipeline.input_changes ); - if (is_elt) { - cva->merge = elt->inputs & pre->outputs; - elt->ops = active_ops & ~pre->ops; - } + return tnl->pipeline.input_changes; } - -void _tnl_build_immediate_pipeline( GLcontext *ctx ) +static GLuint check_output_changes( GLcontext *ctx ) { +#if 0 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 ); + + for (i = 0; i < VERT_RESULT_MAX; i++) { + if (tnl->vb.ResultPtr[i]->size != tnl->last_result_size[i] || + tnl->vb.ResultPtr[i]->stride != tnl->last_result_stride[i]) { + tnl->last_result_size[i] = tnl->vb.ResultPtr[i]->size; + tnl->last_result_stride[i] = tnl->vb.ResultPtr[i]->stride; + tnl->pipeline.output_changes |= 1<pipeline_valid = 1; - tnl->CVA.orflag = 0; - - if (MESA_VERBOSE&VERBOSE_PIPELINE) - _tnl_print_pipeline( ctx, elt ); + if (tnl->pipeline.output_changes) + tnl->Driver.NotifyOutputChanges( ctx, tnl->pipeline.output_changes ); + + return tnl->pipeline.output_changes; +#else + return ~0; +#endif } -#define INTERESTED ~0 -void _tnl_update_pipelines( GLcontext *ctx ) +void _tnl_run_pipeline( 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 j; - 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; - - for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) { - if (ctx->Texture.Unit[j]._ReallyEnabled) - flags |= VERT_TEX(j); - } - - if (ctx->Polygon._Unfilled) - flags |= VERT_EDGE; + unsigned short __tmp; + GLuint i; - if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) - flags |= VERT_FOG_COORD; + if (!tnl->vb.Count) + return; - if (ctx->RenderMode==GL_FEEDBACK) { - flags = (VERT_WIN | VERT_RGBA | VERT_INDEX | VERT_NORM | - VERT_EDGE | VERT_TEX_ANY); + /* Check for changed input sizes or change in stride to/from zero + * (ie const or non-const). + */ + if (check_input_changes( ctx ) || tnl->pipeline.new_state) { + if (ctx->VertexProgram._MaintainTnlProgram) + _tnl_UpdateFixedFunctionProgram( ctx ); + + for (i = 0; i < tnl->pipeline.nr_stages ; i++) { + struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; + if (s->validate) + s->validate( ctx, s ); } + + tnl->pipeline.new_state = 0; + tnl->pipeline.input_changes = 0; + + /* Pipeline can only change its output in response to either a + * statechange or an input size/stride change. No other changes + * are allowed. + */ + if (check_output_changes( ctx )) + _tnl_notify_pipeline_output_change( ctx ); + } - tnl->_RenderFlags = flags; - - cva->elt.new_state |= newstate; - cva->elt.pipeline_valid = 0; + START_FAST_MATH(__tmp); - cva->pre.new_state |= newstate; - cva->pre.forbidden_inputs = 0; - cva->pre.pipeline_valid = 0; - cva->lock_changed = 0; + for (i = 0; i < tnl->pipeline.nr_stages ; i++) { + struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i]; + if (!s->run( ctx, s )) + break; } - 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; + END_FAST_MATH(__tmp); } -void _tnl_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) _tnl_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; -} +/* The default pipeline. This is useful for software rasterizers, and + * simple hardware rasterizers. For customization, I don't recommend + * tampering with the internals of these stages in the way that + * drivers did in Mesa 3.4. These stages are basically black boxes, + * and should be left intact. + * + * To customize the pipeline, consider: + * + * - removing redundant stages (making sure that the software rasterizer + * can cope with this on fallback paths). An example is fog + * coordinate generation, which is not required in the FX driver. + * + * - replacing general-purpose machine-independent stages with + * general-purpose machine-specific stages. There is no example of + * this to date, though it must be borne in mind that all subsequent + * stages that reference the output of the new stage must cope with + * any machine-specific data introduced. This may not be easy + * unless there are no such stages (ie the new stage is the last in + * the pipe). + * + * - inserting optimized (but specialized) stages ahead of the + * general-purpose fallback implementation. For example, the old + * fastpath mechanism, which only works when the VB->Elts input is + * available, can be duplicated by placing the fastpath stage at the + * head of this pipeline. Such specialized stages are currently + * constrained to have no outputs (ie. they must either finish the * + * pipeline by returning GL_FALSE from run(), or do nothing). + * + * Some work can be done to lift some of the restrictions in the final + * case, if it becomes necessary to do so. + */ +const struct tnl_pipeline_stage *_tnl_default_pipeline[] = { + &_tnl_vertex_transform_stage, + &_tnl_normal_transform_stage, + &_tnl_lighting_stage, + &_tnl_texgen_stage, + &_tnl_texture_transform_stage, + &_tnl_point_attenuation_stage, + &_tnl_vertex_program_stage, + &_tnl_fog_coordinate_stage, + &_tnl_render_stage, + NULL +}; + +const struct tnl_pipeline_stage *_tnl_vp_pipeline[] = { + &_tnl_vertex_program_stage, + &_tnl_render_stage, + NULL +};