xref: /aosp_15_r20/external/mesa3d/src/gallium/auxiliary/draw/draw_pipe_aaline.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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