Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. /**
  26.  * \file  programopt.c
  27.  * Vertex/Fragment program optimizations and transformations for program
  28.  * options, etc.
  29.  *
  30.  * \author Brian Paul
  31.  */
  32.  
  33.  
  34. #include "main/glheader.h"
  35. #include "main/context.h"
  36. #include "prog_parameter.h"
  37. #include "prog_statevars.h"
  38. #include "program.h"
  39. #include "programopt.h"
  40. #include "prog_instruction.h"
  41.  
  42.  
  43. /**
  44.  * This function inserts instructions for coordinate modelview * projection
  45.  * into a vertex program.
  46.  * May be used to implement the position_invariant option.
  47.  */
  48. static void
  49. _mesa_insert_mvp_dp4_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
  50. {
  51.    struct prog_instruction *newInst;
  52.    const GLuint origLen = vprog->Base.NumInstructions;
  53.    const GLuint newLen = origLen + 4;
  54.    GLuint i;
  55.  
  56.    /*
  57.     * Setup state references for the modelview/projection matrix.
  58.     * XXX we should check if these state vars are already declared.
  59.     */
  60.    static const gl_state_index mvpState[4][STATE_LENGTH] = {
  61.       { STATE_MVP_MATRIX, 0, 0, 0, 0 },  /* state.matrix.mvp.row[0] */
  62.       { STATE_MVP_MATRIX, 0, 1, 1, 0 },  /* state.matrix.mvp.row[1] */
  63.       { STATE_MVP_MATRIX, 0, 2, 2, 0 },  /* state.matrix.mvp.row[2] */
  64.       { STATE_MVP_MATRIX, 0, 3, 3, 0 },  /* state.matrix.mvp.row[3] */
  65.    };
  66.    GLint mvpRef[4];
  67.  
  68.    for (i = 0; i < 4; i++) {
  69.       mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
  70.                                             mvpState[i]);
  71.    }
  72.  
  73.    /* Alloc storage for new instructions */
  74.    newInst = _mesa_alloc_instructions(newLen);
  75.    if (!newInst) {
  76.       _mesa_error(ctx, GL_OUT_OF_MEMORY,
  77.                   "glProgramString(inserting position_invariant code)");
  78.       return;
  79.    }
  80.  
  81.    /*
  82.     * Generated instructions:
  83.     * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position;
  84.     * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position;
  85.     * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position;
  86.     * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position;
  87.     */
  88.    _mesa_init_instructions(newInst, 4);
  89.    for (i = 0; i < 4; i++) {
  90.       newInst[i].Opcode = OPCODE_DP4;
  91.       newInst[i].DstReg.File = PROGRAM_OUTPUT;
  92.       newInst[i].DstReg.Index = VARYING_SLOT_POS;
  93.       newInst[i].DstReg.WriteMask = (WRITEMASK_X << i);
  94.       newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR;
  95.       newInst[i].SrcReg[0].Index = mvpRef[i];
  96.       newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
  97.       newInst[i].SrcReg[1].File = PROGRAM_INPUT;
  98.       newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS;
  99.       newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
  100.    }
  101.  
  102.    /* Append original instructions after new instructions */
  103.    _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
  104.  
  105.    /* free old instructions */
  106.    _mesa_free_instructions(vprog->Base.Instructions, origLen);
  107.  
  108.    /* install new instructions */
  109.    vprog->Base.Instructions = newInst;
  110.    vprog->Base.NumInstructions = newLen;
  111.    vprog->Base.InputsRead |= VERT_BIT_POS;
  112.    vprog->Base.OutputsWritten |= BITFIELD64_BIT(VARYING_SLOT_POS);
  113. }
  114.  
  115.  
  116. static void
  117. _mesa_insert_mvp_mad_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
  118. {
  119.    struct prog_instruction *newInst;
  120.    const GLuint origLen = vprog->Base.NumInstructions;
  121.    const GLuint newLen = origLen + 4;
  122.    GLuint hposTemp;
  123.    GLuint i;
  124.  
  125.    /*
  126.     * Setup state references for the modelview/projection matrix.
  127.     * XXX we should check if these state vars are already declared.
  128.     */
  129.    static const gl_state_index mvpState[4][STATE_LENGTH] = {
  130.       { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE },
  131.       { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE },
  132.       { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE },
  133.       { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE },
  134.    };
  135.    GLint mvpRef[4];
  136.  
  137.    for (i = 0; i < 4; i++) {
  138.       mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
  139.                                             mvpState[i]);
  140.    }
  141.  
  142.    /* Alloc storage for new instructions */
  143.    newInst = _mesa_alloc_instructions(newLen);
  144.    if (!newInst) {
  145.       _mesa_error(ctx, GL_OUT_OF_MEMORY,
  146.                   "glProgramString(inserting position_invariant code)");
  147.       return;
  148.    }
  149.  
  150.    /* TEMP hposTemp; */
  151.    hposTemp = vprog->Base.NumTemporaries++;
  152.  
  153.    /*
  154.     * Generated instructions:
  155.     *    emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
  156.     *    emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
  157.     *    emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
  158.     *    emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
  159.     */
  160.    _mesa_init_instructions(newInst, 4);
  161.  
  162.    newInst[0].Opcode = OPCODE_MUL;
  163.    newInst[0].DstReg.File = PROGRAM_TEMPORARY;
  164.    newInst[0].DstReg.Index = hposTemp;
  165.    newInst[0].DstReg.WriteMask = WRITEMASK_XYZW;
  166.    newInst[0].SrcReg[0].File = PROGRAM_INPUT;
  167.    newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS;
  168.    newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX;
  169.    newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR;
  170.    newInst[0].SrcReg[1].Index = mvpRef[0];
  171.    newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP;
  172.  
  173.    for (i = 1; i <= 2; i++) {
  174.       newInst[i].Opcode = OPCODE_MAD;
  175.       newInst[i].DstReg.File = PROGRAM_TEMPORARY;
  176.       newInst[i].DstReg.Index = hposTemp;
  177.       newInst[i].DstReg.WriteMask = WRITEMASK_XYZW;
  178.       newInst[i].SrcReg[0].File = PROGRAM_INPUT;
  179.       newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS;
  180.       newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i);
  181.       newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR;
  182.       newInst[i].SrcReg[1].Index = mvpRef[i];
  183.       newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
  184.       newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY;
  185.       newInst[i].SrcReg[2].Index = hposTemp;
  186.       newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP;
  187.    }
  188.  
  189.    newInst[3].Opcode = OPCODE_MAD;
  190.    newInst[3].DstReg.File = PROGRAM_OUTPUT;
  191.    newInst[3].DstReg.Index = VARYING_SLOT_POS;
  192.    newInst[3].DstReg.WriteMask = WRITEMASK_XYZW;
  193.    newInst[3].SrcReg[0].File = PROGRAM_INPUT;
  194.    newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS;
  195.    newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW;
  196.    newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR;
  197.    newInst[3].SrcReg[1].Index = mvpRef[3];
  198.    newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP;
  199.    newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY;
  200.    newInst[3].SrcReg[2].Index = hposTemp;
  201.    newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP;
  202.  
  203.  
  204.    /* Append original instructions after new instructions */
  205.    _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
  206.  
  207.    /* free old instructions */
  208.    _mesa_free_instructions(vprog->Base.Instructions, origLen);
  209.  
  210.    /* install new instructions */
  211.    vprog->Base.Instructions = newInst;
  212.    vprog->Base.NumInstructions = newLen;
  213.    vprog->Base.InputsRead |= VERT_BIT_POS;
  214.    vprog->Base.OutputsWritten |= BITFIELD64_BIT(VARYING_SLOT_POS);
  215. }
  216.  
  217.  
  218. void
  219. _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
  220. {
  221.    if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].PreferDP4)
  222.       _mesa_insert_mvp_dp4_code( ctx, vprog );
  223.    else
  224.       _mesa_insert_mvp_mad_code( ctx, vprog );
  225. }
  226.      
  227.  
  228.  
  229.  
  230.  
  231.  
  232. /**
  233.  * Append instructions to implement fog
  234.  *
  235.  * The \c fragment.fogcoord input is used to compute the fog blend factor.
  236.  *
  237.  * \param ctx      The GL context
  238.  * \param fprog    Fragment program that fog instructions will be appended to.
  239.  * \param fog_mode Fog mode.  One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR.
  240.  * \param saturate True if writes to color outputs should be clamped to [0, 1]
  241.  *
  242.  * \note
  243.  * This function sets \c VARYING_BIT_FOGC in \c fprog->Base.InputsRead.
  244.  *
  245.  * \todo With a little work, this function could be adapted to add fog code
  246.  * to vertex programs too.
  247.  */
  248. void
  249. _mesa_append_fog_code(struct gl_context *ctx,
  250.                       struct gl_fragment_program *fprog, GLenum fog_mode,
  251.                       GLboolean saturate)
  252. {
  253.    static const gl_state_index fogPStateOpt[STATE_LENGTH]
  254.       = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
  255.    static const gl_state_index fogColorState[STATE_LENGTH]
  256.       = { STATE_FOG_COLOR, 0, 0, 0, 0};
  257.    struct prog_instruction *newInst, *inst;
  258.    const GLuint origLen = fprog->Base.NumInstructions;
  259.    const GLuint newLen = origLen + 5;
  260.    GLuint i;
  261.    GLint fogPRefOpt, fogColorRef; /* state references */
  262.    GLuint colorTemp, fogFactorTemp; /* temporary registerss */
  263.  
  264.    if (fog_mode == GL_NONE) {
  265.       _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
  266.                     " with fog_mode == GL_NONE");
  267.       return;
  268.    }
  269.  
  270.    if (!(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR))) {
  271.       /* program doesn't output color, so nothing to do */
  272.       return;
  273.    }
  274.  
  275.    /* Alloc storage for new instructions */
  276.    newInst = _mesa_alloc_instructions(newLen);
  277.    if (!newInst) {
  278.       _mesa_error(ctx, GL_OUT_OF_MEMORY,
  279.                   "glProgramString(inserting fog_option code)");
  280.       return;
  281.    }
  282.  
  283.    /* Copy orig instructions into new instruction buffer */
  284.    _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
  285.  
  286.    /* PARAM fogParamsRefOpt = internal optimized fog params; */
  287.    fogPRefOpt
  288.       = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
  289.    /* PARAM fogColorRef = state.fog.color; */
  290.    fogColorRef
  291.       = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
  292.  
  293.    /* TEMP colorTemp; */
  294.    colorTemp = fprog->Base.NumTemporaries++;
  295.    /* TEMP fogFactorTemp; */
  296.    fogFactorTemp = fprog->Base.NumTemporaries++;
  297.  
  298.    /* Scan program to find where result.color is written */
  299.    inst = newInst;
  300.    for (i = 0; i < fprog->Base.NumInstructions; i++) {
  301.       if (inst->Opcode == OPCODE_END)
  302.          break;
  303.       if (inst->DstReg.File == PROGRAM_OUTPUT &&
  304.           inst->DstReg.Index == FRAG_RESULT_COLOR) {
  305.          /* change the instruction to write to colorTemp w/ clamping */
  306.          inst->DstReg.File = PROGRAM_TEMPORARY;
  307.          inst->DstReg.Index = colorTemp;
  308.          inst->SaturateMode = saturate;
  309.          /* don't break (may be several writes to result.color) */
  310.       }
  311.       inst++;
  312.    }
  313.    assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
  314.  
  315.    _mesa_init_instructions(inst, 5);
  316.  
  317.    /* emit instructions to compute fog blending factor */
  318.    /* this is always clamped to [0, 1] regardless of fragment clamping */
  319.    if (fog_mode == GL_LINEAR) {
  320.       /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
  321.       inst->Opcode = OPCODE_MAD;
  322.       inst->DstReg.File = PROGRAM_TEMPORARY;
  323.       inst->DstReg.Index = fogFactorTemp;
  324.       inst->DstReg.WriteMask = WRITEMASK_X;
  325.       inst->SrcReg[0].File = PROGRAM_INPUT;
  326.       inst->SrcReg[0].Index = VARYING_SLOT_FOGC;
  327.       inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  328.       inst->SrcReg[1].File = PROGRAM_STATE_VAR;
  329.       inst->SrcReg[1].Index = fogPRefOpt;
  330.       inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
  331.       inst->SrcReg[2].File = PROGRAM_STATE_VAR;
  332.       inst->SrcReg[2].Index = fogPRefOpt;
  333.       inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
  334.       inst->SaturateMode = SATURATE_ZERO_ONE;
  335.       inst++;
  336.    }
  337.    else {
  338.       ASSERT(fog_mode == GL_EXP || fog_mode == GL_EXP2);
  339.       /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
  340.       /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
  341.       /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
  342.       inst->Opcode = OPCODE_MUL;
  343.       inst->DstReg.File = PROGRAM_TEMPORARY;
  344.       inst->DstReg.Index = fogFactorTemp;
  345.       inst->DstReg.WriteMask = WRITEMASK_X;
  346.       inst->SrcReg[0].File = PROGRAM_STATE_VAR;
  347.       inst->SrcReg[0].Index = fogPRefOpt;
  348.       inst->SrcReg[0].Swizzle
  349.          = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
  350.       inst->SrcReg[1].File = PROGRAM_INPUT;
  351.       inst->SrcReg[1].Index = VARYING_SLOT_FOGC;
  352.       inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
  353.       inst++;
  354.       if (fog_mode == GL_EXP2) {
  355.          /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
  356.          inst->Opcode = OPCODE_MUL;
  357.          inst->DstReg.File = PROGRAM_TEMPORARY;
  358.          inst->DstReg.Index = fogFactorTemp;
  359.          inst->DstReg.WriteMask = WRITEMASK_X;
  360.          inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  361.          inst->SrcReg[0].Index = fogFactorTemp;
  362.          inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  363.          inst->SrcReg[1].File = PROGRAM_TEMPORARY;
  364.          inst->SrcReg[1].Index = fogFactorTemp;
  365.          inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
  366.          inst++;
  367.       }
  368.       /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
  369.       inst->Opcode = OPCODE_EX2;
  370.       inst->DstReg.File = PROGRAM_TEMPORARY;
  371.       inst->DstReg.Index = fogFactorTemp;
  372.       inst->DstReg.WriteMask = WRITEMASK_X;
  373.       inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  374.       inst->SrcReg[0].Index = fogFactorTemp;
  375.       inst->SrcReg[0].Negate = NEGATE_XYZW;
  376.       inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  377.       inst->SaturateMode = SATURATE_ZERO_ONE;
  378.       inst++;
  379.    }
  380.    /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
  381.    inst->Opcode = OPCODE_LRP;
  382.    inst->DstReg.File = PROGRAM_OUTPUT;
  383.    inst->DstReg.Index = FRAG_RESULT_COLOR;
  384.    inst->DstReg.WriteMask = WRITEMASK_XYZ;
  385.    inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  386.    inst->SrcReg[0].Index = fogFactorTemp;
  387.    inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  388.    inst->SrcReg[1].File = PROGRAM_TEMPORARY;
  389.    inst->SrcReg[1].Index = colorTemp;
  390.    inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
  391.    inst->SrcReg[2].File = PROGRAM_STATE_VAR;
  392.    inst->SrcReg[2].Index = fogColorRef;
  393.    inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
  394.    inst++;
  395.    /* MOV result.color.w, colorTemp.x;  # copy alpha */
  396.    inst->Opcode = OPCODE_MOV;
  397.    inst->DstReg.File = PROGRAM_OUTPUT;
  398.    inst->DstReg.Index = FRAG_RESULT_COLOR;
  399.    inst->DstReg.WriteMask = WRITEMASK_W;
  400.    inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  401.    inst->SrcReg[0].Index = colorTemp;
  402.    inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
  403.    inst++;
  404.    /* END; */
  405.    inst->Opcode = OPCODE_END;
  406.    inst++;
  407.  
  408.    /* free old instructions */
  409.    _mesa_free_instructions(fprog->Base.Instructions, origLen);
  410.  
  411.    /* install new instructions */
  412.    fprog->Base.Instructions = newInst;
  413.    fprog->Base.NumInstructions = inst - newInst;
  414.    fprog->Base.InputsRead |= VARYING_BIT_FOGC;
  415.    assert(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR));
  416. }
  417.  
  418.  
  419.  
  420. static GLboolean
  421. is_texture_instruction(const struct prog_instruction *inst)
  422. {
  423.    switch (inst->Opcode) {
  424.    case OPCODE_TEX:
  425.    case OPCODE_TXB:
  426.    case OPCODE_TXD:
  427.    case OPCODE_TXL:
  428.    case OPCODE_TXP:
  429.    case OPCODE_TXP_NV:
  430.       return GL_TRUE;
  431.    default:
  432.       return GL_FALSE;
  433.    }
  434. }
  435.      
  436.  
  437. /**
  438.  * Count the number of texure indirections in the given program.
  439.  * The program's NumTexIndirections field will be updated.
  440.  * See the GL_ARB_fragment_program spec (issue 24) for details.
  441.  * XXX we count texture indirections in texenvprogram.c (maybe use this code
  442.  * instead and elsewhere).
  443.  */
  444. void
  445. _mesa_count_texture_indirections(struct gl_program *prog)
  446. {
  447.    GLuint indirections = 1;
  448.    GLbitfield tempsOutput = 0x0;
  449.    GLbitfield aluTemps = 0x0;
  450.    GLuint i;
  451.  
  452.    for (i = 0; i < prog->NumInstructions; i++) {
  453.       const struct prog_instruction *inst = prog->Instructions + i;
  454.  
  455.       if (is_texture_instruction(inst)) {
  456.          if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
  457.               (tempsOutput & (1 << inst->SrcReg[0].Index))) ||
  458.              ((inst->Opcode != OPCODE_KIL) &&
  459.               (inst->DstReg.File == PROGRAM_TEMPORARY) &&
  460.               (aluTemps & (1 << inst->DstReg.Index))))
  461.             {
  462.                indirections++;
  463.                tempsOutput = 0x0;
  464.                aluTemps = 0x0;
  465.             }
  466.       }
  467.       else {
  468.          GLuint j;
  469.          for (j = 0; j < 3; j++) {
  470.             if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
  471.                aluTemps |= (1 << inst->SrcReg[j].Index);
  472.          }
  473.          if (inst->DstReg.File == PROGRAM_TEMPORARY)
  474.             aluTemps |= (1 << inst->DstReg.Index);
  475.       }
  476.  
  477.       if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
  478.          tempsOutput |= (1 << inst->DstReg.Index);
  479.    }
  480.  
  481.    prog->NumTexIndirections = indirections;
  482. }
  483.  
  484.  
  485. /**
  486.  * Count number of texture instructions in given program and update the
  487.  * program's NumTexInstructions field.
  488.  */
  489. void
  490. _mesa_count_texture_instructions(struct gl_program *prog)
  491. {
  492.    GLuint i;
  493.    prog->NumTexInstructions = 0;
  494.    for (i = 0; i < prog->NumInstructions; i++) {
  495.       prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
  496.    }
  497. }
  498.  
  499.  
  500. /**
  501.  * Scan/rewrite program to remove reads of custom (output) registers.
  502.  * The passed type has to be PROGRAM_OUTPUT.
  503.  * On some hardware, trying to read an output register causes trouble.
  504.  * So, rewrite the program to use a temporary register in this case.
  505.  */
  506. void
  507. _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
  508. {
  509.    GLuint i;
  510.    GLint outputMap[VARYING_SLOT_MAX];
  511.    GLuint numVaryingReads = 0;
  512.    GLboolean usedTemps[MAX_PROGRAM_TEMPS];
  513.    GLuint firstTemp = 0;
  514.  
  515.    _mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
  516.                              usedTemps, MAX_PROGRAM_TEMPS);
  517.  
  518.    assert(type == PROGRAM_OUTPUT);
  519.  
  520.    for (i = 0; i < VARYING_SLOT_MAX; i++)
  521.       outputMap[i] = -1;
  522.  
  523.    /* look for instructions which read from varying vars */
  524.    for (i = 0; i < prog->NumInstructions; i++) {
  525.       struct prog_instruction *inst = prog->Instructions + i;
  526.       const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
  527.       GLuint j;
  528.       for (j = 0; j < numSrc; j++) {
  529.          if (inst->SrcReg[j].File == type) {
  530.             /* replace the read with a temp reg */
  531.             const GLuint var = inst->SrcReg[j].Index;
  532.             if (outputMap[var] == -1) {
  533.                numVaryingReads++;
  534.                outputMap[var] = _mesa_find_free_register(usedTemps,
  535.                                                          MAX_PROGRAM_TEMPS,
  536.                                                          firstTemp);
  537.                firstTemp = outputMap[var] + 1;
  538.             }
  539.             inst->SrcReg[j].File = PROGRAM_TEMPORARY;
  540.             inst->SrcReg[j].Index = outputMap[var];
  541.          }
  542.       }
  543.    }
  544.  
  545.    if (numVaryingReads == 0)
  546.       return; /* nothing to be done */
  547.  
  548.    /* look for instructions which write to the varying vars identified above */
  549.    for (i = 0; i < prog->NumInstructions; i++) {
  550.       struct prog_instruction *inst = prog->Instructions + i;
  551.       if (inst->DstReg.File == type &&
  552.           outputMap[inst->DstReg.Index] >= 0) {
  553.          /* change inst to write to the temp reg, instead of the varying */
  554.          inst->DstReg.File = PROGRAM_TEMPORARY;
  555.          inst->DstReg.Index = outputMap[inst->DstReg.Index];
  556.       }
  557.    }
  558.  
  559.    /* insert new instructions to copy the temp vars to the varying vars */
  560.    {
  561.       struct prog_instruction *inst;
  562.       GLint endPos, var;
  563.  
  564.       /* Look for END instruction and insert the new varying writes */
  565.       endPos = -1;
  566.       for (i = 0; i < prog->NumInstructions; i++) {
  567.          struct prog_instruction *inst = prog->Instructions + i;
  568.          if (inst->Opcode == OPCODE_END) {
  569.             endPos = i;
  570.             _mesa_insert_instructions(prog, i, numVaryingReads);
  571.             break;
  572.          }
  573.       }
  574.  
  575.       assert(endPos >= 0);
  576.  
  577.       /* insert new MOV instructions here */
  578.       inst = prog->Instructions + endPos;
  579.       for (var = 0; var < VARYING_SLOT_MAX; var++) {
  580.          if (outputMap[var] >= 0) {
  581.             /* MOV VAR[var], TEMP[tmp]; */
  582.             inst->Opcode = OPCODE_MOV;
  583.             inst->DstReg.File = type;
  584.             inst->DstReg.Index = var;
  585.             inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  586.             inst->SrcReg[0].Index = outputMap[var];
  587.             inst++;
  588.          }
  589.       }
  590.    }
  591. }
  592.  
  593.  
  594. /**
  595.  * Make the given fragment program into a "no-op" shader.
  596.  * Actually, just copy the incoming fragment color (or texcoord)
  597.  * to the output color.
  598.  * This is for debug/test purposes.
  599.  */
  600. void
  601. _mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog)
  602. {
  603.    struct prog_instruction *inst;
  604.    GLuint inputAttr;
  605.  
  606.    inst = _mesa_alloc_instructions(2);
  607.    if (!inst) {
  608.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program");
  609.       return;
  610.    }
  611.  
  612.    _mesa_init_instructions(inst, 2);
  613.  
  614.    inst[0].Opcode = OPCODE_MOV;
  615.    inst[0].DstReg.File = PROGRAM_OUTPUT;
  616.    inst[0].DstReg.Index = FRAG_RESULT_COLOR;
  617.    inst[0].SrcReg[0].File = PROGRAM_INPUT;
  618.    if (prog->Base.InputsRead & VARYING_BIT_COL0)
  619.       inputAttr = VARYING_SLOT_COL0;
  620.    else
  621.       inputAttr = VARYING_SLOT_TEX0;
  622.    inst[0].SrcReg[0].Index = inputAttr;
  623.  
  624.    inst[1].Opcode = OPCODE_END;
  625.  
  626.    _mesa_free_instructions(prog->Base.Instructions,
  627.                            prog->Base.NumInstructions);
  628.  
  629.    prog->Base.Instructions = inst;
  630.    prog->Base.NumInstructions = 2;
  631.    prog->Base.InputsRead = BITFIELD64_BIT(inputAttr);
  632.    prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
  633. }
  634.  
  635.  
  636. /**
  637.  * \sa _mesa_nop_fragment_program
  638.  * Replace the given vertex program with a "no-op" program that just
  639.  * transforms vertex position and emits color.
  640.  */
  641. void
  642. _mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog)
  643. {
  644.    struct prog_instruction *inst;
  645.    GLuint inputAttr;
  646.  
  647.    /*
  648.     * Start with a simple vertex program that emits color.
  649.     */
  650.    inst = _mesa_alloc_instructions(2);
  651.    if (!inst) {
  652.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program");
  653.       return;
  654.    }
  655.  
  656.    _mesa_init_instructions(inst, 2);
  657.  
  658.    inst[0].Opcode = OPCODE_MOV;
  659.    inst[0].DstReg.File = PROGRAM_OUTPUT;
  660.    inst[0].DstReg.Index = VARYING_SLOT_COL0;
  661.    inst[0].SrcReg[0].File = PROGRAM_INPUT;
  662.    if (prog->Base.InputsRead & VERT_BIT_COLOR0)
  663.       inputAttr = VERT_ATTRIB_COLOR0;
  664.    else
  665.       inputAttr = VERT_ATTRIB_TEX0;
  666.    inst[0].SrcReg[0].Index = inputAttr;
  667.  
  668.    inst[1].Opcode = OPCODE_END;
  669.  
  670.    _mesa_free_instructions(prog->Base.Instructions,
  671.                            prog->Base.NumInstructions);
  672.  
  673.    prog->Base.Instructions = inst;
  674.    prog->Base.NumInstructions = 2;
  675.    prog->Base.InputsRead = BITFIELD64_BIT(inputAttr);
  676.    prog->Base.OutputsWritten = BITFIELD64_BIT(VARYING_SLOT_COL0);
  677.  
  678.    /*
  679.     * Now insert code to do standard modelview/projection transformation.
  680.     */
  681.    _mesa_insert_mvp_code(ctx, prog);
  682. }
  683.