1 /**************************************************************************
3 * Copyright 2008 VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
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.
34 * Note: this looks a lot like draw_aaline.c but there's actually little
35 * if any code that can be shared.
41 #include "pipe/p_context.h"
42 #include "pipe/p_defines.h"
43 #include "pipe/p_shader_tokens.h"
45 #include "tgsi/tgsi_transform.h"
46 #include "tgsi/tgsi_dump.h"
48 #include "util/u_math.h"
49 #include "util/u_memory.h"
51 #include "draw_context.h"
53 #include "draw_pipe.h"
56 #include "nir/nir_draw_helpers.h"
58 /** Approx number of new tokens for instructions in aa_transform_inst() */
59 #define NUM_NEW_TOKENS 200
63 * Enabling NORMALIZE might give _slightly_ better results.
64 * Basically, it controls whether we compute distance as d=sqrt(x*x+y*y) or
65 * d=x*x+y*y. Since we're working with a unit circle, the later seems
66 * close enough and saves some costly instructions.
72 * Subclass of pipe_shader_state to carry extra fragment shader info.
74 struct aapoint_fragment_shader
76 struct pipe_shader_state state
;
77 void *driver_fs
; /**< the regular shader */
78 void *aapoint_fs
; /**< the aa point-augmented shader */
79 int generic_attrib
; /**< The generic input attrib/texcoord we'll use */
84 * Subclass of draw_stage
88 struct draw_stage stage
;
90 /** half of pipe_rasterizer_state::point_size */
93 /** vertex attrib slot containing point size */
96 /** this is the vertex attrib slot for the new texcoords */
99 /** vertex attrib slot containing position */
102 /** Currently bound fragment shader */
103 struct aapoint_fragment_shader
*fs
;
106 * Driver interface/override functions
108 void * (*driver_create_fs_state
)(struct pipe_context
*,
109 const struct pipe_shader_state
*);
110 void (*driver_bind_fs_state
)(struct pipe_context
*, void *);
111 void (*driver_delete_fs_state
)(struct pipe_context
*, void *);
117 * Subclass of tgsi_transform_context, used for transforming the
118 * user's fragment shader to add the special AA instructions.
120 struct aa_transform_context
{
121 struct tgsi_transform_context base
;
122 uint tempsUsed
; /**< bitmask */
123 int colorOutput
; /**< which output is the primary color */
124 int maxInput
, maxGeneric
; /**< max input index found */
125 int tmp0
, colorTemp
; /**< temp registers */
130 * TGSI declaration transform callback.
131 * Look for two free temp regs and available input reg for new texcoords.
134 aa_transform_decl(struct tgsi_transform_context
*ctx
,
135 struct tgsi_full_declaration
*decl
)
137 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
139 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
&&
140 decl
->Semantic
.Name
== TGSI_SEMANTIC_COLOR
&&
141 decl
->Semantic
.Index
== 0) {
142 aactx
->colorOutput
= decl
->Range
.First
;
144 else if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
145 if ((int) decl
->Range
.Last
> aactx
->maxInput
)
146 aactx
->maxInput
= decl
->Range
.Last
;
147 if (decl
->Semantic
.Name
== TGSI_SEMANTIC_GENERIC
&&
148 (int) decl
->Semantic
.Index
> aactx
->maxGeneric
) {
149 aactx
->maxGeneric
= decl
->Semantic
.Index
;
152 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
154 for (i
= decl
->Range
.First
;
155 i
<= decl
->Range
.Last
; i
++) {
156 aactx
->tempsUsed
|= (1 << i
);
160 ctx
->emit_declaration(ctx
, decl
);
165 * TGSI transform callback.
166 * Insert new declarations and instructions before first instruction.
169 aa_transform_prolog(struct tgsi_transform_context
*ctx
)
171 /* emit our new declarations before the first instruction */
172 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
173 struct tgsi_full_instruction newInst
;
174 const int texInput
= aactx
->maxInput
+ 1;
178 /* find two free temp regs */
179 for (i
= 0; i
< 32; i
++) {
180 if ((aactx
->tempsUsed
& (1u << i
)) == 0) {
181 /* found a free temp */
184 else if (aactx
->colorTemp
< 0)
185 aactx
->colorTemp
= i
;
191 assert(aactx
->colorTemp
!= aactx
->tmp0
);
195 /* declare new generic input/texcoord */
196 tgsi_transform_input_decl(ctx
, texInput
,
197 TGSI_SEMANTIC_GENERIC
, aactx
->maxGeneric
+ 1,
198 TGSI_INTERPOLATE_LINEAR
);
200 /* declare new temp regs */
201 tgsi_transform_temp_decl(ctx
, tmp0
);
202 tgsi_transform_temp_decl(ctx
, aactx
->colorTemp
);
205 * Emit code to compute fragment coverage, kill if outside point radius
208 * t0.x = distance of fragment from center point
209 * t0.y = boolean, is t0.x > 1.0, also misc temp usage
210 * t0.z = temporary for computing 1/(1-k) value
211 * t0.w = final coverage value
214 /* MUL t0.xy, tex, tex; # compute x^2, y^2 */
215 tgsi_transform_op2_inst(ctx
, TGSI_OPCODE_MUL
,
216 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_XY
,
217 TGSI_FILE_INPUT
, texInput
,
218 TGSI_FILE_INPUT
, texInput
, false);
220 /* ADD t0.x, t0.x, t0.y; # x^2 + y^2 */
221 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_ADD
,
222 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_X
,
223 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_X
,
224 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_Y
, false);
226 #if NORMALIZE /* OPTIONAL normalization of length */
227 /* RSQ t0.x, t0.x; */
228 tgsi_transform_op1_inst(ctx
, TGSI_OPCODE_RSQ
,
229 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_X
,
230 TGSI_FILE_TEMPORARY
, tmp0
);
232 /* RCP t0.x, t0.x; */
233 tgsi_transform_op1_inst(ctx
, TGSI_OPCODE_RCP
,
234 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_X
,
235 TGSI_FILE_TEMPORARY
, tmp0
);
238 /* SGT t0.y, t0.xxxx, tex.wwww; # bool b = d > 1 (NOTE tex.w == 1) */
239 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_SGT
,
240 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_Y
,
241 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_X
,
242 TGSI_FILE_INPUT
, texInput
, TGSI_SWIZZLE_W
, false);
244 /* KILL_IF -tmp0.yyyy; # if -tmp0.y < 0, KILL */
245 tgsi_transform_kill_inst(ctx
, TGSI_FILE_TEMPORARY
, tmp0
,
246 TGSI_SWIZZLE_Y
, TRUE
);
248 /* compute coverage factor = (1-d)/(1-k) */
250 /* SUB t0.z, tex.w, tex.z; # m = 1 - k */
251 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_ADD
,
252 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_Z
,
253 TGSI_FILE_INPUT
, texInput
, TGSI_SWIZZLE_W
,
254 TGSI_FILE_INPUT
, texInput
, TGSI_SWIZZLE_Z
, true);
256 /* RCP t0.z, t0.z; # t0.z = 1 / m */
257 newInst
= tgsi_default_full_instruction();
258 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RCP
;
259 newInst
.Instruction
.NumDstRegs
= 1;
260 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
261 newInst
.Dst
[0].Register
.Index
= tmp0
;
262 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_Z
;
263 newInst
.Instruction
.NumSrcRegs
= 1;
264 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
265 newInst
.Src
[0].Register
.Index
= tmp0
;
266 newInst
.Src
[0].Register
.SwizzleX
= TGSI_SWIZZLE_Z
;
267 ctx
->emit_instruction(ctx
, &newInst
);
269 /* SUB t0.y, 1, t0.x; # d = 1 - d */
270 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_ADD
,
271 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_Y
,
272 TGSI_FILE_INPUT
, texInput
, TGSI_SWIZZLE_W
,
273 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_X
, true);
275 /* MUL t0.w, t0.y, t0.z; # coverage = d * m */
276 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_MUL
,
277 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_W
,
278 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_Y
,
279 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_Z
, false);
281 /* SLE t0.y, t0.x, tex.z; # bool b = distance <= k */
282 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_SLE
,
283 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_Y
,
284 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_X
,
285 TGSI_FILE_INPUT
, texInput
, TGSI_SWIZZLE_Z
, false);
287 /* CMP t0.w, -t0.y, tex.w, t0.w;
288 * # if -t0.y < 0 then
293 tgsi_transform_op3_swz_inst(ctx
, TGSI_OPCODE_CMP
,
294 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_W
,
295 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_Y
, 1,
296 TGSI_FILE_INPUT
, texInput
, TGSI_SWIZZLE_W
,
297 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_W
);
302 * TGSI transform callback.
303 * Insert new instructions before the END instruction.
306 aa_transform_epilog(struct tgsi_transform_context
*ctx
)
308 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
310 /* add alpha modulation code at tail of program */
312 /* MOV result.color.xyz, colorTemp; */
313 tgsi_transform_op1_inst(ctx
, TGSI_OPCODE_MOV
,
314 TGSI_FILE_OUTPUT
, aactx
->colorOutput
,
316 TGSI_FILE_TEMPORARY
, aactx
->colorTemp
);
318 /* MUL result.color.w, colorTemp, tmp0.w; */
319 tgsi_transform_op2_inst(ctx
, TGSI_OPCODE_MUL
,
320 TGSI_FILE_OUTPUT
, aactx
->colorOutput
,
322 TGSI_FILE_TEMPORARY
, aactx
->colorTemp
,
323 TGSI_FILE_TEMPORARY
, aactx
->tmp0
, false);
328 * TGSI transform callback.
329 * Called per instruction.
330 * Replace writes to result.color w/ a temp reg.
333 aa_transform_inst(struct tgsi_transform_context
*ctx
,
334 struct tgsi_full_instruction
*inst
)
336 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
339 /* Not an END instruction.
340 * Look for writes to result.color and replace with colorTemp reg.
342 for (i
= 0; i
< inst
->Instruction
.NumDstRegs
; i
++) {
343 struct tgsi_full_dst_register
*dst
= &inst
->Dst
[i
];
344 if (dst
->Register
.File
== TGSI_FILE_OUTPUT
&&
345 dst
->Register
.Index
== aactx
->colorOutput
) {
346 dst
->Register
.File
= TGSI_FILE_TEMPORARY
;
347 dst
->Register
.Index
= aactx
->colorTemp
;
351 ctx
->emit_instruction(ctx
, inst
);
356 * Generate the frag shader we'll use for drawing AA points.
357 * This will be the user's shader plus some texture/modulate instructions.
360 generate_aapoint_fs(struct aapoint_stage
*aapoint
)
362 const struct pipe_shader_state
*orig_fs
= &aapoint
->fs
->state
;
363 struct pipe_shader_state aapoint_fs
;
364 struct aa_transform_context transform
;
365 const uint newLen
= tgsi_num_tokens(orig_fs
->tokens
) + NUM_NEW_TOKENS
;
366 struct pipe_context
*pipe
= aapoint
->stage
.draw
->pipe
;
368 aapoint_fs
= *orig_fs
; /* copy to init */
370 assert(aapoint_fs
.type
== PIPE_SHADER_IR_TGSI
);
371 aapoint_fs
.tokens
= tgsi_alloc_tokens(newLen
);
372 if (aapoint_fs
.tokens
== NULL
)
375 memset(&transform
, 0, sizeof(transform
));
376 transform
.colorOutput
= -1;
377 transform
.maxInput
= -1;
378 transform
.maxGeneric
= -1;
379 transform
.colorTemp
= -1;
381 transform
.base
.prolog
= aa_transform_prolog
;
382 transform
.base
.epilog
= aa_transform_epilog
;
383 transform
.base
.transform_instruction
= aa_transform_inst
;
384 transform
.base
.transform_declaration
= aa_transform_decl
;
386 tgsi_transform_shader(orig_fs
->tokens
,
387 (struct tgsi_token
*) aapoint_fs
.tokens
,
388 newLen
, &transform
.base
);
391 debug_printf("draw_aapoint, orig shader:\n");
392 tgsi_dump(orig_fs
->tokens
, 0);
393 debug_printf("draw_aapoint, new shader:\n");
394 tgsi_dump(aapoint_fs
.tokens
, 0);
397 aapoint
->fs
->aapoint_fs
398 = aapoint
->driver_create_fs_state(pipe
, &aapoint_fs
);
399 if (aapoint
->fs
->aapoint_fs
== NULL
)
402 aapoint
->fs
->generic_attrib
= transform
.maxGeneric
+ 1;
403 FREE((void *)aapoint_fs
.tokens
);
407 FREE((void *)aapoint_fs
.tokens
);
412 generate_aapoint_fs_nir(struct aapoint_stage
*aapoint
)
414 #ifdef LLVM_AVAILABLE
415 struct pipe_context
*pipe
= aapoint
->stage
.draw
->pipe
;
416 const struct pipe_shader_state
*orig_fs
= &aapoint
->fs
->state
;
417 struct pipe_shader_state aapoint_fs
;
419 aapoint_fs
= *orig_fs
; /* copy to init */
420 aapoint_fs
.ir
.nir
= nir_shader_clone(NULL
, orig_fs
->ir
.nir
);
421 if (!aapoint_fs
.ir
.nir
)
424 nir_lower_aapoint_fs(aapoint_fs
.ir
.nir
, &aapoint
->fs
->generic_attrib
);
425 aapoint
->fs
->aapoint_fs
= aapoint
->driver_create_fs_state(pipe
, &aapoint_fs
);
426 if (aapoint
->fs
->aapoint_fs
== NULL
)
437 * When we're about to draw our first AA point in a batch, this function is
438 * called to tell the driver to bind our modified fragment shader.
441 bind_aapoint_fragment_shader(struct aapoint_stage
*aapoint
)
443 struct draw_context
*draw
= aapoint
->stage
.draw
;
444 struct pipe_context
*pipe
= draw
->pipe
;
446 if (!aapoint
->fs
->aapoint_fs
) {
447 if (aapoint
->fs
->state
.type
== PIPE_SHADER_IR_NIR
) {
448 if (!generate_aapoint_fs_nir(aapoint
))
450 } else if (!generate_aapoint_fs(aapoint
))
454 draw
->suspend_flushing
= TRUE
;
455 aapoint
->driver_bind_fs_state(pipe
, aapoint
->fs
->aapoint_fs
);
456 draw
->suspend_flushing
= FALSE
;
463 static inline struct aapoint_stage
*
464 aapoint_stage( struct draw_stage
*stage
)
466 return (struct aapoint_stage
*) stage
;
473 * Draw an AA point by drawing a quad.
476 aapoint_point(struct draw_stage
*stage
, struct prim_header
*header
)
478 const struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
479 struct prim_header tri
;
480 struct vertex_header
*v
[4];
481 const uint tex_slot
= aapoint
->tex_slot
;
482 const uint pos_slot
= aapoint
->pos_slot
;
483 float radius
, *pos
, *tex
;
487 if (aapoint
->psize_slot
>= 0) {
488 radius
= 0.5f
* header
->v
[0]->data
[aapoint
->psize_slot
][0];
491 radius
= aapoint
->radius
;
495 * Note: the texcoords (generic attrib, really) we use are special:
496 * The S and T components simply vary from -1 to +1.
497 * The R component is k, below.
498 * The Q component is 1.0 and will used as a handy constant in the
503 * k is the threshold distance from the point's center at which
504 * we begin alpha attenuation (the coverage value).
505 * Operating within a unit circle, we'll compute the fragment's
506 * distance 'd' from the center point using the texcoords.
510 * compute coverage in [0,1] proportional to d in [k, 1].
512 * coverage = 1.0; // full coverage
515 * Note: the ELSEIF and ELSE clauses are actually implemented with CMP to
516 * avoid using IF/ELSE/ENDIF TGSI opcodes.
521 k
= 1.0f
- 2.0f
* k
+ k
* k
;
523 k
= 1.0f
- 1.0f
/ radius
;
526 /* allocate/dup new verts */
527 for (i
= 0; i
< 4; i
++) {
528 v
[i
] = dup_vert(stage
, header
->v
[0], i
);
532 pos
= v
[0]->data
[pos_slot
];
536 pos
= v
[1]->data
[pos_slot
];
540 pos
= v
[2]->data
[pos_slot
];
544 pos
= v
[3]->data
[pos_slot
];
549 tex
= v
[0]->data
[tex_slot
];
550 ASSIGN_4V(tex
, -1, -1, k
, 1);
552 tex
= v
[1]->data
[tex_slot
];
553 ASSIGN_4V(tex
, 1, -1, k
, 1);
555 tex
= v
[2]->data
[tex_slot
];
556 ASSIGN_4V(tex
, 1, 1, k
, 1);
558 tex
= v
[3]->data
[tex_slot
];
559 ASSIGN_4V(tex
, -1, 1, k
, 1);
561 /* emit 2 tris for the quad strip */
565 stage
->next
->tri( stage
->next
, &tri
);
570 stage
->next
->tri( stage
->next
, &tri
);
575 aapoint_first_point(struct draw_stage
*stage
, struct prim_header
*header
)
577 auto struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
578 struct draw_context
*draw
= stage
->draw
;
579 struct pipe_context
*pipe
= draw
->pipe
;
580 const struct pipe_rasterizer_state
*rast
= draw
->rasterizer
;
583 assert(draw
->rasterizer
->point_smooth
);
585 if (draw
->rasterizer
->point_size
<= 2.0)
586 aapoint
->radius
= 1.0;
588 aapoint
->radius
= 0.5f
* draw
->rasterizer
->point_size
;
591 * Bind (generate) our fragprog.
593 bind_aapoint_fragment_shader(aapoint
);
595 draw_aapoint_prepare_outputs(draw
, draw
->pipeline
.aapoint
);
597 draw
->suspend_flushing
= TRUE
;
599 /* Disable triangle culling, stippling, unfilled mode etc. */
600 r
= draw_get_rasterizer_no_cull(draw
, rast
->scissor
, rast
->flatshade
);
601 pipe
->bind_rasterizer_state(pipe
, r
);
603 draw
->suspend_flushing
= FALSE
;
605 /* now really draw first point */
606 stage
->point
= aapoint_point
;
607 stage
->point(stage
, header
);
612 aapoint_flush(struct draw_stage
*stage
, unsigned flags
)
614 struct draw_context
*draw
= stage
->draw
;
615 struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
616 struct pipe_context
*pipe
= draw
->pipe
;
618 stage
->point
= aapoint_first_point
;
619 stage
->next
->flush( stage
->next
, flags
);
621 /* restore original frag shader */
622 draw
->suspend_flushing
= TRUE
;
623 aapoint
->driver_bind_fs_state(pipe
, aapoint
->fs
? aapoint
->fs
->driver_fs
: NULL
);
625 /* restore original rasterizer state */
626 if (draw
->rast_handle
) {
627 pipe
->bind_rasterizer_state(pipe
, draw
->rast_handle
);
630 draw
->suspend_flushing
= FALSE
;
632 draw_remove_extra_vertex_attribs(draw
);
637 aapoint_reset_stipple_counter(struct draw_stage
*stage
)
639 stage
->next
->reset_stipple_counter( stage
->next
);
644 aapoint_destroy(struct draw_stage
*stage
)
646 struct aapoint_stage
* aapoint
= aapoint_stage(stage
);
647 struct pipe_context
*pipe
= stage
->draw
->pipe
;
649 draw_free_temp_verts( stage
);
651 /* restore the old entry points */
652 pipe
->create_fs_state
= aapoint
->driver_create_fs_state
;
653 pipe
->bind_fs_state
= aapoint
->driver_bind_fs_state
;
654 pipe
->delete_fs_state
= aapoint
->driver_delete_fs_state
;
660 draw_aapoint_prepare_outputs(struct draw_context
*draw
,
661 struct draw_stage
*stage
)
663 struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
664 const struct pipe_rasterizer_state
*rast
= draw
->rasterizer
;
666 /* update vertex attrib info */
667 aapoint
->pos_slot
= draw_current_shader_position_output(draw
);
669 if (!rast
->point_smooth
)
672 if (aapoint
->fs
->aapoint_fs
) {
673 /* allocate the extra post-transformed vertex attribute */
674 aapoint
->tex_slot
= draw_alloc_extra_vertex_attrib(draw
,
675 TGSI_SEMANTIC_GENERIC
,
676 aapoint
->fs
->generic_attrib
);
677 assert(aapoint
->tex_slot
> 0); /* output[0] is vertex pos */
679 aapoint
->tex_slot
= -1;
681 /* find psize slot in post-transform vertex */
682 aapoint
->psize_slot
= -1;
683 if (draw
->rasterizer
->point_size_per_vertex
) {
684 const struct tgsi_shader_info
*info
= draw_get_shader_info(draw
);
686 /* find PSIZ vertex output */
687 for (i
= 0; i
< info
->num_outputs
; i
++) {
688 if (info
->output_semantic_name
[i
] == TGSI_SEMANTIC_PSIZE
) {
689 aapoint
->psize_slot
= i
;
696 static struct aapoint_stage
*
697 draw_aapoint_stage(struct draw_context
*draw
)
699 struct aapoint_stage
*aapoint
= CALLOC_STRUCT(aapoint_stage
);
703 aapoint
->stage
.draw
= draw
;
704 aapoint
->stage
.name
= "aapoint";
705 aapoint
->stage
.next
= NULL
;
706 aapoint
->stage
.point
= aapoint_first_point
;
707 aapoint
->stage
.line
= draw_pipe_passthrough_line
;
708 aapoint
->stage
.tri
= draw_pipe_passthrough_tri
;
709 aapoint
->stage
.flush
= aapoint_flush
;
710 aapoint
->stage
.reset_stipple_counter
= aapoint_reset_stipple_counter
;
711 aapoint
->stage
.destroy
= aapoint_destroy
;
713 if (!draw_alloc_temp_verts( &aapoint
->stage
, 4 ))
720 aapoint
->stage
.destroy(&aapoint
->stage
);
727 static struct aapoint_stage
*
728 aapoint_stage_from_pipe(struct pipe_context
*pipe
)
730 struct draw_context
*draw
= (struct draw_context
*) pipe
->draw
;
731 return aapoint_stage(draw
->pipeline
.aapoint
);
736 * This function overrides the driver's create_fs_state() function and
737 * will typically be called by the state tracker.
740 aapoint_create_fs_state(struct pipe_context
*pipe
,
741 const struct pipe_shader_state
*fs
)
743 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
744 struct aapoint_fragment_shader
*aafs
= CALLOC_STRUCT(aapoint_fragment_shader
);
748 aafs
->state
.type
= fs
->type
;
749 if (fs
->type
== PIPE_SHADER_IR_TGSI
)
750 aafs
->state
.tokens
= tgsi_dup_tokens(fs
->tokens
);
751 #ifdef LLVM_AVAILABLE
753 aafs
->state
.ir
.nir
= nir_shader_clone(NULL
, fs
->ir
.nir
);
756 aafs
->driver_fs
= aapoint
->driver_create_fs_state(pipe
, fs
);
763 aapoint_bind_fs_state(struct pipe_context
*pipe
, void *fs
)
765 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
766 struct aapoint_fragment_shader
*aafs
= (struct aapoint_fragment_shader
*) fs
;
770 aapoint
->driver_bind_fs_state(pipe
,
771 (aafs
? aafs
->driver_fs
: NULL
));
776 aapoint_delete_fs_state(struct pipe_context
*pipe
, void *fs
)
778 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
779 struct aapoint_fragment_shader
*aafs
= (struct aapoint_fragment_shader
*) fs
;
782 aapoint
->driver_delete_fs_state(pipe
, aafs
->driver_fs
);
784 if (aafs
->aapoint_fs
)
785 aapoint
->driver_delete_fs_state(pipe
, aafs
->aapoint_fs
);
787 if (aafs
->state
.type
== PIPE_SHADER_IR_TGSI
)
788 FREE((void*)aafs
->state
.tokens
);
790 ralloc_free(aafs
->state
.ir
.nir
);
797 * Called by drivers that want to install this AA point prim stage
798 * into the draw module's pipeline. This will not be used if the
799 * hardware has native support for AA points.
802 draw_install_aapoint_stage(struct draw_context
*draw
,
803 struct pipe_context
*pipe
)
805 struct aapoint_stage
*aapoint
;
807 pipe
->draw
= (void *) draw
;
810 * Create / install AA point drawing / prim stage
812 aapoint
= draw_aapoint_stage( draw
);
816 /* save original driver functions */
817 aapoint
->driver_create_fs_state
= pipe
->create_fs_state
;
818 aapoint
->driver_bind_fs_state
= pipe
->bind_fs_state
;
819 aapoint
->driver_delete_fs_state
= pipe
->delete_fs_state
;
821 /* override the driver's functions */
822 pipe
->create_fs_state
= aapoint_create_fs_state
;
823 pipe
->bind_fs_state
= aapoint_bind_fs_state
;
824 pipe
->delete_fs_state
= aapoint_delete_fs_state
;
826 draw
->pipeline
.aapoint
= &aapoint
->stage
;