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