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
46static struct pipe_resource *
47util_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
69static void
70util_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
88static void
89util_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
97static void
98util_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
105static void
106util_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
118static void
119util_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
137static void
138util_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
154static void *
155util_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
172static void
173util_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
187static void
188util_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
200static void
201util_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 */
221static bool
222util_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   }
265done:
266
267   free(pixels);
268   return pass;
269}
270
271static bool
272util_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
279enum {
280   SKIP = -1,
281   FAIL = 0, /* also "false" */
282   PASS = 1 /* also "true" */
283};
284
285static void
286util_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 */
315static void
316tgsi_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
368static void
369null_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
423void
424util_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
479static void
480disabled_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
527static void
528test_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
623static void
624test_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
799static void
800test_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
873static bool
874nv12_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. */
889static void
890test_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
1022cleanup:
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 */
1030void
1031util_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