Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Mesa 3-D graphics library
  3.  * Version:  6.5.3
  4.  *
  5.  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the "Software"),
  9.  * to deal in the Software without restriction, including without limitation
  10.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11.  * and/or sell copies of the Software, and to permit persons to whom the
  12.  * Software is furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included
  15.  * in all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  20.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  21.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22.  * CONNECTION WITH THE SOFTWARE OR THE USE OR 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 = VERT_RESULT_HPOS;
  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(VERT_RESULT_HPOS);
  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 = VERT_RESULT_HPOS;
  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(VERT_RESULT_HPOS);
  215. }
  216.  
  217.  
  218. void
  219. _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
  220. {
  221.    if (ctx->mvp_with_dp4)
  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 extra instructions onto the given fragment program to implement
  234.  * the fog mode specified by fprog->FogOption.
  235.  * The fragment.fogcoord input is used to compute the fog blend factor.
  236.  *
  237.  * XXX with a little work, this function could be adapted to add fog code
  238.  * to vertex programs too.
  239.  */
  240. void
  241. _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog)
  242. {
  243.    static const gl_state_index fogPStateOpt[STATE_LENGTH]
  244.       = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
  245.    static const gl_state_index fogColorState[STATE_LENGTH]
  246.       = { STATE_FOG_COLOR, 0, 0, 0, 0};
  247.    struct prog_instruction *newInst, *inst;
  248.    const GLuint origLen = fprog->Base.NumInstructions;
  249.    const GLuint newLen = origLen + 5;
  250.    GLuint i;
  251.    GLint fogPRefOpt, fogColorRef; /* state references */
  252.    GLuint colorTemp, fogFactorTemp; /* temporary registerss */
  253.  
  254.    if (fprog->FogOption == GL_NONE) {
  255.       _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
  256.                     " with FogOption == GL_NONE");
  257.       return;
  258.    }
  259.  
  260.    /* Alloc storage for new instructions */
  261.    newInst = _mesa_alloc_instructions(newLen);
  262.    if (!newInst) {
  263.       _mesa_error(ctx, GL_OUT_OF_MEMORY,
  264.                   "glProgramString(inserting fog_option code)");
  265.       return;
  266.    }
  267.  
  268.    /* Copy orig instructions into new instruction buffer */
  269.    _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
  270.  
  271.    /* PARAM fogParamsRefOpt = internal optimized fog params; */
  272.    fogPRefOpt
  273.       = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
  274.    /* PARAM fogColorRef = state.fog.color; */
  275.    fogColorRef
  276.       = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
  277.  
  278.    /* TEMP colorTemp; */
  279.    colorTemp = fprog->Base.NumTemporaries++;
  280.    /* TEMP fogFactorTemp; */
  281.    fogFactorTemp = fprog->Base.NumTemporaries++;
  282.  
  283.    /* Scan program to find where result.color is written */
  284.    inst = newInst;
  285.    for (i = 0; i < fprog->Base.NumInstructions; i++) {
  286.       if (inst->Opcode == OPCODE_END)
  287.          break;
  288.       if (inst->DstReg.File == PROGRAM_OUTPUT &&
  289.           inst->DstReg.Index == FRAG_RESULT_COLOR) {
  290.          /* change the instruction to write to colorTemp w/ clamping */
  291.          inst->DstReg.File = PROGRAM_TEMPORARY;
  292.          inst->DstReg.Index = colorTemp;
  293.          inst->SaturateMode = SATURATE_ZERO_ONE;
  294.          /* don't break (may be several writes to result.color) */
  295.       }
  296.       inst++;
  297.    }
  298.    assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
  299.  
  300.    _mesa_init_instructions(inst, 5);
  301.  
  302.    /* emit instructions to compute fog blending factor */
  303.    if (fprog->FogOption == GL_LINEAR) {
  304.       /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
  305.       inst->Opcode = OPCODE_MAD;
  306.       inst->DstReg.File = PROGRAM_TEMPORARY;
  307.       inst->DstReg.Index = fogFactorTemp;
  308.       inst->DstReg.WriteMask = WRITEMASK_X;
  309.       inst->SrcReg[0].File = PROGRAM_INPUT;
  310.       inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC;
  311.       inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  312.       inst->SrcReg[1].File = PROGRAM_STATE_VAR;
  313.       inst->SrcReg[1].Index = fogPRefOpt;
  314.       inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
  315.       inst->SrcReg[2].File = PROGRAM_STATE_VAR;
  316.       inst->SrcReg[2].Index = fogPRefOpt;
  317.       inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
  318.       inst->SaturateMode = SATURATE_ZERO_ONE;
  319.       inst++;
  320.    }
  321.    else {
  322.       ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2);
  323.       /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
  324.       /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
  325.       /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
  326.       inst->Opcode = OPCODE_MUL;
  327.       inst->DstReg.File = PROGRAM_TEMPORARY;
  328.       inst->DstReg.Index = fogFactorTemp;
  329.       inst->DstReg.WriteMask = WRITEMASK_X;
  330.       inst->SrcReg[0].File = PROGRAM_STATE_VAR;
  331.       inst->SrcReg[0].Index = fogPRefOpt;
  332.       inst->SrcReg[0].Swizzle
  333.          = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
  334.       inst->SrcReg[1].File = PROGRAM_INPUT;
  335.       inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
  336.       inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
  337.       inst++;
  338.       if (fprog->FogOption == GL_EXP2) {
  339.          /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
  340.          inst->Opcode = OPCODE_MUL;
  341.          inst->DstReg.File = PROGRAM_TEMPORARY;
  342.          inst->DstReg.Index = fogFactorTemp;
  343.          inst->DstReg.WriteMask = WRITEMASK_X;
  344.          inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  345.          inst->SrcReg[0].Index = fogFactorTemp;
  346.          inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  347.          inst->SrcReg[1].File = PROGRAM_TEMPORARY;
  348.          inst->SrcReg[1].Index = fogFactorTemp;
  349.          inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
  350.          inst++;
  351.       }
  352.       /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
  353.       inst->Opcode = OPCODE_EX2;
  354.       inst->DstReg.File = PROGRAM_TEMPORARY;
  355.       inst->DstReg.Index = fogFactorTemp;
  356.       inst->DstReg.WriteMask = WRITEMASK_X;
  357.       inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  358.       inst->SrcReg[0].Index = fogFactorTemp;
  359.       inst->SrcReg[0].Negate = NEGATE_XYZW;
  360.       inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  361.       inst->SaturateMode = SATURATE_ZERO_ONE;
  362.       inst++;
  363.    }
  364.    /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
  365.    inst->Opcode = OPCODE_LRP;
  366.    inst->DstReg.File = PROGRAM_OUTPUT;
  367.    inst->DstReg.Index = FRAG_RESULT_COLOR;
  368.    inst->DstReg.WriteMask = WRITEMASK_XYZ;
  369.    inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  370.    inst->SrcReg[0].Index = fogFactorTemp;
  371.    inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
  372.    inst->SrcReg[1].File = PROGRAM_TEMPORARY;
  373.    inst->SrcReg[1].Index = colorTemp;
  374.    inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
  375.    inst->SrcReg[2].File = PROGRAM_STATE_VAR;
  376.    inst->SrcReg[2].Index = fogColorRef;
  377.    inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
  378.    inst++;
  379.    /* MOV result.color.w, colorTemp.x;  # copy alpha */
  380.    inst->Opcode = OPCODE_MOV;
  381.    inst->DstReg.File = PROGRAM_OUTPUT;
  382.    inst->DstReg.Index = FRAG_RESULT_COLOR;
  383.    inst->DstReg.WriteMask = WRITEMASK_W;
  384.    inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  385.    inst->SrcReg[0].Index = colorTemp;
  386.    inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
  387.    inst++;
  388.    /* END; */
  389.    inst->Opcode = OPCODE_END;
  390.    inst++;
  391.  
  392.    /* free old instructions */
  393.    _mesa_free_instructions(fprog->Base.Instructions, origLen);
  394.  
  395.    /* install new instructions */
  396.    fprog->Base.Instructions = newInst;
  397.    fprog->Base.NumInstructions = inst - newInst;
  398.    fprog->Base.InputsRead |= FRAG_BIT_FOGC;
  399.    /* XXX do this?  fprog->FogOption = GL_NONE; */
  400. }
  401.  
  402.  
  403.  
  404. static GLboolean
  405. is_texture_instruction(const struct prog_instruction *inst)
  406. {
  407.    switch (inst->Opcode) {
  408.    case OPCODE_TEX:
  409.    case OPCODE_TXB:
  410.    case OPCODE_TXD:
  411.    case OPCODE_TXL:
  412.    case OPCODE_TXP:
  413.    case OPCODE_TXP_NV:
  414.       return GL_TRUE;
  415.    default:
  416.       return GL_FALSE;
  417.    }
  418. }
  419.      
  420.  
  421. /**
  422.  * Count the number of texure indirections in the given program.
  423.  * The program's NumTexIndirections field will be updated.
  424.  * See the GL_ARB_fragment_program spec (issue 24) for details.
  425.  * XXX we count texture indirections in texenvprogram.c (maybe use this code
  426.  * instead and elsewhere).
  427.  */
  428. void
  429. _mesa_count_texture_indirections(struct gl_program *prog)
  430. {
  431.    GLuint indirections = 1;
  432.    GLbitfield tempsOutput = 0x0;
  433.    GLbitfield aluTemps = 0x0;
  434.    GLuint i;
  435.  
  436.    for (i = 0; i < prog->NumInstructions; i++) {
  437.       const struct prog_instruction *inst = prog->Instructions + i;
  438.  
  439.       if (is_texture_instruction(inst)) {
  440.          if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
  441.               (tempsOutput & (1 << inst->SrcReg[0].Index))) ||
  442.              ((inst->Opcode != OPCODE_KIL) &&
  443.               (inst->DstReg.File == PROGRAM_TEMPORARY) &&
  444.               (aluTemps & (1 << inst->DstReg.Index))))
  445.             {
  446.                indirections++;
  447.                tempsOutput = 0x0;
  448.                aluTemps = 0x0;
  449.             }
  450.       }
  451.       else {
  452.          GLuint j;
  453.          for (j = 0; j < 3; j++) {
  454.             if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
  455.                aluTemps |= (1 << inst->SrcReg[j].Index);
  456.          }
  457.          if (inst->DstReg.File == PROGRAM_TEMPORARY)
  458.             aluTemps |= (1 << inst->DstReg.Index);
  459.       }
  460.  
  461.       if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
  462.          tempsOutput |= (1 << inst->DstReg.Index);
  463.    }
  464.  
  465.    prog->NumTexIndirections = indirections;
  466. }
  467.  
  468.  
  469. /**
  470.  * Count number of texture instructions in given program and update the
  471.  * program's NumTexInstructions field.
  472.  */
  473. void
  474. _mesa_count_texture_instructions(struct gl_program *prog)
  475. {
  476.    GLuint i;
  477.    prog->NumTexInstructions = 0;
  478.    for (i = 0; i < prog->NumInstructions; i++) {
  479.       prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
  480.    }
  481. }
  482.  
  483.  
  484. /**
  485.  * Scan/rewrite program to remove reads of custom (output) registers.
  486.  * The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING
  487.  * (for vertex shaders).
  488.  * In GLSL shaders, varying vars can be read and written.
  489.  * On some hardware, trying to read an output register causes trouble.
  490.  * So, rewrite the program to use a temporary register in this case.
  491.  */
  492. void
  493. _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
  494. {
  495.    GLuint i;
  496.    GLint outputMap[VERT_RESULT_MAX];
  497.    GLuint numVaryingReads = 0;
  498.    GLboolean usedTemps[MAX_PROGRAM_TEMPS];
  499.    GLuint firstTemp = 0;
  500.  
  501.    _mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
  502.                              usedTemps, MAX_PROGRAM_TEMPS);
  503.  
  504.    assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT);
  505.    assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING);
  506.  
  507.    for (i = 0; i < VERT_RESULT_MAX; i++)
  508.       outputMap[i] = -1;
  509.  
  510.    /* look for instructions which read from varying vars */
  511.    for (i = 0; i < prog->NumInstructions; i++) {
  512.       struct prog_instruction *inst = prog->Instructions + i;
  513.       const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
  514.       GLuint j;
  515.       for (j = 0; j < numSrc; j++) {
  516.          if (inst->SrcReg[j].File == type) {
  517.             /* replace the read with a temp reg */
  518.             const GLuint var = inst->SrcReg[j].Index;
  519.             if (outputMap[var] == -1) {
  520.                numVaryingReads++;
  521.                outputMap[var] = _mesa_find_free_register(usedTemps,
  522.                                                          MAX_PROGRAM_TEMPS,
  523.                                                          firstTemp);
  524.                firstTemp = outputMap[var] + 1;
  525.             }
  526.             inst->SrcReg[j].File = PROGRAM_TEMPORARY;
  527.             inst->SrcReg[j].Index = outputMap[var];
  528.          }
  529.       }
  530.    }
  531.  
  532.    if (numVaryingReads == 0)
  533.       return; /* nothing to be done */
  534.  
  535.    /* look for instructions which write to the varying vars identified above */
  536.    for (i = 0; i < prog->NumInstructions; i++) {
  537.       struct prog_instruction *inst = prog->Instructions + i;
  538.       if (inst->DstReg.File == type &&
  539.           outputMap[inst->DstReg.Index] >= 0) {
  540.          /* change inst to write to the temp reg, instead of the varying */
  541.          inst->DstReg.File = PROGRAM_TEMPORARY;
  542.          inst->DstReg.Index = outputMap[inst->DstReg.Index];
  543.       }
  544.    }
  545.  
  546.    /* insert new instructions to copy the temp vars to the varying vars */
  547.    {
  548.       struct prog_instruction *inst;
  549.       GLint endPos, var;
  550.  
  551.       /* Look for END instruction and insert the new varying writes */
  552.       endPos = -1;
  553.       for (i = 0; i < prog->NumInstructions; i++) {
  554.          struct prog_instruction *inst = prog->Instructions + i;
  555.          if (inst->Opcode == OPCODE_END) {
  556.             endPos = i;
  557.             _mesa_insert_instructions(prog, i, numVaryingReads);
  558.             break;
  559.          }
  560.       }
  561.  
  562.       assert(endPos >= 0);
  563.  
  564.       /* insert new MOV instructions here */
  565.       inst = prog->Instructions + endPos;
  566.       for (var = 0; var < VERT_RESULT_MAX; var++) {
  567.          if (outputMap[var] >= 0) {
  568.             /* MOV VAR[var], TEMP[tmp]; */
  569.             inst->Opcode = OPCODE_MOV;
  570.             inst->DstReg.File = type;
  571.             inst->DstReg.Index = var;
  572.             inst->SrcReg[0].File = PROGRAM_TEMPORARY;
  573.             inst->SrcReg[0].Index = outputMap[var];
  574.             inst++;
  575.          }
  576.       }
  577.    }
  578. }
  579.  
  580.  
  581. /**
  582.  * Make the given fragment program into a "no-op" shader.
  583.  * Actually, just copy the incoming fragment color (or texcoord)
  584.  * to the output color.
  585.  * This is for debug/test purposes.
  586.  */
  587. void
  588. _mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog)
  589. {
  590.    struct prog_instruction *inst;
  591.    GLuint inputAttr;
  592.  
  593.    inst = _mesa_alloc_instructions(2);
  594.    if (!inst) {
  595.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program");
  596.       return;
  597.    }
  598.  
  599.    _mesa_init_instructions(inst, 2);
  600.  
  601.    inst[0].Opcode = OPCODE_MOV;
  602.    inst[0].DstReg.File = PROGRAM_OUTPUT;
  603.    inst[0].DstReg.Index = FRAG_RESULT_COLOR;
  604.    inst[0].SrcReg[0].File = PROGRAM_INPUT;
  605.    if (prog->Base.InputsRead & FRAG_BIT_COL0)
  606.       inputAttr = FRAG_ATTRIB_COL0;
  607.    else
  608.       inputAttr = FRAG_ATTRIB_TEX0;
  609.    inst[0].SrcReg[0].Index = inputAttr;
  610.  
  611.    inst[1].Opcode = OPCODE_END;
  612.  
  613.    _mesa_free_instructions(prog->Base.Instructions,
  614.                            prog->Base.NumInstructions);
  615.  
  616.    prog->Base.Instructions = inst;
  617.    prog->Base.NumInstructions = 2;
  618.    prog->Base.InputsRead = 1 << inputAttr;
  619.    prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
  620. }
  621.  
  622.  
  623. /**
  624.  * \sa _mesa_nop_fragment_program
  625.  * Replace the given vertex program with a "no-op" program that just
  626.  * transforms vertex position and emits color.
  627.  */
  628. void
  629. _mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog)
  630. {
  631.    struct prog_instruction *inst;
  632.    GLuint inputAttr;
  633.  
  634.    /*
  635.     * Start with a simple vertex program that emits color.
  636.     */
  637.    inst = _mesa_alloc_instructions(2);
  638.    if (!inst) {
  639.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program");
  640.       return;
  641.    }
  642.  
  643.    _mesa_init_instructions(inst, 2);
  644.  
  645.    inst[0].Opcode = OPCODE_MOV;
  646.    inst[0].DstReg.File = PROGRAM_OUTPUT;
  647.    inst[0].DstReg.Index = VERT_RESULT_COL0;
  648.    inst[0].SrcReg[0].File = PROGRAM_INPUT;
  649.    if (prog->Base.InputsRead & VERT_BIT_COLOR0)
  650.       inputAttr = VERT_ATTRIB_COLOR0;
  651.    else
  652.       inputAttr = VERT_ATTRIB_TEX0;
  653.    inst[0].SrcReg[0].Index = inputAttr;
  654.  
  655.    inst[1].Opcode = OPCODE_END;
  656.  
  657.    _mesa_free_instructions(prog->Base.Instructions,
  658.                            prog->Base.NumInstructions);
  659.  
  660.    prog->Base.Instructions = inst;
  661.    prog->Base.NumInstructions = 2;
  662.    prog->Base.InputsRead = 1 << inputAttr;
  663.    prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0);
  664.  
  665.    /*
  666.     * Now insert code to do standard modelview/projection transformation.
  667.     */
  668.    _mesa_insert_mvp_code(ctx, prog);
  669. }
  670.