Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
  4.  * Copyright 2010 VMware, Inc.
  5.  * 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 TUNGSTEN GRAPHICS 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.  * Polygon stipple helper module.  Drivers/GPUs which don't support polygon
  31.  * stipple natively can use this module to simulate it.
  32.  *
  33.  * Basically, modify fragment shader to sample the 32x32 stipple pattern
  34.  * texture and do a fragment kill for the 'off' bits.
  35.  *
  36.  * This was originally a 'draw' module stage, but since we don't need
  37.  * vertex window coords or anything, it can be a stand-alone utility module.
  38.  *
  39.  * Authors:  Brian Paul
  40.  */
  41.  
  42.  
  43. #include "pipe/p_context.h"
  44. #include "pipe/p_defines.h"
  45. #include "pipe/p_shader_tokens.h"
  46. #include "util/u_inlines.h"
  47.  
  48. #include "util/u_format.h"
  49. #include "util/u_memory.h"
  50. #include "util/u_pstipple.h"
  51. #include "util/u_sampler.h"
  52.  
  53. #include "tgsi/tgsi_transform.h"
  54. #include "tgsi/tgsi_dump.h"
  55. #include "tgsi/tgsi_scan.h"
  56.  
  57. /** Approx number of new tokens for instructions in pstip_transform_inst() */
  58. #define NUM_NEW_TOKENS 50
  59.  
  60.  
  61. static void
  62. util_pstipple_update_stipple_texture(struct pipe_context *pipe,
  63.                                      struct pipe_resource *tex,
  64.                                      const uint32_t pattern[32])
  65. {
  66.    static const uint bit31 = 1 << 31;
  67.    struct pipe_transfer *transfer;
  68.    ubyte *data;
  69.    int i, j;
  70.  
  71.    /* map texture memory */
  72.    data = pipe_transfer_map(pipe, tex, 0, 0,
  73.                             PIPE_TRANSFER_WRITE, 0, 0, 32, 32, &transfer);
  74.  
  75.    /*
  76.     * Load alpha texture.
  77.     * Note: 0 means keep the fragment, 255 means kill it.
  78.     * We'll negate the texel value and use KILP which kills if value
  79.     * is negative.
  80.     */
  81.    for (i = 0; i < 32; i++) {
  82.       for (j = 0; j < 32; j++) {
  83.          if (pattern[i] & (bit31 >> j)) {
  84.             /* fragment "on" */
  85.             data[i * transfer->stride + j] = 0;
  86.          }
  87.          else {
  88.             /* fragment "off" */
  89.             data[i * transfer->stride + j] = 255;
  90.          }
  91.       }
  92.    }
  93.  
  94.    /* unmap */
  95.    pipe->transfer_unmap(pipe, transfer);
  96. }
  97.  
  98.  
  99. /**
  100.  * Create a 32x32 alpha8 texture that encodes the given stipple pattern.
  101.  */
  102. struct pipe_resource *
  103. util_pstipple_create_stipple_texture(struct pipe_context *pipe,
  104.                                      const uint32_t pattern[32])
  105. {
  106.    struct pipe_screen *screen = pipe->screen;
  107.    struct pipe_resource templat, *tex;
  108.  
  109.    memset(&templat, 0, sizeof(templat));
  110.    templat.target = PIPE_TEXTURE_2D;
  111.    templat.format = PIPE_FORMAT_A8_UNORM;
  112.    templat.last_level = 0;
  113.    templat.width0 = 32;
  114.    templat.height0 = 32;
  115.    templat.depth0 = 1;
  116.    templat.array_size = 1;
  117.    templat.bind = PIPE_BIND_SAMPLER_VIEW;
  118.  
  119.    tex = screen->resource_create(screen, &templat);
  120.  
  121.    if (tex)
  122.       util_pstipple_update_stipple_texture(pipe, tex, pattern);
  123.  
  124.    return tex;
  125. }
  126.  
  127.  
  128. /**
  129.  * Create sampler view to sample the stipple texture.
  130.  */
  131. struct pipe_sampler_view *
  132. util_pstipple_create_sampler_view(struct pipe_context *pipe,
  133.                                   struct pipe_resource *tex)
  134. {
  135.    struct pipe_sampler_view templat, *sv;
  136.  
  137.    u_sampler_view_default_template(&templat, tex, tex->format);
  138.    sv = pipe->create_sampler_view(pipe, tex, &templat);
  139.  
  140.    return sv;
  141. }
  142.  
  143.  
  144. /**
  145.  * Create the sampler CSO that'll be used for stippling.
  146.  */
  147. void *
  148. util_pstipple_create_sampler(struct pipe_context *pipe)
  149. {
  150.    struct pipe_sampler_state templat;
  151.    void *s;
  152.  
  153.    memset(&templat, 0, sizeof(templat));
  154.    templat.wrap_s = PIPE_TEX_WRAP_REPEAT;
  155.    templat.wrap_t = PIPE_TEX_WRAP_REPEAT;
  156.    templat.wrap_r = PIPE_TEX_WRAP_REPEAT;
  157.    templat.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
  158.    templat.min_img_filter = PIPE_TEX_FILTER_NEAREST;
  159.    templat.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
  160.    templat.normalized_coords = 1;
  161.    templat.min_lod = 0.0f;
  162.    templat.max_lod = 0.0f;
  163.  
  164.    s = pipe->create_sampler_state(pipe, &templat);
  165.    return s;
  166. }
  167.  
  168.  
  169.  
  170. /**
  171.  * Subclass of tgsi_transform_context, used for transforming the
  172.  * user's fragment shader to add the extra texture sample and fragment kill
  173.  * instructions.
  174.  */
  175. struct pstip_transform_context {
  176.    struct tgsi_transform_context base;
  177.    struct tgsi_shader_info info;
  178.    uint tempsUsed;  /**< bitmask */
  179.    int wincoordInput;
  180.    int maxInput;
  181.    uint samplersUsed;  /**< bitfield of samplers used */
  182.    int freeSampler;  /** an available sampler for the pstipple */
  183.    int texTemp;  /**< temp registers */
  184.    int numImmed;
  185.    boolean firstInstruction;
  186.    uint coordOrigin;
  187. };
  188.  
  189.  
  190. /**
  191.  * TGSI declaration transform callback.
  192.  * Track samplers used, temps used, inputs used.
  193.  */
  194. static void
  195. pstip_transform_decl(struct tgsi_transform_context *ctx,
  196.                      struct tgsi_full_declaration *decl)
  197. {
  198.    struct pstip_transform_context *pctx =
  199.       (struct pstip_transform_context *) ctx;
  200.  
  201.    /* XXX we can use tgsi_shader_info instead of some of this */
  202.  
  203.    if (decl->Declaration.File == TGSI_FILE_SAMPLER) {
  204.       uint i;
  205.       for (i = decl->Range.First; i <= decl->Range.Last; i++) {
  206.          pctx->samplersUsed |= 1 << i;
  207.       }
  208.    }
  209.    else if (decl->Declaration.File == TGSI_FILE_INPUT) {
  210.       pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last);
  211.       if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION)
  212.          pctx->wincoordInput = (int) decl->Range.First;
  213.    }
  214.    else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
  215.       uint i;
  216.       for (i = decl->Range.First; i <= decl->Range.Last; i++) {
  217.          pctx->tempsUsed |= (1 << i);
  218.       }
  219.    }
  220.  
  221.    ctx->emit_declaration(ctx, decl);
  222. }
  223.  
  224.  
  225. static void
  226. pstip_transform_immed(struct tgsi_transform_context *ctx,
  227.                       struct tgsi_full_immediate *immed)
  228. {
  229.    struct pstip_transform_context *pctx =
  230.       (struct pstip_transform_context *) ctx;
  231.    pctx->numImmed++;
  232. }
  233.  
  234.  
  235. /**
  236.  * Find the lowest zero bit in the given word, or -1 if bitfield is all ones.
  237.  */
  238. static int
  239. free_bit(uint bitfield)
  240. {
  241.    return ffs(~bitfield) - 1;
  242. }
  243.  
  244.  
  245. /**
  246.  * TGSI instruction transform callback.
  247.  * Before the first instruction, insert our new code to sample the
  248.  * stipple texture (using the fragment coord register) then kill the
  249.  * fragment if the stipple texture bit is off.
  250.  *
  251.  * Insert:
  252.  *   declare new registers
  253.  *   MUL texTemp, INPUT[wincoord], 1/32;
  254.  *   TEX texTemp, texTemp, sampler;
  255.  *   KIL -texTemp;   # if -texTemp < 0, KILL fragment
  256.  *   [...original code...]
  257.  */
  258. static void
  259. pstip_transform_inst(struct tgsi_transform_context *ctx,
  260.                      struct tgsi_full_instruction *inst)
  261. {
  262.    struct pstip_transform_context *pctx =
  263.       (struct pstip_transform_context *) ctx;
  264.  
  265.    if (pctx->firstInstruction) {
  266.       /* emit our new declarations before the first instruction */
  267.  
  268.       struct tgsi_full_declaration decl;
  269.       struct tgsi_full_instruction newInst;
  270.       uint i;
  271.       int wincoordInput;
  272.  
  273.       /* find free texture sampler */
  274.       pctx->freeSampler = free_bit(pctx->samplersUsed);
  275.       if (pctx->freeSampler >= PIPE_MAX_SAMPLERS)
  276.          pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
  277.  
  278.       if (pctx->wincoordInput < 0)
  279.          wincoordInput = pctx->maxInput + 1;
  280.       else
  281.          wincoordInput = pctx->wincoordInput;
  282.  
  283.       /* find one free temp register */
  284.       for (i = 0; i < 32; i++) {
  285.          if ((pctx->tempsUsed & (1 << i)) == 0) {
  286.             /* found a free temp */
  287.             if (pctx->texTemp < 0)
  288.                pctx->texTemp  = i;
  289.             else
  290.                break;
  291.          }
  292.       }
  293.       assert(pctx->texTemp >= 0);
  294.  
  295.       if (pctx->wincoordInput < 0) {
  296.          /* declare new position input reg */
  297.          decl = tgsi_default_full_declaration();
  298.          decl.Declaration.File = TGSI_FILE_INPUT;
  299.          decl.Declaration.Interpolate = 1;
  300.          decl.Declaration.Semantic = 1;
  301.          decl.Semantic.Name = TGSI_SEMANTIC_POSITION;
  302.          decl.Semantic.Index = 0;
  303.          decl.Range.First =
  304.             decl.Range.Last = wincoordInput;
  305.          decl.Interp.Interpolate = TGSI_INTERPOLATE_LINEAR;
  306.          ctx->emit_declaration(ctx, &decl);
  307.       }
  308.  
  309.       /* declare new sampler */
  310.       decl = tgsi_default_full_declaration();
  311.       decl.Declaration.File = TGSI_FILE_SAMPLER;
  312.       decl.Range.First =
  313.       decl.Range.Last = pctx->freeSampler;
  314.       ctx->emit_declaration(ctx, &decl);
  315.  
  316.       /* declare new temp regs */
  317.       decl = tgsi_default_full_declaration();
  318.       decl.Declaration.File = TGSI_FILE_TEMPORARY;
  319.       decl.Range.First =
  320.       decl.Range.Last = pctx->texTemp;
  321.       ctx->emit_declaration(ctx, &decl);
  322.  
  323.       /* emit immediate = {1/32, 1/32, 1, 1}
  324.        * The index/position of this immediate will be pctx->numImmed
  325.        */
  326.       {
  327.          static const float value[4] = { 1.0/32, 1.0/32, 1.0, 1.0 };
  328.          struct tgsi_full_immediate immed;
  329.          uint size = 4;
  330.          immed = tgsi_default_full_immediate();
  331.          immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
  332.          immed.u[0].Float = value[0];
  333.          immed.u[1].Float = value[1];
  334.          immed.u[2].Float = value[2];
  335.          immed.u[3].Float = value[3];
  336.          ctx->emit_immediate(ctx, &immed);
  337.       }
  338.  
  339.       pctx->firstInstruction = FALSE;
  340.  
  341.  
  342.       /*
  343.        * Insert new MUL/TEX/KILP instructions at start of program
  344.        * Take gl_FragCoord, divide by 32 (stipple size), sample the
  345.        * texture and kill fragment if needed.
  346.        *
  347.        * We'd like to use non-normalized texcoords to index into a RECT
  348.        * texture, but we can only use REPEAT wrap mode with normalized
  349.        * texcoords.  Darn.
  350.        */
  351.  
  352.       /* XXX invert wincoord if origin isn't lower-left... */
  353.  
  354.       /* MUL texTemp, INPUT[wincoord], 1/32; */
  355.       newInst = tgsi_default_full_instruction();
  356.       newInst.Instruction.Opcode = TGSI_OPCODE_MUL;
  357.       newInst.Instruction.NumDstRegs = 1;
  358.       newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
  359.       newInst.Dst[0].Register.Index = pctx->texTemp;
  360.       newInst.Instruction.NumSrcRegs = 2;
  361.       newInst.Src[0].Register.File = TGSI_FILE_INPUT;
  362.       newInst.Src[0].Register.Index = wincoordInput;
  363.       newInst.Src[1].Register.File = TGSI_FILE_IMMEDIATE;
  364.       newInst.Src[1].Register.Index = pctx->numImmed;
  365.       ctx->emit_instruction(ctx, &newInst);
  366.  
  367.       /* TEX texTemp, texTemp, sampler; */
  368.       newInst = tgsi_default_full_instruction();
  369.       newInst.Instruction.Opcode = TGSI_OPCODE_TEX;
  370.       newInst.Instruction.NumDstRegs = 1;
  371.       newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
  372.       newInst.Dst[0].Register.Index = pctx->texTemp;
  373.       newInst.Instruction.NumSrcRegs = 2;
  374.       newInst.Instruction.Texture = TRUE;
  375.       newInst.Texture.Texture = TGSI_TEXTURE_2D;
  376.       newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
  377.       newInst.Src[0].Register.Index = pctx->texTemp;
  378.       newInst.Src[1].Register.File = TGSI_FILE_SAMPLER;
  379.       newInst.Src[1].Register.Index = pctx->freeSampler;
  380.       ctx->emit_instruction(ctx, &newInst);
  381.  
  382.       /* KIL -texTemp;   # if -texTemp < 0, KILL fragment */
  383.       newInst = tgsi_default_full_instruction();
  384.       newInst.Instruction.Opcode = TGSI_OPCODE_KIL;
  385.       newInst.Instruction.NumDstRegs = 0;
  386.       newInst.Instruction.NumSrcRegs = 1;
  387.       newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
  388.       newInst.Src[0].Register.Index = pctx->texTemp;
  389.       newInst.Src[0].Register.Negate = 1;
  390.       ctx->emit_instruction(ctx, &newInst);
  391.    }
  392.  
  393.    /* emit this instruction */
  394.    ctx->emit_instruction(ctx, inst);
  395. }
  396.  
  397.  
  398. /**
  399.  * Given a fragment shader, return a new fragment shader which
  400.  * samples a stipple texture and executes KILL.
  401.  */
  402. struct pipe_shader_state *
  403. util_pstipple_create_fragment_shader(struct pipe_context *pipe,
  404.                                      struct pipe_shader_state *fs,
  405.                                      unsigned *samplerUnitOut)
  406. {
  407.    struct pipe_shader_state *new_fs;
  408.    struct pstip_transform_context transform;
  409.    const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS;
  410.    unsigned i;
  411.  
  412.    new_fs = MALLOC(sizeof(*new_fs));
  413.    if (!new_fs)
  414.       return NULL;
  415.  
  416.    new_fs->tokens = tgsi_alloc_tokens(newLen);
  417.    if (!new_fs->tokens) {
  418.       FREE(new_fs);
  419.       return NULL;
  420.    }
  421.  
  422.    /* Setup shader transformation info/context.
  423.     */
  424.    memset(&transform, 0, sizeof(transform));
  425.    transform.wincoordInput = -1;
  426.    transform.maxInput = -1;
  427.    transform.texTemp = -1;
  428.    transform.firstInstruction = TRUE;
  429.    transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT;
  430.    transform.base.transform_instruction = pstip_transform_inst;
  431.    transform.base.transform_declaration = pstip_transform_decl;
  432.    transform.base.transform_immediate = pstip_transform_immed;
  433.  
  434.    tgsi_scan_shader(fs->tokens, &transform.info);
  435.  
  436.    /* find fragment coordinate origin property */
  437.    for (i = 0; i < transform.info.num_properties; i++) {
  438.       if (transform.info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN)
  439.          transform.coordOrigin = transform.info.properties[i].data[0];
  440.    }
  441.  
  442.    tgsi_transform_shader(fs->tokens,
  443.                          (struct tgsi_token *) new_fs->tokens,
  444.                          newLen, &transform.base);
  445.  
  446. #if 0 /* DEBUG */
  447.    tgsi_dump(fs->tokens, 0);
  448.    tgsi_dump(new_fs->tokens, 0);
  449. #endif
  450.  
  451.    assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
  452.    *samplerUnitOut = transform.freeSampler;
  453.  
  454.    return new_fs;
  455. }
  456.  
  457.