1 /**************************************************************************
2  *
3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4  * All Rights Reserved.
5  * Copyright 2009 Marek Olšák <maraeo@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 Olšák
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 *
util_make_vertex_passthrough_shader(struct pipe_context * pipe,uint num_attribs,const uint * semantic_names,const uint * semantic_indexes)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 *
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)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 *
util_make_fragment_tex_shader_writemask(struct pipe_context * pipe,unsigned tex_target,unsigned interp_mode,unsigned writemask)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 *
util_make_fragment_tex_shader(struct pipe_context * pipe,unsigned tex_target,unsigned interp_mode)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 *
util_make_fragment_tex_shader_writedepth(struct pipe_context * pipe,unsigned tex_target,unsigned interp_mode)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 *
util_make_fragment_tex_shader_writedepthstencil(struct pipe_context * pipe,unsigned tex_target,unsigned interp_mode)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 *
util_make_fragment_tex_shader_writestencil(struct pipe_context * pipe,unsigned tex_target,unsigned interp_mode)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 *
util_make_fragment_passthrough_shader(struct pipe_context * pipe)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 *
util_make_fragment_cloneinput_shader(struct pipe_context * pipe,int num_cbufs,int input_semantic,int input_interpolate)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 *
util_make_fs_blit_msaa_gen(struct pipe_context * pipe,unsigned tgsi_tex,const char * output_semantic,const char * output_mask)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 *
util_make_fs_blit_msaa_color(struct pipe_context * pipe,unsigned tgsi_tex)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 *
util_make_fs_blit_msaa_depth(struct pipe_context * pipe,unsigned tgsi_tex)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 *
util_make_fs_blit_msaa_stencil(struct pipe_context * pipe,unsigned tgsi_tex)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 *
util_make_fs_blit_msaa_depthstencil(struct pipe_context * pipe,unsigned tgsi_tex)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