gallium/auxiliary: Sanitize NULL checks into canonical form
[mesa.git] / src / gallium / auxiliary / util / u_simple_shaders.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
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 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.
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 *
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 bool window_space)
64 {
65 return util_make_vertex_passthrough_shader_with_so(pipe, num_attribs,
66 semantic_names,
67 semantic_indexes,
68 window_space, NULL);
69 }
70
71 void *
72 util_make_vertex_passthrough_shader_with_so(struct pipe_context *pipe,
73 uint num_attribs,
74 const uint *semantic_names,
75 const uint *semantic_indexes,
76 bool window_space,
77 const struct pipe_stream_output_info *so)
78 {
79 struct ureg_program *ureg;
80 uint i;
81
82 ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
83 if (!ureg)
84 return NULL;
85
86 if (window_space)
87 ureg_property(ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, TRUE);
88
89 for (i = 0; i < num_attribs; i++) {
90 struct ureg_src src;
91 struct ureg_dst dst;
92
93 src = ureg_DECL_vs_input( ureg, i );
94
95 dst = ureg_DECL_output( ureg,
96 semantic_names[i],
97 semantic_indexes[i]);
98
99 ureg_MOV( ureg, dst, src );
100 }
101
102 ureg_END( ureg );
103
104 return ureg_create_shader_with_so_and_destroy( ureg, pipe, so );
105 }
106
107
108 void *util_make_layered_clear_vertex_shader(struct pipe_context *pipe)
109 {
110 static const char text[] =
111 "VERT\n"
112 "DCL IN[0]\n"
113 "DCL IN[1]\n"
114 "DCL SV[0], INSTANCEID\n"
115 "DCL OUT[0], POSITION\n"
116 "DCL OUT[1], GENERIC[0]\n"
117 "DCL OUT[2], LAYER\n"
118
119 "MOV OUT[0], IN[0]\n"
120 "MOV OUT[1], IN[1]\n"
121 "MOV OUT[2], SV[0]\n"
122 "END\n";
123 struct tgsi_token tokens[1000];
124 struct pipe_shader_state state = {tokens};
125
126 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
127 assert(0);
128 return NULL;
129 }
130 return pipe->create_vs_state(pipe, &state);
131 }
132
133 /**
134 * Takes position and color, and outputs position, color, and instance id.
135 */
136 void *util_make_layered_clear_helper_vertex_shader(struct pipe_context *pipe)
137 {
138 static const char text[] =
139 "VERT\n"
140 "DCL IN[0]\n"
141 "DCL IN[1]\n"
142 "DCL SV[0], INSTANCEID\n"
143 "DCL OUT[0], POSITION\n"
144 "DCL OUT[1], GENERIC[0]\n"
145 "DCL OUT[2], GENERIC[1]\n"
146
147 "MOV OUT[0], IN[0]\n"
148 "MOV OUT[1], IN[1]\n"
149 "MOV OUT[2].x, SV[0].xxxx\n"
150 "END\n";
151 struct tgsi_token tokens[1000];
152 struct pipe_shader_state state = {tokens};
153
154 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
155 assert(0);
156 return NULL;
157 }
158 return pipe->create_vs_state(pipe, &state);
159 }
160
161 /**
162 * Takes position, color, and target layer, and emits vertices on that target
163 * layer, with the specified color.
164 */
165 void *util_make_layered_clear_geometry_shader(struct pipe_context *pipe)
166 {
167 static const char text[] =
168 "GEOM\n"
169 "PROPERTY GS_INPUT_PRIMITIVE TRIANGLES\n"
170 "PROPERTY GS_OUTPUT_PRIMITIVE TRIANGLE_STRIP\n"
171 "PROPERTY GS_MAX_OUTPUT_VERTICES 3\n"
172 "PROPERTY GS_INVOCATIONS 1\n"
173 "DCL IN[][0], POSITION\n" /* position */
174 "DCL IN[][1], GENERIC[0]\n" /* color */
175 "DCL IN[][2], GENERIC[1]\n" /* vs invocation */
176 "DCL OUT[0], POSITION\n"
177 "DCL OUT[1], GENERIC[0]\n"
178 "DCL OUT[2], LAYER\n"
179 "IMM[0] INT32 {0, 0, 0, 0}\n"
180
181 "MOV OUT[0], IN[0][0]\n"
182 "MOV OUT[1], IN[0][1]\n"
183 "MOV OUT[2].x, IN[0][2].xxxx\n"
184 "EMIT IMM[0].xxxx\n"
185 "MOV OUT[0], IN[1][0]\n"
186 "MOV OUT[1], IN[1][1]\n"
187 "MOV OUT[2].x, IN[1][2].xxxx\n"
188 "EMIT IMM[0].xxxx\n"
189 "MOV OUT[0], IN[2][0]\n"
190 "MOV OUT[1], IN[2][1]\n"
191 "MOV OUT[2].x, IN[2][2].xxxx\n"
192 "EMIT IMM[0].xxxx\n"
193 "END\n";
194 struct tgsi_token tokens[1000];
195 struct pipe_shader_state state = {tokens};
196
197 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
198 assert(0);
199 return NULL;
200 }
201 return pipe->create_gs_state(pipe, &state);
202 }
203
204 /**
205 * Make simple fragment texture shader:
206 * IMM {0,0,0,1} // (if writemask != 0xf)
207 * MOV OUT[0], IMM[0] // (if writemask != 0xf)
208 * TEX OUT[0].writemask, IN[0], SAMP[0], 2D;
209 * END;
210 *
211 * \param tex_target one of PIPE_TEXTURE_x
212 * \parma interp_mode either TGSI_INTERPOLATE_LINEAR or PERSPECTIVE
213 * \param writemask mask of TGSI_WRITEMASK_x
214 */
215 void *
216 util_make_fragment_tex_shader_writemask(struct pipe_context *pipe,
217 unsigned tex_target,
218 unsigned interp_mode,
219 unsigned writemask,
220 enum tgsi_return_type stype)
221 {
222 struct ureg_program *ureg;
223 struct ureg_src sampler;
224 struct ureg_src tex;
225 struct ureg_dst out;
226
227 assert(interp_mode == TGSI_INTERPOLATE_LINEAR ||
228 interp_mode == TGSI_INTERPOLATE_PERSPECTIVE);
229
230 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
231 if (!ureg)
232 return NULL;
233
234 sampler = ureg_DECL_sampler( ureg, 0 );
235
236 ureg_DECL_sampler_view(ureg, 0, tex_target, stype, stype, stype, stype);
237
238 tex = ureg_DECL_fs_input( ureg,
239 TGSI_SEMANTIC_GENERIC, 0,
240 interp_mode );
241
242 out = ureg_DECL_output( ureg,
243 TGSI_SEMANTIC_COLOR,
244 0 );
245
246 if (writemask != TGSI_WRITEMASK_XYZW) {
247 struct ureg_src imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
248
249 ureg_MOV( ureg, out, imm );
250 }
251
252 if (tex_target == TGSI_TEXTURE_BUFFER)
253 ureg_TXF(ureg,
254 ureg_writemask(out, writemask),
255 tex_target, tex, sampler);
256 else
257 ureg_TEX(ureg,
258 ureg_writemask(out, writemask),
259 tex_target, tex, sampler);
260
261 ureg_END( ureg );
262
263 return ureg_create_shader_and_destroy( ureg, pipe );
264 }
265
266
267 /**
268 * Make a simple fragment shader that sets the output color to a color
269 * taken from a texture.
270 * \param tex_target one of PIPE_TEXTURE_x
271 */
272 void *
273 util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target,
274 unsigned interp_mode,
275 enum tgsi_return_type stype)
276 {
277 return util_make_fragment_tex_shader_writemask( pipe,
278 tex_target,
279 interp_mode,
280 TGSI_WRITEMASK_XYZW,
281 stype );
282 }
283
284
285 /**
286 * Make a simple fragment texture shader which reads an X component from
287 * a texture and writes it as depth.
288 */
289 void *
290 util_make_fragment_tex_shader_writedepth(struct pipe_context *pipe,
291 unsigned tex_target,
292 unsigned interp_mode)
293 {
294 struct ureg_program *ureg;
295 struct ureg_src sampler;
296 struct ureg_src tex;
297 struct ureg_dst out, depth;
298 struct ureg_src imm;
299
300 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
301 if (!ureg)
302 return NULL;
303
304 sampler = ureg_DECL_sampler( ureg, 0 );
305
306 ureg_DECL_sampler_view(ureg, 0, tex_target,
307 TGSI_RETURN_TYPE_FLOAT,
308 TGSI_RETURN_TYPE_FLOAT,
309 TGSI_RETURN_TYPE_FLOAT,
310 TGSI_RETURN_TYPE_FLOAT);
311
312 tex = ureg_DECL_fs_input( ureg,
313 TGSI_SEMANTIC_GENERIC, 0,
314 interp_mode );
315
316 out = ureg_DECL_output( ureg,
317 TGSI_SEMANTIC_COLOR,
318 0 );
319
320 depth = ureg_DECL_output( ureg,
321 TGSI_SEMANTIC_POSITION,
322 0 );
323
324 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
325
326 ureg_MOV( ureg, out, imm );
327
328 ureg_TEX( ureg,
329 ureg_writemask(depth, TGSI_WRITEMASK_Z),
330 tex_target, tex, sampler );
331 ureg_END( ureg );
332
333 return ureg_create_shader_and_destroy( ureg, pipe );
334 }
335
336
337 /**
338 * Make a simple fragment texture shader which reads the texture unit 0 and 1
339 * and writes it as depth and stencil, respectively.
340 */
341 void *
342 util_make_fragment_tex_shader_writedepthstencil(struct pipe_context *pipe,
343 unsigned tex_target,
344 unsigned interp_mode)
345 {
346 struct ureg_program *ureg;
347 struct ureg_src depth_sampler, stencil_sampler;
348 struct ureg_src tex;
349 struct ureg_dst out, depth, stencil;
350 struct ureg_src imm;
351
352 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
353 if (!ureg)
354 return NULL;
355
356 depth_sampler = ureg_DECL_sampler( ureg, 0 );
357 ureg_DECL_sampler_view(ureg, 0, tex_target,
358 TGSI_RETURN_TYPE_FLOAT,
359 TGSI_RETURN_TYPE_FLOAT,
360 TGSI_RETURN_TYPE_FLOAT,
361 TGSI_RETURN_TYPE_FLOAT);
362 stencil_sampler = ureg_DECL_sampler( ureg, 1 );
363 ureg_DECL_sampler_view(ureg, 0, tex_target,
364 TGSI_RETURN_TYPE_UINT,
365 TGSI_RETURN_TYPE_UINT,
366 TGSI_RETURN_TYPE_UINT,
367 TGSI_RETURN_TYPE_UINT);
368
369 tex = ureg_DECL_fs_input( ureg,
370 TGSI_SEMANTIC_GENERIC, 0,
371 interp_mode );
372
373 out = ureg_DECL_output( ureg,
374 TGSI_SEMANTIC_COLOR,
375 0 );
376
377 depth = ureg_DECL_output( ureg,
378 TGSI_SEMANTIC_POSITION,
379 0 );
380
381 stencil = ureg_DECL_output( ureg,
382 TGSI_SEMANTIC_STENCIL,
383 0 );
384
385 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
386
387 ureg_MOV( ureg, out, imm );
388
389 ureg_TEX( ureg,
390 ureg_writemask(depth, TGSI_WRITEMASK_Z),
391 tex_target, tex, depth_sampler );
392 ureg_TEX( ureg,
393 ureg_writemask(stencil, TGSI_WRITEMASK_Y),
394 tex_target, tex, stencil_sampler );
395 ureg_END( ureg );
396
397 return ureg_create_shader_and_destroy( ureg, pipe );
398 }
399
400
401 /**
402 * Make a simple fragment texture shader which reads a texture and writes it
403 * as stencil.
404 */
405 void *
406 util_make_fragment_tex_shader_writestencil(struct pipe_context *pipe,
407 unsigned tex_target,
408 unsigned interp_mode)
409 {
410 struct ureg_program *ureg;
411 struct ureg_src stencil_sampler;
412 struct ureg_src tex;
413 struct ureg_dst out, stencil;
414 struct ureg_src imm;
415
416 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
417 if (!ureg)
418 return NULL;
419
420 stencil_sampler = ureg_DECL_sampler( ureg, 0 );
421
422 ureg_DECL_sampler_view(ureg, 0, tex_target,
423 TGSI_RETURN_TYPE_UINT,
424 TGSI_RETURN_TYPE_UINT,
425 TGSI_RETURN_TYPE_UINT,
426 TGSI_RETURN_TYPE_UINT);
427
428 tex = ureg_DECL_fs_input( ureg,
429 TGSI_SEMANTIC_GENERIC, 0,
430 interp_mode );
431
432 out = ureg_DECL_output( ureg,
433 TGSI_SEMANTIC_COLOR,
434 0 );
435
436 stencil = ureg_DECL_output( ureg,
437 TGSI_SEMANTIC_STENCIL,
438 0 );
439
440 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
441
442 ureg_MOV( ureg, out, imm );
443
444 ureg_TEX( ureg,
445 ureg_writemask(stencil, TGSI_WRITEMASK_Y),
446 tex_target, tex, stencil_sampler );
447 ureg_END( ureg );
448
449 return ureg_create_shader_and_destroy( ureg, pipe );
450 }
451
452
453 /**
454 * Make simple fragment color pass-through shader that replicates OUT[0]
455 * to all bound colorbuffers.
456 */
457 void *
458 util_make_fragment_passthrough_shader(struct pipe_context *pipe,
459 int input_semantic,
460 int input_interpolate,
461 boolean write_all_cbufs)
462 {
463 static const char shader_templ[] =
464 "FRAG\n"
465 "%s"
466 "DCL IN[0], %s[0], %s\n"
467 "DCL OUT[0], COLOR[0]\n"
468
469 "MOV OUT[0], IN[0]\n"
470 "END\n";
471
472 char text[sizeof(shader_templ)+100];
473 struct tgsi_token tokens[1000];
474 struct pipe_shader_state state = {tokens};
475
476 sprintf(text, shader_templ,
477 write_all_cbufs ? "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n" : "",
478 tgsi_semantic_names[input_semantic],
479 tgsi_interpolate_names[input_interpolate]);
480
481 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
482 assert(0);
483 return NULL;
484 }
485 #if 0
486 tgsi_dump(state.tokens, 0);
487 #endif
488
489 return pipe->create_fs_state(pipe, &state);
490 }
491
492
493 void *
494 util_make_empty_fragment_shader(struct pipe_context *pipe)
495 {
496 struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
497 if (!ureg)
498 return NULL;
499
500 ureg_END(ureg);
501 return ureg_create_shader_and_destroy(ureg, pipe);
502 }
503
504
505 /**
506 * Make a fragment shader that copies the input color to N output colors.
507 */
508 void *
509 util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs,
510 int input_semantic,
511 int input_interpolate)
512 {
513 struct ureg_program *ureg;
514 struct ureg_src src;
515 struct ureg_dst dst[PIPE_MAX_COLOR_BUFS];
516 int i;
517
518 assert(num_cbufs <= PIPE_MAX_COLOR_BUFS);
519
520 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
521 if (!ureg)
522 return NULL;
523
524 src = ureg_DECL_fs_input( ureg, input_semantic, 0,
525 input_interpolate );
526
527 for (i = 0; i < num_cbufs; i++)
528 dst[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, i );
529
530 for (i = 0; i < num_cbufs; i++)
531 ureg_MOV( ureg, dst[i], src );
532
533 ureg_END( ureg );
534
535 return ureg_create_shader_and_destroy( ureg, pipe );
536 }
537
538
539 static void *
540 util_make_fs_blit_msaa_gen(struct pipe_context *pipe,
541 unsigned tgsi_tex,
542 const char *samp_type,
543 const char *output_semantic,
544 const char *output_mask)
545 {
546 static const char shader_templ[] =
547 "FRAG\n"
548 "DCL IN[0], GENERIC[0], LINEAR\n"
549 "DCL SAMP[0]\n"
550 "DCL SVIEW[0], %s, %s\n"
551 "DCL OUT[0], %s\n"
552 "DCL TEMP[0]\n"
553
554 "F2U TEMP[0], IN[0]\n"
555 "TXF OUT[0]%s, TEMP[0], SAMP[0], %s\n"
556 "END\n";
557
558 const char *type = tgsi_texture_names[tgsi_tex];
559 char text[sizeof(shader_templ)+100];
560 struct tgsi_token tokens[1000];
561 struct pipe_shader_state state = {tokens};
562
563 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
564 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
565
566 sprintf(text, shader_templ, type, samp_type,
567 output_semantic, output_mask, type);
568
569 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
570 puts(text);
571 assert(0);
572 return NULL;
573 }
574 #if 0
575 tgsi_dump(state.tokens, 0);
576 #endif
577
578 return pipe->create_fs_state(pipe, &state);
579 }
580
581
582 /**
583 * Make a fragment shader that sets the output color to a color
584 * fetched from a multisample texture.
585 * \param tex_target one of PIPE_TEXTURE_x
586 */
587 void *
588 util_make_fs_blit_msaa_color(struct pipe_context *pipe,
589 unsigned tgsi_tex,
590 enum tgsi_return_type stype)
591 {
592 const char *samp_type;
593
594 if (stype == TGSI_RETURN_TYPE_UINT)
595 samp_type = "UINT";
596 else if (stype == TGSI_RETURN_TYPE_SINT)
597 samp_type = "SINT";
598 else
599 samp_type = "FLOAT";
600
601 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, samp_type,
602 "COLOR[0]", "");
603 }
604
605
606 /**
607 * Make a fragment shader that sets the output depth to a depth value
608 * fetched from a multisample texture.
609 * \param tex_target one of PIPE_TEXTURE_x
610 */
611 void *
612 util_make_fs_blit_msaa_depth(struct pipe_context *pipe,
613 unsigned tgsi_tex)
614 {
615 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, "FLOAT",
616 "POSITION", ".z");
617 }
618
619
620 /**
621 * Make a fragment shader that sets the output stencil to a stencil value
622 * fetched from a multisample texture.
623 * \param tex_target one of PIPE_TEXTURE_x
624 */
625 void *
626 util_make_fs_blit_msaa_stencil(struct pipe_context *pipe,
627 unsigned tgsi_tex)
628 {
629 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, "UINT",
630 "STENCIL", ".y");
631 }
632
633
634 /**
635 * Make a fragment shader that sets the output depth and stencil to depth
636 * and stencil values fetched from two multisample textures / samplers.
637 * The sizes of both textures should match (it should be one depth-stencil
638 * texture).
639 * \param tex_target one of PIPE_TEXTURE_x
640 */
641 void *
642 util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe,
643 unsigned tgsi_tex)
644 {
645 static const char shader_templ[] =
646 "FRAG\n"
647 "DCL IN[0], GENERIC[0], LINEAR\n"
648 "DCL SAMP[0..1]\n"
649 "DCL OUT[0], POSITION\n"
650 "DCL OUT[1], STENCIL\n"
651 "DCL TEMP[0]\n"
652
653 "F2U TEMP[0], IN[0]\n"
654 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n"
655 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n"
656 "END\n";
657
658 const char *type = tgsi_texture_names[tgsi_tex];
659 char text[sizeof(shader_templ)+100];
660 struct tgsi_token tokens[1000];
661 struct pipe_shader_state state = {tokens};
662
663 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
664 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
665
666 sprintf(text, shader_templ, type, type);
667
668 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
669 assert(0);
670 return NULL;
671 }
672 #if 0
673 tgsi_dump(state.tokens, 0);
674 #endif
675
676 return pipe->create_fs_state(pipe, &state);
677 }
678
679
680 void *
681 util_make_fs_msaa_resolve(struct pipe_context *pipe,
682 unsigned tgsi_tex, unsigned nr_samples,
683 enum tgsi_return_type stype)
684 {
685 struct ureg_program *ureg;
686 struct ureg_src sampler, coord;
687 struct ureg_dst out, tmp_sum, tmp_coord, tmp;
688 int i;
689
690 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
691 if (!ureg)
692 return NULL;
693
694 /* Declarations. */
695 sampler = ureg_DECL_sampler(ureg, 0);
696 ureg_DECL_sampler_view(ureg, 0, tgsi_tex, stype, stype, stype, stype);
697 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
698 TGSI_INTERPOLATE_LINEAR);
699 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
700 tmp_sum = ureg_DECL_temporary(ureg);
701 tmp_coord = ureg_DECL_temporary(ureg);
702 tmp = ureg_DECL_temporary(ureg);
703
704 /* Instructions. */
705 ureg_MOV(ureg, tmp_sum, ureg_imm1f(ureg, 0));
706 ureg_F2U(ureg, tmp_coord, coord);
707
708 for (i = 0; i < nr_samples; i++) {
709 /* Read one sample. */
710 ureg_MOV(ureg, ureg_writemask(tmp_coord, TGSI_WRITEMASK_W),
711 ureg_imm1u(ureg, i));
712 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord), sampler);
713
714 if (stype == TGSI_RETURN_TYPE_UINT)
715 ureg_U2F(ureg, tmp, ureg_src(tmp));
716 else if (stype == TGSI_RETURN_TYPE_SINT)
717 ureg_I2F(ureg, tmp, ureg_src(tmp));
718
719 /* Add it to the sum.*/
720 ureg_ADD(ureg, tmp_sum, ureg_src(tmp_sum), ureg_src(tmp));
721 }
722
723 /* Calculate the average and return. */
724 ureg_MUL(ureg, tmp_sum, ureg_src(tmp_sum),
725 ureg_imm1f(ureg, 1.0 / nr_samples));
726
727 if (stype == TGSI_RETURN_TYPE_UINT)
728 ureg_F2U(ureg, out, ureg_src(tmp_sum));
729 else if (stype == TGSI_RETURN_TYPE_SINT)
730 ureg_F2I(ureg, out, ureg_src(tmp_sum));
731 else
732 ureg_MOV(ureg, out, ureg_src(tmp_sum));
733
734 ureg_END(ureg);
735
736 return ureg_create_shader_and_destroy(ureg, pipe);
737 }
738
739
740 void *
741 util_make_fs_msaa_resolve_bilinear(struct pipe_context *pipe,
742 unsigned tgsi_tex, unsigned nr_samples,
743 enum tgsi_return_type stype)
744 {
745 struct ureg_program *ureg;
746 struct ureg_src sampler, coord;
747 struct ureg_dst out, tmp, top, bottom;
748 struct ureg_dst tmp_coord[4], tmp_sum[4];
749 int i, c;
750
751 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
752 if (!ureg)
753 return NULL;
754
755 /* Declarations. */
756 sampler = ureg_DECL_sampler(ureg, 0);
757 ureg_DECL_sampler_view(ureg, 0, tgsi_tex, stype, stype, stype, stype);
758 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
759 TGSI_INTERPOLATE_LINEAR);
760 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
761 for (c = 0; c < 4; c++)
762 tmp_sum[c] = ureg_DECL_temporary(ureg);
763 for (c = 0; c < 4; c++)
764 tmp_coord[c] = ureg_DECL_temporary(ureg);
765 tmp = ureg_DECL_temporary(ureg);
766 top = ureg_DECL_temporary(ureg);
767 bottom = ureg_DECL_temporary(ureg);
768
769 /* Instructions. */
770 for (c = 0; c < 4; c++)
771 ureg_MOV(ureg, tmp_sum[c], ureg_imm1f(ureg, 0));
772
773 /* Get 4 texture coordinates for the bilinear filter. */
774 ureg_F2U(ureg, tmp_coord[0], coord); /* top-left */
775 ureg_UADD(ureg, tmp_coord[1], ureg_src(tmp_coord[0]),
776 ureg_imm4u(ureg, 1, 0, 0, 0)); /* top-right */
777 ureg_UADD(ureg, tmp_coord[2], ureg_src(tmp_coord[0]),
778 ureg_imm4u(ureg, 0, 1, 0, 0)); /* bottom-left */
779 ureg_UADD(ureg, tmp_coord[3], ureg_src(tmp_coord[0]),
780 ureg_imm4u(ureg, 1, 1, 0, 0)); /* bottom-right */
781
782 for (i = 0; i < nr_samples; i++) {
783 for (c = 0; c < 4; c++) {
784 /* Read one sample. */
785 ureg_MOV(ureg, ureg_writemask(tmp_coord[c], TGSI_WRITEMASK_W),
786 ureg_imm1u(ureg, i));
787 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord[c]), sampler);
788
789 if (stype == TGSI_RETURN_TYPE_UINT)
790 ureg_U2F(ureg, tmp, ureg_src(tmp));
791 else if (stype == TGSI_RETURN_TYPE_SINT)
792 ureg_I2F(ureg, tmp, ureg_src(tmp));
793
794 /* Add it to the sum.*/
795 ureg_ADD(ureg, tmp_sum[c], ureg_src(tmp_sum[c]), ureg_src(tmp));
796 }
797 }
798
799 /* Calculate the average. */
800 for (c = 0; c < 4; c++)
801 ureg_MUL(ureg, tmp_sum[c], ureg_src(tmp_sum[c]),
802 ureg_imm1f(ureg, 1.0 / nr_samples));
803
804 /* Take the 4 average values and apply a standard bilinear filter. */
805 ureg_FRC(ureg, tmp, coord);
806
807 ureg_LRP(ureg, top,
808 ureg_scalar(ureg_src(tmp), 0),
809 ureg_src(tmp_sum[1]),
810 ureg_src(tmp_sum[0]));
811
812 ureg_LRP(ureg, bottom,
813 ureg_scalar(ureg_src(tmp), 0),
814 ureg_src(tmp_sum[3]),
815 ureg_src(tmp_sum[2]));
816
817 ureg_LRP(ureg, tmp,
818 ureg_scalar(ureg_src(tmp), 1),
819 ureg_src(bottom),
820 ureg_src(top));
821
822 /* Convert to the texture format and return. */
823 if (stype == TGSI_RETURN_TYPE_UINT)
824 ureg_F2U(ureg, out, ureg_src(tmp));
825 else if (stype == TGSI_RETURN_TYPE_SINT)
826 ureg_F2I(ureg, out, ureg_src(tmp));
827 else
828 ureg_MOV(ureg, out, ureg_src(tmp));
829
830 ureg_END(ureg);
831
832 return ureg_create_shader_and_destroy(ureg, pipe);
833 }
834
835 void *
836 util_make_geometry_passthrough_shader(struct pipe_context *pipe,
837 uint num_attribs,
838 const ubyte *semantic_names,
839 const ubyte *semantic_indexes)
840 {
841 static const unsigned zero[4] = {0, 0, 0, 0};
842
843 struct ureg_program *ureg;
844 struct ureg_dst dst[PIPE_MAX_SHADER_OUTPUTS];
845 struct ureg_src src[PIPE_MAX_SHADER_INPUTS];
846 struct ureg_src imm;
847
848 unsigned i;
849
850 ureg = ureg_create(TGSI_PROCESSOR_GEOMETRY);
851 if (!ureg)
852 return NULL;
853
854 ureg_property(ureg, TGSI_PROPERTY_GS_INPUT_PRIM, PIPE_PRIM_POINTS);
855 ureg_property(ureg, TGSI_PROPERTY_GS_OUTPUT_PRIM, PIPE_PRIM_POINTS);
856 ureg_property(ureg, TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, 1);
857 ureg_property(ureg, TGSI_PROPERTY_GS_INVOCATIONS, 1);
858 imm = ureg_DECL_immediate_uint(ureg, zero, 4);
859
860 /**
861 * Loop over all the attribs and declare the corresponding
862 * declarations in the geometry shader
863 */
864 for (i = 0; i < num_attribs; i++) {
865 src[i] = ureg_DECL_input(ureg, semantic_names[i],
866 semantic_indexes[i], 0, 1);
867 src[i] = ureg_src_dimension(src[i], 0);
868 dst[i] = ureg_DECL_output(ureg, semantic_names[i], semantic_indexes[i]);
869 }
870
871 /* MOV dst[i] src[i] */
872 for (i = 0; i < num_attribs; i++) {
873 ureg_MOV(ureg, dst[i], src[i]);
874 }
875
876 /* EMIT IMM[0] */
877 ureg_insn(ureg, TGSI_OPCODE_EMIT, NULL, 0, &imm, 1);
878
879 /* END */
880 ureg_END(ureg);
881
882 return ureg_create_shader_and_destroy(ureg, pipe);
883 }
884