• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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