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/format/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 "frontend/winsys_handle.h"
42 #include <stdio.h>
43
44 #define TOLERANCE 0.01
45
46 static struct pipe_resource *
util_create_texture2d(struct pipe_screen * screen,unsigned width,unsigned height,enum pipe_format format,unsigned num_samples)47 util_create_texture2d(struct pipe_screen *screen, unsigned width,
48 unsigned height, enum pipe_format format,
49 unsigned num_samples)
50 {
51 struct pipe_resource templ = {0};
52
53 templ.target = PIPE_TEXTURE_2D;
54 templ.width0 = width;
55 templ.height0 = height;
56 templ.depth0 = 1;
57 templ.array_size = 1;
58 templ.nr_samples = num_samples;
59 templ.nr_storage_samples = num_samples;
60 templ.format = format;
61 templ.usage = PIPE_USAGE_DEFAULT;
62 templ.bind = PIPE_BIND_SAMPLER_VIEW |
63 (util_format_is_depth_or_stencil(format) ?
64 PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
65
66 return screen->resource_create(screen, &templ);
67 }
68
69 static void
util_set_framebuffer_cb0(struct cso_context * cso,struct pipe_context * ctx,struct pipe_resource * tex)70 util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
71 struct pipe_resource *tex)
72 {
73 struct pipe_surface templ = {{0}}, *surf;
74 struct pipe_framebuffer_state fb = {0};
75
76 templ.format = tex->format;
77 surf = ctx->create_surface(ctx, tex, &templ);
78
79 fb.width = tex->width0;
80 fb.height = tex->height0;
81 fb.cbufs[0] = surf;
82 fb.nr_cbufs = 1;
83
84 cso_set_framebuffer(cso, &fb);
85 pipe_surface_reference(&surf, NULL);
86 }
87
88 static void
util_set_blend_normal(struct cso_context * cso)89 util_set_blend_normal(struct cso_context *cso)
90 {
91 struct pipe_blend_state blend = {0};
92
93 blend.rt[0].colormask = PIPE_MASK_RGBA;
94 cso_set_blend(cso, &blend);
95 }
96
97 static void
util_set_dsa_disable(struct cso_context * cso)98 util_set_dsa_disable(struct cso_context *cso)
99 {
100 struct pipe_depth_stencil_alpha_state dsa = {{{0}}};
101
102 cso_set_depth_stencil_alpha(cso, &dsa);
103 }
104
105 static void
util_set_rasterizer_normal(struct cso_context * cso)106 util_set_rasterizer_normal(struct cso_context *cso)
107 {
108 struct pipe_rasterizer_state rs = {0};
109
110 rs.half_pixel_center = 1;
111 rs.bottom_edge_rule = 1;
112 rs.depth_clip_near = 1;
113 rs.depth_clip_far = 1;
114
115 cso_set_rasterizer(cso, &rs);
116 }
117
118 static void
util_set_max_viewport(struct cso_context * cso,struct pipe_resource * tex)119 util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
120 {
121 struct pipe_viewport_state viewport;
122
123 viewport.scale[0] = 0.5f * tex->width0;
124 viewport.scale[1] = 0.5f * tex->height0;
125 viewport.scale[2] = 1.0f;
126 viewport.translate[0] = 0.5f * tex->width0;
127 viewport.translate[1] = 0.5f * tex->height0;
128 viewport.translate[2] = 0.0f;
129 viewport.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X;
130 viewport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y;
131 viewport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z;
132 viewport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W;
133
134 cso_set_viewport(cso, &viewport);
135 }
136
137 static void
util_set_interleaved_vertex_elements(struct cso_context * cso,unsigned num_elements)138 util_set_interleaved_vertex_elements(struct cso_context *cso,
139 unsigned num_elements)
140 {
141 struct cso_velems_state velem;
142 unsigned i;
143
144 memset(&velem, 0, sizeof(velem));
145 velem.count = num_elements;
146 for (i = 0; i < num_elements; i++) {
147 velem.velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
148 velem.velems[i].src_offset = i * 16;
149 }
150
151 cso_set_vertex_elements(cso, &velem);
152 }
153
154 static void *
util_set_passthrough_vertex_shader(struct cso_context * cso,struct pipe_context * ctx,bool window_space)155 util_set_passthrough_vertex_shader(struct cso_context *cso,
156 struct pipe_context *ctx,
157 bool window_space)
158 {
159 static const enum tgsi_semantic vs_attribs[] = {
160 TGSI_SEMANTIC_POSITION,
161 TGSI_SEMANTIC_GENERIC
162 };
163 static const uint vs_indices[] = {0, 0};
164 void *vs;
165
166 vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
167 window_space);
168 cso_set_vertex_shader_handle(cso, vs);
169 return vs;
170 }
171
172 static void
util_set_common_states_and_clear(struct cso_context * cso,struct pipe_context * ctx,struct pipe_resource * cb)173 util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
174 struct pipe_resource *cb)
175 {
176 static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
177
178 util_set_framebuffer_cb0(cso, ctx, cb);
179 util_set_blend_normal(cso);
180 util_set_dsa_disable(cso);
181 util_set_rasterizer_normal(cso);
182 util_set_max_viewport(cso, cb);
183
184 ctx->clear(ctx, PIPE_CLEAR_COLOR0, NULL, (void*)clear_color, 0, 0);
185 }
186
187 static void
util_draw_fullscreen_quad(struct cso_context * cso)188 util_draw_fullscreen_quad(struct cso_context *cso)
189 {
190 static float vertices[] = {
191 -1, -1, 0, 1, 0, 0, 0, 0,
192 -1, 1, 0, 1, 0, 1, 0, 0,
193 1, 1, 0, 1, 1, 1, 0, 0,
194 1, -1, 0, 1, 1, 0, 0, 0
195 };
196 util_set_interleaved_vertex_elements(cso, 2);
197 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
198 }
199
200 static void
util_draw_fullscreen_quad_fill(struct cso_context * cso,float r,float g,float b,float a)201 util_draw_fullscreen_quad_fill(struct cso_context *cso,
202 float r, float g, float b, float a)
203 {
204 float vertices[] = {
205 -1, -1, 0, 1, r, g, b, a,
206 -1, 1, 0, 1, r, g, b, a,
207 1, 1, 0, 1, r, g, b, a,
208 1, -1, 0, 1, r, g, b, a,
209 };
210 util_set_interleaved_vertex_elements(cso, 2);
211 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
212 }
213
214 /**
215 * Probe and test if the rectangle contains the expected color.
216 *
217 * If "num_expected_colors" > 1, at least one expected color must match
218 * the probed color. "expected" should be an array of 4*num_expected_colors
219 * floats.
220 */
221 static bool
util_probe_rect_rgba_multi(struct pipe_context * ctx,struct pipe_resource * tex,unsigned offx,unsigned offy,unsigned w,unsigned h,const float * expected,unsigned num_expected_colors)222 util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
223 unsigned offx, unsigned offy, unsigned w,
224 unsigned h,
225 const float *expected,
226 unsigned num_expected_colors)
227 {
228 struct pipe_transfer *transfer;
229 void *map;
230 float *pixels = malloc(w * h * 4 * sizeof(float));
231 unsigned x,y,e,c;
232 bool pass = true;
233
234 map = pipe_texture_map(ctx, tex, 0, 0, PIPE_MAP_READ,
235 offx, offy, w, h, &transfer);
236 pipe_get_tile_rgba(transfer, map, 0, 0, w, h, tex->format, pixels);
237 pipe_texture_unmap(ctx, transfer);
238
239 for (e = 0; e < num_expected_colors; e++) {
240 for (y = 0; y < h; y++) {
241 for (x = 0; x < w; x++) {
242 float *probe = &pixels[(y*w + x)*4];
243
244 for (c = 0; c < 4; c++) {
245 if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
246 if (e < num_expected_colors-1)
247 goto next_color; /* test the next expected color */
248
249 printf("Probe color at (%i,%i), ", offx+x, offy+y);
250 printf("Expected: %.3f, %.3f, %.3f, %.3f, ",
251 expected[e*4], expected[e*4+1],
252 expected[e*4+2], expected[e*4+3]);
253 printf("Got: %.3f, %.3f, %.3f, %.3f\n",
254 probe[0], probe[1], probe[2], probe[3]);
255 pass = false;
256 goto done;
257 }
258 }
259 }
260 }
261 break; /* this color was successful */
262
263 next_color:;
264 }
265 done:
266
267 free(pixels);
268 return pass;
269 }
270
271 static bool
util_probe_rect_rgba(struct pipe_context * ctx,struct pipe_resource * tex,unsigned offx,unsigned offy,unsigned w,unsigned h,const float * expected)272 util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
273 unsigned offx, unsigned offy, unsigned w, unsigned h,
274 const float *expected)
275 {
276 return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
277 }
278
279 enum {
280 SKIP = -1,
281 FAIL = 0, /* also "false" */
282 PASS = 1 /* also "true" */
283 };
284
285 static void
util_report_result_helper(int status,const char * name,...)286 util_report_result_helper(int status, const char *name, ...)
287 {
288 char buf[256];
289 va_list ap;
290
291 va_start(ap, name);
292 vsnprintf(buf, sizeof(buf), name, ap);
293 va_end(ap);
294
295 printf("Test(%s) = %s\n", buf,
296 status == SKIP ? "skip" :
297 status == PASS ? "pass" : "fail");
298 }
299
300 #define util_report_result(status) util_report_result_helper(status, __func__)
301
302 /**
303 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
304 *
305 * The viewport state is set as usual, but it should have no effect.
306 * Clipping should also be disabled.
307 *
308 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
309 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
310 * multiplied by 1/w (otherwise nothing would be rendered).
311 *
312 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
313 * during perspective interpolation is not tested.
314 */
315 static void
tgsi_vs_window_space_position(struct pipe_context * ctx)316 tgsi_vs_window_space_position(struct pipe_context *ctx)
317 {
318 struct cso_context *cso;
319 struct pipe_resource *cb;
320 void *fs, *vs;
321 bool pass = true;
322 static const float red[] = {1, 0, 0, 1};
323
324 if (!ctx->screen->get_param(ctx->screen,
325 PIPE_CAP_VS_WINDOW_SPACE_POSITION)) {
326 util_report_result(SKIP);
327 return;
328 }
329
330 cso = cso_create_context(ctx, 0);
331 cb = util_create_texture2d(ctx->screen, 256, 256,
332 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
333 util_set_common_states_and_clear(cso, ctx, cb);
334
335 /* Fragment shader. */
336 fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
337 TGSI_INTERPOLATE_LINEAR, TRUE);
338 cso_set_fragment_shader_handle(cso, fs);
339
340 /* Vertex shader. */
341 vs = util_set_passthrough_vertex_shader(cso, ctx, true);
342
343 /* Draw. */
344 {
345 static float vertices[] = {
346 0, 0, 0, 0, 1, 0, 0, 1,
347 0, 256, 0, 0, 1, 0, 0, 1,
348 256, 256, 0, 0, 1, 0, 0, 1,
349 256, 0, 0, 0, 1, 0, 0, 1,
350 };
351 util_set_interleaved_vertex_elements(cso, 2);
352 util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
353 }
354
355 /* Probe pixels. */
356 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
357 cb->width0, cb->height0, red);
358
359 /* Cleanup. */
360 cso_destroy_context(cso);
361 ctx->delete_vs_state(ctx, vs);
362 ctx->delete_fs_state(ctx, fs);
363 pipe_resource_reference(&cb, NULL);
364
365 util_report_result(pass);
366 }
367
368 static void
null_sampler_view(struct pipe_context * ctx,unsigned tgsi_tex_target)369 null_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target)
370 {
371 struct cso_context *cso;
372 struct pipe_resource *cb;
373 void *fs, *vs;
374 bool pass = true;
375 /* 2 expected colors: */
376 static const float expected_tex[] = {0, 0, 0, 1,
377 0, 0, 0, 0};
378 static const float expected_buf[] = {0, 0, 0, 0};
379 const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ?
380 expected_buf : expected_tex;
381 unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2;
382
383 if (tgsi_tex_target == TGSI_TEXTURE_BUFFER &&
384 !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) {
385 util_report_result_helper(SKIP, "%s: %s", __func__,
386 tgsi_texture_names[tgsi_tex_target]);
387 return;
388 }
389
390 cso = cso_create_context(ctx, 0);
391 cb = util_create_texture2d(ctx->screen, 256, 256,
392 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
393 util_set_common_states_and_clear(cso, ctx, cb);
394
395 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0, 1, false, NULL);
396
397 /* Fragment shader. */
398 fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target,
399 TGSI_INTERPOLATE_LINEAR,
400 TGSI_RETURN_TYPE_FLOAT,
401 TGSI_RETURN_TYPE_FLOAT, false, false);
402 cso_set_fragment_shader_handle(cso, fs);
403
404 /* Vertex shader. */
405 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
406 util_draw_fullscreen_quad(cso);
407
408 /* Probe pixels. */
409 pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
410 cb->width0, cb->height0, expected,
411 num_expected);
412
413 /* Cleanup. */
414 cso_destroy_context(cso);
415 ctx->delete_vs_state(ctx, vs);
416 ctx->delete_fs_state(ctx, fs);
417 pipe_resource_reference(&cb, NULL);
418
419 util_report_result_helper(pass, "%s: %s", __func__,
420 tgsi_texture_names[tgsi_tex_target]);
421 }
422
423 void
util_test_constant_buffer(struct pipe_context * ctx,struct pipe_resource * constbuf)424 util_test_constant_buffer(struct pipe_context *ctx,
425 struct pipe_resource *constbuf)
426 {
427 struct cso_context *cso;
428 struct pipe_resource *cb;
429 void *fs, *vs;
430 bool pass = true;
431 static const float zero[] = {0, 0, 0, 0};
432
433 cso = cso_create_context(ctx, 0);
434 cb = util_create_texture2d(ctx->screen, 256, 256,
435 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
436 util_set_common_states_and_clear(cso, ctx, cb);
437
438 pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf);
439
440 /* Fragment shader. */
441 {
442 static const char *text = /* I don't like ureg... */
443 "FRAG\n"
444 "DCL CONST[0][0]\n"
445 "DCL OUT[0], COLOR\n"
446
447 "MOV OUT[0], CONST[0][0]\n"
448 "END\n";
449 struct tgsi_token tokens[1000];
450 struct pipe_shader_state state = {0};
451
452 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
453 puts("Can't compile a fragment shader.");
454 util_report_result(FAIL);
455 return;
456 }
457 pipe_shader_state_from_tgsi(&state, tokens);
458 fs = ctx->create_fs_state(ctx, &state);
459 cso_set_fragment_shader_handle(cso, fs);
460 }
461
462 /* Vertex shader. */
463 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
464 util_draw_fullscreen_quad(cso);
465
466 /* Probe pixels. */
467 pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0,
468 cb->height0, zero);
469
470 /* Cleanup. */
471 cso_destroy_context(cso);
472 ctx->delete_vs_state(ctx, vs);
473 ctx->delete_fs_state(ctx, fs);
474 pipe_resource_reference(&cb, NULL);
475
476 util_report_result(pass);
477 }
478
479 static void
disabled_fragment_shader(struct pipe_context * ctx)480 disabled_fragment_shader(struct pipe_context *ctx)
481 {
482 struct cso_context *cso;
483 struct pipe_resource *cb;
484 void *vs;
485 struct pipe_rasterizer_state rs = {0};
486 struct pipe_query *query;
487 union pipe_query_result qresult;
488
489 cso = cso_create_context(ctx, 0);
490 cb = util_create_texture2d(ctx->screen, 256, 256,
491 PIPE_FORMAT_R8G8B8A8_UNORM, 0);
492 util_set_common_states_and_clear(cso, ctx, cb);
493
494 /* No rasterization. */
495 rs.rasterizer_discard = 1;
496 cso_set_rasterizer(cso, &rs);
497
498 vs = util_set_passthrough_vertex_shader(cso, ctx, false);
499
500 void *fs = util_make_empty_fragment_shader(ctx);
501 cso_set_fragment_shader_handle(cso, fs);
502
503 query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0);
504 ctx->begin_query(ctx, query);
505 util_draw_fullscreen_quad(cso);
506 ctx->end_query(ctx, query);
507 ctx->get_query_result(ctx, query, true, &qresult);
508
509 /* Cleanup. */
510 cso_destroy_context(cso);
511 ctx->delete_vs_state(ctx, vs);
512 ctx->delete_fs_state(ctx, fs);
513 ctx->destroy_query(ctx, query);
514 pipe_resource_reference(&cb, NULL);
515
516 /* Check PRIMITIVES_GENERATED. */
517 util_report_result(qresult.u64 == 2);
518 }
519
520 #if defined(PIPE_OS_LINUX) && defined(HAVE_LIBDRM)
521 #include <libsync.h>
522 #else
523 #define sync_merge(str, fd1, fd2) (-1)
524 #define sync_wait(fd, timeout) (-1)
525 #endif
526
527 static void
test_sync_file_fences(struct pipe_context * ctx)528 test_sync_file_fences(struct pipe_context *ctx)
529 {
530 struct pipe_screen *screen = ctx->screen;
531 bool pass = true;
532 enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC;
533
534 if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
535 return;
536
537 struct cso_context *cso = cso_create_context(ctx, 0);
538 struct pipe_resource *buf =
539 pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024);
540 struct pipe_resource *tex =
541 util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0);
542 struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL;
543
544 /* Run 2 clears, get fencess. */
545 uint32_t value = 0;
546 ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
547 ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD);
548
549 struct pipe_box box;
550 u_box_2d(0, 0, tex->width0, tex->height0, &box);
551 ctx->clear_texture(ctx, tex, 0, &box, &value);
552 ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD);
553 pass = pass && buf_fence && tex_fence;
554
555 /* Export fences. */
556 int buf_fd = screen->fence_get_fd(screen, buf_fence);
557 int tex_fd = screen->fence_get_fd(screen, tex_fence);
558 pass = pass && buf_fd >= 0 && tex_fd >= 0;
559
560 /* Merge fences. */
561 int merged_fd = sync_merge("test", buf_fd, tex_fd);
562 pass = pass && merged_fd >= 0;
563
564 /* (Re)import all fences. */
565 struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL;
566 struct pipe_fence_handle *merged_fence = NULL;
567 ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type);
568 ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type);
569 ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type);
570 pass = pass && re_buf_fence && re_tex_fence && merged_fence;
571
572 /* Run another clear after waiting for everything. */
573 struct pipe_fence_handle *final_fence = NULL;
574 ctx->fence_server_sync(ctx, merged_fence);
575 value = 0xff;
576 ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
577 ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD);
578 pass = pass && final_fence;
579
580 /* Wait for the last fence. */
581 int final_fd = screen->fence_get_fd(screen, final_fence);
582 pass = pass && final_fd >= 0;
583 pass = pass && sync_wait(final_fd, -1) == 0;
584
585 /* Check that all fences are signalled. */
586 pass = pass && sync_wait(buf_fd, 0) == 0;
587 pass = pass && sync_wait(tex_fd, 0) == 0;
588 pass = pass && sync_wait(merged_fd, 0) == 0;
589
590 pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0);
591 pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0);
592 pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0);
593 pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0);
594 pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0);
595 pass = pass && screen->fence_finish(screen, NULL, final_fence, 0);
596
597 /* Cleanup. */
598 #ifndef PIPE_OS_WINDOWS
599 if (buf_fd >= 0)
600 close(buf_fd);
601 if (tex_fd >= 0)
602 close(tex_fd);
603 if (merged_fd >= 0)
604 close(merged_fd);
605 if (final_fd >= 0)
606 close(final_fd);
607 #endif
608
609 screen->fence_reference(screen, &buf_fence, NULL);
610 screen->fence_reference(screen, &tex_fence, NULL);
611 screen->fence_reference(screen, &re_buf_fence, NULL);
612 screen->fence_reference(screen, &re_tex_fence, NULL);
613 screen->fence_reference(screen, &merged_fence, NULL);
614 screen->fence_reference(screen, &final_fence, NULL);
615
616 cso_destroy_context(cso);
617 pipe_resource_reference(&buf, NULL);
618 pipe_resource_reference(&tex, NULL);
619
620 util_report_result(pass);
621 }
622
623 static void
test_texture_barrier(struct pipe_context * ctx,bool use_fbfetch,unsigned num_samples)624 test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
625 unsigned num_samples)
626 {
627 struct cso_context *cso;
628 struct pipe_resource *cb;
629 struct pipe_sampler_view *view = NULL;
630 char name[256];
631 const char *text;
632
633 assert(num_samples >= 1 && num_samples <= 8);
634
635 snprintf(name, sizeof(name), "%s: %s, %u samples", __func__,
636 use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1));
637
638 if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) {
639 util_report_result_helper(SKIP, name);
640 return;
641 }
642 if (use_fbfetch &&
643 !ctx->screen->get_param(ctx->screen, PIPE_CAP_FBFETCH)) {
644 util_report_result_helper(SKIP, name);
645 return;
646 }
647
648 cso = cso_create_context(ctx, 0);
649 cb = util_create_texture2d(ctx->screen, 256, 256,
650 PIPE_FORMAT_R8G8B8A8_UNORM, num_samples);
651 util_set_common_states_and_clear(cso, ctx, cb);
652
653 /* Clear each sample to a different value. */
654 if (num_samples > 1) {
655 void *fs =
656 util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
657 TGSI_INTERPOLATE_LINEAR, TRUE);
658 cso_set_fragment_shader_handle(cso, fs);
659
660 /* Vertex shader. */
661 void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
662
663 for (unsigned i = 0; i < num_samples / 2; i++) {
664 float value;
665
666 /* 2 consecutive samples should have the same color to test MSAA
667 * compression properly.
668 */
669 if (num_samples == 2) {
670 value = 0.1;
671 } else {
672 /* The average value must be 0.1 */
673 static const float values[] = {
674 0.0, 0.2, 0.05, 0.15
675 };
676 value = values[i];
677 }
678
679 ctx->set_sample_mask(ctx, 0x3 << (i * 2));
680 util_draw_fullscreen_quad_fill(cso, value, value, value, value);
681 }
682 ctx->set_sample_mask(ctx, ~0);
683
684 cso_set_vertex_shader_handle(cso, NULL);
685 cso_set_fragment_shader_handle(cso, NULL);
686 ctx->delete_vs_state(ctx, vs);
687 ctx->delete_fs_state(ctx, fs);
688 }
689
690 if (use_fbfetch) {
691 /* Fragment shader. */
692 text = "FRAG\n"
693 "DCL OUT[0], COLOR[0]\n"
694 "DCL TEMP[0]\n"
695 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
696
697 "FBFETCH TEMP[0], OUT[0]\n"
698 "ADD OUT[0], TEMP[0], IMM[0]\n"
699 "END\n";
700 } else {
701 struct pipe_sampler_view templ = {0};
702 templ.format = cb->format;
703 templ.target = cb->target;
704 templ.swizzle_r = PIPE_SWIZZLE_X;
705 templ.swizzle_g = PIPE_SWIZZLE_Y;
706 templ.swizzle_b = PIPE_SWIZZLE_Z;
707 templ.swizzle_a = PIPE_SWIZZLE_W;
708 view = ctx->create_sampler_view(ctx, cb, &templ);
709 ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, &view);
710
711 /* Fragment shader. */
712 if (num_samples > 1) {
713 text = "FRAG\n"
714 "DCL SV[0], POSITION\n"
715 "DCL SV[1], SAMPLEID\n"
716 "DCL SAMP[0]\n"
717 "DCL SVIEW[0], 2D_MSAA, FLOAT\n"
718 "DCL OUT[0], COLOR[0]\n"
719 "DCL TEMP[0]\n"
720 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
721
722 "F2I TEMP[0].xy, SV[0].xyyy\n"
723 "MOV TEMP[0].w, SV[1].xxxx\n"
724 "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n"
725 "ADD OUT[0], TEMP[0], IMM[0]\n"
726 "END\n";
727 } else {
728 text = "FRAG\n"
729 "DCL SV[0], POSITION\n"
730 "DCL SAMP[0]\n"
731 "DCL SVIEW[0], 2D, FLOAT\n"
732 "DCL OUT[0], COLOR[0]\n"
733 "DCL TEMP[0]\n"
734 "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
735 "IMM[1] INT32 { 0, 0, 0, 0}\n"
736
737 "F2I TEMP[0].xy, SV[0].xyyy\n"
738 "MOV TEMP[0].zw, IMM[1]\n"
739 "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n"
740 "ADD OUT[0], TEMP[0], IMM[0]\n"
741 "END\n";
742 }
743 }
744
745 struct tgsi_token tokens[1000];
746 struct pipe_shader_state state = {0};
747
748 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
749 assert(0);
750 util_report_result_helper(FAIL, name);
751 return;
752 }
753 pipe_shader_state_from_tgsi(&state, tokens);
754
755 void *fs = ctx->create_fs_state(ctx, &state);
756 cso_set_fragment_shader_handle(cso, fs);
757
758 /* Vertex shader. */
759 void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
760
761 if (num_samples > 1 && !use_fbfetch)
762 ctx->set_min_samples(ctx, num_samples);
763
764 for (int i = 0; i < 2; i++) {
765 ctx->texture_barrier(ctx,
766 use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER :
767 PIPE_TEXTURE_BARRIER_SAMPLER);
768 util_draw_fullscreen_quad(cso);
769 }
770 if (num_samples > 1 && !use_fbfetch)
771 ctx->set_min_samples(ctx, 1);
772
773 /* Probe pixels.
774 *
775 * For single sample:
776 * result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9)
777 *
778 * For MSAA 4x:
779 * sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8)
780 * sample1 = sample0
781 * sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0)
782 * sample3 = sample2
783 * resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9)
784 */
785 static const float expected[] = {0.3, 0.5, 0.7, 0.9};
786 bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
787 cb->width0, cb->height0, expected);
788
789 /* Cleanup. */
790 cso_destroy_context(cso);
791 ctx->delete_vs_state(ctx, vs);
792 ctx->delete_fs_state(ctx, fs);
793 pipe_sampler_view_reference(&view, NULL);
794 pipe_resource_reference(&cb, NULL);
795
796 util_report_result_helper(pass, name);
797 }
798
799 static void
test_compute_clear_image(struct pipe_context * ctx)800 test_compute_clear_image(struct pipe_context *ctx)
801 {
802 struct pipe_resource *cb;
803 const char *text;
804
805 cb = util_create_texture2d(ctx->screen, 256, 256,
806 PIPE_FORMAT_R8G8B8A8_UNORM, 1);
807
808 /* Compute shader. */
809 text = "COMP\n"
810 "PROPERTY CS_FIXED_BLOCK_WIDTH 8\n"
811 "PROPERTY CS_FIXED_BLOCK_HEIGHT 8\n"
812 "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
813 "DCL SV[0], THREAD_ID\n"
814 "DCL SV[1], BLOCK_ID\n"
815 "DCL IMAGE[0], 2D, PIPE_FORMAT_R8G8B8A8_UNORM, WR\n"
816 "DCL TEMP[0]\n"
817 "IMM[0] UINT32 { 8, 8, 0, 0}\n"
818 "IMM[1] FLT32 { 1, 0, 0, 0}\n"
819
820 /* TEMP[0].xy = SV[1] * IMM[0] + SV[0]; */
821 "UMAD TEMP[0].xy, SV[1], IMM[0], SV[0]\n"
822 "STORE IMAGE[0], TEMP[0], IMM[1], 2D, PIPE_FORMAT_R8G8B8A8_UNORM\n"
823 "END\n";
824
825 struct tgsi_token tokens[1000];
826 if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
827 assert(0);
828 util_report_result(FAIL);
829 return;
830 }
831
832 struct pipe_compute_state state = {0};
833 state.ir_type = PIPE_SHADER_IR_TGSI;
834 state.prog = tokens;
835
836 void *compute_shader = ctx->create_compute_state(ctx, &state);
837 ctx->bind_compute_state(ctx, compute_shader);
838
839 /* Bind the image. */
840 struct pipe_image_view image = {0};
841 image.resource = cb;
842 image.shader_access = image.access = PIPE_IMAGE_ACCESS_READ_WRITE;
843 image.format = cb->format;
844
845 ctx->set_shader_images(ctx, PIPE_SHADER_COMPUTE, 0, 1, 0, &image);
846
847 /* Dispatch compute. */
848 struct pipe_grid_info info = {0};
849 info.block[0] = 8;
850 info.block[1] = 8;
851 info.block[2] = 1;
852 info.grid[0] = cb->width0 / 8;
853 info.grid[1] = cb->height0 / 8;
854 info.grid[2] = 1;
855
856 ctx->launch_grid(ctx, &info);
857
858 /* Check pixels. */
859 static const float expected[] = {1.0, 0.0, 0.0, 0.0};
860 bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
861 cb->width0, cb->height0, expected);
862
863 /* Cleanup. */
864 ctx->delete_compute_state(ctx, compute_shader);
865 pipe_resource_reference(&cb, NULL);
866
867 util_report_result(pass);
868 }
869
870 #define NV12_WIDTH 2560
871 #define NV12_HEIGHT 1440
872
873 static bool
nv12_validate_resource_fields(struct pipe_resource * tex)874 nv12_validate_resource_fields(struct pipe_resource *tex)
875 {
876 return tex->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 0) &&
877 tex->width0 == NV12_WIDTH &&
878 tex->height0 == NV12_HEIGHT &&
879 tex->last_level == 0 &&
880 tex->usage == PIPE_USAGE_DEFAULT &&
881 tex->next &&
882 tex->next->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 1) &&
883 tex->next->width0 == tex->width0 / 2 &&
884 tex->next->height0 == tex->height0 / 2 &&
885 tex->next->usage == tex->usage;
886 }
887
888 /* This test enforces the behavior of NV12 allocation and exports. */
889 static void
test_nv12(struct pipe_screen * screen)890 test_nv12(struct pipe_screen *screen)
891 {
892 struct pipe_resource *tex = util_create_texture2d(screen, NV12_WIDTH, NV12_HEIGHT,
893 PIPE_FORMAT_NV12, 1);
894
895 if (!tex) {
896 printf("resource_create failed\n");
897 util_report_result(false);
898 return;
899 }
900
901 if (!nv12_validate_resource_fields(tex)) {
902 printf("incorrect pipe_resource fields\n");
903 util_report_result(false);
904 return;
905 }
906
907 /* resource_get_param */
908 if (screen->resource_get_param) {
909 struct {
910 uint64_t handle, dmabuf, offset, stride, planes;
911 } handle[3];
912
913 /* Export */
914 for (unsigned i = 0; i < 3; i++) {
915 struct pipe_resource *res = i == 2 ? tex->next : tex;
916 unsigned plane = i == 2 ? 0 : i;
917
918 if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
919 PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS,
920 0, &handle[i].handle)) {
921 printf("resource_get_param failed\n");
922 util_report_result(false);
923 goto cleanup;
924 }
925
926 if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
927 PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD,
928 0, &handle[i].dmabuf)) {
929 printf("resource_get_param failed\n");
930 util_report_result(false);
931 goto cleanup;
932 }
933
934 if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
935 PIPE_RESOURCE_PARAM_OFFSET,
936 0, &handle[i].offset)) {
937 printf("resource_get_param failed\n");
938 util_report_result(false);
939 goto cleanup;
940 }
941
942 if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
943 PIPE_RESOURCE_PARAM_STRIDE,
944 0, &handle[i].stride)) {
945 printf("resource_get_param failed\n");
946 util_report_result(false);
947 goto cleanup;
948 }
949
950 if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
951 PIPE_RESOURCE_PARAM_NPLANES,
952 0, &handle[i].planes)) {
953 printf("resource_get_param failed\n");
954 util_report_result(false);
955 goto cleanup;
956 }
957 }
958
959 /* Validate export. */
960 bool get_param_pass = /* Sanity checking */
961 handle[0].handle && handle[1].handle && handle[2].handle &&
962 handle[0].dmabuf && handle[1].dmabuf && handle[2].dmabuf &&
963 handle[0].stride && handle[1].stride && handle[2].stride &&
964 handle[0].planes == 2 &&
965 handle[1].planes == 2 &&
966 handle[2].planes == 2 &&
967 /* Different planes */
968 handle[0].handle == handle[1].handle &&
969 handle[0].offset != handle[1].offset &&
970 /* Same planes. */
971 handle[1].handle == handle[2].handle &&
972 handle[1].stride == handle[2].stride &&
973 handle[1].offset == handle[2].offset;
974
975 if (!get_param_pass) {
976 printf("resource_get_param returned incorrect values\n");
977 util_report_result(false);
978 goto cleanup;
979 }
980 }
981
982 /* resource_get_handle */
983 struct winsys_handle handle[4] = {{0}};
984
985 /* Export */
986 for (unsigned i = 0; i < 4; i++) {
987 handle[i].type = i < 2 ? WINSYS_HANDLE_TYPE_KMS : WINSYS_HANDLE_TYPE_FD;
988 handle[i].plane = i % 2;
989
990 if (!screen->resource_get_handle(screen, NULL, tex, &handle[i], 0)) {
991 printf("resource_get_handle failed\n");
992 util_report_result(false);
993 goto cleanup;
994 }
995 }
996
997 /* Validate export. */
998 bool get_handle_pass = /* Sanity checking */
999 handle[0].handle && handle[1].handle &&
1000 handle[0].stride && handle[1].stride &&
1001 handle[2].handle && handle[3].handle &&
1002 handle[2].stride && handle[3].stride &&
1003 /* KMS - different planes */
1004 handle[0].handle == handle[1].handle &&
1005 handle[0].offset != handle[1].offset &&
1006 /* DMABUF - different planes */
1007 handle[2].offset != handle[3].offset &&
1008 /* KMS and DMABUF equivalence */
1009 handle[0].offset == handle[2].offset &&
1010 handle[1].offset == handle[3].offset &&
1011 handle[0].stride == handle[2].stride &&
1012 handle[1].stride == handle[3].stride;
1013
1014 if (!get_handle_pass) {
1015 printf("resource_get_handle returned incorrect values\n");
1016 util_report_result(false);
1017 goto cleanup;
1018 }
1019
1020 util_report_result(true);
1021
1022 cleanup:
1023 pipe_resource_reference(&tex, NULL);
1024 }
1025
1026 /**
1027 * Run all tests. This should be run with a clean context after
1028 * context_create.
1029 */
1030 void
util_run_tests(struct pipe_screen * screen)1031 util_run_tests(struct pipe_screen *screen)
1032 {
1033 struct pipe_context *ctx = screen->context_create(screen, NULL, 0);
1034
1035 disabled_fragment_shader(ctx);
1036 tgsi_vs_window_space_position(ctx);
1037 null_sampler_view(ctx, TGSI_TEXTURE_2D);
1038 null_sampler_view(ctx, TGSI_TEXTURE_BUFFER);
1039 util_test_constant_buffer(ctx, NULL);
1040 test_sync_file_fences(ctx);
1041
1042 for (int i = 1; i <= 8; i = i * 2)
1043 test_texture_barrier(ctx, false, i);
1044 for (int i = 1; i <= 8; i = i * 2)
1045 test_texture_barrier(ctx, true, i);
1046 ctx->destroy(ctx);
1047
1048 ctx = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY);
1049 test_compute_clear_image(ctx);
1050 ctx->destroy(ctx);
1051
1052 test_nv12(screen);
1053
1054 puts("Done. Exiting..");
1055 exit(0);
1056 }
1057