| /************************************************************************** |
| * |
| * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. |
| * All Rights Reserved. |
| * Copyright 2009 Marek Olšák <maraeo@gmail.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| /** |
| * @file |
| * Simple vertex/fragment shader generators. |
| * |
| * @author Brian Paul |
| Marek Olšák |
| */ |
| |
| |
| #include "pipe/p_context.h" |
| #include "pipe/p_shader_tokens.h" |
| #include "pipe/p_state.h" |
| #include "util/u_simple_shaders.h" |
| #include "util/u_debug.h" |
| #include "util/u_memory.h" |
| #include "tgsi/tgsi_dump.h" |
| #include "tgsi/tgsi_strings.h" |
| #include "tgsi/tgsi_ureg.h" |
| #include "tgsi/tgsi_text.h" |
| #include <stdio.h> /* include last */ |
| |
| |
| |
| /** |
| * Make simple vertex pass-through shader. |
| * \param num_attribs number of attributes to pass through |
| * \param semantic_names array of semantic names for each attribute |
| * \param semantic_indexes array of semantic indexes for each attribute |
| */ |
| void * |
| util_make_vertex_passthrough_shader(struct pipe_context *pipe, |
| uint num_attribs, |
| const uint *semantic_names, |
| const uint *semantic_indexes) |
| { |
| return util_make_vertex_passthrough_shader_with_so(pipe, num_attribs, |
| semantic_names, |
| semantic_indexes, NULL); |
| } |
| |
| void * |
| util_make_vertex_passthrough_shader_with_so(struct pipe_context *pipe, |
| uint num_attribs, |
| const uint *semantic_names, |
| const uint *semantic_indexes, |
| const struct pipe_stream_output_info *so) |
| { |
| struct ureg_program *ureg; |
| uint i; |
| |
| ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); |
| if (ureg == NULL) |
| return NULL; |
| |
| for (i = 0; i < num_attribs; i++) { |
| struct ureg_src src; |
| struct ureg_dst dst; |
| |
| src = ureg_DECL_vs_input( ureg, i ); |
| |
| dst = ureg_DECL_output( ureg, |
| semantic_names[i], |
| semantic_indexes[i]); |
| |
| ureg_MOV( ureg, dst, src ); |
| } |
| |
| ureg_END( ureg ); |
| |
| return ureg_create_shader_with_so_and_destroy( ureg, pipe, so ); |
| } |
| |
| |
| /** |
| * Make simple fragment texture shader: |
| * IMM {0,0,0,1} // (if writemask != 0xf) |
| * MOV OUT[0], IMM[0] // (if writemask != 0xf) |
| * TEX OUT[0].writemask, IN[0], SAMP[0], 2D; |
| * END; |
| * |
| * \param tex_target one of PIPE_TEXTURE_x |
| * \parma interp_mode either TGSI_INTERPOLATE_LINEAR or PERSPECTIVE |
| * \param writemask mask of TGSI_WRITEMASK_x |
| */ |
| void * |
| util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, |
| unsigned tex_target, |
| unsigned interp_mode, |
| unsigned writemask ) |
| { |
| struct ureg_program *ureg; |
| struct ureg_src sampler; |
| struct ureg_src tex; |
| struct ureg_dst out; |
| |
| assert(interp_mode == TGSI_INTERPOLATE_LINEAR || |
| interp_mode == TGSI_INTERPOLATE_PERSPECTIVE); |
| |
| ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); |
| if (ureg == NULL) |
| return NULL; |
| |
| sampler = ureg_DECL_sampler( ureg, 0 ); |
| |
| tex = ureg_DECL_fs_input( ureg, |
| TGSI_SEMANTIC_GENERIC, 0, |
| interp_mode ); |
| |
| out = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_COLOR, |
| 0 ); |
| |
| if (writemask != TGSI_WRITEMASK_XYZW) { |
| struct ureg_src imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); |
| |
| ureg_MOV( ureg, out, imm ); |
| } |
| |
| ureg_TEX( ureg, |
| ureg_writemask(out, writemask), |
| tex_target, tex, sampler ); |
| ureg_END( ureg ); |
| |
| return ureg_create_shader_and_destroy( ureg, pipe ); |
| } |
| |
| |
| /** |
| * Make a simple fragment shader that sets the output color to a color |
| * taken from a texture. |
| * \param tex_target one of PIPE_TEXTURE_x |
| */ |
| void * |
| util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target, |
| unsigned interp_mode) |
| { |
| return util_make_fragment_tex_shader_writemask( pipe, |
| tex_target, |
| interp_mode, |
| TGSI_WRITEMASK_XYZW ); |
| } |
| |
| |
| /** |
| * Make a simple fragment texture shader which reads an X component from |
| * a texture and writes it as depth. |
| */ |
| void * |
| util_make_fragment_tex_shader_writedepth(struct pipe_context *pipe, |
| unsigned tex_target, |
| unsigned interp_mode) |
| { |
| struct ureg_program *ureg; |
| struct ureg_src sampler; |
| struct ureg_src tex; |
| struct ureg_dst out, depth; |
| struct ureg_src imm; |
| |
| ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); |
| if (ureg == NULL) |
| return NULL; |
| |
| sampler = ureg_DECL_sampler( ureg, 0 ); |
| |
| tex = ureg_DECL_fs_input( ureg, |
| TGSI_SEMANTIC_GENERIC, 0, |
| interp_mode ); |
| |
| out = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_COLOR, |
| 0 ); |
| |
| depth = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_POSITION, |
| 0 ); |
| |
| imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); |
| |
| ureg_MOV( ureg, out, imm ); |
| |
| ureg_TEX( ureg, |
| ureg_writemask(depth, TGSI_WRITEMASK_Z), |
| tex_target, tex, sampler ); |
| ureg_END( ureg ); |
| |
| return ureg_create_shader_and_destroy( ureg, pipe ); |
| } |
| |
| |
| /** |
| * Make a simple fragment texture shader which reads the texture unit 0 and 1 |
| * and writes it as depth and stencil, respectively. |
| */ |
| void * |
| util_make_fragment_tex_shader_writedepthstencil(struct pipe_context *pipe, |
| unsigned tex_target, |
| unsigned interp_mode) |
| { |
| struct ureg_program *ureg; |
| struct ureg_src depth_sampler, stencil_sampler; |
| struct ureg_src tex; |
| struct ureg_dst out, depth, stencil; |
| struct ureg_src imm; |
| |
| ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); |
| if (ureg == NULL) |
| return NULL; |
| |
| depth_sampler = ureg_DECL_sampler( ureg, 0 ); |
| stencil_sampler = ureg_DECL_sampler( ureg, 1 ); |
| |
| tex = ureg_DECL_fs_input( ureg, |
| TGSI_SEMANTIC_GENERIC, 0, |
| interp_mode ); |
| |
| out = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_COLOR, |
| 0 ); |
| |
| depth = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_POSITION, |
| 0 ); |
| |
| stencil = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_STENCIL, |
| 0 ); |
| |
| imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); |
| |
| ureg_MOV( ureg, out, imm ); |
| |
| ureg_TEX( ureg, |
| ureg_writemask(depth, TGSI_WRITEMASK_Z), |
| tex_target, tex, depth_sampler ); |
| ureg_TEX( ureg, |
| ureg_writemask(stencil, TGSI_WRITEMASK_Y), |
| tex_target, tex, stencil_sampler ); |
| ureg_END( ureg ); |
| |
| return ureg_create_shader_and_destroy( ureg, pipe ); |
| } |
| |
| |
| /** |
| * Make a simple fragment texture shader which reads a texture and writes it |
| * as stencil. |
| */ |
| void * |
| util_make_fragment_tex_shader_writestencil(struct pipe_context *pipe, |
| unsigned tex_target, |
| unsigned interp_mode) |
| { |
| struct ureg_program *ureg; |
| struct ureg_src stencil_sampler; |
| struct ureg_src tex; |
| struct ureg_dst out, stencil; |
| struct ureg_src imm; |
| |
| ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); |
| if (ureg == NULL) |
| return NULL; |
| |
| stencil_sampler = ureg_DECL_sampler( ureg, 0 ); |
| |
| tex = ureg_DECL_fs_input( ureg, |
| TGSI_SEMANTIC_GENERIC, 0, |
| interp_mode ); |
| |
| out = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_COLOR, |
| 0 ); |
| |
| stencil = ureg_DECL_output( ureg, |
| TGSI_SEMANTIC_STENCIL, |
| 0 ); |
| |
| imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); |
| |
| ureg_MOV( ureg, out, imm ); |
| |
| ureg_TEX( ureg, |
| ureg_writemask(stencil, TGSI_WRITEMASK_Y), |
| tex_target, tex, stencil_sampler ); |
| ureg_END( ureg ); |
| |
| return ureg_create_shader_and_destroy( ureg, pipe ); |
| } |
| |
| |
| /** |
| * Make simple fragment color pass-through shader. |
| */ |
| void * |
| util_make_fragment_passthrough_shader(struct pipe_context *pipe) |
| { |
| return util_make_fragment_cloneinput_shader(pipe, 1, TGSI_SEMANTIC_COLOR, |
| TGSI_INTERPOLATE_PERSPECTIVE); |
| } |
| |
| |
| /** |
| * Make a fragment shader that copies the input color to N output colors. |
| */ |
| void * |
| util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs, |
| int input_semantic, |
| int input_interpolate) |
| { |
| struct ureg_program *ureg; |
| struct ureg_src src; |
| struct ureg_dst dst[PIPE_MAX_COLOR_BUFS]; |
| int i; |
| |
| assert(num_cbufs <= PIPE_MAX_COLOR_BUFS); |
| |
| ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); |
| if (ureg == NULL) |
| return NULL; |
| |
| src = ureg_DECL_fs_input( ureg, input_semantic, 0, |
| input_interpolate ); |
| |
| for (i = 0; i < num_cbufs; i++) |
| dst[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, i ); |
| |
| for (i = 0; i < num_cbufs; i++) |
| ureg_MOV( ureg, dst[i], src ); |
| |
| ureg_END( ureg ); |
| |
| return ureg_create_shader_and_destroy( ureg, pipe ); |
| } |
| |
| |
| static void * |
| util_make_fs_blit_msaa_gen(struct pipe_context *pipe, |
| unsigned tgsi_tex, |
| const char *output_semantic, |
| const char *output_mask) |
| { |
| static const char shader_templ[] = |
| "FRAG\n" |
| "DCL IN[0], GENERIC[0], LINEAR\n" |
| "DCL SAMP[0]\n" |
| "DCL OUT[0], %s\n" |
| "DCL TEMP[0]\n" |
| |
| "F2U TEMP[0], IN[0]\n" |
| "TXF OUT[0]%s, TEMP[0].xyzz, SAMP[0], %s\n" |
| "END\n"; |
| |
| const char *type = tgsi_texture_names[tgsi_tex]; |
| char text[sizeof(shader_templ)+100]; |
| struct tgsi_token tokens[1000]; |
| struct pipe_shader_state state = {tokens}; |
| |
| assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || |
| tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); |
| |
| sprintf(text, shader_templ, output_semantic, output_mask, type); |
| |
| if (!tgsi_text_translate(text, tokens, Elements(tokens))) { |
| puts(text); |
| assert(0); |
| return NULL; |
| } |
| #if 0 |
| tgsi_dump(state.tokens, 0); |
| #endif |
| |
| return pipe->create_fs_state(pipe, &state); |
| } |
| |
| |
| /** |
| * Make a fragment shader that sets the output color to a color |
| * fetched from a multisample texture. |
| * \param tex_target one of PIPE_TEXTURE_x |
| */ |
| void * |
| util_make_fs_blit_msaa_color(struct pipe_context *pipe, |
| unsigned tgsi_tex) |
| { |
| return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, |
| "COLOR[0]", ""); |
| } |
| |
| |
| /** |
| * Make a fragment shader that sets the output depth to a depth value |
| * fetched from a multisample texture. |
| * \param tex_target one of PIPE_TEXTURE_x |
| */ |
| void * |
| util_make_fs_blit_msaa_depth(struct pipe_context *pipe, |
| unsigned tgsi_tex) |
| { |
| return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, |
| "POSITION", ".z"); |
| } |
| |
| |
| /** |
| * Make a fragment shader that sets the output stencil to a stencil value |
| * fetched from a multisample texture. |
| * \param tex_target one of PIPE_TEXTURE_x |
| */ |
| void * |
| util_make_fs_blit_msaa_stencil(struct pipe_context *pipe, |
| unsigned tgsi_tex) |
| { |
| return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, |
| "STENCIL", ".y"); |
| } |
| |
| |
| /** |
| * Make a fragment shader that sets the output depth and stencil to depth |
| * and stencil values fetched from two multisample textures / samplers. |
| * The sizes of both textures should match (it should be one depth-stencil |
| * texture). |
| * \param tex_target one of PIPE_TEXTURE_x |
| */ |
| void * |
| util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe, |
| unsigned tgsi_tex) |
| { |
| static const char shader_templ[] = |
| "FRAG\n" |
| "DCL IN[0], GENERIC[0], LINEAR\n" |
| "DCL SAMP[0..1]\n" |
| "DCL OUT[0], POSITION\n" |
| "DCL OUT[1], STENCIL\n" |
| "DCL TEMP[0]\n" |
| |
| "F2U TEMP[0], IN[0]\n" |
| "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n" |
| "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n" |
| "END\n"; |
| |
| const char *type = tgsi_texture_names[tgsi_tex]; |
| char text[sizeof(shader_templ)+100]; |
| struct tgsi_token tokens[1000]; |
| struct pipe_shader_state state = {tokens}; |
| |
| assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || |
| tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); |
| |
| sprintf(text, shader_templ, type, type); |
| |
| if (!tgsi_text_translate(text, tokens, Elements(tokens))) { |
| assert(0); |
| return NULL; |
| } |
| #if 0 |
| tgsi_dump(state.tokens, 0); |
| #endif |
| |
| return pipe->create_fs_state(pipe, &state); |
| } |