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