13464ebd5Sriastradh/************************************************************************** 23464ebd5Sriastradh * 3af69d88dSmrg * Copyright 2008 VMware, Inc. 43464ebd5Sriastradh * Copyright 2010 VMware, Inc. 53464ebd5Sriastradh * All Rights Reserved. 63464ebd5Sriastradh * 73464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 83464ebd5Sriastradh * copy of this software and associated documentation files (the 93464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including 103464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish, 113464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to 123464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to 133464ebd5Sriastradh * the following conditions: 143464ebd5Sriastradh * 153464ebd5Sriastradh * The above copyright notice and this permission notice (including the 163464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions 173464ebd5Sriastradh * of the Software. 183464ebd5Sriastradh * 193464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 203464ebd5Sriastradh * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 213464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22af69d88dSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 233464ebd5Sriastradh * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 243464ebd5Sriastradh * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 253464ebd5Sriastradh * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 263464ebd5Sriastradh * 273464ebd5Sriastradh **************************************************************************/ 283464ebd5Sriastradh 293464ebd5Sriastradh/** 303464ebd5Sriastradh * Polygon stipple helper module. Drivers/GPUs which don't support polygon 313464ebd5Sriastradh * stipple natively can use this module to simulate it. 323464ebd5Sriastradh * 333464ebd5Sriastradh * Basically, modify fragment shader to sample the 32x32 stipple pattern 343464ebd5Sriastradh * texture and do a fragment kill for the 'off' bits. 353464ebd5Sriastradh * 363464ebd5Sriastradh * This was originally a 'draw' module stage, but since we don't need 373464ebd5Sriastradh * vertex window coords or anything, it can be a stand-alone utility module. 383464ebd5Sriastradh * 393464ebd5Sriastradh * Authors: Brian Paul 403464ebd5Sriastradh */ 413464ebd5Sriastradh 423464ebd5Sriastradh 433464ebd5Sriastradh#include "pipe/p_context.h" 443464ebd5Sriastradh#include "pipe/p_defines.h" 453464ebd5Sriastradh#include "pipe/p_shader_tokens.h" 463464ebd5Sriastradh#include "util/u_inlines.h" 473464ebd5Sriastradh 487ec681f3Smrg#include "util/format/u_format.h" 493464ebd5Sriastradh#include "util/u_memory.h" 503464ebd5Sriastradh#include "util/u_pstipple.h" 513464ebd5Sriastradh#include "util/u_sampler.h" 523464ebd5Sriastradh 533464ebd5Sriastradh#include "tgsi/tgsi_transform.h" 543464ebd5Sriastradh#include "tgsi/tgsi_dump.h" 55af69d88dSmrg#include "tgsi/tgsi_scan.h" 563464ebd5Sriastradh 573464ebd5Sriastradh/** Approx number of new tokens for instructions in pstip_transform_inst() */ 5801e04c3fSmrg#define NUM_NEW_TOKENS 53 593464ebd5Sriastradh 603464ebd5Sriastradh 6101e04c3fSmrgvoid 623464ebd5Sriastradhutil_pstipple_update_stipple_texture(struct pipe_context *pipe, 633464ebd5Sriastradh struct pipe_resource *tex, 643464ebd5Sriastradh const uint32_t pattern[32]) 653464ebd5Sriastradh{ 6601e04c3fSmrg static const uint bit31 = 1u << 31; 673464ebd5Sriastradh struct pipe_transfer *transfer; 683464ebd5Sriastradh ubyte *data; 693464ebd5Sriastradh int i, j; 703464ebd5Sriastradh 713464ebd5Sriastradh /* map texture memory */ 727ec681f3Smrg data = pipe_texture_map(pipe, tex, 0, 0, 737ec681f3Smrg PIPE_MAP_WRITE, 0, 0, 32, 32, &transfer); 743464ebd5Sriastradh 753464ebd5Sriastradh /* 763464ebd5Sriastradh * Load alpha texture. 773464ebd5Sriastradh * Note: 0 means keep the fragment, 255 means kill it. 78af69d88dSmrg * We'll negate the texel value and use KILL_IF which kills if value 793464ebd5Sriastradh * is negative. 803464ebd5Sriastradh */ 813464ebd5Sriastradh for (i = 0; i < 32; i++) { 823464ebd5Sriastradh for (j = 0; j < 32; j++) { 833464ebd5Sriastradh if (pattern[i] & (bit31 >> j)) { 843464ebd5Sriastradh /* fragment "on" */ 853464ebd5Sriastradh data[i * transfer->stride + j] = 0; 863464ebd5Sriastradh } 873464ebd5Sriastradh else { 883464ebd5Sriastradh /* fragment "off" */ 893464ebd5Sriastradh data[i * transfer->stride + j] = 255; 903464ebd5Sriastradh } 913464ebd5Sriastradh } 923464ebd5Sriastradh } 933464ebd5Sriastradh 943464ebd5Sriastradh /* unmap */ 957ec681f3Smrg pipe->texture_unmap(pipe, transfer); 963464ebd5Sriastradh} 973464ebd5Sriastradh 983464ebd5Sriastradh 993464ebd5Sriastradh/** 1003464ebd5Sriastradh * Create a 32x32 alpha8 texture that encodes the given stipple pattern. 1013464ebd5Sriastradh */ 1023464ebd5Sriastradhstruct pipe_resource * 1033464ebd5Sriastradhutil_pstipple_create_stipple_texture(struct pipe_context *pipe, 1043464ebd5Sriastradh const uint32_t pattern[32]) 1053464ebd5Sriastradh{ 1063464ebd5Sriastradh struct pipe_screen *screen = pipe->screen; 1073464ebd5Sriastradh struct pipe_resource templat, *tex; 1083464ebd5Sriastradh 1093464ebd5Sriastradh memset(&templat, 0, sizeof(templat)); 1103464ebd5Sriastradh templat.target = PIPE_TEXTURE_2D; 1113464ebd5Sriastradh templat.format = PIPE_FORMAT_A8_UNORM; 1123464ebd5Sriastradh templat.last_level = 0; 1133464ebd5Sriastradh templat.width0 = 32; 1143464ebd5Sriastradh templat.height0 = 32; 1153464ebd5Sriastradh templat.depth0 = 1; 1163464ebd5Sriastradh templat.array_size = 1; 1173464ebd5Sriastradh templat.bind = PIPE_BIND_SAMPLER_VIEW; 1183464ebd5Sriastradh 1193464ebd5Sriastradh tex = screen->resource_create(screen, &templat); 1203464ebd5Sriastradh 12101e04c3fSmrg if (tex && pattern) 1223464ebd5Sriastradh util_pstipple_update_stipple_texture(pipe, tex, pattern); 1233464ebd5Sriastradh 1243464ebd5Sriastradh return tex; 1253464ebd5Sriastradh} 1263464ebd5Sriastradh 1273464ebd5Sriastradh 1283464ebd5Sriastradh/** 1293464ebd5Sriastradh * Create sampler view to sample the stipple texture. 1303464ebd5Sriastradh */ 1313464ebd5Sriastradhstruct pipe_sampler_view * 1323464ebd5Sriastradhutil_pstipple_create_sampler_view(struct pipe_context *pipe, 1333464ebd5Sriastradh struct pipe_resource *tex) 1343464ebd5Sriastradh{ 1353464ebd5Sriastradh struct pipe_sampler_view templat, *sv; 1363464ebd5Sriastradh 1373464ebd5Sriastradh u_sampler_view_default_template(&templat, tex, tex->format); 1383464ebd5Sriastradh sv = pipe->create_sampler_view(pipe, tex, &templat); 1393464ebd5Sriastradh 1403464ebd5Sriastradh return sv; 1413464ebd5Sriastradh} 1423464ebd5Sriastradh 1433464ebd5Sriastradh 1443464ebd5Sriastradh/** 1453464ebd5Sriastradh * Create the sampler CSO that'll be used for stippling. 1463464ebd5Sriastradh */ 1473464ebd5Sriastradhvoid * 1483464ebd5Sriastradhutil_pstipple_create_sampler(struct pipe_context *pipe) 1493464ebd5Sriastradh{ 1503464ebd5Sriastradh struct pipe_sampler_state templat; 1513464ebd5Sriastradh void *s; 1523464ebd5Sriastradh 1533464ebd5Sriastradh memset(&templat, 0, sizeof(templat)); 1543464ebd5Sriastradh templat.wrap_s = PIPE_TEX_WRAP_REPEAT; 1553464ebd5Sriastradh templat.wrap_t = PIPE_TEX_WRAP_REPEAT; 1563464ebd5Sriastradh templat.wrap_r = PIPE_TEX_WRAP_REPEAT; 1573464ebd5Sriastradh templat.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; 1583464ebd5Sriastradh templat.min_img_filter = PIPE_TEX_FILTER_NEAREST; 1593464ebd5Sriastradh templat.mag_img_filter = PIPE_TEX_FILTER_NEAREST; 1603464ebd5Sriastradh templat.normalized_coords = 1; 1613464ebd5Sriastradh templat.min_lod = 0.0f; 1623464ebd5Sriastradh templat.max_lod = 0.0f; 1633464ebd5Sriastradh 1643464ebd5Sriastradh s = pipe->create_sampler_state(pipe, &templat); 1653464ebd5Sriastradh return s; 1663464ebd5Sriastradh} 1673464ebd5Sriastradh 1683464ebd5Sriastradh 1693464ebd5Sriastradh 1703464ebd5Sriastradh/** 1713464ebd5Sriastradh * Subclass of tgsi_transform_context, used for transforming the 1723464ebd5Sriastradh * user's fragment shader to add the extra texture sample and fragment kill 1733464ebd5Sriastradh * instructions. 1743464ebd5Sriastradh */ 1753464ebd5Sriastradhstruct pstip_transform_context { 1763464ebd5Sriastradh struct tgsi_transform_context base; 177af69d88dSmrg struct tgsi_shader_info info; 1783464ebd5Sriastradh uint tempsUsed; /**< bitmask */ 1793464ebd5Sriastradh int wincoordInput; 18001e04c3fSmrg unsigned wincoordFile; 1813464ebd5Sriastradh int maxInput; 1823464ebd5Sriastradh uint samplersUsed; /**< bitfield of samplers used */ 1833464ebd5Sriastradh int freeSampler; /** an available sampler for the pstipple */ 1843464ebd5Sriastradh int numImmed; 185af69d88dSmrg uint coordOrigin; 18601e04c3fSmrg unsigned fixedUnit; 18701e04c3fSmrg bool hasFixedUnit; 1883464ebd5Sriastradh}; 1893464ebd5Sriastradh 1903464ebd5Sriastradh 1913464ebd5Sriastradh/** 1923464ebd5Sriastradh * TGSI declaration transform callback. 193af69d88dSmrg * Track samplers used, temps used, inputs used. 1943464ebd5Sriastradh */ 1953464ebd5Sriastradhstatic void 1963464ebd5Sriastradhpstip_transform_decl(struct tgsi_transform_context *ctx, 1973464ebd5Sriastradh struct tgsi_full_declaration *decl) 1983464ebd5Sriastradh{ 1993464ebd5Sriastradh struct pstip_transform_context *pctx = 2003464ebd5Sriastradh (struct pstip_transform_context *) ctx; 2013464ebd5Sriastradh 202af69d88dSmrg /* XXX we can use tgsi_shader_info instead of some of this */ 203af69d88dSmrg 2043464ebd5Sriastradh if (decl->Declaration.File == TGSI_FILE_SAMPLER) { 2053464ebd5Sriastradh uint i; 206af69d88dSmrg for (i = decl->Range.First; i <= decl->Range.Last; i++) { 20701e04c3fSmrg pctx->samplersUsed |= 1u << i; 2083464ebd5Sriastradh } 2093464ebd5Sriastradh } 21001e04c3fSmrg else if (decl->Declaration.File == pctx->wincoordFile) { 2113464ebd5Sriastradh pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last); 2123464ebd5Sriastradh if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) 2133464ebd5Sriastradh pctx->wincoordInput = (int) decl->Range.First; 2143464ebd5Sriastradh } 2153464ebd5Sriastradh else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { 2163464ebd5Sriastradh uint i; 217af69d88dSmrg for (i = decl->Range.First; i <= decl->Range.Last; i++) { 2183464ebd5Sriastradh pctx->tempsUsed |= (1 << i); 2193464ebd5Sriastradh } 2203464ebd5Sriastradh } 2213464ebd5Sriastradh 2223464ebd5Sriastradh ctx->emit_declaration(ctx, decl); 2233464ebd5Sriastradh} 2243464ebd5Sriastradh 2253464ebd5Sriastradh 2263464ebd5Sriastradhstatic void 2273464ebd5Sriastradhpstip_transform_immed(struct tgsi_transform_context *ctx, 2283464ebd5Sriastradh struct tgsi_full_immediate *immed) 2293464ebd5Sriastradh{ 2303464ebd5Sriastradh struct pstip_transform_context *pctx = 2313464ebd5Sriastradh (struct pstip_transform_context *) ctx; 2323464ebd5Sriastradh pctx->numImmed++; 23301e04c3fSmrg ctx->emit_immediate(ctx, immed); 2343464ebd5Sriastradh} 2353464ebd5Sriastradh 2363464ebd5Sriastradh 2373464ebd5Sriastradh/** 2383464ebd5Sriastradh * Find the lowest zero bit in the given word, or -1 if bitfield is all ones. 2393464ebd5Sriastradh */ 2403464ebd5Sriastradhstatic int 2413464ebd5Sriastradhfree_bit(uint bitfield) 2423464ebd5Sriastradh{ 2433464ebd5Sriastradh return ffs(~bitfield) - 1; 2443464ebd5Sriastradh} 2453464ebd5Sriastradh 2463464ebd5Sriastradh 2473464ebd5Sriastradh/** 24801e04c3fSmrg * TGSI transform prolog 249af69d88dSmrg * Before the first instruction, insert our new code to sample the 250af69d88dSmrg * stipple texture (using the fragment coord register) then kill the 251af69d88dSmrg * fragment if the stipple texture bit is off. 252af69d88dSmrg * 253af69d88dSmrg * Insert: 254af69d88dSmrg * declare new registers 255af69d88dSmrg * MUL texTemp, INPUT[wincoord], 1/32; 256af69d88dSmrg * TEX texTemp, texTemp, sampler; 257af69d88dSmrg * KILL_IF -texTemp; # if -texTemp < 0, kill fragment 258af69d88dSmrg * [...original code...] 2593464ebd5Sriastradh */ 2603464ebd5Sriastradhstatic void 26101e04c3fSmrgpstip_transform_prolog(struct tgsi_transform_context *ctx) 2623464ebd5Sriastradh{ 2633464ebd5Sriastradh struct pstip_transform_context *pctx = 2643464ebd5Sriastradh (struct pstip_transform_context *) ctx; 26501e04c3fSmrg int wincoordInput; 26601e04c3fSmrg int texTemp; 26701e04c3fSmrg int sampIdx; 26801e04c3fSmrg 26901e04c3fSmrg STATIC_ASSERT(sizeof(pctx->samplersUsed) * 8 >= PIPE_MAX_SAMPLERS); 27001e04c3fSmrg 27101e04c3fSmrg /* find free texture sampler */ 27201e04c3fSmrg pctx->freeSampler = free_bit(pctx->samplersUsed); 27301e04c3fSmrg if (pctx->freeSampler < 0 || pctx->freeSampler >= PIPE_MAX_SAMPLERS) 27401e04c3fSmrg pctx->freeSampler = PIPE_MAX_SAMPLERS - 1; 2753464ebd5Sriastradh 27601e04c3fSmrg if (pctx->wincoordInput < 0) 27701e04c3fSmrg wincoordInput = pctx->maxInput + 1; 27801e04c3fSmrg else 27901e04c3fSmrg wincoordInput = pctx->wincoordInput; 2803464ebd5Sriastradh 28101e04c3fSmrg if (pctx->wincoordInput < 0) { 2823464ebd5Sriastradh struct tgsi_full_declaration decl; 2833464ebd5Sriastradh 28401e04c3fSmrg decl = tgsi_default_full_declaration(); 28501e04c3fSmrg /* declare new position input reg */ 28601e04c3fSmrg decl.Declaration.File = pctx->wincoordFile; 28701e04c3fSmrg decl.Declaration.Semantic = 1; 28801e04c3fSmrg decl.Semantic.Name = TGSI_SEMANTIC_POSITION; 28901e04c3fSmrg decl.Range.First = 29001e04c3fSmrg decl.Range.Last = wincoordInput; 29101e04c3fSmrg 29201e04c3fSmrg if (pctx->wincoordFile == TGSI_FILE_INPUT) { 293af69d88dSmrg decl.Declaration.Interpolate = 1; 294af69d88dSmrg decl.Interp.Interpolate = TGSI_INTERPOLATE_LINEAR; 2953464ebd5Sriastradh } 2963464ebd5Sriastradh 2973464ebd5Sriastradh ctx->emit_declaration(ctx, &decl); 29801e04c3fSmrg } 2993464ebd5Sriastradh 30001e04c3fSmrg sampIdx = pctx->hasFixedUnit ? (int)pctx->fixedUnit : pctx->freeSampler; 3013464ebd5Sriastradh 30201e04c3fSmrg /* declare new sampler */ 30301e04c3fSmrg tgsi_transform_sampler_decl(ctx, sampIdx); 3043464ebd5Sriastradh 30501e04c3fSmrg /* if the src shader has SVIEW decl's for each SAMP decl, we 30601e04c3fSmrg * need to continue the trend and ensure there is a matching 30701e04c3fSmrg * SVIEW for the new SAMP we just created 30801e04c3fSmrg */ 30901e04c3fSmrg if (pctx->info.file_max[TGSI_FILE_SAMPLER_VIEW] != -1) { 31001e04c3fSmrg tgsi_transform_sampler_view_decl(ctx, 31101e04c3fSmrg sampIdx, 31201e04c3fSmrg TGSI_TEXTURE_2D, 31301e04c3fSmrg TGSI_RETURN_TYPE_FLOAT); 31401e04c3fSmrg } 31501e04c3fSmrg 31601e04c3fSmrg /* Declare temp[0] reg if not already declared. 31701e04c3fSmrg * We can always use temp[0] since this code is before 31801e04c3fSmrg * the rest of the shader. 31901e04c3fSmrg */ 32001e04c3fSmrg texTemp = 0; 32101e04c3fSmrg if ((pctx->tempsUsed & (1 << texTemp)) == 0) { 32201e04c3fSmrg tgsi_transform_temp_decl(ctx, texTemp); 3233464ebd5Sriastradh } 3243464ebd5Sriastradh 32501e04c3fSmrg /* emit immediate = {1/32, 1/32, 1, 1} 32601e04c3fSmrg * The index/position of this immediate will be pctx->numImmed 32701e04c3fSmrg */ 32801e04c3fSmrg tgsi_transform_immediate_decl(ctx, 1.0/32.0, 1.0/32.0, 1.0, 1.0); 32901e04c3fSmrg 33001e04c3fSmrg /* 33101e04c3fSmrg * Insert new MUL/TEX/KILL_IF instructions at start of program 33201e04c3fSmrg * Take gl_FragCoord, divide by 32 (stipple size), sample the 33301e04c3fSmrg * texture and kill fragment if needed. 33401e04c3fSmrg * 33501e04c3fSmrg * We'd like to use non-normalized texcoords to index into a RECT 33601e04c3fSmrg * texture, but we can only use REPEAT wrap mode with normalized 33701e04c3fSmrg * texcoords. Darn. 33801e04c3fSmrg */ 33901e04c3fSmrg 34001e04c3fSmrg /* XXX invert wincoord if origin isn't lower-left... */ 34101e04c3fSmrg 34201e04c3fSmrg /* MUL texTemp, INPUT[wincoord], 1/32; */ 34301e04c3fSmrg tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL, 34401e04c3fSmrg TGSI_FILE_TEMPORARY, texTemp, 34501e04c3fSmrg TGSI_WRITEMASK_XYZW, 34601e04c3fSmrg pctx->wincoordFile, wincoordInput, 34701e04c3fSmrg TGSI_FILE_IMMEDIATE, pctx->numImmed, false); 34801e04c3fSmrg 34901e04c3fSmrg /* TEX texTemp, texTemp, sampler, 2D; */ 35001e04c3fSmrg tgsi_transform_tex_inst(ctx, 35101e04c3fSmrg TGSI_FILE_TEMPORARY, texTemp, 35201e04c3fSmrg TGSI_FILE_TEMPORARY, texTemp, 35301e04c3fSmrg TGSI_TEXTURE_2D, sampIdx); 35401e04c3fSmrg 35501e04c3fSmrg /* KILL_IF -texTemp; # if -texTemp < 0, kill fragment */ 35601e04c3fSmrg tgsi_transform_kill_inst(ctx, 35701e04c3fSmrg TGSI_FILE_TEMPORARY, texTemp, 35801e04c3fSmrg TGSI_SWIZZLE_W, TRUE); 3593464ebd5Sriastradh} 3603464ebd5Sriastradh 3613464ebd5Sriastradh 3623464ebd5Sriastradh/** 3633464ebd5Sriastradh * Given a fragment shader, return a new fragment shader which 3643464ebd5Sriastradh * samples a stipple texture and executes KILL. 36501e04c3fSmrg * 36601e04c3fSmrg * \param samplerUnitOut returns the index of the sampler unit which 36701e04c3fSmrg * will be used to sample the stipple texture; 36801e04c3fSmrg * if NULL, the fixed unit is used 36901e04c3fSmrg * \param fixedUnit fixed texture unit used for the stipple texture 37001e04c3fSmrg * \param wincoordFile TGSI_FILE_INPUT or TGSI_FILE_SYSTEM_VALUE, 37101e04c3fSmrg * depending on which one is supported by the driver 37201e04c3fSmrg * for TGSI_SEMANTIC_POSITION in the fragment shader 3733464ebd5Sriastradh */ 37401e04c3fSmrgstruct tgsi_token * 37501e04c3fSmrgutil_pstipple_create_fragment_shader(const struct tgsi_token *tokens, 37601e04c3fSmrg unsigned *samplerUnitOut, 37701e04c3fSmrg unsigned fixedUnit, 37801e04c3fSmrg unsigned wincoordFile) 3793464ebd5Sriastradh{ 3803464ebd5Sriastradh struct pstip_transform_context transform; 38101e04c3fSmrg const uint newLen = tgsi_num_tokens(tokens) + NUM_NEW_TOKENS; 38201e04c3fSmrg struct tgsi_token *new_tokens; 3833464ebd5Sriastradh 38401e04c3fSmrg new_tokens = tgsi_alloc_tokens(newLen); 38501e04c3fSmrg if (!new_tokens) { 3863464ebd5Sriastradh return NULL; 3873464ebd5Sriastradh } 3883464ebd5Sriastradh 389af69d88dSmrg /* Setup shader transformation info/context. 390af69d88dSmrg */ 3913464ebd5Sriastradh memset(&transform, 0, sizeof(transform)); 3923464ebd5Sriastradh transform.wincoordInput = -1; 39301e04c3fSmrg transform.wincoordFile = wincoordFile; 3943464ebd5Sriastradh transform.maxInput = -1; 395af69d88dSmrg transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT; 39601e04c3fSmrg transform.hasFixedUnit = !samplerUnitOut; 39701e04c3fSmrg transform.fixedUnit = fixedUnit; 39801e04c3fSmrg transform.base.prolog = pstip_transform_prolog; 3993464ebd5Sriastradh transform.base.transform_declaration = pstip_transform_decl; 4003464ebd5Sriastradh transform.base.transform_immediate = pstip_transform_immed; 4013464ebd5Sriastradh 40201e04c3fSmrg tgsi_scan_shader(tokens, &transform.info); 403af69d88dSmrg 40401e04c3fSmrg transform.coordOrigin = 40501e04c3fSmrg transform.info.properties[TGSI_PROPERTY_FS_COORD_ORIGIN]; 406af69d88dSmrg 40701e04c3fSmrg tgsi_transform_shader(tokens, new_tokens, newLen, &transform.base); 4083464ebd5Sriastradh 4093464ebd5Sriastradh#if 0 /* DEBUG */ 4103464ebd5Sriastradh tgsi_dump(fs->tokens, 0); 411af69d88dSmrg tgsi_dump(new_fs->tokens, 0); 4123464ebd5Sriastradh#endif 4133464ebd5Sriastradh 41401e04c3fSmrg if (samplerUnitOut) { 41501e04c3fSmrg assert(transform.freeSampler < PIPE_MAX_SAMPLERS); 41601e04c3fSmrg *samplerUnitOut = transform.freeSampler; 41701e04c3fSmrg } 4183464ebd5Sriastradh 41901e04c3fSmrg return new_tokens; 4203464ebd5Sriastradh} 421