1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 * Copyright 2009 Marek Olšák <[email protected]>
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 "util/u_string.h"
45 #include "tgsi/tgsi_dump.h"
46 #include "tgsi/tgsi_strings.h"
47 #include "tgsi/tgsi_ureg.h"
48 #include "tgsi/tgsi_text.h"
49 #include <stdio.h> /* include last */
50
51
52
53 /**
54 * Make simple vertex pass-through shader.
55 * \param num_attribs number of attributes to pass through
56 * \param semantic_names array of semantic names for each attribute
57 * \param semantic_indexes array of semantic indexes for each attribute
58 */
59 void *
util_make_vertex_passthrough_shader(struct pipe_context * pipe,unsigned num_attribs,const enum tgsi_semantic * semantic_names,const unsigned * semantic_indexes,bool window_space)60 util_make_vertex_passthrough_shader(struct pipe_context *pipe,
61 unsigned num_attribs,
62 const enum tgsi_semantic *semantic_names,
63 const unsigned *semantic_indexes,
64 bool window_space)
65 {
66 return util_make_vertex_passthrough_shader_with_so(pipe, num_attribs,
67 semantic_names,
68 semantic_indexes,
69 window_space, false, NULL);
70 }
71
72 void *
util_make_vertex_passthrough_shader_with_so(struct pipe_context * pipe,unsigned num_attribs,const enum tgsi_semantic * semantic_names,const unsigned * semantic_indexes,bool window_space,bool layered,const struct pipe_stream_output_info * so)73 util_make_vertex_passthrough_shader_with_so(struct pipe_context *pipe,
74 unsigned num_attribs,
75 const enum tgsi_semantic *semantic_names,
76 const unsigned *semantic_indexes,
77 bool window_space, bool layered,
78 const struct pipe_stream_output_info *so)
79 {
80 struct ureg_program *ureg;
81 unsigned i;
82
83 ureg = ureg_create( PIPE_SHADER_VERTEX );
84 if (!ureg)
85 return NULL;
86
87 if (window_space)
88 ureg_property(ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, true);
89
90 for (i = 0; i < num_attribs; i++) {
91 struct ureg_src src;
92 struct ureg_dst dst;
93
94 src = ureg_DECL_vs_input( ureg, i );
95
96 dst = ureg_DECL_output( ureg,
97 semantic_names[i],
98 semantic_indexes[i]);
99
100 ureg_MOV( ureg, dst, src );
101 }
102
103 if (layered) {
104 struct ureg_src instance_id =
105 ureg_DECL_system_value(ureg, TGSI_SEMANTIC_INSTANCEID, 0);
106 struct ureg_dst layer = ureg_DECL_output(ureg, TGSI_SEMANTIC_LAYER, 0);
107
108 ureg_MOV(ureg, ureg_writemask(layer, TGSI_WRITEMASK_X),
109 ureg_scalar(instance_id, TGSI_SWIZZLE_X));
110 }
111
112 ureg_END( ureg );
113
114 return ureg_create_shader_with_so_and_destroy( ureg, pipe, so );
115 }
116
117
util_make_layered_clear_vertex_shader(struct pipe_context * pipe)118 void *util_make_layered_clear_vertex_shader(struct pipe_context *pipe)
119 {
120 const enum tgsi_semantic semantic_names[] = {TGSI_SEMANTIC_POSITION,
121 TGSI_SEMANTIC_GENERIC};
122 const unsigned semantic_indices[] = {0, 0};
123
124 return util_make_vertex_passthrough_shader_with_so(pipe, 2, semantic_names,
125 semantic_indices, false,
126 true, NULL);
127 }
128
129 /**
130 * Takes position and color, and outputs position, color, and instance id.
131 */
util_make_layered_clear_helper_vertex_shader(struct pipe_context * pipe)132 void *util_make_layered_clear_helper_vertex_shader(struct pipe_context *pipe)
133 {
134 static const char text[] =
135 "VERT\n"
136 "DCL IN[0]\n"
137 "DCL IN[1]\n"
138 "DCL SV[0], INSTANCEID\n"
139 "DCL OUT[0], POSITION\n"
140 "DCL OUT[1], GENERIC[0]\n"
141 "DCL OUT[2], GENERIC[1]\n"
142
143 "MOV OUT[0], IN[0]\n"
144 "MOV OUT[1], IN[1]\n"
145 "MOV OUT[2].x, SV[0].xxxx\n"
146 "END\n";
147 struct tgsi_token tokens[1000];
148 struct pipe_shader_state state = {0};
149
150 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
151 assert(0);
152 return NULL;
153 }
154 pipe_shader_state_from_tgsi(&state, tokens);
155 return pipe->create_vs_state(pipe, &state);
156 }
157
158 /**
159 * Takes position, color, and target layer, and emits vertices on that target
160 * layer, with the specified color.
161 */
util_make_layered_clear_geometry_shader(struct pipe_context * pipe)162 void *util_make_layered_clear_geometry_shader(struct pipe_context *pipe)
163 {
164 static const char text[] =
165 "GEOM\n"
166 "PROPERTY GS_INPUT_PRIMITIVE TRIANGLES\n"
167 "PROPERTY GS_OUTPUT_PRIMITIVE TRIANGLE_STRIP\n"
168 "PROPERTY GS_MAX_OUTPUT_VERTICES 3\n"
169 "PROPERTY GS_INVOCATIONS 1\n"
170 "DCL IN[][0], POSITION\n" /* position */
171 "DCL IN[][1], GENERIC[0]\n" /* color */
172 "DCL IN[][2], GENERIC[1]\n" /* vs invocation */
173 "DCL OUT[0], POSITION\n"
174 "DCL OUT[1], GENERIC[0]\n"
175 "DCL OUT[2], LAYER\n"
176 "IMM[0] INT32 {0, 0, 0, 0}\n"
177
178 "MOV OUT[0], IN[0][0]\n"
179 "MOV OUT[1], IN[0][1]\n"
180 "MOV OUT[2].x, IN[0][2].xxxx\n"
181 "EMIT IMM[0].xxxx\n"
182 "MOV OUT[0], IN[1][0]\n"
183 "MOV OUT[1], IN[1][1]\n"
184 "MOV OUT[2].x, IN[1][2].xxxx\n"
185 "EMIT IMM[0].xxxx\n"
186 "MOV OUT[0], IN[2][0]\n"
187 "MOV OUT[1], IN[2][1]\n"
188 "MOV OUT[2].x, IN[2][2].xxxx\n"
189 "EMIT IMM[0].xxxx\n"
190 "END\n";
191 struct tgsi_token tokens[1000];
192 struct pipe_shader_state state = {0};
193
194 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
195 assert(0);
196 return NULL;
197 }
198 pipe_shader_state_from_tgsi(&state, tokens);
199 return pipe->create_gs_state(pipe, &state);
200 }
201
202 static void
ureg_load_tex(struct ureg_program * ureg,struct ureg_dst out,struct ureg_src coord,struct ureg_src sampler,enum tgsi_texture_type tex_target,bool load_level_zero,bool use_txf)203 ureg_load_tex(struct ureg_program *ureg, struct ureg_dst out,
204 struct ureg_src coord, struct ureg_src sampler,
205 enum tgsi_texture_type tex_target,
206 bool load_level_zero, bool use_txf)
207 {
208 if (use_txf) {
209 struct ureg_dst temp = ureg_DECL_temporary(ureg);
210
211 /* Nearest filtering floors and then converts to integer, and then
212 * applies clamp to edge as clamp(coord, 0, dim - 1).
213 * u_blitter only uses this when the coordinates are in bounds,
214 * so no clamping is needed and we can use trunc instead of floor. trunc
215 * with f2i will get optimized out in NIR where f2i has round-to-zero
216 * behaviour already.
217 */
218 unsigned wrmask = tex_target == TGSI_TEXTURE_1D ||
219 tex_target == TGSI_TEXTURE_1D_ARRAY ? TGSI_WRITEMASK_X :
220 tex_target == TGSI_TEXTURE_3D ? TGSI_WRITEMASK_XYZ :
221 TGSI_WRITEMASK_XY;
222
223 ureg_MOV(ureg, temp, coord);
224 ureg_TRUNC(ureg, ureg_writemask(temp, wrmask), ureg_src(temp));
225 ureg_F2I(ureg, temp, ureg_src(temp));
226
227 if (load_level_zero)
228 ureg_TXF_LZ(ureg, out, tex_target, ureg_src(temp), sampler);
229 else
230 ureg_TXF(ureg, out, tex_target, ureg_src(temp), sampler);
231 } else {
232 if (load_level_zero)
233 ureg_TEX_LZ(ureg, out, tex_target, coord, sampler);
234 else
235 ureg_TEX(ureg, out, tex_target, coord, sampler);
236 }
237 }
238
239 /**
240 * Make simple fragment texture shader:
241 * TEX TEMP[0], IN[0], SAMP[0], 2D;
242 * .. optional SINT <-> UINT clamping ..
243 * MOV OUT[0], TEMP[0]
244 * END;
245 *
246 * \param tex_target one of TGSI_TEXTURE_x
247 */
248 void *
util_make_fragment_tex_shader(struct pipe_context * pipe,enum tgsi_texture_type tex_target,enum tgsi_return_type stype,enum tgsi_return_type dtype,bool load_level_zero,bool use_txf)249 util_make_fragment_tex_shader(struct pipe_context *pipe,
250 enum tgsi_texture_type tex_target,
251 enum tgsi_return_type stype,
252 enum tgsi_return_type dtype,
253 bool load_level_zero,
254 bool use_txf)
255 {
256 struct ureg_program *ureg;
257 struct ureg_src sampler;
258 struct ureg_src tex;
259 struct ureg_dst temp;
260 struct ureg_dst out;
261
262 assert((stype == TGSI_RETURN_TYPE_FLOAT) == (dtype == TGSI_RETURN_TYPE_FLOAT));
263
264 ureg = ureg_create( PIPE_SHADER_FRAGMENT );
265 if (!ureg)
266 return NULL;
267
268 sampler = ureg_DECL_sampler( ureg, 0 );
269
270 ureg_DECL_sampler_view(ureg, 0, tex_target, stype, stype, stype, stype);
271
272 tex = ureg_DECL_fs_input( ureg,
273 TGSI_SEMANTIC_GENERIC, 0,
274 TGSI_INTERPOLATE_LINEAR );
275
276 out = ureg_DECL_output( ureg,
277 TGSI_SEMANTIC_COLOR,
278 0 );
279
280 temp = ureg_DECL_temporary(ureg);
281
282 if (tex_target == TGSI_TEXTURE_BUFFER)
283 ureg_TXF(ureg,
284 ureg_writemask(temp, TGSI_WRITEMASK_XYZW),
285 tex_target, tex, sampler);
286 else
287 ureg_load_tex(ureg, ureg_writemask(temp, TGSI_WRITEMASK_XYZW), tex, sampler,
288 tex_target, load_level_zero, use_txf);
289
290 if (stype != dtype) {
291 if (stype == TGSI_RETURN_TYPE_SINT) {
292 assert(dtype == TGSI_RETURN_TYPE_UINT);
293
294 ureg_IMAX(ureg, temp, ureg_src(temp), ureg_imm1i(ureg, 0));
295 } else {
296 assert(stype == TGSI_RETURN_TYPE_UINT);
297 assert(dtype == TGSI_RETURN_TYPE_SINT);
298
299 ureg_UMIN(ureg, temp, ureg_src(temp), ureg_imm1u(ureg, (1u << 31) - 1));
300 }
301 }
302
303 ureg_MOV(ureg, out, ureg_src(temp));
304
305 ureg_END( ureg );
306
307 return ureg_create_shader_and_destroy( ureg, pipe );
308 }
309
310 /**
311 * Make a simple fragment texture shader which reads the texture unit 0 and 1
312 * and writes it as depth and stencil, respectively.
313 */
314 void *
util_make_fs_blit_zs(struct pipe_context * pipe,unsigned zs_mask,enum tgsi_texture_type tex_target,bool load_level_zero,bool use_txf)315 util_make_fs_blit_zs(struct pipe_context *pipe, unsigned zs_mask,
316 enum tgsi_texture_type tex_target,
317 bool load_level_zero, bool use_txf)
318 {
319 struct ureg_program *ureg;
320 struct ureg_src depth_sampler, stencil_sampler, coord;
321 struct ureg_dst depth, stencil, tmp;
322
323 ureg = ureg_create(PIPE_SHADER_FRAGMENT);
324 if (!ureg)
325 return NULL;
326
327 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
328 TGSI_INTERPOLATE_LINEAR);
329 tmp = ureg_DECL_temporary(ureg);
330
331 if (zs_mask & PIPE_MASK_Z) {
332 depth_sampler = ureg_DECL_sampler(ureg, 0);
333 ureg_DECL_sampler_view(ureg, 0, tex_target,
334 TGSI_RETURN_TYPE_FLOAT,
335 TGSI_RETURN_TYPE_FLOAT,
336 TGSI_RETURN_TYPE_FLOAT,
337 TGSI_RETURN_TYPE_FLOAT);
338
339 ureg_load_tex(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), coord,
340 depth_sampler, tex_target, load_level_zero, use_txf);
341
342 depth = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
343 ureg_MOV(ureg, ureg_writemask(depth, TGSI_WRITEMASK_Z),
344 ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
345 }
346
347 if (zs_mask & PIPE_MASK_S) {
348 stencil_sampler = ureg_DECL_sampler(ureg, zs_mask & PIPE_MASK_Z ? 1 : 0);
349 ureg_DECL_sampler_view(ureg, zs_mask & PIPE_MASK_Z ? 1 : 0, tex_target,
350 TGSI_RETURN_TYPE_UINT,
351 TGSI_RETURN_TYPE_UINT,
352 TGSI_RETURN_TYPE_UINT,
353 TGSI_RETURN_TYPE_UINT);
354
355 ureg_load_tex(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), coord,
356 stencil_sampler, tex_target, load_level_zero, use_txf);
357
358 stencil = ureg_DECL_output(ureg, TGSI_SEMANTIC_STENCIL, 0);
359 ureg_MOV(ureg, ureg_writemask(stencil, TGSI_WRITEMASK_Y),
360 ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
361 }
362
363 ureg_END(ureg);
364
365 return ureg_create_shader_and_destroy(ureg, pipe);
366 }
367
368
369 /**
370 * Make simple fragment color pass-through shader that replicates OUT[0]
371 * to all bound colorbuffers.
372 */
373 void *
util_make_fragment_passthrough_shader(struct pipe_context * pipe,int input_semantic,int input_interpolate,bool write_all_cbufs)374 util_make_fragment_passthrough_shader(struct pipe_context *pipe,
375 int input_semantic,
376 int input_interpolate,
377 bool write_all_cbufs)
378 {
379 static const char shader_templ[] =
380 "FRAG\n"
381 "%s"
382 "DCL IN[0], %s[0], %s\n"
383 "DCL OUT[0], COLOR[0]\n"
384
385 "MOV OUT[0], IN[0]\n"
386 "END\n";
387
388 char text[sizeof(shader_templ)+100];
389 struct tgsi_token tokens[1000];
390 struct pipe_shader_state state = {0};
391
392 sprintf(text, shader_templ,
393 write_all_cbufs ? "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n" : "",
394 tgsi_semantic_names[input_semantic],
395 tgsi_interpolate_names[input_interpolate]);
396
397 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
398 assert(0);
399 return NULL;
400 }
401 pipe_shader_state_from_tgsi(&state, tokens);
402 #if 0
403 tgsi_dump(state.tokens, 0);
404 #endif
405
406 return pipe->create_fs_state(pipe, &state);
407 }
408
409
410 void *
util_make_empty_fragment_shader(struct pipe_context * pipe)411 util_make_empty_fragment_shader(struct pipe_context *pipe)
412 {
413 struct ureg_program *ureg = ureg_create(PIPE_SHADER_FRAGMENT);
414 if (!ureg)
415 return NULL;
416
417 ureg_END(ureg);
418 return ureg_create_shader_and_destroy(ureg, pipe);
419 }
420
421
422 /**
423 * Make a fragment shader that copies the input color to N output colors.
424 */
425 void *
util_make_fragment_cloneinput_shader(struct pipe_context * pipe,int num_cbufs,int input_semantic,int input_interpolate)426 util_make_fragment_cloneinput_shader(struct pipe_context *pipe, int num_cbufs,
427 int input_semantic,
428 int input_interpolate)
429 {
430 struct ureg_program *ureg;
431 struct ureg_src src;
432 struct ureg_dst dst[PIPE_MAX_COLOR_BUFS];
433 int i;
434
435 assert(num_cbufs <= PIPE_MAX_COLOR_BUFS);
436
437 ureg = ureg_create( PIPE_SHADER_FRAGMENT );
438 if (!ureg)
439 return NULL;
440
441 src = ureg_DECL_fs_input( ureg, input_semantic, 0,
442 input_interpolate );
443
444 for (i = 0; i < num_cbufs; i++)
445 dst[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, i );
446
447 for (i = 0; i < num_cbufs; i++)
448 ureg_MOV( ureg, dst[i], src );
449
450 ureg_END( ureg );
451
452 return ureg_create_shader_and_destroy( ureg, pipe );
453 }
454
455
456 static void *
util_make_fs_blit_msaa_gen(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,bool sample_shading,bool has_txq,const char * samp_type,const char * output_semantic,const char * output_mask,const char * conversion)457 util_make_fs_blit_msaa_gen(struct pipe_context *pipe,
458 enum tgsi_texture_type tgsi_tex,
459 bool sample_shading, bool has_txq,
460 const char *samp_type,
461 const char *output_semantic,
462 const char *output_mask,
463 const char *conversion)
464 {
465 char text[1000];
466 struct tgsi_token tokens[1000];
467 struct pipe_shader_state state = {0};
468
469 if (has_txq) {
470 static const char shader_templ[] =
471 "FRAG\n"
472 "DCL IN[0], GENERIC[0], LINEAR\n"
473 "DCL SAMP[0]\n"
474 "DCL SVIEW[0], %s, %s\n"
475 "DCL OUT[0], %s\n"
476 "DCL TEMP[0..1]\n"
477 "IMM[0] INT32 {0, -1, 2147483647, 0}\n"
478 "%s"
479
480 /* Nearest filtering floors and then converts to integer, and then
481 * applies clamp to edge as clamp(coord, 0, dim - 1).
482 */
483 "MOV TEMP[0], IN[0]\n"
484 "FLR TEMP[0].xy, TEMP[0]\n"
485 "F2I TEMP[0], TEMP[0]\n"
486 "IMAX TEMP[0].xy, TEMP[0], IMM[0].xxxx\n"
487 /* Clamp to edge for the upper bound. */
488 "TXQ TEMP[1].xy, IMM[0].xxxx, SAMP[0], %s\n"
489 "UADD TEMP[1].xy, TEMP[1], IMM[0].yyyy\n" /* width - 1, height - 1 */
490 "IMIN TEMP[0].xy, TEMP[0], TEMP[1]\n"
491 /* Texel fetch. */
492 "%s"
493 "TXF TEMP[0], TEMP[0], SAMP[0], %s\n"
494 "%s"
495 "MOV OUT[0]%s, TEMP[0]\n"
496 "END\n";
497
498 const char *type = tgsi_texture_names[tgsi_tex];
499
500 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
501 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
502
503 snprintf(text, sizeof(text), shader_templ, type, samp_type,
504 output_semantic, sample_shading ? "DCL SV[0], SAMPLEID\n" : "",
505 type, sample_shading ? "MOV TEMP[0].w, SV[0].xxxx\n" : "",
506 type, conversion, output_mask);
507 } else {
508 static const char shader_templ[] =
509 "FRAG\n"
510 "DCL IN[0], GENERIC[0], LINEAR\n"
511 "DCL SAMP[0]\n"
512 "DCL SVIEW[0], %s, %s\n"
513 "DCL OUT[0], %s\n"
514 "DCL TEMP[0..1]\n"
515 "IMM[0] INT32 {0, -1, 2147483647, 0}\n"
516 "%s"
517
518 /* Nearest filtering floors and then converts to integer, and then
519 * applies clamp to edge as clamp(coord, 0, dim - 1). Don't clamp
520 * to dim - 1 because TXQ is unsupported.
521 */
522 "MOV TEMP[0], IN[0]\n"
523 "FLR TEMP[0].xy, TEMP[0]\n"
524 "F2I TEMP[0], TEMP[0]\n"
525 "IMAX TEMP[0].xy, TEMP[0], IMM[0].xxxx\n"
526 /* Texel fetch. */
527 "%s"
528 "TXF TEMP[0], TEMP[0], SAMP[0], %s\n"
529 "%s"
530 "MOV OUT[0]%s, TEMP[0]\n"
531 "END\n";
532
533 const char *type = tgsi_texture_names[tgsi_tex];
534
535 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
536 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
537
538 snprintf(text, sizeof(text), shader_templ, type, samp_type,
539 output_semantic, sample_shading ? "DCL SV[0], SAMPLEID\n" : "",
540 sample_shading ? "MOV TEMP[0].w, SV[0].xxxx\n" : "",
541 type, conversion, output_mask);
542 }
543
544 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
545 puts(text);
546 assert(0);
547 return NULL;
548 }
549 pipe_shader_state_from_tgsi(&state, tokens);
550 #if 0
551 tgsi_dump(state.tokens, 0);
552 #endif
553
554 return pipe->create_fs_state(pipe, &state);
555 }
556
557
558 /**
559 * Make a fragment shader that sets the output color to a color
560 * fetched from a multisample texture.
561 * \param tex_target one of PIPE_TEXTURE_x
562 */
563 void *
util_make_fs_blit_msaa_color(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,enum tgsi_return_type stype,enum tgsi_return_type dtype,bool sample_shading,bool has_txq)564 util_make_fs_blit_msaa_color(struct pipe_context *pipe,
565 enum tgsi_texture_type tgsi_tex,
566 enum tgsi_return_type stype,
567 enum tgsi_return_type dtype,
568 bool sample_shading, bool has_txq)
569 {
570 const char *samp_type;
571 const char *conversion = "";
572
573 if (stype == TGSI_RETURN_TYPE_UINT) {
574 samp_type = "UINT";
575
576 if (dtype == TGSI_RETURN_TYPE_SINT) {
577 conversion = "UMIN TEMP[0], TEMP[0], IMM[0].zzzz\n";
578 }
579 } else if (stype == TGSI_RETURN_TYPE_SINT) {
580 samp_type = "SINT";
581
582 if (dtype == TGSI_RETURN_TYPE_UINT) {
583 conversion = "IMAX TEMP[0], TEMP[0], IMM[0].xxxx\n";
584 }
585 } else {
586 assert(dtype == TGSI_RETURN_TYPE_FLOAT);
587 samp_type = "FLOAT";
588 }
589
590 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, sample_shading, has_txq,
591 samp_type, "COLOR[0]", "", conversion);
592 }
593
594
595 /**
596 * Make a fragment shader that sets the output depth to a depth value
597 * fetched from a multisample texture.
598 * \param tex_target one of PIPE_TEXTURE_x
599 */
600 void *
util_make_fs_blit_msaa_depth(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,bool sample_shading,bool has_txq)601 util_make_fs_blit_msaa_depth(struct pipe_context *pipe,
602 enum tgsi_texture_type tgsi_tex,
603 bool sample_shading, bool has_txq)
604 {
605 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, sample_shading, has_txq,
606 "FLOAT", "POSITION", ".z",
607 "MOV TEMP[0].z, TEMP[0].xxxx\n");
608 }
609
610
611 /**
612 * Make a fragment shader that sets the output stencil to a stencil value
613 * fetched from a multisample texture.
614 * \param tex_target one of PIPE_TEXTURE_x
615 */
616 void *
util_make_fs_blit_msaa_stencil(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,bool sample_shading,bool has_txq)617 util_make_fs_blit_msaa_stencil(struct pipe_context *pipe,
618 enum tgsi_texture_type tgsi_tex,
619 bool sample_shading, bool has_txq)
620 {
621 return util_make_fs_blit_msaa_gen(pipe, tgsi_tex, sample_shading, has_txq,
622 "UINT", "STENCIL", ".y",
623 "MOV TEMP[0].y, TEMP[0].xxxx\n");
624 }
625
626
627 /**
628 * Make a fragment shader that sets the output depth and stencil to depth
629 * and stencil values fetched from two multisample textures / samplers.
630 * The sizes of both textures should match (it should be one depth-stencil
631 * texture).
632 * \param tex_target one of PIPE_TEXTURE_x
633 */
634 void *
util_make_fs_blit_msaa_depthstencil(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,bool sample_shading,bool has_txq)635 util_make_fs_blit_msaa_depthstencil(struct pipe_context *pipe,
636 enum tgsi_texture_type tgsi_tex,
637 bool sample_shading, bool has_txq)
638 {
639 const char *type = tgsi_texture_names[tgsi_tex];
640 char text[1000];
641 struct tgsi_token tokens[1000];
642 struct pipe_shader_state state = {0};
643
644 assert(tgsi_tex == TGSI_TEXTURE_2D_MSAA ||
645 tgsi_tex == TGSI_TEXTURE_2D_ARRAY_MSAA);
646
647 if (has_txq) {
648 static const char shader_templ[] =
649 "FRAG\n"
650 "DCL IN[0], GENERIC[0], LINEAR\n"
651 "DCL SAMP[0..1]\n"
652 "DCL SVIEW[0], %s, FLOAT\n"
653 "DCL SVIEW[1], %s, UINT\n"
654 "DCL OUT[0], POSITION\n"
655 "DCL OUT[1], STENCIL\n"
656 "DCL TEMP[0..1]\n"
657 "IMM[0] INT32 {0, -1, 0, 0}\n"
658 "%s"
659
660 /* Nearest filtering floors and then converts to integer, and then
661 * applies clamp to edge as clamp(coord, 0, dim - 1).
662 */
663 "MOV TEMP[0], IN[0]\n"
664 "FLR TEMP[0].xy, TEMP[0]\n"
665 "F2I TEMP[0], TEMP[0]\n"
666 "IMAX TEMP[0].xy, TEMP[0], IMM[0].xxxx\n"
667 /* Clamp to edge for the upper bound. */
668 "TXQ TEMP[1].xy, IMM[0].xxxx, SAMP[0], %s\n"
669 "UADD TEMP[1].xy, TEMP[1], IMM[0].yyyy\n" /* width - 1, height - 1 */
670 "IMIN TEMP[0].xy, TEMP[0], TEMP[1]\n"
671 /* Texel fetch. */
672 "%s"
673 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n"
674 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n"
675 "END\n";
676
677 sprintf(text, shader_templ, type, type,
678 sample_shading ? "DCL SV[0], SAMPLEID\n" : "", type,
679 sample_shading ? "MOV TEMP[0].w, SV[0].xxxx\n" : "",
680 type, type);
681 } else {
682 static const char shader_templ[] =
683 "FRAG\n"
684 "DCL IN[0], GENERIC[0], LINEAR\n"
685 "DCL SAMP[0..1]\n"
686 "DCL SVIEW[0], %s, FLOAT\n"
687 "DCL SVIEW[1], %s, UINT\n"
688 "DCL OUT[0], POSITION\n"
689 "DCL OUT[1], STENCIL\n"
690 "DCL TEMP[0..1]\n"
691 "IMM[0] INT32 {0, -1, 0, 0}\n"
692 "%s"
693
694 /* Nearest filtering floors and then converts to integer, and then
695 * applies clamp to edge as clamp(coord, 0, dim - 1). Don't clamp
696 * to dim - 1 because TXQ is unsupported.
697 */
698 "MOV TEMP[0], IN[0]\n"
699 "FLR TEMP[0].xy, TEMP[0]\n"
700 "F2I TEMP[0], TEMP[0]\n"
701 "IMAX TEMP[0].xy, TEMP[0], IMM[0].xxxx\n"
702 /* Texel fetch. */
703 "%s"
704 "TXF OUT[0].z, TEMP[0], SAMP[0], %s\n"
705 "TXF OUT[1].y, TEMP[0], SAMP[1], %s\n"
706 "END\n";
707
708 sprintf(text, shader_templ, type, type,
709 sample_shading ? "DCL SV[0], SAMPLEID\n" : "",
710 sample_shading ? "MOV TEMP[0].w, SV[0].xxxx\n" : "",
711 type, type);
712 }
713
714 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
715 assert(0);
716 return NULL;
717 }
718 pipe_shader_state_from_tgsi(&state, tokens);
719 #if 0
720 tgsi_dump(state.tokens, 0);
721 #endif
722
723 return pipe->create_fs_state(pipe, &state);
724 }
725
726
727 void *
util_make_fs_msaa_resolve(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,unsigned nr_samples,bool has_txq)728 util_make_fs_msaa_resolve(struct pipe_context *pipe,
729 enum tgsi_texture_type tgsi_tex, unsigned nr_samples,
730 bool has_txq)
731 {
732 struct ureg_program *ureg;
733 struct ureg_src sampler, coord;
734 struct ureg_dst out, tmp_sum, tmp_coord, tmp;
735 unsigned i;
736
737 ureg = ureg_create(PIPE_SHADER_FRAGMENT);
738 if (!ureg)
739 return NULL;
740
741 /* Declarations. */
742 sampler = ureg_DECL_sampler(ureg, 0);
743 ureg_DECL_sampler_view(ureg, 0, tgsi_tex,
744 TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT,
745 TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT);
746 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
747 TGSI_INTERPOLATE_LINEAR);
748 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
749 tmp_sum = ureg_DECL_temporary(ureg);
750 tmp_coord = ureg_DECL_temporary(ureg);
751 tmp = ureg_DECL_temporary(ureg);
752
753 /* Instructions. */
754 ureg_MOV(ureg, tmp_sum, ureg_imm1f(ureg, 0));
755
756 /* Nearest filtering floors and then converts to integer, and then
757 * applies clamp to edge as clamp(coord, 0, dim - 1).
758 */
759 ureg_MOV(ureg, tmp_coord, coord);
760 ureg_FLR(ureg, ureg_writemask(tmp_coord, TGSI_WRITEMASK_XY),
761 ureg_src(tmp_coord));
762 ureg_F2I(ureg, tmp_coord, ureg_src(tmp_coord));
763 ureg_IMAX(ureg, tmp_coord, ureg_src(tmp_coord), ureg_imm1i(ureg, 0));
764
765 /* Clamp to edge for the upper bound. */
766 if (has_txq) {
767 ureg_TXQ(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XY), tgsi_tex,
768 ureg_imm1u(ureg, 0), sampler);
769 ureg_UADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp),
770 ureg_imm2i(ureg, -1, -1)); /* width - 1, height - 1 */
771 ureg_IMIN(ureg, ureg_writemask(tmp_coord, TGSI_WRITEMASK_XY),
772 ureg_src(tmp_coord), ureg_src(tmp));
773 }
774
775 for (i = 0; i < nr_samples; i++) {
776 /* Read one sample. */
777 ureg_MOV(ureg, ureg_writemask(tmp_coord, TGSI_WRITEMASK_W),
778 ureg_imm1u(ureg, i));
779 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord), sampler);
780
781 /* Add it to the sum.*/
782 ureg_ADD(ureg, tmp_sum, ureg_src(tmp_sum), ureg_src(tmp));
783 }
784
785 /* Calculate the average and return. */
786 ureg_MUL(ureg, out, ureg_src(tmp_sum),
787 ureg_imm1f(ureg, 1.0 / nr_samples));
788 ureg_END(ureg);
789
790 return ureg_create_shader_and_destroy(ureg, pipe);
791 }
792
793
794 void *
util_make_fs_msaa_resolve_bilinear(struct pipe_context * pipe,enum tgsi_texture_type tgsi_tex,unsigned nr_samples,bool has_txq)795 util_make_fs_msaa_resolve_bilinear(struct pipe_context *pipe,
796 enum tgsi_texture_type tgsi_tex,
797 unsigned nr_samples, bool has_txq)
798 {
799 struct ureg_program *ureg;
800 struct ureg_src sampler, coord;
801 struct ureg_dst out, tmp, top, bottom;
802 struct ureg_dst tmp_coord[4], tmp_sum[4], weights;
803 unsigned i, c;
804
805 ureg = ureg_create(PIPE_SHADER_FRAGMENT);
806 if (!ureg)
807 return NULL;
808
809 /* Declarations. */
810 sampler = ureg_DECL_sampler(ureg, 0);
811 ureg_DECL_sampler_view(ureg, 0, tgsi_tex,
812 TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT,
813 TGSI_RETURN_TYPE_FLOAT, TGSI_RETURN_TYPE_FLOAT);
814 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
815 TGSI_INTERPOLATE_LINEAR);
816 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
817 for (c = 0; c < 4; c++)
818 tmp_sum[c] = ureg_DECL_temporary(ureg);
819 for (c = 0; c < 4; c++)
820 tmp_coord[c] = ureg_DECL_temporary(ureg);
821 tmp = ureg_DECL_temporary(ureg);
822 top = ureg_DECL_temporary(ureg);
823 weights = ureg_DECL_temporary(ureg);
824 bottom = ureg_DECL_temporary(ureg);
825
826 /* Instructions. */
827 for (c = 0; c < 4; c++)
828 ureg_MOV(ureg, tmp_sum[c], ureg_imm1f(ureg, 0));
829
830 /* Bilinear filtering starts with subtracting 0.5 from unnormalized
831 * coordinates.
832 */
833 ureg_MOV(ureg, ureg_writemask(tmp_coord[0], TGSI_WRITEMASK_ZW), coord);
834 ureg_ADD(ureg, ureg_writemask(tmp_coord[0], TGSI_WRITEMASK_XY), coord,
835 ureg_imm2f(ureg, -0.5, -0.5));
836
837 /* Get the filter weights. */
838 ureg_FRC(ureg, ureg_writemask(weights, TGSI_WRITEMASK_XY),
839 ureg_src(tmp_coord[0]));
840
841 /* Convert to integer by flooring to get the top-left coordinates. */
842 ureg_FLR(ureg, ureg_writemask(tmp_coord[0], TGSI_WRITEMASK_XY),
843 ureg_src(tmp_coord[0]));
844 ureg_F2I(ureg, tmp_coord[0], ureg_src(tmp_coord[0]));
845
846 /* Get the bottom-right coordinates. */
847 ureg_UADD(ureg, tmp_coord[3], ureg_src(tmp_coord[0]),
848 ureg_imm4u(ureg, 1, 1, 0, 0)); /* bottom-right */
849
850 /* Clamp to edge. */
851 if (has_txq) {
852 ureg_TXQ(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XY), tgsi_tex,
853 ureg_imm1u(ureg, 0), sampler);
854 ureg_UADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XY), ureg_src(tmp),
855 ureg_imm2i(ureg, -1, -1)); /* width - 1, height - 1 */
856
857 ureg_IMIN(ureg, ureg_writemask(tmp_coord[0], TGSI_WRITEMASK_XY),
858 ureg_src(tmp_coord[0]), ureg_src(tmp));
859 ureg_IMIN(ureg, ureg_writemask(tmp_coord[3], TGSI_WRITEMASK_XY),
860 ureg_src(tmp_coord[3]), ureg_src(tmp));
861 }
862
863 ureg_IMAX(ureg, ureg_writemask(tmp_coord[0], TGSI_WRITEMASK_XY),
864 ureg_src(tmp_coord[0]), ureg_imm2i(ureg, 0, 0));
865 ureg_IMAX(ureg, ureg_writemask(tmp_coord[3], TGSI_WRITEMASK_XY),
866 ureg_src(tmp_coord[3]), ureg_imm2i(ureg, 0, 0));
867
868 /* Get the remaining top-right and bottom-left coordinates. */
869 ureg_MOV(ureg, ureg_writemask(tmp_coord[1], TGSI_WRITEMASK_X),
870 ureg_src(tmp_coord[3]));
871 ureg_MOV(ureg, ureg_writemask(tmp_coord[1], TGSI_WRITEMASK_YZW),
872 ureg_src(tmp_coord[0])); /* top-right */
873
874 ureg_MOV(ureg, ureg_writemask(tmp_coord[2], TGSI_WRITEMASK_Y),
875 ureg_src(tmp_coord[3]));
876 ureg_MOV(ureg, ureg_writemask(tmp_coord[2], TGSI_WRITEMASK_XZW),
877 ureg_src(tmp_coord[0])); /* bottom-left */
878
879 for (i = 0; i < nr_samples; i++) {
880 for (c = 0; c < 4; c++) {
881 /* Read one sample. */
882 ureg_MOV(ureg, ureg_writemask(tmp_coord[c], TGSI_WRITEMASK_W),
883 ureg_imm1u(ureg, i));
884 ureg_TXF(ureg, tmp, tgsi_tex, ureg_src(tmp_coord[c]), sampler);
885
886 /* Add it to the sum.*/
887 ureg_ADD(ureg, tmp_sum[c], ureg_src(tmp_sum[c]), ureg_src(tmp));
888 }
889 }
890
891 /* Calculate the average. */
892 for (c = 0; c < 4; c++)
893 ureg_MUL(ureg, tmp_sum[c], ureg_src(tmp_sum[c]),
894 ureg_imm1f(ureg, 1.0 / nr_samples));
895
896 /* Take the 4 average values and apply a standard bilinear filter. */
897 ureg_LRP(ureg, top,
898 ureg_scalar(ureg_src(weights), 0),
899 ureg_src(tmp_sum[1]),
900 ureg_src(tmp_sum[0]));
901
902 ureg_LRP(ureg, bottom,
903 ureg_scalar(ureg_src(weights), 0),
904 ureg_src(tmp_sum[3]),
905 ureg_src(tmp_sum[2]));
906
907 ureg_LRP(ureg, out,
908 ureg_scalar(ureg_src(weights), 1),
909 ureg_src(bottom),
910 ureg_src(top));
911 ureg_END(ureg);
912
913 return ureg_create_shader_and_destroy(ureg, pipe);
914 }
915
916 void *
util_make_geometry_passthrough_shader(struct pipe_context * pipe,unsigned num_attribs,const uint8_t * semantic_names,const uint8_t * semantic_indexes)917 util_make_geometry_passthrough_shader(struct pipe_context *pipe,
918 unsigned num_attribs,
919 const uint8_t *semantic_names,
920 const uint8_t *semantic_indexes)
921 {
922 static const unsigned zero[4] = {0, 0, 0, 0};
923
924 struct ureg_program *ureg;
925 struct ureg_dst dst[PIPE_MAX_SHADER_OUTPUTS];
926 struct ureg_src src[PIPE_MAX_SHADER_INPUTS];
927 struct ureg_src imm;
928
929 unsigned i;
930
931 ureg = ureg_create(PIPE_SHADER_GEOMETRY);
932 if (!ureg)
933 return NULL;
934
935 ureg_property(ureg, TGSI_PROPERTY_GS_INPUT_PRIM, MESA_PRIM_POINTS);
936 ureg_property(ureg, TGSI_PROPERTY_GS_OUTPUT_PRIM, MESA_PRIM_POINTS);
937 ureg_property(ureg, TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES, 1);
938 ureg_property(ureg, TGSI_PROPERTY_GS_INVOCATIONS, 1);
939 imm = ureg_DECL_immediate_uint(ureg, zero, 4);
940
941 /**
942 * Loop over all the attribs and declare the corresponding
943 * declarations in the geometry shader
944 */
945 for (i = 0; i < num_attribs; i++) {
946 src[i] = ureg_DECL_input(ureg, semantic_names[i],
947 semantic_indexes[i], 0, 1);
948 src[i] = ureg_src_dimension(src[i], 0);
949 dst[i] = ureg_DECL_output(ureg, semantic_names[i], semantic_indexes[i]);
950 }
951
952 /* MOV dst[i] src[i] */
953 for (i = 0; i < num_attribs; i++) {
954 ureg_MOV(ureg, dst[i], src[i]);
955 }
956
957 /* EMIT IMM[0] */
958 ureg_insn(ureg, TGSI_OPCODE_EMIT, NULL, 0, &imm, 1, 0);
959
960 /* END */
961 ureg_END(ureg);
962
963 return ureg_create_shader_and_destroy(ureg, pipe);
964 }
965
966
967 /**
968 * Blit from color to ZS or from ZS to color in a manner that is equivalent
969 * to memcpy.
970 *
971 * Color is either R32_UINT (for Z24S8 / S8Z24) or R32G32_UINT (Z32_S8X24).
972 *
973 * Depth and stencil samplers are used to load depth and stencil,
974 * and they are packed and the result is written to a color output.
975 * OR
976 * A color sampler is used to load a color value, which is unpacked and
977 * written to depth and stencil shader outputs.
978 */
979 void *
util_make_fs_pack_color_zs(struct pipe_context * pipe,enum tgsi_texture_type tex_target,enum pipe_format zs_format,bool dst_is_color)980 util_make_fs_pack_color_zs(struct pipe_context *pipe,
981 enum tgsi_texture_type tex_target,
982 enum pipe_format zs_format,
983 bool dst_is_color)
984 {
985 struct ureg_program *ureg;
986 struct ureg_src depth_sampler, stencil_sampler, color_sampler, coord;
987 struct ureg_dst out, depth, depth_x, stencil, out_depth, out_stencil, color;
988
989 assert(zs_format == PIPE_FORMAT_Z24_UNORM_S8_UINT || /* color is R32_UINT */
990 zs_format == PIPE_FORMAT_S8_UINT_Z24_UNORM || /* color is R32_UINT */
991 zs_format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT || /* color is R32G32_UINT */
992 zs_format == PIPE_FORMAT_Z24X8_UNORM || /* color is R32_UINT */
993 zs_format == PIPE_FORMAT_X8Z24_UNORM); /* color is R32_UINT */
994
995 bool has_stencil = zs_format != PIPE_FORMAT_Z24X8_UNORM &&
996 zs_format != PIPE_FORMAT_X8Z24_UNORM;
997 bool is_z24 = zs_format != PIPE_FORMAT_Z32_FLOAT_S8X24_UINT;
998 bool z24_is_high = zs_format == PIPE_FORMAT_S8_UINT_Z24_UNORM ||
999 zs_format == PIPE_FORMAT_X8Z24_UNORM;
1000
1001 ureg = ureg_create(PIPE_SHADER_FRAGMENT);
1002 if (!ureg)
1003 return NULL;
1004
1005 coord = ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_GENERIC, 0,
1006 TGSI_INTERPOLATE_LINEAR);
1007
1008 if (dst_is_color) {
1009 /* Load depth. */
1010 depth_sampler = ureg_DECL_sampler(ureg, 0);
1011 ureg_DECL_sampler_view(ureg, 0, tex_target,
1012 TGSI_RETURN_TYPE_FLOAT,
1013 TGSI_RETURN_TYPE_FLOAT,
1014 TGSI_RETURN_TYPE_FLOAT,
1015 TGSI_RETURN_TYPE_FLOAT);
1016
1017 depth = ureg_DECL_temporary(ureg);
1018 depth_x = ureg_writemask(depth, TGSI_WRITEMASK_X);
1019 ureg_load_tex(ureg, depth_x, coord, depth_sampler, tex_target, true, true);
1020
1021 /* Pack to Z24. */
1022 if (is_z24) {
1023 double imm = 0xffffff;
1024 struct ureg_src imm_f64 = ureg_DECL_immediate_f64(ureg, &imm, 2);
1025 struct ureg_dst tmp_xy = ureg_writemask(ureg_DECL_temporary(ureg),
1026 TGSI_WRITEMASK_XY);
1027
1028 ureg_F2D(ureg, tmp_xy, ureg_src(depth));
1029 ureg_DMUL(ureg, tmp_xy, ureg_src(tmp_xy), imm_f64);
1030 ureg_D2U(ureg, depth_x, ureg_src(tmp_xy));
1031
1032 if (z24_is_high)
1033 ureg_SHL(ureg, depth_x, ureg_src(depth), ureg_imm1u(ureg, 8));
1034 else
1035 ureg_AND(ureg, depth_x, ureg_src(depth), ureg_imm1u(ureg, 0xffffff));
1036 }
1037
1038 if (has_stencil) {
1039 /* Load stencil. */
1040 stencil_sampler = ureg_DECL_sampler(ureg, 1);
1041 ureg_DECL_sampler_view(ureg, 0, tex_target,
1042 TGSI_RETURN_TYPE_UINT,
1043 TGSI_RETURN_TYPE_UINT,
1044 TGSI_RETURN_TYPE_UINT,
1045 TGSI_RETURN_TYPE_UINT);
1046
1047 stencil = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_X);
1048 ureg_load_tex(ureg, stencil, coord, stencil_sampler, tex_target,
1049 true, true);
1050
1051 /* Pack stencil into depth. */
1052 if (is_z24) {
1053 if (!z24_is_high)
1054 ureg_SHL(ureg, stencil, ureg_src(stencil), ureg_imm1u(ureg, 24));
1055
1056 ureg_OR(ureg, depth_x, ureg_src(depth), ureg_src(stencil));
1057 }
1058 }
1059
1060 out = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0);
1061
1062 if (is_z24) {
1063 ureg_MOV(ureg, ureg_writemask(out, TGSI_WRITEMASK_X), ureg_src(depth));
1064 } else {
1065 /* Z32_S8X24 */
1066 ureg_MOV(ureg, ureg_writemask(depth, TGSI_WRITEMASK_Y),
1067 ureg_scalar(ureg_src(stencil), TGSI_SWIZZLE_X));
1068 ureg_MOV(ureg, ureg_writemask(out, TGSI_WRITEMASK_XY), ureg_src(depth));
1069 }
1070 } else {
1071 color_sampler = ureg_DECL_sampler(ureg, 0);
1072 ureg_DECL_sampler_view(ureg, 0, tex_target,
1073 TGSI_RETURN_TYPE_UINT,
1074 TGSI_RETURN_TYPE_UINT,
1075 TGSI_RETURN_TYPE_UINT,
1076 TGSI_RETURN_TYPE_UINT);
1077
1078 color = ureg_DECL_temporary(ureg);
1079 ureg_load_tex(ureg, color, coord, color_sampler, tex_target, true, true);
1080
1081 depth = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_X);
1082 stencil = ureg_writemask(ureg_DECL_temporary(ureg), TGSI_WRITEMASK_X);
1083
1084 if (is_z24) {
1085 double imm = 1.0 / 0xffffff;
1086 struct ureg_src imm_f64 = ureg_DECL_immediate_f64(ureg, &imm, 2);
1087 struct ureg_dst tmp_xy = ureg_writemask(ureg_DECL_temporary(ureg),
1088 TGSI_WRITEMASK_XY);
1089
1090 ureg_UBFE(ureg, depth, ureg_src(color),
1091 ureg_imm1u(ureg, z24_is_high ? 8 : 0),
1092 ureg_imm1u(ureg, 24));
1093 ureg_U2D(ureg, tmp_xy, ureg_src(depth));
1094 ureg_DMUL(ureg, tmp_xy, ureg_src(tmp_xy), imm_f64);
1095 ureg_D2F(ureg, depth, ureg_src(tmp_xy));
1096 } else {
1097 /* depth = color.x; (Z32_S8X24) */
1098 ureg_MOV(ureg, depth, ureg_src(color));
1099 }
1100
1101 out_depth = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0);
1102 ureg_MOV(ureg, ureg_writemask(out_depth, TGSI_WRITEMASK_Z),
1103 ureg_scalar(ureg_src(depth), TGSI_SWIZZLE_X));
1104
1105 if (has_stencil) {
1106 if (is_z24) {
1107 ureg_UBFE(ureg, stencil, ureg_src(color),
1108 ureg_imm1u(ureg, z24_is_high ? 0 : 24),
1109 ureg_imm1u(ureg, 8));
1110 } else {
1111 /* stencil = color.y[0:7]; (Z32_S8X24) */
1112 ureg_UBFE(ureg, stencil,
1113 ureg_scalar(ureg_src(color), TGSI_SWIZZLE_Y),
1114 ureg_imm1u(ureg, 0),
1115 ureg_imm1u(ureg, 8));
1116 }
1117
1118 out_stencil = ureg_DECL_output(ureg, TGSI_SEMANTIC_STENCIL, 0);
1119 ureg_MOV(ureg, ureg_writemask(out_stencil, TGSI_WRITEMASK_Y),
1120 ureg_scalar(ureg_src(stencil), TGSI_SWIZZLE_X));
1121 }
1122 }
1123
1124 ureg_END(ureg);
1125
1126 return ureg_create_shader_and_destroy(ureg, pipe);
1127 }
1128
1129
1130 /**
1131 * Create passthrough tessellation control shader.
1132 * Passthrough tessellation control shader has output of vertex shader
1133 * as input and input of tessellation eval shader as output.
1134 */
1135 void *
util_make_tess_ctrl_passthrough_shader(struct pipe_context * pipe,unsigned num_vs_outputs,unsigned num_tes_inputs,const uint8_t * vs_semantic_names,const uint8_t * vs_semantic_indexes,const uint8_t * tes_semantic_names,const uint8_t * tes_semantic_indexes,const unsigned vertices_per_patch)1136 util_make_tess_ctrl_passthrough_shader(struct pipe_context *pipe,
1137 unsigned num_vs_outputs,
1138 unsigned num_tes_inputs,
1139 const uint8_t *vs_semantic_names,
1140 const uint8_t *vs_semantic_indexes,
1141 const uint8_t *tes_semantic_names,
1142 const uint8_t *tes_semantic_indexes,
1143 const unsigned vertices_per_patch)
1144 {
1145 unsigned i, j;
1146 unsigned num_regs;
1147
1148 struct ureg_program *ureg;
1149 struct ureg_dst temp, addr;
1150 struct ureg_src invocationID;
1151 struct ureg_dst dst[PIPE_MAX_SHADER_OUTPUTS];
1152 struct ureg_src src[PIPE_MAX_SHADER_INPUTS];
1153
1154 ureg = ureg_create(PIPE_SHADER_TESS_CTRL);
1155
1156 if (!ureg)
1157 return NULL;
1158
1159 ureg_property(ureg, TGSI_PROPERTY_TCS_VERTICES_OUT, vertices_per_patch);
1160
1161 num_regs = 0;
1162
1163 for (i = 0; i < num_tes_inputs; i++) {
1164 switch (tes_semantic_names[i]) {
1165 case TGSI_SEMANTIC_POSITION:
1166 case TGSI_SEMANTIC_PSIZE:
1167 case TGSI_SEMANTIC_COLOR:
1168 case TGSI_SEMANTIC_BCOLOR:
1169 case TGSI_SEMANTIC_CLIPDIST:
1170 case TGSI_SEMANTIC_CLIPVERTEX:
1171 case TGSI_SEMANTIC_TEXCOORD:
1172 case TGSI_SEMANTIC_FOG:
1173 case TGSI_SEMANTIC_GENERIC:
1174 for (j = 0; j < num_vs_outputs; j++) {
1175 if (tes_semantic_names[i] == vs_semantic_names[j] &&
1176 tes_semantic_indexes[i] == vs_semantic_indexes[j]) {
1177
1178 dst[num_regs] = ureg_DECL_output(ureg,
1179 tes_semantic_names[i],
1180 tes_semantic_indexes[i]);
1181 src[num_regs] = ureg_DECL_input(ureg, vs_semantic_names[j],
1182 vs_semantic_indexes[j],
1183 0, 1);
1184
1185 if (tes_semantic_names[i] == TGSI_SEMANTIC_GENERIC ||
1186 tes_semantic_names[i] == TGSI_SEMANTIC_POSITION) {
1187 src[num_regs] = ureg_src_dimension(src[num_regs], 0);
1188 dst[num_regs] = ureg_dst_dimension(dst[num_regs], 0);
1189 }
1190
1191 num_regs++;
1192 break;
1193 }
1194 }
1195 break;
1196 default:
1197 break;
1198 }
1199 }
1200
1201 dst[num_regs] = ureg_DECL_output(ureg, TGSI_SEMANTIC_TESSOUTER,
1202 num_regs);
1203 src[num_regs] = ureg_DECL_constant(ureg, 0);
1204 num_regs++;
1205 dst[num_regs] = ureg_DECL_output(ureg, TGSI_SEMANTIC_TESSINNER,
1206 num_regs);
1207 src[num_regs] = ureg_DECL_constant(ureg, 1);
1208 num_regs++;
1209
1210 if (vertices_per_patch > 1) {
1211 invocationID = ureg_DECL_system_value(ureg,
1212 TGSI_SEMANTIC_INVOCATIONID, 0);
1213 temp = ureg_DECL_local_temporary(ureg);
1214 addr = ureg_DECL_address(ureg);
1215 ureg_UARL(ureg, ureg_writemask(addr, TGSI_WRITEMASK_X),
1216 ureg_scalar(invocationID, TGSI_SWIZZLE_X));
1217 }
1218
1219 for (i = 0; i < num_regs; i++) {
1220 if (dst[i].Dimension && vertices_per_patch > 1) {
1221 struct ureg_src addr_x = ureg_scalar(ureg_src(addr), TGSI_SWIZZLE_X);
1222 ureg_MOV(ureg, temp, ureg_src_dimension_indirect(src[i],
1223 addr_x, 0));
1224 ureg_MOV(ureg, ureg_dst_dimension_indirect(dst[i],
1225 addr_x, 0), ureg_src(temp));
1226 }
1227 else
1228 ureg_MOV(ureg, dst[i], src[i]);
1229 }
1230
1231 ureg_END(ureg);
1232
1233 return ureg_create_shader_and_destroy(ureg, pipe);
1234 }
1235
1236 void *
util_make_fs_stencil_blit(struct pipe_context * pipe,bool msaa_src,bool has_txq)1237 util_make_fs_stencil_blit(struct pipe_context *pipe, bool msaa_src, bool has_txq)
1238 {
1239 char text[1000];
1240 struct tgsi_token tokens[1000];
1241 struct pipe_shader_state state = { 0 };
1242 enum tgsi_texture_type tgsi_tex = msaa_src ? TGSI_TEXTURE_2D_MSAA :
1243 TGSI_TEXTURE_2D;
1244
1245 if (has_txq) {
1246 static const char shader_templ[] =
1247 "FRAG\n"
1248 "DCL IN[0], GENERIC[0], LINEAR\n"
1249 "DCL SAMP[0]\n"
1250 "DCL SVIEW[0], %s, UINT\n"
1251 "DCL CONST[0][0]\n"
1252 "DCL TEMP[0..1]\n"
1253 "IMM[0] INT32 {0, -1, 0, 0}\n"
1254
1255 /* Nearest filtering floors and then converts to integer, and then
1256 * applies clamp to edge as clamp(coord, 0, dim - 1).
1257 */
1258 "MOV TEMP[0], IN[0]\n"
1259 "FLR TEMP[0].xy, TEMP[0]\n"
1260 "F2I TEMP[0], TEMP[0]\n"
1261 "IMAX TEMP[0].xy, TEMP[0], IMM[0].xxxx\n"
1262 /* Clamp to edge for the upper bound. */
1263 "TXQ TEMP[1].xy, IMM[0].xxxx, SAMP[0], %s\n"
1264 "UADD TEMP[1].xy, TEMP[1], IMM[0].yyyy\n" /* width - 1, height - 1 */
1265 "IMIN TEMP[0].xy, TEMP[0], TEMP[1]\n"
1266 /* Texel fetch. */
1267 "TXF_LZ TEMP[0].x, TEMP[0], SAMP[0], %s\n"
1268 "AND TEMP[0].x, TEMP[0], CONST[0][0]\n"
1269 "USNE TEMP[0].x, TEMP[0], CONST[0][0]\n"
1270 "U2F TEMP[0].x, TEMP[0]\n"
1271 "KILL_IF -TEMP[0].xxxx\n"
1272 "END\n";
1273
1274 sprintf(text, shader_templ, tgsi_texture_names[tgsi_tex],
1275 tgsi_texture_names[tgsi_tex], tgsi_texture_names[tgsi_tex]);
1276 } else {
1277 static const char shader_templ[] =
1278 "FRAG\n"
1279 "DCL IN[0], GENERIC[0], LINEAR\n"
1280 "DCL SAMP[0]\n"
1281 "DCL SVIEW[0], %s, UINT\n"
1282 "DCL CONST[0][0]\n"
1283 "DCL TEMP[0..1]\n"
1284 "IMM[0] INT32 {0, -1, 0, 0}\n"
1285
1286 /* Nearest filtering floors and then converts to integer, and then
1287 * applies clamp to edge as clamp(coord, 0, dim - 1).
1288 */
1289 "MOV TEMP[0], IN[0]\n"
1290 "FLR TEMP[0].xy, TEMP[0]\n"
1291 "F2I TEMP[0], TEMP[0]\n"
1292 "IMAX TEMP[0].xy, TEMP[0], IMM[0].xxxx\n"
1293 /* Texel fetch. */
1294 "TXF_LZ TEMP[0].x, TEMP[0], SAMP[0], %s\n"
1295 "AND TEMP[0].x, TEMP[0], CONST[0][0]\n"
1296 "USNE TEMP[0].x, TEMP[0], CONST[0][0]\n"
1297 "U2F TEMP[0].x, TEMP[0]\n"
1298 "KILL_IF -TEMP[0].xxxx\n"
1299 "END\n";
1300
1301 sprintf(text, shader_templ, tgsi_texture_names[tgsi_tex],
1302 tgsi_texture_names[tgsi_tex]);
1303 }
1304
1305 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
1306 assert(0);
1307 return NULL;
1308 }
1309
1310 pipe_shader_state_from_tgsi(&state, tokens);
1311
1312 return pipe->create_fs_state(pipe, &state);
1313 }
1314
1315 void *
util_make_fs_clear_all_cbufs(struct pipe_context * pipe)1316 util_make_fs_clear_all_cbufs(struct pipe_context *pipe)
1317 {
1318 static const char text[] =
1319 "FRAG\n"
1320 "PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1\n"
1321 "DCL OUT[0], COLOR[0]\n"
1322 "DCL CONST[0][0]\n"
1323
1324 "MOV OUT[0], CONST[0][0]\n"
1325 "END\n";
1326
1327 struct tgsi_token tokens[1000];
1328 struct pipe_shader_state state = { 0 };
1329
1330 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
1331 assert(0);
1332 return NULL;
1333 }
1334
1335 pipe_shader_state_from_tgsi(&state, tokens);
1336
1337 return pipe->create_fs_state(pipe, &state);
1338 }
1339