gallium: add pipe_resource::nr_storage_samples, and set it same as nr_samples
[mesa.git] / src / gallium / auxiliary / util / u_tests.c
1 /**************************************************************************
2 *
3 * Copyright 2014 Advanced Micro Devices, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "util/u_tests.h"
29
30 #include "util/u_draw_quad.h"
31 #include "util/u_format.h"
32 #include "util/u_inlines.h"
33 #include "util/u_memory.h"
34 #include "util/u_simple_shaders.h"
35 #include "util/u_surface.h"
36 #include "util/u_string.h"
37 #include "util/u_tile.h"
38 #include "tgsi/tgsi_strings.h"
39 #include "tgsi/tgsi_text.h"
40 #include "cso_cache/cso_context.h"
41 #include <stdio.h>
42
43 #define TOLERANCE 0.01
44
45 static struct pipe_resource *
46 util_create_texture2d(struct pipe_screen *screen, unsigned width,
47 unsigned height, enum pipe_format format,
48 unsigned num_samples)
49 {
50 struct pipe_resource templ = {{0}};
51
52 templ.target = PIPE_TEXTURE_2D;
53 templ.width0 = width;
54 templ.height0 = height;
55 templ.depth0 = 1;
56 templ.array_size = 1;
57 templ.nr_samples = num_samples;
58 templ.nr_storage_samples = num_samples;
59 templ.format = format;
60 templ.usage = PIPE_USAGE_DEFAULT;
61 templ.bind = PIPE_BIND_SAMPLER_VIEW |
62 (util_format_is_depth_or_stencil(format) ?
63 PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
64
65 return screen->resource_create(screen, &templ);
66 }
67
68 static void
69 util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
70 struct pipe_resource *tex)
71 {
72 struct pipe_surface templ = {{0}}, *surf;
73 struct pipe_framebuffer_state fb = {0};
74
75 templ.format = tex->format;
76 surf = ctx->create_surface(ctx, tex, &templ);
77
78 fb.width = tex->width0;
79 fb.height = tex->height0;
80 fb.cbufs[0] = surf;
81 fb.nr_cbufs = 1;
82
83 cso_set_framebuffer(cso, &fb);
84 pipe_surface_reference(&surf, NULL);
85 }
86
87 static void
88 util_set_blend_normal(struct cso_context *cso)
89 {
90 struct pipe_blend_state blend = {0};
91
92 blend.rt[0].colormask = PIPE_MASK_RGBA;
93 cso_set_blend(cso, &blend);
94 }
95
96 static void
97 util_set_dsa_disable(struct cso_context *cso)
98 {
99 struct pipe_depth_stencil_alpha_state dsa = {{0}};
100
101 cso_set_depth_stencil_alpha(cso, &dsa);
102 }
103
104 static void
105 util_set_rasterizer_normal(struct cso_context *cso)
106 {
107 struct pipe_rasterizer_state rs = {0};
108
109 rs.half_pixel_center = 1;
110 rs.bottom_edge_rule = 1;
111 rs.depth_clip = 1;
112
113 cso_set_rasterizer(cso, &rs);
114 }
115
116 static void
117 util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
118 {
119 struct pipe_viewport_state viewport;
120
121 viewport.scale[0] = 0.5f * tex->width0;
122 viewport.scale[1] = 0.5f * tex->height0;
123 viewport.scale[2] = 1.0f;
124 viewport.translate[0] = 0.5f * tex->width0;
125 viewport.translate[1] = 0.5f * tex->height0;
126 viewport.translate[2] = 0.0f;
127
128 cso_set_viewport(cso, &viewport);
129 }
130
131 static void
132 util_set_interleaved_vertex_elements(struct cso_context *cso,
133 unsigned num_elements)
134 {
135 unsigned i;
136 struct pipe_vertex_element *velem =
137 calloc(1, num_elements * sizeof(struct pipe_vertex_element));
138
139 for (i = 0; i < num_elements; i++) {
140 velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
141 velem[i].src_offset = i * 16;
142 }
143
144 cso_set_vertex_elements(cso, num_elements, velem);
145 free(velem);
146 }
147
148 static void *
149 util_set_passthrough_vertex_shader(struct cso_context *cso,
150 struct pipe_context *ctx,
151 bool window_space)
152 {
153 static const enum tgsi_semantic vs_attribs[] = {
154 TGSI_SEMANTIC_POSITION,
155 TGSI_SEMANTIC_GENERIC
156 };
157 static const uint vs_indices[] = {0, 0};
158 void *vs;
159
160 vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
161 window_space);
162 cso_set_vertex_shader_handle(cso, vs);
163 return vs;
164 }
165
166 static void
167 util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
168 struct pipe_resource *cb)
169 {
170 static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
171
172 util_set_framebuffer_cb0(cso, ctx, cb);
173 util_set_blend_normal(cso);
174 util_set_dsa_disable(cso);
175 util_set_rasterizer_normal(cso);
176 util_set_max_viewport(cso, cb);
177
178 ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
179 }
180
181 static void
182 util_draw_fullscreen_quad(struct cso_context *cso)
183 {
184 static float vertices[] = {
185 -1, -1, 0, 1, 0, 0, 0, 0,
186 -1, 1, 0, 1, 0, 1, 0, 0,
187 1, 1, 0, 1, 1, 1, 0, 0,
188 1, -1, 0, 1, 1, 0, 0, 0
189 };
190 util_set_interleaved_vertex_elements(cso, 2);
191 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
192 }
193
194 static void
195 util_draw_fullscreen_quad_fill(struct cso_context *cso,
196 float r, float g, float b, float a)
197 {
198 float vertices[] = {
199 -1, -1, 0, 1, r, g, b, a,
200 -1, 1, 0, 1, r, g, b, a,
201 1, 1, 0, 1, r, g, b, a,
202 1, -1, 0, 1, r, g, b, a,
203 };
204 util_set_interleaved_vertex_elements(cso, 2);
205 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
206 }
207
208 /**
209 * Probe and test if the rectangle contains the expected color.
210 *
211 * If "num_expected_colors" > 1, at least one expected color must match
212 * the probed color. "expected" should be an array of 4*num_expected_colors
213 * floats.
214 */
215 static bool
216 util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
217 unsigned offx, unsigned offy, unsigned w,
218 unsigned h,
219 const float *expected,
220 unsigned num_expected_colors)
221 {
222 struct pipe_transfer *transfer;
223 void *map;
224 float *pixels = malloc(w * h * 4 * sizeof(float));
225 unsigned x,y,e,c;
226 bool pass = true;
227
228 map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
229 offx, offy, w, h, &transfer);
230 pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
231 pipe_transfer_unmap(ctx, transfer);
232
233 for (e = 0; e < num_expected_colors; e++) {
234 for (y = 0; y < h; y++) {
235 for (x = 0; x < w; x++) {
236 float *probe = &pixels[(y*w + x)*4];
237
238 for (c = 0; c < 4; c++) {
239 if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
240 if (e < num_expected_colors-1)
241 goto next_color; /* test the next expected color */
242
243 printf("Probe color at (%i,%i), ", offx+x, offy+y);
244 printf("Expected: %.3f, %.3f, %.3f, %.3f, ",
245 expected[e*4], expected[e*4+1],
246 expected[e*4+2], expected[e*4+3]);
247 printf("Got: %.3f, %.3f, %.3f, %.3f\n",
248 probe[0], probe[1], probe[2], probe[3]);
249 pass = false;
250 goto done;
251 }
252 }
253 }
254 }
255 break; /* this color was successful */
256
257 next_color:;
258 }
259 done:
260
261 free(pixels);
262 return pass;
263 }
264
265 static bool
266 util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
267 unsigned offx, unsigned offy, unsigned w, unsigned h,
268 const float *expected)
269 {
270 return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
271 }
272
273 enum {
274 SKIP = -1,
275 FAIL = 0, /* also "false" */
276 PASS = 1 /* also "true" */
277 };
278
279 static void
280 util_report_result_helper(int status, const char *name, ...)
281 {
282 char buf[256];
283 va_list ap;
284
285 va_start(ap, name);
286 util_vsnprintf(buf, sizeof(buf), name, ap);
287 va_end(ap);
288
289 printf("Test(%s) = %s\n", buf,
290 status == SKIP ? "skip" :
291 status == PASS ? "pass" : "fail");
292 }
293
294 #define util_report_result(status) util_report_result_helper(status, __func__)
295
296 /**
297 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
298 *
299 * The viewport state is set as usual, but it should have no effect.
300 * Clipping should also be disabled.
301 *
302 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
303 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
304 * multiplied by 1/w (otherwise nothing would be rendered).
305 *
306 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
307 * during perspective interpolation is not tested.
308 */
309 static void
310 tgsi_vs_window_space_position(struct pipe_context *ctx)
311 {
312 struct cso_context *cso;
313 struct pipe_resource *cb;
314 void *fs, *vs;
315 bool pass = true;
316 static const float red[] = {1, 0, 0, 1};
317
318 if (!ctx->screen->get_param(ctx->screen,
319 PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
320 util_report_result(SKIP);
321 return;
322 }
323
324 cso = cso_create_context(ctx, 0);
325 cb = util_create_texture2d(ctx->screen, 256, 256,
326 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
327 util_set_common_states_and_clear(cso, ctx, cb);
328
329 /* Fragment shader. */
330 fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
331 TGSI_INTERPOLATE_LINEAR, TRUE);
332 cso_set_fragment_shader_handle(cso, fs);
333
334 /* Vertex shader. */
335 vs = util_set_passthrough_vertex_shader(cso, ctx, true);
336
337 /* Draw. */
338 {
339 static float vertices[] = {
340 0, 0, 0, 0, 1, 0, 0, 1,
341 0, 256, 0, 0, 1, 0, 0, 1,
342 256, 256, 0, 0, 1, 0, 0, 1,
343 256, 0, 0, 0, 1, 0, 0, 1,
344 };
345 util_set_interleaved_vertex_elements(cso, 2);
346 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
347 }
348
349 /* Probe pixels. */
350 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
351 cb->width0, cb->height0, red);
352
353 /* Cleanup. */
354 cso_destroy_context(cso);
355 ctx->delete_vs_state(ctx, vs);
356 ctx->delete_fs_state(ctx, fs);
357 pipe_resource_reference(&cb, NULL);
358
359 util_report_result(pass);
360 }
361
362 static void
363 null_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target)
364 {
365 struct cso_context *cso;
366 struct pipe_resource *cb;
367 void *fs, *vs;
368 bool pass = true;
369 /* 2 expected colors: */
370 static const float expected_tex[] = {0, 0, 0, 1,
371 0, 0, 0, 0};
372 static const float expected_buf[] = {0, 0, 0, 0};
373 const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ?
374 expected_buf : expected_tex;
375 unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2;
376
377 if (tgsi_tex_target == TGSI_TEXTURE_BUFFER &&
378 !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) {
379 util_report_result_helper(SKIP, "%s: %s", __func__,
380 tgsi_texture_names[tgsi_tex_target]);
381 return;
382 }
383
384 cso = cso_create_context(ctx, 0);
385 cb = util_create_texture2d(ctx->screen, 256, 256,
386 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
387 util_set_common_states_and_clear(cso, ctx, cb);
388
389 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, NULL);
390
391 /* Fragment shader. */
392 fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target,
393 TGSI_INTERPOLATE_LINEAR,
394 TGSI_RETURN_TYPE_FLOAT,
395 TGSI_RETURN_TYPE_FLOAT, false, false);
396 cso_set_fragment_shader_handle(cso, fs);
397
398 /* Vertex shader. */
399 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
400 util_draw_fullscreen_quad(cso);
401
402 /* Probe pixels. */
403 pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
404 cb->width0, cb->height0, expected,
405 num_expected);
406
407 /* Cleanup. */
408 cso_destroy_context(cso);
409 ctx->delete_vs_state(ctx, vs);
410 ctx->delete_fs_state(ctx, fs);
411 pipe_resource_reference(&cb, NULL);
412
413 util_report_result_helper(pass, "%s: %s", __func__,
414 tgsi_texture_names[tgsi_tex_target]);
415 }
416
417 void
418 util_test_constant_buffer(struct pipe_context *ctx,
419 struct pipe_resource *constbuf)
420 {
421 struct cso_context *cso;
422 struct pipe_resource *cb;
423 void *fs, *vs;
424 bool pass = true;
425 static const float zero[] = {0, 0, 0, 0};
426
427 cso = cso_create_context(ctx, 0);
428 cb = util_create_texture2d(ctx->screen, 256, 256,
429 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
430 util_set_common_states_and_clear(cso, ctx, cb);
431
432 pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf);
433
434 /* Fragment shader. */
435 {
436 static const char *text = /* I don't like ureg... */
437 "FRAG\n"
438 "DCL CONST[0][0]\n"
439 "DCL OUT[0], COLOR\n"
440
441 "MOV OUT[0], CONST[0][0]\n"
442 "END\n";
443 struct tgsi_token tokens[1000];
444 struct pipe_shader_state state;
445
446 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
447 puts("Can't compile a fragment shader.");
448 util_report_result(FAIL);
449 return;
450 }
451 pipe_shader_state_from_tgsi(&state, tokens);
452 fs = ctx->create_fs_state(ctx, &state);
453 cso_set_fragment_shader_handle(cso, fs);
454 }
455
456 /* Vertex shader. */
457 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
458 util_draw_fullscreen_quad(cso);
459
460 /* Probe pixels. */
461 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0,
462 cb->height0, zero);
463
464 /* Cleanup. */
465 cso_destroy_context(cso);
466 ctx->delete_vs_state(ctx, vs);
467 ctx->delete_fs_state(ctx, fs);
468 pipe_resource_reference(&cb, NULL);
469
470 util_report_result(pass);
471 }
472
473 static void
474 null_fragment_shader(struct pipe_context *ctx)
475 {
476 struct cso_context *cso;
477 struct pipe_resource *cb;
478 void *vs;
479 struct pipe_rasterizer_state rs = {0};
480 struct pipe_query *query;
481 union pipe_query_result qresult;
482
483 cso = cso_create_context(ctx, 0);
484 cb = util_create_texture2d(ctx->screen, 256, 256,
485 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
486 util_set_common_states_and_clear(cso, ctx, cb);
487
488 /* No rasterization. */
489 rs.rasterizer_discard = 1;
490 cso_set_rasterizer(cso, &rs);
491
492 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
493
494 query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0);
495 ctx->begin_query(ctx, query);
496 util_draw_fullscreen_quad(cso);
497 ctx->end_query(ctx, query);
498 ctx->get_query_result(ctx, query, true, &qresult);
499
500 /* Cleanup. */
501 cso_destroy_context(cso);
502 ctx->delete_vs_state(ctx, vs);
503 ctx->destroy_query(ctx, query);
504 pipe_resource_reference(&cb, NULL);
505
506 /* Check PRIMITIVES_GENERATED. */
507 util_report_result(qresult.u64 == 2);
508 }
509
510 #if defined(PIPE_OS_LINUX) && defined(HAVE_LIBDRM)
511 #include <libsync.h>
512 #else
513 #define sync_merge(str, fd1, fd2) (-1)
514 #define sync_wait(fd, timeout) (-1)
515 #endif
516
517 static void
518 test_sync_file_fences(struct pipe_context *ctx)
519 {
520 struct pipe_screen *screen = ctx->screen;
521 bool pass = true;
522 enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC;
523
524 if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
525 return;
526
527 struct cso_context *cso = cso_create_context(ctx, 0);
528 struct pipe_resource *buf =
529 pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024);
530 struct pipe_resource *tex =
531 util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0);
532 struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL;
533
534 /* Run 2 clears, get fencess. */
535 uint32_t value = 0;
536 ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
537 ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD);
538
539 struct pipe_box box;
540 u_box_2d(0, 0, tex->width0, tex->height0, &box);
541 ctx->clear_texture(ctx, tex, 0, &box, &value);
542 ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD);
543 pass = pass && buf_fence && tex_fence;
544
545 /* Export fences. */
546 int buf_fd = screen->fence_get_fd(screen, buf_fence);
547 int tex_fd = screen->fence_get_fd(screen, tex_fence);
548 pass = pass && buf_fd >= 0 && tex_fd >= 0;
549
550 /* Merge fences. */
551 int merged_fd = sync_merge("test", buf_fd, tex_fd);
552 pass = pass && merged_fd >= 0;
553
554 /* (Re)import all fences. */
555 struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL;
556 struct pipe_fence_handle *merged_fence = NULL;
557 ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type);
558 ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type);
559 ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type);
560 pass = pass && re_buf_fence && re_tex_fence && merged_fence;
561
562 /* Run another clear after waiting for everything. */
563 struct pipe_fence_handle *final_fence = NULL;
564 ctx->fence_server_sync(ctx, merged_fence);
565 value = 0xff;
566 ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
567 ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD);
568 pass = pass && final_fence;
569
570 /* Wait for the last fence. */
571 int final_fd = screen->fence_get_fd(screen, final_fence);
572 pass = pass && final_fd >= 0;
573 pass = pass && sync_wait(final_fd, -1) == 0;
574
575 /* Check that all fences are signalled. */
576 pass = pass && sync_wait(buf_fd, 0) == 0;
577 pass = pass && sync_wait(tex_fd, 0) == 0;
578 pass = pass && sync_wait(merged_fd, 0) == 0;
579
580 pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0);
581 pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0);
582 pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0);
583 pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0);
584 pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0);
585 pass = pass && screen->fence_finish(screen, NULL, final_fence, 0);
586
587 /* Cleanup. */
588 #ifndef PIPE_OS_WINDOWS
589 if (buf_fd >= 0)
590 close(buf_fd);
591 if (tex_fd >= 0)
592 close(tex_fd);
593 if (merged_fd >= 0)
594 close(merged_fd);
595 if (final_fd >= 0)
596 close(final_fd);
597 #endif
598
599 screen->fence_reference(screen, &buf_fence, NULL);
600 screen->fence_reference(screen, &tex_fence, NULL);
601 screen->fence_reference(screen, &re_buf_fence, NULL);
602 screen->fence_reference(screen, &re_tex_fence, NULL);
603 screen->fence_reference(screen, &merged_fence, NULL);
604 screen->fence_reference(screen, &final_fence, NULL);
605
606 cso_destroy_context(cso);
607 pipe_resource_reference(&buf, NULL);
608 pipe_resource_reference(&tex, NULL);
609
610 util_report_result(pass);
611 }
612
613 static void
614 test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
615 unsigned num_samples)
616 {
617 struct cso_context *cso;
618 struct pipe_resource *cb;
619 struct pipe_sampler_view *view = NULL;
620 char name[256];
621 const char *text;
622
623 assert(num_samples >= 1 && num_samples <= 8);
624
625 snprintf(name, sizeof(name), "%s: %s, %u samples", __func__,
626 use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1));
627
628 if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) {
629 util_report_result_helper(SKIP, name);
630 return;
631 }
632 if (use_fbfetch &&
633 !ctx->screen->get_param(ctx->screen, PIPE_CAP_TGSI_FS_FBFETCH)) {
634 util_report_result_helper(SKIP, name);
635 return;
636 }
637
638 cso = cso_create_context(ctx, 0);
639 cb = util_create_texture2d(ctx->screen, 256, 256,
640 PIPE_FORMAT_R8G8B8A8_UNORM, num_samples);
641 util_set_common_states_and_clear(cso, ctx, cb);
642
643 /* Clear each sample to a different value. */
644 if (num_samples > 1) {
645 void *fs =
646 util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
647 TGSI_INTERPOLATE_LINEAR, TRUE);
648 cso_set_fragment_shader_handle(cso, fs);
649
650 /* Vertex shader. */
651 void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
652
653 for (unsigned i = 0; i < num_samples / 2; i++) {
654 float value;
655
656 /* 2 consecutive samples should have the same color to test MSAA
657 * compression properly.
658 */
659 if (num_samples == 2) {
660 value = 0.1;
661 } else {
662 /* The average value must be 0.1 */
663 static const float values[] = {
664 0.0, 0.2, 0.05, 0.15
665 };
666 value = values[i];
667 }
668
669 ctx->set_sample_mask(ctx, 0x3 << (i * 2));
670 util_draw_fullscreen_quad_fill(cso, value, value, value, value);
671 }
672 ctx->set_sample_mask(ctx, ~0);
673
674 cso_set_vertex_shader_handle(cso, NULL);
675 cso_set_fragment_shader_handle(cso, NULL);
676 ctx->delete_vs_state(ctx, vs);
677 ctx->delete_fs_state(ctx, fs);
678 }
679
680 if (use_fbfetch) {
681 /* Fragment shader. */
682 text = "FRAG\n"
683 "DCL OUT[0], COLOR[0]\n"
684 "DCL TEMP[0]\n"
685 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
686
687 "FBFETCH TEMP[0], OUT[0]\n"
688 "ADD OUT[0], TEMP[0], IMM[0]\n"
689 "END\n";
690 } else {
691 struct pipe_sampler_view templ = {{0}};
692 templ.format = cb->format;
693 templ.target = cb->target;
694 templ.swizzle_r = PIPE_SWIZZLE_X;
695 templ.swizzle_g = PIPE_SWIZZLE_Y;
696 templ.swizzle_b = PIPE_SWIZZLE_Z;
697 templ.swizzle_a = PIPE_SWIZZLE_W;
698 view = ctx->create_sampler_view(ctx, cb, &templ);
699 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &view);
700
701 /* Fragment shader. */
702 if (num_samples > 1) {
703 text = "FRAG\n"
704 "DCL SV[0], POSITION\n"
705 "DCL SV[1], SAMPLEID\n"
706 "DCL SAMP[0]\n"
707 "DCL SVIEW[0], 2D_MSAA, FLOAT\n"
708 "DCL OUT[0], COLOR[0]\n"
709 "DCL TEMP[0]\n"
710 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
711
712 "F2I TEMP[0].xy, SV[0].xyyy\n"
713 "MOV TEMP[0].w, SV[1].xxxx\n"
714 "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n"
715 "ADD OUT[0], TEMP[0], IMM[0]\n"
716 "END\n";
717 } else {
718 text = "FRAG\n"
719 "DCL SV[0], POSITION\n"
720 "DCL SAMP[0]\n"
721 "DCL SVIEW[0], 2D, FLOAT\n"
722 "DCL OUT[0], COLOR[0]\n"
723 "DCL TEMP[0]\n"
724 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
725 "IMM[1] INT32 { 0, 0, 0, 0}\n"
726
727 "F2I TEMP[0].xy, SV[0].xyyy\n"
728 "MOV TEMP[0].zw, IMM[1]\n"
729 "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n"
730 "ADD OUT[0], TEMP[0], IMM[0]\n"
731 "END\n";
732 }
733 }
734
735 struct tgsi_token tokens[1000];
736 struct pipe_shader_state state;
737
738 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
739 assert(0);
740 util_report_result_helper(FAIL, name);
741 return;
742 }
743 pipe_shader_state_from_tgsi(&state, tokens);
744
745 void *fs = ctx->create_fs_state(ctx, &state);
746 cso_set_fragment_shader_handle(cso, fs);
747
748 /* Vertex shader. */
749 void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
750
751 if (num_samples > 1 && !use_fbfetch)
752 ctx->set_min_samples(ctx, num_samples);
753
754 for (int i = 0; i < 2; i++) {
755 ctx->texture_barrier(ctx,
756 use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER :
757 PIPE_TEXTURE_BARRIER_SAMPLER);
758 util_draw_fullscreen_quad(cso);
759 }
760 if (num_samples > 1 && !use_fbfetch)
761 ctx->set_min_samples(ctx, 1);
762
763 /* Probe pixels.
764 *
765 * For single sample:
766 * result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9)
767 *
768 * For MSAA 4x:
769 * sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8)
770 * sample1 = sample0
771 * sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0)
772 * sample3 = sample2
773 * resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9)
774 */
775 static const float expected[] = {0.3, 0.5, 0.7, 0.9};
776 bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
777 cb->width0, cb->height0, expected);
778
779 /* Cleanup. */
780 cso_destroy_context(cso);
781 ctx->delete_vs_state(ctx, vs);
782 ctx->delete_fs_state(ctx, fs);
783 pipe_sampler_view_reference(&view, NULL);
784 pipe_resource_reference(&cb, NULL);
785
786 util_report_result_helper(pass, name);
787 }
788
789 /**
790 * Run all tests. This should be run with a clean context after
791 * context_create.
792 */
793 void
794 util_run_tests(struct pipe_screen *screen)
795 {
796 struct pipe_context *ctx = screen->context_create(screen, NULL, 0);
797
798 null_fragment_shader(ctx);
799 tgsi_vs_window_space_position(ctx);
800 null_sampler_view(ctx, TGSI_TEXTURE_2D);
801 null_sampler_view(ctx, TGSI_TEXTURE_BUFFER);
802 util_test_constant_buffer(ctx, NULL);
803 test_sync_file_fences(ctx);
804
805 for (int i = 1; i <= 8; i = i * 2)
806 test_texture_barrier(ctx, false, i);
807 for (int i = 1; i <= 8; i = i * 2)
808 test_texture_barrier(ctx, true, i);
809
810 ctx->destroy(ctx);
811
812 puts("Done. Exiting..");
813 exit(0);
814 }