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