draw: create specialized vs varients incorporating fetch & emit

This commit is contained in:
Keith Whitwell
2008-05-15 12:39:08 +01:00
parent 2f0d1396e4
commit 7c99d7fe60
9 changed files with 764 additions and 2 deletions
+2 -1
View File
@@ -26,7 +26,7 @@ C_SOURCES = \
draw_pt_emit.c \
draw_pt_fetch.c \
draw_pt_fetch_emit.c \
draw_pt_middle_fse.c \
draw_pt_fetch_shade_emit.c \
draw_pt_fetch_shade_pipeline.c \
draw_pt_post_vs.c \
draw_pt_util.c \
@@ -34,6 +34,7 @@ C_SOURCES = \
draw_pt_vcache.c \
draw_vertex.c \
draw_vs.c \
draw_vs_varient.c \
draw_vs_exec.c \
draw_vs_llvm.c \
draw_vs_sse.c
@@ -184,7 +184,9 @@ struct draw_context
struct gallivm_cpu_engine *engine;
struct translate *fetch;
struct translate_cache *fetch_cache;
struct translate *emit;
struct translate_cache *emit_cache;
} vs;
@@ -0,0 +1,338 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, 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 ITS 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 <keith@tungstengraphics.com>
*/
#include "pipe/p_util.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_pt.h"
#include "draw/draw_vs.h"
#include "translate/translate.h"
struct fetch_shade_emit;
/* Prototype fetch, shade, emit-hw-verts all in one go.
*/
struct fetch_shade_emit {
struct draw_pt_middle_end base;
struct draw_context *draw;
/* Temporaries:
*/
const float *constants;
unsigned pitch[PIPE_MAX_ATTRIBS];
const ubyte *src[PIPE_MAX_ATTRIBS];
unsigned prim;
struct draw_vs_varient_key key;
struct draw_vs_varient *active;
};
static void fse_prepare( struct draw_pt_middle_end *middle,
unsigned prim,
unsigned opt )
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
unsigned num_vs_inputs = draw->vs.vertex_shader->info.num_inputs;
unsigned num_vs_outputs = draw->vs.vertex_shader->info.num_outputs;
const struct vertex_info *vinfo;
unsigned i;
boolean need_psize = 0;
if (draw->pt.user.elts) {
assert(0);
return ;
}
if (!draw->render->set_primitive( draw->render,
prim )) {
assert(0);
return;
}
/* Must do this after set_primitive() above:
*/
vinfo = draw->render->get_vertex_info(draw->render);
fse->key.nr_elements = MAX2(num_vs_outputs, /* outputs - translate to hw format */
num_vs_inputs); /* inputs - fetch from api format */
fse->key.output_stride = vinfo->size * 4;
memset(fse->key.element, 0,
fse->key.nr_elements * sizeof(fse->key.element[0]));
for (i = 0; i < num_vs_inputs; i++) {
const struct pipe_vertex_element *src = &draw->pt.vertex_element[i];
fse->key.element[i].in.format = src->src_format;
/* Consider ignoring these, ie make generated programs
* independent of this state:
*/
fse->key.element[i].in.buffer = src->vertex_buffer_index;
fse->key.element[i].in.offset = src->src_offset;
}
{
unsigned dst_offset = 0;
for (i = 0; i < vinfo->num_attribs; i++) {
unsigned emit_sz = 0;
unsigned output_format = PIPE_FORMAT_NONE;
unsigned vs_output = vinfo->src_index[i];
switch (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:
need_psize = 1;
output_format = PIPE_FORMAT_R32_FLOAT;
emit_sz = 1 * sizeof(float);
vs_output = num_vs_outputs + 1;
break;
default:
assert(0);
break;
}
/* The elements in the key correspond to vertex shader output
* numbers, not to positions in the hw vertex description --
* that's handled by the output_offset field.
*/
fse->key.element[vs_output].out.format = output_format;
fse->key.element[vs_output].out.offset = dst_offset;
dst_offset += emit_sz;
assert(fse->key.output_stride >= dst_offset);
}
}
/* To make psize work, really need to tell the vertex shader to
* copy that value from input->output. For 'translate' this was
* implicit for all elements.
*/
#if 0
if (need_psize) {
unsigned input = num_vs_inputs + 1;
const struct pipe_vertex_element *src = &draw->pt.vertex_element[i];
fse->key.element[i].input_format = PIPE_FORMAT_R32_FLOAT;
fse->key.element[i].input_buffer = 0; //nr_buffers + 1;
fse->key.element[i].input_offset = 0;
fse->key.nr_elements += 1;
}
#endif
/* Would normally look up a vertex shader and peruse its list of
* varients somehow. We omitted that step and put all the
* hardcoded "shaders" into an array. We're just making the
* assumption that this happens to be a matching shader... ie
* you're running isosurf, aren't you?
*/
fse->active = draw_vs_lookup_varient( draw->vs.vertex_shader,
&fse->key );
if (!fse->active) {
assert(0);
return ;
}
/* Now set buffer pointers:
*/
for (i = 0; i < num_vs_inputs; i++) {
unsigned buf = draw->pt.vertex_element[i].vertex_buffer_index;
fse->active->set_input( fse->active,
i,
((const ubyte *) draw->pt.user.vbuffer[buf] +
draw->pt.vertex_buffer[buf].buffer_offset),
draw->pt.vertex_buffer[buf].pitch );
}
fse->active->set_constants( fse->active,
(const float (*)[4])draw->pt.user.constants );
//return TRUE;
}
static void fse_run_linear( struct draw_pt_middle_end *middle,
unsigned start,
unsigned count )
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
unsigned alloc_count = align(count, 4);
char *hw_verts;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush( draw, DRAW_FLUSH_BACKEND );
hw_verts = draw->render->allocate_vertices( draw->render,
(ushort)fse->key.output_stride,
(ushort)alloc_count );
if (!hw_verts) {
assert(0);
return;
}
/* Single routine to fetch vertices, run shader and emit HW verts.
* Clipping and viewport transformation are done elsewhere --
* either by the API or on hardware, or for some other reason not
* required...
*/
fse->active->run_linear( fse->active,
start, count,
hw_verts );
/* Draw arrays path to avoid re-emitting index list again and
* again.
*/
draw->render->draw_arrays( draw->render,
0,
count );
draw->render->release_vertices( draw->render,
hw_verts,
fse->key.output_stride,
count );
}
static void
fse_run(struct draw_pt_middle_end *middle,
const unsigned *fetch_elts,
unsigned fetch_count,
const ushort *draw_elts,
unsigned draw_count )
{
struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
struct draw_context *draw = fse->draw;
unsigned alloc_count = align(fetch_count, 4);
void *hw_verts;
/* XXX: need to flush to get prim_vbuf.c to release its allocation??
*/
draw_do_flush( draw, DRAW_FLUSH_BACKEND );
hw_verts = draw->render->allocate_vertices( draw->render,
(ushort)fse->key.output_stride,
(ushort)alloc_count );
if (!hw_verts) {
assert(0);
return;
}
/* Single routine to fetch vertices, run shader and emit HW verts.
*/
fse->active->run_elts( fse->active,
fetch_elts,
fetch_count,
hw_verts );
draw->render->draw( draw->render,
draw_elts,
draw_count );
draw->render->release_vertices( draw->render,
hw_verts,
fse->key.output_stride,
fetch_count );
}
static void fse_finish( struct draw_pt_middle_end *middle )
{
}
static void
fse_destroy( struct draw_pt_middle_end *middle )
{
FREE(middle);
}
struct draw_pt_middle_end *draw_pt_middle_fse( struct draw_context *draw )
{
struct fetch_shade_emit *fse = CALLOC_STRUCT(fetch_shade_emit);
if (!fse)
return NULL;
fse->base.prepare = fse_prepare;
fse->base.run = fse_run;
fse->base.run_linear = fse_run_linear;
fse->base.finish = fse_finish;
fse->base.destroy = fse_destroy;
fse->draw = draw;
return &fse->base;
}
+82 -1
View File
@@ -36,6 +36,8 @@
#include "draw_private.h"
#include "draw_context.h"
#include "draw_vs.h"
#include "translate/translate.h"
#include "translate/translate_cache.h"
@@ -90,11 +92,25 @@ boolean
draw_vs_init( struct draw_context *draw )
{
tgsi_exec_machine_init(&draw->vs.machine);
/* FIXME: give this machine thing a proper constructor:
*/
draw->vs.machine.Inputs = align_malloc(PIPE_MAX_ATTRIBS * sizeof(struct tgsi_exec_vector), 16);
draw->vs.machine.Outputs = align_malloc(PIPE_MAX_ATTRIBS * sizeof(struct tgsi_exec_vector), 16);
if (!draw->vs.machine.Inputs)
return FALSE;
draw->vs.machine.Outputs = align_malloc(PIPE_MAX_ATTRIBS * sizeof(struct tgsi_exec_vector), 16);
if (!draw->vs.machine.Outputs)
return FALSE;
draw->vs.emit_cache = translate_cache_create();
if (!draw->vs.emit_cache)
return FALSE;
draw->vs.fetch_cache = translate_cache_create();
if (!draw->vs.fetch_cache)
return FALSE;
return TRUE;
}
@@ -107,6 +123,71 @@ draw_vs_destroy( struct draw_context *draw )
if (draw->vs.machine.Outputs)
align_free(draw->vs.machine.Outputs);
if (draw->vs.fetch_cache)
translate_cache_destroy(draw->vs.fetch_cache);
if (draw->vs.emit_cache)
translate_cache_destroy(draw->vs.emit_cache);
tgsi_exec_machine_free_data(&draw->vs.machine);
}
struct draw_vs_varient *
draw_vs_lookup_varient( struct draw_vertex_shader *vs,
const struct draw_vs_varient_key *key )
{
struct draw_vs_varient *varient;
unsigned i;
/* Lookup existing varient:
*/
for (i = 0; i < vs->nr_varients; i++)
if (draw_vs_varient_key_compare(key, &vs->varient[i]->key) == 0)
return vs->varient[i];
/* Else have to create a new one:
*/
varient = vs->create_varient( vs, key );
if (varient == NULL)
return NULL;
/* Add it to our list:
*/
assert(vs->nr_varients < Elements(vs->varient));
vs->varient[vs->nr_varients++] = varient;
/* Done
*/
return varient;
}
struct translate *
draw_vs_get_fetch( struct draw_context *draw,
struct translate_key *key )
{
if (!draw->vs.fetch ||
translate_key_compare(&draw->vs.fetch->key, key) != 0)
{
translate_key_sanitize(key);
draw->vs.fetch = translate_cache_find(draw->vs.fetch_cache, key);
}
return draw->vs.fetch;
}
struct translate *
draw_vs_get_emit( struct draw_context *draw,
struct translate_key *key )
{
if (!draw->vs.emit ||
translate_key_compare(&draw->vs.emit->key, key) != 0)
{
translate_key_sanitize(key);
draw->vs.emit = translate_cache_find(draw->vs.emit_cache, key);
}
return draw->vs.emit;
}
+105
View File
@@ -38,10 +38,63 @@
struct draw_context;
struct pipe_shader_state;
struct draw_vs_input
{
enum pipe_format format;
unsigned buffer;
unsigned offset;
};
struct draw_vs_output
{
enum pipe_format format;
unsigned offset;
};
struct draw_vs_element {
struct draw_vs_input in;
struct draw_vs_output out;
};
struct draw_vs_varient_key {
unsigned output_stride;
unsigned nr_elements;
struct draw_vs_element element[PIPE_MAX_ATTRIBS];
};
struct draw_vs_varient {
struct draw_vs_varient_key key;
struct draw_vertex_shader *vs;
void (*set_input)( struct draw_vs_varient *,
unsigned i,
const void *ptr,
unsigned stride );
void (*set_constants)( struct draw_vs_varient *,
const float (*constants)[4] );
void (*run_linear)( struct draw_vs_varient *shader,
unsigned start,
unsigned count,
void *output_buffer );
void (*run_elts)( struct draw_vs_varient *shader,
const unsigned *elts,
unsigned count,
void *output_buffer );
void (*destroy)( struct draw_vs_varient * );
};
/**
* Private version of the compiled vertex_shader
*/
struct draw_vertex_shader {
struct draw_context *draw;
/* This member will disappear shortly:
*/
@@ -49,6 +102,14 @@ struct draw_vertex_shader {
struct tgsi_shader_info info;
/*
*/
struct draw_vs_varient *varient[16];
unsigned nr_varients;
struct draw_vs_varient *(*create_varient)( struct draw_vertex_shader *shader,
const struct draw_vs_varient_key *key );
void (*prepare)( struct draw_vertex_shader *shader,
struct draw_context *draw );
@@ -68,6 +129,15 @@ struct draw_vertex_shader {
};
struct draw_vs_varient *
draw_vs_lookup_varient( struct draw_vertex_shader *base,
const struct draw_vs_varient_key *key );
/********************************************************************************
* Internal functions:
*/
struct draw_vertex_shader *
draw_create_vs_exec(struct draw_context *draw,
const struct pipe_shader_state *templ);
@@ -80,8 +150,43 @@ struct draw_vertex_shader *
draw_create_vs_llvm(struct draw_context *draw,
const struct pipe_shader_state *templ);
/********************************************************************************
* Helpers for vs implementations that don't do their own fetch/emit varients.
* Means these can be shared between shaders.
*/
struct translate;
struct translate_key;
struct translate *draw_vs_get_fetch( struct draw_context *draw,
struct translate_key *key );
struct translate *draw_vs_get_emit( struct draw_context *draw,
struct translate_key *key );
struct draw_vs_varient *draw_vs_varient_generic( struct draw_vertex_shader *vs,
const struct draw_vs_varient_key *key );
static INLINE int draw_vs_varient_keysize( const struct draw_vs_varient_key *key )
{
return 2 * sizeof(int) + key->nr_elements * sizeof(struct draw_vs_element);
}
static INLINE int draw_vs_varient_key_compare( const struct draw_vs_varient_key *a,
const struct draw_vs_varient_key *b )
{
int keysize = draw_vs_varient_keysize(a);
return memcmp(a, b, keysize);
}
#define MAX_TGSI_VERTICES 4
#endif
@@ -179,9 +179,11 @@ draw_create_vs_exec(struct draw_context *draw,
tgsi_scan_shader(state->tokens, &vs->base.info);
vs->base.draw = draw;
vs->base.prepare = vs_exec_prepare;
vs->base.run_linear = vs_exec_run_linear;
vs->base.delete = vs_exec_delete;
vs->base.create_varient = draw_vs_varient_generic;
vs->machine = &draw->vs.machine;
return &vs->base;
@@ -114,7 +114,9 @@ draw_create_vs_llvm(struct draw_context *draw,
tgsi_scan_shader(vs->base.state.tokens, &vs->base.info);
vs->base.draw = draw;
vs->base.prepare = vs_llvm_prepare;
vs->base.create_varient = draw_vs_varient_generic;
vs->base.run_linear = vs_llvm_run_linear;
vs->base.delete = vs_llvm_delete;
vs->machine = &draw->machine;
+2
View File
@@ -155,6 +155,8 @@ draw_create_vs_sse(struct draw_context *draw,
tgsi_scan_shader(templ->tokens, &vs->base.info);
vs->base.draw = draw;
vs->base.create_varient = draw_vs_varient_generic;
vs->base.prepare = vs_sse_prepare;
vs->base.run_linear = vs_sse_run_linear;
vs->base.delete = vs_sse_delete;
@@ -0,0 +1,229 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, 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 ITS 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 <keith@tungstengraphics.com>
*/
#include "pipe/p_util.h"
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_vs.h"
#include "translate/translate.h"
#include "translate/translate_cache.h"
/* A first pass at incorporating vertex fetch/emit functionality into
*/
struct draw_vs_varient_generic {
struct draw_vs_varient base;
struct draw_vertex_shader *shader;
struct draw_context *draw;
/* Basic plan is to run these two translate functions before/after
* the vertex shader's existing run_linear() routine to simulate
* the inclusion of this functionality into the shader...
*
* Next will look at actually including it.
*/
struct translate *fetch;
struct translate *emit;
const float (*constants)[4];
};
static void vsvg_set_constants( struct draw_vs_varient *varient,
const float (*constants)[4] )
{
struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
vsvg->constants = constants;
}
static void vsvg_set_input( struct draw_vs_varient *varient,
unsigned buffer,
const void *ptr,
unsigned stride )
{
struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
vsvg->fetch->set_buffer(vsvg->fetch,
buffer,
ptr,
stride);
}
static void vsvg_run_elts( struct draw_vs_varient *varient,
const unsigned *elts,
unsigned count,
void *output_buffer)
{
struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
/* Want to do this in small batches for cache locality?
*/
vsvg->fetch->run_elts( vsvg->fetch,
elts,
count,
output_buffer );
//if (!vsvg->base.vs->is_passthrough)
{
vsvg->base.vs->run_linear( vsvg->base.vs,
output_buffer,
output_buffer,
vsvg->constants,
count,
vsvg->base.key.output_stride,
vsvg->base.key.output_stride);
//if (!vsvg->already_in_emit_format)
vsvg->emit->set_buffer( vsvg->emit,
0,
output_buffer,
vsvg->base.key.output_stride );
vsvg->emit->run( vsvg->emit,
0, count,
output_buffer );
}
}
static void vsvg_run_linear( struct draw_vs_varient *varient,
unsigned start,
unsigned count,
void *output_buffer )
{
struct draw_vs_varient_generic *vsvg = (struct draw_vs_varient_generic *)varient;
//debug_printf("%s %d %d\n", __FUNCTION__, start, count);
vsvg->fetch->run( vsvg->fetch,
start,
count,
output_buffer );
//if (!vsvg->base.vs->is_passthrough)
{
vsvg->base.vs->run_linear( vsvg->base.vs,
output_buffer,
output_buffer,
vsvg->constants,
count,
vsvg->base.key.output_stride,
vsvg->base.key.output_stride);
//if (!vsvg->already_in_emit_format)
vsvg->emit->set_buffer( vsvg->emit,
0,
output_buffer,
vsvg->base.key.output_stride );
vsvg->emit->run( vsvg->emit,
0, count,
output_buffer );
}
}
static void vsvg_destroy( struct draw_vs_varient *varient )
{
FREE(varient);
}
struct draw_vs_varient *draw_vs_varient_generic( struct draw_vertex_shader *vs,
const struct draw_vs_varient_key *key )
{
unsigned i;
struct translate_key fetch, emit;
struct draw_vs_varient_generic *vsvg = CALLOC_STRUCT( draw_vs_varient_generic );
if (vsvg == NULL)
return NULL;
vsvg->base.key = *key;
vsvg->base.vs = vs;
vsvg->base.set_input = vsvg_set_input;
vsvg->base.set_constants = vsvg_set_constants;
vsvg->base.run_elts = vsvg_run_elts;
vsvg->base.run_linear = vsvg_run_linear;
vsvg->base.destroy = vsvg_destroy;
/* OK, have to build a new one:
*/
fetch.nr_elements = vs->info.num_inputs;
fetch.output_stride = 0;
for (i = 0; i < vs->info.num_inputs; i++) {
fetch.element[i].input_format = key->element[i].in.format;
fetch.element[i].input_buffer = key->element[i].in.buffer;
fetch.element[i].input_offset = key->element[i].in.offset;
fetch.element[i].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
fetch.element[i].output_offset = fetch.output_stride;
fetch.output_stride += 4 * sizeof(float);
}
emit.nr_elements = vs->info.num_outputs;
emit.output_stride = key->output_stride;
for (i = 0; i < vs->info.num_outputs; i++) {
emit.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
emit.element[i].input_buffer = 0;
emit.element[i].input_offset = i * 4 * sizeof(float);
emit.element[i].output_format = key->element[i].out.format;
emit.element[i].output_offset = key->element[i].out.offset;
}
vsvg->fetch = draw_vs_get_fetch( vs->draw, &fetch );
vsvg->emit = draw_vs_get_emit( vs->draw, &emit );
return &vsvg->base;
}