draw_pipe_aapoint.c revision e6f3e24330926b2ea04c39b5a60b9a20123e5bd4
1/************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/** 29 * AA point stage: AA points are converted to quads and rendered with a 30 * special fragment shader. Another approach would be to use a texture 31 * map image of a point, but experiments indicate the quality isn't nearly 32 * as good as this approach. 33 * 34 * Note: this looks a lot like draw_aaline.c but there's actually little 35 * if any code that can be shared. 36 * 37 * Authors: Brian Paul 38 */ 39 40 41#include "pipe/p_context.h" 42#include "pipe/p_defines.h" 43#include "pipe/p_shader_tokens.h" 44 45#include "tgsi/tgsi_transform.h" 46#include "tgsi/tgsi_dump.h" 47 48#include "util/u_math.h" 49#include "util/u_memory.h" 50 51#include "draw_context.h" 52#include "draw_vs.h" 53#include "draw_pipe.h" 54 55 56/** Approx number of new tokens for instructions in aa_transform_inst() */ 57#define NUM_NEW_TOKENS 200 58 59 60/* 61 * Enabling NORMALIZE might give _slightly_ better results. 62 * Basically, it controls whether we compute distance as d=sqrt(x*x+y*y) or 63 * d=x*x+y*y. Since we're working with a unit circle, the later seems 64 * close enough and saves some costly instructions. 65 */ 66#define NORMALIZE 0 67 68 69/** 70 * Subclass of pipe_shader_state to carry extra fragment shader info. 71 */ 72struct aapoint_fragment_shader 73{ 74 struct pipe_shader_state state; 75 void *driver_fs; /**< the regular shader */ 76 void *aapoint_fs; /**< the aa point-augmented shader */ 77 int generic_attrib; /**< The generic input attrib/texcoord we'll use */ 78}; 79 80 81/** 82 * Subclass of draw_stage 83 */ 84struct aapoint_stage 85{ 86 struct draw_stage stage; 87 88 /** half of pipe_rasterizer_state::point_size */ 89 float radius; 90 91 /** vertex attrib slot containing point size */ 92 int psize_slot; 93 94 /** this is the vertex attrib slot for the new texcoords */ 95 uint tex_slot; 96 97 /** vertex attrib slot containing position */ 98 uint pos_slot; 99 100 /** Currently bound fragment shader */ 101 struct aapoint_fragment_shader *fs; 102 103 /* 104 * Driver interface/override functions 105 */ 106 void * (*driver_create_fs_state)(struct pipe_context *, 107 const struct pipe_shader_state *); 108 void (*driver_bind_fs_state)(struct pipe_context *, void *); 109 void (*driver_delete_fs_state)(struct pipe_context *, void *); 110}; 111 112 113 114/** 115 * Subclass of tgsi_transform_context, used for transforming the 116 * user's fragment shader to add the special AA instructions. 117 */ 118struct aa_transform_context { 119 struct tgsi_transform_context base; 120 uint tempsUsed; /**< bitmask */ 121 int colorOutput; /**< which output is the primary color */ 122 int maxInput, maxGeneric; /**< max input index found */ 123 int tmp0, colorTemp; /**< temp registers */ 124 boolean firstInstruction; 125}; 126 127 128/** 129 * TGSI declaration transform callback. 130 * Look for two free temp regs and available input reg for new texcoords. 131 */ 132static void 133aa_transform_decl(struct tgsi_transform_context *ctx, 134 struct tgsi_full_declaration *decl) 135{ 136 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx; 137 138 if (decl->Declaration.File == TGSI_FILE_OUTPUT && 139 decl->Semantic.Name == TGSI_SEMANTIC_COLOR && 140 decl->Semantic.Index == 0) { 141 aactx->colorOutput = decl->Range.First; 142 } 143 else if (decl->Declaration.File == TGSI_FILE_INPUT) { 144 if ((int) decl->Range.Last > aactx->maxInput) 145 aactx->maxInput = decl->Range.Last; 146 if (decl->Semantic.Name == TGSI_SEMANTIC_GENERIC && 147 (int) decl->Semantic.Index > aactx->maxGeneric) { 148 aactx->maxGeneric = decl->Semantic.Index; 149 } 150 } 151 else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { 152 uint i; 153 for (i = decl->Range.First; 154 i <= decl->Range.Last; i++) { 155 aactx->tempsUsed |= (1 << i); 156 } 157 } 158 159 ctx->emit_declaration(ctx, decl); 160} 161 162 163/** 164 * TGSI instruction transform callback. 165 * Replace writes to result.color w/ a temp reg. 166 * Upon END instruction, insert texture sampling code for antialiasing. 167 */ 168static void 169aa_transform_inst(struct tgsi_transform_context *ctx, 170 struct tgsi_full_instruction *inst) 171{ 172 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx; 173 struct tgsi_full_instruction newInst; 174 175 if (aactx->firstInstruction) { 176 /* emit our new declarations before the first instruction */ 177 178 struct tgsi_full_declaration decl; 179 const int texInput = aactx->maxInput + 1; 180 int tmp0; 181 uint i; 182 183 /* find two free temp regs */ 184 for (i = 0; i < 32; i++) { 185 if ((aactx->tempsUsed & (1 << i)) == 0) { 186 /* found a free temp */ 187 if (aactx->tmp0 < 0) 188 aactx->tmp0 = i; 189 else if (aactx->colorTemp < 0) 190 aactx->colorTemp = i; 191 else 192 break; 193 } 194 } 195 196 assert(aactx->colorTemp != aactx->tmp0); 197 198 tmp0 = aactx->tmp0; 199 200 /* declare new generic input/texcoord */ 201 decl = tgsi_default_full_declaration(); 202 decl.Declaration.File = TGSI_FILE_INPUT; 203 /* XXX this could be linear... */ 204 decl.Declaration.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE; 205 decl.Declaration.Semantic = 1; 206 decl.Semantic.Name = TGSI_SEMANTIC_GENERIC; 207 decl.Semantic.Index = aactx->maxGeneric + 1; 208 decl.Range.First = 209 decl.Range.Last = texInput; 210 ctx->emit_declaration(ctx, &decl); 211 212 /* declare new temp regs */ 213 decl = tgsi_default_full_declaration(); 214 decl.Declaration.File = TGSI_FILE_TEMPORARY; 215 decl.Range.First = 216 decl.Range.Last = tmp0; 217 ctx->emit_declaration(ctx, &decl); 218 219 decl = tgsi_default_full_declaration(); 220 decl.Declaration.File = TGSI_FILE_TEMPORARY; 221 decl.Range.First = 222 decl.Range.Last = aactx->colorTemp; 223 ctx->emit_declaration(ctx, &decl); 224 225 aactx->firstInstruction = FALSE; 226 227 228 /* 229 * Emit code to compute fragment coverage, kill if outside point radius 230 * 231 * Temp reg0 usage: 232 * t0.x = distance of fragment from center point 233 * t0.y = boolean, is t0.x > 1.0, also misc temp usage 234 * t0.z = temporary for computing 1/(1-k) value 235 * t0.w = final coverage value 236 */ 237 238 /* MUL t0.xy, tex, tex; # compute x^2, y^2 */ 239 newInst = tgsi_default_full_instruction(); 240 newInst.Instruction.Opcode = TGSI_OPCODE_MUL; 241 newInst.Instruction.NumDstRegs = 1; 242 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 243 newInst.Dst[0].Register.Index = tmp0; 244 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XY; 245 newInst.Instruction.NumSrcRegs = 2; 246 newInst.Src[0].Register.File = TGSI_FILE_INPUT; 247 newInst.Src[0].Register.Index = texInput; 248 newInst.Src[1].Register.File = TGSI_FILE_INPUT; 249 newInst.Src[1].Register.Index = texInput; 250 ctx->emit_instruction(ctx, &newInst); 251 252 /* ADD t0.x, t0.x, t0.y; # x^2 + y^2 */ 253 newInst = tgsi_default_full_instruction(); 254 newInst.Instruction.Opcode = TGSI_OPCODE_ADD; 255 newInst.Instruction.NumDstRegs = 1; 256 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 257 newInst.Dst[0].Register.Index = tmp0; 258 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_X; 259 newInst.Instruction.NumSrcRegs = 2; 260 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 261 newInst.Src[0].Register.Index = tmp0; 262 newInst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X; 263 newInst.Src[1].Register.File = TGSI_FILE_TEMPORARY; 264 newInst.Src[1].Register.Index = tmp0; 265 newInst.Src[1].Register.SwizzleX = TGSI_SWIZZLE_Y; 266 ctx->emit_instruction(ctx, &newInst); 267 268#if NORMALIZE /* OPTIONAL normalization of length */ 269 /* RSQ t0.x, t0.x; */ 270 newInst = tgsi_default_full_instruction(); 271 newInst.Instruction.Opcode = TGSI_OPCODE_RSQ; 272 newInst.Instruction.NumDstRegs = 1; 273 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 274 newInst.Dst[0].Register.Index = tmp0; 275 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_X; 276 newInst.Instruction.NumSrcRegs = 1; 277 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 278 newInst.Src[0].Register.Index = tmp0; 279 ctx->emit_instruction(ctx, &newInst); 280 281 /* RCP t0.x, t0.x; */ 282 newInst = tgsi_default_full_instruction(); 283 newInst.Instruction.Opcode = TGSI_OPCODE_RCP; 284 newInst.Instruction.NumDstRegs = 1; 285 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 286 newInst.Dst[0].Register.Index = tmp0; 287 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_X; 288 newInst.Instruction.NumSrcRegs = 1; 289 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 290 newInst.Src[0].Register.Index = tmp0; 291 ctx->emit_instruction(ctx, &newInst); 292#endif 293 294 /* SGT t0.y, t0.xxxx, tex.wwww; # bool b = d > 1 (NOTE tex.w == 1) */ 295 newInst = tgsi_default_full_instruction(); 296 newInst.Instruction.Opcode = TGSI_OPCODE_SGT; 297 newInst.Instruction.NumDstRegs = 1; 298 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 299 newInst.Dst[0].Register.Index = tmp0; 300 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_Y; 301 newInst.Instruction.NumSrcRegs = 2; 302 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 303 newInst.Src[0].Register.Index = tmp0; 304 newInst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X; 305 newInst.Src[1].Register.File = TGSI_FILE_INPUT; 306 newInst.Src[1].Register.Index = texInput; 307 newInst.Src[1].Register.SwizzleY = TGSI_SWIZZLE_W; 308 ctx->emit_instruction(ctx, &newInst); 309 310 /* KIL -tmp0.yyyy; # if -tmp0.y < 0, KILL */ 311 newInst = tgsi_default_full_instruction(); 312 newInst.Instruction.Opcode = TGSI_OPCODE_KIL; 313 newInst.Instruction.NumDstRegs = 0; 314 newInst.Instruction.NumSrcRegs = 1; 315 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 316 newInst.Src[0].Register.Index = tmp0; 317 newInst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_Y; 318 newInst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_Y; 319 newInst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_Y; 320 newInst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_Y; 321 newInst.Src[0].Register.Negate = 1; 322 ctx->emit_instruction(ctx, &newInst); 323 324 325 /* compute coverage factor = (1-d)/(1-k) */ 326 327 /* SUB t0.z, tex.w, tex.z; # m = 1 - k */ 328 newInst = tgsi_default_full_instruction(); 329 newInst.Instruction.Opcode = TGSI_OPCODE_SUB; 330 newInst.Instruction.NumDstRegs = 1; 331 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 332 newInst.Dst[0].Register.Index = tmp0; 333 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_Z; 334 newInst.Instruction.NumSrcRegs = 2; 335 newInst.Src[0].Register.File = TGSI_FILE_INPUT; 336 newInst.Src[0].Register.Index = texInput; 337 newInst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_W; 338 newInst.Src[1].Register.File = TGSI_FILE_INPUT; 339 newInst.Src[1].Register.Index = texInput; 340 newInst.Src[1].Register.SwizzleZ = TGSI_SWIZZLE_Z; 341 ctx->emit_instruction(ctx, &newInst); 342 343 /* RCP t0.z, t0.z; # t0.z = 1 / m */ 344 newInst = tgsi_default_full_instruction(); 345 newInst.Instruction.Opcode = TGSI_OPCODE_RCP; 346 newInst.Instruction.NumDstRegs = 1; 347 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 348 newInst.Dst[0].Register.Index = tmp0; 349 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_Z; 350 newInst.Instruction.NumSrcRegs = 1; 351 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 352 newInst.Src[0].Register.Index = tmp0; 353 newInst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_Z; 354 ctx->emit_instruction(ctx, &newInst); 355 356 /* SUB t0.y, 1, t0.x; # d = 1 - d */ 357 newInst = tgsi_default_full_instruction(); 358 newInst.Instruction.Opcode = TGSI_OPCODE_SUB; 359 newInst.Instruction.NumDstRegs = 1; 360 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 361 newInst.Dst[0].Register.Index = tmp0; 362 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_Y; 363 newInst.Instruction.NumSrcRegs = 2; 364 newInst.Src[0].Register.File = TGSI_FILE_INPUT; 365 newInst.Src[0].Register.Index = texInput; 366 newInst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_W; 367 newInst.Src[1].Register.File = TGSI_FILE_TEMPORARY; 368 newInst.Src[1].Register.Index = tmp0; 369 newInst.Src[1].Register.SwizzleY = TGSI_SWIZZLE_X; 370 ctx->emit_instruction(ctx, &newInst); 371 372 /* MUL t0.w, t0.y, t0.z; # coverage = d * m */ 373 newInst = tgsi_default_full_instruction(); 374 newInst.Instruction.Opcode = TGSI_OPCODE_MUL; 375 newInst.Instruction.NumDstRegs = 1; 376 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 377 newInst.Dst[0].Register.Index = tmp0; 378 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_W; 379 newInst.Instruction.NumSrcRegs = 2; 380 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 381 newInst.Src[0].Register.Index = tmp0; 382 newInst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_Y; 383 newInst.Src[1].Register.File = TGSI_FILE_TEMPORARY; 384 newInst.Src[1].Register.Index = tmp0; 385 newInst.Src[1].Register.SwizzleW = TGSI_SWIZZLE_Z; 386 ctx->emit_instruction(ctx, &newInst); 387 388 /* SLE t0.y, t0.x, tex.z; # bool b = distance <= k */ 389 newInst = tgsi_default_full_instruction(); 390 newInst.Instruction.Opcode = TGSI_OPCODE_SLE; 391 newInst.Instruction.NumDstRegs = 1; 392 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 393 newInst.Dst[0].Register.Index = tmp0; 394 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_Y; 395 newInst.Instruction.NumSrcRegs = 2; 396 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 397 newInst.Src[0].Register.Index = tmp0; 398 newInst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X; 399 newInst.Src[1].Register.File = TGSI_FILE_INPUT; 400 newInst.Src[1].Register.Index = texInput; 401 newInst.Src[1].Register.SwizzleY = TGSI_SWIZZLE_Z; 402 ctx->emit_instruction(ctx, &newInst); 403 404 /* CMP t0.w, -t0.y, tex.w, t0.w; 405 * # if -t0.y < 0 then 406 * t0.w = 1 407 * else 408 * t0.w = t0.w 409 */ 410 newInst = tgsi_default_full_instruction(); 411 newInst.Instruction.Opcode = TGSI_OPCODE_CMP; 412 newInst.Instruction.NumDstRegs = 1; 413 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 414 newInst.Dst[0].Register.Index = tmp0; 415 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_W; 416 newInst.Instruction.NumSrcRegs = 3; 417 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 418 newInst.Src[0].Register.Index = tmp0; 419 newInst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_Y; 420 newInst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_Y; 421 newInst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_Y; 422 newInst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_Y; 423 newInst.Src[0].Register.Negate = 1; 424 newInst.Src[1].Register.File = TGSI_FILE_INPUT; 425 newInst.Src[1].Register.Index = texInput; 426 newInst.Src[1].Register.SwizzleX = TGSI_SWIZZLE_W; 427 newInst.Src[1].Register.SwizzleY = TGSI_SWIZZLE_W; 428 newInst.Src[1].Register.SwizzleZ = TGSI_SWIZZLE_W; 429 newInst.Src[1].Register.SwizzleW = TGSI_SWIZZLE_W; 430 newInst.Src[2].Register.File = TGSI_FILE_TEMPORARY; 431 newInst.Src[2].Register.Index = tmp0; 432 newInst.Src[2].Register.SwizzleX = TGSI_SWIZZLE_W; 433 newInst.Src[2].Register.SwizzleY = TGSI_SWIZZLE_W; 434 newInst.Src[2].Register.SwizzleZ = TGSI_SWIZZLE_W; 435 newInst.Src[2].Register.SwizzleW = TGSI_SWIZZLE_W; 436 ctx->emit_instruction(ctx, &newInst); 437 438 } 439 440 if (inst->Instruction.Opcode == TGSI_OPCODE_END) { 441 /* add alpha modulation code at tail of program */ 442 443 /* MOV result.color.xyz, colorTemp; */ 444 newInst = tgsi_default_full_instruction(); 445 newInst.Instruction.Opcode = TGSI_OPCODE_MOV; 446 newInst.Instruction.NumDstRegs = 1; 447 newInst.Dst[0].Register.File = TGSI_FILE_OUTPUT; 448 newInst.Dst[0].Register.Index = aactx->colorOutput; 449 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZ; 450 newInst.Instruction.NumSrcRegs = 1; 451 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 452 newInst.Src[0].Register.Index = aactx->colorTemp; 453 ctx->emit_instruction(ctx, &newInst); 454 455 /* MUL result.color.w, colorTemp, tmp0.w; */ 456 newInst = tgsi_default_full_instruction(); 457 newInst.Instruction.Opcode = TGSI_OPCODE_MUL; 458 newInst.Instruction.NumDstRegs = 1; 459 newInst.Dst[0].Register.File = TGSI_FILE_OUTPUT; 460 newInst.Dst[0].Register.Index = aactx->colorOutput; 461 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_W; 462 newInst.Instruction.NumSrcRegs = 2; 463 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 464 newInst.Src[0].Register.Index = aactx->colorTemp; 465 newInst.Src[1].Register.File = TGSI_FILE_TEMPORARY; 466 newInst.Src[1].Register.Index = aactx->tmp0; 467 ctx->emit_instruction(ctx, &newInst); 468 } 469 else { 470 /* Not an END instruction. 471 * Look for writes to result.color and replace with colorTemp reg. 472 */ 473 uint i; 474 475 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 476 struct tgsi_full_dst_register *dst = &inst->Dst[i]; 477 if (dst->Register.File == TGSI_FILE_OUTPUT && 478 dst->Register.Index == aactx->colorOutput) { 479 dst->Register.File = TGSI_FILE_TEMPORARY; 480 dst->Register.Index = aactx->colorTemp; 481 } 482 } 483 } 484 485 ctx->emit_instruction(ctx, inst); 486} 487 488 489/** 490 * Generate the frag shader we'll use for drawing AA points. 491 * This will be the user's shader plus some texture/modulate instructions. 492 */ 493static boolean 494generate_aapoint_fs(struct aapoint_stage *aapoint) 495{ 496 const struct pipe_shader_state *orig_fs = &aapoint->fs->state; 497 struct pipe_shader_state aapoint_fs; 498 struct aa_transform_context transform; 499 const uint newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS; 500 struct pipe_context *pipe = aapoint->stage.draw->pipe; 501 502 aapoint_fs = *orig_fs; /* copy to init */ 503 aapoint_fs.tokens = tgsi_alloc_tokens(newLen); 504 if (aapoint_fs.tokens == NULL) 505 return FALSE; 506 507 memset(&transform, 0, sizeof(transform)); 508 transform.colorOutput = -1; 509 transform.maxInput = -1; 510 transform.maxGeneric = -1; 511 transform.colorTemp = -1; 512 transform.tmp0 = -1; 513 transform.firstInstruction = TRUE; 514 transform.base.transform_instruction = aa_transform_inst; 515 transform.base.transform_declaration = aa_transform_decl; 516 517 tgsi_transform_shader(orig_fs->tokens, 518 (struct tgsi_token *) aapoint_fs.tokens, 519 newLen, &transform.base); 520 521#if 0 /* DEBUG */ 522 printf("draw_aapoint, orig shader:\n"); 523 tgsi_dump(orig_fs->tokens, 0); 524 printf("draw_aapoint, new shader:\n"); 525 tgsi_dump(aapoint_fs.tokens, 0); 526#endif 527 528 aapoint->fs->aapoint_fs 529 = aapoint->driver_create_fs_state(pipe, &aapoint_fs); 530 if (aapoint->fs->aapoint_fs == NULL) 531 goto fail; 532 533 aapoint->fs->generic_attrib = transform.maxGeneric + 1; 534 FREE((void *)aapoint_fs.tokens); 535 return TRUE; 536 537fail: 538 FREE((void *)aapoint_fs.tokens); 539 return FALSE; 540} 541 542 543/** 544 * When we're about to draw our first AA point in a batch, this function is 545 * called to tell the driver to bind our modified fragment shader. 546 */ 547static boolean 548bind_aapoint_fragment_shader(struct aapoint_stage *aapoint) 549{ 550 struct draw_context *draw = aapoint->stage.draw; 551 struct pipe_context *pipe = draw->pipe; 552 553 if (!aapoint->fs->aapoint_fs && 554 !generate_aapoint_fs(aapoint)) 555 return FALSE; 556 557 draw->suspend_flushing = TRUE; 558 aapoint->driver_bind_fs_state(pipe, aapoint->fs->aapoint_fs); 559 draw->suspend_flushing = FALSE; 560 561 return TRUE; 562} 563 564 565 566static INLINE struct aapoint_stage * 567aapoint_stage( struct draw_stage *stage ) 568{ 569 return (struct aapoint_stage *) stage; 570} 571 572 573 574 575/** 576 * Draw an AA point by drawing a quad. 577 */ 578static void 579aapoint_point(struct draw_stage *stage, struct prim_header *header) 580{ 581 const struct aapoint_stage *aapoint = aapoint_stage(stage); 582 struct prim_header tri; 583 struct vertex_header *v[4]; 584 const uint tex_slot = aapoint->tex_slot; 585 const uint pos_slot = aapoint->pos_slot; 586 float radius, *pos, *tex; 587 uint i; 588 float k; 589 590 if (aapoint->psize_slot >= 0) { 591 radius = 0.5f * header->v[0]->data[aapoint->psize_slot][0]; 592 } 593 else { 594 radius = aapoint->radius; 595 } 596 597 /* 598 * Note: the texcoords (generic attrib, really) we use are special: 599 * The S and T components simply vary from -1 to +1. 600 * The R component is k, below. 601 * The Q component is 1.0 and will used as a handy constant in the 602 * fragment shader. 603 */ 604 605 /* 606 * k is the threshold distance from the point's center at which 607 * we begin alpha attenuation (the coverage value). 608 * Operating within a unit circle, we'll compute the fragment's 609 * distance 'd' from the center point using the texcoords. 610 * IF d > 1.0 THEN 611 * KILL fragment 612 * ELSE IF d > k THEN 613 * compute coverage in [0,1] proportional to d in [k, 1]. 614 * ELSE 615 * coverage = 1.0; // full coverage 616 * ENDIF 617 * 618 * Note: the ELSEIF and ELSE clauses are actually implemented with CMP to 619 * avoid using IF/ELSE/ENDIF TGSI opcodes. 620 */ 621 622#if !NORMALIZE 623 k = 1.0f / radius; 624 k = 1.0f - 2.0f * k + k * k; 625#else 626 k = 1.0f - 1.0f / radius; 627#endif 628 629 /* allocate/dup new verts */ 630 for (i = 0; i < 4; i++) { 631 v[i] = dup_vert(stage, header->v[0], i); 632 } 633 634 /* new verts */ 635 pos = v[0]->data[pos_slot]; 636 pos[0] -= radius; 637 pos[1] -= radius; 638 639 pos = v[1]->data[pos_slot]; 640 pos[0] += radius; 641 pos[1] -= radius; 642 643 pos = v[2]->data[pos_slot]; 644 pos[0] += radius; 645 pos[1] += radius; 646 647 pos = v[3]->data[pos_slot]; 648 pos[0] -= radius; 649 pos[1] += radius; 650 651 /* new texcoords */ 652 tex = v[0]->data[tex_slot]; 653 ASSIGN_4V(tex, -1, -1, k, 1); 654 655 tex = v[1]->data[tex_slot]; 656 ASSIGN_4V(tex, 1, -1, k, 1); 657 658 tex = v[2]->data[tex_slot]; 659 ASSIGN_4V(tex, 1, 1, k, 1); 660 661 tex = v[3]->data[tex_slot]; 662 ASSIGN_4V(tex, -1, 1, k, 1); 663 664 /* emit 2 tris for the quad strip */ 665 tri.v[0] = v[0]; 666 tri.v[1] = v[1]; 667 tri.v[2] = v[2]; 668 stage->next->tri( stage->next, &tri ); 669 670 tri.v[0] = v[0]; 671 tri.v[1] = v[2]; 672 tri.v[2] = v[3]; 673 stage->next->tri( stage->next, &tri ); 674} 675 676 677static void 678aapoint_first_point(struct draw_stage *stage, struct prim_header *header) 679{ 680 auto struct aapoint_stage *aapoint = aapoint_stage(stage); 681 struct draw_context *draw = stage->draw; 682 struct pipe_context *pipe = draw->pipe; 683 const struct pipe_rasterizer_state *rast = draw->rasterizer; 684 void *r; 685 686 assert(draw->rasterizer->point_smooth); 687 688 if (draw->rasterizer->point_size <= 2.0) 689 aapoint->radius = 1.0; 690 else 691 aapoint->radius = 0.5f * draw->rasterizer->point_size; 692 693 /* 694 * Bind (generate) our fragprog. 695 */ 696 bind_aapoint_fragment_shader(aapoint); 697 698 /* update vertex attrib info */ 699 aapoint->tex_slot = draw_current_shader_outputs(draw); 700 assert(aapoint->tex_slot > 0); /* output[0] is vertex pos */ 701 702 aapoint->pos_slot = draw_current_shader_position_output(draw); 703 704 /* allocate the extra post-transformed vertex attribute */ 705 (void) draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC, 706 aapoint->fs->generic_attrib); 707 708 /* find psize slot in post-transform vertex */ 709 aapoint->psize_slot = -1; 710 if (draw->rasterizer->point_size_per_vertex) { 711 /* find PSIZ vertex output */ 712 const struct draw_vertex_shader *vs = draw->vs.vertex_shader; 713 uint i; 714 for (i = 0; i < vs->info.num_outputs; i++) { 715 if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) { 716 aapoint->psize_slot = i; 717 break; 718 } 719 } 720 } 721 722 draw->suspend_flushing = TRUE; 723 724 /* Disable triangle culling, stippling, unfilled mode etc. */ 725 r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade); 726 pipe->bind_rasterizer_state(pipe, r); 727 728 draw->suspend_flushing = FALSE; 729 730 /* now really draw first point */ 731 stage->point = aapoint_point; 732 stage->point(stage, header); 733} 734 735 736static void 737aapoint_flush(struct draw_stage *stage, unsigned flags) 738{ 739 struct draw_context *draw = stage->draw; 740 struct aapoint_stage *aapoint = aapoint_stage(stage); 741 struct pipe_context *pipe = draw->pipe; 742 743 stage->point = aapoint_first_point; 744 stage->next->flush( stage->next, flags ); 745 746 /* restore original frag shader */ 747 draw->suspend_flushing = TRUE; 748 aapoint->driver_bind_fs_state(pipe, aapoint->fs->driver_fs); 749 750 /* restore original rasterizer state */ 751 if (draw->rast_handle) { 752 pipe->bind_rasterizer_state(pipe, draw->rast_handle); 753 } 754 755 draw->suspend_flushing = FALSE; 756 757 draw_remove_extra_vertex_attribs(draw); 758} 759 760 761static void 762aapoint_reset_stipple_counter(struct draw_stage *stage) 763{ 764 stage->next->reset_stipple_counter( stage->next ); 765} 766 767 768static void 769aapoint_destroy(struct draw_stage *stage) 770{ 771 draw_free_temp_verts( stage ); 772 FREE( stage ); 773} 774 775 776static struct aapoint_stage * 777draw_aapoint_stage(struct draw_context *draw) 778{ 779 struct aapoint_stage *aapoint = CALLOC_STRUCT(aapoint_stage); 780 if (aapoint == NULL) 781 goto fail; 782 783 aapoint->stage.draw = draw; 784 aapoint->stage.name = "aapoint"; 785 aapoint->stage.next = NULL; 786 aapoint->stage.point = aapoint_first_point; 787 aapoint->stage.line = draw_pipe_passthrough_line; 788 aapoint->stage.tri = draw_pipe_passthrough_tri; 789 aapoint->stage.flush = aapoint_flush; 790 aapoint->stage.reset_stipple_counter = aapoint_reset_stipple_counter; 791 aapoint->stage.destroy = aapoint_destroy; 792 793 if (!draw_alloc_temp_verts( &aapoint->stage, 4 )) 794 goto fail; 795 796 return aapoint; 797 798 fail: 799 if (aapoint) 800 aapoint->stage.destroy(&aapoint->stage); 801 802 return NULL; 803 804} 805 806 807static struct aapoint_stage * 808aapoint_stage_from_pipe(struct pipe_context *pipe) 809{ 810 struct draw_context *draw = (struct draw_context *) pipe->draw; 811 return aapoint_stage(draw->pipeline.aapoint); 812} 813 814 815/** 816 * This function overrides the driver's create_fs_state() function and 817 * will typically be called by the state tracker. 818 */ 819static void * 820aapoint_create_fs_state(struct pipe_context *pipe, 821 const struct pipe_shader_state *fs) 822{ 823 struct aapoint_stage *aapoint = aapoint_stage_from_pipe(pipe); 824 struct aapoint_fragment_shader *aafs = CALLOC_STRUCT(aapoint_fragment_shader); 825 if (aafs == NULL) 826 return NULL; 827 828 aafs->state = *fs; 829 830 /* pass-through */ 831 aafs->driver_fs = aapoint->driver_create_fs_state(pipe, fs); 832 833 return aafs; 834} 835 836 837static void 838aapoint_bind_fs_state(struct pipe_context *pipe, void *fs) 839{ 840 struct aapoint_stage *aapoint = aapoint_stage_from_pipe(pipe); 841 struct aapoint_fragment_shader *aafs = (struct aapoint_fragment_shader *) fs; 842 /* save current */ 843 aapoint->fs = aafs; 844 /* pass-through */ 845 aapoint->driver_bind_fs_state(pipe, 846 (aafs ? aafs->driver_fs : NULL)); 847} 848 849 850static void 851aapoint_delete_fs_state(struct pipe_context *pipe, void *fs) 852{ 853 struct aapoint_stage *aapoint = aapoint_stage_from_pipe(pipe); 854 struct aapoint_fragment_shader *aafs = (struct aapoint_fragment_shader *) fs; 855 856 /* pass-through */ 857 aapoint->driver_delete_fs_state(pipe, aafs->driver_fs); 858 859 if (aafs->aapoint_fs) 860 aapoint->driver_delete_fs_state(pipe, aafs->aapoint_fs); 861 862 FREE(aafs); 863} 864 865 866/** 867 * Called by drivers that want to install this AA point prim stage 868 * into the draw module's pipeline. This will not be used if the 869 * hardware has native support for AA points. 870 */ 871boolean 872draw_install_aapoint_stage(struct draw_context *draw, 873 struct pipe_context *pipe) 874{ 875 struct aapoint_stage *aapoint; 876 877 pipe->draw = (void *) draw; 878 879 /* 880 * Create / install AA point drawing / prim stage 881 */ 882 aapoint = draw_aapoint_stage( draw ); 883 if (aapoint == NULL) 884 return FALSE; 885 886 /* save original driver functions */ 887 aapoint->driver_create_fs_state = pipe->create_fs_state; 888 aapoint->driver_bind_fs_state = pipe->bind_fs_state; 889 aapoint->driver_delete_fs_state = pipe->delete_fs_state; 890 891 /* override the driver's functions */ 892 pipe->create_fs_state = aapoint_create_fs_state; 893 pipe->bind_fs_state = aapoint_bind_fs_state; 894 pipe->delete_fs_state = aapoint_delete_fs_state; 895 896 draw->pipeline.aapoint = &aapoint->stage; 897 898 return TRUE; 899} 900