Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2008 VMware, Inc.
  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 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.  * 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 KILL_IF 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 numImmed;
  184.    uint coordOrigin;
  185.    unsigned fixedUnit;
  186.    bool hasFixedUnit;
  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 transform prolog
  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.  *   KILL_IF -texTemp;   # if -texTemp < 0, kill fragment
  256.  *   [...original code...]
  257.  */
  258. static void
  259. pstip_transform_prolog(struct tgsi_transform_context *ctx)
  260. {
  261.    struct pstip_transform_context *pctx =
  262.       (struct pstip_transform_context *) ctx;
  263.    int wincoordInput;
  264.    int texTemp;
  265.  
  266.    /* find free texture sampler */
  267.    pctx->freeSampler = free_bit(pctx->samplersUsed);
  268.    if (pctx->freeSampler >= PIPE_MAX_SAMPLERS)
  269.       pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
  270.  
  271.    if (pctx->wincoordInput < 0)
  272.       wincoordInput = pctx->maxInput + 1;
  273.    else
  274.       wincoordInput = pctx->wincoordInput;
  275.  
  276.    if (pctx->wincoordInput < 0) {
  277.       /* declare new position input reg */
  278.       tgsi_transform_input_decl(ctx, wincoordInput,
  279.                                 TGSI_SEMANTIC_POSITION, 1,
  280.                                 TGSI_INTERPOLATE_LINEAR);
  281.    }
  282.  
  283.    /* declare new sampler */
  284.    tgsi_transform_sampler_decl(ctx,
  285.          pctx->hasFixedUnit ? pctx->fixedUnit : pctx->freeSampler);
  286.  
  287.    /* Declare temp[0] reg if not already declared.
  288.     * We can always use temp[0] since this code is before
  289.     * the rest of the shader.
  290.     */
  291.    texTemp = 0;
  292.    if ((pctx->tempsUsed & (1 << texTemp)) == 0) {
  293.       tgsi_transform_temp_decl(ctx, texTemp);
  294.    }
  295.  
  296.    /* emit immediate = {1/32, 1/32, 1, 1}
  297.     * The index/position of this immediate will be pctx->numImmed
  298.     */
  299.    tgsi_transform_immediate_decl(ctx, 1.0/32.0, 1.0/32.0, 1.0, 1.0);
  300.  
  301.    /*
  302.     * Insert new MUL/TEX/KILL_IF instructions at start of program
  303.     * Take gl_FragCoord, divide by 32 (stipple size), sample the
  304.     * texture and kill fragment if needed.
  305.     *
  306.     * We'd like to use non-normalized texcoords to index into a RECT
  307.     * texture, but we can only use REPEAT wrap mode with normalized
  308.     * texcoords.  Darn.
  309.     */
  310.  
  311.    /* XXX invert wincoord if origin isn't lower-left... */
  312.  
  313.    /* MUL texTemp, INPUT[wincoord], 1/32; */
  314.    tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,
  315.                            TGSI_FILE_TEMPORARY, texTemp,
  316.                            TGSI_WRITEMASK_XYZW,
  317.                            TGSI_FILE_INPUT, wincoordInput,
  318.                            TGSI_FILE_IMMEDIATE, pctx->numImmed);
  319.  
  320.    /* TEX texTemp, texTemp, sampler; */
  321.    tgsi_transform_tex_2d_inst(ctx,
  322.                               TGSI_FILE_TEMPORARY, texTemp,
  323.                               TGSI_FILE_TEMPORARY, texTemp,
  324.                               pctx->hasFixedUnit ? pctx->fixedUnit
  325.                                                  : pctx->freeSampler);
  326.  
  327.    /* KILL_IF -texTemp;   # if -texTemp < 0, kill fragment */
  328.    tgsi_transform_kill_inst(ctx,
  329.                             TGSI_FILE_TEMPORARY, texTemp,
  330.                             TGSI_SWIZZLE_W);
  331. }
  332.  
  333.  
  334. /**
  335.  * Given a fragment shader, return a new fragment shader which
  336.  * samples a stipple texture and executes KILL.
  337.  *
  338.  * \param samplerUnitOut  returns the index of the sampler unit which
  339.  *                        will be used to sample the stipple texture;
  340.  *                        if NULL, the fixed unit is used
  341.  * \param fixedUnit       fixed texture unit used for the stipple texture
  342.  */
  343. struct tgsi_token *
  344. util_pstipple_create_fragment_shader(const struct tgsi_token *tokens,
  345.                                      unsigned *samplerUnitOut,
  346.                                      unsigned fixedUnit)
  347. {
  348.    struct pstip_transform_context transform;
  349.    const uint newLen = tgsi_num_tokens(tokens) + NUM_NEW_TOKENS;
  350.    struct tgsi_token *new_tokens;
  351.  
  352.    new_tokens = tgsi_alloc_tokens(newLen);
  353.    if (!new_tokens) {
  354.       return NULL;
  355.    }
  356.  
  357.    /* Setup shader transformation info/context.
  358.     */
  359.    memset(&transform, 0, sizeof(transform));
  360.    transform.wincoordInput = -1;
  361.    transform.maxInput = -1;
  362.    transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT;
  363.    transform.hasFixedUnit = !samplerUnitOut;
  364.    transform.fixedUnit = fixedUnit;
  365.    transform.base.prolog = pstip_transform_prolog;
  366.    transform.base.transform_declaration = pstip_transform_decl;
  367.    transform.base.transform_immediate = pstip_transform_immed;
  368.  
  369.    tgsi_scan_shader(tokens, &transform.info);
  370.  
  371.    transform.coordOrigin =
  372.       transform.info.properties[TGSI_PROPERTY_FS_COORD_ORIGIN];
  373.  
  374.    tgsi_transform_shader(tokens, new_tokens, newLen, &transform.base);
  375.  
  376. #if 0 /* DEBUG */
  377.    tgsi_dump(fs->tokens, 0);
  378.    tgsi_dump(new_fs->tokens, 0);
  379. #endif
  380.  
  381.    if (samplerUnitOut) {
  382.       assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
  383.       *samplerUnitOut = transform.freeSampler;
  384.    }
  385.  
  386.    return new_tokens;
  387. }
  388.