draw_pipe_aaline.c revision c173eb990a20611ac47c1727e1fb11d7fd3aa0c4
1/************************************************************************** 2 * 3 * Copyright 2007 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 line stage: AA lines are converted to texture mapped triangles. 30 * 31 * Authors: Brian Paul 32 */ 33 34 35#include "pipe/p_context.h" 36#include "pipe/p_defines.h" 37#include "pipe/p_shader_tokens.h" 38 39#include "util/u_format.h" 40#include "util/u_math.h" 41#include "util/u_memory.h" 42 43#include "tgsi/tgsi_transform.h" 44#include "tgsi/tgsi_dump.h" 45 46#include "draw_context.h" 47#include "draw_private.h" 48#include "draw_pipe.h" 49 50 51/** 52 * Max texture level for the alpha texture used for antialiasing 53 */ 54#define MAX_TEXTURE_LEVEL 5 /* 32 x 32 */ 55 56 57/** 58 * Subclass of pipe_shader_state to carry extra fragment shader info. 59 */ 60struct aaline_fragment_shader 61{ 62 struct pipe_shader_state state; 63 void *driver_fs; 64 void *aaline_fs; 65 uint sampler_unit; 66 int generic_attrib; /**< texcoord/generic used for texture */ 67}; 68 69 70/** 71 * Subclass of draw_stage 72 */ 73struct aaline_stage 74{ 75 struct draw_stage stage; 76 77 float half_line_width; 78 79 /** For AA lines, this is the vertex attrib slot for the new texcoords */ 80 uint tex_slot; 81 /** position, not necessarily output zero */ 82 uint pos_slot; 83 84 void *sampler_cso; 85 struct pipe_texture *texture; 86 uint num_samplers; 87 uint num_textures; 88 89 90 /* 91 * Currently bound state 92 */ 93 struct aaline_fragment_shader *fs; 94 struct { 95 void *sampler[PIPE_MAX_SAMPLERS]; 96 struct pipe_texture *texture[PIPE_MAX_SAMPLERS]; 97 } state; 98 99 /* 100 * Driver interface/override functions 101 */ 102 void * (*driver_create_fs_state)(struct pipe_context *, 103 const struct pipe_shader_state *); 104 void (*driver_bind_fs_state)(struct pipe_context *, void *); 105 void (*driver_delete_fs_state)(struct pipe_context *, void *); 106 107 void (*driver_bind_sampler_states)(struct pipe_context *, unsigned, 108 void **); 109 void (*driver_set_sampler_textures)(struct pipe_context *, unsigned, 110 struct pipe_texture **); 111 112 struct pipe_context *pipe; 113}; 114 115 116 117/** 118 * Subclass of tgsi_transform_context, used for transforming the 119 * user's fragment shader to add the special AA instructions. 120 */ 121struct aa_transform_context { 122 struct tgsi_transform_context base; 123 uint tempsUsed; /**< bitmask */ 124 int colorOutput; /**< which output is the primary color */ 125 uint samplersUsed; /**< bitfield of samplers used */ 126 int freeSampler; /** an available sampler for the pstipple */ 127 int maxInput, maxGeneric; /**< max input index found */ 128 int colorTemp, texTemp; /**< temp registers */ 129 boolean firstInstruction; 130}; 131 132 133/** 134 * TGSI declaration transform callback. 135 * Look for a free sampler, a free input attrib, and two free temp regs. 136 */ 137static void 138aa_transform_decl(struct tgsi_transform_context *ctx, 139 struct tgsi_full_declaration *decl) 140{ 141 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx; 142 143 if (decl->Declaration.File == TGSI_FILE_OUTPUT && 144 decl->Semantic.Name == TGSI_SEMANTIC_COLOR && 145 decl->Semantic.Index == 0) { 146 aactx->colorOutput = decl->Range.First; 147 } 148 else if (decl->Declaration.File == TGSI_FILE_SAMPLER) { 149 uint i; 150 for (i = decl->Range.First; 151 i <= decl->Range.Last; i++) { 152 aactx->samplersUsed |= 1 << i; 153 } 154 } 155 else if (decl->Declaration.File == TGSI_FILE_INPUT) { 156 if ((int) decl->Range.Last > aactx->maxInput) 157 aactx->maxInput = decl->Range.Last; 158 if (decl->Semantic.Name == TGSI_SEMANTIC_GENERIC && 159 (int) decl->Semantic.Index > aactx->maxGeneric) { 160 aactx->maxGeneric = decl->Semantic.Index; 161 } 162 } 163 else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { 164 uint i; 165 for (i = decl->Range.First; 166 i <= decl->Range.Last; i++) { 167 aactx->tempsUsed |= (1 << i); 168 } 169 } 170 171 ctx->emit_declaration(ctx, decl); 172} 173 174 175/** 176 * Find the lowest zero bit in the given word, or -1 if bitfield is all ones. 177 */ 178static int 179free_bit(uint bitfield) 180{ 181 return ffs(~bitfield) - 1; 182} 183 184 185/** 186 * TGSI instruction transform callback. 187 * Replace writes to result.color w/ a temp reg. 188 * Upon END instruction, insert texture sampling code for antialiasing. 189 */ 190static void 191aa_transform_inst(struct tgsi_transform_context *ctx, 192 struct tgsi_full_instruction *inst) 193{ 194 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx; 195 196 if (aactx->firstInstruction) { 197 /* emit our new declarations before the first instruction */ 198 199 struct tgsi_full_declaration decl; 200 uint i; 201 202 /* find free sampler */ 203 aactx->freeSampler = free_bit(aactx->samplersUsed); 204 if (aactx->freeSampler >= PIPE_MAX_SAMPLERS) 205 aactx->freeSampler = PIPE_MAX_SAMPLERS - 1; 206 207 /* find two free temp regs */ 208 for (i = 0; i < 32; i++) { 209 if ((aactx->tempsUsed & (1 << i)) == 0) { 210 /* found a free temp */ 211 if (aactx->colorTemp < 0) 212 aactx->colorTemp = i; 213 else if (aactx->texTemp < 0) 214 aactx->texTemp = i; 215 else 216 break; 217 } 218 } 219 assert(aactx->colorTemp >= 0); 220 assert(aactx->texTemp >= 0); 221 222 /* declare new generic input/texcoord */ 223 decl = tgsi_default_full_declaration(); 224 decl.Declaration.File = TGSI_FILE_INPUT; 225 /* XXX this could be linear... */ 226 decl.Declaration.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE; 227 decl.Declaration.Semantic = 1; 228 decl.Semantic.Name = TGSI_SEMANTIC_GENERIC; 229 decl.Semantic.Index = aactx->maxGeneric + 1; 230 decl.Range.First = 231 decl.Range.Last = aactx->maxInput + 1; 232 ctx->emit_declaration(ctx, &decl); 233 234 /* declare new sampler */ 235 decl = tgsi_default_full_declaration(); 236 decl.Declaration.File = TGSI_FILE_SAMPLER; 237 decl.Range.First = 238 decl.Range.Last = aactx->freeSampler; 239 ctx->emit_declaration(ctx, &decl); 240 241 /* declare new temp regs */ 242 decl = tgsi_default_full_declaration(); 243 decl.Declaration.File = TGSI_FILE_TEMPORARY; 244 decl.Range.First = 245 decl.Range.Last = aactx->texTemp; 246 ctx->emit_declaration(ctx, &decl); 247 248 decl = tgsi_default_full_declaration(); 249 decl.Declaration.File = TGSI_FILE_TEMPORARY; 250 decl.Range.First = 251 decl.Range.Last = aactx->colorTemp; 252 ctx->emit_declaration(ctx, &decl); 253 254 aactx->firstInstruction = FALSE; 255 } 256 257 if (inst->Instruction.Opcode == TGSI_OPCODE_END && 258 aactx->colorOutput != -1) { 259 struct tgsi_full_instruction newInst; 260 261 /* TEX */ 262 newInst = tgsi_default_full_instruction(); 263 newInst.Instruction.Opcode = TGSI_OPCODE_TEX; 264 newInst.Instruction.NumDstRegs = 1; 265 newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY; 266 newInst.Dst[0].Register.Index = aactx->texTemp; 267 newInst.Instruction.NumSrcRegs = 2; 268 newInst.Instruction.Texture = TRUE; 269 newInst.Texture.Texture = TGSI_TEXTURE_2D; 270 newInst.Src[0].Register.File = TGSI_FILE_INPUT; 271 newInst.Src[0].Register.Index = aactx->maxInput + 1; 272 newInst.Src[1].Register.File = TGSI_FILE_SAMPLER; 273 newInst.Src[1].Register.Index = aactx->freeSampler; 274 275 ctx->emit_instruction(ctx, &newInst); 276 277 /* MOV rgb */ 278 newInst = tgsi_default_full_instruction(); 279 newInst.Instruction.Opcode = TGSI_OPCODE_MOV; 280 newInst.Instruction.NumDstRegs = 1; 281 newInst.Dst[0].Register.File = TGSI_FILE_OUTPUT; 282 newInst.Dst[0].Register.Index = aactx->colorOutput; 283 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZ; 284 newInst.Instruction.NumSrcRegs = 1; 285 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 286 newInst.Src[0].Register.Index = aactx->colorTemp; 287 ctx->emit_instruction(ctx, &newInst); 288 289 /* MUL alpha */ 290 newInst = tgsi_default_full_instruction(); 291 newInst.Instruction.Opcode = TGSI_OPCODE_MUL; 292 newInst.Instruction.NumDstRegs = 1; 293 newInst.Dst[0].Register.File = TGSI_FILE_OUTPUT; 294 newInst.Dst[0].Register.Index = aactx->colorOutput; 295 newInst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_W; 296 newInst.Instruction.NumSrcRegs = 2; 297 newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY; 298 newInst.Src[0].Register.Index = aactx->colorTemp; 299 newInst.Src[1].Register.File = TGSI_FILE_TEMPORARY; 300 newInst.Src[1].Register.Index = aactx->texTemp; 301 ctx->emit_instruction(ctx, &newInst); 302 303 /* END */ 304 newInst = tgsi_default_full_instruction(); 305 newInst.Instruction.Opcode = TGSI_OPCODE_END; 306 newInst.Instruction.NumDstRegs = 0; 307 newInst.Instruction.NumSrcRegs = 0; 308 ctx->emit_instruction(ctx, &newInst); 309 } 310 else { 311 /* Not an END instruction. 312 * Look for writes to result.color and replace with colorTemp reg. 313 */ 314 uint i; 315 316 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 317 struct tgsi_full_dst_register *dst = &inst->Dst[i]; 318 if (dst->Register.File == TGSI_FILE_OUTPUT && 319 dst->Register.Index == aactx->colorOutput) { 320 dst->Register.File = TGSI_FILE_TEMPORARY; 321 dst->Register.Index = aactx->colorTemp; 322 } 323 } 324 325 ctx->emit_instruction(ctx, inst); 326 } 327} 328 329 330/** 331 * Generate the frag shader we'll use for drawing AA lines. 332 * This will be the user's shader plus some texture/modulate instructions. 333 */ 334static boolean 335generate_aaline_fs(struct aaline_stage *aaline) 336{ 337 const struct pipe_shader_state *orig_fs = &aaline->fs->state; 338 struct pipe_shader_state aaline_fs; 339 struct aa_transform_context transform; 340 341#define MAX 1000 342 343 aaline_fs = *orig_fs; /* copy to init */ 344 aaline_fs.tokens = MALLOC(sizeof(struct tgsi_token) * MAX); 345 if (aaline_fs.tokens == NULL) 346 return FALSE; 347 348 memset(&transform, 0, sizeof(transform)); 349 transform.colorOutput = -1; 350 transform.maxInput = -1; 351 transform.maxGeneric = -1; 352 transform.colorTemp = -1; 353 transform.texTemp = -1; 354 transform.firstInstruction = TRUE; 355 transform.base.transform_instruction = aa_transform_inst; 356 transform.base.transform_declaration = aa_transform_decl; 357 358 tgsi_transform_shader(orig_fs->tokens, 359 (struct tgsi_token *) aaline_fs.tokens, 360 MAX, &transform.base); 361 362#if 0 /* DEBUG */ 363 tgsi_dump(orig_fs->tokens, 0); 364 tgsi_dump(aaline_fs.tokens, 0); 365#endif 366 367 aaline->fs->sampler_unit = transform.freeSampler; 368 369 aaline->fs->aaline_fs 370 = aaline->driver_create_fs_state(aaline->pipe, &aaline_fs); 371 if (aaline->fs->aaline_fs == NULL) 372 goto fail; 373 374 aaline->fs->generic_attrib = transform.maxGeneric + 1; 375 FREE((void *)aaline_fs.tokens); 376 return TRUE; 377 378fail: 379 FREE((void *)aaline_fs.tokens); 380 return FALSE; 381} 382 383 384/** 385 * Create the texture map we'll use for antialiasing the lines. 386 */ 387static boolean 388aaline_create_texture(struct aaline_stage *aaline) 389{ 390 struct pipe_context *pipe = aaline->pipe; 391 struct pipe_screen *screen = pipe->screen; 392 struct pipe_texture texTemp; 393 uint level; 394 395 memset(&texTemp, 0, sizeof(texTemp)); 396 texTemp.target = PIPE_TEXTURE_2D; 397 texTemp.format = PIPE_FORMAT_A8_UNORM; /* XXX verify supported by driver! */ 398 texTemp.last_level = MAX_TEXTURE_LEVEL; 399 texTemp.width0 = 1 << MAX_TEXTURE_LEVEL; 400 texTemp.height0 = 1 << MAX_TEXTURE_LEVEL; 401 texTemp.depth0 = 1; 402 403 aaline->texture = screen->texture_create(screen, &texTemp); 404 if (!aaline->texture) 405 return FALSE; 406 407 /* Fill in mipmap images. 408 * Basically each level is solid opaque, except for the outermost 409 * texels which are zero. Special case the 1x1 and 2x2 levels. 410 */ 411 for (level = 0; level <= MAX_TEXTURE_LEVEL; level++) { 412 struct pipe_transfer *transfer; 413 const uint size = u_minify(aaline->texture->width0, level); 414 ubyte *data; 415 uint i, j; 416 417 assert(aaline->texture->width0 == aaline->texture->height0); 418 419 /* This texture is new, no need to flush. 420 */ 421 transfer = screen->get_tex_transfer(screen, aaline->texture, 0, level, 0, 422 PIPE_TRANSFER_WRITE, 0, 0, size, size); 423 data = screen->transfer_map(screen, transfer); 424 if (data == NULL) 425 return FALSE; 426 427 for (i = 0; i < size; i++) { 428 for (j = 0; j < size; j++) { 429 ubyte d; 430 if (size == 1) { 431 d = 255; 432 } 433 else if (size == 2) { 434 d = 200; /* tuneable */ 435 } 436 else if (i == 0 || j == 0 || i == size - 1 || j == size - 1) { 437 d = 0; 438 } 439 else { 440 d = 255; 441 } 442 data[i * transfer->stride + j] = d; 443 } 444 } 445 446 /* unmap */ 447 screen->transfer_unmap(screen, transfer); 448 screen->tex_transfer_destroy(transfer); 449 } 450 return TRUE; 451} 452 453 454/** 455 * Create the sampler CSO that'll be used for antialiasing. 456 * By using a mipmapped texture, we don't have to generate a different 457 * texture image for each line size. 458 */ 459static boolean 460aaline_create_sampler(struct aaline_stage *aaline) 461{ 462 struct pipe_sampler_state sampler; 463 struct pipe_context *pipe = aaline->pipe; 464 465 memset(&sampler, 0, sizeof(sampler)); 466 sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 467 sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 468 sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 469 sampler.min_mip_filter = PIPE_TEX_MIPFILTER_LINEAR; 470 sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; 471 sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; 472 sampler.normalized_coords = 1; 473 sampler.min_lod = 0.0f; 474 sampler.max_lod = MAX_TEXTURE_LEVEL; 475 476 aaline->sampler_cso = pipe->create_sampler_state(pipe, &sampler); 477 if (aaline->sampler_cso == NULL) 478 return FALSE; 479 480 return TRUE; 481} 482 483 484/** 485 * When we're about to draw our first AA line in a batch, this function is 486 * called to tell the driver to bind our modified fragment shader. 487 */ 488static boolean 489bind_aaline_fragment_shader(struct aaline_stage *aaline) 490{ 491 struct draw_context *draw = aaline->stage.draw; 492 493 if (!aaline->fs->aaline_fs && 494 !generate_aaline_fs(aaline)) 495 return FALSE; 496 497 draw->suspend_flushing = TRUE; 498 aaline->driver_bind_fs_state(aaline->pipe, aaline->fs->aaline_fs); 499 draw->suspend_flushing = FALSE; 500 501 return TRUE; 502} 503 504 505 506static INLINE struct aaline_stage * 507aaline_stage( struct draw_stage *stage ) 508{ 509 return (struct aaline_stage *) stage; 510} 511 512 513/** 514 * Draw a wide line by drawing a quad, using geometry which will 515 * fullfill GL's antialiased line requirements. 516 */ 517static void 518aaline_line(struct draw_stage *stage, struct prim_header *header) 519{ 520 const struct aaline_stage *aaline = aaline_stage(stage); 521 const float half_width = aaline->half_line_width; 522 struct prim_header tri; 523 struct vertex_header *v[8]; 524 uint texPos = aaline->tex_slot; 525 uint posPos = aaline->pos_slot; 526 float *pos, *tex; 527 float dx = header->v[1]->data[posPos][0] - header->v[0]->data[posPos][0]; 528 float dy = header->v[1]->data[posPos][1] - header->v[0]->data[posPos][1]; 529 double a = atan2(dy, dx); 530 float c_a = (float) cos(a), s_a = (float) sin(a); 531 uint i; 532 533 /* XXX the ends of lines aren't quite perfect yet, but probably passable */ 534 dx = 0.5F * half_width; 535 dy = half_width; 536 537 /* allocate/dup new verts */ 538 for (i = 0; i < 8; i++) { 539 v[i] = dup_vert(stage, header->v[i/4], i); 540 } 541 542 /* 543 * Quad strip for line from v0 to v1 (*=endpoints): 544 * 545 * 1 3 5 7 546 * +---+---------------------+---+ 547 * | | 548 * | *v0 v1* | 549 * | | 550 * +---+---------------------+---+ 551 * 0 2 4 6 552 */ 553 554 /* new verts */ 555 pos = v[0]->data[posPos]; 556 pos[0] += (-dx * c_a - dy * s_a); 557 pos[1] += (-dx * s_a + dy * c_a); 558 559 pos = v[1]->data[posPos]; 560 pos[0] += (-dx * c_a - -dy * s_a); 561 pos[1] += (-dx * s_a + -dy * c_a); 562 563 pos = v[2]->data[posPos]; 564 pos[0] += ( dx * c_a - dy * s_a); 565 pos[1] += ( dx * s_a + dy * c_a); 566 567 pos = v[3]->data[posPos]; 568 pos[0] += ( dx * c_a - -dy * s_a); 569 pos[1] += ( dx * s_a + -dy * c_a); 570 571 pos = v[4]->data[posPos]; 572 pos[0] += (-dx * c_a - dy * s_a); 573 pos[1] += (-dx * s_a + dy * c_a); 574 575 pos = v[5]->data[posPos]; 576 pos[0] += (-dx * c_a - -dy * s_a); 577 pos[1] += (-dx * s_a + -dy * c_a); 578 579 pos = v[6]->data[posPos]; 580 pos[0] += ( dx * c_a - dy * s_a); 581 pos[1] += ( dx * s_a + dy * c_a); 582 583 pos = v[7]->data[posPos]; 584 pos[0] += ( dx * c_a - -dy * s_a); 585 pos[1] += ( dx * s_a + -dy * c_a); 586 587 /* new texcoords */ 588 tex = v[0]->data[texPos]; 589 ASSIGN_4V(tex, 0, 0, 0, 1); 590 591 tex = v[1]->data[texPos]; 592 ASSIGN_4V(tex, 0, 1, 0, 1); 593 594 tex = v[2]->data[texPos]; 595 ASSIGN_4V(tex, .5, 0, 0, 1); 596 597 tex = v[3]->data[texPos]; 598 ASSIGN_4V(tex, .5, 1, 0, 1); 599 600 tex = v[4]->data[texPos]; 601 ASSIGN_4V(tex, .5, 0, 0, 1); 602 603 tex = v[5]->data[texPos]; 604 ASSIGN_4V(tex, .5, 1, 0, 1); 605 606 tex = v[6]->data[texPos]; 607 ASSIGN_4V(tex, 1, 0, 0, 1); 608 609 tex = v[7]->data[texPos]; 610 ASSIGN_4V(tex, 1, 1, 0, 1); 611 612 /* emit 6 tris for the quad strip */ 613 tri.v[0] = v[2]; tri.v[1] = v[1]; tri.v[2] = v[0]; 614 stage->next->tri( stage->next, &tri ); 615 616 tri.v[0] = v[3]; tri.v[1] = v[1]; tri.v[2] = v[2]; 617 stage->next->tri( stage->next, &tri ); 618 619 tri.v[0] = v[4]; tri.v[1] = v[3]; tri.v[2] = v[2]; 620 stage->next->tri( stage->next, &tri ); 621 622 tri.v[0] = v[5]; tri.v[1] = v[3]; tri.v[2] = v[4]; 623 stage->next->tri( stage->next, &tri ); 624 625 tri.v[0] = v[6]; tri.v[1] = v[5]; tri.v[2] = v[4]; 626 stage->next->tri( stage->next, &tri ); 627 628 tri.v[0] = v[7]; tri.v[1] = v[5]; tri.v[2] = v[6]; 629 stage->next->tri( stage->next, &tri ); 630} 631 632 633static void 634aaline_first_line(struct draw_stage *stage, struct prim_header *header) 635{ 636 auto struct aaline_stage *aaline = aaline_stage(stage); 637 struct draw_context *draw = stage->draw; 638 struct pipe_context *pipe = aaline->pipe; 639 uint num_samplers; 640 641 assert(draw->rasterizer->line_smooth); 642 643 if (draw->rasterizer->line_width <= 3.0) 644 aaline->half_line_width = 1.5f; 645 else 646 aaline->half_line_width = 0.5f * draw->rasterizer->line_width; 647 648 /* 649 * Bind (generate) our fragprog, sampler and texture 650 */ 651 if (!bind_aaline_fragment_shader(aaline)) { 652 stage->line = draw_pipe_passthrough_line; 653 stage->line(stage, header); 654 return; 655 } 656 657 /* update vertex attrib info */ 658 aaline->tex_slot = draw_current_shader_outputs(draw); 659 aaline->pos_slot = draw_current_shader_position_output(draw);; 660 661 /* advertise the extra post-transformed vertex attribute */ 662 draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC; 663 draw->extra_shader_outputs.semantic_index = aaline->fs->generic_attrib; 664 draw->extra_shader_outputs.slot = aaline->tex_slot; 665 666 /* how many samplers? */ 667 /* we'll use sampler/texture[pstip->sampler_unit] for the stipple */ 668 num_samplers = MAX2(aaline->num_textures, aaline->num_samplers); 669 num_samplers = MAX2(num_samplers, aaline->fs->sampler_unit + 1); 670 671 aaline->state.sampler[aaline->fs->sampler_unit] = aaline->sampler_cso; 672 pipe_texture_reference(&aaline->state.texture[aaline->fs->sampler_unit], 673 aaline->texture); 674 675 draw->suspend_flushing = TRUE; 676 aaline->driver_bind_sampler_states(pipe, num_samplers, aaline->state.sampler); 677 aaline->driver_set_sampler_textures(pipe, num_samplers, aaline->state.texture); 678 draw->suspend_flushing = FALSE; 679 680 /* now really draw first line */ 681 stage->line = aaline_line; 682 stage->line(stage, header); 683} 684 685 686static void 687aaline_flush(struct draw_stage *stage, unsigned flags) 688{ 689 struct draw_context *draw = stage->draw; 690 struct aaline_stage *aaline = aaline_stage(stage); 691 struct pipe_context *pipe = aaline->pipe; 692 693 stage->line = aaline_first_line; 694 stage->next->flush( stage->next, flags ); 695 696 /* restore original frag shader, texture, sampler state */ 697 draw->suspend_flushing = TRUE; 698 aaline->driver_bind_fs_state(pipe, aaline->fs->driver_fs); 699 aaline->driver_bind_sampler_states(pipe, aaline->num_samplers, 700 aaline->state.sampler); 701 aaline->driver_set_sampler_textures(pipe, aaline->num_textures, 702 aaline->state.texture); 703 draw->suspend_flushing = FALSE; 704 705 draw->extra_shader_outputs.slot = 0; 706} 707 708 709static void 710aaline_reset_stipple_counter(struct draw_stage *stage) 711{ 712 stage->next->reset_stipple_counter( stage->next ); 713} 714 715 716static void 717aaline_destroy(struct draw_stage *stage) 718{ 719 struct aaline_stage *aaline = aaline_stage(stage); 720 uint i; 721 722 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { 723 pipe_texture_reference(&aaline->state.texture[i], NULL); 724 } 725 726 if (aaline->sampler_cso) 727 aaline->pipe->delete_sampler_state(aaline->pipe, aaline->sampler_cso); 728 729 if (aaline->texture) 730 pipe_texture_reference(&aaline->texture, NULL); 731 732 draw_free_temp_verts( stage ); 733 734 FREE( stage ); 735} 736 737 738static struct aaline_stage * 739draw_aaline_stage(struct draw_context *draw) 740{ 741 struct aaline_stage *aaline = CALLOC_STRUCT(aaline_stage); 742 if (aaline == NULL) 743 return NULL; 744 745 if (!draw_alloc_temp_verts( &aaline->stage, 8 )) 746 goto fail; 747 748 aaline->stage.draw = draw; 749 aaline->stage.name = "aaline"; 750 aaline->stage.next = NULL; 751 aaline->stage.point = draw_pipe_passthrough_point; 752 aaline->stage.line = aaline_first_line; 753 aaline->stage.tri = draw_pipe_passthrough_tri; 754 aaline->stage.flush = aaline_flush; 755 aaline->stage.reset_stipple_counter = aaline_reset_stipple_counter; 756 aaline->stage.destroy = aaline_destroy; 757 758 return aaline; 759 760 fail: 761 if (aaline) 762 aaline_destroy(&aaline->stage); 763 764 return NULL; 765} 766 767 768static struct aaline_stage * 769aaline_stage_from_pipe(struct pipe_context *pipe) 770{ 771 struct draw_context *draw = (struct draw_context *) pipe->draw; 772 return aaline_stage(draw->pipeline.aaline); 773} 774 775 776/** 777 * This function overrides the driver's create_fs_state() function and 778 * will typically be called by the state tracker. 779 */ 780static void * 781aaline_create_fs_state(struct pipe_context *pipe, 782 const struct pipe_shader_state *fs) 783{ 784 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe); 785 struct aaline_fragment_shader *aafs = CALLOC_STRUCT(aaline_fragment_shader); 786 if (aafs == NULL) 787 return NULL; 788 789 aafs->state = *fs; 790 791 /* pass-through */ 792 aafs->driver_fs = aaline->driver_create_fs_state(aaline->pipe, fs); 793 794 return aafs; 795} 796 797 798static void 799aaline_bind_fs_state(struct pipe_context *pipe, void *fs) 800{ 801 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe); 802 struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs; 803 804 /* save current */ 805 aaline->fs = aafs; 806 /* pass-through */ 807 aaline->driver_bind_fs_state(aaline->pipe, 808 (aafs ? aafs->driver_fs : NULL)); 809} 810 811 812static void 813aaline_delete_fs_state(struct pipe_context *pipe, void *fs) 814{ 815 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe); 816 struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs; 817 /* pass-through */ 818 aaline->driver_delete_fs_state(aaline->pipe, aafs->driver_fs); 819 820 if (aafs->aaline_fs) 821 aaline->driver_delete_fs_state(aaline->pipe, aafs->aaline_fs); 822 823 FREE(aafs); 824} 825 826 827static void 828aaline_bind_sampler_states(struct pipe_context *pipe, 829 unsigned num, void **sampler) 830{ 831 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe); 832 833 /* save current */ 834 memcpy(aaline->state.sampler, sampler, num * sizeof(void *)); 835 aaline->num_samplers = num; 836 837 /* pass-through */ 838 aaline->driver_bind_sampler_states(aaline->pipe, num, sampler); 839} 840 841 842static void 843aaline_set_sampler_textures(struct pipe_context *pipe, 844 unsigned num, struct pipe_texture **texture) 845{ 846 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe); 847 uint i; 848 849 /* save current */ 850 for (i = 0; i < num; i++) { 851 pipe_texture_reference(&aaline->state.texture[i], texture[i]); 852 } 853 for ( ; i < PIPE_MAX_SAMPLERS; i++) { 854 pipe_texture_reference(&aaline->state.texture[i], NULL); 855 } 856 aaline->num_textures = num; 857 858 /* pass-through */ 859 aaline->driver_set_sampler_textures(aaline->pipe, num, texture); 860} 861 862 863/** 864 * Called by drivers that want to install this AA line prim stage 865 * into the draw module's pipeline. This will not be used if the 866 * hardware has native support for AA lines. 867 */ 868boolean 869draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe) 870{ 871 struct aaline_stage *aaline; 872 873 pipe->draw = (void *) draw; 874 875 /* 876 * Create / install AA line drawing / prim stage 877 */ 878 aaline = draw_aaline_stage( draw ); 879 if (!aaline) 880 goto fail; 881 882 aaline->pipe = pipe; 883 884 /* create special texture, sampler state */ 885 if (!aaline_create_texture(aaline)) 886 goto fail; 887 888 if (!aaline_create_sampler(aaline)) 889 goto fail; 890 891 /* save original driver functions */ 892 aaline->driver_create_fs_state = pipe->create_fs_state; 893 aaline->driver_bind_fs_state = pipe->bind_fs_state; 894 aaline->driver_delete_fs_state = pipe->delete_fs_state; 895 896 aaline->driver_bind_sampler_states = pipe->bind_fragment_sampler_states; 897 aaline->driver_set_sampler_textures = pipe->set_fragment_sampler_textures; 898 899 /* override the driver's functions */ 900 pipe->create_fs_state = aaline_create_fs_state; 901 pipe->bind_fs_state = aaline_bind_fs_state; 902 pipe->delete_fs_state = aaline_delete_fs_state; 903 904 pipe->bind_fragment_sampler_states = aaline_bind_sampler_states; 905 pipe->set_fragment_sampler_textures = aaline_set_sampler_textures; 906 907 /* Install once everything is known to be OK: 908 */ 909 draw->pipeline.aaline = &aaline->stage; 910 911 return TRUE; 912 913 fail: 914 if (aaline) 915 aaline->stage.destroy( &aaline->stage ); 916 917 return FALSE; 918} 919