softpipe: implement fragment shader variants

We'll need shader variants to accomodate the new polygon stipple utility.
This commit is contained in:
Brian Paul 2011-07-21 09:55:22 -06:00
parent 3dde6be908
commit c534f11164
13 changed files with 251 additions and 117 deletions

View file

@ -64,6 +64,7 @@ struct softpipe_context {
struct pipe_depth_stencil_alpha_state *depth_stencil;
struct pipe_rasterizer_state *rasterizer;
struct sp_fragment_shader *fs;
struct sp_fragment_shader_variant *fs_variant;
struct sp_vertex_shader *vs;
struct sp_geometry_shader *gs;
struct sp_velems_state *velems;

View file

@ -31,17 +31,15 @@
#ifndef SP_FS_H
#define SP_FS_H
struct sp_fragment_shader *
softpipe_create_fs_exec(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ);
struct sp_fragment_shader *
softpipe_create_fs_sse(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ);
struct sp_fragment_shader_variant *
softpipe_create_fs_variant_exec(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ);
struct sp_fragment_shader_variant *
softpipe_create_fs_variant_sse(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ);
struct sp_fragment_shader *
softpipe_create_fs_llvm(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ);
struct tgsi_interp_coef;
struct tgsi_exec_vector;

View file

@ -42,25 +42,25 @@
/**
* Subclass of sp_fragment_shader
* Subclass of sp_fragment_shader_variant
*/
struct sp_exec_fragment_shader
{
struct sp_fragment_shader base;
struct sp_fragment_shader_variant base;
/* No other members for now */
};
/** cast wrapper */
static INLINE struct sp_exec_fragment_shader *
sp_exec_fragment_shader(const struct sp_fragment_shader *base)
sp_exec_fragment_shader(const struct sp_fragment_shader_variant *var)
{
return (struct sp_exec_fragment_shader *) base;
return (struct sp_exec_fragment_shader *) var;
}
static void
exec_prepare( const struct sp_fragment_shader *base,
exec_prepare( const struct sp_fragment_shader_variant *var,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers )
{
@ -68,9 +68,9 @@ exec_prepare( const struct sp_fragment_shader *base,
* Bind tokens/shader to the interpreter's machine state.
* Avoid redundant binding.
*/
if (machine->Tokens != base->shader.tokens) {
if (machine->Tokens != var->tokens) {
tgsi_exec_machine_bind_shader( machine,
base->shader.tokens,
var->tokens,
PIPE_MAX_SAMPLERS,
samplers );
}
@ -118,7 +118,7 @@ setup_pos_vector(const struct tgsi_interp_coef *coef,
* interface:
*/
static unsigned
exec_run( const struct sp_fragment_shader *base,
exec_run( const struct sp_fragment_shader_variant *var,
struct tgsi_exec_machine *machine,
struct quad_header *quad )
{
@ -136,9 +136,9 @@ exec_run( const struct sp_fragment_shader *base,
/* store outputs */
{
const ubyte *sem_name = base->info.output_semantic_name;
const ubyte *sem_index = base->info.output_semantic_index;
const uint n = base->info.num_outputs;
const ubyte *sem_name = var->info.output_semantic_name;
const ubyte *sem_index = var->info.output_semantic_index;
const uint n = var->info.num_outputs;
uint i;
for (i = 0; i < n; i++) {
switch (sem_name[i]) {
@ -180,16 +180,16 @@ exec_run( const struct sp_fragment_shader *base,
static void
exec_delete( struct sp_fragment_shader *base )
exec_delete( struct sp_fragment_shader_variant *var )
{
FREE((void *) base->shader.tokens);
FREE(base);
FREE( (void *) var->tokens );
FREE(var);
}
struct sp_fragment_shader *
softpipe_create_fs_exec(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ)
struct sp_fragment_shader_variant *
softpipe_create_fs_variant_exec(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ)
{
struct sp_exec_fragment_shader *shader;
@ -197,8 +197,6 @@ softpipe_create_fs_exec(struct softpipe_context *softpipe,
if (!shader)
return NULL;
/* we need to keep a local copy of the tokens */
shader->base.shader.tokens = tgsi_dup_tokens(templ->tokens);
shader->base.prepare = exec_prepare;
shader->base.run = exec_run;
shader->base.delete = exec_delete;

View file

@ -48,11 +48,11 @@
/**
* Subclass of sp_fragment_shader
* Subclass of sp_fragment_shader_variant
*/
struct sp_sse_fragment_shader
{
struct sp_fragment_shader base;
struct sp_fragment_shader_variant base;
struct x86_function sse2_program;
tgsi_sse2_fs_function func;
float immediates[TGSI_EXEC_NUM_IMMEDIATES][4];
@ -61,14 +61,14 @@ struct sp_sse_fragment_shader
/** cast wrapper */
static INLINE struct sp_sse_fragment_shader *
sp_sse_fragment_shader(const struct sp_fragment_shader *base)
sp_sse_fragment_shader(const struct sp_fragment_shader_variant *base)
{
return (struct sp_sse_fragment_shader *) base;
}
static void
fs_sse_prepare( const struct sp_fragment_shader *base,
fs_sse_prepare( const struct sp_fragment_shader_variant *base,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers )
{
@ -119,7 +119,7 @@ setup_pos_vector(const struct tgsi_interp_coef *coef,
* TODO: process >1 quad at a time
*/
static unsigned
fs_sse_run( const struct sp_fragment_shader *base,
fs_sse_run( const struct sp_fragment_shader_variant *base,
struct tgsi_exec_machine *machine,
struct quad_header *quad )
{
@ -189,7 +189,7 @@ fs_sse_run( const struct sp_fragment_shader *base,
static void
fs_sse_delete( struct sp_fragment_shader *base )
fs_sse_delete( struct sp_fragment_shader_variant *base )
{
struct sp_sse_fragment_shader *shader = sp_sse_fragment_shader(base);
@ -198,9 +198,9 @@ fs_sse_delete( struct sp_fragment_shader *base )
}
struct sp_fragment_shader *
softpipe_create_fs_sse(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ)
struct sp_fragment_shader_variant *
softpipe_create_fs_variant_sse(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ)
{
struct sp_sse_fragment_shader *shader;
@ -226,7 +226,6 @@ softpipe_create_fs_sse(struct softpipe_context *softpipe,
return NULL;
}
shader->base.shader.tokens = NULL; /* don't hold reference to templ->tokens */
shader->base.prepare = fs_sse_prepare;
shader->base.run = fs_sse_run;
shader->base.delete = fs_sse_delete;
@ -239,9 +238,9 @@ softpipe_create_fs_sse(struct softpipe_context *softpipe,
/* Maybe put this variant in the header file.
*/
struct sp_fragment_shader *
softpipe_create_fs_sse(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ)
struct sp_fragment_shader_variant *
softpipe_create_fs_variant_sse(struct softpipe_context *softpipe,
const struct pipe_shader_state *templ)
{
return NULL;
}

View file

@ -797,7 +797,7 @@ blend_fallback(struct quad_stage *qs,
unsigned cbuf;
boolean write_all;
write_all = softpipe->fs->info.color0_writes_all_cbufs;
write_all = softpipe->fs_variant->info.color0_writes_all_cbufs;
for (cbuf = 0; cbuf < softpipe->framebuffer.nr_cbufs; cbuf++)
{

View file

@ -726,9 +726,9 @@ depth_test_quads_fallback(struct quad_stage *qs,
unsigned nr)
{
unsigned i, pass = 0;
const struct sp_fragment_shader *fs = qs->softpipe->fs;
boolean interp_depth = !fs->info.writes_z;
boolean shader_stencil_ref = fs->info.writes_stencil;
const struct tgsi_shader_info *fsInfo = &qs->softpipe->fs_variant->info;
boolean interp_depth = !fsInfo->writes_z;
boolean shader_stencil_ref = fsInfo->writes_stencil;
struct depth_data data;
data.use_shader_stencil_refs = FALSE;
@ -837,7 +837,9 @@ choose_depth_test(struct quad_stage *qs,
struct quad_header *quads[],
unsigned nr)
{
boolean interp_depth = !qs->softpipe->fs->info.writes_z;
const struct tgsi_shader_info *fsInfo = &qs->softpipe->fs_variant->info;
boolean interp_depth = !fsInfo->writes_z;
boolean alpha = qs->softpipe->depth_stencil->alpha.enabled;

View file

@ -74,7 +74,7 @@ shade_quad(struct quad_stage *qs, struct quad_header *quad)
struct tgsi_exec_machine *machine = softpipe->fs_machine;
/* run shader */
return softpipe->fs->run( softpipe->fs, machine, quad );
return softpipe->fs_variant->run( softpipe->fs_variant, machine, quad );
}
@ -140,10 +140,10 @@ shade_begin(struct quad_stage *qs)
{
struct softpipe_context *softpipe = qs->softpipe;
softpipe->fs->prepare( softpipe->fs,
softpipe->fs_machine,
(struct tgsi_sampler **)
softpipe->tgsi.frag_samplers_list );
softpipe->fs_variant->prepare( softpipe->fs_variant,
softpipe->fs_machine,
(struct tgsi_sampler **)
softpipe->tgsi.frag_samplers_list );
qs->next->begin(qs->next);
}

View file

@ -46,9 +46,9 @@ sp_build_quad_pipeline(struct softpipe_context *sp)
sp->depth_stencil->depth.enabled &&
sp->framebuffer.zsbuf &&
!sp->depth_stencil->alpha.enabled &&
!sp->fs->info.uses_kill &&
!sp->fs->info.writes_z &&
!sp->fs->info.writes_stencil;
!sp->fs_variant->info.uses_kill &&
!sp->fs_variant->info.writes_z &&
!sp->fs_variant->info.writes_stencil;
sp->quad.first = sp->quad.blend;

View file

@ -568,17 +568,18 @@ tri_persp_coeff(struct setup_context *setup,
static void
setup_fragcoord_coeff(struct setup_context *setup, uint slot)
{
struct sp_fragment_shader* spfs = setup->softpipe->fs;
const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
/*X*/
setup->coef[slot].a0[0] = spfs->info.pixel_center_integer ? 0.0 : 0.5;
setup->coef[slot].a0[0] = fsInfo->pixel_center_integer ? 0.0 : 0.5;
setup->coef[slot].dadx[0] = 1.0;
setup->coef[slot].dady[0] = 0.0;
/*Y*/
setup->coef[slot].a0[1] =
(spfs->info.origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0)
+ (spfs->info.pixel_center_integer ? 0.0 : 0.5);
(fsInfo->origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0)
+ (fsInfo->pixel_center_integer ? 0.0 : 0.5);
setup->coef[slot].dadx[1] = 0.0;
setup->coef[slot].dady[1] = spfs->info.origin_lower_left ? -1.0 : 1.0;
setup->coef[slot].dady[1] = fsInfo->origin_lower_left ? -1.0 : 1.0;
/*Z*/
setup->coef[slot].a0[2] = setup->posCoef.a0[2];
setup->coef[slot].dadx[2] = setup->posCoef.dadx[2];
@ -599,7 +600,7 @@ static void
setup_tri_coefficients(struct setup_context *setup)
{
struct softpipe_context *softpipe = setup->softpipe;
const struct sp_fragment_shader *spfs = softpipe->fs;
const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
uint fragSlot;
float v[3];
@ -618,7 +619,7 @@ setup_tri_coefficients(struct setup_context *setup)
/* setup interpolation for all the remaining attributes:
*/
for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
const uint vertSlot = vinfo->attrib[fragSlot].src_index;
uint j;
@ -632,7 +633,7 @@ setup_tri_coefficients(struct setup_context *setup)
tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
setup->vmid[vertSlot][j],
setup->vmax[vertSlot][j],
spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
v);
tri_linear_coeff(setup, &setup->coef[fragSlot], j, v);
}
@ -642,7 +643,7 @@ setup_tri_coefficients(struct setup_context *setup)
tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
setup->vmid[vertSlot][j],
setup->vmax[vertSlot][j],
spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
v);
tri_persp_coeff(setup, &setup->coef[fragSlot], j, v);
}
@ -654,7 +655,7 @@ setup_tri_coefficients(struct setup_context *setup)
assert(0);
}
if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
/* convert 0 to 1.0 and 1 to -1.0 */
setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
setup->coef[fragSlot].dadx[0] = 0.0;
@ -939,7 +940,7 @@ setup_line_coefficients(struct setup_context *setup,
const float (*v1)[4])
{
struct softpipe_context *softpipe = setup->softpipe;
const struct sp_fragment_shader *spfs = softpipe->fs;
const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
uint fragSlot;
float area;
@ -974,7 +975,7 @@ setup_line_coefficients(struct setup_context *setup,
/* setup interpolation for all the remaining attributes:
*/
for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
const uint vertSlot = vinfo->attrib[fragSlot].src_index;
uint j;
@ -987,7 +988,7 @@ setup_line_coefficients(struct setup_context *setup,
for (j = 0; j < NUM_CHANNELS; j++) {
line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
setup->vmax[vertSlot][j],
spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
v);
line_linear_coeff(setup, &setup->coef[fragSlot], j, v);
}
@ -996,7 +997,7 @@ setup_line_coefficients(struct setup_context *setup,
for (j = 0; j < NUM_CHANNELS; j++) {
line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
setup->vmax[vertSlot][j],
spfs->info.input_cylindrical_wrap[fragSlot] & (1 << j),
fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
v);
line_persp_coeff(setup, &setup->coef[fragSlot], j, v);
}
@ -1008,7 +1009,7 @@ setup_line_coefficients(struct setup_context *setup,
assert(0);
}
if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
/* convert 0 to 1.0 and 1 to -1.0 */
setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
setup->coef[fragSlot].dadx[0] = 0.0;
@ -1188,7 +1189,7 @@ sp_setup_point(struct setup_context *setup,
const float (*v0)[4])
{
struct softpipe_context *softpipe = setup->softpipe;
const struct sp_fragment_shader *spfs = softpipe->fs;
const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
const int sizeAttr = setup->softpipe->psize_slot;
const float size
= sizeAttr > 0 ? v0[sizeAttr][0]
@ -1232,7 +1233,7 @@ sp_setup_point(struct setup_context *setup,
const_coeff(setup, &setup->posCoef, 0, 2);
const_coeff(setup, &setup->posCoef, 0, 3);
for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
const uint vertSlot = vinfo->attrib[fragSlot].src_index;
uint j;
@ -1255,7 +1256,7 @@ sp_setup_point(struct setup_context *setup,
assert(0);
}
if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
/* convert 0 to 1.0 and 1 to -1.0 */
setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
setup->coef[fragSlot].dadx[0] = 0.0;

View file

@ -60,31 +60,43 @@ struct tgsi_exec_machine;
struct vertex_info;
/**
* Subclass of pipe_shader_state (though it doesn't really need to be).
*
* This is starting to look an awful lot like a quad pipeline stage...
*/
struct sp_fragment_shader {
struct pipe_shader_state shader;
struct sp_fragment_shader_variant_key
{
int foo; /* XXX temporary */
};
struct sp_fragment_shader_variant
{
const struct tgsi_token *tokens;
struct sp_fragment_shader_variant_key key;
struct tgsi_shader_info info;
/* See comments about this elsewhere */
#if 0
struct draw_fragment_shader *draw_shader;
#endif
void (*prepare)( const struct sp_fragment_shader *shader,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers);
void (*prepare)(const struct sp_fragment_shader_variant *shader,
struct tgsi_exec_machine *machine,
struct tgsi_sampler **samplers);
/* Run the shader - this interface will get cleaned up in the
* future:
*/
unsigned (*run)( const struct sp_fragment_shader *shader,
struct tgsi_exec_machine *machine,
struct quad_header *quad );
unsigned (*run)(const struct sp_fragment_shader_variant *shader,
struct tgsi_exec_machine *machine,
struct quad_header *quad);
/* Deletes this instance of the object */
void (*delete)(struct sp_fragment_shader_variant *shader);
struct sp_fragment_shader_variant *next;
};
void (*delete)( struct sp_fragment_shader * );
/** Subclass of pipe_shader_state */
struct sp_fragment_shader {
struct pipe_shader_state shader;
struct sp_fragment_shader_variant *variants;
struct draw_fragment_shader *draw_shader;
};
@ -138,7 +150,7 @@ softpipe_set_framebuffer_state(struct pipe_context *,
const struct pipe_framebuffer_state *);
void
softpipe_update_derived( struct softpipe_context *softpipe );
softpipe_update_derived(struct softpipe_context *softpipe);
void
softpipe_draw_vbo(struct pipe_context *pipe,
@ -167,4 +179,10 @@ struct vertex_info *
softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe);
struct sp_fragment_shader_variant *
softpipe_find_fs_variant(struct softpipe_context *softpipe,
struct sp_fragment_shader *fs,
const struct sp_fragment_shader_variant_key *key);
#endif

View file

@ -64,7 +64,7 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
if (vinfo->num_attribs == 0) {
/* compute vertex layout now */
const struct sp_fragment_shader *spfs = softpipe->fs;
const struct tgsi_shader_info *fsInfo = &softpipe->fs_variant->info;
struct vertex_info *vinfo_vbuf = &softpipe->vertex_info_vbuf;
const uint num = draw_num_shader_outputs(softpipe->draw);
uint i;
@ -84,11 +84,11 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
* from the vertex shader.
*/
vinfo->num_attribs = 0;
for (i = 0; i < spfs->info.num_inputs; i++) {
for (i = 0; i < fsInfo->num_inputs; i++) {
int src;
enum interp_mode interp;
switch (spfs->info.input_interpolate[i]) {
switch (fsInfo->input_interpolate[i]) {
case TGSI_INTERPOLATE_CONSTANT:
interp = INTERP_CONSTANT;
break;
@ -103,7 +103,7 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
interp = INTERP_LINEAR;
}
switch (spfs->info.input_semantic_name[i]) {
switch (fsInfo->input_semantic_name[i]) {
case TGSI_SEMANTIC_POSITION:
interp = INTERP_POS;
break;
@ -117,8 +117,8 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe)
/* this includes texcoords and varying vars */
src = draw_find_shader_output(softpipe->draw,
spfs->info.input_semantic_name[i],
spfs->info.input_semantic_index[i]);
fsInfo->input_semantic_name[i],
fsInfo->input_semantic_index[i]);
draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src);
}
@ -241,10 +241,46 @@ update_tgsi_samplers( struct softpipe_context *softpipe )
}
static void
update_fragment_shader(struct softpipe_context *softpipe)
{
struct sp_fragment_shader_variant_key key;
memset(&key, 0, sizeof(key));
if (softpipe->fs) {
softpipe->fs_variant = softpipe_find_fs_variant(softpipe,
softpipe->fs, &key);
}
else {
softpipe->fs_variant = NULL;
}
/* This would be the logical place to pass the fragment shader
* to the draw module. However, doing this here, during state
* validation, causes problems with the 'draw' module helpers for
* wide/AA/stippled lines.
* In principle, the draw's fragment shader should be per-variant
* but that doesn't work. So we use a single draw fragment shader
* per fragment shader, not per variant.
*/
#if 0
if (softpipe->fs_variant) {
draw_bind_fragment_shader(softpipe->draw,
softpipe->fs_variant->draw_shader);
}
else {
draw_bind_fragment_shader(softpipe->draw, NULL);
}
#endif
}
/* Hopefully this will remain quite simple, otherwise need to pull in
* something like the state tracker mechanism.
*/
void softpipe_update_derived( struct softpipe_context *softpipe )
void
softpipe_update_derived(struct softpipe_context *softpipe)
{
struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen);
@ -255,6 +291,10 @@ void softpipe_update_derived( struct softpipe_context *softpipe )
softpipe->dirty |= SP_NEW_TEXTURE;
}
if (softpipe->dirty & (SP_NEW_RASTERIZER |
SP_NEW_FS))
update_fragment_shader(softpipe);
if (softpipe->dirty & (SP_NEW_SAMPLER |
SP_NEW_TEXTURE |
SP_NEW_FS |

View file

@ -373,8 +373,9 @@ softpipe_reset_sampler_variants(struct softpipe_context *softpipe)
}
}
for (i = 0; i <= softpipe->fs->info.file_max[TGSI_FILE_SAMPLER]; i++) {
for (i = 0; i <= softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]; i++) {
if (softpipe->fragment_samplers[i]) {
assert(softpipe->fragment_sampler_views[i]->texture);
softpipe->tgsi.frag_samplers_list[i] =
get_sampler_variant( i,
sp_sampler(softpipe->fragment_samplers[i]),

View file

@ -42,37 +42,91 @@
#include "tgsi/tgsi_parse.h"
/**
* Create a new fragment shader variant.
*/
static struct sp_fragment_shader_variant *
create_fs_variant(struct softpipe_context *softpipe,
struct sp_fragment_shader *fs,
const struct sp_fragment_shader_variant_key *key)
{
struct sp_fragment_shader_variant *var;
struct pipe_shader_state *curfs = &fs->shader;
/* codegen, create variant object */
var = softpipe_create_fs_variant_sse(softpipe, curfs);
if (!var) {
var = softpipe_create_fs_variant_exec(softpipe, curfs);
}
if (var) {
var->key = *key;
var->tokens = tgsi_dup_tokens(curfs->tokens);
tgsi_scan_shader(var->tokens, &var->info);
/* See comments elsewhere about draw fragment shaders */
#if 0
/* draw's fs state */
var->draw_shader = draw_create_fragment_shader(softpipe->draw,
&fs->shader);
if (!var->draw_shader) {
var->delete(var);
FREE((void *) var->tokens);
return NULL;
}
#endif
/* insert variant into linked list */
var->next = fs->variants;
fs->variants = var;
}
return var;
}
struct sp_fragment_shader_variant *
softpipe_find_fs_variant(struct softpipe_context *sp,
struct sp_fragment_shader *fs,
const struct sp_fragment_shader_variant_key *key)
{
struct sp_fragment_shader_variant *var;
for (var = fs->variants; var; var = var->next) {
if (memcmp(&var->key, key, sizeof(*key)) == 0) {
/* found it */
return var;
}
}
return create_fs_variant(sp, fs, key);
}
static void *
softpipe_create_fs_state(struct pipe_context *pipe,
const struct pipe_shader_state *templ)
{
struct softpipe_context *softpipe = softpipe_context(pipe);
struct sp_fragment_shader *state;
unsigned i;
struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader);
/* debug */
if (softpipe->dump_fs)
tgsi_dump(templ->tokens, 0);
/* codegen */
state = softpipe_create_fs_sse( softpipe, templ );
if (!state) {
state = softpipe_create_fs_exec( softpipe, templ );
}
if (!state)
return NULL;
/* we need to keep a local copy of the tokens */
state->shader.tokens = tgsi_dup_tokens(templ->tokens);
/* draw's fs state */
state->draw_shader = draw_create_fragment_shader(softpipe->draw, templ);
state->draw_shader = draw_create_fragment_shader(softpipe->draw,
&state->shader);
if (!state->draw_shader) {
state->delete( state );
FREE((void *) state->shader.tokens);
FREE(state);
return NULL;
}
/* get/save the summary info for this shader */
tgsi_scan_shader(templ->tokens, &state->info);
return state;
}
@ -81,6 +135,7 @@ static void
softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
{
struct softpipe_context *softpipe = softpipe_context(pipe);
struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs;
if (softpipe->fs == fs)
return;
@ -89,8 +144,14 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
softpipe->fs = fs;
draw_bind_fragment_shader(softpipe->draw,
(softpipe->fs ? softpipe->fs->draw_shader : NULL));
if (fs == NULL)
softpipe->fs_variant = NULL;
if (state)
draw_bind_fragment_shader(softpipe->draw,
state->draw_shader);
else
draw_bind_fragment_shader(softpipe->draw, NULL);
softpipe->dirty |= SP_NEW_FS;
}
@ -101,8 +162,9 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
{
struct softpipe_context *softpipe = softpipe_context(pipe);
struct sp_fragment_shader *state = fs;
struct sp_fragment_shader_variant *var, *next_var;
assert(fs != softpipe_context(pipe)->fs);
assert(fs != softpipe->fs);
if (softpipe->fs_machine->Tokens == state->shader.tokens) {
/* unbind the shader from the tgsi executor if we're
@ -111,9 +173,23 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL);
}
/* delete variants */
for (var = state->variants; var; var = next_var) {
next_var = var->next;
assert(var != softpipe->fs_variant);
/* See comments elsewhere about draw fragment shaders */
#if 0
draw_delete_fragment_shader(softpipe->draw, var->draw_shader);
#endif
var->delete(var);
}
draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
state->delete( state );
FREE((void *) state->shader.tokens);
}