st/mesa: add a fallback for clear_with_quad when no vs_layer
[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 == NULL)
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 {
221 struct ureg_program *ureg;
222 struct ureg_src sampler;
223 struct ureg_src tex;
224 struct ureg_dst out;
225
226 assert(interp_mode == TGSI_INTERPOLATE_LINEAR ||
227 interp_mode == TGSI_INTERPOLATE_PERSPECTIVE);
228
229 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
230 if (ureg == NULL)
231 return NULL;
232
233 sampler = ureg_DECL_sampler( ureg, 0 );
234
235 tex = ureg_DECL_fs_input( ureg,
236 TGSI_SEMANTIC_GENERIC, 0,
237 interp_mode );
238
239 out = ureg_DECL_output( ureg,
240 TGSI_SEMANTIC_COLOR,
241 0 );
242
243 if (writemask != TGSI_WRITEMASK_XYZW) {
244 struct ureg_src imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
245
246 ureg_MOV( ureg, out, imm );
247 }
248
249 ureg_TEX( ureg,
250 ureg_writemask(out, writemask),
251 tex_target, tex, sampler );
252 ureg_END( ureg );
253
254 return ureg_create_shader_and_destroy( ureg, pipe );
255 }
256
257
258 /**
259 * Make a simple fragment shader that sets the output color to a color
260 * taken from a texture.
261 * \param tex_target one of PIPE_TEXTURE_x
262 */
263 void *
264 util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target,
265 unsigned interp_mode)
266 {
267 return util_make_fragment_tex_shader_writemask( pipe,
268 tex_target,
269 interp_mode,
270 TGSI_WRITEMASK_XYZW );
271 }
272
273
274 /**
275 * Make a simple fragment texture shader which reads an X component from
276 * a texture and writes it as depth.
277 */
278 void *
279 util_make_fragment_tex_shader_writedepth(struct pipe_context *pipe,
280 unsigned tex_target,
281 unsigned interp_mode)
282 {
283 struct ureg_program *ureg;
284 struct ureg_src sampler;
285 struct ureg_src tex;
286 struct ureg_dst out, depth;
287 struct ureg_src imm;
288
289 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
290 if (ureg == NULL)
291 return NULL;
292
293 sampler = ureg_DECL_sampler( ureg, 0 );
294
295 tex = ureg_DECL_fs_input( ureg,
296 TGSI_SEMANTIC_GENERIC, 0,
297 interp_mode );
298
299 out = ureg_DECL_output( ureg,
300 TGSI_SEMANTIC_COLOR,
301 0 );
302
303 depth = ureg_DECL_output( ureg,
304 TGSI_SEMANTIC_POSITION,
305 0 );
306
307 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
308
309 ureg_MOV( ureg, out, imm );
310
311 ureg_TEX( ureg,
312 ureg_writemask(depth, TGSI_WRITEMASK_Z),
313 tex_target, tex, sampler );
314 ureg_END( ureg );
315
316 return ureg_create_shader_and_destroy( ureg, pipe );
317 }
318
319
320 /**
321 * Make a simple fragment texture shader which reads the texture unit 0 and 1
322 * and writes it as depth and stencil, respectively.
323 */
324 void *
325 util_make_fragment_tex_shader_writedepthstencil(struct pipe_context *pipe,
326 unsigned tex_target,
327 unsigned interp_mode)
328 {
329 struct ureg_program *ureg;
330 struct ureg_src depth_sampler, stencil_sampler;
331 struct ureg_src tex;
332 struct ureg_dst out, depth, stencil;
333 struct ureg_src imm;
334
335 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
336 if (ureg == NULL)
337 return NULL;
338
339 depth_sampler = ureg_DECL_sampler( ureg, 0 );
340 stencil_sampler = ureg_DECL_sampler( ureg, 1 );
341
342 tex = ureg_DECL_fs_input( ureg,
343 TGSI_SEMANTIC_GENERIC, 0,
344 interp_mode );
345
346 out = ureg_DECL_output( ureg,
347 TGSI_SEMANTIC_COLOR,
348 0 );
349
350 depth = ureg_DECL_output( ureg,
351 TGSI_SEMANTIC_POSITION,
352 0 );
353
354 stencil = ureg_DECL_output( ureg,
355 TGSI_SEMANTIC_STENCIL,
356 0 );
357
358 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
359
360 ureg_MOV( ureg, out, imm );
361
362 ureg_TEX( ureg,
363 ureg_writemask(depth, TGSI_WRITEMASK_Z),
364 tex_target, tex, depth_sampler );
365 ureg_TEX( ureg,
366 ureg_writemask(stencil, TGSI_WRITEMASK_Y),
367 tex_target, tex, stencil_sampler );
368 ureg_END( ureg );
369
370 return ureg_create_shader_and_destroy( ureg, pipe );
371 }
372
373
374 /**
375 * Make a simple fragment texture shader which reads a texture and writes it
376 * as stencil.
377 */
378 void *
379 util_make_fragment_tex_shader_writestencil(struct pipe_context *pipe,
380 unsigned tex_target,
381 unsigned interp_mode)
382 {
383 struct ureg_program *ureg;
384 struct ureg_src stencil_sampler;
385 struct ureg_src tex;
386 struct ureg_dst out, stencil;
387 struct ureg_src imm;
388
389 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
390 if (ureg == NULL)
391 return NULL;
392
393 stencil_sampler = ureg_DECL_sampler( ureg, 0 );
394
395 tex = ureg_DECL_fs_input( ureg,
396 TGSI_SEMANTIC_GENERIC, 0,
397 interp_mode );
398
399 out = ureg_DECL_output( ureg,
400 TGSI_SEMANTIC_COLOR,
401 0 );
402
403 stencil = ureg_DECL_output( ureg,
404 TGSI_SEMANTIC_STENCIL,
405 0 );
406
407 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
408
409 ureg_MOV( ureg, out, imm );
410
411 ureg_TEX( ureg,
412 ureg_writemask(stencil, TGSI_WRITEMASK_Y),
413 tex_target, tex, stencil_sampler );
414 ureg_END( ureg );
415
416 return ureg_create_shader_and_destroy( ureg, pipe );
417 }
418
419
420 /**
421 * Make simple fragment color pass-through shader that replicates OUT[0]
422 * to all bound colorbuffers.
423 */
424 void *
425 util_make_fragment_passthrough_shader(struct pipe_context *pipe,
426 int input_semantic,
427 int input_interpolate,
428 boolean write_all_cbufs)
429 {
430 static const char shader_templ[] =
431 "FRAG\n"
432 "%s"
433 "DCL IN[0], %s[0], %s\n"
434 "DCL OUT[0], COLOR[0]\n"
435
436 "MOV OUT[0], IN[0]\n"
437 "END\n";
438
439 char text[sizeof(shader_templ)+100];
440 struct tgsi_token tokens[1000];
441 struct pipe_shader_state state = {tokens};
442
443 sprintf(text, shader_templ,
444 write_all_cbufs ? "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n" : "",
445 tgsi_semantic_names[input_semantic],
446 tgsi_interpolate_names[input_interpolate]);
447
448 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
449 assert(0);
450 return NULL;
451 }
452 #if 0
453 tgsi_dump(state.tokens, 0);
454 #endif
455
456 return pipe->create_fs_state(pipe, &state);
457 }
458
459
460 void *
461 util_make_empty_fragment_shader(struct pipe_context *pipe)
462 {
463 struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
464 if (ureg == NULL)
465 return NULL;
466
467 ureg_END(ureg);
468 return ureg_create_shader_and_destroy(ureg, pipe);
469 }
470
471
472 /**
473 * Make a fragment shader that copies the input color to N output colors.
474 */
475 void *
476 util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs,
477 int input_semantic,
478 int input_interpolate)
479 {
480 struct ureg_program *ureg;
481 struct ureg_src src;
482 struct ureg_dst dst[PIPE_MAX_COLOR_BUFS];
483 int i;
484
485 assert(num_cbufs <= PIPE_MAX_COLOR_BUFS);
486
487 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
488 if (ureg == NULL)
489 return NULL;
490
491 src = ureg_DECL_fs_input( ureg, input_semantic, 0,
492 input_interpolate );
493
494 for (i = 0; i < num_cbufs; i++)
495 dst[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, i );
496
497 for (i = 0; i < num_cbufs; i++)
498 ureg_MOV( ureg, dst[i], src );
499
500 ureg_END( ureg );
501
502 return ureg_create_shader_and_destroy( ureg, pipe );
503 }
504
505
506 static void *
507 util_make_fs_blit_msaa_gen(struct pipe_context *pipe,
508 unsigned tgsi_tex,
509 const char *output_semantic,
510 const char *output_mask)
511 {
512 static const char shader_templ[] =
513 "FRAG\n"
514 "DCL IN[0], GENERIC[0], LINEAR\n"
515 "DCL SAMP[0]\n"
516 "DCL OUT[0], %s\n"
517 "DCL TEMP[0]\n"
518
519 "F2U TEMP[0], IN[0]\n"
520 "TXF OUT[0]%s, TEMP[0], SAMP[0], %s\n"
521 "END\n";
522
523 const char *type = tgsi_texture_names[tgsi_tex];
524 char text[sizeof(shader_templ)+100];
525 struct tgsi_token tokens[1000];
526 struct pipe_shader_state state = {tokens};
527
528 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
529 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
530
531 sprintf(text, shader_templ, output_semantic, output_mask, type);
532
533 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
534 puts(text);
535 assert(0);
536 return NULL;
537 }
538 #if 0
539 tgsi_dump(state.tokens, 0);
540 #endif
541
542 return pipe->create_fs_state(pipe, &state);
543 }
544
545
546 /**
547 * Make a fragment shader that sets the output color to a color
548 * fetched from a multisample texture.
549 * \param tex_target one of PIPE_TEXTURE_x
550 */
551 void *
552 util_make_fs_blit_msaa_color(struct pipe_context *pipe,
553 unsigned tgsi_tex)
554 {
555 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex,
556 "COLOR[0]", "");
557 }
558
559
560 /**
561 * Make a fragment shader that sets the output depth to a depth value
562 * fetched from a multisample texture.
563 * \param tex_target one of PIPE_TEXTURE_x
564 */
565 void *
566 util_make_fs_blit_msaa_depth(struct pipe_context *pipe,
567 unsigned tgsi_tex)
568 {
569 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex,
570 "POSITION", ".z");
571 }
572
573
574 /**
575 * Make a fragment shader that sets the output stencil to a stencil value
576 * fetched from a multisample texture.
577 * \param tex_target one of PIPE_TEXTURE_x
578 */
579 void *
580 util_make_fs_blit_msaa_stencil(struct pipe_context *pipe,
581 unsigned tgsi_tex)
582 {
583 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex,
584 "STENCIL", ".y");
585 }
586
587
588 /**
589 * Make a fragment shader that sets the output depth and stencil to depth
590 * and stencil values fetched from two multisample textures / samplers.
591 * The sizes of both textures should match (it should be one depth-stencil
592 * texture).
593 * \param tex_target one of PIPE_TEXTURE_x
594 */
595 void *
596 util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe,
597 unsigned tgsi_tex)
598 {
599 static const char shader_templ[] =
600 "FRAG\n"
601 "DCL IN[0], GENERIC[0], LINEAR\n"
602 "DCL SAMP[0..1]\n"
603 "DCL OUT[0], POSITION\n"
604 "DCL OUT[1], STENCIL\n"
605 "DCL TEMP[0]\n"
606
607 "F2U TEMP[0], IN[0]\n"
608 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n"
609 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n"
610 "END\n";
611
612 const char *type = tgsi_texture_names[tgsi_tex];
613 char text[sizeof(shader_templ)+100];
614 struct tgsi_token tokens[1000];
615 struct pipe_shader_state state = {tokens};
616
617 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
618 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
619
620 sprintf(text, shader_templ, type, type);
621
622 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
623 assert(0);
624 return NULL;
625 }
626 #if 0
627 tgsi_dump(state.tokens, 0);
628 #endif
629
630 return pipe->create_fs_state(pipe, &state);
631 }
632
633
634 void *
635 util_make_fs_msaa_resolve(struct pipe_context *pipe,
636 unsigned tgsi_tex, unsigned nr_samples,
637 boolean is_uint, boolean is_sint)
638 {
639 struct ureg_program *ureg;
640 struct ureg_src sampler, coord;
641 struct ureg_dst out, tmp_sum, tmp_coord, tmp;
642 int i;
643
644 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
645 if (!ureg)
646 return NULL;
647
648 /* Declarations. */
649 sampler = ureg_DECL_sampler(ureg, 0);
650 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
651 TGSI_INTERPOLATE_LINEAR);
652 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
653 tmp_sum = ureg_DECL_temporary(ureg);
654 tmp_coord = ureg_DECL_temporary(ureg);
655 tmp = ureg_DECL_temporary(ureg);
656
657 /* Instructions. */
658 ureg_MOV(ureg, tmp_sum, ureg_imm1f(ureg, 0));
659 ureg_F2U(ureg, tmp_coord, coord);
660
661 for (i = 0; i < nr_samples; i++) {
662 /* Read one sample. */
663 ureg_MOV(ureg, ureg_writemask(tmp_coord, TGSI_WRITEMASK_W),
664 ureg_imm1u(ureg, i));
665 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord), sampler);
666
667 if (is_uint)
668 ureg_U2F(ureg, tmp, ureg_src(tmp));
669 else if (is_sint)
670 ureg_I2F(ureg, tmp, ureg_src(tmp));
671
672 /* Add it to the sum.*/
673 ureg_ADD(ureg, tmp_sum, ureg_src(tmp_sum), ureg_src(tmp));
674 }
675
676 /* Calculate the average and return. */
677 ureg_MUL(ureg, tmp_sum, ureg_src(tmp_sum),
678 ureg_imm1f(ureg, 1.0 / nr_samples));
679
680 if (is_uint)
681 ureg_F2U(ureg, out, ureg_src(tmp_sum));
682 else if (is_sint)
683 ureg_F2I(ureg, out, ureg_src(tmp_sum));
684 else
685 ureg_MOV(ureg, out, ureg_src(tmp_sum));
686
687 ureg_END(ureg);
688
689 return ureg_create_shader_and_destroy(ureg, pipe);
690 }
691
692
693 void *
694 util_make_fs_msaa_resolve_bilinear(struct pipe_context *pipe,
695 unsigned tgsi_tex, unsigned nr_samples,
696 boolean is_uint, boolean is_sint)
697 {
698 struct ureg_program *ureg;
699 struct ureg_src sampler, coord;
700 struct ureg_dst out, tmp, top, bottom;
701 struct ureg_dst tmp_coord[4], tmp_sum[4];
702 int i, c;
703
704 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
705 if (!ureg)
706 return NULL;
707
708 /* Declarations. */
709 sampler = ureg_DECL_sampler(ureg, 0);
710 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
711 TGSI_INTERPOLATE_LINEAR);
712 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
713 for (c = 0; c < 4; c++)
714 tmp_sum[c] = ureg_DECL_temporary(ureg);
715 for (c = 0; c < 4; c++)
716 tmp_coord[c] = ureg_DECL_temporary(ureg);
717 tmp = ureg_DECL_temporary(ureg);
718 top = ureg_DECL_temporary(ureg);
719 bottom = ureg_DECL_temporary(ureg);
720
721 /* Instructions. */
722 for (c = 0; c < 4; c++)
723 ureg_MOV(ureg, tmp_sum[c], ureg_imm1f(ureg, 0));
724
725 /* Get 4 texture coordinates for the bilinear filter. */
726 ureg_F2U(ureg, tmp_coord[0], coord); /* top-left */
727 ureg_UADD(ureg, tmp_coord[1], ureg_src(tmp_coord[0]),
728 ureg_imm4u(ureg, 1, 0, 0, 0)); /* top-right */
729 ureg_UADD(ureg, tmp_coord[2], ureg_src(tmp_coord[0]),
730 ureg_imm4u(ureg, 0, 1, 0, 0)); /* bottom-left */
731 ureg_UADD(ureg, tmp_coord[3], ureg_src(tmp_coord[0]),
732 ureg_imm4u(ureg, 1, 1, 0, 0)); /* bottom-right */
733
734 for (i = 0; i < nr_samples; i++) {
735 for (c = 0; c < 4; c++) {
736 /* Read one sample. */
737 ureg_MOV(ureg, ureg_writemask(tmp_coord[c], TGSI_WRITEMASK_W),
738 ureg_imm1u(ureg, i));
739 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord[c]), sampler);
740
741 if (is_uint)
742 ureg_U2F(ureg, tmp, ureg_src(tmp));
743 else if (is_sint)
744 ureg_I2F(ureg, tmp, ureg_src(tmp));
745
746 /* Add it to the sum.*/
747 ureg_ADD(ureg, tmp_sum[c], ureg_src(tmp_sum[c]), ureg_src(tmp));
748 }
749 }
750
751 /* Calculate the average. */
752 for (c = 0; c < 4; c++)
753 ureg_MUL(ureg, tmp_sum[c], ureg_src(tmp_sum[c]),
754 ureg_imm1f(ureg, 1.0 / nr_samples));
755
756 /* Take the 4 average values and apply a standard bilinear filter. */
757 ureg_FRC(ureg, tmp, coord);
758
759 ureg_LRP(ureg, top,
760 ureg_scalar(ureg_src(tmp), 0),
761 ureg_src(tmp_sum[1]),
762 ureg_src(tmp_sum[0]));
763
764 ureg_LRP(ureg, bottom,
765 ureg_scalar(ureg_src(tmp), 0),
766 ureg_src(tmp_sum[3]),
767 ureg_src(tmp_sum[2]));
768
769 ureg_LRP(ureg, tmp,
770 ureg_scalar(ureg_src(tmp), 1),
771 ureg_src(bottom),
772 ureg_src(top));
773
774 /* Convert to the texture format and return. */
775 if (is_uint)
776 ureg_F2U(ureg, out, ureg_src(tmp));
777 else if (is_sint)
778 ureg_F2I(ureg, out, ureg_src(tmp));
779 else
780 ureg_MOV(ureg, out, ureg_src(tmp));
781
782 ureg_END(ureg);
783
784 return ureg_create_shader_and_destroy(ureg, pipe);
785 }