2 * Copyright 2014 VMware, Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * This utility transforms the fragment shader to support anti-aliasing points.
31 #include "util/u_debug.h"
32 #include "util/u_math.h"
33 #include "tgsi_info.h"
34 #include "tgsi_aa_point.h"
35 #include "tgsi_transform.h"
37 #define INVALID_INDEX 9999
39 struct aa_transform_context
41 struct tgsi_transform_context base
;
43 unsigned tmp
; // temp register
44 unsigned color_out
; // frag color out register
45 unsigned color_tmp
; // frag color temp register
46 unsigned num_tmp
; // number of temp registers
47 unsigned num_imm
; // number of immediates
48 unsigned num_input
; // number of inputs
49 unsigned aa_point_coord_index
;
52 static inline struct aa_transform_context
*
53 aa_transform_context(struct tgsi_transform_context
*ctx
)
55 return (struct aa_transform_context
*) ctx
;
59 * TGSI declaration transform callback.
62 aa_decl(struct tgsi_transform_context
*ctx
,
63 struct tgsi_full_declaration
*decl
)
65 struct aa_transform_context
*ts
= aa_transform_context(ctx
);
67 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
&&
68 decl
->Semantic
.Name
== TGSI_SEMANTIC_COLOR
&&
69 decl
->Semantic
.Index
== 0) {
70 ts
->color_out
= decl
->Range
.First
;
72 else if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
75 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
76 ts
->num_tmp
= MAX2(ts
->num_tmp
, (unsigned)(decl
->Range
.Last
+ 1));
79 ctx
->emit_declaration(ctx
, decl
);
83 * TGSI immediate declaration transform callback.
86 aa_immediate(struct tgsi_transform_context
*ctx
,
87 struct tgsi_full_immediate
*imm
)
89 struct aa_transform_context
*ts
= aa_transform_context(ctx
);
91 ctx
->emit_immediate(ctx
, imm
);
96 * TGSI transform prolog callback.
99 aa_prolog(struct tgsi_transform_context
*ctx
)
101 struct aa_transform_context
*ts
= aa_transform_context(ctx
);
106 /* Declare two temporary registers, one for temporary and
109 ts
->tmp
= ts
->num_tmp
++;
110 ts
->color_tmp
= ts
->num_tmp
++;
112 tgsi_transform_temps_decl(ctx
, ts
->tmp
, ts
->color_tmp
);
114 /* Declare new generic input/texcoord */
115 texIn
= ts
->num_input
++;
116 tgsi_transform_input_decl(ctx
, texIn
, TGSI_SEMANTIC_GENERIC
,
117 ts
->aa_point_coord_index
, TGSI_INTERPOLATE_LINEAR
);
119 /* Declare extra immediates */
121 tgsi_transform_immediate_decl(ctx
, 0.5, 0.5, 0.45, 1.0);
124 * Emit code to compute fragment coverage.
125 * The point always has radius 0.5. The threshold value will be a
126 * value less than, but close to 0.5, such as 0.45.
127 * We compute a coverage factor from the distance and threshold.
128 * If the coverage is negative, the fragment is outside the circle and
130 * If the coverage is >= 1, the fragment is fully inside the threshold
131 * distance. We limit/clamp the coverage to 1.
132 * Otherwise, the fragment is between the threshold value and 0.5 and we
133 * compute a coverage value in [0,1].
135 * Input reg (texIn) usage:
136 * texIn.x = x point coord in [0,1]
137 * texIn.y = y point coord in [0,1]
138 * texIn.z = "k" the smoothing threshold distance
141 * Temp reg (t0) usage:
142 * t0.x = distance of fragment from center point
143 * t0.y = boolean, is t0.x > 0.5, also misc temp usage
144 * t0.z = temporary for computing 1/(0.5-k) value
145 * t0.w = final coverage value
150 /* SUB t0.xy, texIn, (0.5, 0,5) */
151 tgsi_transform_op2_inst(ctx
, TGSI_OPCODE_ADD
,
152 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_XY
,
153 TGSI_FILE_INPUT
, texIn
,
154 TGSI_FILE_IMMEDIATE
, imm
, true);
156 /* DP2 t0.x, t0.xy, t0.xy; # t0.x = x^2 + y^2 */
157 tgsi_transform_op2_inst(ctx
, TGSI_OPCODE_DP2
,
158 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_X
,
159 TGSI_FILE_TEMPORARY
, tmp0
,
160 TGSI_FILE_TEMPORARY
, tmp0
, false);
162 /* SQRT t0.x, t0.x */
163 tgsi_transform_op1_inst(ctx
, TGSI_OPCODE_SQRT
,
164 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_X
,
165 TGSI_FILE_TEMPORARY
, tmp0
);
167 /* compute coverage factor = (0.5-d)/(0.5-k) */
169 /* SUB t0.w, 0.5, texIn.z; # t0.w = 0.5-k */
170 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_ADD
,
171 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_W
,
172 TGSI_FILE_IMMEDIATE
, imm
, TGSI_SWIZZLE_X
,
173 TGSI_FILE_INPUT
, texIn
, TGSI_SWIZZLE_Z
, true);
175 /* SUB t0.y, 0.5, t0.x; # t0.y = 0.5-d */
176 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_ADD
,
177 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_Y
,
178 TGSI_FILE_IMMEDIATE
, imm
, TGSI_SWIZZLE_X
,
179 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_X
, true);
181 /* DIV t0.w, t0.y, t0.w; # coverage = (0.5-d)/(0.5-k) */
182 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_DIV
,
183 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_W
,
184 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_Y
,
185 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_W
, false);
187 /* If the coverage value is negative, it means the fragment is outside
188 * the point's circular boundary. Kill it.
190 /* KILL_IF tmp0.w; # if tmp0.w < 0 KILL */
191 tgsi_transform_kill_inst(ctx
, TGSI_FILE_TEMPORARY
, tmp0
,
192 TGSI_SWIZZLE_W
, FALSE
);
194 /* If the distance is less than the threshold, the coverage/alpha value
195 * will be greater than one. Clamp to one here.
197 /* MIN tmp0.w, tmp0.w, 1.0 */
198 tgsi_transform_op2_swz_inst(ctx
, TGSI_OPCODE_MIN
,
199 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_WRITEMASK_W
,
200 TGSI_FILE_TEMPORARY
, tmp0
, TGSI_SWIZZLE_W
,
201 TGSI_FILE_IMMEDIATE
, imm
, TGSI_SWIZZLE_W
, false);
205 * TGSI instruction transform callback.
208 aa_inst(struct tgsi_transform_context
*ctx
,
209 struct tgsi_full_instruction
*inst
)
211 struct aa_transform_context
*ts
= aa_transform_context(ctx
);
214 /* Look for writes to color output reg and replace it with
217 for (i
= 0; i
< inst
->Instruction
.NumDstRegs
; i
++) {
218 struct tgsi_full_dst_register
*dst
= &inst
->Dst
[i
];
219 if (dst
->Register
.File
== TGSI_FILE_OUTPUT
&&
220 dst
->Register
.Index
== (int)ts
->color_out
) {
221 dst
->Register
.File
= TGSI_FILE_TEMPORARY
;
222 dst
->Register
.Index
= ts
->color_tmp
;
226 ctx
->emit_instruction(ctx
, inst
);
230 * TGSI transform epilog callback.
233 aa_epilog(struct tgsi_transform_context
*ctx
)
235 struct aa_transform_context
*ts
= aa_transform_context(ctx
);
237 /* add alpha modulation code at tail of program */
238 assert(ts
->color_out
!= INVALID_INDEX
);
239 assert(ts
->color_tmp
!= INVALID_INDEX
);
241 /* MOV output.color.xyz colorTmp */
242 tgsi_transform_op1_inst(ctx
, TGSI_OPCODE_MOV
,
243 TGSI_FILE_OUTPUT
, ts
->color_out
,
245 TGSI_FILE_TEMPORARY
, ts
->color_tmp
);
247 /* MUL output.color.w colorTmp.w tmp0.w */
248 tgsi_transform_op2_inst(ctx
, TGSI_OPCODE_MUL
,
249 TGSI_FILE_OUTPUT
, ts
->color_out
,
251 TGSI_FILE_TEMPORARY
, ts
->color_tmp
,
252 TGSI_FILE_TEMPORARY
, ts
->tmp
, false);
256 * TGSI utility to transform a fragment shader to support antialiasing point.
258 * This utility accepts two inputs:
259 *\param tokens_in -- the original token string of the shader
260 *\param aa_point_coord_index -- the semantic index of the generic register
261 * that contains the point sprite texture coord
263 * For each fragment in the point, we compute the distance of the fragment
264 * from the point center using the point sprite texture coordinates.
265 * If the distance is greater than 0.5, we'll discard the fragment.
266 * Otherwise, we'll compute a coverage value which approximates how much
267 * of the fragment is inside the bounding circle of the point. If the distance
268 * is less than 'k', the coverage is 1. Else, the coverage is between 0 and 1.
269 * The final fragment color's alpha channel is then modulated by the coverage
273 tgsi_add_aa_point(const struct tgsi_token
*tokens_in
,
274 const int aa_point_coord_index
)
276 struct aa_transform_context transform
;
277 const uint num_new_tokens
= 200; /* should be enough */
278 const uint new_len
= tgsi_num_tokens(tokens_in
) + num_new_tokens
;
279 struct tgsi_token
*new_tokens
;
281 /* allocate new tokens buffer */
282 new_tokens
= tgsi_alloc_tokens(new_len
);
286 /* setup transformation context */
287 memset(&transform
, 0, sizeof(transform
));
288 transform
.base
.transform_declaration
= aa_decl
;
289 transform
.base
.transform_instruction
= aa_inst
;
290 transform
.base
.transform_immediate
= aa_immediate
;
291 transform
.base
.prolog
= aa_prolog
;
292 transform
.base
.epilog
= aa_epilog
;
294 transform
.tmp
= INVALID_INDEX
;
295 transform
.color_out
= INVALID_INDEX
;
296 transform
.color_tmp
= INVALID_INDEX
;
298 assert(aa_point_coord_index
!= -1);
299 transform
.aa_point_coord_index
= (unsigned)aa_point_coord_index
;
301 transform
.num_tmp
= 0;
302 transform
.num_imm
= 0;
303 transform
.num_input
= 0;
305 /* transform the shader */
306 tgsi_transform_shader(tokens_in
, new_tokens
, new_len
, &transform
.base
);