Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/tgsi/tgsi_aa_point.c
4565 views
1
/*
2
* Copyright 2014 VMware, Inc.
3
* All Rights Reserved.
4
*
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:
12
*
13
* The above copyright notice and this permission notice (including the
14
* next paragraph) shall be included in all copies or substantial portions
15
* of the Software.
16
*
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.
24
*/
25
26
27
/**
28
* This utility transforms the fragment shader to support anti-aliasing points.
29
*/
30
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"
36
37
#define INVALID_INDEX 9999
38
39
struct aa_transform_context
40
{
41
struct tgsi_transform_context base;
42
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;
50
};
51
52
static inline struct aa_transform_context *
53
aa_transform_context(struct tgsi_transform_context *ctx)
54
{
55
return (struct aa_transform_context *) ctx;
56
}
57
58
/**
59
* TGSI declaration transform callback.
60
*/
61
static void
62
aa_decl(struct tgsi_transform_context *ctx,
63
struct tgsi_full_declaration *decl)
64
{
65
struct aa_transform_context *ts = aa_transform_context(ctx);
66
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;
71
}
72
else if (decl->Declaration.File == TGSI_FILE_INPUT) {
73
ts->num_input++;
74
}
75
else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
76
ts->num_tmp = MAX2(ts->num_tmp, (unsigned)(decl->Range.Last + 1));
77
}
78
79
ctx->emit_declaration(ctx, decl);
80
}
81
82
/**
83
* TGSI immediate declaration transform callback.
84
*/
85
static void
86
aa_immediate(struct tgsi_transform_context *ctx,
87
struct tgsi_full_immediate *imm)
88
{
89
struct aa_transform_context *ts = aa_transform_context(ctx);
90
91
ctx->emit_immediate(ctx, imm);
92
ts->num_imm++;
93
}
94
95
/**
96
* TGSI transform prolog callback.
97
*/
98
static void
99
aa_prolog(struct tgsi_transform_context *ctx)
100
{
101
struct aa_transform_context *ts = aa_transform_context(ctx);
102
unsigned tmp0;
103
unsigned texIn;
104
unsigned imm;
105
106
/* Declare two temporary registers, one for temporary and
107
* one for color.
108
*/
109
ts->tmp = ts->num_tmp++;
110
ts->color_tmp = ts->num_tmp++;
111
112
tgsi_transform_temps_decl(ctx, ts->tmp, ts->color_tmp);
113
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);
118
119
/* Declare extra immediates */
120
imm = ts->num_imm++;
121
tgsi_transform_immediate_decl(ctx, 0.5, 0.5, 0.45, 1.0);
122
123
/*
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
129
* it's discarded.
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].
134
*
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
139
* texIn.w = unused
140
*
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
146
*/
147
148
tmp0 = ts->tmp;
149
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);
155
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);
161
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);
166
167
/* compute coverage factor = (0.5-d)/(0.5-k) */
168
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);
174
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);
180
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);
186
187
/* If the coverage value is negative, it means the fragment is outside
188
* the point's circular boundary. Kill it.
189
*/
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);
193
194
/* If the distance is less than the threshold, the coverage/alpha value
195
* will be greater than one. Clamp to one here.
196
*/
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);
202
}
203
204
/**
205
* TGSI instruction transform callback.
206
*/
207
static void
208
aa_inst(struct tgsi_transform_context *ctx,
209
struct tgsi_full_instruction *inst)
210
{
211
struct aa_transform_context *ts = aa_transform_context(ctx);
212
unsigned i;
213
214
/* Look for writes to color output reg and replace it with
215
* color temp reg.
216
*/
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;
223
}
224
}
225
226
ctx->emit_instruction(ctx, inst);
227
}
228
229
/**
230
* TGSI transform epilog callback.
231
*/
232
static void
233
aa_epilog(struct tgsi_transform_context *ctx)
234
{
235
struct aa_transform_context *ts = aa_transform_context(ctx);
236
237
/* add alpha modulation code at tail of program */
238
assert(ts->color_out != INVALID_INDEX);
239
assert(ts->color_tmp != INVALID_INDEX);
240
241
/* MOV output.color.xyz colorTmp */
242
tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV,
243
TGSI_FILE_OUTPUT, ts->color_out,
244
TGSI_WRITEMASK_XYZ,
245
TGSI_FILE_TEMPORARY, ts->color_tmp);
246
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,
250
TGSI_WRITEMASK_W,
251
TGSI_FILE_TEMPORARY, ts->color_tmp,
252
TGSI_FILE_TEMPORARY, ts->tmp, false);
253
}
254
255
/**
256
* TGSI utility to transform a fragment shader to support antialiasing point.
257
*
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
262
*
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
270
* value.
271
*/
272
struct tgsi_token *
273
tgsi_add_aa_point(const struct tgsi_token *tokens_in,
274
const int aa_point_coord_index)
275
{
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;
280
281
/* allocate new tokens buffer */
282
new_tokens = tgsi_alloc_tokens(new_len);
283
if (!new_tokens)
284
return NULL;
285
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;
293
294
transform.tmp = INVALID_INDEX;
295
transform.color_out = INVALID_INDEX;
296
transform.color_tmp = INVALID_INDEX;
297
298
assert(aa_point_coord_index != -1);
299
transform.aa_point_coord_index = (unsigned)aa_point_coord_index;
300
301
transform.num_tmp = 0;
302
transform.num_imm = 0;
303
transform.num_input = 0;
304
305
/* transform the shader */
306
tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
307
308
return new_tokens;
309
}
310
311