head	3.20;
access;
symbols
	merge-1:3.14.2.8
	autoconf:3.14.0.4
	experimental-1:3.14.0.2;
locks; strict;
comment	@ * @;


3.20
date	99.08.03.14.42.02;	author keithw;	state Exp;
branches;
next	3.19;

3.19
date	99.08.02.23.28.20;	author keithw;	state Exp;
branches;
next	3.18;

3.18
date	99.07.20.22.35.20;	author keithw;	state Exp;
branches;
next	3.17;

3.17
date	99.07.12.15.11.51;	author brianp;	state Exp;
branches;
next	3.16;

3.16
date	99.07.12.12.05.24;	author keithw;	state Exp;
branches;
next	3.15;

3.15
date	99.06.07.12.07.07;	author keithw;	state Exp;
branches;
next	3.14;

3.14
date	99.05.16.17.09.59;	author keithw;	state Exp;
branches
	3.14.2.1;
next	3.13;

3.13
date	99.05.02.00.59.24;	author keithw;	state Exp;
branches;
next	3.12;

3.12
date	99.04.29.14.43.16;	author keithw;	state Exp;
branches;
next	3.11;

3.11
date	99.04.28.22.55.40;	author keithw;	state Exp;
branches;
next	3.10;

3.10
date	99.04.24.21.53.04;	author keithw;	state Exp;
branches;
next	3.9;

3.9
date	99.04.24.13.21.43;	author keithw;	state Exp;
branches;
next	3.8;

3.8
date	99.04.24.01.08.02;	author keithw;	state Exp;
branches;
next	3.7;

3.7
date	99.04.23.16.14.21;	author keithw;	state Exp;
branches;
next	3.6;

3.6
date	99.04.07.22.26.03;	author brianp;	state Exp;
branches;
next	3.5;

3.5
date	99.04.07.22.23.58;	author brianp;	state Exp;
branches;
next	3.4;

3.4
date	99.04.07.22.19.04;	author brianp;	state Exp;
branches;
next	3.3;

3.3
date	99.04.06.01.11.49;	author keithw;	state Exp;
branches;
next	3.2;

3.2
date	99.04.01.14.23.37;	author joukj;	state Exp;
branches;
next	3.1;

3.1
date	99.03.31.20.18.39;	author keithw;	state Exp;
branches;
next	;

3.14.2.1
date	99.05.21.21.29.26;	author keithw;	state Exp;
branches;
next	3.14.2.2;

3.14.2.2
date	99.05.22.19.14.39;	author keithw;	state Exp;
branches;
next	3.14.2.3;

3.14.2.3
date	99.05.24.02.13.39;	author keithw;	state Exp;
branches;
next	3.14.2.4;

3.14.2.4
date	99.05.30.13.30.34;	author keithw;	state Exp;
branches;
next	3.14.2.5;

3.14.2.5
date	99.06.01.00.45.21;	author keithw;	state Exp;
branches;
next	3.14.2.6;

3.14.2.6
date	99.06.06.22.35.54;	author keithw;	state Exp;
branches;
next	3.14.2.7;

3.14.2.7
date	99.06.19.15.04.14;	author keithw;	state Exp;
branches;
next	3.14.2.8;

3.14.2.8
date	99.07.05.19.42.32;	author keithw;	state Exp;
branches;
next	;


desc
@@


3.20
log
@fixes for bugs from eero and miklos
@
text
@/* $Id: pipeline.c,v 3.19 1999/08/02 23:28:20 keithw Exp $ */

/*
 * Mesa 3-D graphics library
 * Version:  3.1
 * 
 * Copyright (C) 1999  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 "bbox.h"
#include "clip.h"
#include "context.h"
#include "cva.h"
#include "pipeline.h"
#include "vbcull.h"
#include "vbindirect.h"
#include "vbrender.h"
#include "vbxform.h"
#include "fog.h"
#include "light.h"
#include "mmath.h"
#include "shade.h"
#include "stages.h"
#include "types.h"
#include "translate.h"
#include "xform.h"
#include <stdio.h>

#ifndef MESA_VERBOSE
int MESA_VERBOSE = 0 
               | VERBOSE_PIPELINE
/*                 | VERBOSE_IMMEDIATE */
/*                 | VERBOSE_VARRAY */
/*                 | VERBOSE_TEXTURE */
/*                 | VERBOSE_API */
/*                 | VERBOSE_DRIVER */
/*                 | VERBOSE_STATE */
;
#endif

#ifndef MESA_DEBUG_FLAGS
int MESA_DEBUG_FLAGS = 0 
/*                 | DEBUG_ALWAYS_FLUSH */
;
#endif



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;

   if (MESA_VERBOSE&VERBOSE_PIPELINE)
      gl_print_pipe_ops( "reset cva vb", stages ); 

   if (ctx->Driver.ResetCvaVB)
      ctx->Driver.ResetCvaVB( 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;
      VB->LastCount = VB->Count;
   }

   if (stages & PIPE_OP_NORM_XFORM) {
      VB->NormalPtr = &ctx->CVA.v.Normal;
   }

   if (stages & PIPE_OP_LIGHT) 
   {
      VB->ColorPtr = VB->Color[0] = VB->Color[1] = &ctx->CVA.v.Color;
      VB->IndexPtr = VB->Index[0] = VB->Index[1] = &ctx->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] = &ctx->CVA.v.Color;
	 VB->Index[0] = VB->Index[1] = &ctx->CVA.v.Index;
      }
      VB->ColorPtr = VB->Color[0];
      VB->IndexPtr = VB->Index[0];
   }
}




static const char *pipeline_name[3] = {
   0,
   "Immediate",
   "CVA Precalc",
};



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 gl_pipeline_init( GLcontext *ctx )
{
   if (ctx->Driver.RegisterPipelineStages)
      ctx->NrPipelineStages = 
	 ctx->Driver.RegisterPipelineStages( ctx->PipelineStage,
					     gl_default_pipeline,
					     gl_default_nr_stages );
   else 
   {
      MEMCPY( ctx->PipelineStage, 
	      gl_default_pipeline, 
	      sizeof(*gl_default_pipeline) * gl_default_nr_stages );

      ctx->NrPipelineStages = gl_default_nr_stages;
   }

   pipeline_ctr( &ctx->CVA.elt, ctx, PIPE_IMMEDIATE);
   pipeline_ctr( &ctx->CVA.pre, ctx, PIPE_PRECALC );
}






#define MINIMAL_VERT_DATA (VERT_DATA&~(VERT_TEX0_4|VERT_TEX1_4|VERT_EVAL_ANY))

#define VERT_CURRENT_DATA (VERT_TEX0_1234|VERT_TEX1_1234|VERT_RGBA| \
			   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.
 */
void gl_build_full_precalc_pipeline( GLcontext *ctx )
{
   struct gl_pipeline_stage *pipeline = ctx->PipelineStage;
   struct gl_cva *cva = &ctx->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 & ctx->Current.Flag & 
		      ~ctx->Array.Summary);
   GLuint changed_outputs = (ctx->Array.NewArrayState | 
			     (fallback & cva->orflag));
   GLuint available = fallback | ctx->Array.Flags;

   pre->cva_state_change = 0;
   pre->generated = 0;
   pre->ops = 0;
   pre->outputs = 0;
   pre->inputs = 0;
   pre->forbidden_inputs = 0;
   pre->fallback = 0;
   
   if (ctx->Array.Summary & VERT_ELT) 
      cva->orflag &= VERT_MATERIAL;
  
   cva->orflag &= ~ctx->Array.Summary;
   available &= ~cva->orflag;
   
   pre->outputs = available;
   pre->inputs = available;

   if (MESA_VERBOSE & VERBOSE_PIPELINE)
      fprintf(stderr, ": Rebuild pipeline\n");
      
   /* 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 < ctx->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->inputs |= pipeline[i].inputs & ~pre->generated; */
/*  	    pre->outputs |= pipeline[i].inputs & ~pre->generated; */
	    pre->generated |= pipeline[i].outputs;
	    pre->outputs |= pipeline[i].outputs;
	    available |= pipeline[i].outputs;
	    pre->forbidden_inputs |= pipeline[i].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;

   if (ctx->Driver.OptimizePrecalcPipeline)
      ctx->Driver.OptimizePrecalcPipeline( ctx, pre );
}

void gl_build_precalc_pipeline( GLcontext *ctx )
{
   struct gl_pipeline *pre = &ctx->CVA.pre;   
   struct gl_pipeline *elt = &ctx->CVA.elt;   

   if (!ctx->Driver.BuildPrecalcPipeline ||
       !ctx->Driver.BuildPrecalcPipeline( ctx ))
      gl_build_full_precalc_pipeline( ctx );

   pre->data_valid = 0;
   pre->pipeline_valid = 1;
   elt->pipeline_valid = 0;
   
   pre->new_state = 0;
   elt->new_state = 0;
   ctx->CVA.orflag = 0;
   
   if (MESA_VERBOSE&VERBOSE_PIPELINE)
      gl_print_pipeline( ctx, pre ); 
}


void gl_build_immediate_pipeline( GLcontext *ctx )
{
   struct gl_pipeline_stage *pipeline = ctx->PipelineStage;
   struct gl_cva *cva = &ctx->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 && ctx->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 < ctx->NrPipelineStages ; i++) {
      pipeline[i].active &= ~PIPE_IMMEDIATE;

      if ((pipeline[i].state_change & newstate) ||
  	  (pipeline[i].forbidden_inputs & available)) 
      {
	 pipeline[i].check(ctx, &pipeline[i]);
      }

      if ((pipeline[i].type & PIPE_IMMEDIATE) &&
	  (pipeline[i].ops & active_ops) == 0 
/*  	  && (pipeline[i].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].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;

   if (is_elt) {
      cva->merge = elt->inputs & pre->outputs;
      elt->ops = active_ops & ~pre->ops;
   }
   
   elt->generated = generated;
   elt->pipeline_valid = 1;
   elt->new_state = 0;

   if (MESA_VERBOSE&VERBOSE_PIPELINE)
      gl_print_pipeline( ctx, elt ); 
}
   
#define INTERESTED ~(NEW_DRIVER_STATE|NEW_CLIENT_STATE|NEW_TEXTURE_ENABLE)

void gl_update_pipelines( GLcontext *ctx )
{
   GLuint newstate = ctx->NewState;
   struct gl_cva *cva = &ctx->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 ||
       ctx->Array.Flags != cva->last_array_flags)
   {   
      GLuint flags = VERT_WIN;

      if (ctx->Visual->RGBAflag) 
	 flags |= VERT_RGBA;
      else 
	 flags |= VERT_INDEX;

      if (ctx->Texture.Enabled & 0xf) {
	 if (ctx->Texture.Unit[0].EnvMode == GL_REPLACE)
	    flags &= ~VERT_RGBA;

	 flags |= VERT_TEX0_ANY;
      }

      if (ctx->Texture.Enabled & 0xf0)
	 flags |= VERT_TEX1_ANY;
   
      if (ctx->Polygon.Unfilled) 
	 flags |= VERT_EDGE;
 
      if (ctx->RenderMode==GL_FEEDBACK) 
      {
	 flags = (VERT_WIN|VERT_RGBA|VERT_INDEX|
		  VERT_NORM|VERT_EDGE|
		  VERT_TEX0_ANY|VERT_TEX1_ANY);
      }

      ctx->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 (ctx->Array.NewArrayState != cva->last_array_new_state)
      cva->pre.pipeline_valid = 0;

   cva->pre.data_valid = 0;
   cva->last_array_new_state = ctx->Array.NewArrayState;
   cva->last_orflag = cva->orflag;
   cva->last_array_flags = ctx->Array.Flags;
}

void gl_run_pipeline( struct vertex_buffer *VB )
{
   struct gl_pipeline *pipe = VB->pipeline;
   struct gl_pipeline_stage **stages = pipe->stages;
   
   pipe->data_valid = 1;	/* optimized stages might want to reset this. */

   START_FAST_MATH;
   
   for ( VB->Culled = 0; *stages && !VB->Culled ; stages++ ) 
      (*stages)->run( VB );
      
   END_FAST_MATH;
}

void gl_print_vert_flags( const char *name, GLuint flags ) 
{
   fprintf(stderr, 
	   "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
	   name,
	   flags,
	   (flags & VERT_OBJ_ANY)    ? "vertices, " : "",
	   (flags & VERT_ELT)        ? "array-elt, " : "",
	   (flags & VERT_RGBA)       ? "colors, " : "",
	   (flags & VERT_NORM)       ? "normals, " : "",
	   (flags & VERT_INDEX)      ? "index, " : "",
	   (flags & VERT_EDGE)       ? "edgeflag, " : "",
	   (flags & VERT_MATERIAL)   ? "material, " : "",
	   (flags & VERT_TEX0_ANY)   ? "texcoord0, " : "",
	   (flags & VERT_TEX1_ANY)   ? "texcoord1, " : "",
	   (flags & VERT_EVAL_ANY)   ? "eval-coord, " : "",
	   (flags & VERT_EYE)        ? "eye, " : "",
	   (flags & VERT_WIN)        ? "win, " : "",
	   (flags & VERT_PRECALC_DATA) ? "precalc data, " : "",
	   (flags & VERT_SETUP_FULL) ? "driver-data, " : "", 
	   (flags & VERT_SETUP_PART) ? "partial-driver-data, " : ""
      );
}

void gl_print_tri_caps( const char *name, GLuint flags ) 
{
   fprintf(stderr, 
	   "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
	   name,
	   flags,
	   (flags & DD_FEEDBACK)            ? "feedback, " : "",
	   (flags & DD_SELECT)              ? "select, " : "",
	   (flags & DD_FLATSHADE)           ? "flat-shade, " : "",
	   (flags & DD_MULTIDRAW)           ? "multidraw, " : "",
	   (flags & DD_SEPERATE_SPECULAR)   ? "seperate-specular, " : "",
	   (flags & DD_TRI_LIGHT_TWOSIDE)   ? "tri-light-twoside, " : "",
	   (flags & DD_TRI_UNFILLED)        ? "tri-unfilled, " : "",
	   (flags & DD_TRI_STIPPLE)         ? "tri-stipple, " : "",
	   (flags & DD_TRI_OFFSET)          ? "tri-offset, " : "",
	   (flags & DD_TRI_CULL)            ? "tri-bf-cull, " : "",
	   (flags & DD_LINE_SMOOTH)         ? "line-smooth, " : "",
	   (flags & DD_LINE_STIPPLE)        ? "line-stipple, " : "",
	   (flags & DD_LINE_WIDTH)          ? "line-wide, " : "",
	   (flags & DD_POINT_SMOOTH)        ? "point-smooth, " : "", 
	   (flags & DD_POINT_SIZE)          ? "point-size, " : "", 
	   (flags & DD_POINT_ATTEN)         ? "point-atten, " : "", 
	   (flags & DD_EARLY_CULL)          ? "do-cull, " : "", 
	   (flags & DD_POINT_SW_RASTERIZE)  ? "sw-points, " : "", 
	   (flags & DD_LINE_SW_RASTERIZE)   ? "sw-lines, " : "", 
	   (flags & DD_TRI_SW_RASTERIZE)    ? "sw-tris, " : "", 
	   (flags & DD_QUAD_SW_RASTERIZE)   ? "sw-quads, " : ""
      );
}


void gl_print_pipeline( GLcontext *ctx, struct gl_pipeline *p )
{
   struct gl_pipeline_stage *pipeline = ctx->PipelineStage;
/*     struct gl_pipeline_stage **stages = p->stages; */
   GLuint i;

   fprintf(stderr,"Type: %s\n", pipeline_name[p->type]);

   if (!p->pipeline_valid) {
      printf("--> Not up to date!!!\n");
      return;
   }

   gl_print_vert_flags("Inputs", p->inputs);
   gl_print_vert_flags("Forbidden", p->forbidden_inputs);
   gl_print_vert_flags("Outputs", p->outputs);

   for (i = 0 ; i < ctx->NrPipelineStages ; i++) 
      if (pipeline[i].active & p->type) {
	 fprintf(stderr,"%u: %s\n", i, pipeline[i].name);

/*  	 if (p->type == PIPE_PRECALC && *stages == &pipeline[i]) { */
/*  	    stages++; */
/*  	    fprintf(stderr,"\t--> needs precalc\n"); */
/*  	 } */

	 gl_print_vert_flags("\tinputs", pipeline[i].inputs);
	 gl_print_vert_flags("\toutputs", pipeline[i].outputs);

	 if (p->type == PIPE_PRECALC && pipeline[i].forbidden_inputs)
	    gl_print_vert_flags("\tforbidden", 
				pipeline[i].forbidden_inputs);
      }

   if (p->type == PIPE_PRECALC) {
      struct gl_pipeline_stage **stages = p->stages;
      fprintf(stderr,"\nStages requiring precalculation:\n");
      for ( i=0 ; stages[i] ; i++) {
	 fprintf(stderr, "%u: %s\n", i, stages[i]->name);
	 gl_print_vert_flags("\tinputs", stages[i]->inputs);
	 gl_print_vert_flags("\toutputs", stages[i]->outputs);
	 if (stages[i]->forbidden_inputs)
	    gl_print_vert_flags("\tforbidden", stages[i]->forbidden_inputs);
      }
   }
}



void gl_print_active_pipeline( GLcontext *ctx, struct gl_pipeline *p )
{
   struct gl_pipeline_stage **stages = p->stages;
   GLuint i;

   (void) ctx;

   fprintf(stderr,"Type: %s\n", pipeline_name[p->type]);

   if (!p->pipeline_valid) {
      printf("--> Not up to date!!!\n");
      return;
   }

   gl_print_vert_flags("Inputs", p->inputs);
   gl_print_vert_flags("Forbidden", p->forbidden_inputs);
   gl_print_vert_flags("Outputs", p->outputs);

   for ( i=0 ; stages[i] ; i++) {
      fprintf(stderr, "%u: %s\n", i, stages[i]->name);

      gl_print_vert_flags("\tinputs", stages[i]->inputs);
      gl_print_vert_flags("\toutputs", stages[i]->outputs);

      if (p->type == PIPE_PRECALC && stages[i]->forbidden_inputs)
	    gl_print_vert_flags("\tforbidden", 
				stages[i]->forbidden_inputs);
      }
}


@


3.19
log
@fix for miklos' cva line bug
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.18 1999/07/20 22:35:20 keithw Exp $ */
d58 1
a58 1
               | VERBOSE_DRIVER
d201 2
a202 1
/* Called prior to every recomputation of the CVA precalc data.
d229 1
a229 1
   if (ctx->Array.Summary & VERT_ELT) {
d231 6
a236 3
   }

   available &= ctx->Array.Summary | ~cva->orflag;
d279 2
a280 2
	    pre->inputs |= pipeline[i].inputs & ~pre->generated;
	    pre->outputs |= pipeline[i].inputs & ~pre->generated;
a324 2


a389 2
   ctx->Flags = PIPE_FLAGS_TO_VERT_FLAGS(elt->inputs); 

@


3.18
log
@line clipping and rasterization bugs
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.17 1999/07/12 15:11:51 brianp Exp $ */
d53 1
a53 1
/*                 | VERBOSE_PIPELINE */
d58 1
a58 1
/*                 | VERBOSE_DRIVER */
d226 1
d295 1
@


3.17
log
@silenced compiler warnings
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.16 1999/07/12 12:05:24 keithw Exp $ */
d496 30
@


3.16
log
@merge from experimental branch upto merge-1 tag
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.15 1999/06/07 12:07:07 keithw Exp $ */
d538 1
a538 1
	 fprintf(stderr, "%d: %s\n", i, stages[i]->name);
d554 2
d568 1
a568 1
      fprintf(stderr, "%d: %s\n", i, stages[i]->name);
@


3.15
log
@Bugfix for bug reported by Eero
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14 1999/05/16 17:09:59 keithw Exp $ */
d45 1
d47 1
d51 17
a68 1
GLmatrix gl_identity_mat;
d71 1
a71 1
void gl_init_vbxform()
d73 15
a87 1
   gl_matrix_ctr( &gl_identity_mat );
d98 10
a107 1
   if (stages & PIPE_OP_VERT_XFORM) {
a108 4
      if (VB->CullMode & (CULL_MASK_ACTIVE|CLIP_MASK_ACTIVE)) {
	 MEMSET(VB->ClipMask, 0, VB->Count);	
      }
 
d112 1
d117 1
a117 1
   if (stages & PIPE_OP_NORM_XFORM) 
d119 2
a120 1
   
d123 2
a124 2
      VB->Color[0] = VB->Color[1] = &ctx->CVA.v.Color;
      VB->Index[0] = VB->Index[1] = &ctx->CVA.v.Index;
d137 2
a142 844
/* KW: Even if all the vertices are clipped or culled, still need to
 *     execute the material changes.
 * 
 *     TODO: Do this backwards, from count to start.  
 */
void gl_update_materials( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   GLuint orflag = VB->OrFlag;

   if (orflag & VERT_MATERIAL) 
   {
      GLuint i;
      GLuint cm_flag, interesting;
      GLubyte (*CMcolor)[4];
      GLuint *flag = VB->Flag;
      struct gl_material (*new_material)[2] = VB->Material;
      GLuint *new_material_mask = VB->MaterialMask;

      if (ctx->Light.ColorMaterialEnabled) {
	 cm_flag = VERT_RGBA;
	 interesting = VERT_END_VB | VERT_RGBA | VERT_MATERIAL;
	 CMcolor = (GLubyte (*)[4])VB->ColorPtr->start - VB->Start;
      }
      else 
      {
	 CMcolor = 0;
	 cm_flag = 0;
	 interesting = VERT_END_VB | VERT_MATERIAL;
      }

      for ( i = VB->Start ; i <= VB->Count ; i++ ) 
      {
	 while (!(flag[i] & interesting)) i++;
	 
	 if ( flag[i] & cm_flag ) 
	    gl_update_color_material( ctx, CMcolor[i] );
	 
	 if ( flag[i] & VERT_MATERIAL )
	    gl_update_material( ctx, new_material[i], new_material_mask[i] );
      }
   }
   else if ((orflag & VERT_RGBA) && ctx->Light.ColorMaterialEnabled) 
      gl_update_color_material( ctx, ctx->Current.ByteColor );   
}


/* Todo: work this out in advance.
 */
static void import_outstanding_data( struct vertex_buffer *VB )
{
   GLuint i;
   GLuint flags = VB->ctx->Flags;

   /* Can happen if ModelView and Projection matrices are both the
    * identity - GL is just the rasterizer.  Unfortunately we need to
    * copy the data for clipping or because a primitive overlapped the
    * end of the VB last time around.
    */
   if (!(VB->ClipPtr->flags & VEC_WRITABLE)) {      
      VB->ClipPtr = Transform( &VB->Clip,
			       &gl_identity_mat,
			       VB->ClipPtr,
			       VB->ClipMask + VB->Start,
			       VB->CullFlag[0]);
   }

   if ((flags & VERT_RGBA) &&
       !(VB->ColorPtr->flags & VEC_WRITABLE)) 
   {
      GLuint stride = VB->ColorPtr->stride;
      GLubyte *ptr = (GLubyte *)VB->ColorPtr->start;
      GLubyte (*dest)[4] = VB->LitColor[0]->data;
      for (i = VB->Start ; i < VB->Count ; i++, ptr += stride) {
	 COPY_4UBV( dest[i], ptr );
      }
      VB->ColorPtr = VB->LitColor[0];
   }

   if ((flags & VERT_INDEX) &&
       !(VB->IndexPtr->flags & VEC_WRITABLE)) 
   {
      GLuint stride = VB->IndexPtr->stride;
      GLuint *ptr = VB->IndexPtr->start;
      GLuint *dest = VB->store.Index->data;
      for (i = VB->Start ; i < VB->Count ; i++, 
	      ptr = (GLuint *)((GLubyte*)ptr + stride)) {
	 dest[i] = *ptr;
      }
      VB->IndexPtr = VB->store.Index;
   }

   if ((flags & VERT_TEX0_ANY) &&
       !(VB->TexCoordPtr[0]->flags & VEC_WRITABLE)) 
   {
      VB->TexCoordPtr[0] = Transform(VB->store.TexCoord[0],
				     &gl_identity_mat, 
				     VB->TexCoordPtr[0],
				     VB->ClipMask + VB->Start,
				     VB->CullFlag[0]);      
   }

   if ((flags & VERT_TEX1_ANY) && 
       !(VB->TexCoordPtr[1]->flags & VEC_WRITABLE)) 
   {
      VB->TexCoordPtr[1] = Transform(VB->store.TexCoord[1],
				     &gl_identity_mat, 
				     VB->TexCoordPtr[1],
				     VB->ClipMask + VB->Start,
				     VB->CullFlag[0]);      
   }
}




#if 0
/* Figure this is too rare to update via UpdateState, so give it a
 * flag of its own.  
 */
static void gl_calculate_model_project_win_matrix( GLcontext *ctx )
{
    gl_matrix_mul( &ctx->ModelProjectWinMatrix,
		   &ctx->Viewport.WindowMap,
		   &ctx->ModelProjectMatrix );

   gl_matrix_analyze( &ctx->ModelProjectWinMatrix );
   ctx->ModelProjectWinMatrixUptodate = GL_TRUE;
}
#endif



static void bound_cull_vb( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   VB->Projected = &VB->Win;
   VB->ClipPtr = &VB->Clip;
   VB->Culled = 1;

/*    printf("bound cull vb\n"); */

   gl_dont_cull_vb( VB );

   {
      GLuint start = 3 - VB->CopyCount;
      GLuint dst;
      GLuint *copy = VB->Copy;
      GLmatrix *mat = &ctx->ModelProjectMatrix;
      
      for (dst = start ; dst < VB->Start ; dst++) {
	 GLfloat *src = VEC_ELT(VB->ObjPtr, GLfloat, copy[dst]);
	 GLfloat *clip = VB->Clip.data[copy[dst]];
	 gl_transform_point_sz( clip, mat->m, src, VB->ObjPtr->size );
	 {
	    const GLfloat cw = clip[3];
	    const GLfloat cx = clip[0];
	    const GLfloat cy = clip[1];
	    const GLfloat cz = clip[2]; 
	    GLuint mask = 0;
	    if (cx >  cw) mask |= CLIP_RIGHT_BIT;
	    if (cx < -cw) mask |= CLIP_LEFT_BIT;
	    if (cy >  cw) mask |= CLIP_TOP_BIT;
	    if (cy < -cw) mask |= CLIP_BOTTOM_BIT;
	    if (cz >  cw) mask |= CLIP_FAR_BIT;
	    if (cz < -cw) mask |= CLIP_NEAR_BIT;
	    VB->ClipMask[copy[dst]] = mask;
	 }
      }
   }
}





static void do_vertex_pipeline( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   GLmatrix *proj_mat = ctx->vb_proj_matrix;
   GLvector4f *proj_dest = &VB->Clip;
   GLboolean need_window_transform = (1 || ctx->DoViewportMapping);
   GLubyte needclip;
   GLuint copycount = VB->CopyCount;

#define ADJ_VEC_STRIDE(v, c) (STRIDE_F((v)->start, -(c)*(v)->stride), (v)->count+=(c))


   /* Eye transform
    */
   VB->Unprojected = VB->ObjPtr;

   if (ctx->NeedEyeCoords && ctx->ModelView.type != MATRIX_IDENTITY)
      VB->Unprojected = TransformRaw( &VB->Eye, &ctx->ModelView, VB->ObjPtr );

   VB->EyePtr = VB->Unprojected;



   /* Bounding box check - never in cva or immediate.  Simulate a 
    * bounding box inclusion if clipping is disabled.
    */
   needclip = ~0;      
   if (0 && VB->ctx->Hint.ClipVolumeClipping != GL_FASTEST) {

      needclip = ~0;

      if (VB->BoundsPtr) {
	 GLubyte andmask = VB->ClipAndMask, ormask = VB->ClipOrMask;

	 gl_test_bound_tab[VB->ObjPtr->size]( &ormask, &andmask, 
					      &ctx->ModelProjectMatrix, 
					      VB->BoundsPtr );

       	 if (andmask) {
	    bound_cull_vb( VB );
	    gl_update_materials( VB );
	    return;
	 }
	 
	 needclip = ormask;

#if 0
	 /* Maybe combine the window transform into the clip transform.
	  */
	 if (!ormask && !ctx->NeedEyeCoords && !ctx->NeedClipCoords) {
	    if (!ctx->ModelProjectWinMatrixUptodate) 
	       gl_calculate_model_project_win_matrix( ctx );
	    proj_mat = &ctx->ModelProjectWinMatrix;
	    proj_dest = &VB->Win;
	    need_window_transform = 0;
	 }
#endif
      } 
   }


   /* Clip transform.
    */
   VB->ClipPtr = VB->Unprojected;

   if (proj_mat->type != MATRIX_IDENTITY ||
       (ctx->NeedCull && VB->Unprojected->stride != 4*sizeof(GLfloat))) 
   {
      VB->ClipPtr = TransformRaw(proj_dest, proj_mat, VB->Unprojected );
   } 




   /* Cliptest and/or perspective divide.
    */

   if (needclip)
   {
      VB->Projected = gl_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
						      &VB->Win,
						      VB->ClipMask + VB->Start,
						      &VB->ClipOrMask, 
						      &VB->ClipAndMask );
      if (VB->ClipOrMask) 
	 VB->CullMode |= CLIP_MASK_ACTIVE;      

      if (VB->ClipAndMask) {
	 VB->Culled = 1;	 
	 gl_update_materials(VB);
	 return;      
      }
   } 
   else if (VB->ClipPtr->size == 4) 
   {
      VB->Projected = gl_project_points( &VB->Win, VB->ClipPtr );
   }
   else
   {
      VB->Projected = VB->ClipPtr;
      gl_vector4f_clean_elem(&VB->Win, VB->Count, 3);
   }


   /* User cliptest.
    */
   if (ctx->Transform.AnyClip && !gl_user_cliptest( VB )) {
      VB->Culled = 1;
      gl_update_materials(VB);
      return;
   }
   


   /* Vertex culling - not for cva precalc.
    */
   if (VB->EarlyCull && (VB->ClipOrMask || ctx->NeedCull))
   {
      GLuint cullcount = gl_cull_vb( VB );      
      if (cullcount == VB->Count) { 
	 VB->Culled = 1; 
	 gl_update_materials(VB);
	 return; 
      }
      if (cullcount || ctx->LightTwoSide) VB->CullMode |= CULL_MASK_ACTIVE;
   }
   else if (VB->IM) {
      gl_dont_cull_vb( VB );
   }



   /* Fixup for glDrawArrays.
    */
   if (VB->Type == VB_IMMEDIATE && 
      (VB->ClipOrMask || VB->CopyCount != 0)) 
      import_outstanding_data( VB ); 
   


   /* Window transform.
    */
   if (need_window_transform) {

      if (VB->Start != VB->CopyStart) {
	 ADJ_VEC_STRIDE( VB->Projected, copycount );
	 VB->Win.start = (GLfloat *)VB->Win.data[VB->CopyStart];
      }

      (void) Transform( &VB->Win,
			&ctx->Viewport.WindowMap, 
			VB->Projected, 
			VB->ClipMask + VB->CopyStart,
			VB->CullFlag[1]);

      if (VB->Win.size == 2) 
	 gl_vector4f_clean_elem(&VB->Win, VB->Count, 2);      
   }      
}






static void do_normal_transform( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   GLuint tmp = 0;

   if (VB->Type == VB_CVA_PRECALC) 
      VB->NormalPtr = &ctx->CVA.v.Normal;


   if (VB->CullMode & (COMPACTED_NORMALS|CULL_MASK_ACTIVE)) {
      tmp = 1;
      gl_make_normal_cullmask( VB );
   }
	 
   (ctx->NormalTransform[tmp])(&ctx->ModelView,
			       ctx->vb_rescale_factor,
			       VB->NormalPtr,
			       VB->NormalLengthPtr ? VB->NormalLengthPtr + VB->Start : 0,
			       VB->NormCullStart,
			       VB->store.Normal);
	    
   VB->NormalPtr = VB->store.Normal;
}



static void do_lighting( struct vertex_buffer *VB )
{
   GLubyte flags = VB->CullMode & (CULL_MASK_ACTIVE|COMPACTED_NORMALS);

   if ((flags&CULL_MASK_ACTIVE) && !VB->NormCullStart)
      gl_make_normal_cullmask( VB );

   gl_shade_func_tab[VB->ctx->shade_func_flags | flags]( VB );
}   



static void do_update_materials( struct vertex_buffer *VB )
{
   gl_update_materials( VB );
}   


static void do_texture_0( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   
   if (ctx->Texture.Unit[0].TexGenEnabled) 
      (ctx->Texture.Unit[0].func[VB->CullMode & 0x3])( VB, 0 );

   if (VB->TexCoordPtr[0]->stride != 4*sizeof(GLfloat) ||
       ctx->TextureMatrix[0].type != MATRIX_IDENTITY) 
   {
      VB->TexCoordPtr[0] = Transform( VB->store.TexCoord[0],
				      &ctx->TextureMatrix[0], 
				      VB->TexCoordPtr[0], 
				      VB->ClipMask + VB->Start,
				      VB->CullFlag[0]);
   }
}


static void do_texture_1( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;

   if (ctx->Texture.Unit[1].TexGenEnabled) 
      (ctx->Texture.Unit[1].func[VB->CullMode & 0x3])( VB, 1 );

   if (VB->TexCoordPtr[1]->stride != 4*sizeof(GLfloat) ||
       ctx->TextureMatrix[1].type != MATRIX_IDENTITY) 
   {
      VB->TexCoordPtr[1] = Transform( VB->store.TexCoord[1],
				      &ctx->TextureMatrix[1], 
				      VB->TexCoordPtr[1], 
				      VB->ClipMask + VB->Start,
				      VB->CullFlag[0]);
   }
}




/* Inputs: ArrayElt + (ctx->Flags - ctx->Array.LockPrecalcOutputs)
 * Outputs: nil.
 *
 * Kinda hard to compute the inputs, but once done, 
 */
static void do_merge_and_render( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   ctx->Driver.MergeAndRenderCVA( VB, ctx->CVA.VB );
}


static void do_indirect_render( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   ctx->Driver.RenderVBIndirect( VB, ctx->CVA.VB );
}


static void do_partial_setup( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;
   ctx->Driver.PartialRasterSetupCVA( VB, 
				      ctx->CVA.pre.new_outputs,
				      ctx->CVA.pre.outputs );
}


/* Done if we need to pull cva data into the immediate struct for some
 * further processing, or if there is no ctx->Driver.MergeAndRenderCVA()
 * implemented.  Inputs: ArrayElt - Outputs: ctx->Array.LockPrecalcOutputs
 *
 * Should only be done if a later stage needs LockPrecalcOutputs.  If 
 */
static void do_cva_merge( struct vertex_buffer *VB )
{
   struct gl_cva *cva = &VB->ctx->CVA;
   gl_merge_cva( VB, cva->VB );
}






/* Inputs: ctx->Flags, Outputs: nil
 * 
 * Cva issues will always have been resolved prior to reaching this point.
 * If we do an early render, we will never call this function.
 */
static void do_render( struct vertex_buffer *VB )
{
   gl_render_vb( VB );   
}


/* With CVA, 'full setup' can be acheived by the partial setup code when
 * only some of the elements have changed.
 */
static void do_full_setup( struct vertex_buffer *VB )
{
   GLcontext *ctx = VB->ctx;

   if (VB->Type == VB_CVA_PRECALC) {
      ctx->Driver.PartialRasterSetupCVA( VB, 
					 ctx->CVA.pre.new_outputs,
					 ctx->CVA.pre.outputs );
   } else 
      ctx->Driver.RasterSetup( VB, VB->CopyStart, VB->Count );
}



static void check_fog( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   if (ctx->Fog.Enabled && ctx->FogMode==FOG_VERTEX) 
   {
      GLuint flags;

      if (ctx->Visual->RGBAflag) 
	 flags = VERT_EYE|VERT_RGBA;       
      else
	 flags = VERT_EYE|VERT_INDEX;
      
      d->type = PIPE_ANY;
      d->inputs = flags;
      d->outputs = VERT_RGBA;
   }
}


static void check_lighting( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   if (ctx->Light.Enabled) 
   {
      GLuint flags = VERT_NORM|VERT_MATERIAL;
      
      if (ctx->Light.NeedVertices)
	 if (ctx->NeedEyeCoords)
	    flags |= VERT_EYE;
	 else
	    flags |= VERT_OBJ_ANY;

      if (ctx->Light.ColorMaterialEnabled) flags |= VERT_RGBA;
      
      d->type = PIPE_ANY;
      d->inputs = flags;
      d->outputs = VERT_RGBA;
   } 
}

static void check_update_materials( GLcontext *ctx, 
				    struct gl_pipeline_stage *d )
{
   if (!ctx->Light.Enabled) {
      GLuint flags = VERT_MATERIAL;
      if (ctx->Light.ColorMaterialEnabled) flags |= VERT_RGBA;
      d->type = PIPE_CVA_ELT|PIPE_IMMEDIATE;
      d->inputs = flags;
      d->outputs = 0;
   }
}

      
static void check_normal_transform( GLcontext *ctx, 
				    struct gl_pipeline_stage *d )
{
   if (ctx->NormalTransform) {
      d->type = PIPE_ANY;
      d->inputs = VERT_NORM;
      d->outputs = VERT_NORM;
   }
}

static void check_texture( GLcontext *ctx, GLuint i, 
			   struct gl_pipeline_stage *d )
{
   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
   
   if (texUnit->Enabled)
   {
      GLuint texflag = VERT_TEX_ANY(i);
      GLuint flags = 0;

      /* safe?
       */
      if (texUnit->GenFlags & TEXGEN_NEED_VERTICES) {
	 if (0)
	    flags |= VERT_OBJ_ANY;
	 if (1)
	    flags |= VERT_EYE;
      }
      
      if (texUnit->GenFlags & TEXGEN_NEED_NORMALS)
	 flags |= VERT_NORM;

      if (texUnit->Enabled & ~texUnit->TexGenEnabled)
	 flags |= texflag;

      d->type = PIPE_ANY;
      d->inputs = flags;
      d->outputs = texflag;
   }
}


static void check_texture_0( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   check_texture(ctx, 0, d);
}

static void check_texture_1( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   check_texture(ctx, 1, d);
}

static void check_cva_merge( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   (void) ctx;
   d->type = PIPE_CVA_ELT;
   d->inputs = VERT_ELT;
   d->outputs = 0; 
}



static void check_render( GLcontext *ctx, struct gl_pipeline_stage *d )
{  
   d->type = PIPE_CVA_ELT|PIPE_IMMEDIATE;
   if (ctx->RenderMode == GL_RENDER && ctx->Driver.RasterSetup)
      d->inputs = VERT_RAST_SETUP_FULL;
   else 
      d->inputs = ctx->RenderFlags; 
   d->outputs = 0;
}


static void check_full_setup( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   if (ctx->RenderMode == GL_RENDER && ctx->Driver.RasterSetup) {
      d->type = PIPE_ANY;
      d->inputs = ctx->RenderFlags;
      d->outputs = VERT_RAST_SETUP_FULL;

      if ( ctx->IndirectTriangles & DD_TRI_CULL )
	 d->type = PIPE_IMMEDIATE|PIPE_CVA_ELT;
   }
}  

static void check_indirect_render( GLcontext *ctx, 
				   struct gl_pipeline_stage *d )
{   
   /* Could be more clever about culling.
    */
   if (ctx->RenderMode == GL_RENDER && !ctx->IndirectTriangles) 
   {
      d->type = PIPE_CVA_ELT;
      d->inputs = VERT_RAST_SETUP_FULL | VERT_ELT;
   }      
}

static void check_merge_and_render( GLcontext *ctx, 
				    struct gl_pipeline_stage *d )
{   
   if (ctx->Driver.CheckMergeAndRenderCVA && !ctx->IndirectTriangles) 
   {
      d->update_inputs = ctx->Driver.CheckMergeAndRenderCVA;
      d->update_inputs( ctx, d );
   }
}

static void check_partial_setup( GLcontext *ctx, struct gl_pipeline_stage *d )
{   
   if (ctx->Driver.CheckPartialRasterSetupCVA && !ctx->IndirectTriangles) 
   {
      d->update_inputs = ctx->Driver.CheckPartialRasterSetupCVA;
      d->update_inputs( ctx, d );
   }
}



static void check_vertex( GLcontext *ctx, struct gl_pipeline_stage *d )
{
   (void) ctx;
   d->type = PIPE_ANY;
   d->inputs = VERT_OBJ_ANY;
   d->outputs = VERT_EYE | VERT_WIN;
}

static void check_cva_prepare_arrays( GLcontext *ctx, 
				      struct gl_pipeline_stage *d )
{
   (void) ctx;
   d->type = PIPE_CVA_PRECALC;
   d->inputs = 0;		/* always run */
   d->outputs = 0;
}


/* 
 */
#define DYN_STATE 0,0,0

static CONST struct gl_pipeline_stage static_pipeline[] = {
   { "cva merge", 
     0,
     PIPE_CVA_ELT,		
     0,
     NEW_CLIENT_STATE,		/* state change */
     0,				/* cva state change */
     0,				/* cva forbidden */
     DYN_STATE,
     check_cva_merge,
     do_cva_merge },
   
   { "cva prepare arrays",
     0,
     PIPE_CVA_PRECALC,
     0,
     0,
     NEW_CLIENT_STATE,
     0,
     PIPE_CVA_PRECALC, 0, 0,
     check_cva_prepare_arrays,
     gl_prepare_arrays_cva },

   { "vertex pipeline",
     PIPE_OP_VERT_XFORM,
     PIPE_CVA_PRECALC|PIPE_IMMEDIATE,
     0,
     0,
     NEW_MODELVIEW|NEW_PROJECTION|NEW_USER_CLIP,
     0,
     0,VERT_OBJ_ANY, VERT_EYE|VERT_WIN,
     check_vertex,
     do_vertex_pipeline },
   
   { "normal transform",
     PIPE_OP_NORM_XFORM,
     PIPE_ANY,
     0,
     NEW_NORMAL_TRANSFORM,
     NEW_NORMAL_TRANSFORM,
     0,
     DYN_STATE,
     check_normal_transform,
     do_normal_transform },
   
   { "lighting", 
     PIPE_OP_LIGHT,
     PIPE_ANY,
     0,
     NEW_LIGHTING,
     NEW_LIGHTING|NEW_MODELVIEW,
     VERT_MATERIAL,		/* I hate glMaterial() */
     DYN_STATE,
     check_lighting,
     do_lighting },
   
   { "update materials (no lighting)",
     0,
     PIPE_CVA_ELT|PIPE_IMMEDIATE,
     0,
     NEW_LIGHTING,
     0,
     0,
     DYN_STATE,
     check_update_materials,
     do_update_materials },
   
   { "fog",
     PIPE_OP_FOG,
     PIPE_ANY,
     0,
     NEW_LIGHTING|NEW_RASTER_OPS,
     NEW_LIGHTING|NEW_RASTER_OPS|NEW_FOG|NEW_MODELVIEW,
     0,
     DYN_STATE,
     check_fog,
     gl_fog_vertices },
   
   { "texture gen/transform 0",
     PIPE_OP_TEX0,
     PIPE_ANY,
     0,
     NEW_TEXTURING,
     NEW_TEXTURING|NEW_TEXTURE_MATRIX,
     0,
     DYN_STATE,
     check_texture_0,
     do_texture_0 },
   
   { "texture gen/transform 1",
     PIPE_OP_TEX1,
     PIPE_ANY,
     0,
     NEW_TEXTURING,
     NEW_TEXTURING|NEW_TEXTURE_MATRIX,
     0,
     DYN_STATE,
     check_texture_1,
     do_texture_1 },   

   { "cva indirect render",
     PIPE_OP_RENDER,
     PIPE_CVA_ELT,
     0,
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS,     
     0,
     0,
     DYN_STATE,
     check_indirect_render,
     do_indirect_render },

   { "cva merge & render", 
     PIPE_OP_RAST_SETUP_1|PIPE_OP_RENDER, /* rsetup1 if processing in elt? */
     PIPE_CVA_ELT,		
     0,
     NEW_CLIENT_STATE,  
     0,				/* cva state change */     
     0,				/* cva forbidden */
     DYN_STATE,
     check_merge_and_render,
     do_merge_and_render },

   { "full raster setup",	/* prepare for indirect and normal render */
     PIPE_OP_RAST_SETUP_0|PIPE_OP_RAST_SETUP_1,
     PIPE_ANY,
     0,
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS|NEW_POLYGON,     
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS|NEW_POLYGON,
     0,
     DYN_STATE,
     check_full_setup,
     do_full_setup },

   { "partial raster setup",	/* prepare for merge_and_render */
     PIPE_OP_RAST_SETUP_0,
     PIPE_CVA_PRECALC,
     0,
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS|NEW_POLYGON,     
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS|NEW_POLYGON,
     0,
     DYN_STATE,
     check_partial_setup,
     do_partial_setup },

   { "render",
     PIPE_OP_RENDER,
     PIPE_CVA_ELT|PIPE_IMMEDIATE,
     0,
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS,     
     0,
     0,
     DYN_STATE,
     check_render,
     do_render }
};
d145 1
a145 1
static const char *pipeline_name[9] = {
a147 2
   "CVA Elt",
   0,
a148 4
   0,
   0,
   0,
   "CVA Precalc Update"
d151 2
d165 2
a166 2
   for (i = 0 ; i < Elements(static_pipeline) ; i++) 
      p->state_change |= static_pipeline[i].state_change;
d172 10
a181 1
   MEMCPY( ctx->PipelineStage, static_pipeline, sizeof(static_pipeline) );
d183 5
a187 3
   pipeline_ctr( &ctx->Pipeline, ctx, PIPE_IMMEDIATE);
   pipeline_ctr( &ctx->CVA.elt, ctx, PIPE_CVA_ELT );
   pipeline_ctr( &ctx->CVA.pre, ctx, PIPE_CVA_PRECALC );
a190 17
void gl_build_immediate_pipeline( GLcontext *ctx ) 
{
   struct gl_pipeline *p = &ctx->Pipeline;
   struct gl_pipeline_stage *pipeline = ctx->PipelineStage;
   GLuint generated = 0;
   GLuint newstate = ctx->NewState;
   GLuint flags = VERT_WIN;
   GLuint i;
  
   /* Precalculate this value because lots of stages use it.
    */
   if (ctx->RenderMode==GL_FEEDBACK) 
   {
      flags = (VERT_WIN|VERT_RGBA|VERT_INDEX|
	       VERT_NORM|VERT_EDGE|
	       VERT_TEX0_ANY|VERT_TEX1_ANY);
   }
a191 2
   if (ctx->Texture.Enabled & 0xf)
      flags |= VERT_TEX0_ANY;
a192 7
   if (ctx->Texture.Enabled & 0xf0)
      flags |= VERT_TEX1_ANY;
   
   if (ctx->Visual->RGBAflag) 
      flags |= VERT_RGBA;
   else 
      flags |= VERT_INDEX;
a193 5
   if (ctx->Polygon.Unfilled) 
      flags |= VERT_EDGE;
 
   ctx->RenderFlags = flags;
   p->inputs = 0;
d195 1
a195 8
   for (i = 0 ; i < Elements(static_pipeline) ; i++) {
      
      if (pipeline[i].state_change & newstate) {
	 pipeline[i].type = 0;
	 pipeline[i].update_inputs(ctx, &pipeline[i] );
      }
      
      pipeline[i].active &= ~PIPE_IMMEDIATE;
d197 3
a199 28
      if ((pipeline[i].type & PIPE_IMMEDIATE) && pipeline[i].inputs)
      {
	 pipeline[i].active |= PIPE_IMMEDIATE;
	 p->inputs |= pipeline[i].inputs & ~generated;
	 generated |= pipeline[i].outputs;
	 p->ops |= pipeline[i].ops;

	 /* only one render available to the immediate pipeline - no need
	  * for this check:
	  * if (pipeline[i].ops & PIPE_OP_RENDER)
	  *     break;
	  */
      }
   }

   if (0 && (MESA_VERBOSE & VERBOSE_PIPELINE))
      gl_print_pipeline(ctx, p);
}

#ifndef MESA_VERBOSE
int MESA_VERBOSE = 0
/*  | VERBOSE_PIPELINE */
/*  | VERBOSE_TEXTURE */
/*  | VERBOSE_VARRAY */
/*  | VERBOSE_IMMEDIATE */
/*  | VERBOSE_DRIVER */
;
#endif
d201 1
a201 2
/* Called only when we want to use the cva pipelines and there has been
 * a state change.
d203 1
a203 1
void gl_update_cva_pipelines( GLcontext *ctx )
d208 1
a208 1
   struct gl_pipeline *elt = &cva->elt;
d210 1
a210 2
   GLuint newstate = ctx->Array.NewState;
   GLuint newinputs = ctx->Array.NewArrayState;
a211 1
   GLuint active_ops = 0;
d213 6
a219 1
   pre->outputs = ctx->Array.Summary;
d221 4
d226 3
a228 7
   pre->new_inputs = newinputs;


   if (MESA_VERBOSE&VERBOSE_PIPELINE) {
      gl_print_vert_flags("new inputs", newinputs);
      gl_print_vert_flags("cva->orflag", cva->orflag);
      gl_print_vert_flags("array state", ctx->Array.Summary);
d231 1
a231 6
   /* Slight hack for lighting.
    */
   if (!(cva->orflag & VERT_MATERIAL))
      pre->outputs |= VERT_MATERIAL;
   else if (oldoutputs & VERT_MATERIAL)
      newinputs |= VERT_MATERIAL;
d233 2
a234 2
   cva->orflag = 0;
   if (MESA_VERBOSE&VERBOSE_PIPELINE) gl_print_vert_flags("pre->outputs", pre->outputs);
d244 3
a246 7
   for (i = 0 ; i < Elements(static_pipeline) ; i++) {
      pipeline[i].active &= ~PIPE_CVA_RUN_PRECALC;

      if (pipeline[i].special & PIPE_CVA_PRECALC) {
	 pipeline[i].type = 0;
	 pipeline[i].update_inputs(ctx, &pipeline[i]);
      }
d248 1
a248 1
      if (pipeline[i].type & PIPE_CVA_PRECALC) 
d251 2
a252 1
	     (newinputs & pipeline[i].inputs))
d255 5
a259 4
	    newinputs |= pipeline[i].outputs;
	    pipeline[i].active &= ~PIPE_CVA_PRECALC;
	    if ((pipeline[i].inputs & pre->outputs) == pipeline[i].inputs &&
		(pipeline[i].ops & active_ops) == 0)
d261 2
a262 1
	       pipeline[i].active |= PIPE_CVA_PRECALC | PIPE_CVA_RUN_PRECALC;
d266 4
d271 6
a276 2
	 if (pipeline[i].active & PIPE_CVA_PRECALC) {
	    active_ops |= pipeline[i].ops;
d278 2
a279 4
	    pre->forbidden_inputs |= pipeline[i].cva_forbidden_inputs;

/*  	    printf("after %s, ", pipeline[i].name);  */
/*  	    gl_print_vert_flags("pre->outputs", pre->outputs); */
d281 6
a287 2
      else 
	 pipeline[i].active &= ~PIPE_CVA_PRECALC;
d290 7
a296 2
   pre->ops = active_ops;
   pre->new_outputs = newinputs & pre->outputs;
d298 46
a343 3
   if (!cva->VB) {
      cva->VB = gl_vb_create_for_cva( ctx, ctx->Const.MaxArrayLockSize );
      gl_alloc_cva_store( cva, cva->VB->Size );
a345 6
   if (!(pre->outputs & (VERT_RAST_SETUP_FULL|VERT_RAST_SETUP_PART)) && 
       ctx->Driver.InvalidateRasterSetupCVA)
   {
/*        printf("invalidate raster setup\n"); */
      ctx->Driver.InvalidateRasterSetupCVA( cva->VB );
   }
d347 5
a351 1
   gl_reset_cva_vb( cva->VB, changed_ops );
d353 5
a357 14
   if (1) {
      GLuint available = pre->outputs | VERT_DATA;
      GLuint generated = 0;
      elt->outputs = 0;		/* not used */
      elt->inputs = 0;

      for (i = 0 ; i < Elements(static_pipeline) ; i++) {
	 pipeline[i].active &= ~PIPE_CVA_ELT;

	 /* fix me */
	 if (1) {
	    pipeline[i].type = 0;
	    pipeline[i].update_inputs(ctx, &pipeline[i]);
	 }
d359 8
a366 3
	 if ((pipeline[i].type & PIPE_CVA_ELT) &&
	     (pipeline[i].ops & active_ops) == 0 &&
	     (pipeline[i].inputs & available) == pipeline[i].inputs) 
d369 3
a371 1
	    pipeline[i].active |= PIPE_CVA_ELT;
a374 4
	 
	    if (pipeline[i].ops & PIPE_OP_RENDER) {
	       break;
	    }
d377 1
d379 1
a379 3
      /* clean the remaining elements */
      for (i++ ; i < Elements(static_pipeline) ; i++) 
	 pipeline[i].active &= ~PIPE_CVA_ELT;
d381 1
d385 6
d392 1
a392 2
   if (MESA_VERBOSE&VERBOSE_PIPELINE) {
      gl_print_pipeline( ctx, pre ); 
a393 6
   }

   cva->pre.data_valid = 0;
   cva->pre.pipeline_valid = 1;
   ctx->Array.NewState = 0;
   ctx->Array.NewArrayState = 0;
d395 2
a396 2


d403 46
a448 3
   if (ctx->Pipeline.state_change & newstate) {
      gl_build_immediate_pipeline( ctx );
      ctx->Flags = ctx->Pipeline.inputs;
a449 2
   
   ctx->Array.NewState |= newstate;
d451 3
a453 2
   cva->pre.forbidden_inputs = 0;
   cva->pre.pipeline_valid = 0;
d455 3
d460 1
a460 2

void gl_run_pipeline( struct vertex_buffer *VB, GLuint type )
d462 4
a465 2
   struct gl_pipeline_stage *pipeline = VB->ctx->PipelineStage;
   GLuint i;
a467 6

   for (i = 0 ; i < Elements(static_pipeline) ; i++) 
      if (pipeline[i].active & type) {
	 pipeline[i].func( VB );	    
	 if (VB->Culled) break;	 
      }
d469 3
d478 1
a478 1
	   "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
d483 14
a496 13
	  (flags & VERT_RGBA)       ? "colors, " : "",
	  (flags & VERT_NORM)       ? "normals, " : "",
	  (flags & VERT_INDEX)      ? "index, " : "",
	  (flags & VERT_EDGE)       ? "edgeflag, " : "",
	  (flags & VERT_MATERIAL)   ? "material, " : "",
	  (flags & VERT_TEX0_ANY)   ? "texcoord0, " : "",
	  (flags & VERT_TEX1_ANY)   ? "texcoord1, " : "",
	  (flags & VERT_EVAL_ANY)   ? "eval-coord, " : "",
	  (flags & VERT_EYE)        ? "eye, " : "",
	  (flags & VERT_WIN)        ? "win, " : "",
	  (flags & VERT_RAST_SETUP_FULL) ? "driver-data, " : "", 
	  (flags & VERT_RAST_SETUP_PART) ? "partial-driver-data, " : ""
         );
d503 1
d508 5
d514 1
d517 1
a517 1
   for (i = 0 ; i < Elements(static_pipeline) ; i++) 
d521 4
a524 3
	 if (p->type == PIPE_CVA_PRECALC &&
	     (pipeline[i].active & PIPE_CVA_RUN_PRECALC))
	    fprintf(stderr,"\t--> needs precalc\n");
d529 43
a571 1
	 if (p->type == PIPE_CVA_PRECALC && pipeline[i].cva_forbidden_inputs)
d573 1
a573 1
				pipeline[i].cva_forbidden_inputs);
@


3.14
log
@misc. bug fixes
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.13 1999/05/02 00:59:24 keithw Exp $ */
d1045 3
d1148 1
a1148 1
      gl_alloc_cva_store( cva, ctx->Const.MaxArrayLockSize );
@


3.14.2.1
log
@Quake3 inspired optimizations
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14 1999/05/16 17:09:59 keithw Exp $ */
a44 1
#include "stages.h"
a45 1
#include "translate.h"
d49 9
a57 10
#ifndef MESA_VERBOSE
int MESA_VERBOSE = 0 
               | VERBOSE_PIPELINE
               | VERBOSE_IMMEDIATE
/*                 | VERBOSE_VARRAY */
/*                 | VERBOSE_TEXTURE */
               | VERBOSE_API
/*                 | VERBOSE_DRIVER */
;
#endif
d66 1
a66 2
   if (ctx->Driver.ResetCvaVB)
      ctx->Driver.ResetCvaVB( VB, stages );
d68 1
a68 3
   if (stages & PIPE_OP_VERT_XFORM) 
   {
      if (VB->CullMode & (CULL_MASK_ACTIVE|CLIP_MASK_ACTIVE)) 
d70 2
a71 4
      
      if (VB->ClipOrMask & CLIP_USER_BIT)
	 MEMSET(VB->UserClipMask, 0, VB->Count);

a74 1
      VB->CullFlag[0] = VB->CullFlag[1] = 0;
d79 1
a79 1
   if (stages & PIPE_OP_NORM_XFORM) {
d81 1
a81 2
   }

d84 2
a85 2
      VB->ColorPtr = VB->Color[0] = VB->Color[1] = &ctx->CVA.v.Color;
      VB->IndexPtr = VB->Index[0] = VB->Index[1] = &ctx->CVA.v.Index;
a97 2
      VB->ColorPtr = VB->Color[0];
      VB->IndexPtr = VB->Index[0];
d102 665
d769 180
a948 1
static const char *pipeline_name[3] = {
d951 2
d954 4
a959 2


d972 2
a973 2
   for (i = 0 ; i < gl_default_nr_stages ; i++) 
      p->state_change |= gl_default_pipeline[i].state_change;
d979 1
a979 13
   if (ctx->Driver.RegisterPipelineStages)
      ctx->NrPipelineStages = 
	 ctx->Driver.RegisterPipelineStages( ctx->PipelineStage,
					     gl_default_pipeline,
					     gl_default_nr_stages );
   else 
   {
      MEMCPY( ctx->PipelineStage, 
	      gl_default_pipeline, 
	      sizeof(*gl_default_pipeline) * gl_default_nr_stages );

      ctx->NrPipelineStages = gl_default_nr_stages;
   }
d981 3
a983 2
   pipeline_ctr( &ctx->CVA.elt, ctx, PIPE_IMMEDIATE);
   pipeline_ctr( &ctx->CVA.pre, ctx, PIPE_PRECALC );
d987 17
d1005 2
d1008 7
d1016 5
d1022 8
a1029 1
#define MINIMAL_VERT_DATA (VERT_DATA&~(VERT_TEX0_4|VERT_TEX1_4))
d1031 15
a1045 3
#define VERT_CURRENT_DATA (VERT_TEX0_1234|VERT_TEX1_1234|VERT_RGBA| \
			   VERT_INDEX|VERT_EDGE|VERT_NORM| \
	                   VERT_MATERIAL)
d1047 12
a1058 1
/* Called prior to every recomputation of the CVA precalc data.
d1060 1
a1060 1
void gl_build_precalc_pipeline( GLcontext *ctx )
d1065 1
a1065 2
   struct gl_pipeline *elt = &cva->elt;   
   struct gl_pipeline_stage **stages = pre->stages;
d1067 2
a1068 1
   GLuint newstate = pre->new_state;
d1070 1
a1071 6
   GLuint oldinputs = pre->inputs;
   GLuint fallback = (VERT_CURRENT_DATA & ctx->Current.Flag & 
		      ~ctx->Array.Summary);
   GLuint changed_outputs = (ctx->Array.NewArrayState | 
			     (fallback & cva->orflag));
   GLuint available = fallback | ctx->Array.Flags;
d1073 1
a1074 4
   pre->generated = 0;
   pre->ops = 0;
   pre->outputs = 0;
   pre->inputs = 0;
d1076 7
a1082 3
   
   if (ctx->Array.Summary & VERT_ELT) {
      cva->orflag &= VERT_MATERIAL;
d1085 7
a1091 1
   available &= ctx->Array.Summary | ~cva->orflag;
d1093 1
a1093 4


   if (MESA_VERBOSE & VERBOSE_PIPELINE)
      fprintf(stderr, ": Rebuild pipeline\n");
d1103 7
a1109 3
   for (i = 0 ; i < ctx->NrPipelineStages ; i++) 
   {
      pipeline[i].check(ctx, &pipeline[i]);
d1111 1
a1111 1
      if (pipeline[i].type & PIPE_PRECALC) 
d1114 1
a1114 2
	     (changed_outputs & pipeline[i].inputs) ||
	     !pipeline[i].inputs)
d1117 4
a1120 5
	    changed_outputs |= pipeline[i].outputs;
	    pipeline[i].active &= ~PIPE_PRECALC;

	    if ((pipeline[i].inputs & ~available) == 0 &&
		(pipeline[i].ops & pre->ops) == 0)
d1122 1
a1122 2
	       pipeline[i].active |= PIPE_PRECALC;
	       *stages++ = &pipeline[i];
a1125 4
	 /* Incompatible with multiple stages structs implementing
	  * the same stage.
	  */
	 available &= ~pipeline[i].outputs;
d1127 4
d1132 2
a1133 8
	 if (pipeline[i].active & PIPE_PRECALC) {
	    pre->ops |= pipeline[i].ops;
	    pre->inputs |= pipeline[i].inputs & ~pre->generated;
	    pre->outputs |= pipeline[i].inputs & ~pre->generated;
	    pre->generated |= pipeline[i].outputs;
	    pre->outputs |= pipeline[i].outputs;
	    available |= pipeline[i].outputs;
	    pre->forbidden_inputs |= pipeline[i].forbidden_inputs;
a1134 6
      } 
      else if (pipeline[i].active & PIPE_PRECALC) 
      {
	 pipeline[i].active &= ~PIPE_PRECALC;
	 changed_outputs |= pipeline[i].outputs;
	 changed_ops |= pipeline[i].ops;
d1136 2
d1140 2
a1141 1
   *stages = 0;
d1143 4
a1146 3
   pre->new_outputs = pre->outputs & (changed_outputs | ~oldoutputs);
   pre->new_inputs = pre->inputs & ~oldinputs;
   pre->forbidden_inputs |= pre->inputs & fallback;
d1148 5
a1152 32
   pre->changed_ops = changed_ops;
   pre->data_valid = 0;
   pre->pipeline_valid = 1;
   elt->pipeline_valid = 0;
   
   pre->new_state = 0;
   elt->new_state = 0;

   if (MESA_VERBOSE&VERBOSE_PIPELINE)
      gl_print_pipeline( ctx, pre ); 
}



void gl_build_immediate_pipeline( GLcontext *ctx )
{
   struct gl_pipeline_stage *pipeline = ctx->PipelineStage;
   struct gl_cva *cva = &ctx->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 && ctx->CompileCVAFlag) {
      is_elt = 1;
      active_ops = cva->pre.ops;
      available |= pre->outputs | VERT_PRECALC_DATA;
d1155 1
d1157 14
a1170 2
   elt->outputs = 0;		/* not used */
   elt->inputs = 0;
d1172 3
a1174 17
   for (i = 0 ; i < ctx->NrPipelineStages ; i++) {
      pipeline[i].active &= ~PIPE_IMMEDIATE;

      if ((pipeline[i].state_change & newstate) ||
  	  (pipeline[i].forbidden_inputs & available)) 
      {
	 pipeline[i].check(ctx, &pipeline[i]);
      }

      if ((pipeline[i].type & PIPE_IMMEDIATE) &&
	  (pipeline[i].ops & active_ops) == 0 
/*  	  && (pipeline[i].forbidden_inputs & available) == 0 */
	 )
      {
	 if (pipeline[i].inputs & ~available) 
	    elt->forbidden_inputs |= pipeline[i].inputs & ~available;
	 else
d1177 1
a1177 3
	    elt->forbidden_inputs |= pipeline[i].forbidden_inputs;
	    pipeline[i].active |= PIPE_IMMEDIATE;
	    *stages++ = &pipeline[i];
d1181 4
a1186 1
   }
d1188 3
a1190 1
   *stages = 0;
a1191 1
   if (is_elt) {
a1194 2
   
   ctx->Flags = PIPE_FLAGS_TO_VERT_FLAGS(elt->inputs); 
d1196 4
a1199 3
   elt->generated = generated;
   elt->pipeline_valid = 1;
   elt->new_state = 0;
d1201 4
a1204 2
   if (MESA_VERBOSE&VERBOSE_PIPELINE) 
      gl_print_pipeline( ctx, elt ); 
d1206 2
a1207 2
   
#define INTERESTED ~(NEW_DRIVER_STATE|NEW_CLIENT_STATE|NEW_TEXTURE_ENABLE)
d1214 4
a1217 29
   newstate &= INTERESTED;
   
   if (0)
   fprintf(stderr, "changed flags %x orflag %x lock %d lockcount %d newstate %x\n", 
	   ctx->Array.Flags ^  cva->last_array_flags,
	   cva->orflag ^ cva->last_orflag,
	   cva->lock_changed,
	   ctx->Array.LockCount,
	   newstate);

   if (newstate ||
       cva->lock_changed ||
       cva->orflag != cva->last_orflag ||
       ctx->Array.Flags != cva->last_array_flags)
   {   
      GLuint flags = VERT_WIN;

      if (ctx->RenderMode==GL_FEEDBACK) 
      {
	 flags = (VERT_WIN|VERT_RGBA|VERT_INDEX|
		  VERT_NORM|VERT_EDGE|
		  VERT_TEX0_ANY|VERT_TEX1_ANY);
      }

      if (ctx->Texture.Enabled & 0xf)
	 flags |= VERT_TEX0_ANY;

      if (ctx->Texture.Enabled & 0xf0)
	 flags |= VERT_TEX1_ANY;
d1219 1
a1219 22
      if (ctx->Visual->RGBAflag) 
	 flags |= VERT_RGBA;
      else 
	 flags |= VERT_INDEX;

      if (ctx->Polygon.Unfilled) 
	 flags |= VERT_EDGE;
 
      ctx->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->pre.data_valid = 0;
      cva->lock_changed = 0;
   }

   if (ctx->Array.NewArrayState != cva->last_array_new_state)
      cva->pre.pipeline_valid = 0;
d1221 2
a1223 3
   cva->last_array_new_state = ctx->Array.NewArrayState;
   cva->last_orflag = cva->orflag;
   cva->last_array_flags = ctx->Array.Flags;
d1226 2
a1227 1
void gl_run_pipeline( struct vertex_buffer *VB )
d1229 2
a1230 2
   struct gl_pipeline *pipe = VB->pipeline;
   struct gl_pipeline_stage **stages = pipe->stages;
d1233 6
a1239 3
   for ( VB->Culled = 0; *stages && !VB->Culled ; stages++ ) 
      (*stages)->run( VB );
      
d1246 1
a1246 1
	   "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
d1251 13
a1263 14
	   (flags & VERT_RGBA)       ? "colors, " : "",
	   (flags & VERT_NORM)       ? "normals, " : "",
	   (flags & VERT_INDEX)      ? "index, " : "",
	   (flags & VERT_EDGE)       ? "edgeflag, " : "",
	   (flags & VERT_MATERIAL)   ? "material, " : "",
	   (flags & VERT_TEX0_ANY)   ? "texcoord0, " : "",
	   (flags & VERT_TEX1_ANY)   ? "texcoord1, " : "",
	   (flags & VERT_EVAL_ANY)   ? "eval-coord, " : "",
	   (flags & VERT_EYE)        ? "eye, " : "",
	   (flags & VERT_WIN)        ? "win, " : "",
	   (flags & VERT_PRECALC_DATA) ? "precalc data, " : "",
	   (flags & VERT_SETUP_FULL) ? "driver-data, " : "", 
	   (flags & VERT_SETUP_PART) ? "partial-driver-data, " : ""
      );
a1269 1
   struct gl_pipeline_stage **stages = p->stages;
a1273 5
   if (!p->pipeline_valid) {
      printf("--> Not up to date!!!\n");
      return;
   }

a1274 1
   gl_print_vert_flags("Forbidden", p->forbidden_inputs);
d1277 1
a1277 1
   for (i = 0 ; i < ctx->NrPipelineStages ; i++) 
d1281 2
a1282 2
	 if (p->type == PIPE_PRECALC && *stages == &pipeline[i]) {
	    stages++;
a1283 1
	 }
d1288 1
a1288 1
	 if (p->type == PIPE_PRECALC && pipeline[i].forbidden_inputs)
d1290 1
a1290 1
				pipeline[i].forbidden_inputs);
@


3.14.2.2
log
@q2, q3 bugfixes
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.1 1999/05/21 21:29:26 keithw Exp $ */
d53 2
a54 2
/*                 | VERBOSE_PIPELINE */
/*                 | VERBOSE_IMMEDIATE */
d57 1
a57 1
/*                 | VERBOSE_API */
d350 1
a350 1
   if (MESA_VERBOSE&VERBOSE_PIPELINE) {
a351 1
   }
d407 1
@


3.14.2.3
log
@new, experimental fast path for quake 3 precalc pipeline
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.2 1999/05/22 19:14:39 keithw Exp $ */
a277 3
   if (ctx->Driver.OptimizePrecalcPipeline)
      ctx->Driver.OptimizePrecalcPipeline( ctx, pre );

a423 2
   
   pipe->data_valid = 1;	/* optimized stages might want to reset this. */
d461 1
a461 1
/*     struct gl_pipeline_stage **stages = p->stages; */
d479 4
a482 4
/*  	 if (p->type == PIPE_PRECALC && *stages == &pipeline[i]) { */
/*  	    stages++; */
/*  	    fprintf(stderr,"\t--> needs precalc\n"); */
/*  	 } */
a489 42
      }

   if (p->type == PIPE_PRECALC) {
      struct gl_pipeline_stage **stages = p->stages;
      fprintf(stderr,"\nStages requiring precalculation:\n");
      for ( i=0 ; stages[i] ; i++) {
	 fprintf(stderr, "%d: %s\n", i, stages[i]->name);
	 gl_print_vert_flags("\tinputs", stages[i]->inputs);
	 gl_print_vert_flags("\toutputs", stages[i]->outputs);
	 if (stages[i]->forbidden_inputs)
	    gl_print_vert_flags("\tforbidden", stages[i]->forbidden_inputs);
      }
   }
}



void gl_print_active_pipeline( GLcontext *ctx, struct gl_pipeline *p )
{
   struct gl_pipeline_stage **stages = p->stages;
   GLuint i;

   fprintf(stderr,"Type: %s\n", pipeline_name[p->type]);

   if (!p->pipeline_valid) {
      printf("--> Not up to date!!!\n");
      return;
   }

   gl_print_vert_flags("Inputs", p->inputs);
   gl_print_vert_flags("Forbidden", p->forbidden_inputs);
   gl_print_vert_flags("Outputs", p->outputs);

   for ( i=0 ; stages[i] ; i++) {
      fprintf(stderr, "%d: %s\n", i, stages[i]->name);

      gl_print_vert_flags("\tinputs", stages[i]->inputs);
      gl_print_vert_flags("\toutputs", stages[i]->outputs);

      if (p->type == PIPE_PRECALC && stages[i]->forbidden_inputs)
	    gl_print_vert_flags("\tforbidden", 
				stages[i]->forbidden_inputs);
@


3.14.2.4
log
@Broadened FX fast path, added support for multipass multitexture.
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.3 1999/05/24 02:13:39 keithw Exp $ */
d53 1
a53 1
               | VERBOSE_PIPELINE
d174 1
a174 1
void gl_build_full_precalc_pipeline( GLcontext *ctx )
d179 1
d204 2
a270 14

   if (ctx->Driver.OptimizePrecalcPipeline)
      ctx->Driver.OptimizePrecalcPipeline( ctx, pre );
}

void gl_build_precalc_pipeline( GLcontext *ctx )
{
   struct gl_pipeline *pre = &ctx->CVA.pre;   
   struct gl_pipeline *elt = &ctx->CVA.elt;   

   if (!ctx->Driver.BuildPrecalcPipeline ||
       !ctx->Driver.BuildPrecalcPipeline( ctx ))
      gl_build_full_precalc_pipeline( ctx );

a276 2
   ctx->CVA.orflag = 0;
   
d278 2
d286 1
d366 8
a373 3

   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_STATE))
      gl_print_enable_flags("enabled", ctx->Enabled);
@


3.14.2.5
log
@When texture.unit[0].envmode is GL_REPLACE, don't need VERT_RGBA as an input to rendering stages.

Rearranged fxfastpath.c without improving its performance.
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.4 1999/05/30 13:30:34 keithw Exp $ */
d53 1
a53 1
/*                 | VERBOSE_PIPELINE */
d56 1
a56 1
               | VERBOSE_TEXTURE
d387 6
a392 8
      if (ctx->Visual->RGBAflag) 
	 flags |= VERT_RGBA;
      else 
	 flags |= VERT_INDEX;

      if (ctx->Texture.Enabled & 0xf) {
	 if (ctx->Texture.Unit[0].EnvMode == GL_REPLACE)
	    flags &= ~VERT_RGBA;
d394 1
a395 1
      }
d400 5
a407 7
      if (ctx->RenderMode==GL_FEEDBACK) 
      {
	 flags = (VERT_WIN|VERT_RGBA|VERT_INDEX|
		  VERT_NORM|VERT_EDGE|
		  VERT_TEX0_ANY|VERT_TEX1_ANY);
      }

@


3.14.2.6
log
@some trial assembly, made newer code active by default
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.5 1999/06/01 00:45:21 keithw Exp $ */
d56 2
a57 2
/*                 | VERBOSE_TEXTURE */
               | VERBOSE_API
a58 1
               | VERBOSE_STATE
@


3.14.2.7
log
@Removed SGIS multitexture, added FX/X86 assm directory
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.6 1999/06/06 22:35:54 keithw Exp $ */
d59 1
a59 7
/*                 | VERBOSE_STATE */
;
#endif

#ifndef MESA_DEBUG_FLAGS
int MESA_DEBUG_FLAGS = 0 
               | DEBUG_ALWAYS_FLUSH
d75 2
a76 2
/*        if (VB->CullMode & (CULL_MASK_ACTIVE|CLIP_MASK_ACTIVE))  */
/*  	 MEMSET(VB->ClipMask, 0, VB->Count);	 */
d167 1
a167 1
#define MINIMAL_VERT_DATA (VERT_DATA&~(VERT_TEX0_4|VERT_TEX1_4|VERT_EVAL_ANY))
@


3.14.2.8
log
@cleaned up fxpipeline
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.14.2.7 1999/06/19 15:04:14 keithw Exp $ */
d81 3
@


3.13
log
@FX polygon offset and debugging changes
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.12 1999/04/29 14:43:16 keithw Exp $ */
d768 1
d917 2
a918 2
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS,     
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS,
d928 2
a929 2
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS,     
     NEW_LIGHTING|NEW_TEXTURING|NEW_RASTER_OPS,
d1048 7
a1054 1
int MESA_VERBOSE = 0;
@


3.12
log
@fixes for xlockmore problems
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.11 1999/04/28 22:55:40 keithw Exp $ */
d1046 3
a1048 2
/*  int kw_verbose = 0; */
#define kw_verbose 0
d1072 2
a1073 1
   if (kw_verbose) {
d1086 1
a1086 1
   if (kw_verbose) gl_print_vert_flags("pre->outputs", pre->outputs);
d1189 3
a1191 3
   if (kw_verbose) {
      printf("CVA Precalc pipeline:\n"); gl_print_pipeline( ctx, pre ); 
      printf("CVA Elt pipeline:\n"); gl_print_pipeline( ctx, elt ); 
d1238 6
a1243 5
   printf("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
	  name,
	  flags,
	  (flags & VERT_OBJ_ANY)    ? "vertices, " : "",
	  (flags & VERT_ELT)        ? "array-elt, " : "",
d1265 1
a1265 1
   printf("Type: %s\n", pipeline_name[p->type]);
d1272 1
a1272 1
	 printf("%u: %s\n", i, pipeline[i].name);
d1276 1
a1276 1
	    printf("\t--> needs precalc\n");
@


3.11
log
@fix for clip glitches, faster FX draw_elements
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.10 1999/04/24 21:53:04 keithw Exp $ */
d304 2
a305 2
   needclip = 0;      
   if (VB->ctx->Hint.ClipVolumeClipping != GL_FASTEST) {
d315 1
d354 1
@


3.10
log
@fix for cva and glPolygonMode
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.9 1999/04/24 13:21:43 keithw Exp $ */
d1044 2
a1045 1

d1069 4
a1072 1
/*     gl_print_vert_flags("cva->orflag", cva->orflag); */
d1082 1
a1082 1
/*     gl_print_vert_flags("pre->outputs", pre->outputs); */
d1184 5
a1188 3
   
/*    printf("CVA Precalc pipeline:\n"); gl_print_pipeline( ctx, pre );  */
/*    printf("CVA Elt pipeline:\n"); gl_print_pipeline( ctx, elt );  */
@


3.9
log
@more material/cva fixes
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.8 1999/04/24 01:08:02 keithw Exp $ */
d715 1
a715 1
      d->inputs = VERT_RAST_SETUP_0 | VERT_RAST_SETUP_1;
d727 1
a727 1
      d->outputs = VERT_RAST_SETUP_0 | VERT_RAST_SETUP_1;
d739 1
a739 2
   if (ctx->RenderMode == GL_RENDER && 
       !(ctx->IndirectTriangles & DD_TRI_CULL)) 
d742 1
a742 1
      d->inputs = VERT_RAST_SETUP_0 | VERT_RAST_SETUP_1 | VERT_ELT;
d749 1
a749 2
   if ( ctx->Driver.CheckMergeAndRenderCVA && 
	!(ctx->IndirectTriangles & DD_TRI_CULL) ) 
d758 1
a758 2
   if ( ctx->Driver.CheckPartialRasterSetupCVA && 
	!(ctx->IndirectTriangles & DD_TRI_CULL) ) 
d1133 1
a1133 1
   if (!(pre->outputs & VERT_RAST_SETUP_0) && 
d1135 2
d1138 1
d1228 1
a1228 1
   printf("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
d1243 2
a1244 2
	  ( (flags & VERT_RAST_SETUP_1) ? "driver-data, " : 
	    (flags & VERT_RAST_SETUP_0) ? "partial-driver-data, " : "" )
@


3.8
log
@another attempt to solve Eero's cva problem
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.7 1999/04/23 16:14:21 keithw Exp $ */
d1081 1
d1105 1
a1110 1
	       newinputs |= pipeline[i].outputs;
d1119 3
@


3.7
log
@fix for Eero's cva problem
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.6 1999/04/07 22:26:03 brianp Exp $ */
d1022 1
a1022 1
   for (i = 2 ; i < Elements(static_pipeline) ; i++) {
a1060 1
   GLuint rebuild_elt = 0;
d1070 3
d1080 1
a1090 1
      GLuint tmp = pipeline[i].active;
a1121 2

      rebuild_elt |= tmp ^ pipeline[i].active;
d1138 1
a1138 1
   if (rebuild_elt & PIPE_CVA_PRECALC) {
@


3.6
log
@silenced more warnings on IRIX
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.5 1999/04/07 22:23:58 brianp Exp $ */
d950 1
d952 1
a954 2
   "Immediate",
   0,
d970 1
d1036 1
d1064 1
d1075 3
d1124 1
d1174 1
@


3.5
log
@silenced warnings on IRIX
@
text
@d1 1
a1 1
/* $Id: pipeline.c,v 3.4 1999/04/07 22:19:04 brianp Exp $ */
d963 1
d1249 1
a1249 1
	 printf("%d: %s\n", i, pipeline[i].name);
@


3.4
log
@inserted copyright info
@
text
@d1 1
a1 1
/* $Id$ */
d703 1
d771 1
d780 1
@


3.3
log
@user-clip bug fixes, faster FX vertex snapping
@
text
@d1 31
a47 5


/* Dynamic pipelines, support for CVA.
 * Copyright (C) 1999 Keith Whitwell.
 */
@


3.2
log
@
  Eero's patch for NULL lengths pointer
@
text
@a22 8
static GLubyte ignore_bits[5] = {
   ~0,				/* not possible */
   ~0, 
   ~VEC_DIRTY_1, 
   ~(VEC_DIRTY_1|VEC_DIRTY_2), 
   ~(VEC_DIRTY_1|VEC_DIRTY_2|VEC_DIRTY_3)
};

d350 1
a350 1
      if (VB->Win.flags & VEC_DIRTY_3) gl_vector4f_clean_elem(&VB->Win, 3);
a353 2


d404 4
a407 4
   }
      
   if (VB->Win.flags & VEC_DIRTY_2 & ignore_bits[VB->Win.size]) 
      gl_vector4f_clean_elem(&VB->Win, 2);
@


3.1
log
@Compiled vertex arrays
@
text
@d442 1
a442 1
			       VB->NormalLengthPtr + VB->Start,
@

