Ejemplo n.º 1
0
/**
 * Delete a program, ignoring the reference count.
 * Don't remove it from the hash table, the caller should do that.
 */
void
_mesa_delete_program(GLcontext *ctx, struct program *prog)
{
   ASSERT(prog);

   if (prog->String)
      _mesa_free(prog->String);
   if (prog->Target == GL_VERTEX_PROGRAM_NV ||
       prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
      struct vertex_program *vprog = (struct vertex_program *) prog;
      if (vprog->Instructions)
         _mesa_free(vprog->Instructions);
      if (vprog->Parameters)
         _mesa_free_parameter_list(vprog->Parameters);
   }
   else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
            prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
      struct fragment_program *fprog = (struct fragment_program *) prog;
      if (fprog->Instructions)
         _mesa_free(fprog->Instructions);
      if (fprog->Parameters)
         _mesa_free_parameter_list(fprog->Parameters);
   }
   _mesa_free(prog);
}
Ejemplo n.º 2
0
/**
 * Delete a program and remove it from the hash table, ignoring the
 * reference count.
 * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
 * by a device driver function.
 */
void
_mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
{
   (void) ctx;
   ASSERT(prog);
   ASSERT(prog->RefCount==0);

   if (prog == &_mesa_DummyProgram)
      return;

   if (prog->String)
      _mesa_free(prog->String);

   _mesa_free_instructions(prog->Instructions, prog->NumInstructions);

   if (prog->Parameters) {
      _mesa_free_parameter_list(prog->Parameters);
   }
   if (prog->Varying) {
      _mesa_free_parameter_list(prog->Varying);
   }
   if (prog->Attributes) {
      _mesa_free_parameter_list(prog->Attributes);
   }

   /* XXX this is a little ugly */
   if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
      struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
      if (vprog->TnlData)
         _mesa_free(vprog->TnlData);
   }

   _mesa_free(prog);
}
Ejemplo n.º 3
0
/**
 * Clear (free) the shader program state that gets produced by linking.
 */
void
_mesa_clear_shader_program_data(GLcontext *ctx,
                                struct gl_shader_program *shProg)
{
   if (shProg->VertexProgram) {
      if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
         /* to prevent a double-free in the next call */
         shProg->VertexProgram->Base.Parameters = NULL;
      }
      ctx->Driver.DeleteProgram(ctx, &shProg->VertexProgram->Base);
      shProg->VertexProgram = NULL;
   }

   if (shProg->FragmentProgram) {
      if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
         /* to prevent a double-free in the next call */
         shProg->FragmentProgram->Base.Parameters = NULL;
      }
      ctx->Driver.DeleteProgram(ctx, &shProg->FragmentProgram->Base);
      shProg->FragmentProgram = NULL;
   }

   if (shProg->Uniforms) {
      _mesa_free_parameter_list(shProg->Uniforms);
      shProg->Uniforms = NULL;
   }

   if (shProg->Varying) {
      _mesa_free_parameter_list(shProg->Varying);
      shProg->Varying = NULL;
   }
}
Ejemplo n.º 4
0
/**
 * Delete a program and remove it from the hash table, ignoring the
 * reference count.
 * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
 * by a device driver function.
 */
void
_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
{
   (void) ctx;
   ASSERT(prog);
   ASSERT(prog->RefCount==0);

   if (prog == &_mesa_DummyProgram)
      return;

   if (prog->String)
      free(prog->String);

   _mesa_free_instructions(prog->Instructions, prog->NumInstructions);

   if (prog->Parameters) {
      _mesa_free_parameter_list(prog->Parameters);
   }
   if (prog->Varying) {
      _mesa_free_parameter_list(prog->Varying);
   }
   if (prog->Attributes) {
      _mesa_free_parameter_list(prog->Attributes);
   }

   free(prog);
}
Ejemplo n.º 5
0
/**
 * Delete a program and remove it from the hash table, ignoring the
 * reference count.
 * Called via ctx->Driver.DeleteProgram.  May be wrapped (OO deriviation)
 * by a device driver function.
 */
void
_mesa_delete_program(struct gl_context *ctx, struct gl_program *prog)
{
   (void) ctx;
   assert(prog);
   assert(prog->RefCount==0);

   if (prog == &_mesa_DummyProgram)
      return;

   free(prog->String);
   free(prog->LocalParams);

   if (prog->Instructions) {
      _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
   }
   if (prog->Parameters) {
      _mesa_free_parameter_list(prog->Parameters);
   }

   if (prog->nir) {
      ralloc_free(prog->nir);
   }

   mtx_destroy(&prog->Mutex);
   free(prog);
}
Ejemplo n.º 6
0
/**
 * Free all the data that hangs off a shader program object, but not the
 * object itself.
 */
void
_mesa_free_shader_program_data(GLcontext *ctx,
                               struct gl_shader_program *shProg)
{
   GLuint i;

   assert(shProg->Type == GL_SHADER_PROGRAM_MESA);

   _mesa_clear_shader_program_data(ctx, shProg);

   if (shProg->Attributes) {
      _mesa_free_parameter_list(shProg->Attributes);
      shProg->Attributes = NULL;
   }

   /* detach shaders */
   for (i = 0; i < shProg->NumShaders; i++) {
      _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
   }
   shProg->NumShaders = 0;

   if (shProg->Shaders) {
      _mesa_free(shProg->Shaders);
      shProg->Shaders = NULL;
   }

   if (shProg->InfoLog) {
      _mesa_free(shProg->InfoLog);
      shProg->InfoLog = NULL;
   }
}
/**
 * Parse the vertex program string.  If success, update the given
 * vertex_program object with the new program.  Else, leave the vertex_program
 * object unchanged.
 */
void
_mesa_parse_arb_vertex_program(struct gl_context *ctx, GLenum target,
			       const GLvoid *str, GLsizei len,
			       struct gl_vertex_program *program)
{
   struct gl_program prog;
   struct asm_parser_state state;

   ASSERT(target == GL_VERTEX_PROGRAM_ARB);

   memset(&prog, 0, sizeof(prog));
   memset(&state, 0, sizeof(state));
   state.prog = &prog;

   if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len,
				&state)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramString(bad program)");
      return;
   }

   if (program->Base.String != NULL)
      free(program->Base.String);

   /* Copy the relevant contents of the arb_program struct into the 
    * vertex_program struct.
    */
   program->Base.String          = prog.String;
   program->Base.NumInstructions = prog.NumInstructions;
   program->Base.NumTemporaries  = prog.NumTemporaries;
   program->Base.NumParameters   = prog.NumParameters;
   program->Base.NumAttributes   = prog.NumAttributes;
   program->Base.NumAddressRegs  = prog.NumAddressRegs;
   program->Base.NumNativeInstructions = prog.NumNativeInstructions;
   program->Base.NumNativeTemporaries = prog.NumNativeTemporaries;
   program->Base.NumNativeParameters = prog.NumNativeParameters;
   program->Base.NumNativeAttributes = prog.NumNativeAttributes;
   program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs;
   program->Base.InputsRead     = prog.InputsRead;
   program->Base.OutputsWritten = prog.OutputsWritten;
   program->Base.IndirectRegisterFiles = prog.IndirectRegisterFiles;
   program->IsPositionInvariant = (state.option.PositionInvariant)
      ? GL_TRUE : GL_FALSE;

   if (program->Base.Instructions)
      free(program->Base.Instructions);
   program->Base.Instructions = prog.Instructions;

   if (program->Base.Parameters)
      _mesa_free_parameter_list(program->Base.Parameters);
   program->Base.Parameters = prog.Parameters; 

#if DEBUG_VP
   printf("____________Vertex program %u __________\n", program->Base.Id);
   _mesa_print_program(&program->Base);
#endif
}
Ejemplo n.º 8
0
/**
 * Delete a fragment program variant.  Note the caller must unlink
 * the variant from the linked list.
 */
static void
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);
      
   FREE(fpv);
}
void r300TranslateFragmentShader(r300ContextPtr r300,
				 struct r300_fragment_program *fp)
{
	struct r300_fragment_program_external_state state;

	build_state(r300, fp, &state);
	if (_mesa_memcmp(&fp->state, &state, sizeof(state))) {
		/* TODO: cache compiled programs */
		fp->translated = GL_FALSE;
		_mesa_memcpy(&fp->state, &state, sizeof(state));
	}

	if (!fp->translated) {
		struct r300_fragment_program_compiler compiler;

		compiler.r300 = r300;
		compiler.fp = fp;
		compiler.code = &fp->code;
		compiler.program = _mesa_clone_program(r300->radeon.glCtx, &fp->mesa_program.Base);

		if (RADEON_DEBUG & DEBUG_PIXEL) {
			_mesa_printf("Fragment Program: Initial program:\n");
			_mesa_print_program(compiler.program);
		}

		insert_WPOS_trailer(&compiler);

		struct radeon_program_transformation transformations[] = {
			{ &transform_TEX, &compiler },
			{ &radeonTransformALU, 0 },
			{ &radeonTransformTrigSimple, 0 }
		};
		radeonLocalTransform(
			r300->radeon.glCtx,
			compiler.program,
			3, transformations);

		if (RADEON_DEBUG & DEBUG_PIXEL) {
			_mesa_printf("Fragment Program: After native rewrite:\n");
			_mesa_print_program(compiler.program);
		}

		struct radeon_nqssadce_descr nqssadce = {
			.Init = &nqssadce_init,
			.IsNativeSwizzle = &r300FPIsNativeSwizzle,
			.BuildSwizzle = &r300FPBuildSwizzle,
			.RewriteDepthOut = GL_TRUE
		};
		radeonNqssaDce(r300->radeon.glCtx, compiler.program, &nqssadce);

		if (RADEON_DEBUG & DEBUG_PIXEL) {
			_mesa_printf("Compiler: after NqSSA-DCE:\n");
			_mesa_print_program(compiler.program);
		}

		if (!r300FragmentProgramEmit(&compiler))
			fp->error = GL_TRUE;

		/* Subtle: Rescue any parameters that have been added during transformations */
		_mesa_free_parameter_list(fp->mesa_program.Base.Parameters);
		fp->mesa_program.Base.Parameters = compiler.program->Parameters;
		compiler.program->Parameters = 0;

		_mesa_reference_program(r300->radeon.glCtx, &compiler.program, NULL);

		if (!fp->error)
			fp->translated = GL_TRUE;
		if (fp->error || (RADEON_DEBUG & DEBUG_PIXEL))
			r300FragmentProgramDump(fp, &fp->code);
		r300UpdateStateParameters(r300->radeon.glCtx, _NEW_PROGRAM);
	}

	update_params(r300, fp);
}
Ejemplo n.º 10
0
/**
 * Resolve binding of generic vertex attributes.
 * For example, if the vertex shader declared "attribute vec4 foobar" we'll
 * allocate a generic vertex attribute for "foobar" and plug that value into
 * the vertex program instructions.
 * But if the user called glBindAttributeLocation(), those bindings will
 * have priority.
 */
static GLboolean
_slang_resolve_attributes(struct gl_shader_program *shProg,
                          const struct gl_program *origProg,
                          struct gl_program *linkedProg)
{
   GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS];
   GLuint i, j;
   GLbitfield usedAttributes; /* generics only, not legacy attributes */
   GLbitfield inputsRead = 0x0;

   assert(origProg != linkedProg);
   assert(origProg->Target == GL_VERTEX_PROGRAM_ARB);
   assert(linkedProg->Target == GL_VERTEX_PROGRAM_ARB);

   if (!shProg->Attributes)
      shProg->Attributes = _mesa_new_parameter_list();

   if (linkedProg->Attributes) {
      _mesa_free_parameter_list(linkedProg->Attributes);
   }
   linkedProg->Attributes = _mesa_new_parameter_list();


   /* Build a bitmask indicating which attribute indexes have been
    * explicitly bound by the user with glBindAttributeLocation().
    */
   usedAttributes = 0x0;
   for (i = 0; i < shProg->Attributes->NumParameters; i++) {
      GLint attr = shProg->Attributes->Parameters[i].StateIndexes[0];
      usedAttributes |= (1 << attr);
   }

   /* If gl_Vertex is used, that actually counts against the limit
    * on generic vertex attributes.  This avoids the ambiguity of
    * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos)
    * or generic attribute[0].  If gl_Vertex is used, we want the former.
    */
   if (origProg->InputsRead & VERT_BIT_POS) {
      usedAttributes |= 0x1;
   }

   /* initialize the generic attribute map entries to -1 */
   for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) {
      attribMap[i] = -1;
   }

   /*
    * Scan program for generic attribute references
    */
   for (i = 0; i < linkedProg->NumInstructions; i++) {
      struct prog_instruction *inst = linkedProg->Instructions + i;
      for (j = 0; j < 3; j++) {
         if (inst->SrcReg[j].File == PROGRAM_INPUT) {
            inputsRead |= (1 << inst->SrcReg[j].Index);
         }

         if (inst->SrcReg[j].File == PROGRAM_INPUT &&
             inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) {
            /*
             * OK, we've found a generic vertex attribute reference.
             */
            const GLint k = inst->SrcReg[j].Index - VERT_ATTRIB_GENERIC0;

            GLint attr = attribMap[k];

            if (attr < 0) {
               /* Need to figure out attribute mapping now.
                */
               const char *name = origProg->Attributes->Parameters[k].Name;
               const GLint size = origProg->Attributes->Parameters[k].Size;
               const GLenum type =origProg->Attributes->Parameters[k].DataType;
               GLint index;

               /* See if there's a user-defined attribute binding for
                * this name.
                */
               index = _mesa_lookup_parameter_index(shProg->Attributes,
                                                    -1, name);
               if (index >= 0) {
                  /* Found a user-defined binding */
                  attr = shProg->Attributes->Parameters[index].StateIndexes[0];
               }
               else {
                  /* No user-defined binding, choose our own attribute number.
                   * Start at 1 since generic attribute 0 always aliases
                   * glVertex/position.
                   */
                  for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) {
                     if (((1 << attr) & usedAttributes) == 0)
                        break;
                  }
                  if (attr == MAX_VERTEX_GENERIC_ATTRIBS) {
                     link_error(shProg, "Too many vertex attributes");
                     return GL_FALSE;
                  }

                  /* mark this attribute as used */
                  usedAttributes |= (1 << attr);
               }

               attribMap[k] = attr;

               /* Save the final name->attrib binding so it can be queried
                * with glGetAttributeLocation().
                */
               _mesa_add_attribute(linkedProg->Attributes, name,
                                   size, type, attr);
            }

            assert(attr >= 0);

            /* update the instruction's src reg */
            inst->SrcReg[j].Index = VERT_ATTRIB_GENERIC0 + attr;
         }
      }
   }

   /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc).
    * When the user queries the active attributes we need to include both
    * the user-defined attributes and the built-in ones.
    */
   for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) {
      if (inputsRead & (1 << i)) {
         _mesa_add_attribute(linkedProg->Attributes,
                             _slang_vert_attrib_name(i),
                             4, /* size in floats */
                             _slang_vert_attrib_type(i),
                             -1 /* attrib/input */);
      }
   }

   return GL_TRUE;
}
Ejemplo n.º 11
0
/**
 * XXX description???
 * \return GL_TRUE for success, GL_FALSE for failure
 */
GLboolean
_mesa_layout_parameters(struct asm_parser_state *state)
{
   struct gl_program_parameter_list *layout;
   struct asm_instruction *inst;
   unsigned i;

   layout =
      _mesa_new_parameter_list_sized(state->prog->Parameters->NumParameters);

   /* PASS 1:  Move any parameters that are accessed indirectly from the
    * original parameter list to the new parameter list.
    */
   for (inst = state->inst_head; inst != NULL; inst = inst->next) {
      for (i = 0; i < 3; i++) {
	 if (inst->SrcReg[i].Base.RelAddr) {
	    /* Only attempt to add the to the new parameter list once.
	     */
	    if (!inst->SrcReg[i].Symbol->pass1_done) {
	       const int new_begin =
		  copy_indirect_accessed_array(state->prog->Parameters, layout,
		      inst->SrcReg[i].Symbol->param_binding_begin,
		      inst->SrcReg[i].Symbol->param_binding_length);

	       if (new_begin < 0) {
		  return GL_FALSE;
	       }

	       inst->SrcReg[i].Symbol->param_binding_begin = new_begin;
	       inst->SrcReg[i].Symbol->pass1_done = 1;
	    }

	    /* Previously the Index was just the offset from the parameter
	     * array.  Now that the base of the parameter array is known, the
	     * index can be updated to its actual value.
	     */
	    inst->Base.SrcReg[i] = inst->SrcReg[i].Base;
	    inst->Base.SrcReg[i].Index +=
	       inst->SrcReg[i].Symbol->param_binding_begin;
	 }
      }
   }

   /* PASS 2:  Move any parameters that are not accessed indirectly from the
    * original parameter list to the new parameter list.
    */
   for (inst = state->inst_head; inst != NULL; inst = inst->next) {
      for (i = 0; i < 3; i++) {
	 const struct gl_program_parameter *p;
	 const int idx = inst->SrcReg[i].Base.Index;
	 unsigned swizzle = SWIZZLE_NOOP;

	 /* All relative addressed operands were processed on the first
	  * pass.  Just skip them here.
	  */
	 if (inst->SrcReg[i].Base.RelAddr) {
	    continue;
	 }

	 if ((inst->SrcReg[i].Base.File <= PROGRAM_VARYING )
	     || (inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY)) {
	    continue;
	 }

	 inst->Base.SrcReg[i] = inst->SrcReg[i].Base;
	 p = & state->prog->Parameters->Parameters[idx];

	 switch (p->Type) {
	 case PROGRAM_CONSTANT: {
	    const float *const v =
	       state->prog->Parameters->ParameterValues[idx];

	    inst->Base.SrcReg[i].Index =
	       _mesa_add_unnamed_constant(layout, v, p->Size, & swizzle);

	    inst->Base.SrcReg[i].Swizzle = 
	       _mesa_combine_swizzles(swizzle, inst->Base.SrcReg[i].Swizzle);
	    break;
	 }

	 case PROGRAM_STATE_VAR:
	    inst->Base.SrcReg[i].Index =
	       _mesa_add_state_reference(layout, p->StateIndexes);
	    break;

	 default:
	    break;
	 }

	 inst->SrcReg[i].Base.File = p->Type;
	 inst->Base.SrcReg[i].File = p->Type;
      }
   }

   layout->StateFlags = state->prog->Parameters->StateFlags;
   _mesa_free_parameter_list(state->prog->Parameters);
   state->prog->Parameters = layout;

   return GL_TRUE;
}
void
_mesa_parse_arb_fragment_program(struct gl_context* ctx, GLenum target,
                                 const GLvoid *str, GLsizei len,
                                 struct gl_fragment_program *program)
{
   struct gl_program prog;
   struct asm_parser_state state;
   GLuint i;

   ASSERT(target == GL_FRAGMENT_PROGRAM_ARB);

   memset(&prog, 0, sizeof(prog));
   memset(&state, 0, sizeof(state));
   state.prog = &prog;

   if (!_mesa_parse_arb_program(ctx, target, (const GLubyte*) str, len,
				&state)) {
      /* Error in the program. Just return. */
      return;
   }

   if (program->Base.String != NULL)
      free(program->Base.String);

   /* Copy the relevant contents of the arb_program struct into the
    * fragment_program struct.
    */
   program->Base.String          = prog.String;
   program->Base.NumInstructions = prog.NumInstructions;
   program->Base.NumTemporaries  = prog.NumTemporaries;
   program->Base.NumParameters   = prog.NumParameters;
   program->Base.NumAttributes   = prog.NumAttributes;
   program->Base.NumAddressRegs  = prog.NumAddressRegs;
   program->Base.NumNativeInstructions = prog.NumNativeInstructions;
   program->Base.NumNativeTemporaries = prog.NumNativeTemporaries;
   program->Base.NumNativeParameters = prog.NumNativeParameters;
   program->Base.NumNativeAttributes = prog.NumNativeAttributes;
   program->Base.NumNativeAddressRegs = prog.NumNativeAddressRegs;
   program->Base.NumAluInstructions   = prog.NumAluInstructions;
   program->Base.NumTexInstructions   = prog.NumTexInstructions;
   program->Base.NumTexIndirections   = prog.NumTexIndirections;
   program->Base.NumNativeAluInstructions = prog.NumAluInstructions;
   program->Base.NumNativeTexInstructions = prog.NumTexInstructions;
   program->Base.NumNativeTexIndirections = prog.NumTexIndirections;
   program->Base.InputsRead      = prog.InputsRead;
   program->Base.OutputsWritten  = prog.OutputsWritten;
   program->Base.IndirectRegisterFiles = prog.IndirectRegisterFiles;
   for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++) {
      program->Base.TexturesUsed[i] = prog.TexturesUsed[i];
      if (prog.TexturesUsed[i])
         program->Base.SamplersUsed |= (1 << i);
   }
   program->Base.ShadowSamplers = prog.ShadowSamplers;
   program->OriginUpperLeft = state.option.OriginUpperLeft;
   program->PixelCenterInteger = state.option.PixelCenterInteger;

   program->UsesKill            = state.fragment.UsesKill;
   program->UsesDFdy            = state.fragment.UsesDFdy;

   if (program->Base.Instructions)
      free(program->Base.Instructions);
   program->Base.Instructions = prog.Instructions;

   if (program->Base.Parameters)
      _mesa_free_parameter_list(program->Base.Parameters);
   program->Base.Parameters    = prog.Parameters;

   /* Append fog instructions now if the program has "OPTION ARB_fog_exp"
    * or similar.  We used to leave this up to drivers, but it appears
    * there's no hardware that wants to do fog in a discrete stage separate
    * from the fragment shader.
    */
   if (state.option.Fog != OPTION_NONE) {
      static const GLenum fog_modes[4] = {
	 GL_NONE, GL_EXP, GL_EXP2, GL_LINEAR
      };

      /* XXX: we should somehow recompile this to remove clamping if disabled
       * On the ATI driver, this is unclampled if fragment clamping is disabled
       */
      _mesa_append_fog_code(ctx, program, fog_modes[state.option.Fog], GL_TRUE);
   }

#if DEBUG_FP
   printf("____________Fragment program %u ________\n", program->Base.Id);
   _mesa_print_program(&program->Base);
#endif
}
Ejemplo n.º 13
0
/**
 * Returns a fragment program which implements the current pixel transfer ops.
 */
static struct gl_fragment_program *
get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key)
{
   struct st_context *st = st_context(ctx);
   struct prog_instruction inst[MAX_INST];
   struct gl_program_parameter_list *params;
   struct gl_fragment_program *fp;
   GLuint ic = 0;
   const GLuint colorTemp = 0;

   fp = (struct gl_fragment_program *)
      ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
   if (!fp)
      return NULL;

   params = _mesa_new_parameter_list();

   /*
    * Get initial pixel color from the texture.
    * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
    */
   _mesa_init_instructions(inst + ic, 1);
   inst[ic].Opcode = OPCODE_TEX;
   inst[ic].DstReg.File = PROGRAM_TEMPORARY;
   inst[ic].DstReg.Index = colorTemp;
   inst[ic].SrcReg[0].File = PROGRAM_INPUT;
   inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
   inst[ic].TexSrcUnit = 0;
   inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
   ic++;
   fp->Base.InputsRead = BITFIELD64_BIT(FRAG_ATTRIB_TEX0);
   fp->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
   fp->Base.SamplersUsed = 0x1;  /* sampler 0 (bit 0) is used */

   if (key->scaleAndBias) {
      static const gl_state_index scale_state[STATE_LENGTH] =
         { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 };
      static const gl_state_index bias_state[STATE_LENGTH] =
         { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 };
      GLint scale_p, bias_p;

      scale_p = _mesa_add_state_reference(params, scale_state);
      bias_p = _mesa_add_state_reference(params, bias_state);

      /* MAD colorTemp, colorTemp, scale, bias; */
      _mesa_init_instructions(inst + ic, 1);
      inst[ic].Opcode = OPCODE_MAD;
      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
      inst[ic].DstReg.Index = colorTemp;
      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
      inst[ic].SrcReg[0].Index = colorTemp;
      inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR;
      inst[ic].SrcReg[1].Index = scale_p;
      inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR;
      inst[ic].SrcReg[2].Index = bias_p;
      ic++;
   }

   if (key->pixelMaps) {
      const GLuint temp = 1;

      /* create the colormap/texture now if not already done */
      if (!st->pixel_xfer.pixelmap_texture) {
         st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx);
         st->pixel_xfer.pixelmap_sampler_view =
            st_create_texture_sampler_view(st->pipe,
                                           st->pixel_xfer.pixelmap_texture);
      }

      /* with a little effort, we can do four pixel map look-ups with
       * two TEX instructions:
       */

      /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
      _mesa_init_instructions(inst + ic, 1);
      inst[ic].Opcode = OPCODE_TEX;
      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
      inst[ic].DstReg.Index = temp;
      inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */
      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
      inst[ic].SrcReg[0].Index = colorTemp;
      inst[ic].TexSrcUnit = 1;
      inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
      ic++;

      /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
      _mesa_init_instructions(inst + ic, 1);
      inst[ic].Opcode = OPCODE_TEX;
      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
      inst[ic].DstReg.Index = temp;
      inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */
      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
      inst[ic].SrcReg[0].Index = colorTemp;
      inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W,
                                                 SWIZZLE_Z, SWIZZLE_W);
      inst[ic].TexSrcUnit = 1;
      inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
      ic++;

      /* MOV colorTemp, temp; */
      _mesa_init_instructions(inst + ic, 1);
      inst[ic].Opcode = OPCODE_MOV;
      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
      inst[ic].DstReg.Index = colorTemp;
      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
      inst[ic].SrcReg[0].Index = temp;
      ic++;

      fp->Base.SamplersUsed |= (1 << 1);  /* sampler 1 is used */
   }

   /* Modify last instruction's dst reg to write to result.color */
   {
      struct prog_instruction *last = &inst[ic - 1];
      last->DstReg.File = PROGRAM_OUTPUT;
      last->DstReg.Index = FRAG_RESULT_COLOR;
   }

   /* END; */
   _mesa_init_instructions(inst + ic, 1);
   inst[ic].Opcode = OPCODE_END;
   ic++;

   assert(ic <= MAX_INST);


   fp->Base.Instructions = _mesa_alloc_instructions(ic);
   if (!fp->Base.Instructions) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY,
                  "generating pixel transfer program");
      _mesa_free_parameter_list(params);
      return NULL;
   }

   _mesa_copy_instructions(fp->Base.Instructions, inst, ic);
   fp->Base.NumInstructions = ic;
   fp->Base.Parameters = params;

#if 0
   printf("========= pixel transfer prog\n");
   _mesa_print_program(&fp->Base);
   _mesa_print_parameter_list(fp->Base.Parameters);
#endif

   return fp;
}