diff options
Diffstat (limited to 'src/mesa/shader/programopt.c')
-rw-r--r-- | src/mesa/shader/programopt.c | 195 |
1 files changed, 177 insertions, 18 deletions
diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c index 199202edf77..55991dcce34 100644 --- a/src/mesa/shader/programopt.c +++ b/src/mesa/shader/programopt.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.5.1 + * Version: 6.5.2 * * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. * @@ -117,31 +117,190 @@ _mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog) /** * Append extra instructions onto the given fragment program to implement - * the fog mode specified by program->FogOption. - * XXX incomplete. + * the fog mode specified by fprog->FogOption. + * The fragment.fogcoord input is used to compute the fog blend factor. + * + * XXX with a little work, this function could be adapted to add fog code + * to vertex programs too. */ void _mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog) { - struct prog_instruction newInst[10]; - - switch (fprog->FogOption) { - case GL_LINEAR: - /* lerp */ - break; - case GL_EXP: - break; - case GL_EXP2: - break; - case GL_NONE: - /* no-op */ + static const GLint fogParamsState[] = { STATE_FOG_PARAMS, 0, 0, 0, 0 }; + static const GLint fogColorState[] = { STATE_FOG_COLOR, 0, 0, 0, 0 }; + struct prog_instruction *newInst, *inst; + const GLuint origLen = fprog->Base.NumInstructions; + const GLuint newLen = origLen + 6; + GLuint i; + GLint fogParamsRef, fogColorRef; /* state references */ + GLuint colorTemp, fogFactorTemp; /* temporary registerss */ + GLfloat fogVals[4]; + GLuint fogConsts; /* constant values for EXP, EXP2 mode */ + + if (fprog->FogOption != GL_NONE) { + _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" + " with FogOption == GL_NONE"); return; - default: - _mesa_problem(ctx, "Invalid fog option"); + } + + /* Alloc storage for new instructions */ + newInst = _mesa_alloc_instructions(newLen); + if (!newInst) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "glProgramString(inserting fog_option code)"); return; } + /* Copy orig instructions into new instruction buffer */ + _mesa_memcpy(newInst, fprog->Base.Instructions, + origLen * sizeof(struct prog_instruction)); + + /* PARAM fogParamsRef = state.fog.params; */ + fogParamsRef + = _mesa_add_state_reference(fprog->Base.Parameters, fogParamsState); + /* PARAM fogColorRef = state.fog.color; */ + fogColorRef + = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); - (void) newInst; + /* TEMP colorTemp; */ + colorTemp = fprog->Base.NumTemporaries++; + /* TEMP fogFactorTemp; */ + fogFactorTemp = fprog->Base.NumTemporaries++; + /* PARAM fogVals = { 1/ln(2), 1/sqrt(ln(2), 0, 0 }; */ + fogVals[0] = 1.0 / log(2.0); + fogVals[1] = 1.0 / SQRTF(log(2.0)); + fogVals[2] = 0.0; + fogVals[3] = 0.0; + fogConsts = _mesa_add_unnamed_constant(fprog->Base.Parameters, fogVals); + + /* Scan program to find where result.color is written */ + inst = newInst; + for (i = 0; i < fprog->Base.NumInstructions; i++) { + if (inst->Opcode == OPCODE_END) + break; + if (inst->DstReg.File == PROGRAM_OUTPUT && + inst->DstReg.Index == FRAG_RESULT_COLR) { + /* change the instruction to write to colorTemp w/ clamping */ + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = colorTemp; + inst->SaturateMode = SATURATE_ZERO_ONE; + /* don't break (may be several writes to result.color) */ + } + inst++; + } + assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ + + for (i = 0; i < 6; i++) + _mesa_init_instruction(inst + i); + + /* emit instructions to compute fog blending factor */ + if (fprog->FogOption == GL_LINEAR) { + /* SUB fogFactorTemp.x, fogParamsRef.z, fragment.fogcoord.x; */ + inst->Opcode = OPCODE_SUB; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_STATE_VAR; + inst->SrcReg[0].Index = fogParamsRef; + inst->SrcReg[0].Swizzle = SWIZZLE_Z; + inst->SrcReg[1].File = PROGRAM_INPUT; + inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; + inst++; + /* MUL fogFactorTemp.x, fogFactorTemp, fogParamsRef.w; */ + inst->Opcode = OPCODE_MUL; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[1].File = PROGRAM_STATE_VAR; + inst->SrcReg[1].Index = fogParamsRef; + inst->SrcReg[1].Swizzle = SWIZZLE_W; + inst++; + } + else { + ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2); + /* MUL fogFactorTemp.x, fogParamsRef.x, fragment.fogcoord; */ + inst->Opcode = OPCODE_MUL; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_STATE_VAR; + inst->SrcReg[0].Index = fogParamsRef; + inst->SrcReg[0].Swizzle = SWIZZLE_X; /* X=density */ + inst->SrcReg[1].File = PROGRAM_INPUT; + inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; + inst->SrcReg[1].Swizzle = SWIZZLE_X; + inst++; + if (fprog->FogOption == GL_EXP2) { + /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ + inst->Opcode = OPCODE_MUL; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[1].File = PROGRAM_TEMPORARY; + inst->SrcReg[1].Index = fogFactorTemp; + inst++; + } + /* EXP: MUL fogFactorTemp.x, fogFactorTemp.x, {1/ln(2)}; */ + /* EXP2: MUL fogFactorTemp.x, fogFactorTemp.x, {1/sqrt(ln(2))}; */ + inst->Opcode = OPCODE_MUL; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[1].File = PROGRAM_CONSTANT; + inst->SrcReg[1].Index = fogConsts; + inst->SrcReg[1].Swizzle + = (fprog->FogOption == GL_EXP) ? SWIZZLE_X : SWIZZLE_Y; + inst++; + /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ + inst->Opcode = OPCODE_EX2; + inst->DstReg.File = PROGRAM_TEMPORARY; + inst->DstReg.Index = fogFactorTemp; + inst->DstReg.WriteMask = WRITEMASK_X; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[0].NegateBase = GL_TRUE; + inst->SaturateMode = SATURATE_ZERO_ONE; + inst++; + } + /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ + inst->Opcode = OPCODE_LRP; + inst->DstReg.File = PROGRAM_OUTPUT; + inst->DstReg.Index = FRAG_RESULT_COLR; + inst->DstReg.WriteMask = WRITEMASK_XYZ; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = fogFactorTemp; + inst->SrcReg[0].Swizzle + = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X); + inst->SrcReg[1].File = PROGRAM_TEMPORARY; + inst->SrcReg[1].Index = colorTemp; + inst->SrcReg[2].File = PROGRAM_STATE_VAR; + inst->SrcReg[2].Index = fogColorRef; + inst++; + /* MOV result.color.w, colorTemp.x; # copy alpha */ + inst->Opcode = OPCODE_MOV; + inst->DstReg.File = PROGRAM_OUTPUT; + inst->DstReg.Index = FRAG_RESULT_COLR; + inst->DstReg.WriteMask = WRITEMASK_W; + inst->SrcReg[0].File = PROGRAM_TEMPORARY; + inst->SrcReg[0].Index = colorTemp; + inst++; + /* END; */ + inst->Opcode = OPCODE_END; + inst++; + + /* free old instructions */ + _mesa_free(fprog->Base.Instructions); + + /* install new instructions */ + fprog->Base.Instructions = newInst; + fprog->Base.NumInstructions = inst - newInst; + fprog->Base.InputsRead |= FRAG_BIT_FOGC; + /* XXX do this? fprog->FogOption = GL_NONE; */ } |