1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * Copyright 2009 Marek Olk <maraeo (at) gmail.com> 6 * 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: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 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. 26 * 27 **************************************************************************/ 28 29 /** 30 * @file 31 * Simple vertex/fragment shader generators. 32 * 33 * @author Brian Paul 34 Marek Olk 35 */ 36 37 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 */ 49 50 51 52 /** 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 57 */ 58 void * 59 util_make_vertex_passthrough_shader(struct pipe_context *pipe, 60 uint num_attribs, 61 const uint *semantic_names, 62 const uint *semantic_indexes) 63 { 64 return util_make_vertex_passthrough_shader_with_so(pipe, num_attribs, 65 semantic_names, 66 semantic_indexes, NULL); 67 } 68 69 void * 70 util_make_vertex_passthrough_shader_with_so(struct pipe_context *pipe, 71 uint num_attribs, 72 const uint *semantic_names, 73 const uint *semantic_indexes, 74 const struct pipe_stream_output_info *so) 75 { 76 struct ureg_program *ureg; 77 uint i; 78 79 ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); 80 if (ureg == NULL) 81 return NULL; 82 83 for (i = 0; i < num_attribs; i++) { 84 struct ureg_src src; 85 struct ureg_dst dst; 86 87 src = ureg_DECL_vs_input( ureg, i ); 88 89 dst = ureg_DECL_output( ureg, 90 semantic_names[i], 91 semantic_indexes[i]); 92 93 ureg_MOV( ureg, dst, src ); 94 } 95 96 ureg_END( ureg ); 97 98 return ureg_create_shader_with_so_and_destroy( ureg, pipe, so ); 99 } 100 101 102 /** 103 * Make simple fragment texture shader: 104 * IMM {0,0,0,1} // (if writemask != 0xf) 105 * MOV OUT[0], IMM[0] // (if writemask != 0xf) 106 * TEX OUT[0].writemask, IN[0], SAMP[0], 2D; 107 * END; 108 * 109 * \param tex_target one of PIPE_TEXTURE_x 110 * \parma interp_mode either TGSI_INTERPOLATE_LINEAR or PERSPECTIVE 111 * \param writemask mask of TGSI_WRITEMASK_x 112 */ 113 void * 114 util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, 115 unsigned tex_target, 116 unsigned interp_mode, 117 unsigned writemask ) 118 { 119 struct ureg_program *ureg; 120 struct ureg_src sampler; 121 struct ureg_src tex; 122 struct ureg_dst out; 123 124 assert(interp_mode == TGSI_INTERPOLATE_LINEAR || 125 interp_mode == TGSI_INTERPOLATE_PERSPECTIVE); 126 127 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); 128 if (ureg == NULL) 129 return NULL; 130 131 sampler = ureg_DECL_sampler( ureg, 0 ); 132 133 tex = ureg_DECL_fs_input( ureg, 134 TGSI_SEMANTIC_GENERIC, 0, 135 interp_mode ); 136 137 out = ureg_DECL_output( ureg, 138 TGSI_SEMANTIC_COLOR, 139 0 ); 140 141 if (writemask != TGSI_WRITEMASK_XYZW) { 142 struct ureg_src imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); 143 144 ureg_MOV( ureg, out, imm ); 145 } 146 147 ureg_TEX( ureg, 148 ureg_writemask(out, writemask), 149 tex_target, tex, sampler ); 150 ureg_END( ureg ); 151 152 return ureg_create_shader_and_destroy( ureg, pipe ); 153 } 154 155 156 /** 157 * Make a simple fragment shader that sets the output color to a color 158 * taken from a texture. 159 * \param tex_target one of PIPE_TEXTURE_x 160 */ 161 void * 162 util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target, 163 unsigned interp_mode) 164 { 165 return util_make_fragment_tex_shader_writemask( pipe, 166 tex_target, 167 interp_mode, 168 TGSI_WRITEMASK_XYZW ); 169 } 170 171 172 /** 173 * Make a simple fragment texture shader which reads an X component from 174 * a texture and writes it as depth. 175 */ 176 void * 177 util_make_fragment_tex_shader_writedepth(struct pipe_context *pipe, 178 unsigned tex_target, 179 unsigned interp_mode) 180 { 181 struct ureg_program *ureg; 182 struct ureg_src sampler; 183 struct ureg_src tex; 184 struct ureg_dst out, depth; 185 struct ureg_src imm; 186 187 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); 188 if (ureg == NULL) 189 return NULL; 190 191 sampler = ureg_DECL_sampler( ureg, 0 ); 192 193 tex = ureg_DECL_fs_input( ureg, 194 TGSI_SEMANTIC_GENERIC, 0, 195 interp_mode ); 196 197 out = ureg_DECL_output( ureg, 198 TGSI_SEMANTIC_COLOR, 199 0 ); 200 201 depth = ureg_DECL_output( ureg, 202 TGSI_SEMANTIC_POSITION, 203 0 ); 204 205 imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); 206 207 ureg_MOV( ureg, out, imm ); 208 209 ureg_TEX( ureg, 210 ureg_writemask(depth, TGSI_WRITEMASK_Z), 211 tex_target, tex, sampler ); 212 ureg_END( ureg ); 213 214 return ureg_create_shader_and_destroy( ureg, pipe ); 215 } 216 217 218 /** 219 * Make a simple fragment texture shader which reads the texture unit 0 and 1 220 * and writes it as depth and stencil, respectively. 221 */ 222 void * 223 util_make_fragment_tex_shader_writedepthstencil(struct pipe_context *pipe, 224 unsigned tex_target, 225 unsigned interp_mode) 226 { 227 struct ureg_program *ureg; 228 struct ureg_src depth_sampler, stencil_sampler; 229 struct ureg_src tex; 230 struct ureg_dst out, depth, stencil; 231 struct ureg_src imm; 232 233 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); 234 if (ureg == NULL) 235 return NULL; 236 237 depth_sampler = ureg_DECL_sampler( ureg, 0 ); 238 stencil_sampler = ureg_DECL_sampler( ureg, 1 ); 239 240 tex = ureg_DECL_fs_input( ureg, 241 TGSI_SEMANTIC_GENERIC, 0, 242 interp_mode ); 243 244 out = ureg_DECL_output( ureg, 245 TGSI_SEMANTIC_COLOR, 246 0 ); 247 248 depth = ureg_DECL_output( ureg, 249 TGSI_SEMANTIC_POSITION, 250 0 ); 251 252 stencil = ureg_DECL_output( ureg, 253 TGSI_SEMANTIC_STENCIL, 254 0 ); 255 256 imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); 257 258 ureg_MOV( ureg, out, imm ); 259 260 ureg_TEX( ureg, 261 ureg_writemask(depth, TGSI_WRITEMASK_Z), 262 tex_target, tex, depth_sampler ); 263 ureg_TEX( ureg, 264 ureg_writemask(stencil, TGSI_WRITEMASK_Y), 265 tex_target, tex, stencil_sampler ); 266 ureg_END( ureg ); 267 268 return ureg_create_shader_and_destroy( ureg, pipe ); 269 } 270 271 272 /** 273 * Make a simple fragment texture shader which reads a texture and writes it 274 * as stencil. 275 */ 276 void * 277 util_make_fragment_tex_shader_writestencil(struct pipe_context *pipe, 278 unsigned tex_target, 279 unsigned interp_mode) 280 { 281 struct ureg_program *ureg; 282 struct ureg_src stencil_sampler; 283 struct ureg_src tex; 284 struct ureg_dst out, stencil; 285 struct ureg_src imm; 286 287 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); 288 if (ureg == NULL) 289 return NULL; 290 291 stencil_sampler = ureg_DECL_sampler( ureg, 0 ); 292 293 tex = ureg_DECL_fs_input( ureg, 294 TGSI_SEMANTIC_GENERIC, 0, 295 interp_mode ); 296 297 out = ureg_DECL_output( ureg, 298 TGSI_SEMANTIC_COLOR, 299 0 ); 300 301 stencil = ureg_DECL_output( ureg, 302 TGSI_SEMANTIC_STENCIL, 303 0 ); 304 305 imm = ureg_imm4f( ureg, 0, 0, 0, 1 ); 306 307 ureg_MOV( ureg, out, imm ); 308 309 ureg_TEX( ureg, 310 ureg_writemask(stencil, TGSI_WRITEMASK_Y), 311 tex_target, tex, stencil_sampler ); 312 ureg_END( ureg ); 313 314 return ureg_create_shader_and_destroy( ureg, pipe ); 315 } 316 317 318 /** 319 * Make simple fragment color pass-through shader. 320 */ 321 void * 322 util_make_fragment_passthrough_shader(struct pipe_context *pipe) 323 { 324 return util_make_fragment_cloneinput_shader(pipe, 1, TGSI_SEMANTIC_COLOR, 325 TGSI_INTERPOLATE_PERSPECTIVE); 326 } 327 328 329 /** 330 * Make a fragment shader that copies the input color to N output colors. 331 */ 332 void * 333 util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs, 334 int input_semantic, 335 int input_interpolate) 336 { 337 struct ureg_program *ureg; 338 struct ureg_src src; 339 struct ureg_dst dst[PIPE_MAX_COLOR_BUFS]; 340 int i; 341 342 assert(num_cbufs <= PIPE_MAX_COLOR_BUFS); 343 344 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); 345 if (ureg == NULL) 346 return NULL; 347 348 src = ureg_DECL_fs_input( ureg, input_semantic, 0, 349 input_interpolate ); 350 351 for (i = 0; i < num_cbufs; i++) 352 dst[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, i ); 353 354 for (i = 0; i < num_cbufs; i++) 355 ureg_MOV( ureg, dst[i], src ); 356 357 ureg_END( ureg ); 358 359 return ureg_create_shader_and_destroy( ureg, pipe ); 360 } 361 362 363 static void * 364 util_make_fs_blit_msaa_gen(struct pipe_context *pipe, 365 unsigned tgsi_tex, 366 const char *output_semantic, 367 const char *output_mask) 368 { 369 static const char shader_templ[] = 370 "FRAG\n" 371 "DCL IN[0], GENERIC[0], LINEAR\n" 372 "DCL SAMP[0]\n" 373 "DCL OUT[0], %s\n" 374 "DCL TEMP[0]\n" 375 376 "F2U TEMP[0], IN[0]\n" 377 "TXF OUT[0]%s, TEMP[0].xyzz, SAMP[0], %s\n" 378 "END\n"; 379 380 const char *type = tgsi_texture_names[tgsi_tex]; 381 char text[sizeof(shader_templ)+100]; 382 struct tgsi_token tokens[1000]; 383 struct pipe_shader_state state = {tokens}; 384 385 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || 386 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); 387 388 sprintf(text, shader_templ, output_semantic, output_mask, type); 389 390 if (!tgsi_text_translate(text, tokens, Elements(tokens))) { 391 puts(text); 392 assert(0); 393 return NULL; 394 } 395 #if 0 396 tgsi_dump(state.tokens, 0); 397 #endif 398 399 return pipe->create_fs_state(pipe, &state); 400 } 401 402 403 /** 404 * Make a fragment shader that sets the output color to a color 405 * fetched from a multisample texture. 406 * \param tex_target one of PIPE_TEXTURE_x 407 */ 408 void * 409 util_make_fs_blit_msaa_color(struct pipe_context *pipe, 410 unsigned tgsi_tex) 411 { 412 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, 413 "COLOR[0]", ""); 414 } 415 416 417 /** 418 * Make a fragment shader that sets the output depth to a depth value 419 * fetched from a multisample texture. 420 * \param tex_target one of PIPE_TEXTURE_x 421 */ 422 void * 423 util_make_fs_blit_msaa_depth(struct pipe_context *pipe, 424 unsigned tgsi_tex) 425 { 426 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, 427 "POSITION", ".z"); 428 } 429 430 431 /** 432 * Make a fragment shader that sets the output stencil to a stencil value 433 * fetched from a multisample texture. 434 * \param tex_target one of PIPE_TEXTURE_x 435 */ 436 void * 437 util_make_fs_blit_msaa_stencil(struct pipe_context *pipe, 438 unsigned tgsi_tex) 439 { 440 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, 441 "STENCIL", ".y"); 442 } 443 444 445 /** 446 * Make a fragment shader that sets the output depth and stencil to depth 447 * and stencil values fetched from two multisample textures / samplers. 448 * The sizes of both textures should match (it should be one depth-stencil 449 * texture). 450 * \param tex_target one of PIPE_TEXTURE_x 451 */ 452 void * 453 util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe, 454 unsigned tgsi_tex) 455 { 456 static const char shader_templ[] = 457 "FRAG\n" 458 "DCL IN[0], GENERIC[0], LINEAR\n" 459 "DCL SAMP[0..1]\n" 460 "DCL OUT[0], POSITION\n" 461 "DCL OUT[1], STENCIL\n" 462 "DCL TEMP[0]\n" 463 464 "F2U TEMP[0], IN[0]\n" 465 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n" 466 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n" 467 "END\n"; 468 469 const char *type = tgsi_texture_names[tgsi_tex]; 470 char text[sizeof(shader_templ)+100]; 471 struct tgsi_token tokens[1000]; 472 struct pipe_shader_state state = {tokens}; 473 474 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA || 475 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA); 476 477 sprintf(text, shader_templ, type, type); 478 479 if (!tgsi_text_translate(text, tokens, Elements(tokens))) { 480 assert(0); 481 return NULL; 482 } 483 #if 0 484 tgsi_dump(state.tokens, 0); 485 #endif 486 487 return pipe->create_fs_state(pipe, &state); 488 } 489