Merge commit 'origin/st-shader-varients'

Conflicts:
	src/mesa/state_tracker/st_atom_shader.c
	src/mesa/state_tracker/st_program.c
This commit is contained in:
Roland Scheidegger 2009-11-26 01:15:25 +01:00
commit 4dcdf3b9c6
14 changed files with 331 additions and 655 deletions

View File

@ -46,7 +46,8 @@ static const struct st_tracked_state *atoms[] =
&st_update_clip,
&st_finalize_textures,
&st_update_shader,
&st_update_fp,
&st_update_vp,
&st_update_rasterizer,
&st_update_polygon_stipple,

View File

@ -47,7 +47,8 @@ void st_validate_state( struct st_context *st );
extern const struct st_tracked_state st_update_framebuffer;
extern const struct st_tracked_state st_update_clip;
extern const struct st_tracked_state st_update_depth_stencil_alpha;
extern const struct st_tracked_state st_update_shader;
extern const struct st_tracked_state st_update_fp;
extern const struct st_tracked_state st_update_vp;
extern const struct st_tracked_state st_update_rasterizer;
extern const struct st_tracked_state st_update_polygon_stipple;
extern const struct st_tracked_state st_update_viewport;

View File

@ -56,82 +56,18 @@
#include "st_mesa_to_tgsi.h"
/**
* This represents a vertex program, especially translated to match
* the inputs of a particular fragment shader.
/*
* Translate fragment program if needed.
*/
struct translated_vertex_program
static void
translate_fp(struct st_context *st,
struct st_fragment_program *stfp)
{
struct st_vertex_program *master;
/** The fragment shader "signature" this vertex shader is meant for: */
GLbitfield frag_inputs;
/** Compared against master vertex program's serialNo: */
GLuint serialNo;
/** Maps VERT_RESULT_x to slot */
GLuint output_to_slot[VERT_RESULT_MAX];
ubyte output_to_semantic_name[VERT_RESULT_MAX];
ubyte output_to_semantic_index[VERT_RESULT_MAX];
/** Pointer to the translated vertex program */
struct st_vertex_program *vp;
struct translated_vertex_program *next; /**< next in linked list */
};
/**
* Given a vertex program output attribute, return the corresponding
* fragment program input attribute.
* \return -1 for vertex outputs that have no corresponding fragment input
*/
static GLint
vp_out_to_fp_in(GLuint vertResult)
{
if (vertResult >= VERT_RESULT_TEX0 &&
vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS)
return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0);
if (vertResult >= VERT_RESULT_VAR0 &&
vertResult < VERT_RESULT_VAR0 + MAX_VARYING)
return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0);
switch (vertResult) {
case VERT_RESULT_HPOS:
return FRAG_ATTRIB_WPOS;
case VERT_RESULT_COL0:
return FRAG_ATTRIB_COL0;
case VERT_RESULT_COL1:
return FRAG_ATTRIB_COL1;
case VERT_RESULT_FOGC:
return FRAG_ATTRIB_FOGC;
default:
/* Back-face colors, edge flags, etc */
return -1;
}
}
/**
* Find a translated vertex program that corresponds to stvp and
* has outputs matched to stfp's inputs.
* This performs vertex and fragment translation (to TGSI) when needed.
*/
static struct translated_vertex_program *
find_translated_vp(struct st_context *st,
struct st_vertex_program *stvp,
struct st_fragment_program *stfp)
{
static const GLuint UNUSED = ~0;
struct translated_vertex_program *xvp;
const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead;
/*
* Translate fragment program if needed.
*/
if (!stfp->state.tokens) {
GLuint inAttr, numIn = 0;
@ -141,7 +77,7 @@ find_translated_vp(struct st_context *st,
numIn++;
}
else {
stfp->input_to_slot[inAttr] = UNUSED;
stfp->input_to_slot[inAttr] = -1;
}
}
@ -151,170 +87,63 @@ find_translated_vp(struct st_context *st,
st_translate_fragment_program(st, stfp, stfp->input_to_slot);
}
}
/**
* Find a translated vertex program that corresponds to stvp and
* has outputs matched to stfp's inputs.
* This performs vertex and fragment translation (to TGSI) when needed.
*/
static struct st_vp_varient *
find_translated_vp(struct st_context *st,
struct st_vertex_program *stvp )
{
struct st_vp_varient *vpv;
struct st_vp_varient_key key;
/* Nothing in our key yet. This will change:
*/
memset(&key, 0, sizeof key);
key.dummy = 0;
/* Do we need to throw away old translations after a change in the
* GL program string?
*/
if (stvp->serialNo != stvp->lastSerialNo) {
/* These may have changed if the program string changed.
*/
st_prepare_vertex_program( st, stvp );
/* We are now up-to-date:
*/
stvp->lastSerialNo = stvp->serialNo;
}
/* See if we've got a translated vertex program whose outputs match
* the fragment program's inputs.
* XXX This could be a hash lookup, using InputsRead as the key.
*/
for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) {
if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) {
for (vpv = stvp->varients; vpv; vpv = vpv->next) {
if (memcmp(&vpv->key, &key, sizeof key) == 0) {
break;
}
}
/* No? Allocate translated vp object now */
if (!xvp) {
xvp = ST_CALLOC_STRUCT(translated_vertex_program);
xvp->frag_inputs = fragInputsRead;
xvp->master = stvp;
xvp->next = stfp->vertex_programs;
stfp->vertex_programs = xvp;
/* No? Perform new translation here. */
if (!vpv) {
vpv = st_translate_vertex_program(st, stvp, &key);
if (!vpv)
return NULL;
vpv->next = stvp->varients;
stvp->varients = vpv;
}
/* See if we need to translate vertex program to TGSI form */
if (xvp->serialNo != stvp->serialNo) {
GLuint outAttr;
const GLbitfield64 outputsWritten = stvp->Base.Base.OutputsWritten;
GLuint numVpOuts = 0;
GLboolean emitPntSize = GL_FALSE, emitBFC0 = GL_FALSE, emitBFC1 = GL_FALSE;
GLbitfield usedGenerics = 0x0;
GLbitfield usedOutputSlots = 0x0;
/* Compute mapping of vertex program outputs to slots, which depends
* on the fragment program's input->slot mapping.
*/
for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
/* set defaults: */
xvp->output_to_slot[outAttr] = UNUSED;
xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_COUNT;
xvp->output_to_semantic_index[outAttr] = 99;
if (outAttr == VERT_RESULT_HPOS) {
/* always put xformed position into slot zero */
GLuint slot = 0;
xvp->output_to_slot[VERT_RESULT_HPOS] = slot;
xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_POSITION;
xvp->output_to_semantic_index[outAttr] = 0;
numVpOuts++;
usedOutputSlots |= (1 << slot);
}
else if (outputsWritten & (1 << outAttr)) {
/* see if the frag prog wants this vert output */
GLint fpInAttrib = vp_out_to_fp_in(outAttr);
if (fpInAttrib >= 0) {
GLuint fpInSlot = stfp->input_to_slot[fpInAttrib];
if (fpInSlot != ~0) {
/* match this vp output to the fp input */
GLuint vpOutSlot = stfp->input_map[fpInSlot];
xvp->output_to_slot[outAttr] = vpOutSlot;
xvp->output_to_semantic_name[outAttr] = stfp->input_semantic_name[fpInSlot];
xvp->output_to_semantic_index[outAttr] = stfp->input_semantic_index[fpInSlot];
numVpOuts++;
usedOutputSlots |= (1 << vpOutSlot);
}
else {
#if 0 /*debug*/
printf("VP output %d not used by FP\n", outAttr);
#endif
}
}
else if (outAttr == VERT_RESULT_PSIZ)
emitPntSize = GL_TRUE;
else if (outAttr == VERT_RESULT_BFC0)
emitBFC0 = GL_TRUE;
else if (outAttr == VERT_RESULT_BFC1)
emitBFC1 = GL_TRUE;
}
#if 0 /*debug*/
printf("assign vp output_to_slot[%d] = %d\n", outAttr,
xvp->output_to_slot[outAttr]);
#endif
}
/* must do these last */
if (emitPntSize) {
GLuint slot = numVpOuts++;
xvp->output_to_slot[VERT_RESULT_PSIZ] = slot;
xvp->output_to_semantic_name[VERT_RESULT_PSIZ] = TGSI_SEMANTIC_PSIZE;
xvp->output_to_semantic_index[VERT_RESULT_PSIZ] = 0;
usedOutputSlots |= (1 << slot);
}
if (emitBFC0) {
GLuint slot = numVpOuts++;
xvp->output_to_slot[VERT_RESULT_BFC0] = slot;
xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR;
xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 0;
usedOutputSlots |= (1 << slot);
}
if (emitBFC1) {
GLuint slot = numVpOuts++;
xvp->output_to_slot[VERT_RESULT_BFC1] = slot;
xvp->output_to_semantic_name[VERT_RESULT_BFC1] = TGSI_SEMANTIC_COLOR;
xvp->output_to_semantic_index[VERT_RESULT_BFC1] = 1;
usedOutputSlots |= (1 << slot);
}
/* build usedGenerics mask */
usedGenerics = 0x0;
for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
if (xvp->output_to_semantic_name[outAttr] == TGSI_SEMANTIC_GENERIC) {
usedGenerics |= (1 << xvp->output_to_semantic_index[outAttr]);
}
}
/* For each vertex program output that doesn't match up to a fragment
* program input, map the vertex program output to a free slot and
* free generic attribute.
*/
for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) {
if (outputsWritten & (1 << outAttr)) {
if (xvp->output_to_slot[outAttr] == UNUSED) {
GLint freeGeneric = _mesa_ffs(~usedGenerics) - 1;
GLint freeSlot = _mesa_ffs(~usedOutputSlots) - 1;
usedGenerics |= (1 << freeGeneric);
usedOutputSlots |= (1 << freeSlot);
xvp->output_to_slot[outAttr] = freeSlot;
xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_GENERIC;
xvp->output_to_semantic_index[outAttr] = freeGeneric;
}
}
#if 0 /*debug*/
printf("vp output_to_slot[%d] = %d\n", outAttr,
xvp->output_to_slot[outAttr]);
#endif
}
assert(stvp->Base.Base.NumInstructions > 1);
st_translate_vertex_program(st, stvp, xvp->output_to_slot,
xvp->output_to_semantic_name,
xvp->output_to_semantic_index);
xvp->vp = stvp;
/* translated VP is up to date now */
xvp->serialNo = stvp->serialNo;
}
return xvp;
return vpv;
}
void
st_free_translated_vertex_programs(struct st_context *st,
struct translated_vertex_program *xvp)
{
struct translated_vertex_program *next;
while (xvp) {
next = xvp->next;
_mesa_free(xvp);
xvp = next;
}
}
static void *
@ -328,32 +157,19 @@ get_passthrough_fs(struct st_context *st)
return st->passthrough_fs;
}
static void
update_linkage( struct st_context *st )
update_fp( struct st_context *st )
{
struct st_vertex_program *stvp;
struct st_fragment_program *stfp;
struct translated_vertex_program *xvp;
/* find active shader and params -- Should be covered by
* ST_NEW_VERTEX_PROGRAM
*/
assert(st->ctx->VertexProgram._Current);
stvp = st_vertex_program(st->ctx->VertexProgram._Current);
assert(stvp->Base.Base.Target == GL_VERTEX_PROGRAM_ARB);
assert(st->ctx->FragmentProgram._Current);
stfp = st_fragment_program(st->ctx->FragmentProgram._Current);
assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB);
xvp = find_translated_vp(st, stvp, stfp);
translate_fp(st, stfp);
st_reference_vertprog(st, &st->vp, stvp);
st_reference_fragprog(st, &st->fp, stfp);
cso_set_vertex_shader_handle(st->cso_context, stvp->driver_shader);
if (st->missing_textures) {
/* use a pass-through frag shader that uses no textures */
void *fs = get_passthrough_fs(st);
@ -362,16 +178,48 @@ update_linkage( struct st_context *st )
else {
cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader);
}
}
st->vertex_result_to_slot = xvp->output_to_slot;
const struct st_tracked_state st_update_fp = {
"st_update_fp", /* name */
{ /* dirty */
0, /* mesa */
ST_NEW_FRAGMENT_PROGRAM /* st */
},
update_fp /* update */
};
static void
update_vp( struct st_context *st )
{
struct st_vertex_program *stvp;
/* find active shader and params -- Should be covered by
* ST_NEW_VERTEX_PROGRAM
*/
assert(st->ctx->VertexProgram._Current);
stvp = st_vertex_program(st->ctx->VertexProgram._Current);
assert(stvp->Base.Base.Target == GL_VERTEX_PROGRAM_ARB);
st->vp_varient = find_translated_vp(st, stvp);
st_reference_vertprog(st, &st->vp, stvp);
cso_set_vertex_shader_handle(st->cso_context,
st->vp_varient->driver_shader);
st->vertex_result_to_slot = stvp->result_to_output;
}
const struct st_tracked_state st_update_shader = {
"st_update_shader", /* name */
const struct st_tracked_state st_update_vp = {
"st_update_vp", /* name */
{ /* dirty */
0, /* mesa */
ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM /* st */
ST_NEW_VERTEX_PROGRAM /* st */
},
update_linkage /* update */
update_vp /* update */
};

View File

@ -169,11 +169,6 @@ make_bitmap_fragment_program(GLcontext *ctx, GLuint samplerIndex)
stfp = (struct st_fragment_program *) p;
stfp->Base.UsesKill = GL_TRUE;
/* No need to send this incomplete program down to hardware:
*
* st_translate_fragment_program(ctx->st, stfp, NULL);
*/
return stfp;
}

View File

@ -60,6 +60,7 @@
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_inlines.h"
#include "tgsi/tgsi_ureg.h"
#include "util/u_tile.h"
#include "util/u_draw_quad.h"
#include "util/u_math.h"
@ -236,78 +237,41 @@ make_fragment_shader_z(struct st_context *st)
* Create a simple vertex shader that just passes through the
* vertex position and texcoord (and optionally, color).
*/
static struct st_vertex_program *
st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor)
static void *
st_make_passthrough_vertex_shader(struct st_context *st,
GLboolean passColor)
{
GLcontext *ctx = st->ctx;
struct st_vertex_program *stvp;
struct gl_program *p;
GLuint ic = 0;
if (!st->drawpix.vert_shaders[passColor]) {
struct ureg_program *ureg =
ureg_create( TGSI_PROCESSOR_VERTEX );
if (st->drawpix.vert_shaders[passColor])
return st->drawpix.vert_shaders[passColor];
if (ureg == NULL)
return NULL;
/*
* Create shader now
*/
p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
if (!p)
return NULL;
/* MOV result.pos, vertex.pos; */
ureg_MOV(ureg,
ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ),
ureg_DECL_vs_input( ureg, 0 ));
/* MOV result.texcoord0, vertex.texcoord0; */
ureg_MOV(ureg,
ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ),
ureg_DECL_vs_input( ureg, 1 ));
if (passColor) {
/* MOV result.color0, vertex.color0; */
ureg_MOV(ureg,
ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ),
ureg_DECL_vs_input( ureg, 2 ));
}
if (passColor)
p->NumInstructions = 4;
else
p->NumInstructions = 3;
p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
if (!p->Instructions) {
ctx->Driver.DeleteProgram(ctx, p);
return NULL;
}
_mesa_init_instructions(p->Instructions, p->NumInstructions);
/* MOV result.pos, vertex.pos; */
p->Instructions[0].Opcode = OPCODE_MOV;
p->Instructions[0].DstReg.File = PROGRAM_OUTPUT;
p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS;
p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT;
p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS;
/* MOV result.texcoord0, vertex.texcoord0; */
p->Instructions[1].Opcode = OPCODE_MOV;
p->Instructions[1].DstReg.File = PROGRAM_OUTPUT;
p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0;
p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT;
p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0;
ic = 2;
if (passColor) {
/* MOV result.color0, vertex.color0; */
p->Instructions[ic].Opcode = OPCODE_MOV;
p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0;
p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0;
ic++;
ureg_END( ureg );
st->drawpix.vert_shaders[passColor] =
ureg_create_shader_and_destroy( ureg, st->pipe );
}
/* END; */
p->Instructions[ic].Opcode = OPCODE_END;
ic++;
assert(ic == p->NumInstructions);
p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0;
p->OutputsWritten = ((1 << VERT_RESULT_TEX0) |
(1 << VERT_RESULT_HPOS));
if (passColor) {
p->InputsRead |= VERT_BIT_COLOR0;
p->OutputsWritten |= (1 << VERT_RESULT_COL0);
}
stvp = (struct st_vertex_program *) p;
st_translate_vertex_program(st, stvp, NULL, NULL, NULL);
st->drawpix.vert_shaders[passColor] = stvp;
return stvp;
return st->drawpix.vert_shaders[passColor];
}
@ -539,8 +503,8 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
GLsizei width, GLsizei height,
GLfloat zoomX, GLfloat zoomY,
struct pipe_texture *pt,
struct st_vertex_program *stvp,
struct st_fragment_program *stfp,
void *driver_vp,
void *driver_fp,
const GLfloat *color,
GLboolean invertTex)
{
@ -575,10 +539,10 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
}
/* fragment shader state: TEX lookup program */
cso_set_fragment_shader_handle(cso, stfp->driver_shader);
cso_set_fragment_shader_handle(cso, driver_fp);
/* vertex shader state: position + texcoord pass-through */
cso_set_vertex_shader_handle(cso, stvp->driver_shader);
cso_set_vertex_shader_handle(cso, driver_vp);
/* texture sampling state: */
@ -806,7 +770,7 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
{
struct st_fragment_program *stfp;
struct st_vertex_program *stvp;
void *driver_vp;
struct st_context *st = st_context(ctx);
struct pipe_surface *ps;
const GLfloat *color;
@ -826,13 +790,13 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
if (format == GL_DEPTH_COMPONENT) {
ps = st->state.framebuffer.zsbuf;
stfp = make_fragment_shader_z(st);
stvp = st_make_passthrough_vertex_shader(st, GL_TRUE);
driver_vp = st_make_passthrough_vertex_shader(st, GL_TRUE);
color = ctx->Current.RasterColor;
}
else {
ps = st->state.framebuffer.cbufs[0];
stfp = combined_drawpix_fragment_program(ctx);
stvp = st_make_passthrough_vertex_shader(st, GL_FALSE);
driver_vp = st_make_passthrough_vertex_shader(st, GL_FALSE);
color = NULL;
}
@ -843,7 +807,10 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
if (pt) {
draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
pt, stvp, stfp, color, GL_FALSE);
pt,
driver_vp,
stfp->driver_shader,
color, GL_FALSE);
pipe_texture_reference(&pt, NULL);
}
}
@ -960,7 +927,7 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct st_renderbuffer *rbRead;
struct st_vertex_program *stvp;
void *driver_vp;
struct st_fragment_program *stfp;
struct pipe_texture *pt;
GLfloat *color;
@ -1009,14 +976,14 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
rbRead = st_get_color_read_renderbuffer(ctx);
color = NULL;
stfp = combined_drawpix_fragment_program(ctx);
stvp = st_make_passthrough_vertex_shader(st, GL_FALSE);
driver_vp = st_make_passthrough_vertex_shader(st, GL_FALSE);
}
else {
assert(type == GL_DEPTH);
rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
stfp = make_fragment_shader_z(st);
stvp = st_make_passthrough_vertex_shader(st, GL_TRUE);
driver_vp = st_make_passthrough_vertex_shader(st, GL_TRUE);
}
srcFormat = rbRead->texture->format;
@ -1148,7 +1115,10 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy,
/* draw textured quad */
draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
pt, stvp, stfp, color, GL_TRUE);
pt,
driver_vp,
stfp->driver_shader,
color, GL_TRUE);
pipe_texture_reference(&pt, NULL);
}

View File

@ -138,24 +138,7 @@ st_delete_program(GLcontext *ctx, struct gl_program *prog)
case GL_VERTEX_PROGRAM_ARB:
{
struct st_vertex_program *stvp = (struct st_vertex_program *) prog;
if (stvp->driver_shader) {
cso_delete_vertex_shader(st->cso_context, stvp->driver_shader);
stvp->driver_shader = NULL;
}
if (stvp->draw_shader) {
#if FEATURE_feedback || FEATURE_drawpix
/* this would only have been allocated for the RasterPos path */
draw_delete_vertex_shader(st->draw, stvp->draw_shader);
stvp->draw_shader = NULL;
#endif
}
if (stvp->state.tokens) {
st_free_tokens(stvp->state.tokens);
stvp->state.tokens = NULL;
}
st_vp_release_varients( st, stvp );
}
break;
case GL_FRAGMENT_PROGRAM_ARB:
@ -177,8 +160,6 @@ st_delete_program(GLcontext *ctx, struct gl_program *prog)
_mesa_reference_program(ctx, &prg, NULL);
stfp->bitmap_program = NULL;
}
st_free_translated_vertex_programs(st, stfp->vertex_programs);
}
break;
default:
@ -219,8 +200,6 @@ static void st_program_string_notify( GLcontext *ctx,
stfp->state.tokens = NULL;
}
stfp->param_state = stfp->Base.Base.Parameters->StateFlags;
if (st->fp == stfp)
st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
}
@ -229,25 +208,7 @@ static void st_program_string_notify( GLcontext *ctx,
stvp->serialNo++;
if (stvp->driver_shader) {
cso_delete_vertex_shader(st->cso_context, stvp->driver_shader);
stvp->driver_shader = NULL;
}
if (stvp->draw_shader) {
#if FEATURE_feedback || FEATURE_drawpix
/* this would only have been allocated for the RasterPos path */
draw_delete_vertex_shader(st->draw, stvp->draw_shader);
stvp->draw_shader = NULL;
#endif
}
if (stvp->state.tokens) {
st_free_tokens(stvp->state.tokens);
stvp->state.tokens = NULL;
}
stvp->param_state = stvp->Base.Base.Parameters->StateFlags;
st_vp_release_varients( st, stvp );
if (st->vp == stvp)
st->dirty.st |= ST_NEW_VERTEX_PROGRAM;

View File

@ -127,6 +127,8 @@ struct st_context
struct st_vertex_program *vp; /**< Currently bound vertex program */
struct st_fragment_program *fp; /**< Currently bound fragment program */
struct st_vp_varient *vp_varient;
struct gl_texture_object *default_texture;
struct {

View File

@ -86,7 +86,8 @@ st_print_current(void)
}
#endif
tgsi_dump( st->vp->state.tokens, 0 );
if (st->vp->varients)
tgsi_dump( st->vp->varients[0].state.tokens, 0 );
if (st->vp->Base.Base.Parameters)
_mesa_print_parameter_list(st->vp->Base.Base.Parameters);

View File

@ -573,7 +573,7 @@ st_draw_vbo(GLcontext *ctx,
/* must get these after state validation! */
vp = ctx->st->vp;
vs = &ctx->st->vp->state;
vs = &ctx->st->vp_varient->state;
#if 0
if (MESA_VERBOSE & VERBOSE_GLSL) {

View File

@ -120,10 +120,10 @@ st_feedback_draw_vbo(GLcontext *ctx,
/* must get these after state validation! */
vp = ctx->st->vp;
vs = &st->vp->state;
vs = &st->vp_varient->state;
if (!st->vp->draw_shader) {
st->vp->draw_shader = draw_create_vertex_shader(draw, vs);
if (!st->vp_varient->draw_shader) {
st->vp_varient->draw_shader = draw_create_vertex_shader(draw, vs);
}
/*
@ -136,7 +136,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
draw_set_viewport_state(draw, &st->state.viewport);
draw_set_clip_state(draw, &st->state.clip);
draw_set_rasterizer_state(draw, &st->state.rasterizer);
draw_bind_vertex_shader(draw, st->vp->draw_shader);
draw_bind_vertex_shader(draw, st->vp_varient->draw_shader);
set_feedback_vertex_format(ctx);
/* loop over TGSI shader inputs to determine vertex buffer

View File

@ -704,12 +704,10 @@ st_translate_mesa_program(
const ubyte inputSemanticName[],
const ubyte inputSemanticIndex[],
const GLuint interpMode[],
const GLbitfield inputFlags[],
GLuint numOutputs,
const GLuint outputMapping[],
const ubyte outputSemanticName[],
const ubyte outputSemanticIndex[],
const GLbitfield outputFlags[] )
const ubyte outputSemanticIndex[] )
{
struct st_translate translate, *t;
struct ureg_program *ureg;

View File

@ -49,12 +49,10 @@ st_translate_mesa_program(
const ubyte inputSemanticName[],
const ubyte inputSemanticIndex[],
const GLuint interpMode[],
const GLbitfield inputFlags[],
GLuint numOutputs,
const GLuint outputMapping[],
const ubyte outputSemanticName[],
const ubyte outputSemanticIndex[],
const GLbitfield outputFlags[] );
const ubyte outputSemanticIndex[] );
void
st_free_tokens(const struct tgsi_token *tokens);

View File

@ -49,6 +49,36 @@
#include "st_mesa_to_tgsi.h"
#include "cso_cache/cso_context.h"
/* Clean out any old compilations:
*/
void
st_vp_release_varients( struct st_context *st,
struct st_vertex_program *stvp )
{
struct st_vp_varient *vpv;
for (vpv = stvp->varients; vpv; ) {
struct st_vp_varient *next = vpv->next;
if (vpv->driver_shader)
cso_delete_vertex_shader(st->cso_context, vpv->driver_shader);
if (vpv->draw_shader)
draw_delete_vertex_shader( st->draw, vpv->draw_shader );
if (vpv->state.tokens)
st_free_tokens(vpv->state.tokens);
FREE( vpv );
vpv = next;
}
stvp->varients = NULL;
}
/**
* Translate a Mesa vertex shader into a TGSI shader.
@ -58,31 +88,13 @@
* \return pointer to cached pipe_shader object.
*/
void
st_translate_vertex_program(struct st_context *st,
struct st_vertex_program *stvp,
const GLuint outputMapping[],
const ubyte *outputSemanticName,
const ubyte *outputSemanticIndex)
st_prepare_vertex_program(struct st_context *st,
struct st_vertex_program *stvp)
{
struct pipe_context *pipe = st->pipe;
GLuint defaultOutputMapping[VERT_RESULT_MAX];
GLuint attr, i;
GLuint num_generic = 0;
GLuint attr;
ubyte vs_input_semantic_name[PIPE_MAX_SHADER_INPUTS];
ubyte vs_input_semantic_index[PIPE_MAX_SHADER_INPUTS];
uint vs_num_inputs = 0;
ubyte vs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
ubyte vs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
uint vs_num_outputs = 0;
GLbitfield input_flags[MAX_PROGRAM_INPUTS];
GLbitfield output_flags[MAX_PROGRAM_OUTPUTS];
/*memset(&vs, 0, sizeof(vs));*/
memset(input_flags, 0, sizeof(input_flags));
memset(output_flags, 0, sizeof(output_flags));
stvp->num_inputs = 0;
stvp->num_outputs = 0;
if (stvp->Base.IsPositionInvariant)
_mesa_insert_mvp_code(st->ctx, &stvp->Base);
@ -93,162 +105,56 @@ st_translate_vertex_program(struct st_context *st,
*/
for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
if (stvp->Base.Base.InputsRead & (1 << attr)) {
const GLuint slot = vs_num_inputs;
vs_num_inputs++;
stvp->input_to_index[attr] = slot;
stvp->index_to_input[slot] = attr;
switch (attr) {
case VERT_ATTRIB_POS:
vs_input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
vs_input_semantic_index[slot] = 0;
break;
case VERT_ATTRIB_WEIGHT:
/* fall-through */
case VERT_ATTRIB_NORMAL:
/* just label as a generic */
vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
vs_input_semantic_index[slot] = 0;
break;
case VERT_ATTRIB_COLOR0:
vs_input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
vs_input_semantic_index[slot] = 0;
break;
case VERT_ATTRIB_COLOR1:
vs_input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
vs_input_semantic_index[slot] = 1;
break;
case VERT_ATTRIB_FOG:
vs_input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
vs_input_semantic_index[slot] = 0;
break;
case VERT_ATTRIB_POINT_SIZE:
vs_input_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
vs_input_semantic_index[slot] = 0;
break;
case VERT_ATTRIB_TEX0:
case VERT_ATTRIB_TEX1:
case VERT_ATTRIB_TEX2:
case VERT_ATTRIB_TEX3:
case VERT_ATTRIB_TEX4:
case VERT_ATTRIB_TEX5:
case VERT_ATTRIB_TEX6:
case VERT_ATTRIB_TEX7:
assert(slot < Elements(vs_input_semantic_name));
vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
vs_input_semantic_index[slot] = num_generic++;
break;
case VERT_ATTRIB_GENERIC0:
case VERT_ATTRIB_GENERIC1:
case VERT_ATTRIB_GENERIC2:
case VERT_ATTRIB_GENERIC3:
case VERT_ATTRIB_GENERIC4:
case VERT_ATTRIB_GENERIC5:
case VERT_ATTRIB_GENERIC6:
case VERT_ATTRIB_GENERIC7:
case VERT_ATTRIB_GENERIC8:
case VERT_ATTRIB_GENERIC9:
case VERT_ATTRIB_GENERIC10:
case VERT_ATTRIB_GENERIC11:
case VERT_ATTRIB_GENERIC12:
case VERT_ATTRIB_GENERIC13:
case VERT_ATTRIB_GENERIC14:
case VERT_ATTRIB_GENERIC15:
assert(attr < VERT_ATTRIB_MAX);
assert(slot < Elements(vs_input_semantic_name));
vs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
vs_input_semantic_index[slot] = num_generic++;
break;
default:
assert(0);
}
input_flags[slot] = stvp->Base.Base.InputFlags[attr];
stvp->input_to_index[attr] = stvp->num_inputs;
stvp->index_to_input[stvp->num_inputs] = attr;
stvp->num_inputs++;
}
}
#if 0
if (outputMapping && outputSemanticName) {
printf("VERT_RESULT written out_slot semantic_name semantic_index\n");
for (attr = 0; attr < VERT_RESULT_MAX; attr++) {
printf(" %-2d %c %3d %2d %2d\n",
attr,
((stvp->Base.Base.OutputsWritten & (1 << attr)) ? 'Y' : ' '),
outputMapping[attr],
outputSemanticName[attr],
outputSemanticIndex[attr]);
}
}
#endif
/* initialize output semantics to defaults */
for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) {
assert(i < Elements(vs_output_semantic_name));
vs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC;
vs_output_semantic_index[i] = 0;
output_flags[i] = 0x0;
}
num_generic = 0;
/*
* Determine number of outputs, the (default) output register
* mapping and the semantic information for each output.
/* Compute mapping of vertex program outputs to slots.
*/
for (attr = 0; attr < VERT_RESULT_MAX; attr++) {
if (stvp->Base.Base.OutputsWritten & (1 << attr)) {
GLuint slot;
if ((stvp->Base.Base.OutputsWritten & (1 << attr)) == 0) {
stvp->result_to_output[attr] = ~0;
}
else {
unsigned slot = stvp->num_outputs++;
/* XXX
* Pass in the fragment program's input's semantic info.
* Use the generic semantic indexes from there, instead of
* guessing below.
*/
if (outputMapping) {
slot = outputMapping[attr];
assert(slot != ~0);
}
else {
slot = vs_num_outputs;
vs_num_outputs++;
defaultOutputMapping[attr] = slot;
}
stvp->result_to_output[attr] = slot;
switch (attr) {
case VERT_RESULT_HPOS:
assert(slot == 0);
vs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
vs_output_semantic_index[slot] = 0;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
stvp->output_semantic_index[slot] = 0;
break;
case VERT_RESULT_COL0:
vs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
vs_output_semantic_index[slot] = 0;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
stvp->output_semantic_index[slot] = 0;
break;
case VERT_RESULT_COL1:
vs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
vs_output_semantic_index[slot] = 1;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
stvp->output_semantic_index[slot] = 1;
break;
case VERT_RESULT_BFC0:
vs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
vs_output_semantic_index[slot] = 0;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
stvp->output_semantic_index[slot] = 0;
break;
case VERT_RESULT_BFC1:
vs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
vs_output_semantic_index[slot] = 1;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
stvp->output_semantic_index[slot] = 1;
break;
case VERT_RESULT_FOGC:
vs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG;
vs_output_semantic_index[slot] = 0;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG;
stvp->output_semantic_index[slot] = 0;
break;
case VERT_RESULT_PSIZ:
vs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
vs_output_semantic_index[slot] = 0;
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
stvp->output_semantic_index[slot] = 0;
break;
case VERT_RESULT_EDGE:
assert(0);
break;
case VERT_RESULT_TEX0:
case VERT_RESULT_TEX1:
case VERT_RESULT_TEX2:
@ -257,92 +163,50 @@ st_translate_vertex_program(struct st_context *st,
case VERT_RESULT_TEX5:
case VERT_RESULT_TEX6:
case VERT_RESULT_TEX7:
/* fall-through */
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0;
break;
case VERT_RESULT_VAR0:
/* fall-through */
default:
assert(slot < Elements(vs_output_semantic_name));
if (outputSemanticName) {
/* use provided semantic into */
assert(outputSemanticName[attr] != TGSI_SEMANTIC_COUNT);
vs_output_semantic_name[slot] = outputSemanticName[attr];
vs_output_semantic_index[slot] = outputSemanticIndex[attr];
}
else {
/* use default semantic info */
vs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
vs_output_semantic_index[slot] = num_generic++;
}
}
assert(slot < Elements(output_flags));
output_flags[slot] = stvp->Base.Base.OutputFlags[attr];
}
}
if (outputMapping) {
/* find max output slot referenced to compute vs_num_outputs */
GLuint maxSlot = 0;
for (attr = 0; attr < VERT_RESULT_MAX; attr++) {
if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot)
maxSlot = outputMapping[attr];
}
vs_num_outputs = maxSlot + 1;
}
else {
outputMapping = defaultOutputMapping;
}
#if 0 /* debug */
{
GLuint i;
printf("outputMapping? %d\n", outputMapping ? 1 : 0);
if (outputMapping) {
printf("attr -> slot\n");
for (i = 0; i < 16; i++) {
printf(" %2d %3d\n", i, outputMapping[i]);
assert(attr < VERT_RESULT_MAX);
stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 -
FRAG_ATTRIB_TEX0 +
attr -
VERT_RESULT_VAR0);
break;
}
}
printf("slot sem_name sem_index\n");
for (i = 0; i < vs_num_outputs; i++) {
printf(" %2d %d %d\n",
i,
vs_output_semantic_name[i],
vs_output_semantic_index[i]);
}
}
#endif
}
/* free old shader state, if any */
if (stvp->state.tokens) {
st_free_tokens(stvp->state.tokens);
stvp->state.tokens = NULL;
}
if (stvp->driver_shader) {
cso_delete_vertex_shader(st->cso_context, stvp->driver_shader);
stvp->driver_shader = NULL;
}
stvp->state.tokens =
struct st_vp_varient *
st_translate_vertex_program(struct st_context *st,
struct st_vertex_program *stvp,
const struct st_vp_varient_key *key)
{
struct st_vp_varient *vpv = CALLOC_STRUCT(st_vp_varient);
struct pipe_context *pipe = st->pipe;
vpv->state.tokens =
st_translate_mesa_program(st->ctx,
TGSI_PROCESSOR_VERTEX,
&stvp->Base.Base,
/* inputs */
vs_num_inputs,
stvp->num_inputs,
stvp->input_to_index,
vs_input_semantic_name,
vs_input_semantic_index,
NULL, /* input semantic name */
NULL, /* input semantic index */
NULL,
input_flags,
/* outputs */
vs_num_outputs,
outputMapping,
vs_output_semantic_name,
vs_output_semantic_index,
output_flags );
stvp->num_outputs,
stvp->result_to_output,
stvp->output_semantic_name,
stvp->output_semantic_index );
stvp->num_inputs = vs_num_inputs;
stvp->driver_shader = pipe->create_vs_state(pipe, &stvp->state);
vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->state);
if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) {
_mesa_print_program(&stvp->Base.Base);
@ -350,9 +214,11 @@ st_translate_vertex_program(struct st_context *st,
}
if (ST_DEBUG & DEBUG_TGSI) {
tgsi_dump( stvp->state.tokens, 0 );
tgsi_dump( vpv->state.tokens, 0 );
debug_printf("\n");
}
return vpv;
}
@ -375,7 +241,6 @@ st_translate_fragment_program(struct st_context *st,
GLuint attr;
const GLbitfield inputsRead = stfp->Base.Base.InputsRead;
GLuint vslot = 0;
GLuint num_generic = 0;
uint fs_num_inputs = 0;
@ -383,13 +248,6 @@ st_translate_fragment_program(struct st_context *st,
ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
uint fs_num_outputs = 0;
GLbitfield input_flags[MAX_PROGRAM_INPUTS];
GLbitfield output_flags[MAX_PROGRAM_OUTPUTS];
/*memset(&fs, 0, sizeof(fs));*/
memset(input_flags, 0, sizeof(input_flags));
memset(output_flags, 0, sizeof(output_flags));
/* which vertex output goes to the first fragment input: */
if (inputsRead & FRAG_BIT_WPOS)
vslot = 0;
@ -432,14 +290,25 @@ st_translate_fragment_program(struct st_context *st,
break;
case FRAG_ATTRIB_FACE:
stfp->input_semantic_name[slot] = TGSI_SEMANTIC_FACE;
stfp->input_semantic_index[slot] = num_generic++;
stfp->input_semantic_index[slot] = 0;
interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
break;
case FRAG_ATTRIB_PNTC:
stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
stfp->input_semantic_index[slot] = num_generic++;
interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
break;
/* In most cases, there is nothing special about these
* inputs, so adopt a convention to use the generic
* semantic name and the mesa FRAG_ATTRIB_ number as the
* index.
*
* All that is required is that the vertex shader labels
* its own outputs similarly, and that the vertex shader
* generates at least every output required by the
* fragment shader plus fixed-function hardware (such as
* BFC).
*
* There is no requirement that semantic indexes start at
* zero or be restricted to a particular range -- nobody
* should be building tables based on semantic index.
*/
case FRAG_ATTRIB_TEX0:
case FRAG_ATTRIB_TEX1:
case FRAG_ATTRIB_TEX2:
@ -448,19 +317,18 @@ st_translate_fragment_program(struct st_context *st,
case FRAG_ATTRIB_TEX5:
case FRAG_ATTRIB_TEX6:
case FRAG_ATTRIB_TEX7:
case FRAG_ATTRIB_PNTC:
case FRAG_ATTRIB_VAR0:
default:
/* Actually, let's try and zero-base this just for
* readability of the generated TGSI.
*/
assert(attr >= FRAG_ATTRIB_TEX0);
stfp->input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0);
stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
stfp->input_semantic_index[slot] = num_generic++;
interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
break;
case FRAG_ATTRIB_VAR0:
/* fall-through */
default:
stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
stfp->input_semantic_index[slot] = num_generic++;
interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
}
input_flags[slot] = stfp->Base.Base.InputFlags[attr];
}
}
@ -498,8 +366,6 @@ st_translate_fragment_program(struct st_context *st,
break;
}
output_flags[fs_num_outputs] = stfp->Base.Base.OutputFlags[attr];
fs_num_outputs++;
}
}
@ -518,13 +384,11 @@ st_translate_fragment_program(struct st_context *st,
stfp->input_semantic_name,
stfp->input_semantic_index,
interpMode,
input_flags,
/* outputs */
fs_num_outputs,
outputMapping,
fs_output_semantic_name,
fs_output_semantic_index,
output_flags );
fs_output_semantic_index );
stfp->driver_shader = pipe->create_fs_state(pipe, &stfp->state);

View File

@ -64,41 +64,70 @@ struct st_fragment_program
struct pipe_shader_state state;
void *driver_shader;
GLuint param_state;
/** List of vertex programs which have been translated such that their
* outputs match this fragment program's inputs.
*/
struct translated_vertex_program *vertex_programs;
/** Program prefixed with glBitmap prologue */
struct st_fragment_program *bitmap_program;
uint bitmap_sampler;
};
struct st_vp_varient_key
{
char dummy; /* currently unused */
};
/**
* This represents a vertex program, especially translated to match
* the inputs of a particular fragment shader.
*/
struct st_vp_varient
{
/* Parameters which generated this translated version of a vertex
* shader:
*/
struct st_vp_varient_key key;
/** TGSI tokens -- why?
*/
struct pipe_shader_state state;
/** Driver's compiled shader */
void *driver_shader;
/** For using our private draw module (glRasterPos) */
struct draw_vertex_shader *draw_shader;
/** Next in linked list */
struct st_vp_varient *next;
};
/**
* Derived from Mesa gl_fragment_program:
*/
struct st_vertex_program
{
struct gl_vertex_program Base; /**< The Mesa vertex program */
GLuint serialNo;
GLuint serialNo, lastSerialNo;
/** maps a Mesa VERT_ATTRIB_x to a packed TGSI input index */
GLuint input_to_index[VERT_ATTRIB_MAX];
/** maps a TGSI input index back to a Mesa VERT_ATTRIB_x */
GLuint index_to_input[PIPE_MAX_SHADER_INPUTS];
GLuint num_inputs;
struct pipe_shader_state state;
void *driver_shader;
/** Maps VERT_RESULT_x to slot */
GLuint result_to_output[VERT_RESULT_MAX];
ubyte output_semantic_name[VERT_RESULT_MAX];
ubyte output_semantic_index[VERT_RESULT_MAX];
GLuint num_outputs;
/** For using our private draw module (glRasterPos) */
struct draw_vertex_shader *draw_shader;
GLuint param_state;
/** List of translated varients of this vertex program.
*/
struct st_vp_varient *varients;
};
@ -143,13 +172,21 @@ st_translate_fragment_program(struct st_context *st,
const GLuint inputMapping[]);
/* Called after program string change, discard all previous
* compilation results.
*/
extern void
st_translate_vertex_program(struct st_context *st,
struct st_vertex_program *vp,
const GLuint vert_output_to_slot[],
const ubyte *fs_input_semantic_name,
const ubyte *fs_input_semantic_index);
st_prepare_vertex_program(struct st_context *st,
struct st_vertex_program *stvp);
extern struct st_vp_varient *
st_translate_vertex_program(struct st_context *st,
struct st_vertex_program *stvp,
const struct st_vp_varient_key *key);
void
st_vp_release_varients( struct st_context *st,
struct st_vertex_program *stvp );
extern void
st_print_shaders(GLcontext *ctx);