1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2010 VMware, Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
30 * Polygon stipple helper module. Drivers/GPUs which don't support polygon
31 * stipple natively can use this module to simulate it.
33 * Basically, modify fragment shader to sample the 32x32 stipple pattern
34 * texture and do a fragment kill for the 'off' bits.
36 * This was originally a 'draw' module stage, but since we don't need
37 * vertex window coords or anything, it can be a stand-alone utility module.
43 #include "pipe/p_context.h"
44 #include "pipe/p_defines.h"
45 #include "pipe/p_shader_tokens.h"
46 #include "util/u_inlines.h"
48 #include "util/u_format.h"
49 #include "util/u_memory.h"
50 #include "util/u_pstipple.h"
51 #include "util/u_sampler.h"
53 #include "tgsi/tgsi_transform.h"
54 #include "tgsi/tgsi_dump.h"
55 #include "tgsi/tgsi_scan.h"
57 /** Approx number of new tokens for instructions in pstip_transform_inst() */
58 #define NUM_NEW_TOKENS 50
62 util_pstipple_update_stipple_texture(struct pipe_context
*pipe
,
63 struct pipe_resource
*tex
,
64 const uint32_t pattern
[32])
66 static const uint bit31
= 1 << 31;
67 struct pipe_transfer
*transfer
;
71 /* map texture memory */
72 transfer
= pipe_get_transfer(pipe
, tex
, 0, 0,
73 PIPE_TRANSFER_WRITE
, 0, 0, 32, 32);
74 data
= pipe
->transfer_map(pipe
, transfer
);
78 * Note: 0 means keep the fragment, 255 means kill it.
79 * We'll negate the texel value and use KILP which kills if value
82 for (i
= 0; i
< 32; i
++) {
83 for (j
= 0; j
< 32; j
++) {
84 if (pattern
[i
] & (bit31
>> j
)) {
86 data
[i
* transfer
->stride
+ j
] = 0;
90 data
[i
* transfer
->stride
+ j
] = 255;
96 pipe
->transfer_unmap(pipe
, transfer
);
97 pipe
->transfer_destroy(pipe
, transfer
);
102 * Create a 32x32 alpha8 texture that encodes the given stipple pattern.
104 struct pipe_resource
*
105 util_pstipple_create_stipple_texture(struct pipe_context
*pipe
,
106 const uint32_t pattern
[32])
108 struct pipe_screen
*screen
= pipe
->screen
;
109 struct pipe_resource templat
, *tex
;
111 memset(&templat
, 0, sizeof(templat
));
112 templat
.target
= PIPE_TEXTURE_2D
;
113 templat
.format
= PIPE_FORMAT_A8_UNORM
;
114 templat
.last_level
= 0;
116 templat
.height0
= 32;
118 templat
.array_size
= 1;
119 templat
.bind
= PIPE_BIND_SAMPLER_VIEW
;
121 tex
= screen
->resource_create(screen
, &templat
);
124 util_pstipple_update_stipple_texture(pipe
, tex
, pattern
);
131 * Create sampler view to sample the stipple texture.
133 struct pipe_sampler_view
*
134 util_pstipple_create_sampler_view(struct pipe_context
*pipe
,
135 struct pipe_resource
*tex
)
137 struct pipe_sampler_view templat
, *sv
;
139 u_sampler_view_default_template(&templat
, tex
, tex
->format
);
140 sv
= pipe
->create_sampler_view(pipe
, tex
, &templat
);
147 * Create the sampler CSO that'll be used for stippling.
150 util_pstipple_create_sampler(struct pipe_context
*pipe
)
152 struct pipe_sampler_state templat
;
155 memset(&templat
, 0, sizeof(templat
));
156 templat
.wrap_s
= PIPE_TEX_WRAP_REPEAT
;
157 templat
.wrap_t
= PIPE_TEX_WRAP_REPEAT
;
158 templat
.wrap_r
= PIPE_TEX_WRAP_REPEAT
;
159 templat
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
160 templat
.min_img_filter
= PIPE_TEX_FILTER_NEAREST
;
161 templat
.mag_img_filter
= PIPE_TEX_FILTER_NEAREST
;
162 templat
.normalized_coords
= 1;
163 templat
.min_lod
= 0.0f
;
164 templat
.max_lod
= 0.0f
;
166 s
= pipe
->create_sampler_state(pipe
, &templat
);
173 * Subclass of tgsi_transform_context, used for transforming the
174 * user's fragment shader to add the extra texture sample and fragment kill
177 struct pstip_transform_context
{
178 struct tgsi_transform_context base
;
179 struct tgsi_shader_info info
;
180 uint tempsUsed
; /**< bitmask */
183 uint samplersUsed
; /**< bitfield of samplers used */
184 int freeSampler
; /** an available sampler for the pstipple */
185 int texTemp
; /**< temp registers */
187 boolean firstInstruction
;
193 * TGSI declaration transform callback.
194 * Track samplers used, temps used, inputs used.
197 pstip_transform_decl(struct tgsi_transform_context
*ctx
,
198 struct tgsi_full_declaration
*decl
)
200 struct pstip_transform_context
*pctx
=
201 (struct pstip_transform_context
*) ctx
;
203 /* XXX we can use tgsi_shader_info instead of some of this */
205 if (decl
->Declaration
.File
== TGSI_FILE_SAMPLER
) {
207 for (i
= decl
->Range
.First
; i
<= decl
->Range
.Last
; i
++) {
208 pctx
->samplersUsed
|= 1 << i
;
211 else if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
212 pctx
->maxInput
= MAX2(pctx
->maxInput
, (int) decl
->Range
.Last
);
213 if (decl
->Semantic
.Name
== TGSI_SEMANTIC_POSITION
)
214 pctx
->wincoordInput
= (int) decl
->Range
.First
;
216 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
218 for (i
= decl
->Range
.First
; i
<= decl
->Range
.Last
; i
++) {
219 pctx
->tempsUsed
|= (1 << i
);
223 ctx
->emit_declaration(ctx
, decl
);
228 pstip_transform_immed(struct tgsi_transform_context
*ctx
,
229 struct tgsi_full_immediate
*immed
)
231 struct pstip_transform_context
*pctx
=
232 (struct pstip_transform_context
*) ctx
;
238 * Find the lowest zero bit in the given word, or -1 if bitfield is all ones.
241 free_bit(uint bitfield
)
243 return ffs(~bitfield
) - 1;
248 * TGSI instruction transform callback.
249 * Before the first instruction, insert our new code to sample the
250 * stipple texture (using the fragment coord register) then kill the
251 * fragment if the stipple texture bit is off.
254 * declare new registers
255 * MUL texTemp, INPUT[wincoord], 1/32;
256 * TEX texTemp, texTemp, sampler;
257 * KIL -texTemp; # if -texTemp < 0, KILL fragment
258 * [...original code...]
261 pstip_transform_inst(struct tgsi_transform_context
*ctx
,
262 struct tgsi_full_instruction
*inst
)
264 struct pstip_transform_context
*pctx
=
265 (struct pstip_transform_context
*) ctx
;
267 if (pctx
->firstInstruction
) {
268 /* emit our new declarations before the first instruction */
270 struct tgsi_full_declaration decl
;
271 struct tgsi_full_instruction newInst
;
275 /* find free texture sampler */
276 pctx
->freeSampler
= free_bit(pctx
->samplersUsed
);
277 if (pctx
->freeSampler
>= PIPE_MAX_SAMPLERS
)
278 pctx
->freeSampler
= PIPE_MAX_SAMPLERS
- 1;
280 if (pctx
->wincoordInput
< 0)
281 wincoordInput
= pctx
->maxInput
+ 1;
283 wincoordInput
= pctx
->wincoordInput
;
285 /* find one free temp register */
286 for (i
= 0; i
< 32; i
++) {
287 if ((pctx
->tempsUsed
& (1 << i
)) == 0) {
288 /* found a free temp */
289 if (pctx
->texTemp
< 0)
295 assert(pctx
->texTemp
>= 0);
297 if (pctx
->wincoordInput
< 0) {
298 /* declare new position input reg */
299 decl
= tgsi_default_full_declaration();
300 decl
.Declaration
.File
= TGSI_FILE_INPUT
;
301 decl
.Declaration
.Interpolate
= TGSI_INTERPOLATE_LINEAR
;
302 decl
.Declaration
.Semantic
= 1;
303 decl
.Semantic
.Name
= TGSI_SEMANTIC_POSITION
;
304 decl
.Semantic
.Index
= 0;
306 decl
.Range
.Last
= wincoordInput
;
307 ctx
->emit_declaration(ctx
, &decl
);
310 /* declare new sampler */
311 decl
= tgsi_default_full_declaration();
312 decl
.Declaration
.File
= TGSI_FILE_SAMPLER
;
314 decl
.Range
.Last
= pctx
->freeSampler
;
315 ctx
->emit_declaration(ctx
, &decl
);
317 /* declare new temp regs */
318 decl
= tgsi_default_full_declaration();
319 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
321 decl
.Range
.Last
= pctx
->texTemp
;
322 ctx
->emit_declaration(ctx
, &decl
);
324 /* emit immediate = {1/32, 1/32, 1, 1}
325 * The index/position of this immediate will be pctx->numImmed
328 static const float value
[4] = { 1.0/32, 1.0/32, 1.0, 1.0 };
329 struct tgsi_full_immediate immed
;
331 immed
= tgsi_default_full_immediate();
332 immed
.Immediate
.NrTokens
= 1 + size
; /* one for the token itself */
333 immed
.u
[0].Float
= value
[0];
334 immed
.u
[1].Float
= value
[1];
335 immed
.u
[2].Float
= value
[2];
336 immed
.u
[3].Float
= value
[3];
337 ctx
->emit_immediate(ctx
, &immed
);
340 pctx
->firstInstruction
= FALSE
;
344 * Insert new MUL/TEX/KILP instructions at start of program
345 * Take gl_FragCoord, divide by 32 (stipple size), sample the
346 * texture and kill fragment if needed.
348 * We'd like to use non-normalized texcoords to index into a RECT
349 * texture, but we can only use REPEAT wrap mode with normalized
353 /* XXX invert wincoord if origin isn't lower-left... */
355 /* MUL texTemp, INPUT[wincoord], 1/32; */
356 newInst
= tgsi_default_full_instruction();
357 newInst
.Instruction
.Opcode
= TGSI_OPCODE_MUL
;
358 newInst
.Instruction
.NumDstRegs
= 1;
359 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
360 newInst
.Dst
[0].Register
.Index
= pctx
->texTemp
;
361 newInst
.Instruction
.NumSrcRegs
= 2;
362 newInst
.Src
[0].Register
.File
= TGSI_FILE_INPUT
;
363 newInst
.Src
[0].Register
.Index
= wincoordInput
;
364 newInst
.Src
[1].Register
.File
= TGSI_FILE_IMMEDIATE
;
365 newInst
.Src
[1].Register
.Index
= pctx
->numImmed
;
366 ctx
->emit_instruction(ctx
, &newInst
);
368 /* TEX texTemp, texTemp, sampler; */
369 newInst
= tgsi_default_full_instruction();
370 newInst
.Instruction
.Opcode
= TGSI_OPCODE_TEX
;
371 newInst
.Instruction
.NumDstRegs
= 1;
372 newInst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
373 newInst
.Dst
[0].Register
.Index
= pctx
->texTemp
;
374 newInst
.Instruction
.NumSrcRegs
= 2;
375 newInst
.Instruction
.Texture
= TRUE
;
376 newInst
.Texture
.Texture
= TGSI_TEXTURE_2D
;
377 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
378 newInst
.Src
[0].Register
.Index
= pctx
->texTemp
;
379 newInst
.Src
[1].Register
.File
= TGSI_FILE_SAMPLER
;
380 newInst
.Src
[1].Register
.Index
= pctx
->freeSampler
;
381 ctx
->emit_instruction(ctx
, &newInst
);
383 /* KIL -texTemp; # if -texTemp < 0, KILL fragment */
384 newInst
= tgsi_default_full_instruction();
385 newInst
.Instruction
.Opcode
= TGSI_OPCODE_KIL
;
386 newInst
.Instruction
.NumDstRegs
= 0;
387 newInst
.Instruction
.NumSrcRegs
= 1;
388 newInst
.Src
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
389 newInst
.Src
[0].Register
.Index
= pctx
->texTemp
;
390 newInst
.Src
[0].Register
.Negate
= 1;
391 ctx
->emit_instruction(ctx
, &newInst
);
394 /* emit this instruction */
395 ctx
->emit_instruction(ctx
, inst
);
400 * Given a fragment shader, return a new fragment shader which
401 * samples a stipple texture and executes KILL.
403 struct pipe_shader_state
*
404 util_pstipple_create_fragment_shader(struct pipe_context
*pipe
,
405 struct pipe_shader_state
*fs
,
406 unsigned *samplerUnitOut
)
408 struct pipe_shader_state
*new_fs
;
409 struct pstip_transform_context transform
;
410 const uint newLen
= tgsi_num_tokens(fs
->tokens
) + NUM_NEW_TOKENS
;
413 new_fs
= MALLOC(sizeof(*new_fs
));
417 new_fs
->tokens
= tgsi_alloc_tokens(newLen
);
418 if (!new_fs
->tokens
) {
423 /* Setup shader transformation info/context.
425 memset(&transform
, 0, sizeof(transform
));
426 transform
.wincoordInput
= -1;
427 transform
.maxInput
= -1;
428 transform
.texTemp
= -1;
429 transform
.firstInstruction
= TRUE
;
430 transform
.coordOrigin
= TGSI_FS_COORD_ORIGIN_UPPER_LEFT
;
431 transform
.base
.transform_instruction
= pstip_transform_inst
;
432 transform
.base
.transform_declaration
= pstip_transform_decl
;
433 transform
.base
.transform_immediate
= pstip_transform_immed
;
435 tgsi_scan_shader(fs
->tokens
, &transform
.info
);
437 /* find fragment coordinate origin property */
438 for (i
= 0; i
< transform
.info
.num_properties
; i
++) {
439 if (transform
.info
.properties
[i
].name
== TGSI_PROPERTY_FS_COORD_ORIGIN
)
440 transform
.coordOrigin
= transform
.info
.properties
[i
].data
[0];
443 tgsi_transform_shader(fs
->tokens
,
444 (struct tgsi_token
*) new_fs
->tokens
,
445 newLen
, &transform
.base
);
448 tgsi_dump(fs
->tokens
, 0);
449 tgsi_dump(new_fs
->tokens
, 0);
452 assert(transform
.freeSampler
< PIPE_MAX_SAMPLERS
);
453 *samplerUnitOut
= transform
.freeSampler
;