diff options
Diffstat (limited to 'src/mesa')
| -rw-r--r-- | src/mesa/pipe/draw/draw_vf.c | 374 | ||||
| -rw-r--r-- | src/mesa/pipe/draw/draw_vf.h | 249 | ||||
| -rw-r--r-- | src/mesa/pipe/draw/draw_vf_generic.c | 983 | ||||
| -rw-r--r-- | src/mesa/pipe/draw/draw_vf_sse.c | 664 | ||||
| -rw-r--r-- | src/mesa/sources | 3 | 
5 files changed, 2273 insertions, 0 deletions
diff --git a/src/mesa/pipe/draw/draw_vf.c b/src/mesa/pipe/draw/draw_vf.c new file mode 100644 index 0000000000..f758460b5f --- /dev/null +++ b/src/mesa/pipe/draw/draw_vf.c @@ -0,0 +1,374 @@ +/* + * Copyright 2003 Tungsten Graphics, inc. + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 (including the next + * paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keithw@tungstengraphics.com> + */ + +#include "glheader.h" +#include "context.h" +#include "colormac.h" + +#include "pipe/p_compiler.h" + +#include "draw_vf.h" + +#define DBG 0 + + + +static boolean match_fastpath( struct draw_vertex_fetch *vf, +				 const struct draw_vf_fastpath *fp) +{ +   unsigned j; + +   if (vf->attr_count != fp->attr_count)  +      return FALSE; + +   for (j = 0; j < vf->attr_count; j++)  +      if (vf->attr[j].format != fp->attr[j].format || +	  vf->attr[j].inputsize != fp->attr[j].size || +	  vf->attr[j].vertoffset != fp->attr[j].offset)  +	 return FALSE; +       +   if (fp->match_strides) { +      if (vf->vertex_stride != fp->vertex_stride) +	 return FALSE; + +      for (j = 0; j < vf->attr_count; j++)  +	 if (vf->attr[j].inputstride != fp->attr[j].stride)  +	    return FALSE; +   } +    +   return TRUE; +} + +static boolean search_fastpath_emit( struct draw_vertex_fetch *vf ) +{ +   struct draw_vf_fastpath *fp = vf->fastpath; + +   for ( ; fp ; fp = fp->next) { +      if (match_fastpath(vf, fp)) { +         vf->emit = fp->func; +	 return TRUE; +      } +   } + +   return FALSE; +} + +void draw_vf_register_fastpath( struct draw_vertex_fetch *vf, +			     boolean match_strides ) +{ +   struct draw_vf_fastpath *fastpath = CALLOC_STRUCT(draw_vf_fastpath); +   unsigned i; + +   fastpath->vertex_stride = vf->vertex_stride; +   fastpath->attr_count = vf->attr_count; +   fastpath->match_strides = match_strides; +   fastpath->func = vf->emit; +   fastpath->attr = (struct draw_vf_attr_type *) +      _mesa_malloc(vf->attr_count * sizeof(fastpath->attr[0])); + +   for (i = 0; i < vf->attr_count; i++) { +      fastpath->attr[i].format = vf->attr[i].format; +      fastpath->attr[i].stride = vf->attr[i].inputstride; +      fastpath->attr[i].size = vf->attr[i].inputsize; +      fastpath->attr[i].offset = vf->attr[i].vertoffset; +   } + +   fastpath->next = vf->fastpath; +   vf->fastpath = fastpath; +} + + + + +/*********************************************************************** + * Build codegen functions or return generic ones: + */ +static void choose_emit_func( struct draw_vertex_fetch *vf,  +			      unsigned count,  +			      uint8_t *dest) +{ +   vf->emit = NULL; +    +   /* Does this match an existing (hardwired, codegen or known-bad) +    * fastpath? +    */ +   if (search_fastpath_emit(vf)) { +      /* Use this result.  If it is null, then it is already known +       * that the current state will fail for codegen and there is no +       * point trying again. +       */ +   } +   else if (vf->codegen_emit) { +      vf->codegen_emit( vf ); +   } + +   if (!vf->emit) { +      draw_vf_generate_hardwired_emit(vf); +   } + +   /* Otherwise use the generic version: +    */ +   if (!vf->emit) +      vf->emit = draw_vf_generic_emit; + +   vf->emit( vf, count, dest ); +} + + + + + +/*********************************************************************** + * Public entrypoints, mostly dispatch to the above: + */ + + + +unsigned draw_vf_set_vertex_attributes( struct draw_vertex_fetch *vf,  +				 const struct draw_vf_attr_map *map, +				 unsigned nr,  +				 unsigned vertex_stride ) +{ +   unsigned offset = 0; +   unsigned i, j; + +   assert(nr < DRAW_VF_ATTRIB_MAX); + +   memset(vf->lookup, 0, sizeof(vf->lookup)); + +   for (j = 0, i = 0; i < nr; i++) { +      const unsigned format = map[i].format; +      if (format == EMIT_PAD) { +	 if (DBG) +	    _mesa_printf("%d: pad %d, offset %d\n", i,   +			 map[i].offset, offset);   + +	 offset += map[i].offset; + +      } +      else { +	 assert(vf->lookup[map[i].attrib] == 0); +	 vf->lookup[map[i].attrib] = &vf->attr[j]; + +	 vf->attr[j].attrib = map[i].attrib; +	 vf->attr[j].format = format; +	 vf->attr[j].insert = draw_vf_format_info[format].insert; +	 vf->attr[j].extract = draw_vf_format_info[format].extract; +	 vf->attr[j].vertattrsize = draw_vf_format_info[format].attrsize; +	 vf->attr[j].vertoffset = offset; +	  +	 if (DBG) +	    _mesa_printf("%d: %s, offset %d\n", i,   +			 draw_vf_format_info[format].name, +			 vf->attr[j].vertoffset);    + +	 offset += draw_vf_format_info[format].attrsize; +	 j++; +      } +   } + +   vf->attr_count = j; +   vf->vertex_stride = vertex_stride ? vertex_stride : offset; +   vf->emit = choose_emit_func; + +   assert(vf->vertex_stride >= offset); +   return vf->vertex_stride; +} + + + +void draw_vf_set_vp_matrix( struct draw_vertex_fetch *vf, +		       const float *viewport ) +{ +   assert(vf->allow_viewport_emits); + +   /* scale */ +   vf->vp[0] = viewport[MAT_SX]; +   vf->vp[1] = viewport[MAT_SY]; +   vf->vp[2] = viewport[MAT_SZ]; +   vf->vp[3] = 1.0; + +   /* translate */ +   vf->vp[4] = viewport[MAT_TX]; +   vf->vp[5] = viewport[MAT_TY]; +   vf->vp[6] = viewport[MAT_TZ]; +   vf->vp[7] = 0.0; +} + +void draw_vf_set_vp_scale_translate( struct draw_vertex_fetch *vf, +				const float *scale, +				const float *translate ) +{ +   assert(vf->allow_viewport_emits); + +   vf->vp[0] = scale[0]; +   vf->vp[1] = scale[1]; +   vf->vp[2] = scale[2]; +   vf->vp[3] = scale[3]; + +   vf->vp[4] = translate[0]; +   vf->vp[5] = translate[1]; +   vf->vp[6] = translate[2]; +   vf->vp[7] = translate[3]; +} + + +/* Set attribute pointers, adjusted for start position: + */ +void draw_vf_set_sources( struct draw_vertex_fetch *vf, +		     GLvector4f * const sources[], +		     unsigned start ) +{ +   struct draw_vf_attr *a = vf->attr; +   unsigned j; +    +   for (j = 0; j < vf->attr_count; j++) { +      const GLvector4f *vptr = sources[a[j].attrib]; +       +      if ((a[j].inputstride != vptr->stride) || +	  (a[j].inputsize != vptr->size)) +	 vf->emit = choose_emit_func; +       +      a[j].inputstride = vptr->stride; +      a[j].inputsize = vptr->size; +      a[j].do_insert = a[j].insert[vptr->size - 1];  +      a[j].inputptr = ((uint8_t *)vptr->data) + start * vptr->stride; +   } +} + + + +/* Emit count VB vertices to dest.   + */ +void draw_vf_emit_vertices( struct draw_vertex_fetch *vf, +		       unsigned count, +		       void *dest ) +{ +   vf->emit( vf, count, (uint8_t*) dest );	 +} + + +/* Extract a named attribute from a hardware vertex.  Will have to + * reverse any viewport transformation, swizzling or other conversions + * which may have been applied. + * + * This is mainly required for on-the-fly vertex translations to + * swrast format. + */ +void draw_vf_get_attr( struct draw_vertex_fetch *vf, +		  const void *vertex, +		  GLenum attr,  +		  const float *dflt, +		  float *dest ) +{ +   const struct draw_vf_attr *a = vf->attr; +   const unsigned attr_count = vf->attr_count; +   unsigned j; + +   for (j = 0; j < attr_count; j++) { +      if (a[j].attrib == attr) { +	 a[j].extract( &a[j], dest, (uint8_t *)vertex + a[j].vertoffset ); +	 return; +      } +   } + +   /* Else return the value from ctx->Current. +    */ +   _mesa_memcpy( dest, dflt, 4*sizeof(float)); +} + + + + +struct draw_vertex_fetch *draw_vf_create( boolean allow_viewport_emits ) +{ +   struct draw_vertex_fetch *vf = CALLOC_STRUCT(draw_vertex_fetch); +   unsigned i; + +   for (i = 0; i < DRAW_VF_ATTRIB_MAX; i++) +      vf->attr[i].vf = vf; + +   vf->allow_viewport_emits = allow_viewport_emits; + +   switch(CHAN_TYPE) { +   case GL_UNSIGNED_BYTE: +      vf->chan_scale[0] = 255.0; +      vf->chan_scale[1] = 255.0; +      vf->chan_scale[2] = 255.0; +      vf->chan_scale[3] = 255.0; +      break; +   case GL_UNSIGNED_SHORT: +      vf->chan_scale[0] = 65535.0; +      vf->chan_scale[1] = 65535.0; +      vf->chan_scale[2] = 65535.0; +      vf->chan_scale[3] = 65535.0; +      break; +   default: +      vf->chan_scale[0] = 1.0; +      vf->chan_scale[1] = 1.0; +      vf->chan_scale[2] = 1.0; +      vf->chan_scale[3] = 1.0; +      break; +   } + +   vf->identity[0] = 0.0; +   vf->identity[1] = 0.0; +   vf->identity[2] = 0.0; +   vf->identity[3] = 1.0; + +   vf->codegen_emit = NULL; + +#ifdef USE_SSE_ASM +   if (!_mesa_getenv("MESA_NO_CODEGEN")) +      vf->codegen_emit = draw_vf_generate_sse_emit; +#endif + +   return vf; +} + + +void draw_vf_destroy( struct draw_vertex_fetch *vf ) +{ +   struct draw_vf_fastpath *fp, *tmp; + +   for (fp = vf->fastpath ; fp ; fp = tmp) { +      tmp = fp->next; +      FREE(fp->attr); + +      /* KW: At the moment, fp->func is constrained to be allocated by +       * _mesa_exec_alloc(), as the hardwired fastpaths in +       * t_vertex_generic.c are handled specially.  It would be nice +       * to unify them, but this probably won't change until this +       * module gets another overhaul. +       */ +      _mesa_exec_free((void *) fp->func); +      FREE(fp); +   } +    +   vf->fastpath = NULL; +   FREE(vf); +} diff --git a/src/mesa/pipe/draw/draw_vf.h b/src/mesa/pipe/draw/draw_vf.h new file mode 100644 index 0000000000..279570aad5 --- /dev/null +++ b/src/mesa/pipe/draw/draw_vf.h @@ -0,0 +1,249 @@ +/* + * Copyright 2003 Tungsten Graphics, inc. + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 (including the next + * paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keithw@tungstengraphics.com> + */ + +#ifndef DRAW_VF_H +#define DRAW_VF_H + + +#include "pipe/p_compiler.h" +#include "math/m_vector.h" + + +enum { +   DRAW_VF_ATTRIB_POS = 0, +   DRAW_VF_ATTRIB_WEIGHT = 1, +   DRAW_VF_ATTRIB_NORMAL = 2, +   DRAW_VF_ATTRIB_COLOR0 = 3, +   DRAW_VF_ATTRIB_COLOR1 = 4, +   DRAW_VF_ATTRIB_FOG = 5, +   DRAW_VF_ATTRIB_COLOR_INDEX = 6, +   DRAW_VF_ATTRIB_EDGEFLAG = 7, +   DRAW_VF_ATTRIB_TEX0 = 8, +   DRAW_VF_ATTRIB_TEX1 = 9, +   DRAW_VF_ATTRIB_TEX2 = 10, +   DRAW_VF_ATTRIB_TEX3 = 11, +   DRAW_VF_ATTRIB_TEX4 = 12, +   DRAW_VF_ATTRIB_TEX5 = 13, +   DRAW_VF_ATTRIB_TEX6 = 14, +   DRAW_VF_ATTRIB_TEX7 = 15, +   DRAW_VF_ATTRIB_VAR0 = 16, +   DRAW_VF_ATTRIB_VAR1 = 17, +   DRAW_VF_ATTRIB_VAR2 = 18, +   DRAW_VF_ATTRIB_VAR3 = 19, +   DRAW_VF_ATTRIB_VAR4 = 20, +   DRAW_VF_ATTRIB_VAR5 = 21, +   DRAW_VF_ATTRIB_VAR6 = 22, +   DRAW_VF_ATTRIB_VAR7 = 23, +   DRAW_VF_ATTRIB_POINTSIZE = 24, +   DRAW_VF_ATTRIB_BFC0 = 25, +   DRAW_VF_ATTRIB_BFC1 = 26, +   DRAW_VF_ATTRIB_CLIP_POS = 27, +   DRAW_VF_ATTRIB_VERTEX_HEADER = 28, +   DRAW_VF_ATTRIB_MAX = 29 +}; + +enum draw_vf_attr_format { +   EMIT_1F, +   EMIT_2F, +   EMIT_3F, +   EMIT_4F, +   EMIT_2F_VIEWPORT,		/**< do viewport transform and emit */ +   EMIT_3F_VIEWPORT,		/**< do viewport transform and emit */ +   EMIT_4F_VIEWPORT,		/**< do viewport transform and emit */ +   EMIT_3F_XYW,			/**< for projective texture */ +   EMIT_1UB_1F,			/**< for fog coordinate */ +   EMIT_3UB_3F_RGB,		/**< for specular color */ +   EMIT_3UB_3F_BGR,		/**< for specular color */ +   EMIT_4UB_4F_RGBA,		/**< for color */ +   EMIT_4UB_4F_BGRA,		/**< for color */ +   EMIT_4UB_4F_ARGB,		/**< for color */ +   EMIT_4UB_4F_ABGR,		/**< for color */ +   EMIT_4CHAN_4F_RGBA,		/**< for swrast color */ +   EMIT_PAD,			/**< leave a hole of 'offset' bytes */ +   EMIT_MAX +}; + +struct draw_vf_attr_map { +   unsigned attrib; +   enum draw_vf_attr_format format; +   unsigned offset; +}; + +struct draw_vertex_fetch; + + +void  +draw_vf_set_vp_matrix( struct draw_vertex_fetch *vf, +                       const float *viewport ); + +void  +draw_vf_set_vp_scale_translate( struct draw_vertex_fetch *vf, +				const float *scale, +				const float *translate ); + +unsigned  +draw_vf_set_vertex_attributes( struct draw_vertex_fetch *vf, +                               const struct draw_vf_attr_map *map, +                               unsigned nr,  +                               unsigned vertex_stride ); + +void  +draw_vf_set_sources( struct draw_vertex_fetch *vf, +		     GLvector4f * const attrib[], +		     unsigned start );  + +void  +draw_vf_emit_vertices( struct draw_vertex_fetch *vf, +		       unsigned count, +		       void *dest ); + +void  +draw_vf_get_attr( struct draw_vertex_fetch *vf, +		  const void *vertex, +		  GLenum attr,  +		  const float *dflt, +		  float *dest ); + +struct draw_vertex_fetch * +draw_vf_create( boolean allow_viewport_emits ); + +void  +draw_vf_destroy( struct draw_vertex_fetch *vf ); + + + +/*********************************************************************** + * Internal functions and structs: + */ + +struct draw_vf_attr; + +typedef void (*draw_vf_extract_func)( const struct draw_vf_attr *a,  +				      float *out,  +				      const uint8_t *v ); + +typedef void (*draw_vf_insert_func)( const struct draw_vf_attr *a,  +				     uint8_t *v,  +				     const float *in ); + +typedef void (*draw_vf_emit_func)( struct draw_vertex_fetch *vf, +      				   unsigned count,  +      				   uint8_t *dest ); + + + +/** + * Describes how to convert/move a vertex attribute from a vertex + * array to a vertex structure. + */ +struct draw_vf_attr +{ +   struct draw_vertex_fetch *vf; + +   unsigned format; +   unsigned inputsize; +   unsigned inputstride; +   unsigned vertoffset;      /**< position of the attrib in the vertex struct */ + +   unsigned attrib;          /**< which vertex attrib (0=position, etc) */ +   unsigned vertattrsize;    /**< size of the attribute in bytes */ + +   uint8_t *inputptr; +   const draw_vf_insert_func *insert; +   draw_vf_insert_func do_insert; +   draw_vf_extract_func extract; +}; + +struct draw_vertex_fetch +{ +   struct draw_vf_attr attr[DRAW_VF_ATTRIB_MAX]; +   unsigned attr_count; +   unsigned vertex_stride; + +   struct draw_vf_attr *lookup[DRAW_VF_ATTRIB_MAX]; +    +   draw_vf_emit_func emit; + +   /* Parameters and constants for codegen: +    */ +   boolean allow_viewport_emits; +   float vp[8];		 +   float chan_scale[4]; +   float identity[4]; + +   struct draw_vf_fastpath *fastpath; +    +   void (*codegen_emit)( struct draw_vertex_fetch *vf ); +}; + + +struct draw_vf_attr_type { +   unsigned format; +   unsigned size; +   unsigned stride; +   unsigned offset; +}; + +struct draw_vf_fastpath { +   unsigned vertex_stride; +   unsigned attr_count; +   boolean match_strides; + +   struct draw_vf_attr_type *attr; + +   draw_vf_emit_func func; +   struct draw_vf_fastpath *next; +}; + + +void  +draw_vf_register_fastpath( struct draw_vertex_fetch *vtx, +                           boolean match_strides ); + +void  +draw_vf_generic_emit( struct draw_vertex_fetch *vf, +                      unsigned count, +                      uint8_t *v ); + +void  +draw_vf_generate_hardwired_emit( struct draw_vertex_fetch *vf ); + +void  +draw_vf_generate_sse_emit( struct draw_vertex_fetch *vf ); + + +struct draw_vf_format_info { +   const char *name; +   draw_vf_extract_func extract; +   draw_vf_insert_func insert[4]; +   const unsigned attrsize; +}; + +const struct draw_vf_format_info draw_vf_format_info[EMIT_MAX]; + + +#endif diff --git a/src/mesa/pipe/draw/draw_vf_generic.c b/src/mesa/pipe/draw/draw_vf_generic.c new file mode 100644 index 0000000000..19e6c587e5 --- /dev/null +++ b/src/mesa/pipe/draw/draw_vf_generic.c @@ -0,0 +1,983 @@ + +/* + * Copyright 2003 Tungsten Graphics, inc. + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 (including the next + * paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keithw@tungstengraphics.com> + */ + +#include "glheader.h" +#include "context.h" +#include "colormac.h" +#include "simple_list.h" + +#include "pipe/p_compiler.h" + +#include "draw_vf.h" + + +/* + * These functions take the NDC coordinates pointed to by 'in', apply the + * NDC->Viewport mapping and store the results at 'v'. + */ + +static INLINE void insert_4f_viewport_4( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = scale[1] * in[1] + trans[1]; +   out[2] = scale[2] * in[2] + trans[2]; +   out[3] = in[3]; +} + +static INLINE void insert_4f_viewport_3( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = scale[1] * in[1] + trans[1]; +   out[2] = scale[2] * in[2] + trans[2]; +   out[3] = 1; +} + +static INLINE void insert_4f_viewport_2( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = scale[1] * in[1] + trans[1]; +   out[2] =                    trans[2]; +   out[3] = 1; +} + +static INLINE void insert_4f_viewport_1( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] =                    trans[1]; +   out[2] =                    trans[2]; +   out[3] = 1; +} + +static INLINE void insert_3f_viewport_3( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = scale[1] * in[1] + trans[1]; +   out[2] = scale[2] * in[2] + trans[2]; +} + +static INLINE void insert_3f_viewport_2( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = scale[1] * in[1] + trans[1]; +   out[2] = scale[2] * in[2] + trans[2]; +} + +static INLINE void insert_3f_viewport_1( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] =                    trans[1]; +   out[2] =                    trans[2]; +} + +static INLINE void insert_2f_viewport_2( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = scale[1] * in[1] + trans[1]; +} + +static INLINE void insert_2f_viewport_1( const struct draw_vf_attr *a, uint8_t *v, +					 const float *in ) +{ +   float *out = (float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = scale[0] * in[0] + trans[0]; +   out[1] = trans[1]; +} + + +/* + * These functions do the same as above, except for the viewport mapping. + */ + +static INLINE void insert_4f_4( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = in[2]; +   out[3] = in[3]; +} + +static INLINE void insert_4f_3( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = in[2]; +   out[3] = 1; +} + +static INLINE void insert_4f_2( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = 0; +   out[3] = 1; +} + +static INLINE void insert_4f_1( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = 0; +   out[2] = 0; +   out[3] = 1; +} + +static INLINE void insert_3f_xyw_4( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = in[3]; +} + +static INLINE void insert_3f_xyw_err( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   (void) a; (void) v; (void) in; +   _mesa_exit(1); +} + +static INLINE void insert_3f_3( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = in[2]; +} + +static INLINE void insert_3f_2( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = 0; +} + +static INLINE void insert_3f_1( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = 0; +   out[2] = 0; +} + + +static INLINE void insert_2f_2( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +} + +static INLINE void insert_2f_1( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; +    +   out[0] = in[0]; +   out[1] = 0; +} + +static INLINE void insert_1f_1( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   float *out = (float *)(v); +   (void) a; + +   out[0] = in[0]; +} + +static INLINE void insert_null( const struct draw_vf_attr *a, uint8_t *v, const float *in ) +{ +   (void) a; (void) v; (void) in; +} + +static INLINE void insert_4chan_4f_rgba_4( const struct draw_vf_attr *a, uint8_t *v,  +					   const float *in ) +{ +   GLchan *c = (GLchan *)v; +   (void) a; +   UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);  +   UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]);  +   UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]);  +   UNCLAMPED_FLOAT_TO_CHAN(c[3], in[3]); +} + +static INLINE void insert_4chan_4f_rgba_3( const struct draw_vf_attr *a, uint8_t *v,  +					   const float *in ) +{ +   GLchan *c = (GLchan *)v; +   (void) a; +   UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);  +   UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]);  +   UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]);  +   c[3] = CHAN_MAX; +} + +static INLINE void insert_4chan_4f_rgba_2( const struct draw_vf_attr *a, uint8_t *v,  +					   const float *in ) +{ +   GLchan *c = (GLchan *)v; +   (void) a; +   UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);  +   UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]);  +   c[2] = 0; +   c[3] = CHAN_MAX; +} + +static INLINE void insert_4chan_4f_rgba_1( const struct draw_vf_attr *a, uint8_t *v,  +					   const float *in ) +{ +   GLchan *c = (GLchan *)v; +   (void) a; +   UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);  +   c[1] = 0; +   c[2] = 0; +   c[3] = CHAN_MAX; +} + +static INLINE void insert_4ub_4f_rgba_4( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]); +} + +static INLINE void insert_4ub_4f_rgba_3( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); +   v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_rgba_2( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   v[2] = 0; +   v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_rgba_1( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   v[1] = 0; +   v[2] = 0; +   v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_bgra_4( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]); +} + +static INLINE void insert_4ub_4f_bgra_3( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); +   v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_bgra_2( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   v[0] = 0; +   v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_bgra_1( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   v[1] = 0; +   v[0] = 0; +   v[3] = 0xff; +} + +static INLINE void insert_4ub_4f_argb_4( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]); +} + +static INLINE void insert_4ub_4f_argb_3( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]); +   v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_argb_2( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); +   v[3] = 0x00; +   v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_argb_1( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]); +   v[2] = 0x00; +   v[3] = 0x00; +   v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_abgr_4( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]); +} + +static INLINE void insert_4ub_4f_abgr_3( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]); +   v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_abgr_2( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]); +   v[1] = 0x00; +   v[0] = 0xff; +} + +static INLINE void insert_4ub_4f_abgr_1( const struct draw_vf_attr *a, uint8_t *v,  +					 const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]); +   v[2] = 0x00; +   v[1] = 0x00; +   v[0] = 0xff; +} + +static INLINE void insert_3ub_3f_rgb_3( const struct draw_vf_attr *a, uint8_t *v,  +					const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]); +} + +static INLINE void insert_3ub_3f_rgb_2( const struct draw_vf_attr *a, uint8_t *v,  +					const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   v[2] = 0; +} + +static INLINE void insert_3ub_3f_rgb_1( const struct draw_vf_attr *a, uint8_t *v,  +					const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +   v[1] = 0; +   v[2] = 0; +} + +static INLINE void insert_3ub_3f_bgr_3( const struct draw_vf_attr *a, uint8_t *v,  +					const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]); +} + +static INLINE void insert_3ub_3f_bgr_2( const struct draw_vf_attr *a, uint8_t *v,  +					const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]); +   v[0] = 0; +} + +static INLINE void insert_3ub_3f_bgr_1( const struct draw_vf_attr *a, uint8_t *v,  +					const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]); +   v[1] = 0; +   v[0] = 0; +} + + +static INLINE void insert_1ub_1f_1( const struct draw_vf_attr *a, uint8_t *v,  +				    const float *in ) +{ +   (void) a; +   UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]); +} + + +/*********************************************************************** + * Functions to perform the reverse operations to the above, for + * swrast translation and clip-interpolation. + *  + * Currently always extracts a full 4 floats. + */ + +static void extract_4f_viewport( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   const float *in = (const float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   /* Although included for completeness, the position coordinate is +    * usually handled differently during clipping. +    */ +   out[0] = (in[0] - trans[0]) / scale[0]; +   out[1] = (in[1] - trans[1]) / scale[1]; +   out[2] = (in[2] - trans[2]) / scale[2]; +   out[3] = in[3]; +} + +static void extract_3f_viewport( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   const float *in = (const float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = (in[0] - trans[0]) / scale[0]; +   out[1] = (in[1] - trans[1]) / scale[1]; +   out[2] = (in[2] - trans[2]) / scale[2]; +   out[3] = 1; +} + + +static void extract_2f_viewport( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   const float *in = (const float *)v; +   const float *scale = a->vf->vp; +   const float *trans = a->vf->vp + 4; +    +   out[0] = (in[0] - trans[0]) / scale[0]; +   out[1] = (in[1] - trans[1]) / scale[1]; +   out[2] = 0; +   out[3] = 1; +} + + +static void extract_4f( const struct draw_vf_attr *a, float *out, const uint8_t *v  ) +{ +   const float *in = (const float *)v; +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = in[2]; +   out[3] = in[3]; +} + +static void extract_3f_xyw( const struct draw_vf_attr *a, float *out, const uint8_t *v ) +{ +   const float *in = (const float *)v; +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = 0; +   out[3] = in[2]; +} + + +static void extract_3f( const struct draw_vf_attr *a, float *out, const uint8_t *v ) +{ +   const float *in = (const float *)v; +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = in[2]; +   out[3] = 1; +} + + +static void extract_2f( const struct draw_vf_attr *a, float *out, const uint8_t *v ) +{ +   const float *in = (const float *)v; +   (void) a; +    +   out[0] = in[0]; +   out[1] = in[1]; +   out[2] = 0; +   out[3] = 1; +} + +static void extract_1f( const struct draw_vf_attr *a, float *out, const uint8_t *v ) +{ +   const float *in = (const float *)v; +   (void) a; +    +   out[0] = in[0]; +   out[1] = 0; +   out[2] = 0; +   out[3] = 1; +} + +static void extract_4chan_4f_rgba( const struct draw_vf_attr *a, float *out,  +				   const uint8_t *v ) +{ +   GLchan *c = (GLchan *)v; +   (void) a; + +   out[0] = CHAN_TO_FLOAT(c[0]); +   out[1] = CHAN_TO_FLOAT(c[1]); +   out[2] = CHAN_TO_FLOAT(c[2]); +   out[3] = CHAN_TO_FLOAT(c[3]); +} + +static void extract_4ub_4f_rgba( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   (void) a; +   out[0] = UBYTE_TO_FLOAT(v[0]); +   out[1] = UBYTE_TO_FLOAT(v[1]); +   out[2] = UBYTE_TO_FLOAT(v[2]); +   out[3] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_4ub_4f_bgra( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   (void) a; +   out[2] = UBYTE_TO_FLOAT(v[0]); +   out[1] = UBYTE_TO_FLOAT(v[1]); +   out[0] = UBYTE_TO_FLOAT(v[2]); +   out[3] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_4ub_4f_argb( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   (void) a; +   out[3] = UBYTE_TO_FLOAT(v[0]); +   out[0] = UBYTE_TO_FLOAT(v[1]); +   out[1] = UBYTE_TO_FLOAT(v[2]); +   out[2] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_4ub_4f_abgr( const struct draw_vf_attr *a, float *out,  +				 const uint8_t *v ) +{ +   (void) a; +   out[3] = UBYTE_TO_FLOAT(v[0]); +   out[2] = UBYTE_TO_FLOAT(v[1]); +   out[1] = UBYTE_TO_FLOAT(v[2]); +   out[0] = UBYTE_TO_FLOAT(v[3]); +} + +static void extract_3ub_3f_rgb( const struct draw_vf_attr *a, float *out,  +				const uint8_t *v ) +{ +   (void) a; +   out[0] = UBYTE_TO_FLOAT(v[0]); +   out[1] = UBYTE_TO_FLOAT(v[1]); +   out[2] = UBYTE_TO_FLOAT(v[2]); +   out[3] = 1; +} + +static void extract_3ub_3f_bgr( const struct draw_vf_attr *a, float *out,  +				const uint8_t *v ) +{ +   (void) a; +   out[2] = UBYTE_TO_FLOAT(v[0]); +   out[1] = UBYTE_TO_FLOAT(v[1]); +   out[0] = UBYTE_TO_FLOAT(v[2]); +   out[3] = 1; +} + +static void extract_1ub_1f( const struct draw_vf_attr *a, float *out, const uint8_t *v ) +{ +   (void) a; +   out[0] = UBYTE_TO_FLOAT(v[0]); +   out[1] = 0; +   out[2] = 0; +   out[3] = 1; +} + + +const struct draw_vf_format_info draw_vf_format_info[EMIT_MAX] =  +{ +   { "1f", +     extract_1f, +     { insert_1f_1, insert_1f_1, insert_1f_1, insert_1f_1 }, +     sizeof(float) }, + +   { "2f", +     extract_2f, +     { insert_2f_1, insert_2f_2, insert_2f_2, insert_2f_2 }, +     2 * sizeof(float) }, + +   { "3f", +     extract_3f, +     { insert_3f_1, insert_3f_2, insert_3f_3, insert_3f_3 }, +     3 * sizeof(float) }, + +   { "4f", +     extract_4f, +     { insert_4f_1, insert_4f_2, insert_4f_3, insert_4f_4 }, +     4 * sizeof(float) }, + +   { "2f_viewport", +     extract_2f_viewport, +     { insert_2f_viewport_1, insert_2f_viewport_2, insert_2f_viewport_2, +       insert_2f_viewport_2 }, +     2 * sizeof(float) }, + +   { "3f_viewport", +     extract_3f_viewport, +     { insert_3f_viewport_1, insert_3f_viewport_2, insert_3f_viewport_3, +       insert_3f_viewport_3 }, +     3 * sizeof(float) }, + +   { "4f_viewport", +     extract_4f_viewport, +     { insert_4f_viewport_1, insert_4f_viewport_2, insert_4f_viewport_3, +       insert_4f_viewport_4 },  +     4 * sizeof(float) }, + +   { "3f_xyw", +     extract_3f_xyw, +     { insert_3f_xyw_err, insert_3f_xyw_err, insert_3f_xyw_err,  +       insert_3f_xyw_4 }, +     3 * sizeof(float) }, + +   { "1ub_1f", +     extract_1ub_1f, +     { insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1 }, +     sizeof(uint8_t) }, + +   { "3ub_3f_rgb", +     extract_3ub_3f_rgb, +     { insert_3ub_3f_rgb_1, insert_3ub_3f_rgb_2, insert_3ub_3f_rgb_3, +       insert_3ub_3f_rgb_3 }, +     3 * sizeof(uint8_t) }, + +   { "3ub_3f_bgr", +     extract_3ub_3f_bgr, +     { insert_3ub_3f_bgr_1, insert_3ub_3f_bgr_2, insert_3ub_3f_bgr_3, +       insert_3ub_3f_bgr_3 }, +     3 * sizeof(uint8_t) }, + +   { "4ub_4f_rgba", +     extract_4ub_4f_rgba, +     { insert_4ub_4f_rgba_1, insert_4ub_4f_rgba_2, insert_4ub_4f_rgba_3,  +       insert_4ub_4f_rgba_4 }, +     4 * sizeof(uint8_t) }, + +   { "4ub_4f_bgra", +     extract_4ub_4f_bgra, +     { insert_4ub_4f_bgra_1, insert_4ub_4f_bgra_2, insert_4ub_4f_bgra_3, +       insert_4ub_4f_bgra_4 }, +     4 * sizeof(uint8_t) }, + +   { "4ub_4f_argb", +     extract_4ub_4f_argb, +     { insert_4ub_4f_argb_1, insert_4ub_4f_argb_2, insert_4ub_4f_argb_3, +       insert_4ub_4f_argb_4 }, +     4 * sizeof(uint8_t) }, + +   { "4ub_4f_abgr", +     extract_4ub_4f_abgr, +     { insert_4ub_4f_abgr_1, insert_4ub_4f_abgr_2, insert_4ub_4f_abgr_3, +       insert_4ub_4f_abgr_4 }, +     4 * sizeof(uint8_t) }, + +   { "4chan_4f_rgba", +     extract_4chan_4f_rgba, +     { insert_4chan_4f_rgba_1, insert_4chan_4f_rgba_2, insert_4chan_4f_rgba_3, +       insert_4chan_4f_rgba_4 }, +     4 * sizeof(GLchan) }, + +   { "pad", +     NULL, +     { NULL, NULL, NULL, NULL }, +     0 } + +}; + + + +     +/*********************************************************************** + * Hardwired fastpaths for emitting whole vertices or groups of + * vertices + */ +#define EMIT5(NR, F0, F1, F2, F3, F4, NAME)				\ +static void NAME( struct draw_vertex_fetch *vf,				\ +		  unsigned count,						\ +		  uint8_t *v )						\ +{									\ +   struct draw_vf_attr *a = vf->attr;				\ +   unsigned i;								\ +									\ +   for (i = 0 ; i < count ; i++, v += vf->vertex_stride) {		\ +      if (NR > 0) {							\ +	 F0( &a[0], v + a[0].vertoffset, (float *)a[0].inputptr );	\ +	 a[0].inputptr += a[0].inputstride;				\ +      }									\ +      									\ +      if (NR > 1) {							\ +	 F1( &a[1], v + a[1].vertoffset, (float *)a[1].inputptr );	\ +	 a[1].inputptr += a[1].inputstride;				\ +      }									\ +      									\ +      if (NR > 2) {							\ +	 F2( &a[2], v + a[2].vertoffset, (float *)a[2].inputptr );	\ +	 a[2].inputptr += a[2].inputstride;				\ +      }									\ +      									\ +      if (NR > 3) {							\ +	 F3( &a[3], v + a[3].vertoffset, (float *)a[3].inputptr );	\ +	 a[3].inputptr += a[3].inputstride;				\ +      }									\ +									\ +      if (NR > 4) {							\ +	 F4( &a[4], v + a[4].vertoffset, (float *)a[4].inputptr );	\ +	 a[4].inputptr += a[4].inputstride;				\ +      }									\ +   }									\ +} + +    +#define EMIT2(F0, F1, NAME) EMIT5(2, F0, F1, insert_null, \ +				  insert_null, insert_null, NAME) + +#define EMIT3(F0, F1, F2, NAME) EMIT5(3, F0, F1, F2, insert_null, \ +				      insert_null, NAME) +    +#define EMIT4(F0, F1, F2, F3, NAME) EMIT5(4, F0, F1, F2, F3, \ +				          insert_null, NAME) +    + +EMIT2(insert_3f_viewport_3, insert_4ub_4f_rgba_4, emit_viewport3_rgba4) +EMIT2(insert_3f_viewport_3, insert_4ub_4f_bgra_4, emit_viewport3_bgra4) +EMIT2(insert_3f_3, insert_4ub_4f_rgba_4, emit_xyz3_rgba4) + +EMIT3(insert_4f_viewport_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_viewport4_rgba4_st2) +EMIT3(insert_4f_viewport_4, insert_4ub_4f_bgra_4, insert_2f_2,  emit_viewport4_bgra4_st2) +EMIT3(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_xyzw4_rgba4_st2) + +EMIT4(insert_4f_viewport_4, insert_4ub_4f_rgba_4, insert_2f_2, insert_2f_2, emit_viewport4_rgba4_st2_st2) +EMIT4(insert_4f_viewport_4, insert_4ub_4f_bgra_4, insert_2f_2, insert_2f_2,  emit_viewport4_bgra4_st2_st2) +EMIT4(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, insert_2f_2, emit_xyzw4_rgba4_st2_st2) + + +/* Use the codegen paths to select one of a number of hardwired + * fastpaths. + */ +void draw_vf_generate_hardwired_emit( struct draw_vertex_fetch *vf ) +{ +   draw_vf_emit_func func = NULL; + +   /* Does it fit a hardwired fastpath?  Help! this is growing out of +    * control! +    */ +   switch (vf->attr_count) { +   case 2: +      if (vf->attr[0].do_insert == insert_3f_viewport_3) { +	 if (vf->attr[1].do_insert == insert_4ub_4f_bgra_4)  +	    func = emit_viewport3_bgra4; +	 else if (vf->attr[1].do_insert == insert_4ub_4f_rgba_4)  +	    func = emit_viewport3_rgba4; +      } +      else if (vf->attr[0].do_insert == insert_3f_3 && +	       vf->attr[1].do_insert == insert_4ub_4f_rgba_4) { + 	 func = emit_xyz3_rgba4;  +      } +      break; +   case 3: +      if (vf->attr[2].do_insert == insert_2f_2) { +	 if (vf->attr[1].do_insert == insert_4ub_4f_rgba_4) { +	    if (vf->attr[0].do_insert == insert_4f_viewport_4) +	       func = emit_viewport4_rgba4_st2; +	    else if (vf->attr[0].do_insert == insert_4f_4)  +	       func = emit_xyzw4_rgba4_st2; +	 } +	 else if (vf->attr[1].do_insert == insert_4ub_4f_bgra_4 && +		  vf->attr[0].do_insert == insert_4f_viewport_4) +	    func = emit_viewport4_bgra4_st2; +      } +      break; +   case 4: +      if (vf->attr[2].do_insert == insert_2f_2 && +	  vf->attr[3].do_insert == insert_2f_2) { +	 if (vf->attr[1].do_insert == insert_4ub_4f_rgba_4) { +	    if (vf->attr[0].do_insert == insert_4f_viewport_4) +	       func = emit_viewport4_rgba4_st2_st2; +	    else if (vf->attr[0].do_insert == insert_4f_4)  +	       func = emit_xyzw4_rgba4_st2_st2; +	 } +	 else if (vf->attr[1].do_insert == insert_4ub_4f_bgra_4 && +		  vf->attr[0].do_insert == insert_4f_viewport_4) +	    func = emit_viewport4_bgra4_st2_st2; +      } +      break; +   } + +   vf->emit = func; +} + +/*********************************************************************** + * Generic (non-codegen) functions for whole vertices or groups of + * vertices + */ + +void draw_vf_generic_emit( struct draw_vertex_fetch *vf, +		      unsigned count, +		      uint8_t *v ) +{ +   struct draw_vf_attr *a = vf->attr; +   const unsigned attr_count = vf->attr_count; +   const unsigned stride = vf->vertex_stride; +   unsigned i, j; + +   for (i = 0 ; i < count ; i++, v += stride) { +      for (j = 0; j < attr_count; j++) { +	 float *in = (float *)a[j].inputptr; +	 a[j].inputptr += a[j].inputstride; +	 a[j].do_insert( &a[j], v + a[j].vertoffset, in ); +      } +   } +} + + diff --git a/src/mesa/pipe/draw/draw_vf_sse.c b/src/mesa/pipe/draw/draw_vf_sse.c new file mode 100644 index 0000000000..2cf3a45ff9 --- /dev/null +++ b/src/mesa/pipe/draw/draw_vf_sse.c @@ -0,0 +1,664 @@ +/* + * Copyright 2003 Tungsten Graphics, inc. + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 (including the next + * paragraph) 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 NON-INFRINGEMENT.  IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keithw@tungstengraphics.com> + */ + +#include "glheader.h" +#include "colormac.h" +#include "simple_list.h" +#include "enums.h" + +#include "pipe/p_compiler.h" + +#include "draw_vf.h" + +#if defined(USE_SSE_ASM) + +#include "x86/rtasm/x86sse.h" +#include "x86/common_x86_asm.h" + + +#define X    0 +#define Y    1 +#define Z    2 +#define W    3 + + +struct x86_program { +   struct x86_function func; + +   struct draw_vertex_fetch *vf; +   boolean inputs_safe; +   boolean outputs_safe; +   boolean have_sse2; +    +   struct x86_reg identity; +   struct x86_reg chan0; +}; + + +static struct x86_reg get_identity( struct x86_program *p ) +{ +   return p->identity; +} + +static void emit_load4f_4( struct x86_program *p, 			    +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   sse_movups(&p->func, dest, arg0); +} + +static void emit_load4f_3( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   /* Have to jump through some hoops: +    * +    * c 0 0 0 +    * c 0 0 1 +    * 0 0 c 1 +    * a b c 1 +    */ +   sse_movss(&p->func, dest, x86_make_disp(arg0, 8)); +   sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) ); +   sse_shufps(&p->func, dest, dest, SHUF(Y,Z,X,W) ); +   sse_movlps(&p->func, dest, arg0); +} + +static void emit_load4f_2( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   /* Initialize from identity, then pull in low two words: +    */ +   sse_movups(&p->func, dest, get_identity(p)); +   sse_movlps(&p->func, dest, arg0); +} + +static void emit_load4f_1( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   /* Pull in low word, then swizzle in identity */ +   sse_movss(&p->func, dest, arg0); +   sse_shufps(&p->func, dest, get_identity(p), SHUF(X,Y,Z,W) ); +} + + + +static void emit_load3f_3( struct x86_program *p, 			    +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   /* Over-reads by 1 dword - potential SEGV if input is a vertex +    * array. +    */ +   if (p->inputs_safe) { +      sse_movups(&p->func, dest, arg0); +   }  +   else { +      /* c 0 0 0 +       * c c c c +       * a b c c  +       */ +      sse_movss(&p->func, dest, x86_make_disp(arg0, 8)); +      sse_shufps(&p->func, dest, dest, SHUF(X,X,X,X)); +      sse_movlps(&p->func, dest, arg0); +   } +} + +static void emit_load3f_2( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   emit_load4f_2(p, dest, arg0); +} + +static void emit_load3f_1( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   emit_load4f_1(p, dest, arg0); +} + +static void emit_load2f_2( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   sse_movlps(&p->func, dest, arg0); +} + +static void emit_load2f_1( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   emit_load4f_1(p, dest, arg0); +} + +static void emit_load1f_1( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   sse_movss(&p->func, dest, arg0); +} + +static void (*load[4][4])( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) = { +   { emit_load1f_1,  +     emit_load1f_1,  +     emit_load1f_1,  +     emit_load1f_1 }, + +   { emit_load2f_1,  +     emit_load2f_2,  +     emit_load2f_2,  +     emit_load2f_2 }, + +   { emit_load3f_1,  +     emit_load3f_2,  +     emit_load3f_3,  +     emit_load3f_3 }, + +   { emit_load4f_1,  +     emit_load4f_2,  +     emit_load4f_3,  +     emit_load4f_4 }  +}; + +static void emit_load( struct x86_program *p, +		       struct x86_reg dest, +		       unsigned sz, +		       struct x86_reg src, +		       unsigned src_sz) +{ +   load[sz-1][src_sz-1](p, dest, src); +} + +static void emit_store4f( struct x86_program *p, 			    +			  struct x86_reg dest, +			  struct x86_reg arg0 ) +{ +   sse_movups(&p->func, dest, arg0); +} + +static void emit_store3f( struct x86_program *p,  +			  struct x86_reg dest, +			  struct x86_reg arg0 ) +{ +   if (p->outputs_safe) { +      /* Emit the extra dword anyway.  This may hurt writecombining, +       * may cause other problems. +       */ +      sse_movups(&p->func, dest, arg0); +   } +   else { +      /* Alternate strategy - emit two, shuffle, emit one. +       */ +      sse_movlps(&p->func, dest, arg0); +      sse_shufps(&p->func, arg0, arg0, SHUF(Z,Z,Z,Z) ); /* NOTE! destructive */ +      sse_movss(&p->func, x86_make_disp(dest,8), arg0); +   } +} + +static void emit_store2f( struct x86_program *p,  +			   struct x86_reg dest, +			   struct x86_reg arg0 ) +{ +   sse_movlps(&p->func, dest, arg0); +} + +static void emit_store1f( struct x86_program *p,  +			  struct x86_reg dest, +			  struct x86_reg arg0 ) +{ +   sse_movss(&p->func, dest, arg0); +} + + +static void (*store[4])( struct x86_program *p,  +			 struct x86_reg dest, +			 struct x86_reg arg0 ) =  +{ +   emit_store1f,  +   emit_store2f,  +   emit_store3f,  +   emit_store4f  +}; + +static void emit_store( struct x86_program *p, +			struct x86_reg dest, +			unsigned sz, +			struct x86_reg temp ) + +{ +   store[sz-1](p, dest, temp); +} + +static void emit_pack_store_4ub( struct x86_program *p, +				 struct x86_reg dest, +				 struct x86_reg temp ) +{ +   /* Scale by 255.0 +    */ +   sse_mulps(&p->func, temp, p->chan0); + +   if (p->have_sse2) { +      sse2_cvtps2dq(&p->func, temp, temp); +      sse2_packssdw(&p->func, temp, temp); +      sse2_packuswb(&p->func, temp, temp); +      sse_movss(&p->func, dest, temp); +   } +   else { +      struct x86_reg mmx0 = x86_make_reg(file_MMX, 0); +      struct x86_reg mmx1 = x86_make_reg(file_MMX, 1); +      sse_cvtps2pi(&p->func, mmx0, temp); +      sse_movhlps(&p->func, temp, temp); +      sse_cvtps2pi(&p->func, mmx1, temp); +      mmx_packssdw(&p->func, mmx0, mmx1); +      mmx_packuswb(&p->func, mmx0, mmx0); +      mmx_movd(&p->func, dest, mmx0); +   } +} + +static int get_offset( const void *a, const void *b ) +{ +   return (const char *)b - (const char *)a; +} + +/* Not much happens here.  Eventually use this function to try and + * avoid saving/reloading the source pointers each vertex (if some of + * them can fit in registers). + */ +static void get_src_ptr( struct x86_program *p, +			 struct x86_reg srcREG, +			 struct x86_reg vfREG, +			 struct draw_vf_attr *a ) +{ +   struct draw_vertex_fetch *vf = p->vf; +   struct x86_reg ptr_to_src = x86_make_disp(vfREG, get_offset(vf, &a->inputptr)); + +   /* Load current a[j].inputptr +    */ +   x86_mov(&p->func, srcREG, ptr_to_src); +} + +static void update_src_ptr( struct x86_program *p, +			 struct x86_reg srcREG, +			 struct x86_reg vfREG, +			 struct draw_vf_attr *a ) +{ +   if (a->inputstride) { +      struct draw_vertex_fetch *vf = p->vf; +      struct x86_reg ptr_to_src = x86_make_disp(vfREG, get_offset(vf, &a->inputptr)); + +      /* add a[j].inputstride (hardcoded value - could just as easily +       * pull the stride value from memory each time). +       */ +      x86_lea(&p->func, srcREG, x86_make_disp(srcREG, a->inputstride)); +       +      /* save new value of a[j].inputptr  +       */ +      x86_mov(&p->func, ptr_to_src, srcREG); +   } +} + + +/* Lots of hardcoding + * + * EAX -- pointer to current output vertex + * ECX -- pointer to current attribute  + *  + */ +static boolean build_vertex_emit( struct x86_program *p ) +{ +   struct draw_vertex_fetch *vf = p->vf; +   unsigned j = 0; + +   struct x86_reg vertexEAX = x86_make_reg(file_REG32, reg_AX); +   struct x86_reg srcECX = x86_make_reg(file_REG32, reg_CX); +   struct x86_reg countEBP = x86_make_reg(file_REG32, reg_BP); +   struct x86_reg vfESI = x86_make_reg(file_REG32, reg_SI); +   struct x86_reg temp = x86_make_reg(file_XMM, 0); +   struct x86_reg vp0 = x86_make_reg(file_XMM, 1); +   struct x86_reg vp1 = x86_make_reg(file_XMM, 2); +   uint8_t *fixup, *label; + +   /* Push a few regs? +    */ +   x86_push(&p->func, countEBP); +   x86_push(&p->func, vfESI); + + +   /* Get vertex count, compare to zero +    */ +   x86_xor(&p->func, srcECX, srcECX); +   x86_mov(&p->func, countEBP, x86_fn_arg(&p->func, 2)); +   x86_cmp(&p->func, countEBP, srcECX); +   fixup = x86_jcc_forward(&p->func, cc_E); + +   /* Initialize destination register.  +    */ +   x86_mov(&p->func, vertexEAX, x86_fn_arg(&p->func, 3)); + +   /* Move argument 1 (vf) into a reg: +    */ +   x86_mov(&p->func, vfESI, x86_fn_arg(&p->func, 1)); + +    +   /* Possibly load vp0, vp1 for viewport calcs: +    */ +   if (vf->allow_viewport_emits) { +      sse_movups(&p->func, vp0, x86_make_disp(vfESI, get_offset(vf, &vf->vp[0]))); +      sse_movups(&p->func, vp1, x86_make_disp(vfESI, get_offset(vf, &vf->vp[4]))); +   } + +   /* always load, needed or not: +    */ +   sse_movups(&p->func, p->chan0, x86_make_disp(vfESI, get_offset(vf, &vf->chan_scale[0]))); +   sse_movups(&p->func, p->identity, x86_make_disp(vfESI, get_offset(vf, &vf->identity[0]))); + +   /* Note address for loop jump */ +   label = x86_get_label(&p->func); + +   /* Emit code for each of the attributes.  Currently routes +    * everything through SSE registers, even when it might be more +    * efficient to stick with regular old x86.  No optimization or +    * other tricks - enough new ground to cover here just getting +    * things working. +    */ +   while (j < vf->attr_count) { +      struct draw_vf_attr *a = &vf->attr[j]; +      struct x86_reg dest = x86_make_disp(vertexEAX, a->vertoffset); + +      /* Now, load an XMM reg from src, perhaps transform, then save. +       * Could be shortcircuited in specific cases: +       */ +      switch (a->format) { +      case EMIT_1F: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize); +	 emit_store(p, dest, 1, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_2F: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); +	 emit_store(p, dest, 2, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_3F: +	 /* Potentially the worst case - hardcode 2+1 copying: +	  */ +	 if (0) { +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); +	    emit_store(p, dest, 3, temp); +	    update_src_ptr(p, srcECX, vfESI, a); +	 } +	 else { +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); +	    emit_store(p, dest, 2, temp); +	    if (a->inputsize > 2) { +	       emit_load(p, temp, 1, x86_make_disp(srcECX, 8), 1); +	       emit_store(p, x86_make_disp(dest,8), 1, temp); +	    } +	    else { +	       sse_movss(&p->func, x86_make_disp(dest,8), get_identity(p)); +	    } +	    update_src_ptr(p, srcECX, vfESI, a); +	 } +	 break; +      case EMIT_4F: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 emit_store(p, dest, 4, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_2F_VIEWPORT:  +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 2, x86_deref(srcECX), a->inputsize); +	 sse_mulps(&p->func, temp, vp0); +	 sse_addps(&p->func, temp, vp1); +	 emit_store(p, dest, 2, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_3F_VIEWPORT:  +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); +	 sse_mulps(&p->func, temp, vp0); +	 sse_addps(&p->func, temp, vp1); +	 emit_store(p, dest, 3, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_4F_VIEWPORT:  +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 sse_mulps(&p->func, temp, vp0); +	 sse_addps(&p->func, temp, vp1); +	 emit_store(p, dest, 4, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_3F_XYW: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 sse_shufps(&p->func, temp, temp, SHUF(X,Y,W,Z)); +	 emit_store(p, dest, 3, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; + +      case EMIT_1UB_1F:	  +	 /* Test for PAD3 + 1UB: +	  */ +	 if (j > 0 && +	     a[-1].vertoffset + a[-1].vertattrsize <= a->vertoffset - 3) +	 { +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 1, x86_deref(srcECX), a->inputsize); +	    sse_shufps(&p->func, temp, temp, SHUF(X,X,X,X)); +	    emit_pack_store_4ub(p, x86_make_disp(dest, -3), temp); /* overkill! */ +	    update_src_ptr(p, srcECX, vfESI, a); +	 } +	 else { +	    _mesa_printf("Can't emit 1ub %x %x %d\n", a->vertoffset, a[-1].vertoffset, a[-1].vertattrsize ); +	    return FALSE; +	 } +	 break; +      case EMIT_3UB_3F_RGB: +      case EMIT_3UB_3F_BGR: +	 /* Test for 3UB + PAD1: +	  */ +	 if (j == vf->attr_count - 1 || +	     a[1].vertoffset >= a->vertoffset + 4) { +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); +	    if (a->format == EMIT_3UB_3F_BGR) +	       sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W)); +	    emit_pack_store_4ub(p, dest, temp); +	    update_src_ptr(p, srcECX, vfESI, a); +	 } +	 /* Test for 3UB + 1UB: +	  */ +	 else if (j < vf->attr_count - 1 && +		  a[1].format == EMIT_1UB_1F && +		  a[1].vertoffset == a->vertoffset + 3) { +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 3, x86_deref(srcECX), a->inputsize); +	    update_src_ptr(p, srcECX, vfESI, a); + +	    /* Make room for incoming value: +	     */ +	    sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z)); + +	    get_src_ptr(p, srcECX, vfESI, &a[1]); +	    emit_load(p, temp, 1, x86_deref(srcECX), a[1].inputsize); +	    update_src_ptr(p, srcECX, vfESI, &a[1]); + +	    /* Rearrange and possibly do BGR conversion: +	     */ +	    if (a->format == EMIT_3UB_3F_BGR) +	       sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X)); +	    else +	       sse_shufps(&p->func, temp, temp, SHUF(Y,Z,W,X)); + +	    emit_pack_store_4ub(p, dest, temp); +	    j++;		/* NOTE: two attrs consumed */ +	 } +	 else { +	    _mesa_printf("Can't emit 3ub\n"); +	 } +	 return FALSE;	/* add this later */ +	 break; + +      case EMIT_4UB_4F_RGBA: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 emit_pack_store_4ub(p, dest, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_4UB_4F_BGRA: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 sse_shufps(&p->func, temp, temp, SHUF(Z,Y,X,W)); +	 emit_pack_store_4ub(p, dest, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_4UB_4F_ARGB: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 sse_shufps(&p->func, temp, temp, SHUF(W,X,Y,Z)); +	 emit_pack_store_4ub(p, dest, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_4UB_4F_ABGR: +	 get_src_ptr(p, srcECX, vfESI, a); +	 emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	 sse_shufps(&p->func, temp, temp, SHUF(W,Z,Y,X)); +	 emit_pack_store_4ub(p, dest, temp); +	 update_src_ptr(p, srcECX, vfESI, a); +	 break; +      case EMIT_4CHAN_4F_RGBA: +	 switch (CHAN_TYPE) { +	 case GL_UNSIGNED_BYTE: +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	    emit_pack_store_4ub(p, dest, temp); +	    update_src_ptr(p, srcECX, vfESI, a); +	    break; +	 case GL_FLOAT: +	    get_src_ptr(p, srcECX, vfESI, a); +	    emit_load(p, temp, 4, x86_deref(srcECX), a->inputsize); +	    emit_store(p, dest, 4, temp); +	    update_src_ptr(p, srcECX, vfESI, a); +	    break; +	 case GL_UNSIGNED_SHORT: +	 default: +	    _mesa_printf("unknown CHAN_TYPE %s\n", _mesa_lookup_enum_by_nr(CHAN_TYPE)); +	    return FALSE; +	 } +	 break; +      default: +	 _mesa_printf("unknown a[%d].format %d\n", j, a->format); +	 return FALSE;	/* catch any new opcodes */ +      } +       +      /* Increment j by at least 1 - may have been incremented above also: +       */ +      j++; +   } + +   /* Next vertex: +    */ +   x86_lea(&p->func, vertexEAX, x86_make_disp(vertexEAX, vf->vertex_stride)); + +   /* decr count, loop if not zero +    */ +   x86_dec(&p->func, countEBP); +   x86_test(&p->func, countEBP, countEBP);  +   x86_jcc(&p->func, cc_NZ, label); + +   /* Exit mmx state? +    */ +   if (p->func.need_emms) +      mmx_emms(&p->func); + +   /* Land forward jump here: +    */ +   x86_fixup_fwd_jump(&p->func, fixup); + +   /* Pop regs and return +    */ +   x86_pop(&p->func, x86_get_base_reg(vfESI)); +   x86_pop(&p->func, countEBP); +   x86_ret(&p->func); + +   vf->emit = (draw_vf_emit_func)x86_get_func(&p->func); +   return TRUE; +} + + + +void draw_vf_generate_sse_emit( struct draw_vertex_fetch *vf ) +{ +   struct x86_program p;    + +   if (!cpu_has_xmm) { +      vf->codegen_emit = NULL; +      return; +   } + +   _mesa_memset(&p, 0, sizeof(p)); + +   p.vf = vf; +   p.inputs_safe = 0;		/* for now */ +   p.outputs_safe = 1;		/* for now */ +   p.have_sse2 = cpu_has_xmm2; +   p.identity = x86_make_reg(file_XMM, 6); +   p.chan0 = x86_make_reg(file_XMM, 7); + +   x86_init_func(&p.func); + +   if (build_vertex_emit(&p)) { +      draw_vf_register_fastpath( vf, TRUE ); +   } +   else { +      /* Note the failure so that we don't keep trying to codegen an +       * impossible state: +       */ +      draw_vf_register_fastpath( vf, FALSE ); +      x86_release_func(&p.func); +   } +} + +#else + +void draw_vf_generate_sse_emit( struct draw_vertex_fetch *vf ) +{ +   /* Dummy version for when USE_SSE_ASM not defined */ +} + +#endif diff --git a/src/mesa/sources b/src/mesa/sources index 97ef7e1936..e31d8cc466 100644 --- a/src/mesa/sources +++ b/src/mesa/sources @@ -175,6 +175,9 @@ DRAW_SOURCES = \  	pipe/draw/draw_vertex_fetch.c \  	pipe/draw/draw_vertex_shader.c \  	pipe/draw/draw_vertex_shader_llvm.c \ +	pipe/draw/draw_vf.c \ +	pipe/draw/draw_vf_generic.c \ +	pipe/draw/draw_vf_sse.c \  	pipe/draw/draw_wide_prims.c  TGSIEXEC_SOURCES = \  | 
