1 /**************************************************************************
3 * Copyright 2007-2018 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 line stage: AA lines are converted triangles (with extra generic)
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"
40 #include "util/u_format.h"
41 #include "util/u_math.h"
42 #include "util/u_memory.h"
44 #include "tgsi/tgsi_transform.h"
45 #include "tgsi/tgsi_dump.h"
47 #include "draw_context.h"
48 #include "draw_private.h"
49 #include "draw_pipe.h"
52 /** Approx number of new tokens for instructions in aa_transform_inst() */
53 #define NUM_NEW_TOKENS 53
57 * Subclass of pipe_shader_state to carry extra fragment shader info.
59 struct aaline_fragment_shader
61 struct pipe_shader_state state
;
64 int generic_attrib
; /**< generic used for distance */
69 * Subclass of draw_stage
73 struct draw_stage stage
;
75 float half_line_width
;
77 /** For AA lines, this is the vertex attrib slot for new generic */
79 /** position, not necessarily output zero */
84 * Currently bound state
86 struct aaline_fragment_shader
*fs
;
89 * Driver interface/override functions
91 void * (*driver_create_fs_state
)(struct pipe_context
*,
92 const struct pipe_shader_state
*);
93 void (*driver_bind_fs_state
)(struct pipe_context
*, void *);
94 void (*driver_delete_fs_state
)(struct pipe_context
*, void *);
100 * Subclass of tgsi_transform_context, used for transforming the
101 * user's fragment shader to add the special AA instructions.
103 struct aa_transform_context
{
104 struct tgsi_transform_context base
;
105 uint64_t tempsUsed
; /**< bitmask */
106 int colorOutput
; /**< which output is the primary color */
107 int maxInput
, maxGeneric
; /**< max input index found */
108 int colorTemp
, aaTemp
; /**< temp registers */
112 * TGSI declaration transform callback.
113 * Look for a free input attrib, and two free temp regs.
116 aa_transform_decl(struct tgsi_transform_context
*ctx
,
117 struct tgsi_full_declaration
*decl
)
119 struct aa_transform_context
*aactx
= (struct aa_transform_context
*)ctx
;
121 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
&&
122 decl
->Semantic
.Name
== TGSI_SEMANTIC_COLOR
&&
123 decl
->Semantic
.Index
== 0) {
124 aactx
->colorOutput
= decl
->Range
.First
;
126 else if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
127 if ((int) decl
->Range
.Last
> aactx
->maxInput
)
128 aactx
->maxInput
= decl
->Range
.Last
;
129 if (decl
->Semantic
.Name
== TGSI_SEMANTIC_GENERIC
&&
130 (int) decl
->Semantic
.Index
> aactx
->maxGeneric
) {
131 aactx
->maxGeneric
= decl
->Semantic
.Index
;
134 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
136 for (i
= decl
->Range
.First
;
137 i
<= decl
->Range
.Last
; i
++) {
139 * XXX this bitfield doesn't really cut it...
141 aactx
->tempsUsed
|= UINT64_C(1) << i
;
145 ctx
->emit_declaration(ctx
, decl
);
150 * Find the lowest zero bit, or -1 if bitfield is all ones.
153 free_bit(uint64_t bitfield
)
155 return ffsll(~bitfield
) - 1;
160 * TGSI transform prolog callback.
163 aa_transform_prolog(struct tgsi_transform_context
*ctx
)
165 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
166 uint64_t usedTemps
= aactx
->tempsUsed
;
168 /* find two free temp regs */
169 aactx
->colorTemp
= free_bit(usedTemps
);
170 usedTemps
|= UINT64_C(1) << aactx
->colorTemp
;
171 aactx
->aaTemp
= free_bit(usedTemps
);
172 assert(aactx
->colorTemp
>= 0);
173 assert(aactx
->aaTemp
>= 0);
175 /* declare new generic input/texcoord */
176 tgsi_transform_input_decl(ctx
, aactx
->maxInput
+ 1,
177 TGSI_SEMANTIC_GENERIC
, aactx
->maxGeneric
+ 1,
178 TGSI_INTERPOLATE_LINEAR
);
180 /* declare new temp regs */
181 tgsi_transform_temp_decl(ctx
, aactx
->aaTemp
);
182 tgsi_transform_temp_decl(ctx
, aactx
->colorTemp
);
187 * TGSI transform epilog callback.
190 aa_transform_epilog(struct tgsi_transform_context
*ctx
)
192 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
194 if (aactx
->colorOutput
!= -1) {
195 struct tgsi_full_instruction inst
;
196 /* insert distance-based coverage code for antialiasing. */
198 /* saturate(linewidth - fabs(interpx), linelength - fabs(interpz) */
199 inst
= tgsi_default_full_instruction();
200 inst
.Instruction
.Saturate
= true;
201 inst
.Instruction
.Opcode
= TGSI_OPCODE_ADD
;
202 inst
.Instruction
.NumDstRegs
= 1;
203 tgsi_transform_dst_reg(&inst
.Dst
[0], TGSI_FILE_TEMPORARY
,
204 aactx
->aaTemp
, TGSI_WRITEMASK_XZ
);
205 inst
.Instruction
.NumSrcRegs
= 2;
206 tgsi_transform_src_reg(&inst
.Src
[1], TGSI_FILE_INPUT
, aactx
->maxInput
+ 1,
207 TGSI_SWIZZLE_X
, TGSI_SWIZZLE_X
,
208 TGSI_SWIZZLE_Z
, TGSI_SWIZZLE_Z
);
209 tgsi_transform_src_reg(&inst
.Src
[0], TGSI_FILE_INPUT
, aactx
->maxInput
+ 1,
210 TGSI_SWIZZLE_Y
, TGSI_SWIZZLE_Y
,
211 TGSI_SWIZZLE_W
, TGSI_SWIZZLE_W
);
212 inst
.Src
[1].Register
.Absolute
= true;
213 inst
.Src
[1].Register
.Negate
= true;
214 ctx
->emit_instruction(ctx
, &inst
);
216 /* MUL width / height alpha */
217 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_MUL
,
218 TGSI_FILE_TEMPORARY
, aactx
->aaTemp
,
220 TGSI_FILE_TEMPORARY
, aactx
->aaTemp
,
222 TGSI_FILE_TEMPORARY
, aactx
->aaTemp
,
223 TGSI_SWIZZLE_Z
, false);
226 tgsi_transform_op1_inst(ctx
, TGSI_OPCODE_MOV
,
227 TGSI_FILE_OUTPUT
, aactx
->colorOutput
,
229 TGSI_FILE_TEMPORARY
, aactx
->colorTemp
);
232 tgsi_transform_op2_inst(ctx
, TGSI_OPCODE_MUL
,
233 TGSI_FILE_OUTPUT
, aactx
->colorOutput
,
235 TGSI_FILE_TEMPORARY
, aactx
->colorTemp
,
236 TGSI_FILE_TEMPORARY
, aactx
->aaTemp
, false);
242 * TGSI instruction transform callback.
243 * Replace writes to result.color w/ a temp reg.
246 aa_transform_inst(struct tgsi_transform_context
*ctx
,
247 struct tgsi_full_instruction
*inst
)
249 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
253 * Look for writes to result.color and replace with colorTemp reg.
255 for (i
= 0; i
< inst
->Instruction
.NumDstRegs
; i
++) {
256 struct tgsi_full_dst_register
*dst
= &inst
->Dst
[i
];
257 if (dst
->Register
.File
== TGSI_FILE_OUTPUT
&&
258 dst
->Register
.Index
== aactx
->colorOutput
) {
259 dst
->Register
.File
= TGSI_FILE_TEMPORARY
;
260 dst
->Register
.Index
= aactx
->colorTemp
;
264 ctx
->emit_instruction(ctx
, inst
);
269 * Generate the frag shader we'll use for drawing AA lines.
270 * This will be the user's shader plus some arithmetic instructions.
273 generate_aaline_fs(struct aaline_stage
*aaline
)
275 struct pipe_context
*pipe
= aaline
->stage
.draw
->pipe
;
276 const struct pipe_shader_state
*orig_fs
= &aaline
->fs
->state
;
277 struct pipe_shader_state aaline_fs
;
278 struct aa_transform_context transform
;
279 const uint newLen
= tgsi_num_tokens(orig_fs
->tokens
) + NUM_NEW_TOKENS
;
281 aaline_fs
= *orig_fs
; /* copy to init */
282 aaline_fs
.tokens
= tgsi_alloc_tokens(newLen
);
283 if (aaline_fs
.tokens
== NULL
)
286 memset(&transform
, 0, sizeof(transform
));
287 transform
.colorOutput
= -1;
288 transform
.maxInput
= -1;
289 transform
.maxGeneric
= -1;
290 transform
.colorTemp
= -1;
291 transform
.aaTemp
= -1;
292 transform
.base
.prolog
= aa_transform_prolog
;
293 transform
.base
.epilog
= aa_transform_epilog
;
294 transform
.base
.transform_instruction
= aa_transform_inst
;
295 transform
.base
.transform_declaration
= aa_transform_decl
;
297 tgsi_transform_shader(orig_fs
->tokens
,
298 (struct tgsi_token
*) aaline_fs
.tokens
,
299 newLen
, &transform
.base
);
302 debug_printf("draw_aaline, orig shader:\n");
303 tgsi_dump(orig_fs
->tokens
, 0);
304 debug_printf("draw_aaline, new shader:\n");
305 tgsi_dump(aaline_fs
.tokens
, 0);
308 aaline
->fs
->aaline_fs
= aaline
->driver_create_fs_state(pipe
, &aaline_fs
);
309 if (aaline
->fs
->aaline_fs
== NULL
)
312 aaline
->fs
->generic_attrib
= transform
.maxGeneric
+ 1;
313 FREE((void *)aaline_fs
.tokens
);
317 FREE((void *)aaline_fs
.tokens
);
323 * When we're about to draw our first AA line in a batch, this function is
324 * called to tell the driver to bind our modified fragment shader.
327 bind_aaline_fragment_shader(struct aaline_stage
*aaline
)
329 struct draw_context
*draw
= aaline
->stage
.draw
;
330 struct pipe_context
*pipe
= draw
->pipe
;
332 if (!aaline
->fs
->aaline_fs
&& !generate_aaline_fs(aaline
))
335 draw
->suspend_flushing
= TRUE
;
336 aaline
->driver_bind_fs_state(pipe
, aaline
->fs
->aaline_fs
);
337 draw
->suspend_flushing
= FALSE
;
344 static inline struct aaline_stage
*
345 aaline_stage(struct draw_stage
*stage
)
347 return (struct aaline_stage
*) stage
;
352 * Draw a wide line by drawing a quad, using geometry which will
353 * fullfill GL's antialiased line requirements.
356 aaline_line(struct draw_stage
*stage
, struct prim_header
*header
)
358 const struct aaline_stage
*aaline
= aaline_stage(stage
);
359 const float half_width
= aaline
->half_line_width
;
360 struct prim_header tri
;
361 struct vertex_header
*v
[8];
362 uint coordPos
= aaline
->coord_slot
;
363 uint posPos
= aaline
->pos_slot
;
365 float dx
= header
->v
[1]->data
[posPos
][0] - header
->v
[0]->data
[posPos
][0];
366 float dy
= header
->v
[1]->data
[posPos
][1] - header
->v
[0]->data
[posPos
][1];
367 float a
= atan2f(dy
, dx
);
368 float c_a
= cosf(a
), s_a
= sinf(a
);
373 half_length
= 0.5f
* sqrtf(dx
* dx
+ dy
* dy
);
375 if (half_length
< 0.5f
) {
377 * The logic we use for "normal" sized segments is incorrect
378 * for very short segments (basically because we only have
379 * one value to interpolate, not a distance to each endpoint).
380 * Therefore, we calculate half_length differently, so that for
381 * original line length (near) 0, we get alpha 0 - otherwise
382 * max alpha would still be 0.5. This also prevents us from
383 * artifacts due to degenerated lines (the endpoints being
384 * identical, which would still receive anywhere from alpha
385 * 0-0.5 otherwise) (at least the pstipple stage may generate
386 * such lines due to float inaccuracies if line length is very
387 * close to a integer).
388 * Might not be fully accurate neither (because the "strength" of
389 * the line is going to be determined by how close to the pixel
390 * center those 1 or 2 fragments are) but it's probably the best
393 half_length
= 2.0f
* half_length
;
395 half_length
= half_length
+ 0.5f
;
401 /* allocate/dup new verts */
402 for (i
= 0; i
< 4; i
++) {
403 v
[i
] = dup_vert(stage
, header
->v
[i
/2], i
);
407 * Quad strip for line from v0 to v1 (*=endpoints):
410 * +-----------------------------+
414 * +-----------------------------+
419 * We increase line length by 0.5 pixels (at each endpoint),
420 * and calculate the tri endpoints by moving them half-width
421 * distance away perpendicular to the line.
422 * XXX: since we change line endpoints (by 0.5 pixel), should
423 * actually re-interpolate all other values?
427 pos
= v
[0]->data
[posPos
];
428 pos
[0] += (-t_l
* c_a
- t_w
* s_a
);
429 pos
[1] += (-t_l
* s_a
+ t_w
* c_a
);
431 pos
= v
[1]->data
[posPos
];
432 pos
[0] += (-t_l
* c_a
- -t_w
* s_a
);
433 pos
[1] += (-t_l
* s_a
+ -t_w
* c_a
);
435 pos
= v
[2]->data
[posPos
];
436 pos
[0] += (t_l
* c_a
- t_w
* s_a
);
437 pos
[1] += (t_l
* s_a
+ t_w
* c_a
);
439 pos
= v
[3]->data
[posPos
];
440 pos
[0] += (t_l
* c_a
- -t_w
* s_a
);
441 pos
[1] += (t_l
* s_a
+ -t_w
* c_a
);
444 tex
= v
[0]->data
[coordPos
];
445 ASSIGN_4V(tex
, -half_width
, half_width
, -half_length
, half_length
);
447 tex
= v
[1]->data
[coordPos
];
448 ASSIGN_4V(tex
, half_width
, half_width
, -half_length
, half_length
);
450 tex
= v
[2]->data
[coordPos
];
451 ASSIGN_4V(tex
, -half_width
, half_width
, half_length
, half_length
);
453 tex
= v
[3]->data
[coordPos
];
454 ASSIGN_4V(tex
, half_width
, half_width
, half_length
, half_length
);
456 tri
.v
[0] = v
[2]; tri
.v
[1] = v
[1]; tri
.v
[2] = v
[0];
457 stage
->next
->tri(stage
->next
, &tri
);
459 tri
.v
[0] = v
[3]; tri
.v
[1] = v
[1]; tri
.v
[2] = v
[2];
460 stage
->next
->tri(stage
->next
, &tri
);
465 aaline_first_line(struct draw_stage
*stage
, struct prim_header
*header
)
467 auto struct aaline_stage
*aaline
= aaline_stage(stage
);
468 struct draw_context
*draw
= stage
->draw
;
469 struct pipe_context
*pipe
= draw
->pipe
;
470 const struct pipe_rasterizer_state
*rast
= draw
->rasterizer
;
473 assert(draw
->rasterizer
->line_smooth
);
475 if (draw
->rasterizer
->line_width
<= 1.0)
476 aaline
->half_line_width
= 1.0;
478 aaline
->half_line_width
= 0.5f
* draw
->rasterizer
->line_width
+ 0.5f
;
480 if (!draw
->rasterizer
->half_pixel_center
)
482 * The tex coords probably would need adjustments?
484 debug_printf("aa lines without half pixel center may be wrong\n");
487 * Bind (generate) our fragprog
489 if (!bind_aaline_fragment_shader(aaline
)) {
490 stage
->line
= draw_pipe_passthrough_line
;
491 stage
->line(stage
, header
);
495 draw_aaline_prepare_outputs(draw
, draw
->pipeline
.aaline
);
497 draw
->suspend_flushing
= TRUE
;
499 /* Disable triangle culling, stippling, unfilled mode etc. */
500 r
= draw_get_rasterizer_no_cull(draw
, rast
->scissor
, rast
->flatshade
);
501 pipe
->bind_rasterizer_state(pipe
, r
);
503 draw
->suspend_flushing
= FALSE
;
505 /* now really draw first line */
506 stage
->line
= aaline_line
;
507 stage
->line(stage
, header
);
512 aaline_flush(struct draw_stage
*stage
, unsigned flags
)
514 struct draw_context
*draw
= stage
->draw
;
515 struct aaline_stage
*aaline
= aaline_stage(stage
);
516 struct pipe_context
*pipe
= draw
->pipe
;
518 stage
->line
= aaline_first_line
;
519 stage
->next
->flush(stage
->next
, flags
);
521 /* restore original frag shader */
522 draw
->suspend_flushing
= TRUE
;
523 aaline
->driver_bind_fs_state(pipe
, aaline
->fs
? aaline
->fs
->driver_fs
: NULL
);
525 /* restore original rasterizer state */
526 if (draw
->rast_handle
) {
527 pipe
->bind_rasterizer_state(pipe
, draw
->rast_handle
);
530 draw
->suspend_flushing
= FALSE
;
532 draw_remove_extra_vertex_attribs(draw
);
537 aaline_reset_stipple_counter(struct draw_stage
*stage
)
539 stage
->next
->reset_stipple_counter(stage
->next
);
544 aaline_destroy(struct draw_stage
*stage
)
546 struct aaline_stage
*aaline
= aaline_stage(stage
);
547 struct pipe_context
*pipe
= stage
->draw
->pipe
;
549 draw_free_temp_verts(stage
);
551 /* restore the old entry points */
552 pipe
->create_fs_state
= aaline
->driver_create_fs_state
;
553 pipe
->bind_fs_state
= aaline
->driver_bind_fs_state
;
554 pipe
->delete_fs_state
= aaline
->driver_delete_fs_state
;
560 static struct aaline_stage
*
561 draw_aaline_stage(struct draw_context
*draw
)
563 struct aaline_stage
*aaline
= CALLOC_STRUCT(aaline_stage
);
567 aaline
->stage
.draw
= draw
;
568 aaline
->stage
.name
= "aaline";
569 aaline
->stage
.next
= NULL
;
570 aaline
->stage
.point
= draw_pipe_passthrough_point
;
571 aaline
->stage
.line
= aaline_first_line
;
572 aaline
->stage
.tri
= draw_pipe_passthrough_tri
;
573 aaline
->stage
.flush
= aaline_flush
;
574 aaline
->stage
.reset_stipple_counter
= aaline_reset_stipple_counter
;
575 aaline
->stage
.destroy
= aaline_destroy
;
577 if (!draw_alloc_temp_verts(&aaline
->stage
, 8))
583 aaline
->stage
.destroy(&aaline
->stage
);
589 static struct aaline_stage
*
590 aaline_stage_from_pipe(struct pipe_context
*pipe
)
592 struct draw_context
*draw
= (struct draw_context
*) pipe
->draw
;
595 return aaline_stage(draw
->pipeline
.aaline
);
603 * This function overrides the driver's create_fs_state() function and
604 * will typically be called by the state tracker.
607 aaline_create_fs_state(struct pipe_context
*pipe
,
608 const struct pipe_shader_state
*fs
)
610 struct aaline_stage
*aaline
= aaline_stage_from_pipe(pipe
);
611 struct aaline_fragment_shader
*aafs
= NULL
;
616 aafs
= CALLOC_STRUCT(aaline_fragment_shader
);
621 aafs
->state
.tokens
= tgsi_dup_tokens(fs
->tokens
);
624 aafs
->driver_fs
= aaline
->driver_create_fs_state(pipe
, fs
);
631 aaline_bind_fs_state(struct pipe_context
*pipe
, void *fs
)
633 struct aaline_stage
*aaline
= aaline_stage_from_pipe(pipe
);
634 struct aaline_fragment_shader
*aafs
= (struct aaline_fragment_shader
*) fs
;
643 aaline
->driver_bind_fs_state(pipe
, (aafs
? aafs
->driver_fs
: NULL
));
648 aaline_delete_fs_state(struct pipe_context
*pipe
, void *fs
)
650 struct aaline_stage
*aaline
= aaline_stage_from_pipe(pipe
);
651 struct aaline_fragment_shader
*aafs
= (struct aaline_fragment_shader
*) fs
;
659 aaline
->driver_delete_fs_state(pipe
, aafs
->driver_fs
);
662 aaline
->driver_delete_fs_state(pipe
, aafs
->aaline_fs
);
665 FREE((void*)aafs
->state
.tokens
);
671 draw_aaline_prepare_outputs(struct draw_context
*draw
,
672 struct draw_stage
*stage
)
674 struct aaline_stage
*aaline
= aaline_stage(stage
);
675 const struct pipe_rasterizer_state
*rast
= draw
->rasterizer
;
677 /* update vertex attrib info */
678 aaline
->pos_slot
= draw_current_shader_position_output(draw
);
680 if (!rast
->line_smooth
)
683 /* allocate the extra post-transformed vertex attribute */
684 aaline
->coord_slot
= draw_alloc_extra_vertex_attrib(draw
,
685 TGSI_SEMANTIC_GENERIC
,
686 aaline
->fs
->generic_attrib
);
690 * Called by drivers that want to install this AA line prim stage
691 * into the draw module's pipeline. This will not be used if the
692 * hardware has native support for AA lines.
695 draw_install_aaline_stage(struct draw_context
*draw
, struct pipe_context
*pipe
)
697 struct aaline_stage
*aaline
;
699 pipe
->draw
= (void *) draw
;
702 * Create / install AA line drawing / prim stage
704 aaline
= draw_aaline_stage(draw
);
708 /* save original driver functions */
709 aaline
->driver_create_fs_state
= pipe
->create_fs_state
;
710 aaline
->driver_bind_fs_state
= pipe
->bind_fs_state
;
711 aaline
->driver_delete_fs_state
= pipe
->delete_fs_state
;
713 /* override the driver's functions */
714 pipe
->create_fs_state
= aaline_create_fs_state
;
715 pipe
->bind_fs_state
= aaline_bind_fs_state
;
716 pipe
->delete_fs_state
= aaline_delete_fs_state
;
718 /* Install once everything is known to be OK:
720 draw
->pipeline
.aaline
= &aaline
->stage
;
726 aaline
->stage
.destroy(&aaline
->stage
);