X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_atom_shader.c;h=6515a98a3fbca10b6bc95855d7bf6581c36de630;hb=ca9ab05d45ebf407485af2daa3742b897ff99162;hp=ee649be885e2fa882ea5e80685796eb93a00c2cd;hpb=940ca2e837efe45caae1cf1d9665f6736347705d;p=mesa.git diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c index ee649be885e..6515a98a3fb 100644 --- a/src/mesa/state_tracker/st_atom_shader.c +++ b/src/mesa/state_tracker/st_atom_shader.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2003 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -18,7 +18,7 @@ * 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 + * IN NO EVENT SHALL VMWARE 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. @@ -35,15 +35,11 @@ * Brian Paul */ - - #include "main/imports.h" #include "main/mtypes.h" -#include "main/macros.h" -#include "shader/program.h" +#include "program/program.h" #include "pipe/p_context.h" -#include "pipe/p_shader_tokens.h" #include "util/u_simple_shaders.h" @@ -52,289 +48,87 @@ #include "st_context.h" #include "st_atom.h" #include "st_program.h" -#include "st_atom_shader.h" -#include "st_mesa_to_tgsi.h" /** - * This represents a vertex program, especially translated to match - * the inputs of a particular fragment shader. + * Return pointer to a pass-through fragment shader. + * This shader is used when a texture is missing/incomplete. */ -struct translated_vertex_program -{ - 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) +static void * +get_passthrough_fs(struct st_context *st) { - 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; + if (!st->passthrough_fs) { + st->passthrough_fs = + util_make_fragment_passthrough_shader(st->pipe, TGSI_SEMANTIC_COLOR, + TGSI_INTERPOLATE_PERSPECTIVE, + TRUE); } + + return st->passthrough_fs; } /** - * 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. + * Update fragment program state/atom. This involves translating the + * Mesa fragment program into a gallium fragment program and binding it. */ -static struct translated_vertex_program * -find_translated_vp(struct st_context *st, - struct st_vertex_program *stvp, - struct st_fragment_program *stfp) +static void +update_fp( struct st_context *st ) { - 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; + struct st_fragment_program *stfp; + struct st_fp_variant_key key; - for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) { - if (fragInputsRead & (1 << inAttr)) { - stfp->input_to_slot[inAttr] = numIn; - numIn++; - } - else { - stfp->input_to_slot[inAttr] = UNUSED; - } - } + assert(st->ctx->FragmentProgram._Current); + stfp = st_fragment_program(st->ctx->FragmentProgram._Current); + assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB); - stfp->num_input_slots = numIn; + memset(&key, 0, sizeof(key)); + key.st = st; - assert(stfp->Base.Base.NumInstructions > 1); + /* _NEW_FRAG_CLAMP */ + key.clamp_color = st->clamp_frag_color_in_shader && + st->ctx->Color._ClampFragmentColor; - st_translate_fragment_program(st, stfp, stfp->input_to_slot); - } + /* Ignore sample qualifier while computing this flag. */ + key.persample_shading = + _mesa_get_min_invocations_per_fragment(st->ctx, &stfp->Base, true) > 1; + st->fp_variant = st_get_fp_variant(st, stfp, &key); - /* 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) { - 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; - } + st_reference_fragprog(st, &st->fp, stfp); - /* See if we need to translate vertex program to TGSI form */ - if (xvp->serialNo != stvp->serialNo) { - GLuint outAttr; - const GLbitfield 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; + if (st->missing_textures) { + /* use a pass-through frag shader that uses no textures */ + void *fs = get_passthrough_fs(st); + cso_set_fragment_shader_handle(st->cso_context, fs); } - - return xvp; -} - - -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; + else { + cso_set_fragment_shader_handle(st->cso_context, + st->fp_variant->driver_shader); } } -static void * -get_passthrough_fs(struct st_context *st) -{ - if (!st->passthrough_fs) { - st->passthrough_fs = - util_make_fragment_passthrough_shader(st->pipe); - } +const struct st_tracked_state st_update_fp = { + "st_update_fp", /* name */ + { /* dirty */ + _NEW_BUFFERS | _NEW_MULTISAMPLE, /* mesa */ + ST_NEW_FRAGMENT_PROGRAM /* st */ + }, + update_fp /* update */ +}; - return st->passthrough_fs; -} +/** + * Update vertex program state/atom. This involves translating the + * Mesa vertex program into a gallium fragment program and binding it. + */ static void -update_linkage( struct st_context *st ) +update_vp( struct st_context *st ) { struct st_vertex_program *stvp; - struct st_fragment_program *stfp; - struct translated_vertex_program *xvp; + struct st_vp_variant_key key; /* find active shader and params -- Should be covered by * ST_NEW_VERTEX_PROGRAM @@ -343,35 +137,72 @@ update_linkage( struct st_context *st ) 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); + memset(&key, 0, sizeof key); + key.st = st; /* variants are per-context */ - xvp = find_translated_vp(st, stvp, stfp); + /* When this is true, we will add an extra input to the vertex + * shader translation (for edgeflags), an extra output with + * edgeflag semantics, and extend the vertex shader to pass through + * the input to the output. We'll need to use similar logic to set + * up the extra vertex_element input for edgeflags. + */ + key.passthrough_edgeflags = st->vertdata_edgeflags; - st_reference_vertprog(st, &st->vp, stvp); - st_reference_fragprog(st, &st->fp, stfp); + key.clamp_color = st->clamp_vert_color_in_shader && + st->ctx->Light._ClampVertexColor; - cso_set_vertex_shader_handle(st->cso_context, stvp->driver_shader); + st->vp_variant = st_get_vp_variant(st, stvp, &key); - if (st->missing_textures) { - /* use a pass-through frag shader that uses no textures */ - void *fs = get_passthrough_fs(st); - cso_set_fragment_shader_handle(st->cso_context, fs); - } - else { - cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader); - } + st_reference_vertprog(st, &st->vp, stvp); + + cso_set_vertex_shader_handle(st->cso_context, + st->vp_variant->driver_shader); - st->vertex_result_to_slot = xvp->output_to_slot; + 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 */ + 0, /* mesa */ + ST_NEW_VERTEX_PROGRAM /* st */ + }, + update_vp /* update */ +}; + + + +static void +update_gp( struct st_context *st ) +{ + struct st_geometry_program *stgp; + struct st_gp_variant_key key; + + if (!st->ctx->GeometryProgram._Current) { + cso_set_geometry_shader_handle(st->cso_context, NULL); + return; + } + + stgp = st_geometry_program(st->ctx->GeometryProgram._Current); + assert(stgp->Base.Base.Target == MESA_GEOMETRY_PROGRAM); + + memset(&key, 0, sizeof(key)); + key.st = st; + + st->gp_variant = st_get_gp_variant(st, stgp, &key); + + st_reference_geomprog(st, &st->gp, stgp); + + cso_set_geometry_shader_handle(st->cso_context, + st->gp_variant->driver_shader); +} + +const struct st_tracked_state st_update_gp = { + "st_update_gp", /* name */ + { /* dirty */ + 0, /* mesa */ + ST_NEW_GEOMETRY_PROGRAM /* st */ }, - update_linkage /* update */ + update_gp /* update */ };