1 /**************************************************************************
2 *
3 * Copyright 2007-2018 VMware, Inc.
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 VMWARE 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 triangles (with extra generic)
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 #include "util/u_inlines.h"
39
40 #include "util/format/u_format.h"
41 #include "util/u_math.h"
42 #include "util/u_memory.h"
43
44 #include "tgsi/tgsi_transform.h"
45 #include "tgsi/tgsi_dump.h"
46
47 #include "draw_context.h"
48 #include "draw_private.h"
49 #include "draw_pipe.h"
50
51 #include "nir.h"
52 #include "nir/nir_draw_helpers.h"
53
54 /** Approx number of new tokens for instructions in aa_transform_inst() */
55 #define NUM_NEW_TOKENS 53
56
57
58 /**
59 * Subclass of pipe_shader_state to carry extra fragment shader info.
60 */
61 struct aaline_fragment_shader
62 {
63 struct pipe_shader_state state;
64 void *driver_fs;
65 void *aaline_fs;
66 int generic_attrib; /**< generic used for distance */
67 };
68
69
70 /**
71 * Subclass of draw_stage
72 */
73 struct 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 new generic */
80 unsigned coord_slot;
81 /** position, not necessarily output zero */
82 unsigned pos_slot;
83
84
85 /*
86 * Currently bound state
87 */
88 struct aaline_fragment_shader *fs;
89
90 /*
91 * Driver interface/override functions
92 */
93 void * (*driver_create_fs_state)(struct pipe_context *,
94 const struct pipe_shader_state *);
95 void (*driver_bind_fs_state)(struct pipe_context *, void *);
96 void (*driver_delete_fs_state)(struct pipe_context *, void *);
97 };
98
99
100
101 /**
102 * Subclass of tgsi_transform_context, used for transforming the
103 * user's fragment shader to add the special AA instructions.
104 */
105 struct aa_transform_context {
106 struct tgsi_transform_context base;
107 uint64_t tempsUsed; /**< bitmask */
108 int colorOutput; /**< which output is the primary color */
109 int maxInput, maxGeneric; /**< max input index found */
110 int numImm; /**< number of immediate regsters */
111 int colorTemp, aaTemp; /**< temp registers */
112 };
113
114 /**
115 * TGSI declaration transform callback.
116 * Look for a free input attrib, and two free temp regs.
117 */
118 static void
aa_transform_decl(struct tgsi_transform_context * ctx,struct tgsi_full_declaration * decl)119 aa_transform_decl(struct tgsi_transform_context *ctx,
120 struct tgsi_full_declaration *decl)
121 {
122 struct aa_transform_context *aactx = (struct aa_transform_context *)ctx;
123
124 if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
125 decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
126 decl->Semantic.Index == 0) {
127 aactx->colorOutput = decl->Range.First;
128 }
129 else if (decl->Declaration.File == TGSI_FILE_INPUT) {
130 if ((int) decl->Range.Last > aactx->maxInput)
131 aactx->maxInput = decl->Range.Last;
132 if (decl->Semantic.Name == TGSI_SEMANTIC_GENERIC &&
133 (int) decl->Semantic.Index > aactx->maxGeneric) {
134 aactx->maxGeneric = decl->Semantic.Index;
135 }
136 }
137 else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
138 unsigned i;
139 for (i = decl->Range.First;
140 i <= decl->Range.Last; i++) {
141 /*
142 * XXX this bitfield doesn't really cut it...
143 */
144 aactx->tempsUsed |= UINT64_C(1) << i;
145 }
146 }
147
148 ctx->emit_declaration(ctx, decl);
149 }
150
151 /**
152 * TGSI immediate declaration transform callback.
153 */
154 static void
aa_immediate(struct tgsi_transform_context * ctx,struct tgsi_full_immediate * imm)155 aa_immediate(struct tgsi_transform_context *ctx,
156 struct tgsi_full_immediate *imm)
157 {
158 struct aa_transform_context *aactx = (struct aa_transform_context *)ctx;
159
160 ctx->emit_immediate(ctx, imm);
161 aactx->numImm++;
162 }
163
164 /**
165 * Find the lowest zero bit, or -1 if bitfield is all ones.
166 */
167 static int
free_bit(uint64_t bitfield)168 free_bit(uint64_t bitfield)
169 {
170 return ffsll(~bitfield) - 1;
171 }
172
173
174 /**
175 * TGSI transform prolog callback.
176 */
177 static void
aa_transform_prolog(struct tgsi_transform_context * ctx)178 aa_transform_prolog(struct tgsi_transform_context *ctx)
179 {
180 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
181 uint64_t usedTemps = aactx->tempsUsed;
182
183 /* find two free temp regs */
184 aactx->colorTemp = free_bit(usedTemps);
185 usedTemps |= UINT64_C(1) << aactx->colorTemp;
186 aactx->aaTemp = free_bit(usedTemps);
187 assert(aactx->colorTemp >= 0);
188 assert(aactx->aaTemp >= 0);
189
190 /* declare new generic input/texcoord */
191 tgsi_transform_input_decl(ctx, aactx->maxInput + 1,
192 TGSI_SEMANTIC_GENERIC, aactx->maxGeneric + 1,
193 TGSI_INTERPOLATE_LINEAR);
194
195 /* declare new temp regs */
196 tgsi_transform_temp_decl(ctx, aactx->aaTemp);
197 tgsi_transform_temp_decl(ctx, aactx->colorTemp);
198
199 /* declare new immediate reg */
200 tgsi_transform_immediate_decl(ctx, 2.0, -1.0, 0.0, 0.25);
201 }
202
203
204 /**
205 * TGSI transform epilog callback.
206 */
207 static void
aa_transform_epilog(struct tgsi_transform_context * ctx)208 aa_transform_epilog(struct tgsi_transform_context *ctx)
209 {
210 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
211
212 if (aactx->colorOutput != -1) {
213 struct tgsi_full_instruction inst;
214 /* insert distance-based coverage code for antialiasing. */
215
216 /* saturate(linewidth - fabs(interpx), linelength - fabs(interpz) */
217 inst = tgsi_default_full_instruction();
218 inst.Instruction.Saturate = true;
219 inst.Instruction.Opcode = TGSI_OPCODE_ADD;
220 inst.Instruction.NumDstRegs = 1;
221 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY,
222 aactx->aaTemp, TGSI_WRITEMASK_XZ);
223 inst.Instruction.NumSrcRegs = 2;
224 tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_INPUT, aactx->maxInput + 1,
225 TGSI_SWIZZLE_X, TGSI_SWIZZLE_X,
226 TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z);
227 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_INPUT, aactx->maxInput + 1,
228 TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y,
229 TGSI_SWIZZLE_W, TGSI_SWIZZLE_W);
230 inst.Src[1].Register.Absolute = true;
231 inst.Src[1].Register.Negate = true;
232 ctx->emit_instruction(ctx, &inst);
233
234 /* linelength * 2 - 1 */
235 tgsi_transform_op3_swz_inst(ctx, TGSI_OPCODE_MAD,
236 TGSI_FILE_TEMPORARY, aactx->aaTemp,
237 TGSI_WRITEMASK_Y,
238 TGSI_FILE_INPUT, aactx->maxInput + 1,
239 TGSI_SWIZZLE_W, false,
240 TGSI_FILE_IMMEDIATE, aactx->numImm,
241 TGSI_SWIZZLE_X,
242 TGSI_FILE_IMMEDIATE, aactx->numImm,
243 TGSI_SWIZZLE_Y);
244
245 /* MIN height alpha */
246 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN,
247 TGSI_FILE_TEMPORARY, aactx->aaTemp,
248 TGSI_WRITEMASK_Z,
249 TGSI_FILE_TEMPORARY, aactx->aaTemp,
250 TGSI_SWIZZLE_Z,
251 TGSI_FILE_TEMPORARY, aactx->aaTemp,
252 TGSI_SWIZZLE_Y, false);
253
254 /* MUL width / height alpha */
255 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL,
256 TGSI_FILE_TEMPORARY, aactx->aaTemp,
257 TGSI_WRITEMASK_W,
258 TGSI_FILE_TEMPORARY, aactx->aaTemp,
259 TGSI_SWIZZLE_X,
260 TGSI_FILE_TEMPORARY, aactx->aaTemp,
261 TGSI_SWIZZLE_Z, false);
262
263 /* MOV rgb */
264 tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV,
265 TGSI_FILE_OUTPUT, aactx->colorOutput,
266 TGSI_WRITEMASK_XYZ,
267 TGSI_FILE_TEMPORARY, aactx->colorTemp);
268
269 /* MUL alpha */
270 tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,
271 TGSI_FILE_OUTPUT, aactx->colorOutput,
272 TGSI_WRITEMASK_W,
273 TGSI_FILE_TEMPORARY, aactx->colorTemp,
274 TGSI_FILE_TEMPORARY, aactx->aaTemp, false);
275 }
276 }
277
278
279 /**
280 * TGSI instruction transform callback.
281 * Replace writes to result.color w/ a temp reg.
282 */
283 static void
aa_transform_inst(struct tgsi_transform_context * ctx,struct tgsi_full_instruction * inst)284 aa_transform_inst(struct tgsi_transform_context *ctx,
285 struct tgsi_full_instruction *inst)
286 {
287 struct aa_transform_context *aactx = (struct aa_transform_context *) ctx;
288 unsigned i;
289
290 /*
291 * Look for writes to result.color and replace with colorTemp reg.
292 */
293 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
294 struct tgsi_full_dst_register *dst = &inst->Dst[i];
295 if (dst->Register.File == TGSI_FILE_OUTPUT &&
296 dst->Register.Index == aactx->colorOutput) {
297 dst->Register.File = TGSI_FILE_TEMPORARY;
298 dst->Register.Index = aactx->colorTemp;
299 }
300 }
301
302 ctx->emit_instruction(ctx, inst);
303 }
304
305
306 /**
307 * Generate the frag shader we'll use for drawing AA lines.
308 * This will be the user's shader plus some arithmetic instructions.
309 */
310 static bool
generate_aaline_fs(struct aaline_stage * aaline)311 generate_aaline_fs(struct aaline_stage *aaline)
312 {
313 struct pipe_context *pipe = aaline->stage.draw->pipe;
314 const struct pipe_shader_state *orig_fs = &aaline->fs->state;
315 struct pipe_shader_state aaline_fs;
316 struct aa_transform_context transform;
317 const unsigned newLen = tgsi_num_tokens(orig_fs->tokens) + NUM_NEW_TOKENS;
318
319 aaline_fs = *orig_fs; /* copy to init */
320
321 memset(&transform, 0, sizeof(transform));
322 transform.colorOutput = -1;
323 transform.maxInput = -1;
324 transform.maxGeneric = -1;
325 transform.colorTemp = -1;
326 transform.aaTemp = -1;
327 transform.base.prolog = aa_transform_prolog;
328 transform.base.epilog = aa_transform_epilog;
329 transform.base.transform_instruction = aa_transform_inst;
330 transform.base.transform_declaration = aa_transform_decl;
331 transform.base.transform_immediate = aa_immediate;
332
333 aaline_fs.tokens = tgsi_transform_shader(orig_fs->tokens, newLen, &transform.base);
334 if (!aaline_fs.tokens)
335 return false;
336
337 #if 0 /* debug */
338 debug_printf("draw_aaline, orig shader:\n");
339 tgsi_dump(orig_fs->tokens, 0);
340 debug_printf("draw_aaline, new shader:\n");
341 tgsi_dump(aaline_fs.tokens, 0);
342 #endif
343
344 aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs);
345 if (aaline->fs->aaline_fs != NULL)
346 aaline->fs->generic_attrib = transform.maxGeneric + 1;
347
348 FREE((void *)aaline_fs.tokens);
349 return aaline->fs->aaline_fs != NULL;
350 }
351
352 static bool
generate_aaline_fs_nir(struct aaline_stage * aaline)353 generate_aaline_fs_nir(struct aaline_stage *aaline)
354 {
355 struct pipe_context *pipe = aaline->stage.draw->pipe;
356 const struct pipe_shader_state *orig_fs = &aaline->fs->state;
357 struct pipe_shader_state aaline_fs;
358
359 aaline_fs = *orig_fs; /* copy to init */
360 aaline_fs.ir.nir = nir_shader_clone(NULL, orig_fs->ir.nir);
361 if (!aaline_fs.ir.nir)
362 return false;
363
364 nir_lower_aaline_fs(aaline_fs.ir.nir, &aaline->fs->generic_attrib, NULL, NULL);
365 aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs);
366 if (aaline->fs->aaline_fs == NULL)
367 return false;
368
369 return true;
370 }
371
372 /**
373 * When we're about to draw our first AA line in a batch, this function is
374 * called to tell the driver to bind our modified fragment shader.
375 */
376 static bool
bind_aaline_fragment_shader(struct aaline_stage * aaline)377 bind_aaline_fragment_shader(struct aaline_stage *aaline)
378 {
379 struct draw_context *draw = aaline->stage.draw;
380 struct pipe_context *pipe = draw->pipe;
381
382 if (!aaline->fs->aaline_fs) {
383 if (aaline->fs->state.type == PIPE_SHADER_IR_NIR) {
384 if (!generate_aaline_fs_nir(aaline))
385 return false;
386 } else
387 if (!generate_aaline_fs(aaline))
388 return false;
389 }
390
391 draw->suspend_flushing = true;
392 aaline->driver_bind_fs_state(pipe, aaline->fs->aaline_fs);
393 draw->suspend_flushing = false;
394
395 return true;
396 }
397
398
399
400 static inline struct aaline_stage *
aaline_stage(struct draw_stage * stage)401 aaline_stage(struct draw_stage *stage)
402 {
403 return (struct aaline_stage *) stage;
404 }
405
406
407 /**
408 * Draw a wide line by drawing a quad, using geometry which will
409 * fullfill GL's antialiased line requirements.
410 */
411 static void
aaline_line(struct draw_stage * stage,struct prim_header * header)412 aaline_line(struct draw_stage *stage, struct prim_header *header)
413 {
414 const struct aaline_stage *aaline = aaline_stage(stage);
415 const float half_width = aaline->half_line_width;
416 struct prim_header tri;
417 struct vertex_header *v[8];
418 unsigned coordPos = aaline->coord_slot;
419 unsigned posPos = aaline->pos_slot;
420 float *pos, *tex;
421 float dx = header->v[1]->data[posPos][0] - header->v[0]->data[posPos][0];
422 float dy = header->v[1]->data[posPos][1] - header->v[0]->data[posPos][1];
423 float length = sqrtf(dx * dx + dy * dy);
424 float c_a = dx / length, s_a = dy / length;
425 float half_length = 0.5 * length;
426 float t_l, t_w;
427 unsigned i;
428
429 half_length = half_length + 0.5f;
430
431 t_w = half_width;
432 t_l = 0.5f;
433
434 /* allocate/dup new verts */
435 for (i = 0; i < 4; i++) {
436 v[i] = dup_vert(stage, header->v[i/2], i);
437 }
438
439 /*
440 * Quad strip for line from v0 to v1 (*=endpoints):
441 *
442 * 1 3
443 * +-----------------------------+
444 * | |
445 * | *v0 v1* |
446 * | |
447 * +-----------------------------+
448 * 0 2
449 */
450
451 /*
452 * We increase line length by 0.5 pixels (at each endpoint),
453 * and calculate the tri endpoints by moving them half-width
454 * distance away perpendicular to the line.
455 * XXX: since we change line endpoints (by 0.5 pixel), should
456 * actually re-interpolate all other values?
457 */
458
459 /* new verts */
460 pos = v[0]->data[posPos];
461 pos[0] += (-t_l * c_a - t_w * s_a);
462 pos[1] += (-t_l * s_a + t_w * c_a);
463
464 pos = v[1]->data[posPos];
465 pos[0] += (-t_l * c_a - -t_w * s_a);
466 pos[1] += (-t_l * s_a + -t_w * c_a);
467
468 pos = v[2]->data[posPos];
469 pos[0] += (t_l * c_a - t_w * s_a);
470 pos[1] += (t_l * s_a + t_w * c_a);
471
472 pos = v[3]->data[posPos];
473 pos[0] += (t_l * c_a - -t_w * s_a);
474 pos[1] += (t_l * s_a + -t_w * c_a);
475
476 /* new texcoords */
477 tex = v[0]->data[coordPos];
478 ASSIGN_4V(tex, -half_width, half_width, -half_length, half_length);
479
480 tex = v[1]->data[coordPos];
481 ASSIGN_4V(tex, half_width, half_width, -half_length, half_length);
482
483 tex = v[2]->data[coordPos];
484 ASSIGN_4V(tex, -half_width, half_width, half_length, half_length);
485
486 tex = v[3]->data[coordPos];
487 ASSIGN_4V(tex, half_width, half_width, half_length, half_length);
488
489 tri.v[0] = v[2]; tri.v[1] = v[1]; tri.v[2] = v[0];
490 stage->next->tri(stage->next, &tri);
491
492 tri.v[0] = v[3]; tri.v[1] = v[1]; tri.v[2] = v[2];
493 stage->next->tri(stage->next, &tri);
494 }
495
496
497 static void
aaline_first_line(struct draw_stage * stage,struct prim_header * header)498 aaline_first_line(struct draw_stage *stage, struct prim_header *header)
499 {
500 auto struct aaline_stage *aaline = aaline_stage(stage);
501 struct draw_context *draw = stage->draw;
502 struct pipe_context *pipe = draw->pipe;
503 const struct pipe_rasterizer_state *rast = draw->rasterizer;
504 void *r;
505
506 assert(draw->rasterizer->line_smooth && !draw->rasterizer->multisample);
507
508 if (draw->rasterizer->line_width <= 1.0)
509 aaline->half_line_width = 1.0;
510 else
511 aaline->half_line_width = 0.5f * draw->rasterizer->line_width + 0.5f;
512
513 if (!draw->rasterizer->half_pixel_center)
514 /*
515 * The tex coords probably would need adjustments?
516 */
517 debug_printf("aa lines without half pixel center may be wrong\n");
518
519 /*
520 * Bind (generate) our fragprog
521 */
522 if (!bind_aaline_fragment_shader(aaline)) {
523 stage->line = draw_pipe_passthrough_line;
524 stage->line(stage, header);
525 return;
526 }
527
528 draw_aaline_prepare_outputs(draw, draw->pipeline.aaline);
529
530 draw->suspend_flushing = true;
531
532 /* Disable triangle culling, stippling, unfilled mode etc. */
533 r = draw_get_rasterizer_no_cull(draw, rast);
534 pipe->bind_rasterizer_state(pipe, r);
535
536 draw->suspend_flushing = false;
537
538 /* now really draw first line */
539 stage->line = aaline_line;
540 stage->line(stage, header);
541 }
542
543
544 static void
aaline_flush(struct draw_stage * stage,unsigned flags)545 aaline_flush(struct draw_stage *stage, unsigned flags)
546 {
547 struct draw_context *draw = stage->draw;
548 struct aaline_stage *aaline = aaline_stage(stage);
549 struct pipe_context *pipe = draw->pipe;
550
551 stage->line = aaline_first_line;
552 stage->next->flush(stage->next, flags);
553
554 /* restore original frag shader */
555 draw->suspend_flushing = true;
556 aaline->driver_bind_fs_state(pipe, aaline->fs ? aaline->fs->driver_fs : NULL);
557
558 /* restore original rasterizer state */
559 if (draw->rast_handle) {
560 pipe->bind_rasterizer_state(pipe, draw->rast_handle);
561 }
562
563 draw->suspend_flushing = false;
564
565 draw_remove_extra_vertex_attribs(draw);
566 }
567
568
569 static void
aaline_reset_stipple_counter(struct draw_stage * stage)570 aaline_reset_stipple_counter(struct draw_stage *stage)
571 {
572 stage->next->reset_stipple_counter(stage->next);
573 }
574
575
576 static void
aaline_destroy(struct draw_stage * stage)577 aaline_destroy(struct draw_stage *stage)
578 {
579 struct aaline_stage *aaline = aaline_stage(stage);
580 struct pipe_context *pipe = stage->draw->pipe;
581
582 draw_free_temp_verts(stage);
583
584 /* restore the old entry points */
585 pipe->create_fs_state = aaline->driver_create_fs_state;
586 pipe->bind_fs_state = aaline->driver_bind_fs_state;
587 pipe->delete_fs_state = aaline->driver_delete_fs_state;
588
589 FREE(stage);
590 }
591
592
593 static struct aaline_stage *
draw_aaline_stage(struct draw_context * draw)594 draw_aaline_stage(struct draw_context *draw)
595 {
596 struct aaline_stage *aaline = CALLOC_STRUCT(aaline_stage);
597 if (!aaline)
598 return NULL;
599
600 aaline->stage.draw = draw;
601 aaline->stage.name = "aaline";
602 aaline->stage.next = NULL;
603 aaline->stage.point = draw_pipe_passthrough_point;
604 aaline->stage.line = aaline_first_line;
605 aaline->stage.tri = draw_pipe_passthrough_tri;
606 aaline->stage.flush = aaline_flush;
607 aaline->stage.reset_stipple_counter = aaline_reset_stipple_counter;
608 aaline->stage.destroy = aaline_destroy;
609
610 if (!draw_alloc_temp_verts(&aaline->stage, 8)) {
611 aaline->stage.destroy(&aaline->stage);
612 return NULL;
613 }
614
615 return aaline;
616 }
617
618
619 static struct aaline_stage *
aaline_stage_from_pipe(struct pipe_context * pipe)620 aaline_stage_from_pipe(struct pipe_context *pipe)
621 {
622 struct draw_context *draw = (struct draw_context *) pipe->draw;
623
624 if (draw) {
625 return aaline_stage(draw->pipeline.aaline);
626 } else {
627 return NULL;
628 }
629 }
630
631
632 /**
633 * This function overrides the driver's create_fs_state() function and
634 * will typically be called by the gallium frontend.
635 */
636 static void *
aaline_create_fs_state(struct pipe_context * pipe,const struct pipe_shader_state * fs)637 aaline_create_fs_state(struct pipe_context *pipe,
638 const struct pipe_shader_state *fs)
639 {
640 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
641 struct aaline_fragment_shader *aafs = NULL;
642
643 if (!aaline)
644 return NULL;
645
646 aafs = CALLOC_STRUCT(aaline_fragment_shader);
647
648 if (!aafs)
649 return NULL;
650
651 aafs->state.type = fs->type;
652 if (fs->type == PIPE_SHADER_IR_TGSI)
653 aafs->state.tokens = tgsi_dup_tokens(fs->tokens);
654 else
655 aafs->state.ir.nir = nir_shader_clone(NULL, fs->ir.nir);
656
657 /* pass-through */
658 aafs->driver_fs = aaline->driver_create_fs_state(pipe, fs);
659
660 return aafs;
661 }
662
663
664 static void
aaline_bind_fs_state(struct pipe_context * pipe,void * fs)665 aaline_bind_fs_state(struct pipe_context *pipe, void *fs)
666 {
667 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
668 struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs;
669
670 if (!aaline) {
671 return;
672 }
673
674 /* save current */
675 aaline->fs = aafs;
676 /* pass-through */
677 aaline->driver_bind_fs_state(pipe, (aafs ? aafs->driver_fs : NULL));
678 }
679
680
681 static void
aaline_delete_fs_state(struct pipe_context * pipe,void * fs)682 aaline_delete_fs_state(struct pipe_context *pipe, void *fs)
683 {
684 struct aaline_stage *aaline = aaline_stage_from_pipe(pipe);
685 struct aaline_fragment_shader *aafs = (struct aaline_fragment_shader *) fs;
686
687 if (!aafs) {
688 return;
689 }
690
691 if (aaline) {
692 /* pass-through */
693 aaline->driver_delete_fs_state(pipe, aafs->driver_fs);
694
695 if (aafs->aaline_fs)
696 aaline->driver_delete_fs_state(pipe, aafs->aaline_fs);
697 }
698
699 if (aafs->state.type == PIPE_SHADER_IR_TGSI)
700 FREE((void*)aafs->state.tokens);
701 else
702 ralloc_free(aafs->state.ir.nir);
703 FREE(aafs);
704 }
705
706
707 void
draw_aaline_prepare_outputs(struct draw_context * draw,struct draw_stage * stage)708 draw_aaline_prepare_outputs(struct draw_context *draw,
709 struct draw_stage *stage)
710 {
711 struct aaline_stage *aaline = aaline_stage(stage);
712 const struct pipe_rasterizer_state *rast = draw->rasterizer;
713
714 /* update vertex attrib info */
715 aaline->pos_slot = draw_current_shader_position_output(draw);
716
717 if (!rast->line_smooth || rast->multisample)
718 return;
719
720 /* allocate the extra post-transformed vertex attribute */
721 if (aaline->fs && aaline->fs->aaline_fs)
722 aaline->coord_slot = draw_alloc_extra_vertex_attrib(draw,
723 TGSI_SEMANTIC_GENERIC,
724 aaline->fs->generic_attrib);
725 else
726 aaline->coord_slot = -1;
727 }
728
729 /**
730 * Called by drivers that want to install this AA line prim stage
731 * into the draw module's pipeline. This will not be used if the
732 * hardware has native support for AA lines.
733 */
734 bool
draw_install_aaline_stage(struct draw_context * draw,struct pipe_context * pipe)735 draw_install_aaline_stage(struct draw_context *draw, struct pipe_context *pipe)
736 {
737 struct aaline_stage *aaline;
738
739 pipe->draw = (void *) draw;
740
741 /*
742 * Create / install AA line drawing / prim stage
743 */
744 aaline = draw_aaline_stage(draw);
745 if (!aaline)
746 return false;
747
748 /* save original driver functions */
749 aaline->driver_create_fs_state = pipe->create_fs_state;
750 aaline->driver_bind_fs_state = pipe->bind_fs_state;
751 aaline->driver_delete_fs_state = pipe->delete_fs_state;
752
753 /* override the driver's functions */
754 pipe->create_fs_state = aaline_create_fs_state;
755 pipe->bind_fs_state = aaline_bind_fs_state;
756 pipe->delete_fs_state = aaline_delete_fs_state;
757
758 /* Install once everything is known to be OK:
759 */
760 draw->pipeline.aaline = &aaline->stage;
761
762 return true;
763 }
764