Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2008 VMware, Inc.
  4.  * All Rights Reserved.
  5.  * Copyright 2008 VMware, Inc.  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
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sub license, 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 portions
  17.  * of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  23.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  **************************************************************************/
  28.  
  29. /**
  30.  * TGSI program scan utility.
  31.  * Used to determine which registers and instructions are used by a shader.
  32.  *
  33.  * Authors:  Brian Paul
  34.  */
  35.  
  36.  
  37. #include "util/u_debug.h"
  38. #include "util/u_math.h"
  39. #include "util/u_memory.h"
  40. #include "util/u_prim.h"
  41. #include "tgsi/tgsi_parse.h"
  42. #include "tgsi/tgsi_util.h"
  43. #include "tgsi/tgsi_scan.h"
  44.  
  45.  
  46.  
  47.  
  48. /**
  49.  * Scan the given TGSI shader to collect information such as number of
  50.  * registers used, special instructions used, etc.
  51.  * \return info  the result of the scan
  52.  */
  53. void
  54. tgsi_scan_shader(const struct tgsi_token *tokens,
  55.                  struct tgsi_shader_info *info)
  56. {
  57.    uint procType, i;
  58.    struct tgsi_parse_context parse;
  59.  
  60.    memset(info, 0, sizeof(*info));
  61.    for (i = 0; i < TGSI_FILE_COUNT; i++)
  62.       info->file_max[i] = -1;
  63.    for (i = 0; i < Elements(info->const_file_max); i++)
  64.       info->const_file_max[i] = -1;
  65.  
  66.    /**
  67.     ** Setup to begin parsing input shader
  68.     **/
  69.    if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
  70.       debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
  71.       return;
  72.    }
  73.    procType = parse.FullHeader.Processor.Processor;
  74.    assert(procType == TGSI_PROCESSOR_FRAGMENT ||
  75.           procType == TGSI_PROCESSOR_VERTEX ||
  76.           procType == TGSI_PROCESSOR_GEOMETRY ||
  77.           procType == TGSI_PROCESSOR_TESSCTRL ||
  78.           procType == TGSI_PROCESSOR_TESSEVAL ||
  79.           procType == TGSI_PROCESSOR_COMPUTE);
  80.    info->processor = procType;
  81.  
  82.  
  83.    /**
  84.     ** Loop over incoming program tokens/instructions
  85.     */
  86.    while( !tgsi_parse_end_of_tokens( &parse ) ) {
  87.  
  88.       info->num_tokens++;
  89.  
  90.       tgsi_parse_token( &parse );
  91.  
  92.       switch( parse.FullToken.Token.Type ) {
  93.       case TGSI_TOKEN_TYPE_INSTRUCTION:
  94.          {
  95.             const struct tgsi_full_instruction *fullinst
  96.                = &parse.FullToken.FullInstruction;
  97.             uint i;
  98.  
  99.             assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
  100.             info->opcode_count[fullinst->Instruction.Opcode]++;
  101.  
  102.             for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
  103.                const struct tgsi_full_src_register *src =
  104.                   &fullinst->Src[i];
  105.                int ind = src->Register.Index;
  106.  
  107.                /* Mark which inputs are effectively used */
  108.                if (src->Register.File == TGSI_FILE_INPUT) {
  109.                   unsigned usage_mask;
  110.                   usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i);
  111.                   if (src->Register.Indirect) {
  112.                      for (ind = 0; ind < info->num_inputs; ++ind) {
  113.                         info->input_usage_mask[ind] |= usage_mask;
  114.                      }
  115.                   } else {
  116.                      assert(ind >= 0);
  117.                      assert(ind < PIPE_MAX_SHADER_INPUTS);
  118.                      info->input_usage_mask[ind] |= usage_mask;
  119.                   }
  120.  
  121.                   if (procType == TGSI_PROCESSOR_FRAGMENT &&
  122.                       info->reads_position &&
  123.                       src->Register.Index == 0 &&
  124.                       (src->Register.SwizzleX == TGSI_SWIZZLE_Z ||
  125.                        src->Register.SwizzleY == TGSI_SWIZZLE_Z ||
  126.                        src->Register.SwizzleZ == TGSI_SWIZZLE_Z ||
  127.                        src->Register.SwizzleW == TGSI_SWIZZLE_Z)) {
  128.                      info->reads_z = TRUE;
  129.                   }
  130.                }
  131.  
  132.                /* check for indirect register reads */
  133.                if (src->Register.Indirect) {
  134.                   info->indirect_files |= (1 << src->Register.File);
  135.                   info->indirect_files_read |= (1 << src->Register.File);
  136.                }
  137.  
  138.                /* MSAA samplers */
  139.                if (src->Register.File == TGSI_FILE_SAMPLER) {
  140.                   assert(fullinst->Instruction.Texture);
  141.                   assert(src->Register.Index < Elements(info->is_msaa_sampler));
  142.  
  143.                   if (fullinst->Instruction.Texture &&
  144.                       (fullinst->Texture.Texture == TGSI_TEXTURE_2D_MSAA ||
  145.                        fullinst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) {
  146.                      info->is_msaa_sampler[src->Register.Index] = TRUE;
  147.                   }
  148.                }
  149.             }
  150.  
  151.             /* check for indirect register writes */
  152.             for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
  153.                const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
  154.                if (dst->Register.Indirect) {
  155.                   info->indirect_files |= (1 << dst->Register.File);
  156.                   info->indirect_files_written |= (1 << dst->Register.File);
  157.                }
  158.             }
  159.  
  160.             info->num_instructions++;
  161.          }
  162.          break;
  163.  
  164.       case TGSI_TOKEN_TYPE_DECLARATION:
  165.          {
  166.             const struct tgsi_full_declaration *fulldecl
  167.                = &parse.FullToken.FullDeclaration;
  168.             const uint file = fulldecl->Declaration.File;
  169.             uint reg;
  170.             if (fulldecl->Declaration.Array)
  171.                info->array_max[file] = MAX2(info->array_max[file], fulldecl->Array.ArrayID);
  172.             for (reg = fulldecl->Range.First;
  173.                  reg <= fulldecl->Range.Last;
  174.                  reg++) {
  175.                unsigned semName = fulldecl->Semantic.Name;
  176.                unsigned semIndex = fulldecl->Semantic.Index;
  177.  
  178.                /* only first 32 regs will appear in this bitfield */
  179.                info->file_mask[file] |= (1 << reg);
  180.                info->file_count[file]++;
  181.                info->file_max[file] = MAX2(info->file_max[file], (int)reg);
  182.  
  183.                if (file == TGSI_FILE_CONSTANT) {
  184.                   int buffer = 0;
  185.  
  186.                   if (fulldecl->Declaration.Dimension)
  187.                      buffer = fulldecl->Dim.Index2D;
  188.  
  189.                   info->const_file_max[buffer] =
  190.                         MAX2(info->const_file_max[buffer], (int)reg);
  191.                }
  192.                else if (file == TGSI_FILE_INPUT) {
  193.                   info->input_semantic_name[reg] = (ubyte) semName;
  194.                   info->input_semantic_index[reg] = (ubyte) semIndex;
  195.                   info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
  196.                   info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;
  197.                   info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
  198.                   info->num_inputs++;
  199.  
  200.                   if (fulldecl->Interp.Location == TGSI_INTERPOLATE_LOC_CENTROID)
  201.                      info->uses_centroid = TRUE;
  202.  
  203.                   if (semName == TGSI_SEMANTIC_PRIMID)
  204.                      info->uses_primid = TRUE;
  205.                   else if (procType == TGSI_PROCESSOR_FRAGMENT) {
  206.                      if (semName == TGSI_SEMANTIC_POSITION)
  207.                         info->reads_position = TRUE;
  208.                      else if (semName == TGSI_SEMANTIC_FACE)
  209.                         info->uses_frontface = TRUE;
  210.                   }
  211.                }
  212.                else if (file == TGSI_FILE_SYSTEM_VALUE) {
  213.                   unsigned index = fulldecl->Range.First;
  214.  
  215.                   info->system_value_semantic_name[index] = semName;
  216.                   info->num_system_values = MAX2(info->num_system_values,
  217.                                                  index + 1);
  218.  
  219.                   if (semName == TGSI_SEMANTIC_INSTANCEID) {
  220.                      info->uses_instanceid = TRUE;
  221.                   }
  222.                   else if (semName == TGSI_SEMANTIC_VERTEXID) {
  223.                      info->uses_vertexid = TRUE;
  224.                   }
  225.                   else if (semName == TGSI_SEMANTIC_VERTEXID_NOBASE) {
  226.                      info->uses_vertexid_nobase = TRUE;
  227.                   }
  228.                   else if (semName == TGSI_SEMANTIC_BASEVERTEX) {
  229.                      info->uses_basevertex = TRUE;
  230.                   }
  231.                   else if (semName == TGSI_SEMANTIC_PRIMID) {
  232.                      info->uses_primid = TRUE;
  233.                   }
  234.                }
  235.                else if (file == TGSI_FILE_OUTPUT) {
  236.                   info->output_semantic_name[reg] = (ubyte) semName;
  237.                   info->output_semantic_index[reg] = (ubyte) semIndex;
  238.                   info->num_outputs++;
  239.  
  240.                   if (procType == TGSI_PROCESSOR_VERTEX ||
  241.                       procType == TGSI_PROCESSOR_GEOMETRY ||
  242.                       procType == TGSI_PROCESSOR_TESSCTRL ||
  243.                       procType == TGSI_PROCESSOR_TESSEVAL) {
  244.                      if (semName == TGSI_SEMANTIC_CLIPDIST) {
  245.                         info->num_written_clipdistance +=
  246.                            util_bitcount(fulldecl->Declaration.UsageMask);
  247.                         info->clipdist_writemask |=
  248.                            fulldecl->Declaration.UsageMask << (semIndex*4);
  249.                      }
  250.                      else if (semName == TGSI_SEMANTIC_CULLDIST) {
  251.                         info->num_written_culldistance +=
  252.                            util_bitcount(fulldecl->Declaration.UsageMask);
  253.                         info->culldist_writemask |=
  254.                            fulldecl->Declaration.UsageMask << (semIndex*4);
  255.                      }
  256.                      else if (semName == TGSI_SEMANTIC_VIEWPORT_INDEX) {
  257.                         info->writes_viewport_index = TRUE;
  258.                      }
  259.                      else if (semName == TGSI_SEMANTIC_LAYER) {
  260.                         info->writes_layer = TRUE;
  261.                      }
  262.                      else if (semName == TGSI_SEMANTIC_PSIZE) {
  263.                         info->writes_psize = TRUE;
  264.                      }
  265.                      else if (semName == TGSI_SEMANTIC_CLIPVERTEX) {
  266.                         info->writes_clipvertex = TRUE;
  267.                      }
  268.                   }
  269.  
  270.                   if (procType == TGSI_PROCESSOR_FRAGMENT) {
  271.                      if (semName == TGSI_SEMANTIC_POSITION) {
  272.                         info->writes_z = TRUE;
  273.                      }
  274.                      else if (semName == TGSI_SEMANTIC_STENCIL) {
  275.                         info->writes_stencil = TRUE;
  276.                      }
  277.                   }
  278.  
  279.                   if (procType == TGSI_PROCESSOR_VERTEX) {
  280.                      if (semName == TGSI_SEMANTIC_EDGEFLAG) {
  281.                         info->writes_edgeflag = TRUE;
  282.                      }
  283.                   }
  284.                }
  285.             }
  286.          }
  287.          break;
  288.  
  289.       case TGSI_TOKEN_TYPE_IMMEDIATE:
  290.          {
  291.             uint reg = info->immediate_count++;
  292.             uint file = TGSI_FILE_IMMEDIATE;
  293.  
  294.             info->file_mask[file] |= (1 << reg);
  295.             info->file_count[file]++;
  296.             info->file_max[file] = MAX2(info->file_max[file], (int)reg);
  297.          }
  298.          break;
  299.  
  300.       case TGSI_TOKEN_TYPE_PROPERTY:
  301.          {
  302.             const struct tgsi_full_property *fullprop
  303.                = &parse.FullToken.FullProperty;
  304.             unsigned name = fullprop->Property.PropertyName;
  305.  
  306.             assert(name < Elements(info->properties));
  307.             info->properties[name] = fullprop->u[0].Data;
  308.          }
  309.          break;
  310.  
  311.       default:
  312.          assert( 0 );
  313.       }
  314.    }
  315.  
  316.    info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
  317.                       info->opcode_count[TGSI_OPCODE_KILL]);
  318.  
  319.    /* The dimensions of the IN decleration in geometry shader have
  320.     * to be deduced from the type of the input primitive.
  321.     */
  322.    if (procType == TGSI_PROCESSOR_GEOMETRY) {
  323.       unsigned input_primitive =
  324.             info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
  325.       int num_verts = u_vertices_per_prim(input_primitive);
  326.       int j;
  327.       info->file_count[TGSI_FILE_INPUT] = num_verts;
  328.       info->file_max[TGSI_FILE_INPUT] =
  329.             MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
  330.       for (j = 0; j < num_verts; ++j) {
  331.          info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
  332.       }
  333.    }
  334.  
  335.    tgsi_parse_free (&parse);
  336. }
  337.  
  338.  
  339.  
  340. /**
  341.  * Check if the given shader is a "passthrough" shader consisting of only
  342.  * MOV instructions of the form:  MOV OUT[n], IN[n]
  343.  *  
  344.  */
  345. boolean
  346. tgsi_is_passthrough_shader(const struct tgsi_token *tokens)
  347. {
  348.    struct tgsi_parse_context parse;
  349.  
  350.    /**
  351.     ** Setup to begin parsing input shader
  352.     **/
  353.    if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
  354.       debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n");
  355.       return FALSE;
  356.    }
  357.  
  358.    /**
  359.     ** Loop over incoming program tokens/instructions
  360.     */
  361.    while (!tgsi_parse_end_of_tokens(&parse)) {
  362.  
  363.       tgsi_parse_token(&parse);
  364.  
  365.       switch (parse.FullToken.Token.Type) {
  366.       case TGSI_TOKEN_TYPE_INSTRUCTION:
  367.          {
  368.             struct tgsi_full_instruction *fullinst =
  369.                &parse.FullToken.FullInstruction;
  370.             const struct tgsi_full_src_register *src =
  371.                &fullinst->Src[0];
  372.             const struct tgsi_full_dst_register *dst =
  373.                &fullinst->Dst[0];
  374.  
  375.             /* Do a whole bunch of checks for a simple move */
  376.             if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV ||
  377.                 (src->Register.File != TGSI_FILE_INPUT &&
  378.                  src->Register.File != TGSI_FILE_SYSTEM_VALUE) ||
  379.                 dst->Register.File != TGSI_FILE_OUTPUT ||
  380.                 src->Register.Index != dst->Register.Index ||
  381.  
  382.                 src->Register.Negate ||
  383.                 src->Register.Absolute ||
  384.  
  385.                 src->Register.SwizzleX != TGSI_SWIZZLE_X ||
  386.                 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
  387.                 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
  388.                 src->Register.SwizzleW != TGSI_SWIZZLE_W ||
  389.  
  390.                 dst->Register.WriteMask != TGSI_WRITEMASK_XYZW)
  391.             {
  392.                tgsi_parse_free(&parse);
  393.                return FALSE;
  394.             }
  395.          }
  396.          break;
  397.  
  398.       case TGSI_TOKEN_TYPE_DECLARATION:
  399.          /* fall-through */
  400.       case TGSI_TOKEN_TYPE_IMMEDIATE:
  401.          /* fall-through */
  402.       case TGSI_TOKEN_TYPE_PROPERTY:
  403.          /* fall-through */
  404.       default:
  405.          ; /* no-op */
  406.       }
  407.    }
  408.  
  409.    tgsi_parse_free(&parse);
  410.  
  411.    /* if we get here, it's a pass-through shader */
  412.    return TRUE;
  413. }
  414.