/** * 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); }
/** * 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); }
/** * 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; } }
/** * 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); }
/** * 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); }
/** * 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 }
/** * 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); }
/** * 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; }
/** * 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 }
/** * 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; }