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 /** Approx number of new tokens for instructions in aa_transform_inst() */
57 #define NUM_NEW_TOKENS 200
61 * Enabling NORMALIZE might give _slightly_ better results.
62 * Basically, it controls whether we compute distance as d=sqrt(x*x+y*y) or
63 * d=x*x+y*y. Since we're working with a unit circle, the later seems
64 * close enough and saves some costly instructions.
70 * Subclass of pipe_shader_state to carry extra fragment shader info.
72 struct aapoint_fragment_shader
74 struct pipe_shader_state state
;
75 void *driver_fs
; /**< the regular shader */
76 void *aapoint_fs
; /**< the aa point-augmented shader */
77 int generic_attrib
; /**< The generic input attrib/texcoord we'll use */
82 * Subclass of draw_stage
86 struct draw_stage stage
;
88 /** half of pipe_rasterizer_state::point_size */
91 /** vertex attrib slot containing point size */
94 /** this is the vertex attrib slot for the new texcoords */
97 /** vertex attrib slot containing position */
100 /** Currently bound fragment shader */
101 struct aapoint_fragment_shader
*fs
;
104 * Driver interface/override functions
106 void * (*driver_create_fs_state
)(struct pipe_context
*,
107 const struct pipe_shader_state
*);
108 void (*driver_bind_fs_state
)(struct pipe_context
*, void *);
109 void (*driver_delete_fs_state
)(struct pipe_context
*, void *);
115 * Subclass of tgsi_transform_context, used for transforming the
116 * user's fragment shader to add the special AA instructions.
118 struct aa_transform_context
{
119 struct tgsi_transform_context base
;
120 uint tempsUsed
; /**< bitmask */
121 int colorOutput
; /**< which output is the primary color */
122 int maxInput
, maxGeneric
; /**< max input index found */
123 int tmp0
, colorTemp
; /**< temp registers */
124 boolean firstInstruction
;
129 * TGSI declaration transform callback.
130 * Look for two free temp regs and available input reg for new texcoords.
133 aa_transform_decl(struct tgsi_transform_context
*ctx
,
134 struct tgsi_full_declaration
*decl
)
136 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
138 if (decl
->Declaration
.File
== TGSI_FILE_OUTPUT
&&
139 decl
->Semantic
.Name
== TGSI_SEMANTIC_COLOR
&&
140 decl
->Semantic
.Index
== 0) {
141 aactx
->colorOutput
= decl
->Range
.First
;
143 else if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
144 if ((int) decl
->Range
.Last
> aactx
->maxInput
)
145 aactx
->maxInput
= decl
->Range
.Last
;
146 if (decl
->Semantic
.Name
== TGSI_SEMANTIC_GENERIC
&&
147 (int) decl
->Semantic
.Index
> aactx
->maxGeneric
) {
148 aactx
->maxGeneric
= decl
->Semantic
.Index
;
151 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
153 for (i
= decl
->Range
.First
;
154 i
<= decl
->Range
.Last
; i
++) {
155 aactx
->tempsUsed
|= (1 << i
);
159 ctx
->emit_declaration(ctx
, decl
);
164 * TGSI instruction transform callback.
165 * Replace writes to result.color w/ a temp reg.
166 * Upon END instruction, insert texture sampling code for antialiasing.
169 aa_transform_inst(struct tgsi_transform_context
*ctx
,
170 struct tgsi_full_instruction
*inst
)
172 struct aa_transform_context
*aactx
= (struct aa_transform_context
*) ctx
;
173 struct tgsi_full_instruction newInst
;
175 if (aactx
->firstInstruction
) {
176 /* emit our new declarations before the first instruction */
178 struct tgsi_full_declaration decl
;
179 const int texInput
= aactx
->maxInput
+ 1;
183 /* find two free temp regs */
184 for (i
= 0; i
< 32; i
++) {
185 if ((aactx
->tempsUsed
& (1 << i
)) == 0) {
186 /* found a free temp */
189 else if (aactx
->colorTemp
< 0)
190 aactx
->colorTemp
= i
;
196 assert(aactx
->colorTemp
!= aactx
->tmp0
);
200 /* declare new generic input/texcoord */
201 decl
= tgsi_default_full_declaration();
202 decl
.Declaration
.File
= TGSI_FILE_INPUT
;
203 /* XXX this could be linear... */
204 decl
.Declaration
.Interpolate
= 1;
205 decl
.Declaration
.Semantic
= 1;
206 decl
.Semantic
.Name
= TGSI_SEMANTIC_GENERIC
;
207 decl
.Semantic
.Index
= aactx
->maxGeneric
+ 1;
209 decl
.Range
.Last
= texInput
;
210 decl
.Interp
.Interpolate
= TGSI_INTERPOLATE_PERSPECTIVE
;
211 ctx
->emit_declaration(ctx
, &decl
);
213 /* declare new temp regs */
214 decl
= tgsi_default_full_declaration();
215 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
217 decl
.Range
.Last
= tmp0
;
218 ctx
->emit_declaration(ctx
, &decl
);
220 decl
= tgsi_default_full_declaration();
221 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
223 decl
.Range
.Last
= aactx
->colorTemp
;
224 ctx
->emit_declaration(ctx
, &decl
);
226 aactx
->firstInstruction
= FALSE
;
230 * Emit code to compute fragment coverage, kill if outside point radius
233 * t0.x = distance of fragment from center point
234 * t0.y = boolean, is t0.x > 1.0, also misc temp usage
235 * t0.z = temporary for computing 1/(1-k) value
236 * t0.w = final coverage value
239 /* MUL t0.xy, tex, tex; # compute x^2, y^2 */
240 newInst
= tgsi_default_full_instruction();
241 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
242 newInst
.Instruction
.NumDstRegs
= 1;
243 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
244 newInst
.Dst
[0].Register
.Index
= tmp0
;
245 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_XY
;
246 newInst
.Instruction
.NumSrcRegs
= 2;
247 newInst
.Src
[0].Register
.File
= TGSI_FILE_INPUT
;
248 newInst
.Src
[0].Register
.Index
= texInput
;
249 newInst
.Src
[1].Register
.File
= TGSI_FILE_INPUT
;
250 newInst
.Src
[1].Register
.Index
= texInput
;
251 ctx
->emit_instruction(ctx
, &newInst
);
253 /* ADD t0.x, t0.x, t0.y; # x^2 + y^2 */
254 newInst
= tgsi_default_full_instruction();
255 newInst
.Instruction
.Opcode
= TGSI_OPCODE_ADD
;
256 newInst
.Instruction
.NumDstRegs
= 1;
257 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
258 newInst
.Dst
[0].Register
.Index
= tmp0
;
259 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_X
;
260 newInst
.Instruction
.NumSrcRegs
= 2;
261 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
262 newInst
.Src
[0].Register
.Index
= tmp0
;
263 newInst
.Src
[0].Register
.SwizzleX
= TGSI_SWIZZLE_X
;
264 newInst
.Src
[1].Register
.File
= TGSI_FILE_TEMPORARY
;
265 newInst
.Src
[1].Register
.Index
= tmp0
;
266 newInst
.Src
[1].Register
.SwizzleX
= TGSI_SWIZZLE_Y
;
267 ctx
->emit_instruction(ctx
, &newInst
);
269 #if NORMALIZE /* OPTIONAL normalization of length */
270 /* RSQ t0.x, t0.x; */
271 newInst
= tgsi_default_full_instruction();
272 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RSQ
;
273 newInst
.Instruction
.NumDstRegs
= 1;
274 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
275 newInst
.Dst
[0].Register
.Index
= tmp0
;
276 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_X
;
277 newInst
.Instruction
.NumSrcRegs
= 1;
278 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
279 newInst
.Src
[0].Register
.Index
= tmp0
;
280 ctx
->emit_instruction(ctx
, &newInst
);
282 /* RCP t0.x, t0.x; */
283 newInst
= tgsi_default_full_instruction();
284 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RCP
;
285 newInst
.Instruction
.NumDstRegs
= 1;
286 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
287 newInst
.Dst
[0].Register
.Index
= tmp0
;
288 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_X
;
289 newInst
.Instruction
.NumSrcRegs
= 1;
290 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
291 newInst
.Src
[0].Register
.Index
= tmp0
;
292 ctx
->emit_instruction(ctx
, &newInst
);
295 /* SGT t0.y, t0.xxxx, tex.wwww; # bool b = d > 1 (NOTE tex.w == 1) */
296 newInst
= tgsi_default_full_instruction();
297 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SGT
;
298 newInst
.Instruction
.NumDstRegs
= 1;
299 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
300 newInst
.Dst
[0].Register
.Index
= tmp0
;
301 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_Y
;
302 newInst
.Instruction
.NumSrcRegs
= 2;
303 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
304 newInst
.Src
[0].Register
.Index
= tmp0
;
305 newInst
.Src
[0].Register
.SwizzleY
= TGSI_SWIZZLE_X
;
306 newInst
.Src
[1].Register
.File
= TGSI_FILE_INPUT
;
307 newInst
.Src
[1].Register
.Index
= texInput
;
308 newInst
.Src
[1].Register
.SwizzleY
= TGSI_SWIZZLE_W
;
309 ctx
->emit_instruction(ctx
, &newInst
);
311 /* KILL_IF -tmp0.yyyy; # if -tmp0.y < 0, KILL */
312 newInst
= tgsi_default_full_instruction();
313 newInst
.Instruction
.Opcode
= TGSI_OPCODE_KILL_IF
;
314 newInst
.Instruction
.NumDstRegs
= 0;
315 newInst
.Instruction
.NumSrcRegs
= 1;
316 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
317 newInst
.Src
[0].Register
.Index
= tmp0
;
318 newInst
.Src
[0].Register
.SwizzleX
= TGSI_SWIZZLE_Y
;
319 newInst
.Src
[0].Register
.SwizzleY
= TGSI_SWIZZLE_Y
;
320 newInst
.Src
[0].Register
.SwizzleZ
= TGSI_SWIZZLE_Y
;
321 newInst
.Src
[0].Register
.SwizzleW
= TGSI_SWIZZLE_Y
;
322 newInst
.Src
[0].Register
.Negate
= 1;
323 ctx
->emit_instruction(ctx
, &newInst
);
326 /* compute coverage factor = (1-d)/(1-k) */
328 /* SUB t0.z, tex.w, tex.z; # m = 1 - k */
329 newInst
= tgsi_default_full_instruction();
330 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SUB
;
331 newInst
.Instruction
.NumDstRegs
= 1;
332 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
333 newInst
.Dst
[0].Register
.Index
= tmp0
;
334 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_Z
;
335 newInst
.Instruction
.NumSrcRegs
= 2;
336 newInst
.Src
[0].Register
.File
= TGSI_FILE_INPUT
;
337 newInst
.Src
[0].Register
.Index
= texInput
;
338 newInst
.Src
[0].Register
.SwizzleZ
= TGSI_SWIZZLE_W
;
339 newInst
.Src
[1].Register
.File
= TGSI_FILE_INPUT
;
340 newInst
.Src
[1].Register
.Index
= texInput
;
341 newInst
.Src
[1].Register
.SwizzleZ
= TGSI_SWIZZLE_Z
;
342 ctx
->emit_instruction(ctx
, &newInst
);
344 /* RCP t0.z, t0.z; # t0.z = 1 / m */
345 newInst
= tgsi_default_full_instruction();
346 newInst
.Instruction
.Opcode
= TGSI_OPCODE_RCP
;
347 newInst
.Instruction
.NumDstRegs
= 1;
348 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
349 newInst
.Dst
[0].Register
.Index
= tmp0
;
350 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_Z
;
351 newInst
.Instruction
.NumSrcRegs
= 1;
352 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
353 newInst
.Src
[0].Register
.Index
= tmp0
;
354 newInst
.Src
[0].Register
.SwizzleX
= TGSI_SWIZZLE_Z
;
355 ctx
->emit_instruction(ctx
, &newInst
);
357 /* SUB t0.y, 1, t0.x; # d = 1 - d */
358 newInst
= tgsi_default_full_instruction();
359 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SUB
;
360 newInst
.Instruction
.NumDstRegs
= 1;
361 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
362 newInst
.Dst
[0].Register
.Index
= tmp0
;
363 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_Y
;
364 newInst
.Instruction
.NumSrcRegs
= 2;
365 newInst
.Src
[0].Register
.File
= TGSI_FILE_INPUT
;
366 newInst
.Src
[0].Register
.Index
= texInput
;
367 newInst
.Src
[0].Register
.SwizzleY
= TGSI_SWIZZLE_W
;
368 newInst
.Src
[1].Register
.File
= TGSI_FILE_TEMPORARY
;
369 newInst
.Src
[1].Register
.Index
= tmp0
;
370 newInst
.Src
[1].Register
.SwizzleY
= TGSI_SWIZZLE_X
;
371 ctx
->emit_instruction(ctx
, &newInst
);
373 /* MUL t0.w, t0.y, t0.z; # coverage = d * m */
374 newInst
= tgsi_default_full_instruction();
375 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
376 newInst
.Instruction
.NumDstRegs
= 1;
377 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
378 newInst
.Dst
[0].Register
.Index
= tmp0
;
379 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_W
;
380 newInst
.Instruction
.NumSrcRegs
= 2;
381 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
382 newInst
.Src
[0].Register
.Index
= tmp0
;
383 newInst
.Src
[0].Register
.SwizzleW
= TGSI_SWIZZLE_Y
;
384 newInst
.Src
[1].Register
.File
= TGSI_FILE_TEMPORARY
;
385 newInst
.Src
[1].Register
.Index
= tmp0
;
386 newInst
.Src
[1].Register
.SwizzleW
= TGSI_SWIZZLE_Z
;
387 ctx
->emit_instruction(ctx
, &newInst
);
389 /* SLE t0.y, t0.x, tex.z; # bool b = distance <= k */
390 newInst
= tgsi_default_full_instruction();
391 newInst
.Instruction
.Opcode
= TGSI_OPCODE_SLE
;
392 newInst
.Instruction
.NumDstRegs
= 1;
393 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
394 newInst
.Dst
[0].Register
.Index
= tmp0
;
395 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_Y
;
396 newInst
.Instruction
.NumSrcRegs
= 2;
397 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
398 newInst
.Src
[0].Register
.Index
= tmp0
;
399 newInst
.Src
[0].Register
.SwizzleY
= TGSI_SWIZZLE_X
;
400 newInst
.Src
[1].Register
.File
= TGSI_FILE_INPUT
;
401 newInst
.Src
[1].Register
.Index
= texInput
;
402 newInst
.Src
[1].Register
.SwizzleY
= TGSI_SWIZZLE_Z
;
403 ctx
->emit_instruction(ctx
, &newInst
);
405 /* CMP t0.w, -t0.y, tex.w, t0.w;
406 * # if -t0.y < 0 then
411 newInst
= tgsi_default_full_instruction();
412 newInst
.Instruction
.Opcode
= TGSI_OPCODE_CMP
;
413 newInst
.Instruction
.NumDstRegs
= 1;
414 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
415 newInst
.Dst
[0].Register
.Index
= tmp0
;
416 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_W
;
417 newInst
.Instruction
.NumSrcRegs
= 3;
418 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
419 newInst
.Src
[0].Register
.Index
= tmp0
;
420 newInst
.Src
[0].Register
.SwizzleX
= TGSI_SWIZZLE_Y
;
421 newInst
.Src
[0].Register
.SwizzleY
= TGSI_SWIZZLE_Y
;
422 newInst
.Src
[0].Register
.SwizzleZ
= TGSI_SWIZZLE_Y
;
423 newInst
.Src
[0].Register
.SwizzleW
= TGSI_SWIZZLE_Y
;
424 newInst
.Src
[0].Register
.Negate
= 1;
425 newInst
.Src
[1].Register
.File
= TGSI_FILE_INPUT
;
426 newInst
.Src
[1].Register
.Index
= texInput
;
427 newInst
.Src
[1].Register
.SwizzleX
= TGSI_SWIZZLE_W
;
428 newInst
.Src
[1].Register
.SwizzleY
= TGSI_SWIZZLE_W
;
429 newInst
.Src
[1].Register
.SwizzleZ
= TGSI_SWIZZLE_W
;
430 newInst
.Src
[1].Register
.SwizzleW
= TGSI_SWIZZLE_W
;
431 newInst
.Src
[2].Register
.File
= TGSI_FILE_TEMPORARY
;
432 newInst
.Src
[2].Register
.Index
= tmp0
;
433 newInst
.Src
[2].Register
.SwizzleX
= TGSI_SWIZZLE_W
;
434 newInst
.Src
[2].Register
.SwizzleY
= TGSI_SWIZZLE_W
;
435 newInst
.Src
[2].Register
.SwizzleZ
= TGSI_SWIZZLE_W
;
436 newInst
.Src
[2].Register
.SwizzleW
= TGSI_SWIZZLE_W
;
437 ctx
->emit_instruction(ctx
, &newInst
);
441 if (inst
->Instruction
.Opcode
== TGSI_OPCODE_END
) {
442 /* add alpha modulation code at tail of program */
444 /* MOV result.color.xyz, colorTemp; */
445 newInst
= tgsi_default_full_instruction();
446 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MOV
;
447 newInst
.Instruction
.NumDstRegs
= 1;
448 newInst
.Dst
[0].Register
.File
= TGSI_FILE_OUTPUT
;
449 newInst
.Dst
[0].Register
.Index
= aactx
->colorOutput
;
450 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_XYZ
;
451 newInst
.Instruction
.NumSrcRegs
= 1;
452 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
453 newInst
.Src
[0].Register
.Index
= aactx
->colorTemp
;
454 ctx
->emit_instruction(ctx
, &newInst
);
456 /* MUL result.color.w, colorTemp, tmp0.w; */
457 newInst
= tgsi_default_full_instruction();
458 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
459 newInst
.Instruction
.NumDstRegs
= 1;
460 newInst
.Dst
[0].Register
.File
= TGSI_FILE_OUTPUT
;
461 newInst
.Dst
[0].Register
.Index
= aactx
->colorOutput
;
462 newInst
.Dst
[0].Register
.WriteMask
= TGSI_WRITEMASK_W
;
463 newInst
.Instruction
.NumSrcRegs
= 2;
464 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
465 newInst
.Src
[0].Register
.Index
= aactx
->colorTemp
;
466 newInst
.Src
[1].Register
.File
= TGSI_FILE_TEMPORARY
;
467 newInst
.Src
[1].Register
.Index
= aactx
->tmp0
;
468 ctx
->emit_instruction(ctx
, &newInst
);
471 /* Not an END instruction.
472 * Look for writes to result.color and replace with colorTemp reg.
476 for (i
= 0; i
< inst
->Instruction
.NumDstRegs
; i
++) {
477 struct tgsi_full_dst_register
*dst
= &inst
->Dst
[i
];
478 if (dst
->Register
.File
== TGSI_FILE_OUTPUT
&&
479 dst
->Register
.Index
== aactx
->colorOutput
) {
480 dst
->Register
.File
= TGSI_FILE_TEMPORARY
;
481 dst
->Register
.Index
= aactx
->colorTemp
;
486 ctx
->emit_instruction(ctx
, inst
);
491 * Generate the frag shader we'll use for drawing AA points.
492 * This will be the user's shader plus some texture/modulate instructions.
495 generate_aapoint_fs(struct aapoint_stage
*aapoint
)
497 const struct pipe_shader_state
*orig_fs
= &aapoint
->fs
->state
;
498 struct pipe_shader_state aapoint_fs
;
499 struct aa_transform_context transform
;
500 const uint newLen
= tgsi_num_tokens(orig_fs
->tokens
) + NUM_NEW_TOKENS
;
501 struct pipe_context
*pipe
= aapoint
->stage
.draw
->pipe
;
503 aapoint_fs
= *orig_fs
; /* copy to init */
504 aapoint_fs
.tokens
= tgsi_alloc_tokens(newLen
);
505 if (aapoint_fs
.tokens
== NULL
)
508 memset(&transform
, 0, sizeof(transform
));
509 transform
.colorOutput
= -1;
510 transform
.maxInput
= -1;
511 transform
.maxGeneric
= -1;
512 transform
.colorTemp
= -1;
514 transform
.firstInstruction
= TRUE
;
515 transform
.base
.transform_instruction
= aa_transform_inst
;
516 transform
.base
.transform_declaration
= aa_transform_decl
;
518 tgsi_transform_shader(orig_fs
->tokens
,
519 (struct tgsi_token
*) aapoint_fs
.tokens
,
520 newLen
, &transform
.base
);
523 debug_printf("draw_aapoint, orig shader:\n");
524 tgsi_dump(orig_fs
->tokens
, 0);
525 debug_printf("draw_aapoint, new shader:\n");
526 tgsi_dump(aapoint_fs
.tokens
, 0);
529 aapoint
->fs
->aapoint_fs
530 = aapoint
->driver_create_fs_state(pipe
, &aapoint_fs
);
531 if (aapoint
->fs
->aapoint_fs
== NULL
)
534 aapoint
->fs
->generic_attrib
= transform
.maxGeneric
+ 1;
535 FREE((void *)aapoint_fs
.tokens
);
539 FREE((void *)aapoint_fs
.tokens
);
545 * When we're about to draw our first AA point in a batch, this function is
546 * called to tell the driver to bind our modified fragment shader.
549 bind_aapoint_fragment_shader(struct aapoint_stage
*aapoint
)
551 struct draw_context
*draw
= aapoint
->stage
.draw
;
552 struct pipe_context
*pipe
= draw
->pipe
;
554 if (!aapoint
->fs
->aapoint_fs
&&
555 !generate_aapoint_fs(aapoint
))
558 draw
->suspend_flushing
= TRUE
;
559 aapoint
->driver_bind_fs_state(pipe
, aapoint
->fs
->aapoint_fs
);
560 draw
->suspend_flushing
= FALSE
;
567 static INLINE
struct aapoint_stage
*
568 aapoint_stage( struct draw_stage
*stage
)
570 return (struct aapoint_stage
*) stage
;
577 * Draw an AA point by drawing a quad.
580 aapoint_point(struct draw_stage
*stage
, struct prim_header
*header
)
582 const struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
583 struct prim_header tri
;
584 struct vertex_header
*v
[4];
585 const uint tex_slot
= aapoint
->tex_slot
;
586 const uint pos_slot
= aapoint
->pos_slot
;
587 float radius
, *pos
, *tex
;
591 if (aapoint
->psize_slot
>= 0) {
592 radius
= 0.5f
* header
->v
[0]->data
[aapoint
->psize_slot
][0];
595 radius
= aapoint
->radius
;
599 * Note: the texcoords (generic attrib, really) we use are special:
600 * The S and T components simply vary from -1 to +1.
601 * The R component is k, below.
602 * The Q component is 1.0 and will used as a handy constant in the
607 * k is the threshold distance from the point's center at which
608 * we begin alpha attenuation (the coverage value).
609 * Operating within a unit circle, we'll compute the fragment's
610 * distance 'd' from the center point using the texcoords.
614 * compute coverage in [0,1] proportional to d in [k, 1].
616 * coverage = 1.0; // full coverage
619 * Note: the ELSEIF and ELSE clauses are actually implemented with CMP to
620 * avoid using IF/ELSE/ENDIF TGSI opcodes.
625 k
= 1.0f
- 2.0f
* k
+ k
* k
;
627 k
= 1.0f
- 1.0f
/ radius
;
630 /* allocate/dup new verts */
631 for (i
= 0; i
< 4; i
++) {
632 v
[i
] = dup_vert(stage
, header
->v
[0], i
);
636 pos
= v
[0]->data
[pos_slot
];
640 pos
= v
[1]->data
[pos_slot
];
644 pos
= v
[2]->data
[pos_slot
];
648 pos
= v
[3]->data
[pos_slot
];
653 tex
= v
[0]->data
[tex_slot
];
654 ASSIGN_4V(tex
, -1, -1, k
, 1);
656 tex
= v
[1]->data
[tex_slot
];
657 ASSIGN_4V(tex
, 1, -1, k
, 1);
659 tex
= v
[2]->data
[tex_slot
];
660 ASSIGN_4V(tex
, 1, 1, k
, 1);
662 tex
= v
[3]->data
[tex_slot
];
663 ASSIGN_4V(tex
, -1, 1, k
, 1);
665 /* emit 2 tris for the quad strip */
669 stage
->next
->tri( stage
->next
, &tri
);
674 stage
->next
->tri( stage
->next
, &tri
);
679 aapoint_first_point(struct draw_stage
*stage
, struct prim_header
*header
)
681 auto struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
682 struct draw_context
*draw
= stage
->draw
;
683 struct pipe_context
*pipe
= draw
->pipe
;
684 const struct pipe_rasterizer_state
*rast
= draw
->rasterizer
;
687 assert(draw
->rasterizer
->point_smooth
);
689 if (draw
->rasterizer
->point_size
<= 2.0)
690 aapoint
->radius
= 1.0;
692 aapoint
->radius
= 0.5f
* draw
->rasterizer
->point_size
;
695 * Bind (generate) our fragprog.
697 bind_aapoint_fragment_shader(aapoint
);
699 draw_aapoint_prepare_outputs(draw
, draw
->pipeline
.aapoint
);
701 draw
->suspend_flushing
= TRUE
;
703 /* Disable triangle culling, stippling, unfilled mode etc. */
704 r
= draw_get_rasterizer_no_cull(draw
, rast
->scissor
, rast
->flatshade
);
705 pipe
->bind_rasterizer_state(pipe
, r
);
707 draw
->suspend_flushing
= FALSE
;
709 /* now really draw first point */
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
= draw
->pipe
;
722 stage
->point
= aapoint_first_point
;
723 stage
->next
->flush( stage
->next
, flags
);
725 /* restore original frag shader */
726 draw
->suspend_flushing
= TRUE
;
727 aapoint
->driver_bind_fs_state(pipe
, aapoint
->fs
? aapoint
->fs
->driver_fs
: NULL
);
729 /* restore original rasterizer state */
730 if (draw
->rast_handle
) {
731 pipe
->bind_rasterizer_state(pipe
, draw
->rast_handle
);
734 draw
->suspend_flushing
= FALSE
;
736 draw_remove_extra_vertex_attribs(draw
);
741 aapoint_reset_stipple_counter(struct draw_stage
*stage
)
743 stage
->next
->reset_stipple_counter( stage
->next
);
748 aapoint_destroy(struct draw_stage
*stage
)
750 struct aapoint_stage
* aapoint
= aapoint_stage(stage
);
751 struct pipe_context
*pipe
= stage
->draw
->pipe
;
753 draw_free_temp_verts( stage
);
755 /* restore the old entry points */
756 pipe
->create_fs_state
= aapoint
->driver_create_fs_state
;
757 pipe
->bind_fs_state
= aapoint
->driver_bind_fs_state
;
758 pipe
->delete_fs_state
= aapoint
->driver_delete_fs_state
;
764 draw_aapoint_prepare_outputs(struct draw_context
*draw
,
765 struct draw_stage
*stage
)
767 struct aapoint_stage
*aapoint
= aapoint_stage(stage
);
768 const struct pipe_rasterizer_state
*rast
= draw
->rasterizer
;
770 /* update vertex attrib info */
771 aapoint
->pos_slot
= draw_current_shader_position_output(draw
);
773 if (!rast
->point_smooth
)
776 /* allocate the extra post-transformed vertex attribute */
777 aapoint
->tex_slot
= draw_alloc_extra_vertex_attrib(draw
,
778 TGSI_SEMANTIC_GENERIC
,
779 aapoint
->fs
->generic_attrib
);
780 assert(aapoint
->tex_slot
> 0); /* output[0] is vertex pos */
782 /* find psize slot in post-transform vertex */
783 aapoint
->psize_slot
= -1;
784 if (draw
->rasterizer
->point_size_per_vertex
) {
785 const struct tgsi_shader_info
*info
= draw_get_shader_info(draw
);
787 /* find PSIZ vertex output */
788 for (i
= 0; i
< info
->num_outputs
; i
++) {
789 if (info
->output_semantic_name
[i
] == TGSI_SEMANTIC_PSIZE
) {
790 aapoint
->psize_slot
= i
;
797 static struct aapoint_stage
*
798 draw_aapoint_stage(struct draw_context
*draw
)
800 struct aapoint_stage
*aapoint
= CALLOC_STRUCT(aapoint_stage
);
804 aapoint
->stage
.draw
= draw
;
805 aapoint
->stage
.name
= "aapoint";
806 aapoint
->stage
.next
= NULL
;
807 aapoint
->stage
.point
= aapoint_first_point
;
808 aapoint
->stage
.line
= draw_pipe_passthrough_line
;
809 aapoint
->stage
.tri
= draw_pipe_passthrough_tri
;
810 aapoint
->stage
.flush
= aapoint_flush
;
811 aapoint
->stage
.reset_stipple_counter
= aapoint_reset_stipple_counter
;
812 aapoint
->stage
.destroy
= aapoint_destroy
;
814 if (!draw_alloc_temp_verts( &aapoint
->stage
, 4 ))
821 aapoint
->stage
.destroy(&aapoint
->stage
);
828 static struct aapoint_stage
*
829 aapoint_stage_from_pipe(struct pipe_context
*pipe
)
831 struct draw_context
*draw
= (struct draw_context
*) pipe
->draw
;
832 return aapoint_stage(draw
->pipeline
.aapoint
);
837 * This function overrides the driver's create_fs_state() function and
838 * will typically be called by the state tracker.
841 aapoint_create_fs_state(struct pipe_context
*pipe
,
842 const struct pipe_shader_state
*fs
)
844 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
845 struct aapoint_fragment_shader
*aafs
= CALLOC_STRUCT(aapoint_fragment_shader
);
849 aafs
->state
.tokens
= tgsi_dup_tokens(fs
->tokens
);
852 aafs
->driver_fs
= aapoint
->driver_create_fs_state(pipe
, fs
);
859 aapoint_bind_fs_state(struct pipe_context
*pipe
, void *fs
)
861 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
862 struct aapoint_fragment_shader
*aafs
= (struct aapoint_fragment_shader
*) fs
;
866 aapoint
->driver_bind_fs_state(pipe
,
867 (aafs
? aafs
->driver_fs
: NULL
));
872 aapoint_delete_fs_state(struct pipe_context
*pipe
, void *fs
)
874 struct aapoint_stage
*aapoint
= aapoint_stage_from_pipe(pipe
);
875 struct aapoint_fragment_shader
*aafs
= (struct aapoint_fragment_shader
*) fs
;
878 aapoint
->driver_delete_fs_state(pipe
, aafs
->driver_fs
);
880 if (aafs
->aapoint_fs
)
881 aapoint
->driver_delete_fs_state(pipe
, aafs
->aapoint_fs
);
883 FREE((void*)aafs
->state
.tokens
);
890 * Called by drivers that want to install this AA point prim stage
891 * into the draw module's pipeline. This will not be used if the
892 * hardware has native support for AA points.
895 draw_install_aapoint_stage(struct draw_context
*draw
,
896 struct pipe_context
*pipe
)
898 struct aapoint_stage
*aapoint
;
900 pipe
->draw
= (void *) draw
;
903 * Create / install AA point drawing / prim stage
905 aapoint
= draw_aapoint_stage( draw
);
909 /* save original driver functions */
910 aapoint
->driver_create_fs_state
= pipe
->create_fs_state
;
911 aapoint
->driver_bind_fs_state
= pipe
->bind_fs_state
;
912 aapoint
->driver_delete_fs_state
= pipe
->delete_fs_state
;
914 /* override the driver's functions */
915 pipe
->create_fs_state
= aapoint_create_fs_state
;
916 pipe
->bind_fs_state
= aapoint_bind_fs_state
;
917 pipe
->delete_fs_state
= aapoint_delete_fs_state
;
919 draw
->pipeline
.aapoint
= &aapoint
->stage
;