+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(tgsi.tokens, 0);
+ debug_printf("\n");
+ }
+
+ /* 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.
+ */
+struct st_fp_variant *
+st_get_fp_variant(struct st_context *st,
+ struct st_fragment_program *stfp,
+ const struct st_fp_variant_key *key)
+{
+ struct st_fp_variant *fpv;
+
+ /* Search for existing variant */
+ for (fpv = stfp->variants; fpv; fpv = fpv->next) {
+ if (memcmp(&fpv->key, key, sizeof(*key)) == 0) {
+ break;
+ }
+ }
+
+ if (!fpv) {
+ /* create new */
+ fpv = st_create_fp_variant(st, stfp, key);
+ if (fpv) {
+ /* insert into list */
+ fpv->next = stfp->variants;
+ stfp->variants = fpv;
+ }
+ }
+
+ return fpv;
+}
+
+
+/**
+ * Translate a program. This is common code for geometry and tessellation
+ * shaders.
+ */
+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 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;
+
+ ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS];
+ ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
+ uint num_inputs = 0;
+
+ ubyte output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
+ ubyte output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
+ uint num_outputs = 0;
+
+ GLint i;
+
+ 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 < VARYING_SLOT_MAX; attr++) {
+ if ((prog->InputsRead & BITFIELD64_BIT(attr)) != 0) {
+ const GLuint slot = num_inputs++;
+
+ inputMapping[attr] = slot;
+ inputSlotToAttr[slot] = attr;
+
+ switch (attr) {
+ 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 VARYING_SLOT_POS:
+ input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
+ input_semantic_index[slot] = 0;
+ break;
+ case VARYING_SLOT_COL0:
+ input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ input_semantic_index[slot] = 0;
+ break;
+ case VARYING_SLOT_COL1:
+ input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
+ input_semantic_index[slot] = 1;
+ break;
+ case VARYING_SLOT_FOGC:
+ input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
+ input_semantic_index[slot] = 0;
+ break;
+ case VARYING_SLOT_CLIP_VERTEX:
+ input_semantic_name[slot] = TGSI_SEMANTIC_CLIPVERTEX;
+ input_semantic_index[slot] = 0;
+ break;
+ 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:
+ 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++) {
+ output_semantic_name[i] = TGSI_SEMANTIC_GENERIC;
+ output_semantic_index[i] = 0;
+ }
+
+ /*
+ * Determine number of outputs, the (default) output register
+ * mapping and the semantic information for each output.
+ */
+ for (attr = 0; attr < VARYING_SLOT_MAX; attr++) {
+ if (prog->OutputsWritten & BITFIELD64_BIT(attr)) {
+ GLuint slot = num_outputs++;
+
+ outputMapping[attr] = slot;
+ outputSlotToAttr[slot] = attr;
+
+ switch (attr) {
+ case VARYING_SLOT_POS:
+ assert(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 VARYING_SLOT_CLIP_DIST1:
+ output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST;
+ output_semantic_index[slot] = 1;
+ break;
+ case VARYING_SLOT_LAYER:
+ output_semantic_name[slot] = TGSI_SEMANTIC_LAYER;
+ output_semantic_index[slot] = 0;
+ break;
+ case VARYING_SLOT_PRIMITIVE_ID:
+ output_semantic_name[slot] = TGSI_SEMANTIC_PRIMID;
+ 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 VARYING_SLOT_TESS_LEVEL_OUTER:
+ output_semantic_name[slot] = TGSI_SEMANTIC_TESSOUTER;
+ output_semantic_index[slot] = 0;
+ break;
+ case VARYING_SLOT_TESS_LEVEL_INNER:
+ output_semantic_name[slot] = TGSI_SEMANTIC_TESSINNER;
+ output_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) {
+ 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 < 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;
+ }
+ }
+ }
+
+ /* 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;
+
+ outputMapping[patch_attr] = slot;
+ outputSlotToAttr[slot] = patch_attr;
+ output_semantic_name[slot] = TGSI_SEMANTIC_PATCH;
+ output_semantic_index[slot] = attr;
+ }
+ }
+
+ 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(prog);
+ debug_printf("\n");
+ }
+
+ if (ST_DEBUG & DEBUG_TGSI) {
+ 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;
+
+ 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 a basic program variant.
+ */
+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 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 */
+ 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 */
+ v->next = *variants;
+ *variants = v;
+ }
+ }
+
+ 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);