static void build_new_tnl_program( const struct state_key *key, struct gl_vertex_program *program, GLuint max_temps) { struct tnl_program p; _mesa_memset(&p, 0, sizeof(p)); p.state = key; p.program = program; p.eye_position = undef; p.eye_position_normalized = undef; p.eye_normal = undef; p.identity = undef; p.temp_in_use = 0; p.nr_instructions = 16; if (max_temps >= sizeof(int) * 8) p.temp_reserved = 0; else p.temp_reserved = ~((1<<max_temps)-1); p.program->Base.Instructions = _mesa_malloc(sizeof(struct prog_instruction) * p.nr_instructions); p.program->Base.String = 0; p.program->Base.NumInstructions = p.program->Base.NumTemporaries = p.program->Base.NumParameters = p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; p.program->Base.Parameters = _mesa_new_parameter_list(); p.program->Base.InputsRead = 0; p.program->Base.OutputsWritten = 0; build_tnl_program( &p ); }
struct gl_program_parameter_list * _mesa_clone_parameter_list(const struct gl_program_parameter_list *list) { struct gl_program_parameter_list *clone; GLuint i; clone = _mesa_new_parameter_list(); if (!clone) return NULL; /** Not too efficient, but correct */ for (i = 0; i < list->NumParameters; i++) { struct gl_program_parameter *p = list->Parameters + i; GLuint size = MIN2(p->Size, 4); GLint j = _mesa_add_parameter(clone, p->Type, p->Name, size, p->DataType, list->ParameterValues[i], NULL); ASSERT(j >= 0); /* copy state indexes */ if (p->Type == PROGRAM_STATE_VAR) { GLint k; struct gl_program_parameter *q = clone->Parameters + j; for (k = 0; k < STATE_LENGTH; k++) { q->StateIndexes[k] = p->StateIndexes[k]; } } else { clone->Parameters[j].Size = p->Size; } } return clone; }
struct gl_program_parameter_list * _mesa_new_parameter_list_sized(unsigned size) { struct gl_program_parameter_list *p = _mesa_new_parameter_list(); if ((p != NULL) && (size != 0)) { p->Size = size; /* alloc arrays */ p->Parameters = (struct gl_program_parameter *) calloc(1, size * sizeof(struct gl_program_parameter)); p->ParameterValues = (gl_constant_value (*)[4]) _mesa_align_malloc(size * 4 *sizeof(gl_constant_value), 16); if ((p->Parameters == NULL) || (p->ParameterValues == NULL)) { free(p->Parameters); _mesa_align_free(p->ParameterValues); free(p); p = NULL; } } return p; }
/** * Allocate a new gl_shader_program object, initialize it. */ struct gl_shader_program * _mesa_new_shader_program(GLcontext *ctx, GLuint name) { struct gl_shader_program *shProg; shProg = CALLOC_STRUCT(gl_shader_program); if (shProg) { shProg->Type = GL_SHADER_PROGRAM_MESA; shProg->Name = name; shProg->RefCount = 1; shProg->Attributes = _mesa_new_parameter_list(); } return shProg; }
static void create_new_program( const struct state_key *key, struct gl_program *program, GLboolean mvp_with_dp4, GLuint max_temps) { struct tnl_program p; memset(&p, 0, sizeof(p)); p.state = key; p.program = program; p.eye_position = undef; p.eye_position_z = undef; p.eye_position_normalized = undef; p.transformed_normal = undef; p.identity = undef; p.temp_in_use = 0; p.mvp_with_dp4 = mvp_with_dp4; if (max_temps >= sizeof(int) * 8) p.temp_reserved = 0; else p.temp_reserved = ~((1<<max_temps)-1); /* Start by allocating 32 instructions. * If we need more, we'll grow the instruction array as needed. */ p.max_inst = 32; p.program->arb.Instructions = rzalloc_array(program, struct prog_instruction, p.max_inst); p.program->String = NULL; p.program->arb.NumInstructions = p.program->arb.NumTemporaries = p.program->arb.NumParameters = p.program->arb.NumAttributes = p.program->arb.NumAddressRegs = 0; p.program->Parameters = _mesa_new_parameter_list(); p.program->info.inputs_read = 0; p.program->info.outputs_written = 0; build_tnl_program( &p ); }
/** * Called in ProgramStringNotify, we need to fill the metadata of the * gl_program attached to the ati_fragment_shader */ void st_init_atifs_prog(struct gl_context *ctx, struct gl_program *prog) { /* we know this is st_fragment_program, because of st_new_ati_fs() */ struct st_fragment_program *stfp = (struct st_fragment_program *) prog; struct ati_fragment_shader *atifs = stfp->ati_fs; unsigned pass, i, r, optype, arg; static const gl_state_index fog_params_state[STATE_LENGTH] = {STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0}; static const gl_state_index fog_color[STATE_LENGTH] = {STATE_FOG_COLOR, 0, 0, 0, 0}; prog->InputsRead = 0; prog->OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); prog->SamplersUsed = 0; prog->Parameters = _mesa_new_parameter_list(); /* fill in InputsRead, SamplersUsed, TexturesUsed */ for (pass = 0; pass < atifs->NumPasses; pass++) { for (r = 0; r < MAX_NUM_FRAGMENT_REGISTERS_ATI; r++) { struct atifs_setupinst *texinst = &atifs->SetupInst[pass][r]; GLuint pass_tex = texinst->src; if (texinst->Opcode == ATI_FRAGMENT_SHADER_SAMPLE_OP) { /* mark which texcoords are used */ prog->InputsRead |= BITFIELD64_BIT(VARYING_SLOT_TEX0 + pass_tex - GL_TEXTURE0_ARB); /* by default there is 1:1 mapping between samplers and textures */ prog->SamplersUsed |= (1 << r); /* the target is unknown here, it will be fixed in the draw call */ prog->TexturesUsed[r] = TEXTURE_2D_BIT; } else if (texinst->Opcode == ATI_FRAGMENT_SHADER_PASS_OP) { if (pass_tex >= GL_TEXTURE0_ARB && pass_tex <= GL_TEXTURE7_ARB) { prog->InputsRead |= BITFIELD64_BIT(VARYING_SLOT_TEX0 + pass_tex - GL_TEXTURE0_ARB); } } } } for (pass = 0; pass < atifs->NumPasses; pass++) { for (i = 0; i < atifs->numArithInstr[pass]; i++) { struct atifs_instruction *inst = &atifs->Instructions[pass][i]; for (optype = 0; optype < 2; optype++) { /* color, alpha */ if (inst->Opcode[optype]) { for (arg = 0; arg < inst->ArgCount[optype]; arg++) { GLint index = inst->SrcReg[optype][arg].Index; if (index == GL_PRIMARY_COLOR_EXT) { prog->InputsRead |= BITFIELD64_BIT(VARYING_SLOT_COL0); } else if (index == GL_SECONDARY_INTERPOLATOR_ATI) { /* note: ATI_fragment_shader.txt never specifies what * GL_SECONDARY_INTERPOLATOR_ATI is, swrast uses * VARYING_SLOT_COL1 for this input */ prog->InputsRead |= BITFIELD64_BIT(VARYING_SLOT_COL1); } } } } } } /* we may need fog */ prog->InputsRead |= BITFIELD64_BIT(VARYING_SLOT_FOGC); /* we always have the ATI_fs constants, and the fog params */ for (i = 0; i < MAX_NUM_FRAGMENT_CONSTANTS_ATI; i++) { _mesa_add_parameter(prog->Parameters, PROGRAM_UNIFORM, NULL, 4, GL_FLOAT, NULL, NULL); } _mesa_add_state_reference(prog->Parameters, fog_params_state); _mesa_add_state_reference(prog->Parameters, fog_color); prog->NumInstructions = 0; prog->NumTemporaries = MAX_NUM_FRAGMENT_REGISTERS_ATI + 3; /* 3 input temps for arith ops */ prog->NumParameters = MAX_NUM_FRAGMENT_CONSTANTS_ATI + 2; /* 2 state variables for fog */ }
/** * Shader linker. Currently: * * 1. The last attached vertex shader and fragment shader are linked. * 2. Varying vars in the two shaders are combined so their locations * agree between the vertex and fragment stages. They're treated as * vertex program output attribs and as fragment program input attribs. * 3. The vertex and fragment programs are cloned and modified to update * src/dst register references so they use the new, linked varying * storage locations. */ void _slang_link(GLcontext *ctx, GLhandleARB programObj, struct gl_shader_program *shProg) { const struct gl_vertex_program *vertProg = NULL; const struct gl_fragment_program *fragProg = NULL; GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE; GLuint numSamplers = 0; GLuint i; _mesa_clear_shader_program_data(ctx, shProg); /* Initialize LinkStatus to "success". Will be cleared if error. */ shProg->LinkStatus = GL_TRUE; /* check that all programs compiled successfully */ for (i = 0; i < shProg->NumShaders; i++) { if (!shProg->Shaders[i]->CompileStatus) { link_error(shProg, "linking with uncompiled shader\n"); return; } } shProg->Uniforms = _mesa_new_uniform_list(); shProg->Varying = _mesa_new_parameter_list(); /* * Find the vertex and fragment shaders which define main() */ { struct gl_shader *vertShader, *fragShader; vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); if (vertShader) vertProg = vertex_program(vertShader->Program); if (fragShader) fragProg = fragment_program(fragShader->Program); if (!shProg->LinkStatus) return; } #if FEATURE_es2_glsl /* must have both a vertex and fragment program for ES2 */ if (!vertProg) { link_error(shProg, "missing vertex shader\n"); return; } if (!fragProg) { link_error(shProg, "missing fragment shader\n"); return; } #endif /* * Make copies of the vertex/fragment programs now since we'll be * changing src/dst registers after merging the uniforms and varying vars. */ _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); if (vertProg) { struct gl_vertex_program *linked_vprog = _mesa_clone_vertex_program(ctx, vertProg); shProg->VertexProgram = linked_vprog; /* refcount OK */ /* vertex program ID not significant; just set Id for debugging purposes */ shProg->VertexProgram->Base.Id = shProg->Name; ASSERT(shProg->VertexProgram->Base.RefCount == 1); } _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); if (fragProg) { struct gl_fragment_program *linked_fprog = _mesa_clone_fragment_program(ctx, fragProg); shProg->FragmentProgram = linked_fprog; /* refcount OK */ /* vertex program ID not significant; just set Id for debugging purposes */ shProg->FragmentProgram->Base.Id = shProg->Name; ASSERT(shProg->FragmentProgram->Base.RefCount == 1); } /* link varying vars */ if (shProg->VertexProgram) { if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) return; } /* link uniform vars */ if (shProg->VertexProgram) { if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base, &numSamplers)) { return; } } if (shProg->FragmentProgram) { if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base, &numSamplers)) { return; } } /*_mesa_print_uniforms(shProg->Uniforms);*/ if (shProg->VertexProgram) { if (!_slang_resolve_attributes(shProg, &vertProg->Base, &shProg->VertexProgram->Base)) { return; } } if (shProg->VertexProgram) { _slang_update_inputs_outputs(&shProg->VertexProgram->Base); _slang_count_temporaries(&shProg->VertexProgram->Base); if (!(shProg->VertexProgram->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_HPOS))) { /* the vertex program did not compute a vertex position */ link_error(shProg, "gl_Position was not written by vertex shader\n"); return; } } if (shProg->FragmentProgram) { _slang_count_temporaries(&shProg->FragmentProgram->Base); _slang_update_inputs_outputs(&shProg->FragmentProgram->Base); } /* Check that all the varying vars needed by the fragment shader are * actually produced by the vertex shader. */ if (shProg->FragmentProgram) { const GLbitfield varyingRead = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0; const GLbitfield64 varyingWritten = shProg->VertexProgram ? shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0; if ((varyingRead & varyingWritten) != varyingRead) { link_error(shProg, "Fragment program using varying vars not written by vertex shader\n"); return; } } /* check that gl_FragColor and gl_FragData are not both written to */ if (shProg->FragmentProgram) { const GLbitfield64 outputsWritten = shProg->FragmentProgram->Base.OutputsWritten; if ((outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && (outputsWritten >= BITFIELD64_BIT(FRAG_RESULT_DATA0))) { link_error(shProg, "Fragment program cannot write both gl_FragColor" " and gl_FragData[].\n"); return; } } if (fragProg && shProg->FragmentProgram) { /* Compute initial program's TexturesUsed info */ _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); /* notify driver that a new fragment program has been compiled/linked */ vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, &shProg->FragmentProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { printf("Mesa pre-link fragment program:\n"); _mesa_print_program(&fragProg->Base); _mesa_print_program_parameters(ctx, &fragProg->Base); printf("Mesa post-link fragment program:\n"); _mesa_print_program(&shProg->FragmentProgram->Base); _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); } } if (vertProg && shProg->VertexProgram) { /* Compute initial program's TexturesUsed info */ _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); /* notify driver that a new vertex program has been compiled/linked */ fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, &shProg->VertexProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { printf("Mesa pre-link vertex program:\n"); _mesa_print_program(&vertProg->Base); _mesa_print_program_parameters(ctx, &vertProg->Base); printf("Mesa post-link vertex program:\n"); _mesa_print_program(&shProg->VertexProgram->Base); _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); } } /* Debug: */ if (0) { if (shProg->VertexProgram) _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); if (shProg->FragmentProgram) _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); } if (ctx->Shader.Flags & GLSL_DUMP) { printf("Varying vars:\n"); _mesa_print_parameter_list(shProg->Varying); if (shProg->InfoLog) { printf("Info Log: %s\n", shProg->InfoLog); } } if (!vertNotify || !fragNotify) { /* driver rejected one/both of the vertex/fragment programs */ if (!shProg->InfoLog) { link_error(shProg, "Vertex and/or fragment program rejected by driver\n"); } } else { shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); } }
/** * 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; }
/** * Parse/compile the 'str' returning the compiled 'program'. * ctx->Program.ErrorPos will be -1 if successful. Otherwise, ErrorPos * indicates the position of the error in 'str'. */ void _mesa_parse_nv_fragment_program(struct gl_context *ctx, GLenum dstTarget, const GLubyte *str, GLsizei len, struct gl_fragment_program *program) { struct parse_state parseState; struct prog_instruction instBuffer[MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS]; struct prog_instruction *newInst; GLenum target; GLubyte *programString; /* Make a null-terminated copy of the program string */ programString = (GLubyte *) MALLOC(len + 1); if (!programString) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } memcpy(programString, str, len); programString[len] = 0; /* Get ready to parse */ memset(&parseState, 0, sizeof(struct parse_state)); parseState.ctx = ctx; parseState.start = programString; parseState.program = program; parseState.numInst = 0; parseState.curLine = programString; parseState.parameters = _mesa_new_parameter_list(); /* Reset error state */ _mesa_set_program_error(ctx, -1, NULL); /* check the program header */ if (strncmp((const char *) programString, "!!FP1.0", 7) == 0) { target = GL_FRAGMENT_PROGRAM_NV; parseState.pos = programString + 7; } else if (strncmp((const char *) programString, "!!FCP1.0", 8) == 0) { /* fragment / register combiner program - not supported */ _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); return; } else { /* invalid header */ _mesa_set_program_error(ctx, 0, "Invalid fragment program header"); _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(bad header)"); return; } /* make sure target and header match */ if (target != dstTarget) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target mismatch 0x%x != 0x%x)", target, dstTarget); return; } if (Parse_InstructionSequence(&parseState, instBuffer)) { GLuint u; /* successful parse! */ if (parseState.outputsWritten == 0) { /* must write at least one output! */ _mesa_error(ctx, GL_INVALID_OPERATION, "Invalid fragment program - no outputs written."); return; } /* copy the compiled instructions */ assert(parseState.numInst <= MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS); newInst = _mesa_alloc_instructions(parseState.numInst); if (!newInst) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; /* out of memory */ } _mesa_copy_instructions(newInst, instBuffer, parseState.numInst); /* install the program */ program->Base.Target = target; if (program->Base.String) { FREE(program->Base.String); } program->Base.String = programString; program->Base.Format = GL_PROGRAM_FORMAT_ASCII_ARB; if (program->Base.Instructions) { free(program->Base.Instructions); } program->Base.Instructions = newInst; program->Base.NumInstructions = parseState.numInst; program->Base.InputsRead = parseState.inputsRead; program->Base.OutputsWritten = parseState.outputsWritten; for (u = 0; u < ctx->Const.MaxTextureImageUnits; u++) program->Base.TexturesUsed[u] = parseState.texturesUsed[u]; /* save program parameters */ program->Base.Parameters = parseState.parameters; /* allocate registers for declared program parameters */ #if 00 _mesa_assign_program_registers(&(program->SymbolTable)); #endif #ifdef DEBUG_foo printf("--- glLoadProgramNV(%d) result ---\n", program->Base.Id); _mesa_fprint_program_opt(stdout, &program->Base, PROG_PRINT_NV, 0); printf("----------------------------------\n"); #endif } else { /* Error! */ _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV"); /* NOTE: _mesa_set_program_error would have been called already */ } }
/** * Returns a fragment program which implements the current pixel transfer ops. */ static struct gl_fragment_program * get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key) { struct st_context *st = ctx->st; 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 = (1 << FRAG_ATTRIB_TEX0); fp->Base.OutputsWritten = (1 << FRAG_RESULT_COLR); 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 }; GLfloat scale[4], bias[4]; GLint scale_p, bias_p; scale[0] = ctx->Pixel.RedScale; scale[1] = ctx->Pixel.GreenScale; scale[2] = ctx->Pixel.BlueScale; scale[3] = ctx->Pixel.AlphaScale; bias[0] = ctx->Pixel.RedBias; bias[1] = ctx->Pixel.GreenBias; bias[2] = ctx->Pixel.BlueBias; bias[3] = ctx->Pixel.AlphaBias; 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 = create_color_map_texture(ctx); } /* 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 */ } if (key->colorMatrix) { static const gl_state_index row0_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 0, 0, 0 }; static const gl_state_index row1_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 1, 1, 0 }; static const gl_state_index row2_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 2, 2, 0 }; static const gl_state_index row3_state[STATE_LENGTH] = { STATE_COLOR_MATRIX, 0, 3, 3, 0 }; GLint row0_p = _mesa_add_state_reference(params, row0_state); GLint row1_p = _mesa_add_state_reference(params, row1_state); GLint row2_p = _mesa_add_state_reference(params, row2_state); GLint row3_p = _mesa_add_state_reference(params, row3_state); const GLuint temp = 1; /* DP4 temp.x, colorTemp, matrow0; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_X; 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 = row0_p; ic++; /* DP4 temp.y, colorTemp, matrow1; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_Y; 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 = row1_p; ic++; /* DP4 temp.z, colorTemp, matrow2; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_Z; 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 = row2_p; ic++; /* DP4 temp.w, colorTemp, matrow3; */ _mesa_init_instructions(inst + ic, 1); inst[ic].Opcode = OPCODE_DP4; inst[ic].DstReg.File = PROGRAM_TEMPORARY; inst[ic].DstReg.Index = temp; inst[ic].DstReg.WriteMask = WRITEMASK_W; 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 = row3_p; 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++; } if (key->colorMatrixPostScaleBias) { 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_param, bias_param; scale_param = _mesa_add_state_reference(params, scale_state); bias_param = _mesa_add_state_reference(params, bias_state); _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_param; inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR; inst[ic].SrcReg[2].Index = bias_param; ic++; } /* 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_COLR; } /* 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"); 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; }