/** * Find/create a vertex program variant. */ struct st_vp_variant * st_get_vp_variant(struct st_context *st, struct st_vertex_program *stvp, const struct st_vp_variant_key *key) { struct st_vp_variant *vpv; /* Search for existing variant */ for (vpv = stvp->variants; vpv; vpv = vpv->next) { if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { break; } } if (!vpv) { /* create now */ vpv = st_translate_vertex_program(st, stvp, key); if (vpv) { /* insert into list */ vpv->next = stvp->variants; stvp->variants = vpv; } } return vpv; }
/** * Called via ctx->Driver.ProgramStringNotify() * Called when the program's text/code is changed. We have to free * all shader variants and corresponding gallium shaders when this happens. */ static GLboolean st_program_string_notify( struct gl_context *ctx, GLenum target, struct gl_program *prog ) { struct st_context *st = st_context(ctx); gl_shader_stage stage = _mesa_program_enum_to_shader_stage(target); if (target == GL_FRAGMENT_PROGRAM_ARB) { struct st_fragment_program *stfp = (struct st_fragment_program *) prog; st_release_fp_variants(st, stfp); if (!st_translate_fragment_program(st, stfp)) return false; if (st->fp == stfp) st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; } else if (target == GL_GEOMETRY_PROGRAM_NV) { struct st_geometry_program *stgp = (struct st_geometry_program *) prog; st_release_basic_variants(st, stgp->Base.Base.Target, &stgp->variants, &stgp->tgsi); if (!st_translate_geometry_program(st, stgp)) return false; if (st->gp == stgp) st->dirty.st |= ST_NEW_GEOMETRY_PROGRAM; } else if (target == GL_VERTEX_PROGRAM_ARB) { struct st_vertex_program *stvp = (struct st_vertex_program *) prog; st_release_vp_variants(st, stvp); if (!st_translate_vertex_program(st, stvp)) return false; if (st->vp == stvp) st->dirty.st |= ST_NEW_VERTEX_PROGRAM; } else if (target == GL_TESS_CONTROL_PROGRAM_NV) { struct st_tessctrl_program *sttcp = (struct st_tessctrl_program *) prog; st_release_basic_variants(st, sttcp->Base.Base.Target, &sttcp->variants, &sttcp->tgsi); if (!st_translate_tessctrl_program(st, sttcp)) return false; if (st->tcp == sttcp) st->dirty.st |= ST_NEW_TESSCTRL_PROGRAM; } else if (target == GL_TESS_EVALUATION_PROGRAM_NV) { struct st_tesseval_program *sttep = (struct st_tesseval_program *) prog; st_release_basic_variants(st, sttep->Base.Base.Target, &sttep->variants, &sttep->tgsi); if (!st_translate_tesseval_program(st, sttep)) return false; if (st->tep == sttep) st->dirty.st |= ST_NEW_TESSEVAL_PROGRAM; } else if (target == GL_COMPUTE_PROGRAM_NV) { struct st_compute_program *stcp = (struct st_compute_program *) prog; st_release_cp_variants(st, stcp); if (!st_translate_compute_program(st, stcp)) return false; if (st->cp == stcp) st->dirty_cp.st |= ST_NEW_COMPUTE_PROGRAM; } else if (target == GL_FRAGMENT_SHADER_ATI) { assert(prog); struct st_fragment_program *stfp = (struct st_fragment_program *) prog; assert(stfp->ati_fs); assert(stfp->ati_fs->Program == prog); st_init_atifs_prog(ctx, prog); st_release_fp_variants(st, stfp); if (!st_translate_fragment_program(st, stfp)) return false; if (st->fp == stfp) st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; } if (ST_DEBUG & DEBUG_PRECOMPILE || st->shader_has_one_variant[stage]) st_precompile_shader_variant(st, prog); return GL_TRUE; }
/** * Find a translated vertex program that corresponds to stvp and * has outputs matched to stfp's inputs. * This performs vertex and fragment translation (to TGSI) when needed. */ static struct translated_vertex_program * find_translated_vp(struct st_context *st, struct st_vertex_program *stvp, struct st_fragment_program *stfp) { static const GLuint UNUSED = ~0; struct translated_vertex_program *xvp; const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead; /* * Translate fragment program if needed. */ if (!stfp->state.tokens) { GLuint inAttr, numIn = 0; 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; } } stfp->num_input_slots = numIn; assert(stfp->Base.Base.NumInstructions > 1); st_translate_fragment_program(st, stfp, stfp->input_to_slot); } /* 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; } /* 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; } return xvp; }
/** * Create a simple vertex shader that just passes through the * vertex position and texcoord (and optionally, color). */ static struct st_vertex_program * st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor) { GLcontext *ctx = st->ctx; struct st_vertex_program *stvp; struct gl_program *p; GLuint ic = 0; if (st->drawpix.vert_shaders[passColor]) return st->drawpix.vert_shaders[passColor]; /* * Create shader now */ p = ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); if (!p) return NULL; if (passColor) p->NumInstructions = 4; else p->NumInstructions = 3; p->Instructions = _mesa_alloc_instructions(p->NumInstructions); if (!p->Instructions) { ctx->Driver.DeleteProgram(ctx, p); return NULL; } _mesa_init_instructions(p->Instructions, p->NumInstructions); /* MOV result.pos, vertex.pos; */ p->Instructions[0].Opcode = OPCODE_MOV; p->Instructions[0].DstReg.File = PROGRAM_OUTPUT; p->Instructions[0].DstReg.Index = VERT_RESULT_HPOS; p->Instructions[0].SrcReg[0].File = PROGRAM_INPUT; p->Instructions[0].SrcReg[0].Index = VERT_ATTRIB_POS; /* MOV result.texcoord0, vertex.texcoord0; */ p->Instructions[1].Opcode = OPCODE_MOV; p->Instructions[1].DstReg.File = PROGRAM_OUTPUT; p->Instructions[1].DstReg.Index = VERT_RESULT_TEX0; p->Instructions[1].SrcReg[0].File = PROGRAM_INPUT; p->Instructions[1].SrcReg[0].Index = VERT_ATTRIB_TEX0; ic = 2; if (passColor) { /* MOV result.color0, vertex.color0; */ p->Instructions[ic].Opcode = OPCODE_MOV; p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; p->Instructions[ic].DstReg.Index = VERT_RESULT_COL0; p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; p->Instructions[ic].SrcReg[0].Index = VERT_ATTRIB_COLOR0; ic++; } /* END; */ p->Instructions[ic].Opcode = OPCODE_END; ic++; assert(ic == p->NumInstructions); p->InputsRead = VERT_BIT_POS | VERT_BIT_TEX0; p->OutputsWritten = ((1 << VERT_RESULT_TEX0) | (1 << VERT_RESULT_HPOS)); if (passColor) { p->InputsRead |= VERT_BIT_COLOR0; p->OutputsWritten |= (1 << VERT_RESULT_COL0); } stvp = (struct st_vertex_program *) p; st_translate_vertex_program(st, stvp, NULL, NULL, NULL); st->drawpix.vert_shaders[passColor] = stvp; return stvp; }