Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright (C) 2010 Corbin Simpson
  3.  * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com>
  4.  *
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining
  8.  * a copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sublicense, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial
  17.  * portions of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  22.  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  23.  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  24.  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  25.  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  */
  28.  
  29. #include "radeon_program_tex.h"
  30.  
  31. #include "radeon_compiler_util.h"
  32.  
  33. /* Series of transformations to be done on textures. */
  34.  
  35. static struct rc_src_register shadow_fail_value(struct r300_fragment_program_compiler *compiler,
  36.                                                 int tmu)
  37. {
  38.         struct rc_src_register reg = { 0, 0, 0, 0, 0, 0 };
  39.  
  40.         reg.File = RC_FILE_NONE;
  41.         reg.Swizzle = combine_swizzles(RC_SWIZZLE_0000,
  42.                                 compiler->state.unit[tmu].texture_swizzle);
  43.         return reg;
  44. }
  45.  
  46. static struct rc_src_register shadow_pass_value(struct r300_fragment_program_compiler *compiler,
  47.                                                 int tmu)
  48. {
  49.         struct rc_src_register reg = { 0, 0, 0, 0, 0, 0 };
  50.  
  51.         reg.File = RC_FILE_NONE;
  52.         reg.Swizzle = combine_swizzles(RC_SWIZZLE_1111,
  53.                                 compiler->state.unit[tmu].texture_swizzle);
  54.         return reg;
  55. }
  56.  
  57. static void scale_texcoords(struct r300_fragment_program_compiler *compiler,
  58.                             struct rc_instruction *inst,
  59.                             unsigned state_constant)
  60. {
  61.         struct rc_instruction *inst_mov;
  62.  
  63.         unsigned temp = rc_find_free_temporary(&compiler->Base);
  64.  
  65.         inst_mov = rc_insert_new_instruction(&compiler->Base, inst->Prev);
  66.  
  67.         inst_mov->U.I.Opcode = RC_OPCODE_MUL;
  68.         inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  69.         inst_mov->U.I.DstReg.Index = temp;
  70.         inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  71.         inst_mov->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
  72.         inst_mov->U.I.SrcReg[1].Index =
  73.                         rc_constants_add_state(&compiler->Base.Program.Constants,
  74.                                                state_constant, inst->U.I.TexSrcUnit);
  75.  
  76.         reset_srcreg(&inst->U.I.SrcReg[0]);
  77.         inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  78.         inst->U.I.SrcReg[0].Index = temp;
  79. }
  80.  
  81. static void projective_divide(struct r300_fragment_program_compiler *compiler,
  82.                               struct rc_instruction *inst)
  83. {
  84.         struct rc_instruction *inst_mul, *inst_rcp;
  85.  
  86.         unsigned temp = rc_find_free_temporary(&compiler->Base);
  87.  
  88.         inst_rcp = rc_insert_new_instruction(&compiler->Base, inst->Prev);
  89.         inst_rcp->U.I.Opcode = RC_OPCODE_RCP;
  90.         inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY;
  91.         inst_rcp->U.I.DstReg.Index = temp;
  92.         inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
  93.         inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  94.         /* Because the input can be arbitrarily swizzled,
  95.          * read the component mapped to W. */
  96.         inst_rcp->U.I.SrcReg[0].Swizzle =
  97.                 RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3));
  98.  
  99.         inst_mul = rc_insert_new_instruction(&compiler->Base, inst->Prev);
  100.         inst_mul->U.I.Opcode = RC_OPCODE_MUL;
  101.         inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
  102.         inst_mul->U.I.DstReg.Index = temp;
  103.         inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  104.         inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
  105.         inst_mul->U.I.SrcReg[1].Index = temp;
  106.         inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW;
  107.  
  108.         reset_srcreg(&inst->U.I.SrcReg[0]);
  109.         inst->U.I.Opcode = RC_OPCODE_TEX;
  110.         inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  111.         inst->U.I.SrcReg[0].Index = temp;
  112. }
  113.  
  114. /**
  115.  * Transform TEX, TXP, TXB, and KIL instructions in the following ways:
  116.  *  - implement texture compare (shadow extensions)
  117.  *  - extract non-native source / destination operands
  118.  *  - premultiply texture coordinates for RECT
  119.  *  - extract operand swizzles
  120.  *  - introduce a temporary register when write masks are needed
  121.  */
  122. int radeonTransformTEX(
  123.         struct radeon_compiler * c,
  124.         struct rc_instruction * inst,
  125.         void* data)
  126. {
  127.         struct r300_fragment_program_compiler *compiler =
  128.                 (struct r300_fragment_program_compiler*)data;
  129.         rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode;
  130.         int is_rect = inst->U.I.TexSrcTarget == RC_TEXTURE_RECT ||
  131.                       compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords;
  132.  
  133.         if (inst->U.I.Opcode != RC_OPCODE_TEX &&
  134.                 inst->U.I.Opcode != RC_OPCODE_TXB &&
  135.                 inst->U.I.Opcode != RC_OPCODE_TXP &&
  136.                 inst->U.I.Opcode != RC_OPCODE_TXD &&
  137.                 inst->U.I.Opcode != RC_OPCODE_TXL &&
  138.                 inst->U.I.Opcode != RC_OPCODE_KIL)
  139.                 return 0;
  140.  
  141.         /* ARB_shadow & EXT_shadow_funcs */
  142.         if (inst->U.I.Opcode != RC_OPCODE_KIL &&
  143.                 ((c->Program.ShadowSamplers & (1 << inst->U.I.TexSrcUnit)) ||
  144.                  (compiler->state.unit[inst->U.I.TexSrcUnit].compare_mode_enabled))) {
  145.                 rc_compare_func comparefunc = compiler->state.unit[inst->U.I.TexSrcUnit].texture_compare_func;
  146.  
  147.                 if (comparefunc == RC_COMPARE_FUNC_NEVER || comparefunc == RC_COMPARE_FUNC_ALWAYS) {
  148.                         inst->U.I.Opcode = RC_OPCODE_MOV;
  149.  
  150.                         if (comparefunc == RC_COMPARE_FUNC_ALWAYS) {
  151.                                 inst->U.I.SrcReg[0] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit);
  152.                         } else {
  153.                                 inst->U.I.SrcReg[0] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit);
  154.                         }
  155.  
  156.                         return 1;
  157.                 } else {
  158.                         struct rc_instruction * inst_rcp = NULL;
  159.                         struct rc_instruction *inst_mul, *inst_add, *inst_cmp;
  160.                         unsigned tmp_texsample;
  161.                         unsigned tmp_sum;
  162.                         int pass, fail;
  163.  
  164.                         /* Save the output register. */
  165.                         struct rc_dst_register output_reg = inst->U.I.DstReg;
  166.                         unsigned saturate_mode = inst->U.I.SaturateMode;
  167.  
  168.                         /* Redirect TEX to a new temp. */
  169.                         tmp_texsample = rc_find_free_temporary(c);
  170.                         inst->U.I.SaturateMode = 0;
  171.                         inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
  172.                         inst->U.I.DstReg.Index = tmp_texsample;
  173.                         inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
  174.  
  175.                         tmp_sum = rc_find_free_temporary(c);
  176.  
  177.                         if (inst->U.I.Opcode == RC_OPCODE_TXP) {
  178.                                 /* Compute 1/W. */
  179.                                 inst_rcp = rc_insert_new_instruction(c, inst);
  180.                                 inst_rcp->U.I.Opcode = RC_OPCODE_RCP;
  181.                                 inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY;
  182.                                 inst_rcp->U.I.DstReg.Index = tmp_sum;
  183.                                 inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
  184.                                 inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  185.                                 inst_rcp->U.I.SrcReg[0].Swizzle =
  186.                                         RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3));
  187.                         }
  188.  
  189.                         /* Divide Z by W (if it's TXP) and saturate. */
  190.                         inst_mul = rc_insert_new_instruction(c, inst_rcp ? inst_rcp : inst);
  191.                         inst_mul->U.I.Opcode = inst->U.I.Opcode == RC_OPCODE_TXP ? RC_OPCODE_MUL : RC_OPCODE_MOV;
  192.                         inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
  193.                         inst_mul->U.I.DstReg.Index = tmp_sum;
  194.                         inst_mul->U.I.DstReg.WriteMask = RC_MASK_W;
  195.                         inst_mul->U.I.SaturateMode = RC_SATURATE_ZERO_ONE;
  196.                         inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  197.                         inst_mul->U.I.SrcReg[0].Swizzle =
  198.                                 RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 2));
  199.                         if (inst->U.I.Opcode == RC_OPCODE_TXP) {
  200.                                 inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
  201.                                 inst_mul->U.I.SrcReg[1].Index = tmp_sum;
  202.                                 inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW;
  203.                         }
  204.  
  205.                         /* Add the depth texture value. */
  206.                         inst_add = rc_insert_new_instruction(c, inst_mul);
  207.                         inst_add->U.I.Opcode = RC_OPCODE_ADD;
  208.                         inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
  209.                         inst_add->U.I.DstReg.Index = tmp_sum;
  210.                         inst_add->U.I.DstReg.WriteMask = RC_MASK_W;
  211.                         inst_add->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  212.                         inst_add->U.I.SrcReg[0].Index = tmp_sum;
  213.                         inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW;
  214.                         inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
  215.                         inst_add->U.I.SrcReg[1].Index = tmp_texsample;
  216.                         inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX;
  217.  
  218.                         /* Note that SrcReg[0] is r, SrcReg[1] is tex and:
  219.                          *   LESS:    r  < tex  <=>      -tex+r < 0
  220.                          *   GEQUAL:  r >= tex  <=> not (-tex+r < 0)
  221.                          *   GREATER: r  > tex  <=>       tex-r < 0
  222.                          *   LEQUAL:  r <= tex  <=> not ( tex-r < 0)
  223.                          *   EQUAL:   GEQUAL
  224.                          *   NOTEQUAL:LESS
  225.                          */
  226.  
  227.                         /* This negates either r or tex: */
  228.                         if (comparefunc == RC_COMPARE_FUNC_LESS || comparefunc == RC_COMPARE_FUNC_GEQUAL ||
  229.                             comparefunc == RC_COMPARE_FUNC_EQUAL || comparefunc == RC_COMPARE_FUNC_NOTEQUAL)
  230.                                 inst_add->U.I.SrcReg[1].Negate = inst_add->U.I.SrcReg[1].Negate ^ RC_MASK_XYZW;
  231.                         else
  232.                                 inst_add->U.I.SrcReg[0].Negate = inst_add->U.I.SrcReg[0].Negate ^ RC_MASK_XYZW;
  233.  
  234.                         /* This negates the whole expresion: */
  235.                         if (comparefunc == RC_COMPARE_FUNC_LESS || comparefunc == RC_COMPARE_FUNC_GREATER ||
  236.                             comparefunc == RC_COMPARE_FUNC_NOTEQUAL) {
  237.                                 pass = 1;
  238.                                 fail = 2;
  239.                         } else {
  240.                                 pass = 2;
  241.                                 fail = 1;
  242.                         }
  243.  
  244.                         inst_cmp = rc_insert_new_instruction(c, inst_add);
  245.                         inst_cmp->U.I.Opcode = RC_OPCODE_CMP;
  246.                         inst_cmp->U.I.SaturateMode = saturate_mode;
  247.                         inst_cmp->U.I.DstReg = output_reg;
  248.                         inst_cmp->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  249.                         inst_cmp->U.I.SrcReg[0].Index = tmp_sum;
  250.                         inst_cmp->U.I.SrcReg[0].Swizzle =
  251.                                         combine_swizzles(RC_SWIZZLE_WWWW,
  252.                                                          compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle);
  253.                         inst_cmp->U.I.SrcReg[pass] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit);
  254.                         inst_cmp->U.I.SrcReg[fail] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit);
  255.  
  256.                         assert(tmp_texsample != tmp_sum);
  257.                 }
  258.         }
  259.  
  260.         /* R300 cannot sample from rectangles and the wrap mode fallback needs
  261.          * normalized coordinates anyway. */
  262.         if (inst->U.I.Opcode != RC_OPCODE_KIL &&
  263.             is_rect && (!c->is_r500 || wrapmode != RC_WRAP_NONE)) {
  264.                 scale_texcoords(compiler, inst, RC_STATE_R300_TEXRECT_FACTOR);
  265.                 inst->U.I.TexSrcTarget = RC_TEXTURE_2D;
  266.         }
  267.  
  268.         /* Divide by W if needed. */
  269.         if (inst->U.I.Opcode == RC_OPCODE_TXP &&
  270.             (wrapmode == RC_WRAP_REPEAT || wrapmode == RC_WRAP_MIRRORED_REPEAT ||
  271.              compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch)) {
  272.                 projective_divide(compiler, inst);
  273.         }
  274.  
  275.         /* Texture wrap modes don't work on NPOT textures.
  276.          *
  277.          * Non-wrapped/clamped texcoords with NPOT are free in HW. Repeat and
  278.          * mirroring are not. If we need to repeat, we do:
  279.          *
  280.          * MUL temp, texcoord, <scaling factor constant>
  281.          * FRC temp, temp ; Discard integer portion of coords
  282.          *
  283.          * This gives us coords in [0, 1].
  284.          *
  285.          * Mirroring is trickier. We're going to start out like repeat:
  286.          *
  287.          * MUL temp, texcoord, <scaling factor constant> ; De-mirror across axes
  288.          * MUL temp, temp, 0.5 ; Pattern repeats in [0, 2]
  289.          *                            ; so scale to [0, 1]
  290.          * FRC temp, temp ; Make the pattern repeat
  291.          * MAD temp, temp, 2, -1 ; Move the pattern to [-1, 1]
  292.          * ADD temp, 1, -abs(temp) ; Now comes a neat trick: use abs to mirror the pattern.
  293.          *                              ; The pattern is backwards, so reverse it (1-x).
  294.          *
  295.          * This gives us coords in [0, 1].
  296.          *
  297.          * ~ C & M. ;)
  298.          */
  299.         if (inst->U.I.Opcode != RC_OPCODE_KIL &&
  300.             wrapmode != RC_WRAP_NONE) {
  301.                 struct rc_instruction *inst_mov;
  302.                 unsigned temp = rc_find_free_temporary(c);
  303.  
  304.                 if (wrapmode == RC_WRAP_REPEAT) {
  305.                         /* Both instructions will be paired up. */
  306.                         struct rc_instruction *inst_frc = rc_insert_new_instruction(c, inst->Prev);
  307.  
  308.                         inst_frc->U.I.Opcode = RC_OPCODE_FRC;
  309.                         inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY;
  310.                         inst_frc->U.I.DstReg.Index = temp;
  311.                         inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  312.                         inst_frc->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  313.                 } else if (wrapmode == RC_WRAP_MIRRORED_REPEAT) {
  314.                         /*
  315.                          * Function:
  316.                          *   f(v) = 1 - abs(frac(v * 0.5) * 2 - 1)
  317.                          *
  318.                          * Code:
  319.                          *   MUL temp, src0, 0.5
  320.                          *   FRC temp, temp
  321.                          *   MAD temp, temp, 2, -1
  322.                          *   ADD temp, 1, -abs(temp)
  323.                          */
  324.  
  325.                         struct rc_instruction *inst_mul, *inst_frc, *inst_mad, *inst_add;
  326.                         unsigned two, two_swizzle;
  327.  
  328.                         inst_mul = rc_insert_new_instruction(c, inst->Prev);
  329.  
  330.                         inst_mul->U.I.Opcode = RC_OPCODE_MUL;
  331.                         inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
  332.                         inst_mul->U.I.DstReg.Index = temp;
  333.                         inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  334.                         inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  335.                         inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_HHHH;
  336.  
  337.                         inst_frc = rc_insert_new_instruction(c, inst->Prev);
  338.  
  339.                         inst_frc->U.I.Opcode = RC_OPCODE_FRC;
  340.                         inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY;
  341.                         inst_frc->U.I.DstReg.Index = temp;
  342.                         inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  343.                         inst_frc->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  344.                         inst_frc->U.I.SrcReg[0].Index = temp;
  345.                         inst_frc->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
  346.  
  347.                         two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2, &two_swizzle);
  348.                         inst_mad = rc_insert_new_instruction(c, inst->Prev);
  349.  
  350.                         inst_mad->U.I.Opcode = RC_OPCODE_MAD;
  351.                         inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
  352.                         inst_mad->U.I.DstReg.Index = temp;
  353.                         inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  354.                         inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  355.                         inst_mad->U.I.SrcReg[0].Index = temp;
  356.                         inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
  357.                         inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
  358.                         inst_mad->U.I.SrcReg[1].Index = two;
  359.                         inst_mad->U.I.SrcReg[1].Swizzle = two_swizzle;
  360.                         inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_1111;
  361.                         inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZ;
  362.  
  363.                         inst_add = rc_insert_new_instruction(c, inst->Prev);
  364.  
  365.                         inst_add->U.I.Opcode = RC_OPCODE_ADD;
  366.                         inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
  367.                         inst_add->U.I.DstReg.Index = temp;
  368.                         inst_add->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  369.                         inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
  370.                         inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
  371.                         inst_add->U.I.SrcReg[1].Index = temp;
  372.                         inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0;
  373.                         inst_add->U.I.SrcReg[1].Abs = 1;
  374.                         inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZ;
  375.                 } else if (wrapmode == RC_WRAP_MIRRORED_CLAMP) {
  376.                         /*
  377.                          * Mirrored clamp modes are bloody simple, we just use abs
  378.                          * to mirror [0, 1] into [-1, 0]. This works for
  379.                          * all modes i.e. CLAMP, CLAMP_TO_EDGE, and CLAMP_TO_BORDER.
  380.                          */
  381.                         struct rc_instruction *inst_mov;
  382.  
  383.                         inst_mov = rc_insert_new_instruction(c, inst->Prev);
  384.  
  385.                         inst_mov->U.I.Opcode = RC_OPCODE_MOV;
  386.                         inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  387.                         inst_mov->U.I.DstReg.Index = temp;
  388.                         inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  389.                         inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  390.                         inst_mov->U.I.SrcReg[0].Abs = 1;
  391.                 }
  392.  
  393.                 /* Preserve W for TXP/TXB. */
  394.                 inst_mov = rc_insert_new_instruction(c, inst->Prev);
  395.  
  396.                 inst_mov->U.I.Opcode = RC_OPCODE_MOV;
  397.                 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  398.                 inst_mov->U.I.DstReg.Index = temp;
  399.                 inst_mov->U.I.DstReg.WriteMask = RC_MASK_W;
  400.                 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  401.  
  402.                 reset_srcreg(&inst->U.I.SrcReg[0]);
  403.                 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  404.                 inst->U.I.SrcReg[0].Index = temp;
  405.         }
  406.  
  407.         /* NPOT -> POT conversion for 3D textures. */
  408.         if (inst->U.I.Opcode != RC_OPCODE_KIL &&
  409.             compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch) {
  410.                 struct rc_instruction *inst_mov;
  411.                 unsigned temp = rc_find_free_temporary(c);
  412.  
  413.                 /* Saturate XYZ. */
  414.                 inst_mov = rc_insert_new_instruction(c, inst->Prev);
  415.                 inst_mov->U.I.Opcode = RC_OPCODE_MOV;
  416.                 inst_mov->U.I.SaturateMode = RC_SATURATE_ZERO_ONE;
  417.                 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  418.                 inst_mov->U.I.DstReg.Index = temp;
  419.                 inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ;
  420.                 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  421.  
  422.                 /* Copy W. */
  423.                 inst_mov = rc_insert_new_instruction(c, inst->Prev);
  424.                 inst_mov->U.I.Opcode = RC_OPCODE_MOV;
  425.                 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  426.                 inst_mov->U.I.DstReg.Index = temp;
  427.                 inst_mov->U.I.DstReg.WriteMask = RC_MASK_W;
  428.                 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  429.  
  430.                 reset_srcreg(&inst->U.I.SrcReg[0]);
  431.                 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  432.                 inst->U.I.SrcReg[0].Index = temp;
  433.  
  434.                 scale_texcoords(compiler, inst, RC_STATE_R300_TEXSCALE_FACTOR);
  435.         }
  436.  
  437.         /* Convert SNORM-encoded ATI1N sampled as UNORM to SNORM.
  438.          * Formula: dst = tex > 0.5 ? tex*2-2 : tex*2
  439.          */
  440.         if (inst->U.I.Opcode != RC_OPCODE_KIL &&
  441.             compiler->state.unit[inst->U.I.TexSrcUnit].convert_unorm_to_snorm) {
  442.                 unsigned two, two_swizzle;
  443.                 struct rc_instruction *inst_mul, *inst_mad, *inst_cnd;
  444.  
  445.                 two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2.35, &two_swizzle);
  446.  
  447.                 inst_mul = rc_insert_new_instruction(c, inst);
  448.                 inst_mul->U.I.Opcode = RC_OPCODE_MUL;
  449.                 inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
  450.                 inst_mul->U.I.DstReg.Index = rc_find_free_temporary(c);
  451.                 inst_mul->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  452.                 inst_mul->U.I.SrcReg[0].Index = rc_find_free_temporary(c); /* redirected TEX output */
  453.                 inst_mul->U.I.SrcReg[1].File = RC_FILE_CONSTANT; /* 2 */
  454.                 inst_mul->U.I.SrcReg[1].Index = two;
  455.                 inst_mul->U.I.SrcReg[1].Swizzle = two_swizzle;
  456.  
  457.                 inst_mad = rc_insert_new_instruction(c, inst_mul);
  458.                 inst_mad->U.I.Opcode = RC_OPCODE_MAD;
  459.                 inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
  460.                 inst_mad->U.I.DstReg.Index = rc_find_free_temporary(c);
  461.                 inst_mad->U.I.SrcReg[0] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */
  462.                 inst_mad->U.I.SrcReg[1] = inst_mul->U.I.SrcReg[1]; /* 2 */
  463.                 inst_mad->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[1]; /* 2 */
  464.                 inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZW;
  465.  
  466.                 inst_cnd = rc_insert_new_instruction(c, inst_mad);
  467.                 inst_cnd->U.I.Opcode = RC_OPCODE_CND;
  468.                 inst_cnd->U.I.SaturateMode = inst->U.I.SaturateMode;
  469.                 inst_cnd->U.I.DstReg = inst->U.I.DstReg;
  470.                 inst_cnd->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  471.                 inst_cnd->U.I.SrcReg[0].Index = inst_mad->U.I.DstReg.Index;
  472.                 inst_cnd->U.I.SrcReg[0].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle;
  473.                 inst_cnd->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
  474.                 inst_cnd->U.I.SrcReg[1].Index = inst_mul->U.I.DstReg.Index;
  475.                 inst_cnd->U.I.SrcReg[1].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle;
  476.                 inst_cnd->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */
  477.  
  478.                 inst->U.I.SaturateMode = 0;
  479.                 inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
  480.                 inst->U.I.DstReg.Index = inst_mul->U.I.SrcReg[0].Index;
  481.                 inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
  482.         }
  483.  
  484.         /* Cannot write texture to output registers or with saturate (all chips),
  485.          * or with masks (non-r500). */
  486.         if (inst->U.I.Opcode != RC_OPCODE_KIL &&
  487.                 (inst->U.I.DstReg.File != RC_FILE_TEMPORARY ||
  488.                  inst->U.I.SaturateMode ||
  489.                  (!c->is_r500 && inst->U.I.DstReg.WriteMask != RC_MASK_XYZW))) {
  490.                 struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst);
  491.  
  492.                 inst_mov->U.I.Opcode = RC_OPCODE_MOV;
  493.                 inst_mov->U.I.SaturateMode = inst->U.I.SaturateMode;
  494.                 inst_mov->U.I.DstReg = inst->U.I.DstReg;
  495.                 inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  496.                 inst_mov->U.I.SrcReg[0].Index = rc_find_free_temporary(c);
  497.  
  498.                 inst->U.I.SaturateMode = 0;
  499.                 inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
  500.                 inst->U.I.DstReg.Index = inst_mov->U.I.SrcReg[0].Index;
  501.                 inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
  502.         }
  503.  
  504.         /* Cannot read texture coordinate from constants file */
  505.         if (inst->U.I.SrcReg[0].File != RC_FILE_TEMPORARY && inst->U.I.SrcReg[0].File != RC_FILE_INPUT) {
  506.                 struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev);
  507.  
  508.                 inst_mov->U.I.Opcode = RC_OPCODE_MOV;
  509.                 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  510.                 inst_mov->U.I.DstReg.Index = rc_find_free_temporary(c);
  511.                 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
  512.  
  513.                 reset_srcreg(&inst->U.I.SrcReg[0]);
  514.                 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
  515.                 inst->U.I.SrcReg[0].Index = inst_mov->U.I.DstReg.Index;
  516.         }
  517.  
  518.         return 1;
  519. }
  520.