diff options
author | marha <marha@users.sourceforge.net> | 2011-07-22 08:22:17 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-07-22 08:22:17 +0200 |
commit | 91e91b72f07f4e61db17ee86c6933a7217f0e25c (patch) | |
tree | 67cfe3dfc7562d2f53e9827b979e1dbbc1acec7b /mesalib/src/gallium/auxiliary/util/u_pstipple.c | |
parent | 88101146f2ec7d53ffb793e365f05097ffd35fd3 (diff) | |
download | vcxsrv-91e91b72f07f4e61db17ee86c6933a7217f0e25c.tar.gz vcxsrv-91e91b72f07f4e61db17ee86c6933a7217f0e25c.tar.bz2 vcxsrv-91e91b72f07f4e61db17ee86c6933a7217f0e25c.zip |
mesa git update 22 July 2011
Diffstat (limited to 'mesalib/src/gallium/auxiliary/util/u_pstipple.c')
-rw-r--r-- | mesalib/src/gallium/auxiliary/util/u_pstipple.c | 891 |
1 files changed, 457 insertions, 434 deletions
diff --git a/mesalib/src/gallium/auxiliary/util/u_pstipple.c b/mesalib/src/gallium/auxiliary/util/u_pstipple.c index 27f72e967..ac0df8c1a 100644 --- a/mesalib/src/gallium/auxiliary/util/u_pstipple.c +++ b/mesalib/src/gallium/auxiliary/util/u_pstipple.c @@ -1,434 +1,457 @@ -/**************************************************************************
- *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright 2010 VMware, Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- **************************************************************************/
-
-/**
- * Polygon stipple helper module. Drivers/GPUs which don't support polygon
- * stipple natively can use this module to simulate it.
- *
- * Basically, modify fragment shader to sample the 32x32 stipple pattern
- * texture and do a fragment kill for the 'off' bits.
- *
- * This was originally a 'draw' module stage, but since we don't need
- * vertex window coords or anything, it can be a stand-alone utility module.
- *
- * Authors: Brian Paul
- */
-
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_inlines.h"
-
-#include "util/u_format.h"
-#include "util/u_memory.h"
-#include "util/u_pstipple.h"
-#include "util/u_sampler.h"
-
-#include "tgsi/tgsi_transform.h"
-#include "tgsi/tgsi_dump.h"
-
-/** Approx number of new tokens for instructions in pstip_transform_inst() */
-#define NUM_NEW_TOKENS 50
-
-
-static void
-util_pstipple_update_stipple_texture(struct pipe_context *pipe,
- struct pipe_resource *tex,
- const uint32_t pattern[32])
-{
- static const uint bit31 = 1 << 31;
- struct pipe_transfer *transfer;
- ubyte *data;
- int i, j;
-
- /* map texture memory */
- transfer = pipe_get_transfer(pipe, tex, 0, 0,
- PIPE_TRANSFER_WRITE, 0, 0, 32, 32);
- data = pipe->transfer_map(pipe, transfer);
-
- /*
- * Load alpha texture.
- * Note: 0 means keep the fragment, 255 means kill it.
- * We'll negate the texel value and use KILP which kills if value
- * is negative.
- */
- for (i = 0; i < 32; i++) {
- for (j = 0; j < 32; j++) {
- if (pattern[i] & (bit31 >> j)) {
- /* fragment "on" */
- data[i * transfer->stride + j] = 0;
- }
- else {
- /* fragment "off" */
- data[i * transfer->stride + j] = 255;
- }
- }
- }
-
- /* unmap */
- pipe->transfer_unmap(pipe, transfer);
- pipe->transfer_destroy(pipe, transfer);
-}
-
-
-/**
- * Create a 32x32 alpha8 texture that encodes the given stipple pattern.
- */
-struct pipe_resource *
-util_pstipple_create_stipple_texture(struct pipe_context *pipe,
- const uint32_t pattern[32])
-{
- struct pipe_screen *screen = pipe->screen;
- struct pipe_resource templat, *tex;
-
- memset(&templat, 0, sizeof(templat));
- templat.target = PIPE_TEXTURE_2D;
- templat.format = PIPE_FORMAT_A8_UNORM;
- templat.last_level = 0;
- templat.width0 = 32;
- templat.height0 = 32;
- templat.depth0 = 1;
- templat.array_size = 1;
- templat.bind = PIPE_BIND_SAMPLER_VIEW;
-
- tex = screen->resource_create(screen, &templat);
-
- if (tex)
- util_pstipple_update_stipple_texture(pipe, tex, pattern);
-
- return tex;
-}
-
-
-/**
- * Create sampler view to sample the stipple texture.
- */
-struct pipe_sampler_view *
-util_pstipple_create_sampler_view(struct pipe_context *pipe,
- struct pipe_resource *tex)
-{
- struct pipe_sampler_view templat, *sv;
-
- u_sampler_view_default_template(&templat, tex, tex->format);
- sv = pipe->create_sampler_view(pipe, tex, &templat);
-
- return sv;
-}
-
-
-/**
- * Create the sampler CSO that'll be used for stippling.
- */
-void *
-util_pstipple_create_sampler(struct pipe_context *pipe)
-{
- struct pipe_sampler_state templat;
- void *s;
-
- memset(&templat, 0, sizeof(templat));
- templat.wrap_s = PIPE_TEX_WRAP_REPEAT;
- templat.wrap_t = PIPE_TEX_WRAP_REPEAT;
- templat.wrap_r = PIPE_TEX_WRAP_REPEAT;
- templat.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
- templat.min_img_filter = PIPE_TEX_FILTER_NEAREST;
- templat.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
- templat.normalized_coords = 1;
- templat.min_lod = 0.0f;
- templat.max_lod = 0.0f;
-
- s = pipe->create_sampler_state(pipe, &templat);
- return s;
-}
-
-
-
-/**
- * Subclass of tgsi_transform_context, used for transforming the
- * user's fragment shader to add the extra texture sample and fragment kill
- * instructions.
- */
-struct pstip_transform_context {
- struct tgsi_transform_context base;
- uint tempsUsed; /**< bitmask */
- int wincoordInput;
- int maxInput;
- uint samplersUsed; /**< bitfield of samplers used */
- int freeSampler; /** an available sampler for the pstipple */
- int texTemp; /**< temp registers */
- int numImmed;
- boolean firstInstruction;
-};
-
-
-/**
- * TGSI declaration transform callback.
- * Look for a free sampler, a free input attrib, and two free temp regs.
- */
-static void
-pstip_transform_decl(struct tgsi_transform_context *ctx,
- struct tgsi_full_declaration *decl)
-{
- struct pstip_transform_context *pctx =
- (struct pstip_transform_context *) ctx;
-
- if (decl->Declaration.File == TGSI_FILE_SAMPLER) {
- uint i;
- for (i = decl->Range.First;
- i <= decl->Range.Last; i++) {
- pctx->samplersUsed |= 1 << i;
- }
- }
- else if (decl->Declaration.File == TGSI_FILE_INPUT) {
- pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last);
- if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION)
- pctx->wincoordInput = (int) decl->Range.First;
- }
- else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
- uint i;
- for (i = decl->Range.First;
- i <= decl->Range.Last; i++) {
- pctx->tempsUsed |= (1 << i);
- }
- }
-
- ctx->emit_declaration(ctx, decl);
-}
-
-
-static void
-pstip_transform_immed(struct tgsi_transform_context *ctx,
- struct tgsi_full_immediate *immed)
-{
- struct pstip_transform_context *pctx =
- (struct pstip_transform_context *) ctx;
- pctx->numImmed++;
-}
-
-
-/**
- * Find the lowest zero bit in the given word, or -1 if bitfield is all ones.
- */
-static int
-free_bit(uint bitfield)
-{
- return ffs(~bitfield) - 1;
-}
-
-
-/**
- * TGSI instruction transform callback.
- * Replace writes to result.color w/ a temp reg.
- * Upon END instruction, insert texture sampling code for antialiasing.
- */
-static void
-pstip_transform_inst(struct tgsi_transform_context *ctx,
- struct tgsi_full_instruction *inst)
-{
- struct pstip_transform_context *pctx =
- (struct pstip_transform_context *) ctx;
-
- if (pctx->firstInstruction) {
- /* emit our new declarations before the first instruction */
-
- struct tgsi_full_declaration decl;
- struct tgsi_full_instruction newInst;
- uint i;
- int wincoordInput;
-
- /* find free sampler */
- pctx->freeSampler = free_bit(pctx->samplersUsed);
- if (pctx->freeSampler >= PIPE_MAX_SAMPLERS)
- pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
-
- if (pctx->wincoordInput < 0)
- wincoordInput = pctx->maxInput + 1;
- else
- wincoordInput = pctx->wincoordInput;
-
- /* find one free temp reg */
- for (i = 0; i < 32; i++) {
- if ((pctx->tempsUsed & (1 << i)) == 0) {
- /* found a free temp */
- if (pctx->texTemp < 0)
- pctx->texTemp = i;
- else
- break;
- }
- }
- assert(pctx->texTemp >= 0);
-
- if (pctx->wincoordInput < 0) {
- /* declare new position input reg */
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_INPUT;
- decl.Declaration.Interpolate = TGSI_INTERPOLATE_LINEAR;
- decl.Declaration.Semantic = 1;
- decl.Semantic.Name = TGSI_SEMANTIC_POSITION;
- decl.Semantic.Index = 0;
- decl.Range.First =
- decl.Range.Last = wincoordInput;
- ctx->emit_declaration(ctx, &decl);
- }
-
- /* declare new sampler */
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_SAMPLER;
- decl.Range.First =
- decl.Range.Last = pctx->freeSampler;
- ctx->emit_declaration(ctx, &decl);
-
- /* declare new temp regs */
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_TEMPORARY;
- decl.Range.First =
- decl.Range.Last = pctx->texTemp;
- ctx->emit_declaration(ctx, &decl);
-
- /* emit immediate = {1/32, 1/32, 1, 1}
- * The index/position of this immediate will be pctx->numImmed
- */
- {
- static const float value[4] = { 1.0/32, 1.0/32, 1.0, 1.0 };
- struct tgsi_full_immediate immed;
- uint size = 4;
- immed = tgsi_default_full_immediate();
- immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
- immed.u[0].Float = value[0];
- immed.u[1].Float = value[1];
- immed.u[2].Float = value[2];
- immed.u[3].Float = value[3];
- ctx->emit_immediate(ctx, &immed);
- }
-
- pctx->firstInstruction = FALSE;
-
-
- /*
- * Insert new MUL/TEX/KILP instructions at start of program
- * Take gl_FragCoord, divide by 32 (stipple size), sample the
- * texture and kill fragment if needed.
- *
- * We'd like to use non-normalized texcoords to index into a RECT
- * texture, but we can only use REPEAT wrap mode with normalized
- * texcoords. Darn.
- */
-
- /* XXX invert wincoord if origin isn't lower-left... */
-
- /* MUL texTemp, INPUT[wincoord], 1/32; */
- newInst = tgsi_default_full_instruction();
- newInst.Instruction.Opcode = TGSI_OPCODE_MUL;
- newInst.Instruction.NumDstRegs = 1;
- newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Dst[0].Register.Index = pctx->texTemp;
- newInst.Instruction.NumSrcRegs = 2;
- newInst.Src[0].Register.File = TGSI_FILE_INPUT;
- newInst.Src[0].Register.Index = wincoordInput;
- newInst.Src[1].Register.File = TGSI_FILE_IMMEDIATE;
- newInst.Src[1].Register.Index = pctx->numImmed;
- ctx->emit_instruction(ctx, &newInst);
-
- /* TEX texTemp, texTemp, sampler; */
- newInst = tgsi_default_full_instruction();
- newInst.Instruction.Opcode = TGSI_OPCODE_TEX;
- newInst.Instruction.NumDstRegs = 1;
- newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Dst[0].Register.Index = pctx->texTemp;
- newInst.Instruction.NumSrcRegs = 2;
- newInst.Instruction.Texture = TRUE;
- newInst.Texture.Texture = TGSI_TEXTURE_2D;
- newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Src[0].Register.Index = pctx->texTemp;
- newInst.Src[1].Register.File = TGSI_FILE_SAMPLER;
- newInst.Src[1].Register.Index = pctx->freeSampler;
- ctx->emit_instruction(ctx, &newInst);
-
- /* KIL -texTemp; # if -texTemp < 0, KILL fragment */
- newInst = tgsi_default_full_instruction();
- newInst.Instruction.Opcode = TGSI_OPCODE_KIL;
- newInst.Instruction.NumDstRegs = 0;
- newInst.Instruction.NumSrcRegs = 1;
- newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
- newInst.Src[0].Register.Index = pctx->texTemp;
- newInst.Src[0].Register.Negate = 1;
- ctx->emit_instruction(ctx, &newInst);
- }
-
- /* emit this instruction */
- ctx->emit_instruction(ctx, inst);
-}
-
-
-/**
- * Given a fragment shader, return a new fragment shader which
- * samples a stipple texture and executes KILL.
- */
-struct pipe_shader_state *
-util_pstipple_create_fragment_shader(struct pipe_context *pipe,
- struct pipe_shader_state *fs,
- unsigned *samplerUnitOut)
-{
- struct pipe_shader_state *new_fs;
- struct pstip_transform_context transform;
- const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS;
-
- new_fs = MALLOC(sizeof(*new_fs));
- if (!new_fs)
- return NULL;
-
- new_fs->tokens = tgsi_alloc_tokens(newLen);
- if (!new_fs->tokens) {
- FREE(new_fs);
- return NULL;
- }
-
- memset(&transform, 0, sizeof(transform));
- transform.wincoordInput = -1;
- transform.maxInput = -1;
- transform.texTemp = -1;
- transform.firstInstruction = TRUE;
- transform.base.transform_instruction = pstip_transform_inst;
- transform.base.transform_declaration = pstip_transform_decl;
- transform.base.transform_immediate = pstip_transform_immed;
-
- tgsi_transform_shader(fs->tokens,
- (struct tgsi_token *) new_fs->tokens,
- newLen, &transform.base);
-
-#if 0 /* DEBUG */
- tgsi_dump(fs->tokens, 0);
- tgsi_dump(pstip_fs.tokens, 0);
-#endif
-
- assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
- *samplerUnitOut = transform.freeSampler;
-
- return new_fs;
-}
-
+/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Polygon stipple helper module. Drivers/GPUs which don't support polygon + * stipple natively can use this module to simulate it. + * + * Basically, modify fragment shader to sample the 32x32 stipple pattern + * texture and do a fragment kill for the 'off' bits. + * + * This was originally a 'draw' module stage, but since we don't need + * vertex window coords or anything, it can be a stand-alone utility module. + * + * Authors: Brian Paul + */ + + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_inlines.h" + +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_pstipple.h" +#include "util/u_sampler.h" + +#include "tgsi/tgsi_transform.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_scan.h" + +/** Approx number of new tokens for instructions in pstip_transform_inst() */ +#define NUM_NEW_TOKENS 50 + + +static void +util_pstipple_update_stipple_texture(struct pipe_context *pipe, + struct pipe_resource *tex, + const uint32_t pattern[32]) +{ + static const uint bit31 = 1 << 31; + struct pipe_transfer *transfer; + ubyte *data; + int i, j; + + /* map texture memory */ + transfer = pipe_get_transfer(pipe, tex, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, 32, 32); + data = pipe->transfer_map(pipe, transfer); + + /* + * Load alpha texture. + * Note: 0 means keep the fragment, 255 means kill it. + * We'll negate the texel value and use KILP which kills if value + * is negative. + */ + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + if (pattern[i] & (bit31 >> j)) { + /* fragment "on" */ + data[i * transfer->stride + j] = 0; + } + else { + /* fragment "off" */ + data[i * transfer->stride + j] = 255; + } + } + } + + /* unmap */ + pipe->transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); +} + + +/** + * Create a 32x32 alpha8 texture that encodes the given stipple pattern. + */ +struct pipe_resource * +util_pstipple_create_stipple_texture(struct pipe_context *pipe, + const uint32_t pattern[32]) +{ + struct pipe_screen *screen = pipe->screen; + struct pipe_resource templat, *tex; + + memset(&templat, 0, sizeof(templat)); + templat.target = PIPE_TEXTURE_2D; + templat.format = PIPE_FORMAT_A8_UNORM; + templat.last_level = 0; + templat.width0 = 32; + templat.height0 = 32; + templat.depth0 = 1; + templat.array_size = 1; + templat.bind = PIPE_BIND_SAMPLER_VIEW; + + tex = screen->resource_create(screen, &templat); + + if (tex) + util_pstipple_update_stipple_texture(pipe, tex, pattern); + + return tex; +} + + +/** + * Create sampler view to sample the stipple texture. + */ +struct pipe_sampler_view * +util_pstipple_create_sampler_view(struct pipe_context *pipe, + struct pipe_resource *tex) +{ + struct pipe_sampler_view templat, *sv; + + u_sampler_view_default_template(&templat, tex, tex->format); + sv = pipe->create_sampler_view(pipe, tex, &templat); + + return sv; +} + + +/** + * Create the sampler CSO that'll be used for stippling. + */ +void * +util_pstipple_create_sampler(struct pipe_context *pipe) +{ + struct pipe_sampler_state templat; + void *s; + + memset(&templat, 0, sizeof(templat)); + templat.wrap_s = PIPE_TEX_WRAP_REPEAT; + templat.wrap_t = PIPE_TEX_WRAP_REPEAT; + templat.wrap_r = PIPE_TEX_WRAP_REPEAT; + templat.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + templat.min_img_filter = PIPE_TEX_FILTER_NEAREST; + templat.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + templat.normalized_coords = 1; + templat.min_lod = 0.0f; + templat.max_lod = 0.0f; + + s = pipe->create_sampler_state(pipe, &templat); + return s; +} + + + +/** + * Subclass of tgsi_transform_context, used for transforming the + * user's fragment shader to add the extra texture sample and fragment kill + * instructions. + */ +struct pstip_transform_context { + struct tgsi_transform_context base; + struct tgsi_shader_info info; + uint tempsUsed; /**< bitmask */ + int wincoordInput; + int maxInput; + uint samplersUsed; /**< bitfield of samplers used */ + int freeSampler; /** an available sampler for the pstipple */ + int texTemp; /**< temp registers */ + int numImmed; + boolean firstInstruction; + uint coordOrigin; +}; + + +/** + * TGSI declaration transform callback. + * Track samplers used, temps used, inputs used. + */ +static void +pstip_transform_decl(struct tgsi_transform_context *ctx, + struct tgsi_full_declaration *decl) +{ + struct pstip_transform_context *pctx = + (struct pstip_transform_context *) ctx; + + /* XXX we can use tgsi_shader_info instead of some of this */ + + if (decl->Declaration.File == TGSI_FILE_SAMPLER) { + uint i; + for (i = decl->Range.First; i <= decl->Range.Last; i++) { + pctx->samplersUsed |= 1 << i; + } + } + else if (decl->Declaration.File == TGSI_FILE_INPUT) { + pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last); + if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) + pctx->wincoordInput = (int) decl->Range.First; + } + else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { + uint i; + for (i = decl->Range.First; i <= decl->Range.Last; i++) { + pctx->tempsUsed |= (1 << i); + } + } + + ctx->emit_declaration(ctx, decl); +} + + +static void +pstip_transform_immed(struct tgsi_transform_context *ctx, + struct tgsi_full_immediate *immed) +{ + struct pstip_transform_context *pctx = + (struct pstip_transform_context *) ctx; + pctx->numImmed++; +} + + +/** + * Find the lowest zero bit in the given word, or -1 if bitfield is all ones. + */ +static int +free_bit(uint bitfield) +{ + return ffs(~bitfield) - 1; +} + + +/** + * TGSI instruction transform callback. + * Before the first instruction, insert our new code to sample the + * stipple texture (using the fragment coord register) then kill the + * fragment if the stipple texture bit is off. + * + * Insert: + * declare new registers + * MUL texTemp, INPUT[wincoord], 1/32; + * TEX texTemp, texTemp, sampler; + * KIL -texTemp; # if -texTemp < 0, KILL fragment + * [...original code...] + */ +static void +pstip_transform_inst(struct tgsi_transform_context *ctx, + struct tgsi_full_instruction *inst) +{ + struct pstip_transform_context *pctx = + (struct pstip_transform_context *) ctx; + + if (pctx->firstInstruction) { + /* emit our new declarations before the first instruction */ + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction newInst; + uint i; + int wincoordInput; + + /* find free texture sampler */ + pctx->freeSampler = free_bit(pctx->samplersUsed); + if (pctx->freeSampler >= PIPE_MAX_SAMPLERS) + pctx->freeSampler = PIPE_MAX_SAMPLERS - 1; + + if (pctx->wincoordInput < 0) + wincoordInput = pctx->maxInput + 1; + else + wincoordInput = pctx->wincoordInput; + + /* find one free temp register */ + for (i = 0; i < 32; i++) { + if ((pctx->tempsUsed & (1 << i)) == 0) { + /* found a free temp */ + if (pctx->texTemp < 0) + pctx->texTemp = i; + else + break; + } + } + assert(pctx->texTemp >= 0); + + if (pctx->wincoordInput < 0) { + /* declare new position input reg */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Interpolate = TGSI_INTERPOLATE_LINEAR; + decl.Declaration.Semantic = 1; + decl.Semantic.Name = TGSI_SEMANTIC_POSITION; + decl.Semantic.Index = 0; + decl.Range.First = + decl.Range.Last = wincoordInput; + ctx->emit_declaration(ctx, &decl); + } + + /* declare new sampler */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.Range.First = + decl.Range.Last = pctx->freeSampler; + ctx->emit_declaration(ctx, &decl); + + /* declare new temp regs */ + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_TEMPORARY; + decl.Range.First = + decl.Range.Last = pctx->texTemp; + ctx->emit_declaration(ctx, &decl); + + /* emit immediate = {1/32, 1/32, 1, 1} + * The index/position of this immediate will be pctx->numImmed + */ + { + static const float value[4] = { 1.0/32, 1.0/32, 1.0, 1.0 }; + struct tgsi_full_immediate immed; + uint size = 4; + immed = tgsi_default_full_immediate(); + immed.Immediate.NrTokens = 1 + size; /* one for the token itself */ + immed.u[0].Float = value[0]; + immed.u[1].Float = value[1]; + immed.u[2].Float = value[2]; + immed.u[3].Float = value[3]; + ctx->emit_immediate(ctx, &immed); + } + + pctx->firstInstruction = FALSE; + + + /* + * Insert new MUL/TEX/KILP instructions at start of program + * Take gl_FragCoord, divide by 32 (stipple size), sample the + * texture and kill fragment if needed. + * + * We'd like to use non-normalized texcoords to index into a RECT + * texture, but we can only use REPEAT wrap mode with normalized + * texcoords. Darn. + */ + + /* XXX invert wincoord if origin isn't lower-left... */ + + /* MUL texTemp, INPUT[wincoord], 1/32; */ + newInst = tgsi_default_full_instruction(); + newInst.Instruction.Opcode = TGSI_OPCODE_MUL; + newInst.Instruction.NumDstRegs = 1; + newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Dst[0].Register.Index = pctx->texTemp; + newInst.Instruction.NumSrcRegs = 2; + newInst.Src[0].Register.File = TGSI_FILE_INPUT; + newInst.Src[0].Register.Index = wincoordInput; + newInst.Src[1].Register.File = TGSI_FILE_IMMEDIATE; + newInst.Src[1].Register.Index = pctx->numImmed; + ctx->emit_instruction(ctx, &newInst); + + /* TEX texTemp, texTemp, sampler; */ + newInst = tgsi_default_full_instruction(); + newInst.Instruction.Opcode = TGSI_OPCODE_TEX; + newInst.Instruction.NumDstRegs = 1; + newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Dst[0].Register.Index = pctx->texTemp; + newInst.Instruction.NumSrcRegs = 2; + newInst.Instruction.Texture = TRUE; + newInst.Texture.Texture = TGSI_TEXTURE_2D; + newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Src[0].Register.Index = pctx->texTemp; + newInst.Src[1].Register.File = TGSI_FILE_SAMPLER; + newInst.Src[1].Register.Index = pctx->freeSampler; + ctx->emit_instruction(ctx, &newInst); + + /* KIL -texTemp; # if -texTemp < 0, KILL fragment */ + newInst = tgsi_default_full_instruction(); + newInst.Instruction.Opcode = TGSI_OPCODE_KIL; + newInst.Instruction.NumDstRegs = 0; + newInst.Instruction.NumSrcRegs = 1; + newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; + newInst.Src[0].Register.Index = pctx->texTemp; + newInst.Src[0].Register.Negate = 1; + ctx->emit_instruction(ctx, &newInst); + } + + /* emit this instruction */ + ctx->emit_instruction(ctx, inst); +} + + +/** + * Given a fragment shader, return a new fragment shader which + * samples a stipple texture and executes KILL. + */ +struct pipe_shader_state * +util_pstipple_create_fragment_shader(struct pipe_context *pipe, + struct pipe_shader_state *fs, + unsigned *samplerUnitOut) +{ + struct pipe_shader_state *new_fs; + struct pstip_transform_context transform; + const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS; + unsigned i; + + new_fs = MALLOC(sizeof(*new_fs)); + if (!new_fs) + return NULL; + + new_fs->tokens = tgsi_alloc_tokens(newLen); + if (!new_fs->tokens) { + FREE(new_fs); + return NULL; + } + + /* Setup shader transformation info/context. + */ + memset(&transform, 0, sizeof(transform)); + transform.wincoordInput = -1; + transform.maxInput = -1; + transform.texTemp = -1; + transform.firstInstruction = TRUE; + transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT; + transform.base.transform_instruction = pstip_transform_inst; + transform.base.transform_declaration = pstip_transform_decl; + transform.base.transform_immediate = pstip_transform_immed; + + tgsi_scan_shader(fs->tokens, &transform.info); + + /* find fragment coordinate origin property */ + for (i = 0; i < transform.info.num_properties; i++) { + if (transform.info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN) + transform.coordOrigin = transform.info.properties[i].data[0]; + } + + tgsi_transform_shader(fs->tokens, + (struct tgsi_token *) new_fs->tokens, + newLen, &transform.base); + +#if 0 /* DEBUG */ + tgsi_dump(fs->tokens, 0); + tgsi_dump(new_fs->tokens, 0); +#endif + + assert(transform.freeSampler < PIPE_MAX_SAMPLERS); + *samplerUnitOut = transform.freeSampler; + + return new_fs; +} + |