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