Пример #1
0
/**
 * 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;
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/**
 * 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;
}
Пример #4
0
/**
 * 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;
}