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