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