Subversion Repositories Kolibri OS

Rev

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

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2010 VMware, Inc.
  4.  * 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
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  17.  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  18.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20.  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  21.  *
  22.  * The above copyright notice and this permission notice (including the
  23.  * next paragraph) shall be included in all copies or substantial portions
  24.  * of the Software.
  25.  *
  26.  **************************************************************************/
  27.  
  28.  
  29. #include "util/u_memory.h"
  30. #include "util/u_math.h"
  31. #include "tgsi/tgsi_parse.h"
  32. #include "tgsi/tgsi_util.h"
  33. #include "tgsi/tgsi_dump.h"
  34. #include "tgsi/tgsi_strings.h"
  35. #include "lp_bld_debug.h"
  36. #include "lp_bld_tgsi.h"
  37.  
  38.  
  39. /**
  40.  * Analysis context.
  41.  *
  42.  * This is where we keep store the value of each channel of the IMM/TEMP/OUT
  43.  * register values, as we walk the shader.
  44.  */
  45. struct analysis_context
  46. {
  47.    struct lp_tgsi_info *info;
  48.  
  49.    unsigned num_imms;
  50.    float imm[LP_MAX_TGSI_IMMEDIATES][4];
  51.    unsigned sample_target[PIPE_MAX_SHADER_SAMPLER_VIEWS];
  52.  
  53.    struct lp_tgsi_channel_info temp[32][4];
  54. };
  55.  
  56.  
  57. /**
  58.  * Describe the specified channel of the src register.
  59.  */
  60. static void
  61. analyse_src(struct analysis_context *ctx,
  62.             struct lp_tgsi_channel_info *chan_info,
  63.             const struct tgsi_src_register *src,
  64.             unsigned chan)
  65. {
  66.    chan_info->file = TGSI_FILE_NULL;
  67.    if (!src->Indirect && !src->Absolute && !src->Negate) {
  68.       unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
  69.       if (src->File == TGSI_FILE_TEMPORARY) {
  70.          if (src->Index < Elements(ctx->temp)) {
  71.             *chan_info = ctx->temp[src->Index][swizzle];
  72.          }
  73.       } else {
  74.          chan_info->file = src->File;
  75.          if (src->File == TGSI_FILE_IMMEDIATE) {
  76.             assert(src->Index < Elements(ctx->imm));
  77.             if (src->Index < Elements(ctx->imm)) {
  78.                chan_info->u.value = ctx->imm[src->Index][swizzle];
  79.             }
  80.          } else {
  81.             chan_info->u.index = src->Index;
  82.             chan_info->swizzle = swizzle;
  83.          }
  84.       }
  85.    }
  86. }
  87.  
  88.  
  89. /**
  90.  * Whether this register channel refers to a specific immediate value.
  91.  */
  92. static boolean
  93. is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
  94. {
  95.    return chan_info->file == TGSI_FILE_IMMEDIATE &&
  96.           chan_info->u.value == value;
  97. }
  98.  
  99.  
  100. /**
  101.  * Analyse properties of tex instructions, in particular used
  102.  * to figure out if a texture is considered indirect.
  103.  * Not actually used by much except the tgsi dumping code.
  104.  */
  105. static void
  106. analyse_tex(struct analysis_context *ctx,
  107.             const struct tgsi_full_instruction *inst,
  108.             enum lp_build_tex_modifier modifier)
  109. {
  110.    struct lp_tgsi_info *info = ctx->info;
  111.    unsigned chan;
  112.  
  113.    if (info->num_texs < Elements(info->tex)) {
  114.       struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
  115.       boolean indirect = FALSE;
  116.       unsigned readmask = 0;
  117.  
  118.       tex_info->target = inst->Texture.Texture;
  119.       switch (inst->Texture.Texture) {
  120.       case TGSI_TEXTURE_1D:
  121.          readmask = TGSI_WRITEMASK_X;
  122.          break;
  123.       case TGSI_TEXTURE_1D_ARRAY:
  124.       case TGSI_TEXTURE_2D:
  125.       case TGSI_TEXTURE_RECT:
  126.          readmask = TGSI_WRITEMASK_XY;
  127.          break;
  128.       case TGSI_TEXTURE_SHADOW1D:
  129.       case TGSI_TEXTURE_SHADOW1D_ARRAY:
  130.       case TGSI_TEXTURE_SHADOW2D:
  131.       case TGSI_TEXTURE_SHADOWRECT:
  132.       case TGSI_TEXTURE_2D_ARRAY:
  133.       case TGSI_TEXTURE_2D_MSAA:
  134.       case TGSI_TEXTURE_3D:
  135.       case TGSI_TEXTURE_CUBE:
  136.          readmask = TGSI_WRITEMASK_XYZ;
  137.          break;
  138.       case TGSI_TEXTURE_SHADOW2D_ARRAY:
  139.       case TGSI_TEXTURE_SHADOWCUBE:
  140.       case TGSI_TEXTURE_2D_ARRAY_MSAA:
  141.       case TGSI_TEXTURE_CUBE_ARRAY:
  142.          readmask = TGSI_WRITEMASK_XYZW;
  143.          /* modifier would be in another not analyzed reg so just say indirect */
  144.          if (modifier != LP_BLD_TEX_MODIFIER_NONE) {
  145.             indirect = TRUE;
  146.          }
  147.          break;
  148.       case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
  149.          readmask = TGSI_WRITEMASK_XYZW;
  150.          indirect = TRUE;
  151.          break;
  152.       default:
  153.          assert(0);
  154.          return;
  155.       }
  156.  
  157.       if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
  158.          /* We don't track explicit derivatives, although we could */
  159.          indirect = TRUE;
  160.          tex_info->sampler_unit = inst->Src[3].Register.Index;
  161.          tex_info->texture_unit = inst->Src[3].Register.Index;
  162.       }  else {
  163.          if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
  164.              modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
  165.              modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
  166.             readmask |= TGSI_WRITEMASK_W;
  167.          }
  168.          tex_info->sampler_unit = inst->Src[1].Register.Index;
  169.          tex_info->texture_unit = inst->Src[1].Register.Index;
  170.       }
  171.  
  172.       for (chan = 0; chan < 4; ++chan) {
  173.          struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
  174.          if (readmask & (1 << chan)) {
  175.             analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
  176.             if (chan_info->file != TGSI_FILE_INPUT) {
  177.                indirect = TRUE;
  178.             }
  179.          } else {
  180.             memset(chan_info, 0, sizeof *chan_info);
  181.          }
  182.       }
  183.  
  184.       if (indirect) {
  185.          info->indirect_textures = TRUE;
  186.       }
  187.  
  188.       ++info->num_texs;
  189.    } else {
  190.       info->indirect_textures = TRUE;
  191.    }
  192. }
  193.  
  194.  
  195. /**
  196.  * Analyse properties of sample instructions, in particular used
  197.  * to figure out if a texture is considered indirect.
  198.  * Not actually used by much except the tgsi dumping code.
  199.  */
  200. static void
  201. analyse_sample(struct analysis_context *ctx,
  202.                const struct tgsi_full_instruction *inst,
  203.                enum lp_build_tex_modifier modifier,
  204.                boolean shadow)
  205. {
  206.    struct lp_tgsi_info *info = ctx->info;
  207.    unsigned chan;
  208.  
  209.    if (info->num_texs < Elements(info->tex)) {
  210.       struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
  211.       unsigned target = ctx->sample_target[inst->Src[1].Register.Index];
  212.       boolean indirect = FALSE;
  213.       boolean shadow = FALSE;
  214.       unsigned readmask;
  215.  
  216.       switch (target) {
  217.       /* note no shadow targets here */
  218.       case TGSI_TEXTURE_BUFFER:
  219.       case TGSI_TEXTURE_1D:
  220.          readmask = TGSI_WRITEMASK_X;
  221.          break;
  222.       case TGSI_TEXTURE_1D_ARRAY:
  223.       case TGSI_TEXTURE_2D:
  224.       case TGSI_TEXTURE_RECT:
  225.          readmask = TGSI_WRITEMASK_XY;
  226.          break;
  227.       case TGSI_TEXTURE_2D_ARRAY:
  228.       case TGSI_TEXTURE_2D_MSAA:
  229.       case TGSI_TEXTURE_3D:
  230.       case TGSI_TEXTURE_CUBE:
  231.          readmask = TGSI_WRITEMASK_XYZ;
  232.          break;
  233.       case TGSI_TEXTURE_CUBE_ARRAY:
  234.       case TGSI_TEXTURE_2D_ARRAY_MSAA:
  235.          readmask = TGSI_WRITEMASK_XYZW;
  236.          break;
  237.       default:
  238.          assert(0);
  239.          return;
  240.       }
  241.  
  242.       tex_info->target = target;
  243.       tex_info->texture_unit = inst->Src[1].Register.Index;
  244.       tex_info->sampler_unit = inst->Src[2].Register.Index;
  245.  
  246.       if (tex_info->texture_unit != tex_info->sampler_unit) {
  247.          info->sampler_texture_units_different = TRUE;
  248.       }
  249.  
  250.       if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV ||
  251.           modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD ||
  252.           modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS || shadow) {
  253.          /* We don't track insts with additional regs, although we could */
  254.          indirect = TRUE;
  255.       }
  256.  
  257.       for (chan = 0; chan < 4; ++chan) {
  258.          struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
  259.          if (readmask & (1 << chan)) {
  260.             analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
  261.             if (chan_info->file != TGSI_FILE_INPUT) {
  262.                indirect = TRUE;
  263.             }
  264.          } else {
  265.             memset(chan_info, 0, sizeof *chan_info);
  266.          }
  267.       }
  268.  
  269.       if (indirect) {
  270.          info->indirect_textures = TRUE;
  271.       }
  272.  
  273.       ++info->num_texs;
  274.    } else {
  275.       info->indirect_textures = TRUE;
  276.    }
  277. }
  278.  
  279.  
  280. /**
  281.  * Process an instruction, and update the register values accordingly.
  282.  */
  283. static void
  284. analyse_instruction(struct analysis_context *ctx,
  285.                     struct tgsi_full_instruction *inst)
  286. {
  287.    struct lp_tgsi_info *info = ctx->info;
  288.    struct lp_tgsi_channel_info (*regs)[4];
  289.    unsigned max_regs;
  290.    unsigned i;
  291.    unsigned index;
  292.    unsigned chan;
  293.  
  294.    for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
  295.       const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
  296.  
  297.       /*
  298.        * Get the lp_tgsi_channel_info array corresponding to the destination
  299.        * register file.
  300.        */
  301.  
  302.       if (dst->File == TGSI_FILE_TEMPORARY) {
  303.          regs = ctx->temp;
  304.          max_regs = Elements(ctx->temp);
  305.       } else if (dst->File == TGSI_FILE_OUTPUT) {
  306.          regs = info->output;
  307.          max_regs = Elements(info->output);
  308.       } else if (dst->File == TGSI_FILE_ADDRESS ||
  309.                  dst->File == TGSI_FILE_PREDICATE) {
  310.          continue;
  311.       } else {
  312.          assert(0);
  313.          continue;
  314.       }
  315.  
  316.       /*
  317.        * Detect direct TEX instructions
  318.        */
  319.  
  320.       switch (inst->Instruction.Opcode) {
  321.       case TGSI_OPCODE_TEX:
  322.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
  323.          break;
  324.       case TGSI_OPCODE_TXD:
  325.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
  326.          break;
  327.       case TGSI_OPCODE_TXB:
  328.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
  329.          break;
  330.       case TGSI_OPCODE_TXL:
  331.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
  332.          break;
  333.       case TGSI_OPCODE_TXP:
  334.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
  335.          break;
  336.       case TGSI_OPCODE_TEX2:
  337.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
  338.          break;
  339.       case TGSI_OPCODE_TXB2:
  340.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
  341.          break;
  342.       case TGSI_OPCODE_TXL2:
  343.          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
  344.          break;
  345.       case TGSI_OPCODE_SAMPLE:
  346.          analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, FALSE);
  347.          break;
  348.       case TGSI_OPCODE_SAMPLE_C:
  349.          analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_NONE, TRUE);
  350.          break;
  351.       case TGSI_OPCODE_SAMPLE_C_LZ:
  352.          analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_ZERO, TRUE);
  353.          break;
  354.       case TGSI_OPCODE_SAMPLE_D:
  355.          analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV, FALSE);
  356.          break;
  357.       case TGSI_OPCODE_SAMPLE_B:
  358.          analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS, FALSE);
  359.          break;
  360.       case TGSI_OPCODE_SAMPLE_L:
  361.          analyse_sample(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD, FALSE);
  362.          break;
  363.       default:
  364.          break;
  365.       }
  366.  
  367.       /*
  368.        * Keep track of assignments and writes
  369.        */
  370.  
  371.       if (dst->Indirect) {
  372.          /*
  373.           * It could be any register index so clear all register indices.
  374.           */
  375.  
  376.          for (chan = 0; chan < 4; ++chan) {
  377.             if (dst->WriteMask & (1 << chan)) {
  378.                for (index = 0; index < max_regs; ++index) {
  379.                   regs[index][chan].file = TGSI_FILE_NULL;
  380.                }
  381.             }
  382.          }
  383.       } else if (dst->Index < max_regs) {
  384.          /*
  385.           * Update this destination register value.
  386.           */
  387.  
  388.          struct lp_tgsi_channel_info res[4];
  389.  
  390.          memset(res, 0, sizeof res);
  391.  
  392.          if (!inst->Instruction.Predicate &&
  393.              !inst->Instruction.Saturate) {
  394.             for (chan = 0; chan < 4; ++chan) {
  395.                if (dst->WriteMask & (1 << chan)) {
  396.                   if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
  397.                      analyse_src(ctx, &res[chan],
  398.                                  &inst->Src[0].Register, chan);
  399.                   } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
  400.                      /*
  401.                       * Propagate values across 1.0 and 0.0 multiplications.
  402.                       */
  403.  
  404.                      struct lp_tgsi_channel_info src0;
  405.                      struct lp_tgsi_channel_info src1;
  406.  
  407.                      analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
  408.                      analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
  409.  
  410.                      if (is_immediate(&src0, 0.0f)) {
  411.                         res[chan] = src0;
  412.                      } else if (is_immediate(&src1, 0.0f)) {
  413.                         res[chan] = src1;
  414.                      } else if (is_immediate(&src0, 1.0f)) {
  415.                         res[chan] = src1;
  416.                      } else if (is_immediate(&src1, 1.0f)) {
  417.                         res[chan] = src0;
  418.                      }
  419.                   }
  420.                }
  421.             }
  422.          }
  423.  
  424.          for (chan = 0; chan < 4; ++chan) {
  425.             if (dst->WriteMask & (1 << chan)) {
  426.                regs[dst->Index][chan] = res[chan];
  427.             }
  428.          }
  429.       }
  430.    }
  431.  
  432.    /*
  433.     * Clear all temporaries information in presence of a control flow opcode.
  434.     */
  435.  
  436.    switch (inst->Instruction.Opcode) {
  437.    case TGSI_OPCODE_IF:
  438.    case TGSI_OPCODE_UIF:
  439.    case TGSI_OPCODE_ELSE:
  440.    case TGSI_OPCODE_ENDIF:
  441.    case TGSI_OPCODE_BGNLOOP:
  442.    case TGSI_OPCODE_BRK:
  443.    case TGSI_OPCODE_BREAKC:
  444.    case TGSI_OPCODE_CONT:
  445.    case TGSI_OPCODE_ENDLOOP:
  446.    case TGSI_OPCODE_CALLNZ:
  447.    case TGSI_OPCODE_CAL:
  448.    case TGSI_OPCODE_BGNSUB:
  449.    case TGSI_OPCODE_ENDSUB:
  450.    case TGSI_OPCODE_SWITCH:
  451.    case TGSI_OPCODE_CASE:
  452.    case TGSI_OPCODE_DEFAULT:
  453.    case TGSI_OPCODE_ENDSWITCH:
  454.    case TGSI_OPCODE_RET:
  455.    case TGSI_OPCODE_END:
  456.       /* XXX: Are there more cases? */
  457.       memset(&ctx->temp, 0, sizeof ctx->temp);
  458.       memset(&info->output, 0, sizeof info->output);
  459.    default:
  460.       break;
  461.    }
  462. }
  463.  
  464.  
  465. static INLINE void
  466. dump_info(const struct tgsi_token *tokens,
  467.           struct lp_tgsi_info *info)
  468. {
  469.    unsigned index;
  470.    unsigned chan;
  471.  
  472.    tgsi_dump(tokens, 0);
  473.  
  474.    for (index = 0; index < info->num_texs; ++index) {
  475.       const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
  476.       debug_printf("TEX[%u] =", index);
  477.       for (chan = 0; chan < 4; ++chan) {
  478.          const struct lp_tgsi_channel_info *chan_info =
  479.                &tex_info->coord[chan];
  480.          if (chan_info->file != TGSI_FILE_NULL) {
  481.             debug_printf(" %s[%u].%c",
  482.                          tgsi_file_name(chan_info->file),
  483.                          chan_info->u.index,
  484.                          "xyzw01"[chan_info->swizzle]);
  485.          } else {
  486.             debug_printf(" _");
  487.          }
  488.       }
  489.       debug_printf(", RES[%u], SAMP[%u], %s\n",
  490.                    tex_info->texture_unit,
  491.                    tex_info->sampler_unit,
  492.                    tgsi_texture_names[tex_info->target]);
  493.    }
  494.  
  495.    for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
  496.       for (chan = 0; chan < 4; ++chan) {
  497.          const struct lp_tgsi_channel_info *chan_info =
  498.                &info->output[index][chan];
  499.          if (chan_info->file != TGSI_FILE_NULL) {
  500.             debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
  501.             if (chan_info->file == TGSI_FILE_IMMEDIATE) {
  502.                debug_printf("%f", chan_info->u.value);
  503.             } else {
  504.                const char *file_name;
  505.                switch (chan_info->file) {
  506.                case TGSI_FILE_CONSTANT:
  507.                   file_name = "CONST";
  508.                   break;
  509.                case TGSI_FILE_INPUT:
  510.                   file_name = "IN";
  511.                   break;
  512.                default:
  513.                   file_name = "???";
  514.                   break;
  515.                }
  516.                debug_printf("%s[%u].%c",
  517.                             file_name,
  518.                             chan_info->u.index,
  519.                             "xyzw01"[chan_info->swizzle]);
  520.             }
  521.             debug_printf("\n");
  522.          }
  523.       }
  524.    }
  525. }
  526.  
  527.  
  528. /**
  529.  * Detect any direct relationship between the output color
  530.  */
  531. void
  532. lp_build_tgsi_info(const struct tgsi_token *tokens,
  533.                    struct lp_tgsi_info *info)
  534. {
  535.    struct tgsi_parse_context parse;
  536.    struct analysis_context *ctx;
  537.    unsigned index;
  538.    unsigned chan;
  539.  
  540.    memset(info, 0, sizeof *info);
  541.  
  542.    tgsi_scan_shader(tokens, &info->base);
  543.  
  544.    ctx = CALLOC(1, sizeof(struct analysis_context));
  545.    ctx->info = info;
  546.  
  547.    tgsi_parse_init(&parse, tokens);
  548.  
  549.    while (!tgsi_parse_end_of_tokens(&parse)) {
  550.       tgsi_parse_token(&parse);
  551.  
  552.       switch (parse.FullToken.Token.Type) {
  553.       case TGSI_TOKEN_TYPE_DECLARATION: {
  554.          struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
  555.          if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
  556.             for (index = decl->Range.First; index <= decl->Range.Last; index++) {
  557.                ctx->sample_target[index] = decl->SamplerView.Resource;
  558.             }
  559.          }
  560.       }
  561.          break;
  562.  
  563.       case TGSI_TOKEN_TYPE_INSTRUCTION:
  564.          {
  565.             struct tgsi_full_instruction *inst =
  566.                   &parse.FullToken.FullInstruction;
  567.  
  568.             if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
  569.                 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
  570.                /* We reached the end of main function body. */
  571.                goto finished;
  572.             }
  573.  
  574.             analyse_instruction(ctx, inst);
  575.          }
  576.          break;
  577.  
  578.       case TGSI_TOKEN_TYPE_IMMEDIATE:
  579.          {
  580.             const unsigned size =
  581.                   parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
  582.             assert(size <= 4);
  583.             if (ctx->num_imms < Elements(ctx->imm)) {
  584.                for (chan = 0; chan < size; ++chan) {
  585.                   float value = parse.FullToken.FullImmediate.u[chan].Float;
  586.                   ctx->imm[ctx->num_imms][chan] = value;
  587.  
  588.                   if (value < 0.0f || value > 1.0f) {
  589.                      info->unclamped_immediates = TRUE;
  590.                   }
  591.                }
  592.                ++ctx->num_imms;
  593.             }
  594.          }
  595.          break;
  596.  
  597.       case TGSI_TOKEN_TYPE_PROPERTY:
  598.          break;
  599.  
  600.       default:
  601.          assert(0);
  602.       }
  603.    }
  604. finished:
  605.  
  606.    tgsi_parse_free(&parse);
  607.    FREE(ctx);
  608.  
  609.  
  610.    /*
  611.     * Link the output color values.
  612.     */
  613.  
  614.    for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
  615.       const struct lp_tgsi_channel_info null_output[4];
  616.       info->cbuf[index] = null_output;
  617.    }
  618.  
  619.    for (index = 0; index < info->base.num_outputs; ++index) {
  620.       unsigned semantic_name = info->base.output_semantic_name[index];
  621.       unsigned semantic_index = info->base.output_semantic_index[index];
  622.       if (semantic_name == TGSI_SEMANTIC_COLOR &&
  623.           semantic_index < PIPE_MAX_COLOR_BUFS) {
  624.          info->cbuf[semantic_index] = info->output[index];
  625.       }
  626.    }
  627.  
  628.    if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
  629.       dump_info(tokens, info);
  630.    }
  631. }
  632.