gallium/u_blitter: implement shader-based MSAA resolve with bilinear filtering
[mesa.git] / src / gallium / auxiliary / util / u_simple_shaders.c
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 *
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 void *util_make_layered_clear_vertex_shader(struct pipe_context *pipe)
103 {
104 static const char text[] =
105 "VERT\n"
106 "DCL IN[0]\n"
107 "DCL IN[1]\n"
108 "DCL SV[0], INSTANCEID\n"
109 "DCL OUT[0], POSITION\n"
110 "DCL OUT[1], GENERIC[0]\n"
111 "DCL OUT[2], LAYER\n"
112
113 "MOV OUT[0], IN[0]\n"
114 "MOV OUT[1], IN[1]\n"
115 "MOV OUT[2], SV[0]\n"
116 "END\n";
117 struct tgsi_token tokens[1000];
118 struct pipe_shader_state state = {tokens};
119
120 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
121 assert(0);
122 return NULL;
123 }
124 return pipe->create_vs_state(pipe, &state);
125 }
126
127
128 /**
129 * Make simple fragment texture shader:
130 * IMM {0,0,0,1} // (if writemask != 0xf)
131 * MOV OUT[0], IMM[0] // (if writemask != 0xf)
132 * TEX OUT[0].writemask, IN[0], SAMP[0], 2D;
133 * END;
134 *
135 * \param tex_target one of PIPE_TEXTURE_x
136 * \parma interp_mode either TGSI_INTERPOLATE_LINEAR or PERSPECTIVE
137 * \param writemask mask of TGSI_WRITEMASK_x
138 */
139 void *
140 util_make_fragment_tex_shader_writemask(struct pipe_context *pipe,
141 unsigned tex_target,
142 unsigned interp_mode,
143 unsigned writemask )
144 {
145 struct ureg_program *ureg;
146 struct ureg_src sampler;
147 struct ureg_src tex;
148 struct ureg_dst out;
149
150 assert(interp_mode == TGSI_INTERPOLATE_LINEAR ||
151 interp_mode == TGSI_INTERPOLATE_PERSPECTIVE);
152
153 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
154 if (ureg == NULL)
155 return NULL;
156
157 sampler = ureg_DECL_sampler( ureg, 0 );
158
159 tex = ureg_DECL_fs_input( ureg,
160 TGSI_SEMANTIC_GENERIC, 0,
161 interp_mode );
162
163 out = ureg_DECL_output( ureg,
164 TGSI_SEMANTIC_COLOR,
165 0 );
166
167 if (writemask != TGSI_WRITEMASK_XYZW) {
168 struct ureg_src imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
169
170 ureg_MOV( ureg, out, imm );
171 }
172
173 ureg_TEX( ureg,
174 ureg_writemask(out, writemask),
175 tex_target, tex, sampler );
176 ureg_END( ureg );
177
178 return ureg_create_shader_and_destroy( ureg, pipe );
179 }
180
181
182 /**
183 * Make a simple fragment shader that sets the output color to a color
184 * taken from a texture.
185 * \param tex_target one of PIPE_TEXTURE_x
186 */
187 void *
188 util_make_fragment_tex_shader(struct pipe_context *pipe, unsigned tex_target,
189 unsigned interp_mode)
190 {
191 return util_make_fragment_tex_shader_writemask( pipe,
192 tex_target,
193 interp_mode,
194 TGSI_WRITEMASK_XYZW );
195 }
196
197
198 /**
199 * Make a simple fragment texture shader which reads an X component from
200 * a texture and writes it as depth.
201 */
202 void *
203 util_make_fragment_tex_shader_writedepth(struct pipe_context *pipe,
204 unsigned tex_target,
205 unsigned interp_mode)
206 {
207 struct ureg_program *ureg;
208 struct ureg_src sampler;
209 struct ureg_src tex;
210 struct ureg_dst out, depth;
211 struct ureg_src imm;
212
213 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
214 if (ureg == NULL)
215 return NULL;
216
217 sampler = ureg_DECL_sampler( ureg, 0 );
218
219 tex = ureg_DECL_fs_input( ureg,
220 TGSI_SEMANTIC_GENERIC, 0,
221 interp_mode );
222
223 out = ureg_DECL_output( ureg,
224 TGSI_SEMANTIC_COLOR,
225 0 );
226
227 depth = ureg_DECL_output( ureg,
228 TGSI_SEMANTIC_POSITION,
229 0 );
230
231 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
232
233 ureg_MOV( ureg, out, imm );
234
235 ureg_TEX( ureg,
236 ureg_writemask(depth, TGSI_WRITEMASK_Z),
237 tex_target, tex, sampler );
238 ureg_END( ureg );
239
240 return ureg_create_shader_and_destroy( ureg, pipe );
241 }
242
243
244 /**
245 * Make a simple fragment texture shader which reads the texture unit 0 and 1
246 * and writes it as depth and stencil, respectively.
247 */
248 void *
249 util_make_fragment_tex_shader_writedepthstencil(struct pipe_context *pipe,
250 unsigned tex_target,
251 unsigned interp_mode)
252 {
253 struct ureg_program *ureg;
254 struct ureg_src depth_sampler, stencil_sampler;
255 struct ureg_src tex;
256 struct ureg_dst out, depth, stencil;
257 struct ureg_src imm;
258
259 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
260 if (ureg == NULL)
261 return NULL;
262
263 depth_sampler = ureg_DECL_sampler( ureg, 0 );
264 stencil_sampler = ureg_DECL_sampler( ureg, 1 );
265
266 tex = ureg_DECL_fs_input( ureg,
267 TGSI_SEMANTIC_GENERIC, 0,
268 interp_mode );
269
270 out = ureg_DECL_output( ureg,
271 TGSI_SEMANTIC_COLOR,
272 0 );
273
274 depth = ureg_DECL_output( ureg,
275 TGSI_SEMANTIC_POSITION,
276 0 );
277
278 stencil = ureg_DECL_output( ureg,
279 TGSI_SEMANTIC_STENCIL,
280 0 );
281
282 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
283
284 ureg_MOV( ureg, out, imm );
285
286 ureg_TEX( ureg,
287 ureg_writemask(depth, TGSI_WRITEMASK_Z),
288 tex_target, tex, depth_sampler );
289 ureg_TEX( ureg,
290 ureg_writemask(stencil, TGSI_WRITEMASK_Y),
291 tex_target, tex, stencil_sampler );
292 ureg_END( ureg );
293
294 return ureg_create_shader_and_destroy( ureg, pipe );
295 }
296
297
298 /**
299 * Make a simple fragment texture shader which reads a texture and writes it
300 * as stencil.
301 */
302 void *
303 util_make_fragment_tex_shader_writestencil(struct pipe_context *pipe,
304 unsigned tex_target,
305 unsigned interp_mode)
306 {
307 struct ureg_program *ureg;
308 struct ureg_src stencil_sampler;
309 struct ureg_src tex;
310 struct ureg_dst out, stencil;
311 struct ureg_src imm;
312
313 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
314 if (ureg == NULL)
315 return NULL;
316
317 stencil_sampler = ureg_DECL_sampler( ureg, 0 );
318
319 tex = ureg_DECL_fs_input( ureg,
320 TGSI_SEMANTIC_GENERIC, 0,
321 interp_mode );
322
323 out = ureg_DECL_output( ureg,
324 TGSI_SEMANTIC_COLOR,
325 0 );
326
327 stencil = ureg_DECL_output( ureg,
328 TGSI_SEMANTIC_STENCIL,
329 0 );
330
331 imm = ureg_imm4f( ureg, 0, 0, 0, 1 );
332
333 ureg_MOV( ureg, out, imm );
334
335 ureg_TEX( ureg,
336 ureg_writemask(stencil, TGSI_WRITEMASK_Y),
337 tex_target, tex, stencil_sampler );
338 ureg_END( ureg );
339
340 return ureg_create_shader_and_destroy( ureg, pipe );
341 }
342
343
344 /**
345 * Make simple fragment color pass-through shader that replicates OUT[0]
346 * to all bound colorbuffers.
347 */
348 void *
349 util_make_fragment_passthrough_shader(struct pipe_context *pipe,
350 int input_semantic,
351 int input_interpolate,
352 boolean write_all_cbufs)
353 {
354 static const char shader_templ[] =
355 "FRAG\n"
356 "%s"
357 "DCL IN[0], %s[0], %s\n"
358 "DCL OUT[0], COLOR[0]\n"
359
360 "MOV OUT[0], IN[0]\n"
361 "END\n";
362
363 char text[sizeof(shader_templ)+100];
364 struct tgsi_token tokens[1000];
365 struct pipe_shader_state state = {tokens};
366
367 sprintf(text, shader_templ,
368 write_all_cbufs ? "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n" : "",
369 tgsi_semantic_names[input_semantic],
370 tgsi_interpolate_names[input_interpolate]);
371
372 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
373 assert(0);
374 return NULL;
375 }
376 #if 0
377 tgsi_dump(state.tokens, 0);
378 #endif
379
380 return pipe->create_fs_state(pipe, &state);
381 }
382
383
384 void *
385 util_make_empty_fragment_shader(struct pipe_context *pipe)
386 {
387 struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
388 if (ureg == NULL)
389 return NULL;
390
391 ureg_END(ureg);
392 return ureg_create_shader_and_destroy(ureg, pipe);
393 }
394
395
396 /**
397 * Make a fragment shader that copies the input color to N output colors.
398 */
399 void *
400 util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs,
401 int input_semantic,
402 int input_interpolate)
403 {
404 struct ureg_program *ureg;
405 struct ureg_src src;
406 struct ureg_dst dst[PIPE_MAX_COLOR_BUFS];
407 int i;
408
409 assert(num_cbufs <= PIPE_MAX_COLOR_BUFS);
410
411 ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
412 if (ureg == NULL)
413 return NULL;
414
415 src = ureg_DECL_fs_input( ureg, input_semantic, 0,
416 input_interpolate );
417
418 for (i = 0; i < num_cbufs; i++)
419 dst[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, i );
420
421 for (i = 0; i < num_cbufs; i++)
422 ureg_MOV( ureg, dst[i], src );
423
424 ureg_END( ureg );
425
426 return ureg_create_shader_and_destroy( ureg, pipe );
427 }
428
429
430 static void *
431 util_make_fs_blit_msaa_gen(struct pipe_context *pipe,
432 unsigned tgsi_tex,
433 const char *output_semantic,
434 const char *output_mask)
435 {
436 static const char shader_templ[] =
437 "FRAG\n"
438 "DCL IN[0], GENERIC[0], LINEAR\n"
439 "DCL SAMP[0]\n"
440 "DCL OUT[0], %s\n"
441 "DCL TEMP[0]\n"
442
443 "F2U TEMP[0], IN[0]\n"
444 "TXF OUT[0]%s, TEMP[0], SAMP[0], %s\n"
445 "END\n";
446
447 const char *type = tgsi_texture_names[tgsi_tex];
448 char text[sizeof(shader_templ)+100];
449 struct tgsi_token tokens[1000];
450 struct pipe_shader_state state = {tokens};
451
452 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
453 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
454
455 sprintf(text, shader_templ, output_semantic, output_mask, type);
456
457 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
458 puts(text);
459 assert(0);
460 return NULL;
461 }
462 #if 0
463 tgsi_dump(state.tokens, 0);
464 #endif
465
466 return pipe->create_fs_state(pipe, &state);
467 }
468
469
470 /**
471 * Make a fragment shader that sets the output color to a color
472 * fetched from a multisample texture.
473 * \param tex_target one of PIPE_TEXTURE_x
474 */
475 void *
476 util_make_fs_blit_msaa_color(struct pipe_context *pipe,
477 unsigned tgsi_tex)
478 {
479 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex,
480 "COLOR[0]", "");
481 }
482
483
484 /**
485 * Make a fragment shader that sets the output depth to a depth value
486 * fetched from a multisample texture.
487 * \param tex_target one of PIPE_TEXTURE_x
488 */
489 void *
490 util_make_fs_blit_msaa_depth(struct pipe_context *pipe,
491 unsigned tgsi_tex)
492 {
493 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex,
494 "POSITION", ".z");
495 }
496
497
498 /**
499 * Make a fragment shader that sets the output stencil to a stencil value
500 * fetched from a multisample texture.
501 * \param tex_target one of PIPE_TEXTURE_x
502 */
503 void *
504 util_make_fs_blit_msaa_stencil(struct pipe_context *pipe,
505 unsigned tgsi_tex)
506 {
507 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex,
508 "STENCIL", ".y");
509 }
510
511
512 /**
513 * Make a fragment shader that sets the output depth and stencil to depth
514 * and stencil values fetched from two multisample textures / samplers.
515 * The sizes of both textures should match (it should be one depth-stencil
516 * texture).
517 * \param tex_target one of PIPE_TEXTURE_x
518 */
519 void *
520 util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe,
521 unsigned tgsi_tex)
522 {
523 static const char shader_templ[] =
524 "FRAG\n"
525 "DCL IN[0], GENERIC[0], LINEAR\n"
526 "DCL SAMP[0..1]\n"
527 "DCL OUT[0], POSITION\n"
528 "DCL OUT[1], STENCIL\n"
529 "DCL TEMP[0]\n"
530
531 "F2U TEMP[0], IN[0]\n"
532 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n"
533 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n"
534 "END\n";
535
536 const char *type = tgsi_texture_names[tgsi_tex];
537 char text[sizeof(shader_templ)+100];
538 struct tgsi_token tokens[1000];
539 struct pipe_shader_state state = {tokens};
540
541 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
542 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
543
544 sprintf(text, shader_templ, type, type);
545
546 if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
547 assert(0);
548 return NULL;
549 }
550 #if 0
551 tgsi_dump(state.tokens, 0);
552 #endif
553
554 return pipe->create_fs_state(pipe, &state);
555 }
556
557
558 void *
559 util_make_fs_msaa_resolve(struct pipe_context *pipe,
560 unsigned tgsi_tex, unsigned nr_samples,
561 boolean is_uint, boolean is_sint)
562 {
563 struct ureg_program *ureg;
564 struct ureg_src sampler, coord;
565 struct ureg_dst out, tmp_sum, tmp_coord, tmp;
566 int i;
567
568 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
569 if (!ureg)
570 return NULL;
571
572 /* Declarations. */
573 sampler = ureg_DECL_sampler(ureg, 0);
574 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
575 TGSI_INTERPOLATE_LINEAR);
576 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
577 tmp_sum = ureg_DECL_temporary(ureg);
578 tmp_coord = ureg_DECL_temporary(ureg);
579 tmp = ureg_DECL_temporary(ureg);
580
581 /* Instructions. */
582 ureg_MOV(ureg, tmp_sum, ureg_imm1f(ureg, 0));
583 ureg_F2U(ureg, tmp_coord, coord);
584
585 for (i = 0; i < nr_samples; i++) {
586 /* Read one sample. */
587 ureg_MOV(ureg, ureg_writemask(tmp_coord, TGSI_WRITEMASK_W),
588 ureg_imm1u(ureg, i));
589 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord), sampler);
590
591 if (is_uint)
592 ureg_U2F(ureg, tmp, ureg_src(tmp));
593 else if (is_sint)
594 ureg_I2F(ureg, tmp, ureg_src(tmp));
595
596 /* Add it to the sum.*/
597 ureg_ADD(ureg, tmp_sum, ureg_src(tmp_sum), ureg_src(tmp));
598 }
599
600 /* Calculate the average and return. */
601 ureg_MUL(ureg, tmp_sum, ureg_src(tmp_sum),
602 ureg_imm1f(ureg, 1.0 / nr_samples));
603
604 if (is_uint)
605 ureg_F2U(ureg, out, ureg_src(tmp_sum));
606 else if (is_sint)
607 ureg_F2I(ureg, out, ureg_src(tmp_sum));
608 else
609 ureg_MOV(ureg, out, ureg_src(tmp_sum));
610
611 ureg_END(ureg);
612
613 return ureg_create_shader_and_destroy(ureg, pipe);
614 }
615
616
617 void *
618 util_make_fs_msaa_resolve_bilinear(struct pipe_context *pipe,
619 unsigned tgsi_tex, unsigned nr_samples,
620 boolean is_uint, boolean is_sint)
621 {
622 struct ureg_program *ureg;
623 struct ureg_src sampler, coord;
624 struct ureg_dst out, tmp, top, bottom;
625 struct ureg_dst tmp_coord[4], tmp_sum[4];
626 int i, c;
627
628 ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
629 if (!ureg)
630 return NULL;
631
632 /* Declarations. */
633 sampler = ureg_DECL_sampler(ureg, 0);
634 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
635 TGSI_INTERPOLATE_LINEAR);
636 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
637 for (c = 0; c < 4; c++)
638 tmp_sum[c] = ureg_DECL_temporary(ureg);
639 for (c = 0; c < 4; c++)
640 tmp_coord[c] = ureg_DECL_temporary(ureg);
641 tmp = ureg_DECL_temporary(ureg);
642 top = ureg_DECL_temporary(ureg);
643 bottom = ureg_DECL_temporary(ureg);
644
645 /* Instructions. */
646 for (c = 0; c < 4; c++)
647 ureg_MOV(ureg, tmp_sum[c], ureg_imm1f(ureg, 0));
648
649 /* Get 4 texture coordinates for the bilinear filter. */
650 ureg_F2U(ureg, tmp_coord[0], coord); /* top-left */
651 ureg_UADD(ureg, tmp_coord[1], ureg_src(tmp_coord[0]),
652 ureg_imm4u(ureg, 1, 0, 0, 0)); /* top-right */
653 ureg_UADD(ureg, tmp_coord[2], ureg_src(tmp_coord[0]),
654 ureg_imm4u(ureg, 0, 1, 0, 0)); /* bottom-left */
655 ureg_UADD(ureg, tmp_coord[3], ureg_src(tmp_coord[0]),
656 ureg_imm4u(ureg, 1, 1, 0, 0)); /* bottom-right */
657
658 for (i = 0; i < nr_samples; i++) {
659 for (c = 0; c < 4; c++) {
660 /* Read one sample. */
661 ureg_MOV(ureg, ureg_writemask(tmp_coord[c], TGSI_WRITEMASK_W),
662 ureg_imm1u(ureg, i));
663 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord[c]), sampler);
664
665 if (is_uint)
666 ureg_U2F(ureg, tmp, ureg_src(tmp));
667 else if (is_sint)
668 ureg_I2F(ureg, tmp, ureg_src(tmp));
669
670 /* Add it to the sum.*/
671 ureg_ADD(ureg, tmp_sum[c], ureg_src(tmp_sum[c]), ureg_src(tmp));
672 }
673 }
674
675 /* Calculate the average. */
676 for (c = 0; c < 4; c++)
677 ureg_MUL(ureg, tmp_sum[c], ureg_src(tmp_sum[c]),
678 ureg_imm1f(ureg, 1.0 / nr_samples));
679
680 /* Take the 4 average values and apply a standard bilinear filter. */
681 ureg_FRC(ureg, tmp, coord);
682
683 ureg_LRP(ureg, top,
684 ureg_scalar(ureg_src(tmp), 0),
685 ureg_src(tmp_sum[1]),
686 ureg_src(tmp_sum[0]));
687
688 ureg_LRP(ureg, bottom,
689 ureg_scalar(ureg_src(tmp), 0),
690 ureg_src(tmp_sum[3]),
691 ureg_src(tmp_sum[2]));
692
693 ureg_LRP(ureg, tmp,
694 ureg_scalar(ureg_src(tmp), 1),
695 ureg_src(bottom),
696 ureg_src(top));
697
698 /* Convert to the texture format and return. */
699 if (is_uint)
700 ureg_F2U(ureg, out, ureg_src(tmp));
701 else if (is_sint)
702 ureg_F2I(ureg, out, ureg_src(tmp));
703 else
704 ureg_MOV(ureg, out, ureg_src(tmp));
705
706 ureg_END(ureg);
707
708 return ureg_create_shader_and_destroy(ureg, pipe);
709 }