1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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_util.h"
42 #include "pipe/p_inlines.h"
43 #include "pipe/p_context.h"
44 #include "pipe/p_defines.h"
45 #include "pipe/p_shader_tokens.h"
47 #include "tgsi/util/tgsi_transform.h"
48 #include "tgsi/util/tgsi_dump.h"
50 #include "draw_context.h"
51 #include "draw_private.h"
55 * Enabling NORMALIZE might give _slightly_ better results.
56 * Basically, it controls whether we compute distance as d=sqrt(x*x+y*y) or
57 * d=x*x+y*y. Since we're working with a unit circle, the later seems
58 * close enough and saves some costly instructions.
64 * Subclass of pipe_shader_state to carry extra fragment shader info.
66 struct aapoint_fragment_shader
68 struct pipe_shader_state state
;
69 void *driver_fs
; /**< the regular shader */
70 void *aapoint_fs
; /**< the aa point-augmented shader */
75 * Subclass of draw_stage
79 struct draw_stage stage
;
84 /** this is the vertex attrib slot for the new texcoords */
88 * Currently bound state
90 struct aapoint_fragment_shader
*fs
;
93 * Driver interface/override functions
95 void * (*driver_create_fs_state
)(struct pipe_context
*,
96 const struct pipe_shader_state
*);
97 void (*driver_bind_fs_state
)(struct pipe_context
*, void *);
98 void (*driver_delete_fs_state
)(struct pipe_context
*, void *);
100 struct pipe_context
*pipe
;
106 * Subclass of tgsi_transform_context, used for transforming the
107 * user's fragment shader to add the special AA instructions.
109 struct aa_transform_context
{
110 struct tgsi_transform_context base
;
111 uint tempsUsed
; /**< bitmask */
112 int colorOutput
; /**< which output is the primary color */
113 int maxInput
, maxGeneric
; /**< max input index found */
114 int tmp0
, colorTemp
; /**< temp registers */
115 boolean firstInstruction
;
120 * TGSI declaration transform callback.
121 * Look for two free temp regs and available input reg for new texcoords.
124 aa_transform_decl(struct tgsi_transform_context
*ctx
,
125 struct tgsi_full_declaration
*decl
)
127 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
129 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
&&
130 decl
->Semantic
.SemanticName
== TGSI_SEMANTIC_COLOR
&&
131 decl
->Semantic
.SemanticIndex
== 0) {
132 aactx
->colorOutput
= decl
->u
.DeclarationRange
.First
;
134 else if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
135 if ((int) decl
->u
.DeclarationRange
.Last
> aactx
->maxInput
)
136 aactx
->maxInput
= decl
->u
.DeclarationRange
.Last
;
137 if (decl
->Semantic
.SemanticName
== TGSI_SEMANTIC_GENERIC
&&
138 (int) decl
->Semantic
.SemanticIndex
> aactx
->maxGeneric
) {
139 aactx
->maxGeneric
= decl
->Semantic
.SemanticIndex
;
142 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
144 for (i
= decl
->u
.DeclarationRange
.First
;
145 i
<= decl
->u
.DeclarationRange
.Last
; i
++) {
146 aactx
->tempsUsed
|= (1 << i
);
150 ctx
->emit_declaration(ctx
, decl
);
155 * TGSI instruction transform callback.
156 * Replace writes to result.color w/ a temp reg.
157 * Upon END instruction, insert texture sampling code for antialiasing.
160 aa_transform_inst(struct tgsi_transform_context
*ctx
,
161 struct tgsi_full_instruction
*inst
)
163 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
164 struct tgsi_full_instruction newInst
;
166 if (aactx
->firstInstruction
) {
167 /* emit our new declarations before the first instruction */
169 struct tgsi_full_declaration decl
;
170 const int texInput
= aactx
->maxInput
+ 1;
174 /* find two free temp regs */
175 for (i
= 0; i
< 32; i
++) {
176 if ((aactx
->tempsUsed
& (1 << i
)) == 0) {
177 /* found a free temp */
180 else if (aactx
->colorTemp
< 0)
181 aactx
->colorTemp
= i
;
187 assert(aactx
->colorTemp
!= aactx
->tmp0
);
191 /* declare new generic input/texcoord */
192 decl
= tgsi_default_full_declaration();
193 decl
.Declaration
.File
= TGSI_FILE_INPUT
;
194 decl
.Declaration
.Semantic
= 1;
195 decl
.Semantic
.SemanticName
= TGSI_SEMANTIC_GENERIC
;
196 decl
.Semantic
.SemanticIndex
= aactx
->maxGeneric
+ 1;
197 decl
.Declaration
.Interpolate
= 1;
198 /* XXX this could be linear... */
199 decl
.Interpolation
.Interpolate
= TGSI_INTERPOLATE_PERSPECTIVE
;
200 decl
.u
.DeclarationRange
.First
=
201 decl
.u
.DeclarationRange
.Last
= texInput
;
202 ctx
->emit_declaration(ctx
, &decl
);
204 /* declare new temp regs */
205 decl
= tgsi_default_full_declaration();
206 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
207 decl
.u
.DeclarationRange
.First
=
208 decl
.u
.DeclarationRange
.Last
= tmp0
;
209 ctx
->emit_declaration(ctx
, &decl
);
211 decl
= tgsi_default_full_declaration();
212 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
213 decl
.u
.DeclarationRange
.First
=
214 decl
.u
.DeclarationRange
.Last
= aactx
->colorTemp
;
215 ctx
->emit_declaration(ctx
, &decl
);
217 aactx
->firstInstruction
= FALSE
;
221 * Emit code to compute fragment coverage, kill if outside point radius
224 * t0.x = distance of fragment from center point
225 * t0.y = boolean, is t0.x > 1 ?
226 * t0.z = temporary for computing 1/(1-k) value
227 * t0.w = final coverage value
230 /* MUL t0.xy, tex, tex; # compute x^2, y^2 */
231 newInst
= tgsi_default_full_instruction();
232 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
233 newInst
.Instruction
.NumDstRegs
= 1;
234 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
235 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
236 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_XY
;
237 newInst
.Instruction
.NumSrcRegs
= 2;
238 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_INPUT
;
239 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= texInput
;
240 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_INPUT
;
241 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= texInput
;
242 ctx
->emit_instruction(ctx
, &newInst
);
244 /* ADD t0.x, t0.x, t0.y; # x^2 + y^2 */
245 newInst
= tgsi_default_full_instruction();
246 newInst
.Instruction
.Opcode
= TGSI_OPCODE_ADD
;
247 newInst
.Instruction
.NumDstRegs
= 1;
248 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
249 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
250 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_X
;
251 newInst
.Instruction
.NumSrcRegs
= 2;
252 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
253 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
254 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_X
;
255 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
256 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= tmp0
;
257 newInst
.FullSrcRegisters
[1].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_Y
;
258 ctx
->emit_instruction(ctx
, &newInst
);
260 #if NORMALIZE /* OPTIONAL normalization of length */
261 /* RSQ t0.x, t0.x; */
262 newInst
= tgsi_default_full_instruction();
263 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RSQ
;
264 newInst
.Instruction
.NumDstRegs
= 1;
265 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
266 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
267 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_X
;
268 newInst
.Instruction
.NumSrcRegs
= 1;
269 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
270 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
271 ctx
->emit_instruction(ctx
, &newInst
);
273 /* RCP t0.x, t0.x; */
274 newInst
= tgsi_default_full_instruction();
275 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RCP
;
276 newInst
.Instruction
.NumDstRegs
= 1;
277 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
278 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
279 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_X
;
280 newInst
.Instruction
.NumSrcRegs
= 1;
281 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
282 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
283 ctx
->emit_instruction(ctx
, &newInst
);
286 /* SGT t0.y, t0.xxxx, t0.wwww; # bool b = d > 1 (NOTE t0.w == 1) */
287 newInst
= tgsi_default_full_instruction();
288 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SGT
;
289 newInst
.Instruction
.NumDstRegs
= 1;
290 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
291 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
292 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_Y
;
293 newInst
.Instruction
.NumSrcRegs
= 2;
294 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
295 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
296 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleY
= TGSI_SWIZZLE_X
;
297 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_INPUT
;
298 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= texInput
;
299 newInst
.FullSrcRegisters
[1].SrcRegister
.SwizzleY
= TGSI_SWIZZLE_W
;
300 ctx
->emit_instruction(ctx
, &newInst
);
302 /* KILP -t0.yyyy; # if b, KILL */
303 newInst
= tgsi_default_full_instruction();
304 newInst
.Instruction
.Opcode
= TGSI_OPCODE_KILP
;
305 newInst
.Instruction
.NumDstRegs
= 0;
306 newInst
.Instruction
.NumSrcRegs
= 1;
307 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
308 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
309 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_Y
;
310 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleY
= TGSI_SWIZZLE_Y
;
311 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleZ
= TGSI_SWIZZLE_Y
;
312 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleW
= TGSI_SWIZZLE_Y
;
313 newInst
.FullSrcRegisters
[0].SrcRegister
.Negate
= 1;
314 ctx
->emit_instruction(ctx
, &newInst
);
316 /* SGT t0.y, t0.x, tex.z; # bool b = distance > k */
317 newInst
= tgsi_default_full_instruction();
318 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SGT
;
319 newInst
.Instruction
.NumDstRegs
= 1;
320 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
321 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
322 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_Y
;
323 newInst
.Instruction
.NumSrcRegs
= 2;
324 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
325 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
326 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleY
= TGSI_SWIZZLE_X
;
327 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_INPUT
;
328 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= texInput
;
329 newInst
.FullSrcRegisters
[1].SrcRegister
.SwizzleY
= TGSI_SWIZZLE_Z
;
330 ctx
->emit_instruction(ctx
, &newInst
);
332 /* IF t0.y # if b then */
333 newInst
= tgsi_default_full_instruction();
334 newInst
.Instruction
.Opcode
= TGSI_OPCODE_IF
;
335 newInst
.Instruction
.NumDstRegs
= 0;
336 newInst
.Instruction
.NumSrcRegs
= 1;
337 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
338 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
339 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_Y
;
340 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleY
= TGSI_SWIZZLE_Y
;
341 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleZ
= TGSI_SWIZZLE_Y
;
342 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleW
= TGSI_SWIZZLE_Y
;
343 ctx
->emit_instruction(ctx
, &newInst
);
346 /* compute coverage factor = (1-d)/(1-k) */
348 /* SUB t0.z, tex.w, tex.z; # m = 1 - k */
349 newInst
= tgsi_default_full_instruction();
350 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SUB
;
351 newInst
.Instruction
.NumDstRegs
= 1;
352 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
353 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
354 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_Z
;
355 newInst
.Instruction
.NumSrcRegs
= 2;
356 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_INPUT
;
357 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= texInput
;
358 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleZ
= TGSI_SWIZZLE_W
;
359 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_INPUT
;
360 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= texInput
;
361 newInst
.FullSrcRegisters
[1].SrcRegister
.SwizzleZ
= TGSI_SWIZZLE_Z
;
362 ctx
->emit_instruction(ctx
, &newInst
);
364 /* RCP t0.z, t0.z; # t0.z = 1 / m */
365 newInst
= tgsi_default_full_instruction();
366 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RCP
;
367 newInst
.Instruction
.NumDstRegs
= 1;
368 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
369 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
370 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_Z
;
371 newInst
.Instruction
.NumSrcRegs
= 1;
372 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
373 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
374 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_Z
;
375 ctx
->emit_instruction(ctx
, &newInst
);
377 /* SUB t0.x, 1, t0.x; # d = 1 - d */
378 newInst
= tgsi_default_full_instruction();
379 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SUB
;
380 newInst
.Instruction
.NumDstRegs
= 1;
381 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
382 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
383 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_X
;
384 newInst
.Instruction
.NumSrcRegs
= 2;
385 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_INPUT
;
386 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= texInput
;
387 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_W
;
388 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
389 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= tmp0
;
390 newInst
.FullSrcRegisters
[1].SrcRegister
.SwizzleX
= TGSI_SWIZZLE_X
;
391 ctx
->emit_instruction(ctx
, &newInst
);
393 /* MUL t0.w, t0.x, t0.z; # coverage = d * m */
394 newInst
= tgsi_default_full_instruction();
395 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
396 newInst
.Instruction
.NumDstRegs
= 1;
397 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
398 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
399 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_W
;
400 newInst
.Instruction
.NumSrcRegs
= 2;
401 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
402 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= tmp0
;
403 newInst
.FullSrcRegisters
[0].SrcRegister
.SwizzleW
= TGSI_SWIZZLE_X
;
404 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
405 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= tmp0
;
406 newInst
.FullSrcRegisters
[1].SrcRegister
.SwizzleW
= TGSI_SWIZZLE_Z
;
407 ctx
->emit_instruction(ctx
, &newInst
);
411 newInst
= tgsi_default_full_instruction();
412 newInst
.Instruction
.Opcode
= TGSI_OPCODE_ELSE
;
413 newInst
.Instruction
.NumDstRegs
= 0;
414 newInst
.Instruction
.NumSrcRegs
= 0;
415 ctx
->emit_instruction(ctx
, &newInst
);
418 /* MOV t0.w, tex.w; # coverage = 1.0 */
419 newInst
= tgsi_default_full_instruction();
420 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MOV
;
421 newInst
.Instruction
.NumDstRegs
= 1;
422 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_TEMPORARY
;
423 newInst
.FullDstRegisters
[0].DstRegister
.Index
= tmp0
;
424 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_W
;
425 newInst
.Instruction
.NumSrcRegs
= 1;
426 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_INPUT
;
427 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= texInput
;
428 ctx
->emit_instruction(ctx
, &newInst
);
432 newInst
= tgsi_default_full_instruction();
433 newInst
.Instruction
.Opcode
= TGSI_OPCODE_ENDIF
;
434 newInst
.Instruction
.NumDstRegs
= 0;
435 newInst
.Instruction
.NumSrcRegs
= 0;
436 ctx
->emit_instruction(ctx
, &newInst
);
439 if (inst
->Instruction
.Opcode
== TGSI_OPCODE_END
) {
440 /* add alpha modulation code at tail of program */
442 /* MOV result.color.xyz, colorTemp; */
443 newInst
= tgsi_default_full_instruction();
444 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MOV
;
445 newInst
.Instruction
.NumDstRegs
= 1;
446 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_OUTPUT
;
447 newInst
.FullDstRegisters
[0].DstRegister
.Index
= aactx
->colorOutput
;
448 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_XYZ
;
449 newInst
.Instruction
.NumSrcRegs
= 1;
450 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
451 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= aactx
->colorTemp
;
452 ctx
->emit_instruction(ctx
, &newInst
);
454 /* MUL result.color.w, colorTemp, tmp0.w; */
455 newInst
= tgsi_default_full_instruction();
456 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
457 newInst
.Instruction
.NumDstRegs
= 1;
458 newInst
.FullDstRegisters
[0].DstRegister
.File
= TGSI_FILE_OUTPUT
;
459 newInst
.FullDstRegisters
[0].DstRegister
.Index
= aactx
->colorOutput
;
460 newInst
.FullDstRegisters
[0].DstRegister
.WriteMask
= TGSI_WRITEMASK_W
;
461 newInst
.Instruction
.NumSrcRegs
= 2;
462 newInst
.FullSrcRegisters
[0].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
463 newInst
.FullSrcRegisters
[0].SrcRegister
.Index
= aactx
->colorTemp
;
464 newInst
.FullSrcRegisters
[1].SrcRegister
.File
= TGSI_FILE_TEMPORARY
;
465 newInst
.FullSrcRegisters
[1].SrcRegister
.Index
= aactx
->tmp0
;
466 ctx
->emit_instruction(ctx
, &newInst
);
469 /* Not an END instruction.
470 * Look for writes to result.color and replace with colorTemp reg.
474 for (i
= 0; i
< inst
->Instruction
.NumDstRegs
; i
++) {
475 struct tgsi_full_dst_register
*dst
= &inst
->FullDstRegisters
[i
];
476 if (dst
->DstRegister
.File
== TGSI_FILE_OUTPUT
&&
477 dst
->DstRegister
.Index
== aactx
->colorOutput
) {
478 dst
->DstRegister
.File
= TGSI_FILE_TEMPORARY
;
479 dst
->DstRegister
.Index
= aactx
->colorTemp
;
484 ctx
->emit_instruction(ctx
, inst
);
489 * Generate the frag shader we'll use for drawing AA lines.
490 * This will be the user's shader plus some texture/modulate instructions.
493 generate_aapoint_fs(struct aapoint_stage
*aapoint
)
495 const struct pipe_shader_state
*orig_fs
= &aapoint
->fs
->state
;
496 struct draw_context
*draw
= aapoint
->stage
.draw
;
497 struct pipe_shader_state aapoint_fs
;
498 struct aa_transform_context transform
;
502 aapoint_fs
= *orig_fs
; /* copy to init */
503 aapoint_fs
.tokens
= MALLOC(sizeof(struct tgsi_token
) * MAX
);
505 memset(&transform
, 0, sizeof(transform
));
506 transform
.colorOutput
= -1;
507 transform
.maxInput
= -1;
508 transform
.maxGeneric
= -1;
509 transform
.colorTemp
= -1;
511 transform
.firstInstruction
= TRUE
;
512 transform
.base
.transform_instruction
= aa_transform_inst
;
513 transform
.base
.transform_declaration
= aa_transform_decl
;
515 tgsi_transform_shader(orig_fs
->tokens
,
516 (struct tgsi_token
*) aapoint_fs
.tokens
,
517 MAX
, &transform
.base
);
520 tgsi_dump(orig_fs
->tokens
, 0);
521 tgsi_dump(aapoint_fs
.tokens
, 0);
524 aapoint_fs
.input_semantic_name
[aapoint_fs
.num_inputs
] = TGSI_SEMANTIC_GENERIC
;
525 aapoint_fs
.input_semantic_index
[aapoint_fs
.num_inputs
] = transform
.maxGeneric
+ 1;
526 aapoint_fs
.num_inputs
++;
528 aapoint
->fs
->aapoint_fs
529 = aapoint
->driver_create_fs_state(aapoint
->pipe
, &aapoint_fs
);
531 /* advertise the extra post-transform vertex attributes which will have
534 draw
->extra_vp_outputs
.semantic_name
= TGSI_SEMANTIC_GENERIC
;
535 draw
->extra_vp_outputs
.semantic_index
= transform
.maxGeneric
+ 1;
540 * When we're about to draw our first AA line in a batch, this function is
541 * called to tell the driver to bind our modified fragment shader.
544 bind_aapoint_fragment_shader(struct aapoint_stage
*aapoint
)
546 if (!aapoint
->fs
->aapoint_fs
) {
547 generate_aapoint_fs(aapoint
);
549 aapoint
->driver_bind_fs_state(aapoint
->pipe
, aapoint
->fs
->aapoint_fs
);
554 static INLINE
struct aapoint_stage
*
555 aapoint_stage( struct draw_stage
*stage
)
557 return (struct aapoint_stage
*) stage
;
562 passthrough_line(struct draw_stage
*stage
, struct prim_header
*header
)
564 stage
->next
->line(stage
->next
, header
);
569 passthrough_tri(struct draw_stage
*stage
, struct prim_header
*header
)
571 stage
->next
->tri(stage
->next
, header
);
576 * Draw an AA point by drawing a quad.
579 aapoint_point(struct draw_stage
*stage
, struct prim_header
*header
)
581 const struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
582 struct prim_header tri
;
583 struct vertex_header
*v
[4];
584 uint texPos
= aapoint
->tex_slot
;
585 float radius
, *pos
, *tex
;
589 if (aapoint
->psize_slot
>= 0) {
590 radius
= 0.5f
* header
->v
[0]->data
[aapoint
->psize_slot
][0];
593 radius
= aapoint
->radius
;
597 * Note: the texcoords (generic attrib, really) we use are special:
598 * The S and T components simply vary from -1 to +1.
599 * The R component is k, below.
600 * The Q component is 1.0 and will used as a handy constant in the
605 * k is the threshold distance from the point's center at which
606 * we begin alpha attenuation (the coverage value).
607 * Operating within a unit circle, we'll compute the fragment's
608 * distance 'd' from the center point using the texcoords.
612 * compute coverage in [0,1] proportional to d in [k, 1].
614 * coverage = 1.0; // full coverage
620 k
= 1.0 - 2.0 * k
+ k
* k
;
622 k
= 1.0 - 1.0 / radius
;
625 /* allocate/dup new verts */
626 for (i
= 0; i
< 4; i
++) {
627 v
[i
] = dup_vert(stage
, header
->v
[0], i
);
648 tex
= v
[0]->data
[texPos
];
649 ASSIGN_4V(tex
, -1, -1, k
, 1);
651 tex
= v
[1]->data
[texPos
];
652 ASSIGN_4V(tex
, 1, -1, k
, 1);
654 tex
= v
[2]->data
[texPos
];
655 ASSIGN_4V(tex
, 1, 1, k
, 1);
657 tex
= v
[3]->data
[texPos
];
658 ASSIGN_4V(tex
, -1, 1, k
, 1);
660 /* emit 2 tris for the quad strip */
664 stage
->next
->tri( stage
->next
, &tri
);
669 stage
->next
->tri( stage
->next
, &tri
);
674 aapoint_first_point(struct draw_stage
*stage
, struct prim_header
*header
)
676 auto struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
677 struct draw_context
*draw
= stage
->draw
;
679 assert(draw
->rasterizer
->point_smooth
);
681 if (draw
->rasterizer
->point_size
<= 2.0)
682 aapoint
->radius
= 1.0;
684 aapoint
->radius
= 0.5f
* draw
->rasterizer
->point_size
;
686 aapoint
->tex_slot
= draw
->num_vs_outputs
;
687 assert(aapoint
->tex_slot
> 0); /* output[0] is vertex pos */
688 draw
->extra_vp_outputs
.slot
= aapoint
->tex_slot
;
693 bind_aapoint_fragment_shader(aapoint
);
695 /* find psize slot in post-transform vertex */
696 aapoint
->psize_slot
= -1;
697 if (draw
->rasterizer
->point_size_per_vertex
) {
698 /* find PSIZ vertex output */
699 const struct draw_vertex_shader
*vs
= draw
->vertex_shader
;
701 for (i
= 0; i
< vs
->state
->num_outputs
; i
++) {
702 if (vs
->state
->output_semantic_name
[i
] == TGSI_SEMANTIC_PSIZE
) {
703 aapoint
->psize_slot
= i
;
709 /* now really draw first line */
710 stage
->point
= aapoint_point
;
711 stage
->point(stage
, header
);
716 aapoint_flush(struct draw_stage
*stage
, unsigned flags
)
718 struct draw_context
*draw
= stage
->draw
;
719 struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
720 struct pipe_context
*pipe
= aapoint
->pipe
;
722 stage
->point
= aapoint_first_point
;
723 stage
->next
->flush( stage
->next
, flags
);
725 /* restore original frag shader */
726 aapoint
->driver_bind_fs_state(pipe
, aapoint
->fs
->driver_fs
);
728 draw
->extra_vp_outputs
.slot
= 0;
733 aapoint_reset_stipple_counter(struct draw_stage
*stage
)
735 stage
->next
->reset_stipple_counter( stage
->next
);
740 aapoint_destroy(struct draw_stage
*stage
)
742 draw_free_temp_verts( stage
);
747 static struct aapoint_stage
*
748 draw_aapoint_stage(struct draw_context
*draw
)
750 struct aapoint_stage
*aapoint
= CALLOC_STRUCT(aapoint_stage
);
752 draw_alloc_temp_verts( &aapoint
->stage
, 4 );
754 aapoint
->stage
.draw
= draw
;
755 aapoint
->stage
.next
= NULL
;
756 aapoint
->stage
.point
= aapoint_first_point
;
757 aapoint
->stage
.line
= passthrough_line
;
758 aapoint
->stage
.tri
= passthrough_tri
;
759 aapoint
->stage
.flush
= aapoint_flush
;
760 aapoint
->stage
.reset_stipple_counter
= aapoint_reset_stipple_counter
;
761 aapoint
->stage
.destroy
= aapoint_destroy
;
768 * XXX temporary? solution to mapping a pipe_context to a aapoint_stage.
771 #define MAX_CONTEXTS 10
773 static struct pipe_context
*Pipe
[MAX_CONTEXTS
];
774 static struct aapoint_stage
*Stage
[MAX_CONTEXTS
];
775 static uint NumContexts
;
778 add_aa_pipe_context(struct pipe_context
*pipe
, struct aapoint_stage
*aa
)
780 assert(NumContexts
< MAX_CONTEXTS
);
781 Pipe
[NumContexts
] = pipe
;
782 Stage
[NumContexts
] = aa
;
786 static struct aapoint_stage
*
787 aapoint_stage_from_pipe(struct pipe_context
*pipe
)
790 for (i
= 0; i
< NumContexts
; i
++) {
800 * This function overrides the driver's create_fs_state() function and
801 * will typically be called by the state tracker.
804 aapoint_create_fs_state(struct pipe_context
*pipe
,
805 const struct pipe_shader_state
*fs
)
807 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
808 struct aapoint_fragment_shader
*aafs
= CALLOC_STRUCT(aapoint_fragment_shader
);
814 aafs
->driver_fs
= aapoint
->driver_create_fs_state(aapoint
->pipe
, fs
);
822 aapoint_bind_fs_state(struct pipe_context
*pipe
, void *fs
)
824 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
825 struct aapoint_fragment_shader
*aafs
= (struct aapoint_fragment_shader
*) fs
;
829 aapoint
->driver_bind_fs_state(aapoint
->pipe
, aafs
->driver_fs
);
834 aapoint_delete_fs_state(struct pipe_context
*pipe
, void *fs
)
836 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
837 struct aapoint_fragment_shader
*aafs
= (struct aapoint_fragment_shader
*) fs
;
839 aapoint
->driver_delete_fs_state(aapoint
->pipe
, aafs
->driver_fs
);
845 * Called by drivers that want to install this AA point prim stage
846 * into the draw module's pipeline. This will not be used if the
847 * hardware has native support for AA points.
850 draw_install_aapoint_stage(struct draw_context
*draw
,
851 struct pipe_context
*pipe
)
853 struct aapoint_stage
*aapoint
;
856 * Create / install AA point drawing / prim stage
858 aapoint
= draw_aapoint_stage( draw
);
860 draw
->pipeline
.aapoint
= &aapoint
->stage
;
862 aapoint
->pipe
= pipe
;
864 /* save original driver functions */
865 aapoint
->driver_create_fs_state
= pipe
->create_fs_state
;
866 aapoint
->driver_bind_fs_state
= pipe
->bind_fs_state
;
867 aapoint
->driver_delete_fs_state
= pipe
->delete_fs_state
;
869 /* override the driver's functions */
870 pipe
->create_fs_state
= aapoint_create_fs_state
;
871 pipe
->bind_fs_state
= aapoint_bind_fs_state
;
872 pipe
->delete_fs_state
= aapoint_delete_fs_state
;
874 add_aa_pipe_context(pipe
, aapoint
);