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