X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_program.c;h=d2d68ac05bfb7f63684fa3d1b76277a8dea84c6d;hb=ea8f4a6b13b94eb060bff4ccc6c13efc01d2b682;hp=cebe39004b83a404d899eff1d077dde1cf1dc841;hpb=697b9945fb0f55428b06821f98fd8621372f81ad;p=mesa.git diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index cebe39004b8..d2d68ac05bf 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007 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. @@ -26,14 +26,13 @@ **************************************************************************/ /* * Authors: - * Keith Whitwell + * Keith Whitwell * Brian Paul */ #include "main/imports.h" #include "main/hash.h" -#include "main/mfeatures.h" #include "main/mtypes.h" #include "program/prog_parameter.h" #include "program/prog_print.h" @@ -44,6 +43,8 @@ #include "pipe/p_shader_tokens.h" #include "draw/draw_context.h" #include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_emulate.h" +#include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_ureg.h" #include "st_debug.h" @@ -52,6 +53,7 @@ #include "st_context.h" #include "st_program.h" #include "st_mesa_to_tgsi.h" +#include "st_atifs_to_tgsi.h" #include "cso_cache/cso_context.h" @@ -66,15 +68,13 @@ delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) if (vpv->driver_shader) cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); -#if FEATURE_feedback || FEATURE_rastpos if (vpv->draw_shader) draw_delete_vertex_shader( st->draw, vpv->draw_shader ); -#endif if (vpv->tgsi.tokens) - st_free_tokens(vpv->tgsi.tokens); + ureg_free_tokens(vpv->tgsi.tokens); - FREE( vpv ); + free( vpv ); } @@ -95,6 +95,11 @@ st_release_vp_variants( struct st_context *st, } stvp->variants = NULL; + + if (stvp->tgsi.tokens) { + tgsi_free_tokens(stvp->tgsi.tokens); + stvp->tgsi.tokens = NULL; + } } @@ -108,11 +113,7 @@ delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv) { if (fpv->driver_shader) cso_delete_fragment_shader(st->cso_context, fpv->driver_shader); - if (fpv->parameters) - _mesa_free_parameter_list(fpv->parameters); - if (fpv->tgsi.tokens) - st_free_tokens(fpv->tgsi.tokens); - FREE(fpv); + free(fpv); } @@ -131,64 +132,114 @@ st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) } stfp->variants = NULL; + + if (stfp->tgsi.tokens) { + ureg_free_tokens(stfp->tgsi.tokens); + stfp->tgsi.tokens = NULL; + } } /** - * Delete a geometry program variant. Note the caller must unlink + * Delete a basic program variant. Note the caller must unlink * the variant from the linked list. */ static void -delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) +delete_basic_variant(struct st_context *st, struct st_basic_variant *v, + GLenum target) { - if (gpv->driver_shader) - cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); - - FREE(gpv); + if (v->driver_shader) { + switch (target) { + case GL_TESS_CONTROL_PROGRAM_NV: + cso_delete_tessctrl_shader(st->cso_context, v->driver_shader); + break; + case GL_TESS_EVALUATION_PROGRAM_NV: + cso_delete_tesseval_shader(st->cso_context, v->driver_shader); + break; + case GL_GEOMETRY_PROGRAM_NV: + cso_delete_geometry_shader(st->cso_context, v->driver_shader); + break; + case GL_COMPUTE_PROGRAM_NV: + cso_delete_compute_shader(st->cso_context, v->driver_shader); + break; + default: + assert(!"this shouldn't occur"); + } + } + + free(v); } /** - * Free all variants of a geometry program. + * Free all basic program variants. */ void -st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) +st_release_basic_variants(struct st_context *st, GLenum target, + struct st_basic_variant **variants, + struct pipe_shader_state *tgsi) { - struct st_gp_variant *gpv; + struct st_basic_variant *v; - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - delete_gp_variant(st, gpv); - gpv = next; + for (v = *variants; v; ) { + struct st_basic_variant *next = v->next; + delete_basic_variant(st, v, target); + v = next; } - stgp->variants = NULL; + *variants = NULL; + + if (tgsi->tokens) { + ureg_free_tokens(tgsi->tokens); + tgsi->tokens = NULL; + } } +/** + * Free all variants of a compute program. + */ +void +st_release_cp_variants(struct st_context *st, struct st_compute_program *stcp) +{ + struct st_basic_variant **variants = &stcp->variants; + struct st_basic_variant *v; + + for (v = *variants; v; ) { + struct st_basic_variant *next = v->next; + delete_basic_variant(st, v, stcp->Base.Base.Target); + v = next; + } + + *variants = NULL; + + if (stcp->tgsi.prog) { + ureg_free_tokens(stcp->tgsi.prog); + stcp->tgsi.prog = NULL; + } +} /** - * Translate a Mesa vertex shader into a TGSI shader. - * \param outputMapping to map vertex program output registers (VERT_RESULT_x) - * to TGSI output slots - * \param tokensOut destination for TGSI tokens - * \return pointer to cached pipe_shader object. + * Translate a vertex program. */ -void -st_prepare_vertex_program(struct gl_context *ctx, +bool +st_translate_vertex_program(struct st_context *st, struct st_vertex_program *stvp) { - GLuint attr; + struct ureg_program *ureg; + enum pipe_error error; + unsigned num_outputs = 0; + unsigned attr; + unsigned input_to_index[VERT_ATTRIB_MAX] = {0}; + unsigned output_slot_to_attr[VARYING_SLOT_MAX] = {0}; + ubyte output_semantic_name[VARYING_SLOT_MAX] = {0}; + ubyte output_semantic_index[VARYING_SLOT_MAX] = {0}; stvp->num_inputs = 0; - stvp->num_outputs = 0; if (stvp->Base.IsPositionInvariant) - _mesa_insert_mvp_code(ctx, &stvp->Base); - - if (!stvp->glsl_to_tgsi) - assert(stvp->Base.Base.NumInstructions > 1); + _mesa_insert_mvp_code(st->ctx, &stvp->Base); /* * Determine number of inputs, the mappings between VERT_ATTRIB_x @@ -196,138 +247,125 @@ st_prepare_vertex_program(struct gl_context *ctx, */ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { if ((stvp->Base.Base.InputsRead & BITFIELD64_BIT(attr)) != 0) { - stvp->input_to_index[attr] = stvp->num_inputs; + input_to_index[attr] = stvp->num_inputs; stvp->index_to_input[stvp->num_inputs] = attr; stvp->num_inputs++; + if ((stvp->Base.Base.DoubleInputsRead & BITFIELD64_BIT(attr)) != 0) { + /* add placeholder for second part of a double attribute */ + stvp->index_to_input[stvp->num_inputs] = ST_DOUBLE_ATTRIB_PLACEHOLDER; + stvp->num_inputs++; + } } } /* bit of a hack, presetup potentially unused edgeflag input */ - stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; + input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; /* Compute mapping of vertex program outputs to slots. */ - for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + for (attr = 0; attr < VARYING_SLOT_MAX; attr++) { if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { stvp->result_to_output[attr] = ~0; } else { - unsigned slot = stvp->num_outputs++; + unsigned slot = num_outputs++; stvp->result_to_output[attr] = slot; + output_slot_to_attr[slot] = attr; switch (attr) { - case VERT_RESULT_HPOS: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_POS: + output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_COL0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_COL0: + output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_COL1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stvp->output_semantic_index[slot] = 1; + case VARYING_SLOT_COL1: + output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + output_semantic_index[slot] = 1; break; - case VERT_RESULT_BFC0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_BFC0: + output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_BFC1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - stvp->output_semantic_index[slot] = 1; + case VARYING_SLOT_BFC1: + output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + output_semantic_index[slot] = 1; break; - case VERT_RESULT_FOGC: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_FOGC: + output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_PSIZ: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_PSIZ: + output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_CLIP_DIST0: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_CLIP_DIST0: + output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_CLIP_DIST1: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; - stvp->output_semantic_index[slot] = 1; + case VARYING_SLOT_CLIP_DIST1: + output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; + output_semantic_index[slot] = 1; break; - case VERT_RESULT_EDGE: + case VARYING_SLOT_EDGE: assert(0); break; - case VERT_RESULT_CLIP_VERTEX: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_CLIPVERTEX; - stvp->output_semantic_index[slot] = 0; + case VARYING_SLOT_CLIP_VERTEX: + output_semantic_name[slot] = TGSI_SEMANTIC_CLIPVERTEX; + output_semantic_index[slot] = 0; break; - - case VERT_RESULT_TEX0: - case VERT_RESULT_TEX1: - case VERT_RESULT_TEX2: - case VERT_RESULT_TEX3: - case VERT_RESULT_TEX4: - case VERT_RESULT_TEX5: - case VERT_RESULT_TEX6: - case VERT_RESULT_TEX7: - stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; + case VARYING_SLOT_LAYER: + output_semantic_name[slot] = TGSI_SEMANTIC_LAYER; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_VIEWPORT: + output_semantic_name[slot] = TGSI_SEMANTIC_VIEWPORT_INDEX; + output_semantic_index[slot] = 0; break; - case VERT_RESULT_VAR0: + case VARYING_SLOT_TEX0: + case VARYING_SLOT_TEX1: + case VARYING_SLOT_TEX2: + case VARYING_SLOT_TEX3: + case VARYING_SLOT_TEX4: + case VARYING_SLOT_TEX5: + case VARYING_SLOT_TEX6: + case VARYING_SLOT_TEX7: + if (st->needs_texcoord_semantic) { + output_semantic_name[slot] = TGSI_SEMANTIC_TEXCOORD; + output_semantic_index[slot] = attr - VARYING_SLOT_TEX0; + break; + } + /* fall through */ + case VARYING_SLOT_VAR0: default: - 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); + assert(attr >= VARYING_SLOT_VAR0 || + (attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7)); + output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + output_semantic_index[slot] = + st_get_generic_varying_index(st, attr); break; } } } /* similar hack to above, presetup potentially unused edgeflag output */ - stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; - stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; - stvp->output_semantic_index[stvp->num_outputs] = 0; -} - - -/** - * Translate a vertex program to create a new variant. - */ -static struct st_vp_variant * -st_translate_vertex_program(struct st_context *st, - struct st_vertex_program *stvp, - const struct st_vp_variant_key *key) -{ - struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); - struct pipe_context *pipe = st->pipe; - struct ureg_program *ureg; - enum pipe_error error; - unsigned num_outputs; - - st_prepare_vertex_program(st->ctx, stvp); + stvp->result_to_output[VARYING_SLOT_EDGE] = num_outputs; + output_semantic_name[num_outputs] = TGSI_SEMANTIC_EDGEFLAG; + output_semantic_index[num_outputs] = 0; if (!stvp->glsl_to_tgsi) - { _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); - } - ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - if (ureg == NULL) { - FREE(vpv); - return NULL; - } - - vpv->key = *key; + ureg = ureg_create_with_screen(TGSI_PROCESSOR_VERTEX, st->pipe->screen); + if (ureg == NULL) + return false; - vpv->num_inputs = stvp->num_inputs; - num_outputs = stvp->num_outputs; - if (key->passthrough_edgeflags) { - vpv->num_inputs++; - num_outputs++; - } + if (stvp->Base.Base.ClipDistanceArraySize) + ureg_property(ureg, TGSI_PROPERTY_NUM_CLIPDIST_ENABLED, + stvp->Base.Base.ClipDistanceArraySize); if (ST_DEBUG & DEBUG_MESA) { _mesa_print_program(&stvp->Base.Base); @@ -335,7 +373,7 @@ st_translate_vertex_program(struct st_context *st, debug_printf("\n"); } - if (stvp->glsl_to_tgsi) + if (stvp->glsl_to_tgsi) { error = st_translate_program(st->ctx, TGSI_PROCESSOR_VERTEX, ureg, @@ -343,67 +381,93 @@ st_translate_vertex_program(struct st_context *st, &stvp->Base.Base, /* inputs */ stvp->num_inputs, - stvp->input_to_index, + input_to_index, + NULL, /* inputSlotToAttr */ NULL, /* input semantic name */ NULL, /* input semantic index */ NULL, /* interp mode */ + NULL, /* interp location */ /* outputs */ - stvp->num_outputs, + num_outputs, stvp->result_to_output, - stvp->output_semantic_name, - stvp->output_semantic_index, - key->passthrough_edgeflags, - key->clamp_color); - else + output_slot_to_attr, + output_semantic_name, + output_semantic_index); + + st_translate_stream_output_info(stvp->glsl_to_tgsi, + stvp->result_to_output, + &stvp->tgsi.stream_output); + + free_glsl_to_tgsi_visitor(stvp->glsl_to_tgsi); + stvp->glsl_to_tgsi = NULL; + } else error = st_translate_mesa_program(st->ctx, TGSI_PROCESSOR_VERTEX, ureg, &stvp->Base.Base, /* inputs */ - vpv->num_inputs, - stvp->input_to_index, + stvp->num_inputs, + input_to_index, NULL, /* input semantic name */ NULL, /* input semantic index */ NULL, /* outputs */ num_outputs, stvp->result_to_output, - stvp->output_semantic_name, - stvp->output_semantic_index, - key->passthrough_edgeflags, - key->clamp_color); + output_semantic_name, + output_semantic_index); + + if (error) { + debug_printf("%s: failed to translate Mesa program:\n", __func__); + _mesa_print_program(&stvp->Base.Base); + debug_assert(0); + return false; + } - if (error) - goto fail; + stvp->tgsi.tokens = ureg_get_tokens(ureg, NULL); + ureg_destroy(ureg); + return stvp->tgsi.tokens != NULL; +} - vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - if (!vpv->tgsi.tokens) - goto fail; +static struct st_vp_variant * +st_create_vp_variant(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); + struct pipe_context *pipe = st->pipe; - ureg_destroy( ureg ); + vpv->key = *key; + vpv->tgsi.tokens = tgsi_dup_tokens(stvp->tgsi.tokens); + vpv->tgsi.stream_output = stvp->tgsi.stream_output; + vpv->num_inputs = stvp->num_inputs; - if (stvp->glsl_to_tgsi) { - st_translate_stream_output_info(stvp->glsl_to_tgsi, - stvp->result_to_output, - &vpv->tgsi.stream_output); - } + /* Emulate features. */ + if (key->clamp_color || key->passthrough_edgeflags) { + const struct tgsi_token *tokens; + unsigned flags = + (key->clamp_color ? TGSI_EMU_CLAMP_COLOR_OUTPUTS : 0) | + (key->passthrough_edgeflags ? TGSI_EMU_PASSTHROUGH_EDGEFLAG : 0); - vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); + tokens = tgsi_emulate(vpv->tgsi.tokens, flags); + + if (tokens) { + tgsi_free_tokens(vpv->tgsi.tokens); + vpv->tgsi.tokens = tokens; + + if (key->passthrough_edgeflags) + vpv->num_inputs++; + } else + fprintf(stderr, "mesa: cannot emulate deprecated features\n"); + } if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( vpv->tgsi.tokens, 0 ); + tgsi_dump(vpv->tgsi.tokens, 0); debug_printf("\n"); } + vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); return vpv; - -fail: - debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); - _mesa_print_program(&stvp->Base.Base); - debug_assert(0); - - ureg_destroy( ureg ); - return NULL; } @@ -426,7 +490,7 @@ st_get_vp_variant(struct st_context *st, if (!vpv) { /* create now */ - vpv = st_translate_vertex_program(st, stvp, key); + vpv = st_create_vp_variant(st, stvp, key); if (vpv) { /* insert into list */ vpv->next = stvp->variants; @@ -460,24 +524,19 @@ st_translate_interp(enum glsl_interp_qualifier glsl_qual, bool is_color) /** - * Translate a Mesa fragment shader into a TGSI shader using extra info in - * the key. - * \return new fragment program variant + * Translate a Mesa fragment shader into a TGSI shader. */ -static struct st_fp_variant * +bool st_translate_fragment_program(struct st_context *st, - struct st_fragment_program *stfp, - const struct st_fp_variant_key *key) + struct st_fragment_program *stfp) { - struct pipe_context *pipe = st->pipe; - struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); - GLboolean deleteFP = GL_FALSE; - GLuint outputMapping[FRAG_RESULT_MAX]; - GLuint inputMapping[FRAG_ATTRIB_MAX]; + GLuint inputMapping[VARYING_SLOT_MAX]; + GLuint inputSlotToAttr[VARYING_SLOT_MAX]; GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ + GLuint interpLocation[PIPE_MAX_SHADER_INPUTS]; GLuint attr; - const GLbitfield64 inputsRead = stfp->Base.Base.InputsRead; + GLbitfield64 inputsRead; struct ureg_program *ureg; GLboolean write_all = GL_FALSE; @@ -490,94 +549,87 @@ st_translate_fragment_program(struct st_context *st, ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; uint fs_num_outputs = 0; - if (!variant) - return NULL; - - assert(!(key->bitmap && key->drawpixels)); - -#if FEATURE_drawpix - if (key->bitmap) { - /* glBitmap drawing */ - struct gl_fragment_program *fp; /* we free this temp program below */ + memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr)); - st_make_bitmap_fragment_program(st, &stfp->Base, - &fp, &variant->bitmap_sampler); - - variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); - stfp = st_fragment_program(fp); - deleteFP = GL_TRUE; - } - else if (key->drawpixels) { - /* glDrawPixels drawing */ - struct gl_fragment_program *fp; /* we free this temp program below */ - - if (key->drawpixels_z || key->drawpixels_stencil) { - fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, - key->drawpixels_stencil); - } - else { - /* RGBA */ - st_make_drawpix_fragment_program(st, &stfp->Base, &fp); - variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); - deleteFP = GL_TRUE; - } - stfp = st_fragment_program(fp); - } -#endif - - if (!stfp->glsl_to_tgsi) + if (!stfp->glsl_to_tgsi) { _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); + if (st->ctx->Const.GLSLFragCoordIsSysVal) + _mesa_program_fragment_position_to_sysval(&stfp->Base.Base); + } /* * Convert Mesa program inputs to TGSI input register semantics. */ - for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { + inputsRead = stfp->Base.Base.InputsRead; + for (attr = 0; attr < VARYING_SLOT_MAX; attr++) { if ((inputsRead & BITFIELD64_BIT(attr)) != 0) { const GLuint slot = fs_num_inputs++; inputMapping[attr] = slot; + inputSlotToAttr[slot] = attr; + if (stfp->Base.IsCentroid & BITFIELD64_BIT(attr)) + interpLocation[slot] = TGSI_INTERPOLATE_LOC_CENTROID; + else if (stfp->Base.IsSample & BITFIELD64_BIT(attr)) + interpLocation[slot] = TGSI_INTERPOLATE_LOC_SAMPLE; + else + interpLocation[slot] = TGSI_INTERPOLATE_LOC_CENTER; switch (attr) { - case FRAG_ATTRIB_WPOS: + case VARYING_SLOT_POS: input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_LINEAR; break; - case FRAG_ATTRIB_COL0: + case VARYING_SLOT_COL0: input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; input_semantic_index[slot] = 0; interpMode[slot] = st_translate_interp(stfp->Base.InterpQualifier[attr], TRUE); break; - case FRAG_ATTRIB_COL1: + case VARYING_SLOT_COL1: input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; input_semantic_index[slot] = 1; interpMode[slot] = st_translate_interp(stfp->Base.InterpQualifier[attr], TRUE); break; - case FRAG_ATTRIB_FOGC: + case VARYING_SLOT_FOGC: input_semantic_name[slot] = TGSI_SEMANTIC_FOG; input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; break; - case FRAG_ATTRIB_FACE: + case VARYING_SLOT_FACE: input_semantic_name[slot] = TGSI_SEMANTIC_FACE; input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; break; - case FRAG_ATTRIB_CLIP_DIST0: + case VARYING_SLOT_PRIMITIVE_ID: + input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; + break; + case VARYING_SLOT_LAYER: + input_semantic_name[slot] = TGSI_SEMANTIC_LAYER; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; + break; + case VARYING_SLOT_VIEWPORT: + input_semantic_name[slot] = TGSI_SEMANTIC_VIEWPORT_INDEX; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; + break; + case VARYING_SLOT_CLIP_DIST0: input_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; break; - case FRAG_ATTRIB_CLIP_DIST1: + case VARYING_SLOT_CLIP_DIST1: input_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; input_semantic_index[slot] = 1; - interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + 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 + * semantic name and the mesa VARYING_SLOT_ number as the * index. * * All that is required is that the vertex shader labels @@ -586,28 +638,51 @@ st_translate_fragment_program(struct st_context *st, * 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. + * However, some drivers may need us to identify the PNTC and TEXi + * varyings if, for example, their capability to replace them with + * sprite coordinates is limited. */ - case FRAG_ATTRIB_PNTC: - case FRAG_ATTRIB_TEX0: - case FRAG_ATTRIB_TEX1: - case FRAG_ATTRIB_TEX2: - case FRAG_ATTRIB_TEX3: - case FRAG_ATTRIB_TEX4: - case FRAG_ATTRIB_TEX5: - case FRAG_ATTRIB_TEX6: - case FRAG_ATTRIB_TEX7: - case FRAG_ATTRIB_VAR0: + case VARYING_SLOT_PNTC: + if (st->needs_texcoord_semantic) { + input_semantic_name[slot] = TGSI_SEMANTIC_PCOORD; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + } + /* fall through */ + case VARYING_SLOT_TEX0: + case VARYING_SLOT_TEX1: + case VARYING_SLOT_TEX2: + case VARYING_SLOT_TEX3: + case VARYING_SLOT_TEX4: + case VARYING_SLOT_TEX5: + case VARYING_SLOT_TEX6: + case VARYING_SLOT_TEX7: + if (st->needs_texcoord_semantic) { + input_semantic_name[slot] = TGSI_SEMANTIC_TEXCOORD; + input_semantic_index[slot] = attr - VARYING_SLOT_TEX0; + interpMode[slot] = + st_translate_interp(stfp->Base.InterpQualifier[attr], FALSE); + break; + } + /* fall through */ + case VARYING_SLOT_VAR0: default: - /* Actually, let's try and zero-base this just for - * readability of the generated TGSI. + /* Semantic indices should be zero-based because drivers may choose + * to assign a fixed slot determined by that index. + * This is useful because ARB_separate_shader_objects uses location + * qualifiers for linkage, and if the semantic index corresponds to + * these locations, linkage passes in the driver become unecessary. + * + * If needs_texcoord_semantic is true, no semantic indices will be + * consumed for the TEXi varyings, and we can base the locations of + * the user varyings on VAR0. Otherwise, we use TEX0 as base index. */ - assert(attr >= FRAG_ATTRIB_TEX0); - input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); + assert(attr >= VARYING_SLOT_VAR0 || attr == VARYING_SLOT_PNTC || + (attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7)); input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - if (attr == FRAG_ATTRIB_PNTC) + input_semantic_index[slot] = st_get_generic_varying_index(st, attr); + if (attr == VARYING_SLOT_PNTC) interpMode[slot] = TGSI_INTERPOLATE_LINEAR; else interpMode[slot] = st_translate_interp(stfp->Base.InterpQualifier[attr], @@ -644,12 +719,21 @@ st_translate_fragment_program(struct st_context *st, outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); } + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_SAMPLE_MASK)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_SAMPLEMASK; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_SAMPLE_MASK] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_SAMPLE_MASK); + } + /* handle remaining outputs (color) */ for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { if (outputsWritten & BITFIELD64_BIT(attr)) { switch (attr) { case FRAG_RESULT_DEPTH: case FRAG_RESULT_STENCIL: + case FRAG_RESULT_SAMPLE_MASK: /* handled above */ assert(0); break; @@ -670,11 +754,9 @@ st_translate_fragment_program(struct st_context *st, } } - ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); - if (ureg == NULL) { - FREE(variant); - return NULL; - } + ureg = ureg_create_with_screen(TGSI_PROCESSOR_FRAGMENT, st->pipe->screen); + if (ureg == NULL) + return false; if (ST_DEBUG & DEBUG_MESA) { _mesa_print_program(&stfp->Base.Base); @@ -682,28 +764,32 @@ st_translate_fragment_program(struct st_context *st, debug_printf("\n"); } if (write_all == GL_TRUE) - ureg_property_fs_color0_writes_all_cbufs(ureg, 1); + ureg_property(ureg, TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS, 1); if (stfp->Base.FragDepthLayout != FRAG_DEPTH_LAYOUT_NONE) { switch (stfp->Base.FragDepthLayout) { case FRAG_DEPTH_LAYOUT_ANY: - ureg_property_fs_depth_layout(ureg, TGSI_FS_DEPTH_LAYOUT_ANY); + ureg_property(ureg, TGSI_PROPERTY_FS_DEPTH_LAYOUT, + TGSI_FS_DEPTH_LAYOUT_ANY); break; case FRAG_DEPTH_LAYOUT_GREATER: - ureg_property_fs_depth_layout(ureg, TGSI_FS_DEPTH_LAYOUT_GREATER); + ureg_property(ureg, TGSI_PROPERTY_FS_DEPTH_LAYOUT, + TGSI_FS_DEPTH_LAYOUT_GREATER); break; case FRAG_DEPTH_LAYOUT_LESS: - ureg_property_fs_depth_layout(ureg, TGSI_FS_DEPTH_LAYOUT_LESS); + ureg_property(ureg, TGSI_PROPERTY_FS_DEPTH_LAYOUT, + TGSI_FS_DEPTH_LAYOUT_LESS); break; case FRAG_DEPTH_LAYOUT_UNCHANGED: - ureg_property_fs_depth_layout(ureg, TGSI_FS_DEPTH_LAYOUT_UNCHANGED); + ureg_property(ureg, TGSI_PROPERTY_FS_DEPTH_LAYOUT, + TGSI_FS_DEPTH_LAYOUT_UNCHANGED); break; default: assert(0); } } - if (stfp->glsl_to_tgsi) + if (stfp->glsl_to_tgsi) { st_translate_program(st->ctx, TGSI_PROCESSOR_FRAGMENT, ureg, @@ -712,15 +798,35 @@ st_translate_fragment_program(struct st_context *st, /* inputs */ fs_num_inputs, inputMapping, + inputSlotToAttr, input_semantic_name, input_semantic_index, interpMode, + interpLocation, /* outputs */ fs_num_outputs, outputMapping, + NULL, fs_output_semantic_name, - fs_output_semantic_index, FALSE, - key->clamp_color ); + fs_output_semantic_index); + + free_glsl_to_tgsi_visitor(stfp->glsl_to_tgsi); + stfp->glsl_to_tgsi = NULL; + } else if (stfp->ati_fs) + st_translate_atifs_program(ureg, + stfp->ati_fs, + &stfp->Base.Base, + /* inputs */ + fs_num_inputs, + inputMapping, + input_semantic_name, + input_semantic_index, + interpMode, + /* outputs */ + fs_num_outputs, + outputMapping, + fs_output_semantic_name, + fs_output_semantic_index); else st_translate_mesa_program(st->ctx, TGSI_PROCESSOR_FRAGMENT, @@ -736,31 +842,140 @@ st_translate_fragment_program(struct st_context *st, fs_num_outputs, outputMapping, fs_output_semantic_name, - fs_output_semantic_index, FALSE, - key->clamp_color); + fs_output_semantic_index); - variant->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); + stfp->tgsi.tokens = ureg_get_tokens(ureg, NULL); + ureg_destroy(ureg); + return stfp->tgsi.tokens != NULL; +} - /* fill in variant */ - variant->driver_shader = pipe->create_fs_state(pipe, &variant->tgsi); - variant->key = *key; +static struct st_fp_variant * +st_create_fp_variant(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct pipe_context *pipe = st->pipe; + struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); + struct pipe_shader_state tgsi = {0}; + + if (!variant) + return NULL; + + tgsi.tokens = stfp->tgsi.tokens; + + assert(!(key->bitmap && key->drawpixels)); + + /* Fix texture targets and add fog for ATI_fs */ + if (stfp->ati_fs) { + const struct tgsi_token *tokens = st_fixup_atifs(tgsi.tokens, key); + + if (tokens) + tgsi.tokens = tokens; + else + fprintf(stderr, "mesa: cannot post-process ATI_fs\n"); + } + + /* Emulate features. */ + if (key->clamp_color || key->persample_shading) { + const struct tgsi_token *tokens; + unsigned flags = + (key->clamp_color ? TGSI_EMU_CLAMP_COLOR_OUTPUTS : 0) | + (key->persample_shading ? TGSI_EMU_FORCE_PERSAMPLE_INTERP : 0); + + tokens = tgsi_emulate(tgsi.tokens, flags); + + if (tokens) { + if (tgsi.tokens != stfp->tgsi.tokens) + tgsi_free_tokens(tgsi.tokens); + tgsi.tokens = tokens; + } else + fprintf(stderr, "mesa: cannot emulate deprecated features\n"); + } + + /* glBitmap */ + if (key->bitmap) { + const struct tgsi_token *tokens; + + variant->bitmap_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1; + + tokens = st_get_bitmap_shader(tgsi.tokens, + st->internal_target, + variant->bitmap_sampler, + st->needs_texcoord_semantic, + st->bitmap.tex_format == + PIPE_FORMAT_L8_UNORM); + + if (tokens) { + if (tgsi.tokens != stfp->tgsi.tokens) + tgsi_free_tokens(tgsi.tokens); + tgsi.tokens = tokens; + } else + fprintf(stderr, "mesa: cannot create a shader for glBitmap\n"); + } + + /* glDrawPixels (color only) */ + if (key->drawpixels) { + const struct tgsi_token *tokens; + unsigned scale_const = 0, bias_const = 0, texcoord_const = 0; + struct gl_program_parameter_list *params = stfp->Base.Base.Parameters; + + /* Find the first unused slot. */ + variant->drawpix_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1; + + if (key->pixelMaps) { + unsigned samplers_used = stfp->Base.Base.SamplersUsed | + (1 << variant->drawpix_sampler); + + variant->pixelmap_sampler = ffs(~samplers_used) - 1; + } + + if (key->scaleAndBias) { + static const gl_state_index scale_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_SCALE }; + static const gl_state_index bias_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_BIAS }; + + scale_const = _mesa_add_state_reference(params, scale_state); + bias_const = _mesa_add_state_reference(params, bias_state); + } + + { + static const gl_state_index state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_CURRENT_ATTRIB, VERT_ATTRIB_TEX0 }; + + texcoord_const = _mesa_add_state_reference(params, state); + } + + tokens = st_get_drawpix_shader(tgsi.tokens, + st->needs_texcoord_semantic, + key->scaleAndBias, scale_const, + bias_const, key->pixelMaps, + variant->drawpix_sampler, + variant->pixelmap_sampler, + texcoord_const, st->internal_target); + + if (tokens) { + if (tgsi.tokens != stfp->tgsi.tokens) + tgsi_free_tokens(tgsi.tokens); + tgsi.tokens = tokens; + } else + fprintf(stderr, "mesa: cannot create a shader for glDrawPixels\n"); + } if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump( variant->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); + tgsi_dump(tgsi.tokens, 0); debug_printf("\n"); } - if (deleteFP) { - /* Free the temporary program made above */ - struct gl_fragment_program *fp = &stfp->Base; - _mesa_reference_fragprog(st->ctx, &fp, NULL); - } + /* fill in variant */ + variant->driver_shader = pipe->create_fs_state(pipe, &tgsi); + variant->key = *key; + if (tgsi.tokens != stfp->tgsi.tokens) + tgsi_free_tokens(tgsi.tokens); return variant; } - /** * Translate fragment program if needed. */ @@ -780,7 +995,7 @@ st_get_fp_variant(struct st_context *st, if (!fpv) { /* create new */ - fpv = st_translate_fragment_program(st, stfp, key); + fpv = st_create_fp_variant(st, stfp, key); if (fpv) { /* insert into list */ fpv->next = stfp->variants; @@ -793,345 +1008,510 @@ st_get_fp_variant(struct st_context *st, /** - * Translate a geometry program to create a new variant. + * Translate a program. This is common code for geometry and tessellation + * shaders. */ -static struct st_gp_variant * -st_translate_geometry_program(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) +static void +st_translate_program_common(struct st_context *st, + struct gl_program *prog, + struct glsl_to_tgsi_visitor *glsl_to_tgsi, + struct ureg_program *ureg, + unsigned tgsi_processor, + struct pipe_shader_state *out_state) { - GLuint inputMapping[GEOM_ATTRIB_MAX]; - GLuint outputMapping[GEOM_RESULT_MAX]; - struct pipe_context *pipe = st->pipe; + GLuint inputSlotToAttr[VARYING_SLOT_TESS_MAX]; + GLuint inputMapping[VARYING_SLOT_TESS_MAX]; + GLuint outputSlotToAttr[VARYING_SLOT_TESS_MAX]; + GLuint outputMapping[VARYING_SLOT_TESS_MAX]; GLuint attr; - const GLbitfield64 inputsRead = stgp->Base.Base.InputsRead; - GLuint vslot = 0; - GLuint num_generic = 0; - uint gs_num_inputs = 0; - uint gs_builtin_inputs = 0; - uint gs_array_offset = 0; + ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + uint num_inputs = 0; - ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; - ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; - uint gs_num_outputs = 0; + ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint num_outputs = 0; GLint i; - GLuint maxSlot = 0; - struct ureg_program *ureg; - - struct st_gp_variant *gpv; - - gpv = CALLOC_STRUCT(st_gp_variant); - if (!gpv) - return NULL; - - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); - _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); - - ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); - if (ureg == NULL) { - FREE(gpv); - return NULL; - } - - /* which vertex output goes to the first geometry input */ - vslot = 0; + memset(inputSlotToAttr, 0, sizeof(inputSlotToAttr)); memset(inputMapping, 0, sizeof(inputMapping)); + memset(outputSlotToAttr, 0, sizeof(outputSlotToAttr)); memset(outputMapping, 0, sizeof(outputMapping)); + memset(out_state, 0, sizeof(*out_state)); + + if (prog->ClipDistanceArraySize) + ureg_property(ureg, TGSI_PROPERTY_NUM_CLIPDIST_ENABLED, + prog->ClipDistanceArraySize); /* * Convert Mesa program inputs to TGSI input register semantics. */ - for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { - if ((inputsRead & BITFIELD64_BIT(attr)) != 0) { - const GLuint slot = gs_num_inputs; - - gs_num_inputs++; + for (attr = 0; attr < VARYING_SLOT_MAX; attr++) { + if ((prog->InputsRead & BITFIELD64_BIT(attr)) != 0) { + const GLuint slot = num_inputs++; inputMapping[attr] = slot; - - stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; - stgp->input_to_index[attr] = vslot; - stgp->index_to_input[vslot] = attr; - ++vslot; - - if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { - gs_array_offset += 2; - } else - ++gs_builtin_inputs; - -#if 0 - debug_printf("input map at %d = %d\n", - slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); -#endif + inputSlotToAttr[slot] = attr; switch (attr) { - case GEOM_ATTRIB_PRIMITIVE_ID: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; - stgp->input_semantic_index[slot] = 0; + case VARYING_SLOT_PRIMITIVE_ID: + assert(tgsi_processor == TGSI_PROCESSOR_GEOMETRY); + input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; + input_semantic_index[slot] = 0; break; - case GEOM_ATTRIB_POSITION: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - stgp->input_semantic_index[slot] = 0; + case VARYING_SLOT_POS: + input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + input_semantic_index[slot] = 0; break; - case GEOM_ATTRIB_COLOR0: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 0; + case VARYING_SLOT_COL0: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 0; break; - case GEOM_ATTRIB_COLOR1: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - stgp->input_semantic_index[slot] = 1; + case VARYING_SLOT_COL1: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 1; break; - case GEOM_ATTRIB_FOG_FRAG_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - stgp->input_semantic_index[slot] = 0; + case VARYING_SLOT_FOGC: + input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + input_semantic_index[slot] = 0; break; - case GEOM_ATTRIB_TEX_COORD: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; + case VARYING_SLOT_CLIP_VERTEX: + input_semantic_name[slot] = TGSI_SEMANTIC_CLIPVERTEX; + input_semantic_index[slot] = 0; break; - case GEOM_ATTRIB_VAR0: - /* fall-through */ + case VARYING_SLOT_CLIP_DIST0: + input_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; + input_semantic_index[slot] = 0; + break; + case VARYING_SLOT_CLIP_DIST1: + input_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; + input_semantic_index[slot] = 1; + break; + case VARYING_SLOT_PSIZ: + input_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + input_semantic_index[slot] = 0; + break; + case VARYING_SLOT_TEX0: + case VARYING_SLOT_TEX1: + case VARYING_SLOT_TEX2: + case VARYING_SLOT_TEX3: + case VARYING_SLOT_TEX4: + case VARYING_SLOT_TEX5: + case VARYING_SLOT_TEX6: + case VARYING_SLOT_TEX7: + if (st->needs_texcoord_semantic) { + input_semantic_name[slot] = TGSI_SEMANTIC_TEXCOORD; + input_semantic_index[slot] = attr - VARYING_SLOT_TEX0; + break; + } + /* fall through */ + case VARYING_SLOT_VAR0: default: - stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - stgp->input_semantic_index[slot] = num_generic++; + assert(attr >= VARYING_SLOT_VAR0 || + (attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7)); + input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + input_semantic_index[slot] = + st_get_generic_varying_index(st, attr); + break; } } } + /* Also add patch inputs. */ + for (attr = 0; attr < 32; attr++) { + if (prog->PatchInputsRead & (1 << attr)) { + GLuint slot = num_inputs++; + GLuint patch_attr = VARYING_SLOT_PATCH0 + attr; + + inputMapping[patch_attr] = slot; + inputSlotToAttr[slot] = patch_attr; + input_semantic_name[slot] = TGSI_SEMANTIC_PATCH; + input_semantic_index[slot] = attr; + } + } + /* initialize output semantics to defaults */ for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { - gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[i] = 0; + output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; + output_semantic_index[i] = 0; } - num_generic = 0; /* * Determine number of outputs, the (default) output register * mapping and the semantic information for each output. */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (stgp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) { - GLuint slot; + for (attr = 0; attr < VARYING_SLOT_MAX; attr++) { + if (prog->OutputsWritten & BITFIELD64_BIT(attr)) { + GLuint slot = num_outputs++; - slot = gs_num_outputs; - gs_num_outputs++; outputMapping[attr] = slot; + outputSlotToAttr[slot] = attr; switch (attr) { - case GEOM_RESULT_POS: + case VARYING_SLOT_POS: assert(slot == 0); - gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - gs_output_semantic_index[slot] = 0; + output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_COL0: + output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_COL1: + output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + output_semantic_index[slot] = 1; + break; + case VARYING_SLOT_BFC0: + output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_BFC1: + output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + output_semantic_index[slot] = 1; + break; + case VARYING_SLOT_FOGC: + output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_PSIZ: + output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_CLIP_VERTEX: + output_semantic_name[slot] = TGSI_SEMANTIC_CLIPVERTEX; + output_semantic_index[slot] = 0; + break; + case VARYING_SLOT_CLIP_DIST0: + output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; + output_semantic_index[slot] = 0; break; - case GEOM_RESULT_COL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 0; + case VARYING_SLOT_CLIP_DIST1: + output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; + output_semantic_index[slot] = 1; break; - case GEOM_RESULT_COL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - gs_output_semantic_index[slot] = 1; + case VARYING_SLOT_LAYER: + output_semantic_name[slot] = TGSI_SEMANTIC_LAYER; + output_semantic_index[slot] = 0; break; - case GEOM_RESULT_SCOL0: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 0; + case VARYING_SLOT_PRIMITIVE_ID: + output_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; + output_semantic_index[slot] = 0; break; - case GEOM_RESULT_SCOL1: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; - gs_output_semantic_index[slot] = 1; + case VARYING_SLOT_VIEWPORT: + output_semantic_name[slot] = TGSI_SEMANTIC_VIEWPORT_INDEX; + output_semantic_index[slot] = 0; break; - case GEOM_RESULT_FOGC: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; - gs_output_semantic_index[slot] = 0; + case VARYING_SLOT_TESS_LEVEL_OUTER: + output_semantic_name[slot] = TGSI_SEMANTIC_TESSOUTER; + output_semantic_index[slot] = 0; break; - case GEOM_RESULT_PSIZ: - gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; - gs_output_semantic_index[slot] = 0; + case VARYING_SLOT_TESS_LEVEL_INNER: + output_semantic_name[slot] = TGSI_SEMANTIC_TESSINNER; + output_semantic_index[slot] = 0; break; - case GEOM_RESULT_TEX0: - case GEOM_RESULT_TEX1: - case GEOM_RESULT_TEX2: - case GEOM_RESULT_TEX3: - case GEOM_RESULT_TEX4: - case GEOM_RESULT_TEX5: - case GEOM_RESULT_TEX6: - case GEOM_RESULT_TEX7: - /* fall-through */ - case GEOM_RESULT_VAR0: - /* fall-through */ + case VARYING_SLOT_TEX0: + case VARYING_SLOT_TEX1: + case VARYING_SLOT_TEX2: + case VARYING_SLOT_TEX3: + case VARYING_SLOT_TEX4: + case VARYING_SLOT_TEX5: + case VARYING_SLOT_TEX6: + case VARYING_SLOT_TEX7: + if (st->needs_texcoord_semantic) { + output_semantic_name[slot] = TGSI_SEMANTIC_TEXCOORD; + output_semantic_index[slot] = attr - VARYING_SLOT_TEX0; + break; + } + /* fall through */ + case VARYING_SLOT_VAR0: default: - assert(slot < Elements(gs_output_semantic_name)); - /* use default semantic info */ - gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - gs_output_semantic_index[slot] = num_generic++; + assert(slot < ARRAY_SIZE(output_semantic_name)); + assert(attr >= VARYING_SLOT_VAR0 || + (attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7)); + output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + output_semantic_index[slot] = + st_get_generic_varying_index(st, attr); + break; } } } - assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); + /* Also add patch outputs. */ + for (attr = 0; attr < 32; attr++) { + if (prog->PatchOutputsWritten & (1 << attr)) { + GLuint slot = num_outputs++; + GLuint patch_attr = VARYING_SLOT_PATCH0 + attr; - /* find max output slot referenced to compute gs_num_outputs */ - for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { - if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) - maxSlot = outputMapping[attr]; - } - gs_num_outputs = maxSlot + 1; - -#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]); - } - } - printf("slot sem_name sem_index\n"); - for (i = 0; i < gs_num_outputs; i++) { - printf(" %2d %d %d\n", - i, - gs_output_semantic_name[i], - gs_output_semantic_index[i]); + outputMapping[patch_attr] = slot; + outputSlotToAttr[slot] = patch_attr; + output_semantic_name[slot] = TGSI_SEMANTIC_PATCH; + output_semantic_index[slot] = attr; } } -#endif - - /* free old shader state, if any */ - if (stgp->tgsi.tokens) { - st_free_tokens(stgp->tgsi.tokens); - stgp->tgsi.tokens = NULL; - } - - ureg_property_gs_input_prim(ureg, stgp->Base.InputType); - ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); - ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); - - st_translate_mesa_program(st->ctx, - TGSI_PROCESSOR_GEOMETRY, - ureg, - &stgp->Base.Base, - /* inputs */ - gs_num_inputs, - inputMapping, - stgp->input_semantic_name, - stgp->input_semantic_index, - NULL, - /* outputs */ - gs_num_outputs, - outputMapping, - gs_output_semantic_name, - gs_output_semantic_index, - FALSE, - FALSE); - - stgp->num_inputs = gs_num_inputs; - stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); - ureg_destroy( ureg ); - - if (stgp->glsl_to_tgsi) { - st_translate_stream_output_info(stgp->glsl_to_tgsi, - outputMapping, - &stgp->tgsi.stream_output); - } - /* fill in new variant */ - gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); - gpv->key = *key; + st_translate_program(st->ctx, + tgsi_processor, + ureg, + glsl_to_tgsi, + prog, + /* inputs */ + num_inputs, + inputMapping, + inputSlotToAttr, + input_semantic_name, + input_semantic_index, + NULL, + NULL, + /* outputs */ + num_outputs, + outputMapping, + outputSlotToAttr, + output_semantic_name, + output_semantic_index); + + out_state->tokens = ureg_get_tokens(ureg, NULL); + ureg_destroy(ureg); + + st_translate_stream_output_info(glsl_to_tgsi, + outputMapping, + &out_state->stream_output); if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { - _mesa_print_program(&stgp->Base.Base); + _mesa_print_program(prog); debug_printf("\n"); } if (ST_DEBUG & DEBUG_TGSI) { - tgsi_dump(stgp->tgsi.tokens, 0); + tgsi_dump(out_state->tokens, 0); debug_printf("\n"); } +} + + +/** + * Translate a geometry program to create a new variant. + */ +bool +st_translate_geometry_program(struct st_context *st, + struct st_geometry_program *stgp) +{ + struct ureg_program *ureg; + + ureg = ureg_create_with_screen(TGSI_PROCESSOR_GEOMETRY, st->pipe->screen); + if (ureg == NULL) + return false; - return gpv; + ureg_property(ureg, TGSI_PROPERTY_GS_INPUT_PRIM, stgp->Base.InputType); + ureg_property(ureg, TGSI_PROPERTY_GS_OUTPUT_PRIM, stgp->Base.OutputType); + ureg_property(ureg, TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, + stgp->Base.VerticesOut); + ureg_property(ureg, TGSI_PROPERTY_GS_INVOCATIONS, stgp->Base.Invocations); + + st_translate_program_common(st, &stgp->Base.Base, stgp->glsl_to_tgsi, ureg, + TGSI_PROCESSOR_GEOMETRY, &stgp->tgsi); + + free_glsl_to_tgsi_visitor(stgp->glsl_to_tgsi); + stgp->glsl_to_tgsi = NULL; + return true; } /** - * Get/create geometry program variant. + * Get/create a basic program variant. */ -struct st_gp_variant * -st_get_gp_variant(struct st_context *st, - struct st_geometry_program *stgp, - const struct st_gp_variant_key *key) +struct st_basic_variant * +st_get_basic_variant(struct st_context *st, + unsigned pipe_shader, + struct pipe_shader_state *tgsi, + struct st_basic_variant **variants) { - struct st_gp_variant *gpv; + struct pipe_context *pipe = st->pipe; + struct st_basic_variant *v; + struct st_basic_variant_key key; + + memset(&key, 0, sizeof(key)); + key.st = st->has_shareable_shaders ? NULL : st; /* Search for existing variant */ - for (gpv = stgp->variants; gpv; gpv = gpv->next) { - if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { + for (v = *variants; v; v = v->next) { + if (memcmp(&v->key, &key, sizeof(key)) == 0) { break; } } - if (!gpv) { + if (!v) { /* create new */ - gpv = st_translate_geometry_program(st, stgp, key); - if (gpv) { + v = CALLOC_STRUCT(st_basic_variant); + if (v) { + /* fill in new variant */ + switch (pipe_shader) { + case PIPE_SHADER_TESS_CTRL: + v->driver_shader = pipe->create_tcs_state(pipe, tgsi); + break; + case PIPE_SHADER_TESS_EVAL: + v->driver_shader = pipe->create_tes_state(pipe, tgsi); + break; + case PIPE_SHADER_GEOMETRY: + v->driver_shader = pipe->create_gs_state(pipe, tgsi); + break; + default: + assert(!"unhandled shader type"); + free(v); + return NULL; + } + + v->key = key; + /* insert into list */ - gpv->next = stgp->variants; - stgp->variants = gpv; + v->next = *variants; + *variants = v; } } - return gpv; + return v; } +/** + * Translate a tessellation control program to create a new variant. + */ +bool +st_translate_tessctrl_program(struct st_context *st, + struct st_tessctrl_program *sttcp) +{ + struct ureg_program *ureg; + + ureg = ureg_create_with_screen(TGSI_PROCESSOR_TESS_CTRL, st->pipe->screen); + if (ureg == NULL) + return false; + + ureg_property(ureg, TGSI_PROPERTY_TCS_VERTICES_OUT, + sttcp->Base.VerticesOut); + + st_translate_program_common(st, &sttcp->Base.Base, sttcp->glsl_to_tgsi, + ureg, TGSI_PROCESSOR_TESS_CTRL, &sttcp->tgsi); + + free_glsl_to_tgsi_visitor(sttcp->glsl_to_tgsi); + sttcp->glsl_to_tgsi = NULL; + return true; +} /** - * Debug- print current shader text + * Translate a tessellation evaluation program to create a new variant. */ -void -st_print_shaders(struct gl_context *ctx) +bool +st_translate_tesseval_program(struct st_context *st, + struct st_tesseval_program *sttep) { - struct gl_shader_program *shProg[3] = { - ctx->Shader.CurrentVertexProgram, - ctx->Shader.CurrentGeometryProgram, - ctx->Shader.CurrentFragmentProgram, - }; - unsigned j; - - for (j = 0; j < 3; j++) { - unsigned i; - - if (shProg[j] == NULL) - continue; - - for (i = 0; i < shProg[j]->NumShaders; i++) { - struct gl_shader *sh; - - switch (shProg[j]->Shaders[i]->Type) { - case GL_VERTEX_SHADER: - sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_GEOMETRY_SHADER_ARB: - sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; - break; - case GL_FRAGMENT_SHADER: - sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; - break; - default: - assert(0); - sh = NULL; - break; - } + struct ureg_program *ureg; - if (sh != NULL) { - printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); - printf("%s\n", sh->Source); - } + ureg = ureg_create_with_screen(TGSI_PROCESSOR_TESS_EVAL, st->pipe->screen); + if (ureg == NULL) + return false; + + if (sttep->Base.PrimitiveMode == GL_ISOLINES) + ureg_property(ureg, TGSI_PROPERTY_TES_PRIM_MODE, GL_LINES); + else + ureg_property(ureg, TGSI_PROPERTY_TES_PRIM_MODE, sttep->Base.PrimitiveMode); + + switch (sttep->Base.Spacing) { + case GL_EQUAL: + ureg_property(ureg, TGSI_PROPERTY_TES_SPACING, PIPE_TESS_SPACING_EQUAL); + break; + case GL_FRACTIONAL_EVEN: + ureg_property(ureg, TGSI_PROPERTY_TES_SPACING, + PIPE_TESS_SPACING_FRACTIONAL_EVEN); + break; + case GL_FRACTIONAL_ODD: + ureg_property(ureg, TGSI_PROPERTY_TES_SPACING, + PIPE_TESS_SPACING_FRACTIONAL_ODD); + break; + default: + assert(0); + } + + ureg_property(ureg, TGSI_PROPERTY_TES_VERTEX_ORDER_CW, + sttep->Base.VertexOrder == GL_CW); + ureg_property(ureg, TGSI_PROPERTY_TES_POINT_MODE, sttep->Base.PointMode); + + st_translate_program_common(st, &sttep->Base.Base, sttep->glsl_to_tgsi, + ureg, TGSI_PROCESSOR_TESS_EVAL, &sttep->tgsi); + + free_glsl_to_tgsi_visitor(sttep->glsl_to_tgsi); + sttep->glsl_to_tgsi = NULL; + return true; +} + + +/** + * Translate a compute program to create a new variant. + */ +bool +st_translate_compute_program(struct st_context *st, + struct st_compute_program *stcp) +{ + struct ureg_program *ureg; + struct pipe_shader_state prog; + + ureg = ureg_create_with_screen(TGSI_PROCESSOR_COMPUTE, st->pipe->screen); + if (ureg == NULL) + return false; + + st_translate_program_common(st, &stcp->Base.Base, stcp->glsl_to_tgsi, ureg, + TGSI_PROCESSOR_COMPUTE, &prog); + + stcp->tgsi.ir_type = PIPE_SHADER_IR_TGSI; + stcp->tgsi.prog = prog.tokens; + stcp->tgsi.req_local_mem = stcp->Base.SharedSize; + stcp->tgsi.req_private_mem = 0; + stcp->tgsi.req_input_mem = 0; + + free_glsl_to_tgsi_visitor(stcp->glsl_to_tgsi); + stcp->glsl_to_tgsi = NULL; + return true; +} + + +/** + * Get/create compute program variant. + */ +struct st_basic_variant * +st_get_cp_variant(struct st_context *st, + struct pipe_compute_state *tgsi, + struct st_basic_variant **variants) +{ + struct pipe_context *pipe = st->pipe; + struct st_basic_variant *v; + struct st_basic_variant_key key; + + memset(&key, 0, sizeof(key)); + key.st = st->has_shareable_shaders ? NULL : st; + + /* Search for existing variant */ + for (v = *variants; v; v = v->next) { + if (memcmp(&v->key, &key, sizeof(key)) == 0) { + break; } } + + if (!v) { + /* create new */ + v = CALLOC_STRUCT(st_basic_variant); + if (v) { + /* fill in new variant */ + v->driver_shader = pipe->create_compute_state(pipe, tgsi); + v->key = key; + + /* insert into list */ + v->next = *variants; + *variants = v; + } + } + + return v; } @@ -1140,15 +1520,15 @@ st_print_shaders(struct gl_context *ctx) * variants attached to the given program which match the given context. */ static void -destroy_program_variants(struct st_context *st, struct gl_program *program) +destroy_program_variants(struct st_context *st, struct gl_program *target) { - if (!program) + if (!target || target == &_mesa_DummyProgram) return; - switch (program->Target) { + switch (target->Target) { case GL_VERTEX_PROGRAM_ARB: { - struct st_vertex_program *stvp = (struct st_vertex_program *) program; + struct st_vertex_program *stvp = (struct st_vertex_program *) target; struct st_vp_variant *vpv, **prevPtr = &stvp->variants; for (vpv = stvp->variants; vpv; ) { @@ -1169,7 +1549,7 @@ destroy_program_variants(struct st_context *st, struct gl_program *program) case GL_FRAGMENT_PROGRAM_ARB: { struct st_fragment_program *stfp = - (struct st_fragment_program *) program; + (struct st_fragment_program *) target; struct st_fp_variant *fpv, **prevPtr = &stfp->variants; for (fpv = stfp->variants; fpv; ) { @@ -1187,30 +1567,41 @@ destroy_program_variants(struct st_context *st, struct gl_program *program) } } break; - case MESA_GEOMETRY_PROGRAM: + case GL_GEOMETRY_PROGRAM_NV: + case GL_TESS_CONTROL_PROGRAM_NV: + case GL_TESS_EVALUATION_PROGRAM_NV: + case GL_COMPUTE_PROGRAM_NV: { - struct st_geometry_program *stgp = - (struct st_geometry_program *) program; - struct st_gp_variant *gpv, **prevPtr = &stgp->variants; - - for (gpv = stgp->variants; gpv; ) { - struct st_gp_variant *next = gpv->next; - if (gpv->key.st == st) { + struct st_geometry_program *gp = (struct st_geometry_program*)target; + struct st_tessctrl_program *tcp = (struct st_tessctrl_program*)target; + struct st_tesseval_program *tep = (struct st_tesseval_program*)target; + struct st_compute_program *cp = (struct st_compute_program*)target; + struct st_basic_variant **variants = + target->Target == GL_GEOMETRY_PROGRAM_NV ? &gp->variants : + target->Target == GL_TESS_CONTROL_PROGRAM_NV ? &tcp->variants : + target->Target == GL_TESS_EVALUATION_PROGRAM_NV ? &tep->variants : + target->Target == GL_COMPUTE_PROGRAM_NV ? &cp->variants : + NULL; + struct st_basic_variant *v, **prevPtr = variants; + + for (v = *variants; v; ) { + struct st_basic_variant *next = v->next; + if (v->key.st == st) { /* unlink from list */ *prevPtr = next; /* destroy this variant */ - delete_gp_variant(st, gpv); + delete_basic_variant(st, v, target->Target); } else { - prevPtr = &gpv->next; + prevPtr = &v->next; } - gpv = next; + v = next; } } break; default: _mesa_problem(NULL, "Unexpected program target 0x%x in " - "destroy_program_variants_cb()", program->Target); + "destroy_program_variants_cb()", target->Target); } } @@ -1235,7 +1626,7 @@ destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) destroy_program_variants(st, shProg->Shaders[i]->Program); } - for (i = 0; i < Elements(shProg->_LinkedShaders); i++) { + for (i = 0; i < ARRAY_SIZE(shProg->_LinkedShaders); i++) { if (shProg->_LinkedShaders[i]) destroy_program_variants(st, shProg->_LinkedShaders[i]->Program); } @@ -1244,6 +1635,9 @@ destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) case GL_VERTEX_SHADER: case GL_FRAGMENT_SHADER: case GL_GEOMETRY_SHADER: + case GL_TESS_CONTROL_SHADER: + case GL_TESS_EVALUATION_SHADER: + case GL_COMPUTE_SHADER: { destroy_program_variants(st, shader->Program); } @@ -1275,6 +1669,12 @@ destroy_program_variants_cb(GLuint key, void *data, void *userData) void st_destroy_program_variants(struct st_context *st) { + /* If shaders can be shared with other contexts, the last context will + * call DeleteProgram on all shaders, releasing everything. + */ + if (st->has_shareable_shaders) + return; + /* ARB vert/frag program */ _mesa_HashWalk(st->ctx->Shared->Programs, destroy_program_variants_cb, st); @@ -1283,3 +1683,84 @@ st_destroy_program_variants(struct st_context *st) _mesa_HashWalk(st->ctx->Shared->ShaderObjects, destroy_shader_program_variants_cb, st); } + + +/** + * For debugging, print/dump the current vertex program. + */ +void +st_print_current_vertex_program(void) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx->VertexProgram._Current) { + struct st_vertex_program *stvp = + (struct st_vertex_program *) ctx->VertexProgram._Current; + struct st_vp_variant *stv; + + debug_printf("Vertex program %u\n", stvp->Base.Base.Id); + + for (stv = stvp->variants; stv; stv = stv->next) { + debug_printf("variant %p\n", stv); + tgsi_dump(stv->tgsi.tokens, 0); + } + } +} + + +/** + * Compile one shader variant. + */ +void +st_precompile_shader_variant(struct st_context *st, + struct gl_program *prog) +{ + switch (prog->Target) { + case GL_VERTEX_PROGRAM_ARB: { + struct st_vertex_program *p = (struct st_vertex_program *)prog; + struct st_vp_variant_key key; + + memset(&key, 0, sizeof(key)); + key.st = st->has_shareable_shaders ? NULL : st; + st_get_vp_variant(st, p, &key); + break; + } + + case GL_TESS_CONTROL_PROGRAM_NV: { + struct st_tessctrl_program *p = (struct st_tessctrl_program *)prog; + st_get_basic_variant(st, PIPE_SHADER_TESS_CTRL, &p->tgsi, &p->variants); + break; + } + + case GL_TESS_EVALUATION_PROGRAM_NV: { + struct st_tesseval_program *p = (struct st_tesseval_program *)prog; + st_get_basic_variant(st, PIPE_SHADER_TESS_EVAL, &p->tgsi, &p->variants); + break; + } + + case GL_GEOMETRY_PROGRAM_NV: { + struct st_geometry_program *p = (struct st_geometry_program *)prog; + st_get_basic_variant(st, PIPE_SHADER_GEOMETRY, &p->tgsi, &p->variants); + break; + } + + case GL_FRAGMENT_PROGRAM_ARB: { + struct st_fragment_program *p = (struct st_fragment_program *)prog; + struct st_fp_variant_key key; + + memset(&key, 0, sizeof(key)); + key.st = st->has_shareable_shaders ? NULL : st; + st_get_fp_variant(st, p, &key); + break; + } + + case GL_COMPUTE_PROGRAM_NV: { + struct st_compute_program *p = (struct st_compute_program *)prog; + st_get_cp_variant(st, &p->tgsi, &p->variants); + break; + } + + default: + assert(0); + } +}