1 /**************************************************************************
3 * Copyright 2008 VMware, Inc.
5 * Copyright 2009 Marek Olšák <maraeo@gmail.com>
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 VMWARE 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 **************************************************************************/
31 * Simple vertex/fragment shader generators.
38 #include "pipe/p_context.h"
39 #include "pipe/p_shader_tokens.h"
40 #include "pipe/p_state.h"
41 #include "util/u_simple_shaders.h"
42 #include "util/u_debug.h"
43 #include "util/u_memory.h"
44 #include "tgsi/tgsi_dump.h"
45 #include "tgsi/tgsi_strings.h"
46 #include "tgsi/tgsi_ureg.h"
47 #include "tgsi/tgsi_text.h"
48 #include <stdio.h> /* include last */
53 * Make simple vertex pass-through shader.
54 * \param num_attribs number of attributes to pass through
55 * \param semantic_names array of semantic names for each attribute
56 * \param semantic_indexes array of semantic indexes for each attribute
59 util_make_vertex_passthrough_shader(struct pipe_context
*pipe
,
61 const uint
*semantic_names
,
62 const uint
*semantic_indexes
)
64 return util_make_vertex_passthrough_shader_with_so(pipe
, num_attribs
,
66 semantic_indexes
, NULL
);
70 util_make_vertex_passthrough_shader_with_so(struct pipe_context
*pipe
,
72 const uint
*semantic_names
,
73 const uint
*semantic_indexes
,
74 const struct pipe_stream_output_info
*so
)
76 struct ureg_program
*ureg
;
79 ureg
= ureg_create( TGSI_PROCESSOR_VERTEX
);
83 for (i
= 0; i
< num_attribs
; i
++) {
87 src
= ureg_DECL_vs_input( ureg
, i
);
89 dst
= ureg_DECL_output( ureg
,
93 ureg_MOV( ureg
, dst
, src
);
98 return ureg_create_shader_with_so_and_destroy( ureg
, pipe
, so
);
102 void *util_make_layered_clear_vertex_shader(struct pipe_context
*pipe
)
104 static const char text
[] =
108 "DCL SV[0], INSTANCEID\n"
109 "DCL OUT[0], POSITION\n"
110 "DCL OUT[1], GENERIC[0]\n"
111 "DCL OUT[2], LAYER\n"
113 "MOV OUT[0], IN[0]\n"
114 "MOV OUT[1], IN[1]\n"
115 "MOV OUT[2], SV[0]\n"
117 struct tgsi_token tokens
[1000];
118 struct pipe_shader_state state
= {tokens
};
120 if (!tgsi_text_translate(text
, tokens
, Elements(tokens
))) {
124 return pipe
->create_vs_state(pipe
, &state
);
129 * Make simple fragment texture shader:
130 * IMM {0,0,0,1} // (if writemask != 0xf)
131 * MOV OUT[0], IMM[0] // (if writemask != 0xf)
132 * TEX OUT[0].writemask, IN[0], SAMP[0], 2D;
135 * \param tex_target one of PIPE_TEXTURE_x
136 * \parma interp_mode either TGSI_INTERPOLATE_LINEAR or PERSPECTIVE
137 * \param writemask mask of TGSI_WRITEMASK_x
140 util_make_fragment_tex_shader_writemask(struct pipe_context
*pipe
,
142 unsigned interp_mode
,
145 struct ureg_program
*ureg
;
146 struct ureg_src sampler
;
150 assert(interp_mode
== TGSI_INTERPOLATE_LINEAR
||
151 interp_mode
== TGSI_INTERPOLATE_PERSPECTIVE
);
153 ureg
= ureg_create( TGSI_PROCESSOR_FRAGMENT
);
157 sampler
= ureg_DECL_sampler( ureg
, 0 );
159 tex
= ureg_DECL_fs_input( ureg
,
160 TGSI_SEMANTIC_GENERIC
, 0,
163 out
= ureg_DECL_output( ureg
,
167 if (writemask
!= TGSI_WRITEMASK_XYZW
) {
168 struct ureg_src imm
= ureg_imm4f( ureg
, 0, 0, 0, 1 );
170 ureg_MOV( ureg
, out
, imm
);
174 ureg_writemask(out
, writemask
),
175 tex_target
, tex
, sampler
);
178 return ureg_create_shader_and_destroy( ureg
, pipe
);
183 * Make a simple fragment shader that sets the output color to a color
184 * taken from a texture.
185 * \param tex_target one of PIPE_TEXTURE_x
188 util_make_fragment_tex_shader(struct pipe_context
*pipe
, unsigned tex_target
,
189 unsigned interp_mode
)
191 return util_make_fragment_tex_shader_writemask( pipe
,
194 TGSI_WRITEMASK_XYZW
);
199 * Make a simple fragment texture shader which reads an X component from
200 * a texture and writes it as depth.
203 util_make_fragment_tex_shader_writedepth(struct pipe_context
*pipe
,
205 unsigned interp_mode
)
207 struct ureg_program
*ureg
;
208 struct ureg_src sampler
;
210 struct ureg_dst out
, depth
;
213 ureg
= ureg_create( TGSI_PROCESSOR_FRAGMENT
);
217 sampler
= ureg_DECL_sampler( ureg
, 0 );
219 tex
= ureg_DECL_fs_input( ureg
,
220 TGSI_SEMANTIC_GENERIC
, 0,
223 out
= ureg_DECL_output( ureg
,
227 depth
= ureg_DECL_output( ureg
,
228 TGSI_SEMANTIC_POSITION
,
231 imm
= ureg_imm4f( ureg
, 0, 0, 0, 1 );
233 ureg_MOV( ureg
, out
, imm
);
236 ureg_writemask(depth
, TGSI_WRITEMASK_Z
),
237 tex_target
, tex
, sampler
);
240 return ureg_create_shader_and_destroy( ureg
, pipe
);
245 * Make a simple fragment texture shader which reads the texture unit 0 and 1
246 * and writes it as depth and stencil, respectively.
249 util_make_fragment_tex_shader_writedepthstencil(struct pipe_context
*pipe
,
251 unsigned interp_mode
)
253 struct ureg_program
*ureg
;
254 struct ureg_src depth_sampler
, stencil_sampler
;
256 struct ureg_dst out
, depth
, stencil
;
259 ureg
= ureg_create( TGSI_PROCESSOR_FRAGMENT
);
263 depth_sampler
= ureg_DECL_sampler( ureg
, 0 );
264 stencil_sampler
= ureg_DECL_sampler( ureg
, 1 );
266 tex
= ureg_DECL_fs_input( ureg
,
267 TGSI_SEMANTIC_GENERIC
, 0,
270 out
= ureg_DECL_output( ureg
,
274 depth
= ureg_DECL_output( ureg
,
275 TGSI_SEMANTIC_POSITION
,
278 stencil
= ureg_DECL_output( ureg
,
279 TGSI_SEMANTIC_STENCIL
,
282 imm
= ureg_imm4f( ureg
, 0, 0, 0, 1 );
284 ureg_MOV( ureg
, out
, imm
);
287 ureg_writemask(depth
, TGSI_WRITEMASK_Z
),
288 tex_target
, tex
, depth_sampler
);
290 ureg_writemask(stencil
, TGSI_WRITEMASK_Y
),
291 tex_target
, tex
, stencil_sampler
);
294 return ureg_create_shader_and_destroy( ureg
, pipe
);
299 * Make a simple fragment texture shader which reads a texture and writes it
303 util_make_fragment_tex_shader_writestencil(struct pipe_context
*pipe
,
305 unsigned interp_mode
)
307 struct ureg_program
*ureg
;
308 struct ureg_src stencil_sampler
;
310 struct ureg_dst out
, stencil
;
313 ureg
= ureg_create( TGSI_PROCESSOR_FRAGMENT
);
317 stencil_sampler
= ureg_DECL_sampler( ureg
, 0 );
319 tex
= ureg_DECL_fs_input( ureg
,
320 TGSI_SEMANTIC_GENERIC
, 0,
323 out
= ureg_DECL_output( ureg
,
327 stencil
= ureg_DECL_output( ureg
,
328 TGSI_SEMANTIC_STENCIL
,
331 imm
= ureg_imm4f( ureg
, 0, 0, 0, 1 );
333 ureg_MOV( ureg
, out
, imm
);
336 ureg_writemask(stencil
, TGSI_WRITEMASK_Y
),
337 tex_target
, tex
, stencil_sampler
);
340 return ureg_create_shader_and_destroy( ureg
, pipe
);
345 * Make simple fragment color pass-through shader that replicates OUT[0]
346 * to all bound colorbuffers.
349 util_make_fragment_passthrough_shader(struct pipe_context
*pipe
,
351 int input_interpolate
,
352 boolean write_all_cbufs
)
354 static const char shader_templ
[] =
357 "DCL IN[0], %s[0], %s\n"
358 "DCL OUT[0], COLOR[0]\n"
360 "MOV OUT[0], IN[0]\n"
363 char text
[sizeof(shader_templ
)+100];
364 struct tgsi_token tokens
[1000];
365 struct pipe_shader_state state
= {tokens
};
367 sprintf(text
, shader_templ
,
368 write_all_cbufs
? "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n" : "",
369 tgsi_semantic_names
[input_semantic
],
370 tgsi_interpolate_names
[input_interpolate
]);
372 if (!tgsi_text_translate(text
, tokens
, Elements(tokens
))) {
377 tgsi_dump(state
.tokens
, 0);
380 return pipe
->create_fs_state(pipe
, &state
);
385 util_make_empty_fragment_shader(struct pipe_context
*pipe
)
387 struct ureg_program
*ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
392 return ureg_create_shader_and_destroy(ureg
, pipe
);
397 * Make a fragment shader that copies the input color to N output colors.
400 util_make_fragment_cloneinput_shader(struct pipe_context
*pipe
, int num_cbufs
,
402 int input_interpolate
)
404 struct ureg_program
*ureg
;
406 struct ureg_dst dst
[PIPE_MAX_COLOR_BUFS
];
409 assert(num_cbufs
<= PIPE_MAX_COLOR_BUFS
);
411 ureg
= ureg_create( TGSI_PROCESSOR_FRAGMENT
);
415 src
= ureg_DECL_fs_input( ureg
, input_semantic
, 0,
418 for (i
= 0; i
< num_cbufs
; i
++)
419 dst
[i
] = ureg_DECL_output( ureg
, TGSI_SEMANTIC_COLOR
, i
);
421 for (i
= 0; i
< num_cbufs
; i
++)
422 ureg_MOV( ureg
, dst
[i
], src
);
426 return ureg_create_shader_and_destroy( ureg
, pipe
);
431 util_make_fs_blit_msaa_gen(struct pipe_context
*pipe
,
433 const char *output_semantic
,
434 const char *output_mask
)
436 static const char shader_templ
[] =
438 "DCL IN[0], GENERIC[0], LINEAR\n"
443 "F2U TEMP[0], IN[0]\n"
444 "TXF OUT[0]%s, TEMP[0], SAMP[0], %s\n"
447 const char *type
= tgsi_texture_names
[tgsi_tex
];
448 char text
[sizeof(shader_templ
)+100];
449 struct tgsi_token tokens
[1000];
450 struct pipe_shader_state state
= {tokens
};
452 assert(tgsi_tex
== TGSI_TEXTURE_2D_MSAA
||
453 tgsi_tex
== TGSI_TEXTURE_2D_ARRAY_MSAA
);
455 sprintf(text
, shader_templ
, output_semantic
, output_mask
, type
);
457 if (!tgsi_text_translate(text
, tokens
, Elements(tokens
))) {
463 tgsi_dump(state
.tokens
, 0);
466 return pipe
->create_fs_state(pipe
, &state
);
471 * Make a fragment shader that sets the output color to a color
472 * fetched from a multisample texture.
473 * \param tex_target one of PIPE_TEXTURE_x
476 util_make_fs_blit_msaa_color(struct pipe_context
*pipe
,
479 return util_make_fs_blit_msaa_gen(pipe
, tgsi_tex
,
485 * Make a fragment shader that sets the output depth to a depth value
486 * fetched from a multisample texture.
487 * \param tex_target one of PIPE_TEXTURE_x
490 util_make_fs_blit_msaa_depth(struct pipe_context
*pipe
,
493 return util_make_fs_blit_msaa_gen(pipe
, tgsi_tex
,
499 * Make a fragment shader that sets the output stencil to a stencil value
500 * fetched from a multisample texture.
501 * \param tex_target one of PIPE_TEXTURE_x
504 util_make_fs_blit_msaa_stencil(struct pipe_context
*pipe
,
507 return util_make_fs_blit_msaa_gen(pipe
, tgsi_tex
,
513 * Make a fragment shader that sets the output depth and stencil to depth
514 * and stencil values fetched from two multisample textures / samplers.
515 * The sizes of both textures should match (it should be one depth-stencil
517 * \param tex_target one of PIPE_TEXTURE_x
520 util_make_fs_blit_msaa_depthstencil(struct pipe_context
*pipe
,
523 static const char shader_templ
[] =
525 "DCL IN[0], GENERIC[0], LINEAR\n"
527 "DCL OUT[0], POSITION\n"
528 "DCL OUT[1], STENCIL\n"
531 "F2U TEMP[0], IN[0]\n"
532 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n"
533 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n"
536 const char *type
= tgsi_texture_names
[tgsi_tex
];
537 char text
[sizeof(shader_templ
)+100];
538 struct tgsi_token tokens
[1000];
539 struct pipe_shader_state state
= {tokens
};
541 assert(tgsi_tex
== TGSI_TEXTURE_2D_MSAA
||
542 tgsi_tex
== TGSI_TEXTURE_2D_ARRAY_MSAA
);
544 sprintf(text
, shader_templ
, type
, type
);
546 if (!tgsi_text_translate(text
, tokens
, Elements(tokens
))) {
551 tgsi_dump(state
.tokens
, 0);
554 return pipe
->create_fs_state(pipe
, &state
);
559 util_make_fs_msaa_resolve(struct pipe_context
*pipe
,
560 unsigned tgsi_tex
, unsigned nr_samples
,
561 boolean is_uint
, boolean is_sint
)
563 struct ureg_program
*ureg
;
564 struct ureg_src sampler
, coord
;
565 struct ureg_dst out
, tmp_sum
, tmp_coord
, tmp
;
568 ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
573 sampler
= ureg_DECL_sampler(ureg
, 0);
574 coord
= ureg_DECL_fs_input(ureg
, TGSI_SEMANTIC_GENERIC
, 0,
575 TGSI_INTERPOLATE_LINEAR
);
576 out
= ureg_DECL_output(ureg
, TGSI_SEMANTIC_COLOR
, 0);
577 tmp_sum
= ureg_DECL_temporary(ureg
);
578 tmp_coord
= ureg_DECL_temporary(ureg
);
579 tmp
= ureg_DECL_temporary(ureg
);
582 ureg_MOV(ureg
, tmp_sum
, ureg_imm1f(ureg
, 0));
583 ureg_F2U(ureg
, tmp_coord
, coord
);
585 for (i
= 0; i
< nr_samples
; i
++) {
586 /* Read one sample. */
587 ureg_MOV(ureg
, ureg_writemask(tmp_coord
, TGSI_WRITEMASK_W
),
588 ureg_imm1u(ureg
, i
));
589 ureg_TXF(ureg
, tmp
, tgsi_tex
, ureg_src(tmp_coord
), sampler
);
592 ureg_U2F(ureg
, tmp
, ureg_src(tmp
));
594 ureg_I2F(ureg
, tmp
, ureg_src(tmp
));
596 /* Add it to the sum.*/
597 ureg_ADD(ureg
, tmp_sum
, ureg_src(tmp_sum
), ureg_src(tmp
));
600 /* Calculate the average and return. */
601 ureg_MUL(ureg
, tmp_sum
, ureg_src(tmp_sum
),
602 ureg_imm1f(ureg
, 1.0 / nr_samples
));
605 ureg_F2U(ureg
, out
, ureg_src(tmp_sum
));
607 ureg_F2I(ureg
, out
, ureg_src(tmp_sum
));
609 ureg_MOV(ureg
, out
, ureg_src(tmp_sum
));
613 return ureg_create_shader_and_destroy(ureg
, pipe
);
618 util_make_fs_msaa_resolve_bilinear(struct pipe_context
*pipe
,
619 unsigned tgsi_tex
, unsigned nr_samples
,
620 boolean is_uint
, boolean is_sint
)
622 struct ureg_program
*ureg
;
623 struct ureg_src sampler
, coord
;
624 struct ureg_dst out
, tmp
, top
, bottom
;
625 struct ureg_dst tmp_coord
[4], tmp_sum
[4];
628 ureg
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
633 sampler
= ureg_DECL_sampler(ureg
, 0);
634 coord
= ureg_DECL_fs_input(ureg
, TGSI_SEMANTIC_GENERIC
, 0,
635 TGSI_INTERPOLATE_LINEAR
);
636 out
= ureg_DECL_output(ureg
, TGSI_SEMANTIC_COLOR
, 0);
637 for (c
= 0; c
< 4; c
++)
638 tmp_sum
[c
] = ureg_DECL_temporary(ureg
);
639 for (c
= 0; c
< 4; c
++)
640 tmp_coord
[c
] = ureg_DECL_temporary(ureg
);
641 tmp
= ureg_DECL_temporary(ureg
);
642 top
= ureg_DECL_temporary(ureg
);
643 bottom
= ureg_DECL_temporary(ureg
);
646 for (c
= 0; c
< 4; c
++)
647 ureg_MOV(ureg
, tmp_sum
[c
], ureg_imm1f(ureg
, 0));
649 /* Get 4 texture coordinates for the bilinear filter. */
650 ureg_F2U(ureg
, tmp_coord
[0], coord
); /* top-left */
651 ureg_UADD(ureg
, tmp_coord
[1], ureg_src(tmp_coord
[0]),
652 ureg_imm4u(ureg
, 1, 0, 0, 0)); /* top-right */
653 ureg_UADD(ureg
, tmp_coord
[2], ureg_src(tmp_coord
[0]),
654 ureg_imm4u(ureg
, 0, 1, 0, 0)); /* bottom-left */
655 ureg_UADD(ureg
, tmp_coord
[3], ureg_src(tmp_coord
[0]),
656 ureg_imm4u(ureg
, 1, 1, 0, 0)); /* bottom-right */
658 for (i
= 0; i
< nr_samples
; i
++) {
659 for (c
= 0; c
< 4; c
++) {
660 /* Read one sample. */
661 ureg_MOV(ureg
, ureg_writemask(tmp_coord
[c
], TGSI_WRITEMASK_W
),
662 ureg_imm1u(ureg
, i
));
663 ureg_TXF(ureg
, tmp
, tgsi_tex
, ureg_src(tmp_coord
[c
]), sampler
);
666 ureg_U2F(ureg
, tmp
, ureg_src(tmp
));
668 ureg_I2F(ureg
, tmp
, ureg_src(tmp
));
670 /* Add it to the sum.*/
671 ureg_ADD(ureg
, tmp_sum
[c
], ureg_src(tmp_sum
[c
]), ureg_src(tmp
));
675 /* Calculate the average. */
676 for (c
= 0; c
< 4; c
++)
677 ureg_MUL(ureg
, tmp_sum
[c
], ureg_src(tmp_sum
[c
]),
678 ureg_imm1f(ureg
, 1.0 / nr_samples
));
680 /* Take the 4 average values and apply a standard bilinear filter. */
681 ureg_FRC(ureg
, tmp
, coord
);
684 ureg_scalar(ureg_src(tmp
), 0),
685 ureg_src(tmp_sum
[1]),
686 ureg_src(tmp_sum
[0]));
688 ureg_LRP(ureg
, bottom
,
689 ureg_scalar(ureg_src(tmp
), 0),
690 ureg_src(tmp_sum
[3]),
691 ureg_src(tmp_sum
[2]));
694 ureg_scalar(ureg_src(tmp
), 1),
698 /* Convert to the texture format and return. */
700 ureg_F2U(ureg
, out
, ureg_src(tmp
));
702 ureg_F2I(ureg
, out
, ureg_src(tmp
));
704 ureg_MOV(ureg
, out
, ureg_src(tmp
));
708 return ureg_create_shader_and_destroy(ureg
, pipe
);