draw: remove draw_vf code, use translate instead

This commit is contained in:
Keith Whitwell 2008-04-18 20:05:36 +01:00
parent 7b34a43d1a
commit cb9f0a5896
8 changed files with 115 additions and 1890 deletions

View file

@ -35,9 +35,6 @@ C_SOURCES = \
draw_vertex_cache.c \
draw_vertex_fetch.c \
draw_vertex_shader.c \
draw_vf.c \
draw_vf_generic.c \
draw_vf_sse.c \
draw_wide_line.c \
draw_wide_point.c

View file

@ -31,9 +31,6 @@ draw = env.ConvenienceLibrary(
'draw_vertex_cache.c',
'draw_vertex_fetch.c',
'draw_vertex_shader.c',
'draw_vf.c',
'draw_vf_generic.c',
'draw_vf_sse.c',
'draw_vs_exec.c',
'draw_vs_llvm.c',
'draw_vs_sse.c',

View file

@ -62,8 +62,7 @@ void draw_pt_emit_prepare( struct pt_emit *emit,
vinfo = draw->render->get_vertex_info(draw->render);
/* In passthrough mode, need to translate from vertex shader
* outputs to hw vertices.
/* Translate from pipeline vertices to hw vertices.
*/
dst_offset = 0;
for (i = 0; i < vinfo->num_attribs; i++) {

View file

@ -40,7 +40,7 @@
#include "draw_vbuf.h"
#include "draw_private.h"
#include "draw_vertex.h"
#include "draw_vf.h"
#include "translate/translate.h"
/**
@ -56,7 +56,7 @@ struct vbuf_stage {
/** Vertex size in bytes */
unsigned vertex_size;
struct draw_vertex_fetch *vf;
struct translate *translate;
/* FIXME: we have no guarantee that 'unsigned' is 32bit */
@ -71,8 +71,9 @@ struct vbuf_stage {
unsigned max_indices;
unsigned nr_indices;
/** Pipe primitive */
unsigned prim;
/* Cache point size somewhere it's address won't change:
*/
float point_size;
};
@ -175,26 +176,25 @@ dump_emitted_vertex(const struct vertex_info *vinfo, const uint8_t *data)
* have a couple of slots at the beginning (1-dword header, 4-dword
* clip pos) that we ignore here. We only use the vertex->data[] fields.
*/
static INLINE void
static INLINE ushort
emit_vertex( struct vbuf_stage *vbuf,
struct vertex_header *vertex )
{
if(vertex->vertex_id != UNDEFINED_VERTEX_ID) {
if(vertex->vertex_id < vbuf->nr_vertices)
return;
else
debug_printf("Bad vertex id 0x%04x (>= 0x%04x)\n",
vertex->vertex_id, vbuf->nr_vertices);
return;
}
if(vertex->vertex_id == UNDEFINED_VERTEX_ID) {
/* Hmm - vertices are emitted one at a time - better make sure
* set_buffer is efficient. Consider a special one-shot mode for
* translate.
*/
vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0);
vbuf->translate->run(vbuf->translate, 0, 1, vbuf->vertex_ptr);
if (0) dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
vertex->vertex_id = vbuf->nr_vertices++;
vbuf->vertex_ptr += vbuf->vertex_size/4;
vertex->vertex_id = vbuf->nr_vertices++;
}
draw_vf_emit_vertex(vbuf->vf, vertex, vbuf->vertex_ptr);
if (0) dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
vbuf->vertex_ptr += vbuf->vertex_size/4;
return vertex->vertex_id;
}
@ -208,9 +208,7 @@ vbuf_tri( struct draw_stage *stage,
check_space( vbuf, 3 );
for (i = 0; i < 3; i++) {
emit_vertex( vbuf, prim->v[i] );
vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
}
}
@ -225,9 +223,7 @@ vbuf_line( struct draw_stage *stage,
check_space( vbuf, 2 );
for (i = 0; i < 2; i++) {
emit_vertex( vbuf, prim->v[i] );
vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
}
}
@ -240,43 +236,112 @@ vbuf_point( struct draw_stage *stage,
check_space( vbuf, 1 );
emit_vertex( vbuf, prim->v[0] );
vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[0]->vertex_id;
vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
}
/**
* Set the prim type for subsequent vertices.
* This may result in a new vertex size. The existing vbuffer (if any)
* will be flushed if needed and a new one allocated.
*/
static void
vbuf_set_prim( struct vbuf_stage *vbuf, uint newprim )
vbuf_set_prim( struct vbuf_stage *vbuf, uint prim )
{
const struct vertex_info *vinfo;
unsigned vertex_size;
struct translate_key hw_key;
unsigned dst_offset;
unsigned i;
assert(newprim == PIPE_PRIM_POINTS ||
newprim == PIPE_PRIM_LINES ||
newprim == PIPE_PRIM_TRIANGLES);
vbuf->render->set_primitive(vbuf->render, prim);
vbuf->prim = newprim;
vbuf->render->set_primitive(vbuf->render, newprim);
/* Must do this after set_primitive() above:
*
* XXX: need some state managment to track when this needs to be
* recalculated. The driver should tell us whether there was a
* state change.
*/
vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
vinfo = vbuf->render->get_vertex_info(vbuf->render);
vertex_size = vinfo->size * sizeof(float);
if (vertex_size != vbuf->vertex_size)
if (vbuf->vertex_size != vbuf->vinfo->size * sizeof(float)) {
vbuf_flush_vertices(vbuf);
vbuf->vertex_size = vbuf->vinfo->size * sizeof(float);
}
vbuf->vinfo = vinfo;
vbuf->vertex_size = vertex_size;
if(vbuf->vf)
draw_vf_set_vertex_info(vbuf->vf,
vbuf->vinfo,
vbuf->stage.draw->rasterizer->point_size);
/* Translate from pipeline vertices to hw vertices.
*/
dst_offset = 0;
memset(&hw_key, 0, sizeof(hw_key));
for (i = 0; i < vbuf->vinfo->num_attribs; i++) {
unsigned emit_sz = 0;
unsigned src_buffer = 0;
unsigned output_format;
unsigned src_offset = (vbuf->vinfo->src_index[i] * 4 * sizeof(float) );
switch (vbuf->vinfo->emit[i]) {
case EMIT_4F:
output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
emit_sz = 4 * sizeof(float);
break;
case EMIT_3F:
output_format = PIPE_FORMAT_R32G32B32_FLOAT;
emit_sz = 3 * sizeof(float);
break;
case EMIT_2F:
output_format = PIPE_FORMAT_R32G32_FLOAT;
emit_sz = 2 * sizeof(float);
break;
case EMIT_1F:
output_format = PIPE_FORMAT_R32_FLOAT;
emit_sz = 1 * sizeof(float);
break;
case EMIT_1F_PSIZE:
output_format = PIPE_FORMAT_R32_FLOAT;
emit_sz = 1 * sizeof(float);
src_buffer = 1;
src_offset = 0;
break;
case EMIT_4UB:
output_format = PIPE_FORMAT_B8G8R8A8_UNORM;
emit_sz = 4 * sizeof(ubyte);
default:
assert(0);
output_format = PIPE_FORMAT_NONE;
emit_sz = 0;
break;
}
hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
hw_key.element[i].input_buffer = src_buffer;
hw_key.element[i].input_offset = src_offset;
hw_key.element[i].output_format = output_format;
hw_key.element[i].output_offset = dst_offset;
dst_offset += emit_sz;
}
hw_key.nr_elements = vbuf->vinfo->num_attribs;
hw_key.output_stride = vbuf->vinfo->size * 4;
/* Don't bother with caching at this stage:
*/
if (!vbuf->translate ||
memcmp(&vbuf->translate->key, &hw_key, sizeof(hw_key)) != 0)
{
if (vbuf->translate)
vbuf->translate->release(vbuf->translate);
vbuf->translate = translate_create( &hw_key );
vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0);
}
vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
/* Allocate new buffer?
*/
if (!vbuf->vertices)
vbuf_alloc_vertices(vbuf);
}
@ -330,29 +395,9 @@ vbuf_flush_indices( struct vbuf_stage *vbuf )
assert((uint) (vbuf->vertex_ptr - vbuf->vertices) ==
vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
switch(vbuf->prim) {
case PIPE_PRIM_POINTS:
break;
case PIPE_PRIM_LINES:
assert(vbuf->nr_indices % 2 == 0);
break;
case PIPE_PRIM_TRIANGLES:
assert(vbuf->nr_indices % 3 == 0);
break;
default:
assert(0);
}
vbuf->render->draw(vbuf->render, vbuf->indices, vbuf->nr_indices);
vbuf->nr_indices = 0;
/* don't need to reset point/line/tri functions */
#if 0
stage->point = vbuf_first_point;
stage->line = vbuf_first_line;
stage->tri = vbuf_first_tri;
#endif
}
@ -433,8 +478,8 @@ static void vbuf_destroy( struct draw_stage *stage )
if(vbuf->indices)
align_free( vbuf->indices );
if(vbuf->vf)
draw_vf_destroy( vbuf->vf );
if(vbuf->translate)
vbuf->translate->release( vbuf->translate );
if (vbuf->render)
vbuf->render->destroy( vbuf->render );
@ -473,11 +518,6 @@ struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
vbuf->vertices = NULL;
vbuf->vertex_ptr = vbuf->vertices;
vbuf->prim = ~0;
vbuf->vf = draw_vf_create();
if (!vbuf->vf)
goto fail;
return &vbuf->stage;

View file

@ -1,378 +0,0 @@
/*
* 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 <stddef.h>
#include "pipe/p_compiler.h"
#include "pipe/p_util.h"
#include "rtasm/rtasm_execmem.h"
#include "draw_vf.h"
#define DRAW_VF_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 *)
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:
*/
static 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 < PIPE_MAX_ATTRIBS);
for (j = 0, i = 0; i < nr; i++) {
const unsigned format = map[i].format;
if (format == DRAW_EMIT_PAD) {
#if (DRAW_VF_DBG)
debug_printf("%d: pad %d, offset %d\n", i,
map[i].offset, offset);
#endif
offset += map[i].offset;
}
else {
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].vertattrsize = draw_vf_format_info[format].attrsize;
vf->attr[j].vertoffset = offset;
vf->attr[j].isconst = draw_vf_format_info[format].isconst;
if(vf->attr[j].isconst)
memcpy(vf->attr[j].data, &map[i].data, vf->attr[j].vertattrsize);
#if (DRAW_VF_DBG)
debug_printf("%d: %s, offset %d\n", i,
draw_vf_format_info[format].name,
vf->attr[j].vertoffset);
#endif
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_vertex_info( struct draw_vertex_fetch *vf,
const struct vertex_info *vinfo,
float point_size )
{
unsigned i, j;
struct draw_vf_attr *a = vf->attr;
struct draw_vf_attr_map attrs[PIPE_MAX_SHADER_INPUTS];
unsigned count = 0; /* for debug/sanity */
unsigned nr_attrs = 0;
for (i = 0; i < vinfo->num_attribs; i++) {
j = vinfo->src_index[i];
switch (vinfo->emit[i]) {
case EMIT_OMIT:
/* no-op */
break;
case EMIT_1F:
attrs[nr_attrs].attrib = j;
attrs[nr_attrs].format = DRAW_EMIT_1F;
attrs[nr_attrs].offset = 0;
nr_attrs++;
count++;
break;
case EMIT_1F_PSIZE:
attrs[nr_attrs].attrib = j;
attrs[nr_attrs].format = DRAW_EMIT_1F_CONST;
attrs[nr_attrs].offset = 0;
attrs[nr_attrs].data.f[0] = point_size;
nr_attrs++;
count++;
break;
case EMIT_2F:
attrs[nr_attrs].attrib = j;
attrs[nr_attrs].format = DRAW_EMIT_2F;
attrs[nr_attrs].offset = 0;
nr_attrs++;
count += 2;
break;
case EMIT_3F:
attrs[nr_attrs].attrib = j;
attrs[nr_attrs].format = DRAW_EMIT_3F;
attrs[nr_attrs].offset = 0;
nr_attrs++;
count += 3;
break;
case EMIT_4F:
attrs[nr_attrs].attrib = j;
attrs[nr_attrs].format = DRAW_EMIT_4F;
attrs[nr_attrs].offset = 0;
nr_attrs++;
count += 4;
break;
case EMIT_4UB:
attrs[nr_attrs].attrib = j;
attrs[nr_attrs].format = DRAW_EMIT_4UB_4F_BGRA;
attrs[nr_attrs].offset = 0;
nr_attrs++;
count += 1;
break;
default:
assert(0);
}
}
assert(count == vinfo->size);
draw_vf_set_vertex_attributes(vf,
attrs,
nr_attrs,
vinfo->size * sizeof(float) );
for (j = 0; j < vf->attr_count; j++) {
a[j].inputsize = 4;
a[j].do_insert = a[j].insert[4 - 1];
if(a[j].isconst) {
a[j].inputptr = a[j].data;
a[j].inputstride = 0;
}
}
}
#if 0
/* 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;
}
}
#endif
/**
* Emit a vertex to dest.
*/
void draw_vf_emit_vertex( struct draw_vertex_fetch *vf,
struct vertex_header *vertex,
void *dest )
{
struct draw_vf_attr *a = vf->attr;
unsigned j;
for (j = 0; j < vf->attr_count; j++) {
if (!a[j].isconst) {
a[j].inputptr = (uint8_t *)&vertex->data[a[j].attrib][0];
a[j].inputstride = 0; /* XXX: one-vertex-max ATM */
}
}
vf->emit( vf, 1, (uint8_t*) dest );
}
struct draw_vertex_fetch *draw_vf_create( void )
{
struct draw_vertex_fetch *vf = CALLOC_STRUCT(draw_vertex_fetch);
unsigned i;
for (i = 0; i < PIPE_MAX_ATTRIBS; i++)
vf->attr[i].vf = vf;
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 (!GETENV("GALLIUM_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
* rtasm_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.
*/
//rtasm_exec_free((void *) fp->func);
FREE(fp);
}
vf->fastpath = NULL;
FREE(vf);
}

View file

@ -1,232 +0,0 @@
/*
* Copyright 2008 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.
*/
/**
* Vertex fetch/store/convert code. This functionality is used in two places:
* 1. Vertex fetch/convert - to grab vertex data from incoming vertex
* arrays and convert to format needed by vertex shaders.
* 2. Vertex store/emit - to convert simple float[][4] vertex attributes
* (which is the organization used throughout the draw/prim pipeline) to
* hardware-specific formats and emit into hardware vertex buffers.
*
*
* Authors:
* Keith Whitwell <keithw@tungstengraphics.com>
*/
#ifndef DRAW_VF_H
#define DRAW_VF_H
#include "pipe/p_compiler.h"
#include "pipe/p_state.h"
#include "draw_vertex.h"
#include "draw_private.h" /* for vertex_header */
enum draw_vf_attr_format {
DRAW_EMIT_1F,
DRAW_EMIT_2F,
DRAW_EMIT_3F,
DRAW_EMIT_4F,
DRAW_EMIT_3F_XYW, /**< for projective texture */
DRAW_EMIT_1UB_1F, /**< for fog coordinate */
DRAW_EMIT_3UB_3F_RGB, /**< for specular color */
DRAW_EMIT_3UB_3F_BGR, /**< for specular color */
DRAW_EMIT_4UB_4F_RGBA, /**< for color */
DRAW_EMIT_4UB_4F_BGRA, /**< for color */
DRAW_EMIT_4UB_4F_ARGB, /**< for color */
DRAW_EMIT_4UB_4F_ABGR, /**< for color */
DRAW_EMIT_1F_CONST,
DRAW_EMIT_2F_CONST,
DRAW_EMIT_3F_CONST,
DRAW_EMIT_4F_CONST,
DRAW_EMIT_PAD, /**< leave a hole of 'offset' bytes */
DRAW_EMIT_MAX
};
struct draw_vf_attr_map
{
/** Input attribute number */
unsigned attrib;
enum draw_vf_attr_format format;
unsigned offset;
/**
* Constant data for DRAW_EMIT_*_CONST
*/
union {
uint8_t ub[4];
float f[4];
} data;
};
struct draw_vertex_fetch;
#if 0
unsigned
draw_vf_set_vertex_attributes( struct draw_vertex_fetch *vf,
const struct draw_vf_attr_map *map,
unsigned nr,
unsigned vertex_stride );
#endif
void draw_vf_set_vertex_info( struct draw_vertex_fetch *vf,
const struct vertex_info *vinfo,
float point_size );
#if 0
void
draw_vf_set_sources( struct draw_vertex_fetch *vf,
GLvector4f * const attrib[],
unsigned start );
#endif
void
draw_vf_emit_vertex( struct draw_vertex_fetch *vf,
struct vertex_header *vertex,
void *dest );
struct draw_vertex_fetch *
draw_vf_create( void );
void
draw_vf_destroy( struct draw_vertex_fetch *vf );
/***********************************************************************
* Internal functions and structs:
*/
struct draw_vf_attr;
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 */
boolean isconst; /**< read from const data below */
uint8_t data[16];
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;
};
struct draw_vertex_fetch
{
struct draw_vf_attr attr[PIPE_MAX_ATTRIBS];
unsigned attr_count;
unsigned vertex_stride;
draw_vf_emit_func emit;
/* Parameters and constants for codegen:
*/
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;
};
/** XXX this could be moved into draw_vf.c */
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 );
/** XXX this type and function could probably be moved into draw_vf.c */
struct draw_vf_format_info {
const char *name;
draw_vf_insert_func insert[4];
const unsigned attrsize;
const boolean isconst;
};
extern const struct draw_vf_format_info
draw_vf_format_info[DRAW_EMIT_MAX];
#endif

View file

@ -1,585 +0,0 @@
/*
* 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 "pipe/p_compiler.h"
#include "pipe/p_debug.h"
#include "pipe/p_util.h"
#include "draw_vf.h"
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;
assert(0);
}
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_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]);
}
const struct draw_vf_format_info draw_vf_format_info[DRAW_EMIT_MAX] =
{
{ "1f",
{ insert_1f_1, insert_1f_1, insert_1f_1, insert_1f_1 },
sizeof(float), FALSE },
{ "2f",
{ insert_2f_1, insert_2f_2, insert_2f_2, insert_2f_2 },
2 * sizeof(float), FALSE },
{ "3f",
{ insert_3f_1, insert_3f_2, insert_3f_3, insert_3f_3 },
3 * sizeof(float), FALSE },
{ "4f",
{ insert_4f_1, insert_4f_2, insert_4f_3, insert_4f_4 },
4 * sizeof(float), FALSE },
{ "3f_xyw",
{ insert_3f_xyw_err, insert_3f_xyw_err, insert_3f_xyw_err,
insert_3f_xyw_4 },
3 * sizeof(float), FALSE },
{ "1ub_1f",
{ insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1 },
sizeof(uint8_t), FALSE },
{ "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), FALSE },
{ "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), FALSE },
{ "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), FALSE },
{ "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), FALSE },
{ "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), FALSE },
{ "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), FALSE },
{ "1f_const",
{ insert_1f_1, insert_1f_1, insert_1f_1, insert_1f_1 },
sizeof(float), TRUE },
{ "2f_const",
{ insert_2f_1, insert_2f_2, insert_2f_2, insert_2f_2 },
2 * sizeof(float), TRUE },
{ "3f_const",
{ insert_3f_1, insert_3f_2, insert_3f_3, insert_3f_3 },
3 * sizeof(float), TRUE },
{ "4f_const",
{ insert_4f_1, insert_4f_2, insert_4f_3, insert_4f_4 },
4 * sizeof(float), TRUE },
{ "pad",
{ NULL, NULL, NULL, NULL },
0, FALSE },
};
/***********************************************************************
* 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_3, insert_4ub_4f_rgba_4, emit_xyz3_rgba4)
EMIT3(insert_4f_4, insert_4ub_4f_rgba_4, insert_2f_2, emit_xyzw4_rgba4_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_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_4)
func = emit_xyzw4_rgba4_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_4)
func = emit_xyzw4_rgba4_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 );
}
}
}

View file

@ -1,613 +0,0 @@
/*
* 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 "pipe/p_compiler.h"
#include "util/u_simple_list.h"
#include "draw_vf.h"
#if defined(USE_SSE_ASM)
#include "rtasm/rtasm_cpu.h"
#include "rtasm/rtasm_x86sse.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);
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));
/* always load, needed or not:
*/
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 DRAW_EMIT_1F:
case DRAW_EMIT_1F_CONST:
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 DRAW_EMIT_2F:
case DRAW_EMIT_2F_CONST:
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 DRAW_EMIT_3F:
case DRAW_EMIT_3F_CONST:
/* 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 DRAW_EMIT_4F:
case DRAW_EMIT_4F_CONST:
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 DRAW_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 DRAW_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 {
debug_printf("Can't emit 1ub %x %x %d\n",
a->vertoffset, a[-1].vertoffset, a[-1].vertattrsize );
return FALSE;
}
break;
case DRAW_EMIT_3UB_3F_RGB:
case DRAW_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 == DRAW_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 == DRAW_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 == DRAW_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 {
debug_printf("Can't emit 3ub\n");
}
return FALSE; /* add this later */
break;
case DRAW_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 DRAW_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 DRAW_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 DRAW_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;
default:
debug_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 (!rtasm_cpu_has_sse()) {
vf->codegen_emit = NULL;
return;
}
memset(&p, 0, sizeof(p));
p.vf = vf;
p.inputs_safe = 0; /* for now */
p.outputs_safe = 1; /* for now */
p.have_sse2 = rtasm_cpu_has_sse2();
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