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