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/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 <stdio.h>
42
43#define TOLERANCE 0.01
44
45static struct pipe_resource *
46util_create_texture2d(struct pipe_screen *screen, unsigned width,
47                      unsigned height, enum pipe_format format,
48                      unsigned num_samples)
49{
50   struct pipe_resource templ = {{0}};
51
52   templ.target = PIPE_TEXTURE_2D;
53   templ.width0 = width;
54   templ.height0 = height;
55   templ.depth0 = 1;
56   templ.array_size = 1;
57   templ.nr_samples = num_samples;
58   templ.nr_storage_samples = num_samples;
59   templ.format = format;
60   templ.usage = PIPE_USAGE_DEFAULT;
61   templ.bind = PIPE_BIND_SAMPLER_VIEW |
62                (util_format_is_depth_or_stencil(format) ?
63                    PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
64
65   return screen->resource_create(screen, &templ);
66}
67
68static void
69util_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
70			 struct pipe_resource *tex)
71{
72   struct pipe_surface templ = {{0}}, *surf;
73   struct pipe_framebuffer_state fb = {0};
74
75   templ.format = tex->format;
76   surf = ctx->create_surface(ctx, tex, &templ);
77
78   fb.width = tex->width0;
79   fb.height = tex->height0;
80   fb.cbufs[0] = surf;
81   fb.nr_cbufs = 1;
82
83   cso_set_framebuffer(cso, &fb);
84   pipe_surface_reference(&surf, NULL);
85}
86
87static void
88util_set_blend_normal(struct cso_context *cso)
89{
90   struct pipe_blend_state blend = {0};
91
92   blend.rt[0].colormask = PIPE_MASK_RGBA;
93   cso_set_blend(cso, &blend);
94}
95
96static void
97util_set_dsa_disable(struct cso_context *cso)
98{
99   struct pipe_depth_stencil_alpha_state dsa = {{0}};
100
101   cso_set_depth_stencil_alpha(cso, &dsa);
102}
103
104static void
105util_set_rasterizer_normal(struct cso_context *cso)
106{
107   struct pipe_rasterizer_state rs = {0};
108
109   rs.half_pixel_center = 1;
110   rs.bottom_edge_rule = 1;
111   rs.depth_clip_near = 1;
112   rs.depth_clip_far = 1;
113
114   cso_set_rasterizer(cso, &rs);
115}
116
117static void
118util_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
119{
120   struct pipe_viewport_state viewport;
121
122   viewport.scale[0] = 0.5f * tex->width0;
123   viewport.scale[1] = 0.5f * tex->height0;
124   viewport.scale[2] = 1.0f;
125   viewport.translate[0] = 0.5f * tex->width0;
126   viewport.translate[1] = 0.5f * tex->height0;
127   viewport.translate[2] = 0.0f;
128
129   cso_set_viewport(cso, &viewport);
130}
131
132static void
133util_set_interleaved_vertex_elements(struct cso_context *cso,
134                                     unsigned num_elements)
135{
136   unsigned i;
137   struct pipe_vertex_element *velem =
138      calloc(1, num_elements * sizeof(struct pipe_vertex_element));
139
140   for (i = 0; i < num_elements; i++) {
141      velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
142      velem[i].src_offset = i * 16;
143   }
144
145   cso_set_vertex_elements(cso, num_elements, velem);
146   free(velem);
147}
148
149static void *
150util_set_passthrough_vertex_shader(struct cso_context *cso,
151                                   struct pipe_context *ctx,
152                                   bool window_space)
153{
154   static const enum tgsi_semantic vs_attribs[] = {
155      TGSI_SEMANTIC_POSITION,
156      TGSI_SEMANTIC_GENERIC
157   };
158   static const uint vs_indices[] = {0, 0};
159   void *vs;
160
161   vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
162                                            window_space);
163   cso_set_vertex_shader_handle(cso, vs);
164   return vs;
165}
166
167static void
168util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
169                                 struct pipe_resource *cb)
170{
171   static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
172
173   util_set_framebuffer_cb0(cso, ctx, cb);
174   util_set_blend_normal(cso);
175   util_set_dsa_disable(cso);
176   util_set_rasterizer_normal(cso);
177   util_set_max_viewport(cso, cb);
178
179   ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
180}
181
182static void
183util_draw_fullscreen_quad(struct cso_context *cso)
184{
185   static float vertices[] = {
186     -1, -1, 0, 1,   0, 0, 0, 0,
187     -1,  1, 0, 1,   0, 1, 0, 0,
188      1,  1, 0, 1,   1, 1, 0, 0,
189      1, -1, 0, 1,   1, 0, 0, 0
190   };
191   util_set_interleaved_vertex_elements(cso, 2);
192   util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
193}
194
195static void
196util_draw_fullscreen_quad_fill(struct cso_context *cso,
197                               float r, float g, float b, float a)
198{
199   float vertices[] = {
200     -1, -1, 0, 1,   r, g, b, a,
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   };
205   util_set_interleaved_vertex_elements(cso, 2);
206   util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
207}
208
209/**
210 * Probe and test if the rectangle contains the expected color.
211 *
212 * If "num_expected_colors" > 1, at least one expected color must match
213 * the probed color. "expected" should be an array of 4*num_expected_colors
214 * floats.
215 */
216static bool
217util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
218                           unsigned offx, unsigned offy, unsigned w,
219                           unsigned h,
220                           const float *expected,
221                           unsigned num_expected_colors)
222{
223   struct pipe_transfer *transfer;
224   void *map;
225   float *pixels = malloc(w * h * 4 * sizeof(float));
226   unsigned x,y,e,c;
227   bool pass = true;
228
229   map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
230                           offx, offy, w, h, &transfer);
231   pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
232   pipe_transfer_unmap(ctx, transfer);
233
234   for (e = 0; e < num_expected_colors; e++) {
235      for (y = 0; y < h; y++) {
236         for (x = 0; x < w; x++) {
237            float *probe = &pixels[(y*w + x)*4];
238
239            for (c = 0; c < 4; c++) {
240               if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
241                  if (e < num_expected_colors-1)
242                     goto next_color; /* test the next expected color */
243
244                  printf("Probe color at (%i,%i),  ", offx+x, offy+y);
245                  printf("Expected: %.3f, %.3f, %.3f, %.3f,  ",
246                         expected[e*4], expected[e*4+1],
247                         expected[e*4+2], expected[e*4+3]);
248                  printf("Got: %.3f, %.3f, %.3f, %.3f\n",
249                         probe[0], probe[1], probe[2], probe[3]);
250                  pass = false;
251                  goto done;
252               }
253            }
254         }
255      }
256      break; /* this color was successful */
257
258   next_color:;
259   }
260done:
261
262   free(pixels);
263   return pass;
264}
265
266static bool
267util_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
268                     unsigned offx, unsigned offy, unsigned w, unsigned h,
269                     const float *expected)
270{
271   return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
272}
273
274enum {
275   SKIP = -1,
276   FAIL = 0, /* also "false" */
277   PASS = 1 /* also "true" */
278};
279
280static void
281util_report_result_helper(int status, const char *name, ...)
282{
283   char buf[256];
284   va_list ap;
285
286   va_start(ap, name);
287   util_vsnprintf(buf, sizeof(buf), name, ap);
288   va_end(ap);
289
290   printf("Test(%s) = %s\n", buf,
291          status == SKIP ? "skip" :
292          status == PASS ? "pass" : "fail");
293}
294
295#define util_report_result(status) util_report_result_helper(status, __func__)
296
297/**
298 * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
299 *
300 * The viewport state is set as usual, but it should have no effect.
301 * Clipping should also be disabled.
302 *
303 * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
304 * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
305 * multiplied by 1/w (otherwise nothing would be rendered).
306 *
307 * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
308 *       during perspective interpolation is not tested.
309 */
310static void
311tgsi_vs_window_space_position(struct pipe_context *ctx)
312{
313   struct cso_context *cso;
314   struct pipe_resource *cb;
315   void *fs, *vs;
316   bool pass = true;
317   static const float red[] = {1, 0, 0, 1};
318
319   if (!ctx->screen->get_param(ctx->screen,
320                               PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
321      util_report_result(SKIP);
322      return;
323   }
324
325   cso = cso_create_context(ctx, 0);
326   cb = util_create_texture2d(ctx->screen, 256, 256,
327                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
328   util_set_common_states_and_clear(cso, ctx, cb);
329
330   /* Fragment shader. */
331   fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
332                                       TGSI_INTERPOLATE_LINEAR, TRUE);
333   cso_set_fragment_shader_handle(cso, fs);
334
335   /* Vertex shader. */
336   vs = util_set_passthrough_vertex_shader(cso, ctx, true);
337
338   /* Draw. */
339   {
340      static float vertices[] = {
341          0,   0, 0, 0,   1,  0, 0, 1,
342          0, 256, 0, 0,   1,  0, 0, 1,
343        256, 256, 0, 0,   1,  0, 0, 1,
344        256,   0, 0, 0,   1,  0, 0, 1,
345      };
346      util_set_interleaved_vertex_elements(cso, 2);
347      util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
348   }
349
350   /* Probe pixels. */
351   pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
352                                       cb->width0, cb->height0, red);
353
354   /* Cleanup. */
355   cso_destroy_context(cso);
356   ctx->delete_vs_state(ctx, vs);
357   ctx->delete_fs_state(ctx, fs);
358   pipe_resource_reference(&cb, NULL);
359
360   util_report_result(pass);
361}
362
363static void
364null_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target)
365{
366   struct cso_context *cso;
367   struct pipe_resource *cb;
368   void *fs, *vs;
369   bool pass = true;
370   /* 2 expected colors: */
371   static const float expected_tex[] = {0, 0, 0, 1,
372                                        0, 0, 0, 0};
373   static const float expected_buf[] = {0, 0, 0, 0};
374   const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ?
375                              expected_buf : expected_tex;
376   unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2;
377
378   if (tgsi_tex_target == TGSI_TEXTURE_BUFFER &&
379       !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) {
380      util_report_result_helper(SKIP, "%s: %s", __func__,
381                                tgsi_texture_names[tgsi_tex_target]);
382      return;
383   }
384
385   cso = cso_create_context(ctx, 0);
386   cb = util_create_texture2d(ctx->screen, 256, 256,
387                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
388   util_set_common_states_and_clear(cso, ctx, cb);
389
390   ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, NULL);
391
392   /* Fragment shader. */
393   fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target,
394                                      TGSI_INTERPOLATE_LINEAR,
395                                      TGSI_RETURN_TYPE_FLOAT,
396                                      TGSI_RETURN_TYPE_FLOAT, false, false);
397   cso_set_fragment_shader_handle(cso, fs);
398
399   /* Vertex shader. */
400   vs = util_set_passthrough_vertex_shader(cso, ctx, false);
401   util_draw_fullscreen_quad(cso);
402
403   /* Probe pixels. */
404   pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
405                                  cb->width0, cb->height0, expected,
406                                  num_expected);
407
408   /* Cleanup. */
409   cso_destroy_context(cso);
410   ctx->delete_vs_state(ctx, vs);
411   ctx->delete_fs_state(ctx, fs);
412   pipe_resource_reference(&cb, NULL);
413
414   util_report_result_helper(pass, "%s: %s", __func__,
415                             tgsi_texture_names[tgsi_tex_target]);
416}
417
418void
419util_test_constant_buffer(struct pipe_context *ctx,
420                          struct pipe_resource *constbuf)
421{
422   struct cso_context *cso;
423   struct pipe_resource *cb;
424   void *fs, *vs;
425   bool pass = true;
426   static const float zero[] = {0, 0, 0, 0};
427
428   cso = cso_create_context(ctx, 0);
429   cb = util_create_texture2d(ctx->screen, 256, 256,
430                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
431   util_set_common_states_and_clear(cso, ctx, cb);
432
433   pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf);
434
435   /* Fragment shader. */
436   {
437      static const char *text = /* I don't like ureg... */
438            "FRAG\n"
439            "DCL CONST[0][0]\n"
440            "DCL OUT[0], COLOR\n"
441
442            "MOV OUT[0], CONST[0][0]\n"
443            "END\n";
444      struct tgsi_token tokens[1000];
445      struct pipe_shader_state state;
446
447      if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
448         puts("Can't compile a fragment shader.");
449         util_report_result(FAIL);
450         return;
451      }
452      pipe_shader_state_from_tgsi(&state, tokens);
453      fs = ctx->create_fs_state(ctx, &state);
454      cso_set_fragment_shader_handle(cso, fs);
455   }
456
457   /* Vertex shader. */
458   vs = util_set_passthrough_vertex_shader(cso, ctx, false);
459   util_draw_fullscreen_quad(cso);
460
461   /* Probe pixels. */
462   pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0,
463                                       cb->height0, zero);
464
465   /* Cleanup. */
466   cso_destroy_context(cso);
467   ctx->delete_vs_state(ctx, vs);
468   ctx->delete_fs_state(ctx, fs);
469   pipe_resource_reference(&cb, NULL);
470
471   util_report_result(pass);
472}
473
474static void
475null_fragment_shader(struct pipe_context *ctx)
476{
477   struct cso_context *cso;
478   struct pipe_resource *cb;
479   void *vs;
480   struct pipe_rasterizer_state rs = {0};
481   struct pipe_query *query;
482   union pipe_query_result qresult;
483
484   cso = cso_create_context(ctx, 0);
485   cb = util_create_texture2d(ctx->screen, 256, 256,
486                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
487   util_set_common_states_and_clear(cso, ctx, cb);
488
489   /* No rasterization. */
490   rs.rasterizer_discard = 1;
491   cso_set_rasterizer(cso, &rs);
492
493   vs = util_set_passthrough_vertex_shader(cso, ctx, false);
494
495   query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0);
496   ctx->begin_query(ctx, query);
497   util_draw_fullscreen_quad(cso);
498   ctx->end_query(ctx, query);
499   ctx->get_query_result(ctx, query, true, &qresult);
500
501   /* Cleanup. */
502   cso_destroy_context(cso);
503   ctx->delete_vs_state(ctx, vs);
504   ctx->destroy_query(ctx, query);
505   pipe_resource_reference(&cb, NULL);
506
507   /* Check PRIMITIVES_GENERATED. */
508   util_report_result(qresult.u64 == 2);
509}
510
511#if defined(PIPE_OS_LINUX) && defined(HAVE_LIBDRM)
512#include <libsync.h>
513#else
514#define sync_merge(str, fd1, fd2) (-1)
515#define sync_wait(fd, timeout) (-1)
516#endif
517
518static void
519test_sync_file_fences(struct pipe_context *ctx)
520{
521   struct pipe_screen *screen = ctx->screen;
522   bool pass = true;
523   enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC;
524
525   if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
526      return;
527
528   struct cso_context *cso = cso_create_context(ctx, 0);
529   struct pipe_resource *buf =
530      pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024);
531   struct pipe_resource *tex =
532      util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0);
533   struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL;
534
535   /* Run 2 clears, get fencess. */
536   uint32_t value = 0;
537   ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
538   ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD);
539
540   struct pipe_box box;
541   u_box_2d(0, 0, tex->width0, tex->height0, &box);
542   ctx->clear_texture(ctx, tex, 0, &box, &value);
543   ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD);
544   pass = pass && buf_fence && tex_fence;
545
546   /* Export fences. */
547   int buf_fd = screen->fence_get_fd(screen, buf_fence);
548   int tex_fd = screen->fence_get_fd(screen, tex_fence);
549   pass = pass && buf_fd >= 0 && tex_fd >= 0;
550
551   /* Merge fences. */
552   int merged_fd = sync_merge("test", buf_fd, tex_fd);
553   pass = pass && merged_fd >= 0;
554
555   /* (Re)import all fences. */
556   struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL;
557   struct pipe_fence_handle *merged_fence = NULL;
558   ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type);
559   ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type);
560   ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type);
561   pass = pass && re_buf_fence && re_tex_fence && merged_fence;
562
563   /* Run another clear after waiting for everything. */
564   struct pipe_fence_handle *final_fence = NULL;
565   ctx->fence_server_sync(ctx, merged_fence);
566   value = 0xff;
567   ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
568   ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD);
569   pass = pass && final_fence;
570
571   /* Wait for the last fence. */
572   int final_fd = screen->fence_get_fd(screen, final_fence);
573   pass = pass && final_fd >= 0;
574   pass = pass && sync_wait(final_fd, -1) == 0;
575
576   /* Check that all fences are signalled. */
577   pass = pass && sync_wait(buf_fd, 0) == 0;
578   pass = pass && sync_wait(tex_fd, 0) == 0;
579   pass = pass && sync_wait(merged_fd, 0) == 0;
580
581   pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0);
582   pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0);
583   pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0);
584   pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0);
585   pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0);
586   pass = pass && screen->fence_finish(screen, NULL, final_fence, 0);
587
588   /* Cleanup. */
589#ifndef PIPE_OS_WINDOWS
590   if (buf_fd >= 0)
591      close(buf_fd);
592   if (tex_fd >= 0)
593      close(tex_fd);
594   if (merged_fd >= 0)
595      close(merged_fd);
596   if (final_fd >= 0)
597      close(final_fd);
598#endif
599
600   screen->fence_reference(screen, &buf_fence, NULL);
601   screen->fence_reference(screen, &tex_fence, NULL);
602   screen->fence_reference(screen, &re_buf_fence, NULL);
603   screen->fence_reference(screen, &re_tex_fence, NULL);
604   screen->fence_reference(screen, &merged_fence, NULL);
605   screen->fence_reference(screen, &final_fence, NULL);
606
607   cso_destroy_context(cso);
608   pipe_resource_reference(&buf, NULL);
609   pipe_resource_reference(&tex, NULL);
610
611   util_report_result(pass);
612}
613
614static void
615test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
616                     unsigned num_samples)
617{
618   struct cso_context *cso;
619   struct pipe_resource *cb;
620   struct pipe_sampler_view *view = NULL;
621   char name[256];
622   const char *text;
623
624   assert(num_samples >= 1 && num_samples <= 8);
625
626   util_snprintf(name, sizeof(name), "%s: %s, %u samples", __func__,
627                 use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1));
628
629   if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) {
630      util_report_result_helper(SKIP, name);
631      return;
632   }
633   if (use_fbfetch &&
634       !ctx->screen->get_param(ctx->screen, PIPE_CAP_TGSI_FS_FBFETCH)) {
635      util_report_result_helper(SKIP, name);
636      return;
637   }
638
639   cso = cso_create_context(ctx, 0);
640   cb = util_create_texture2d(ctx->screen, 256, 256,
641                              PIPE_FORMAT_R8G8B8A8_UNORM, num_samples);
642   util_set_common_states_and_clear(cso, ctx, cb);
643
644   /* Clear each sample to a different value. */
645   if (num_samples > 1) {
646      void *fs =
647         util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
648                                               TGSI_INTERPOLATE_LINEAR, TRUE);
649      cso_set_fragment_shader_handle(cso, fs);
650
651      /* Vertex shader. */
652      void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
653
654      for (unsigned i = 0; i < num_samples / 2; i++) {
655         float value;
656
657         /* 2 consecutive samples should have the same color to test MSAA
658          * compression properly.
659          */
660         if (num_samples == 2) {
661            value = 0.1;
662         } else {
663            /* The average value must be 0.1 */
664            static const float values[] = {
665               0.0, 0.2, 0.05, 0.15
666            };
667            value = values[i];
668         }
669
670         ctx->set_sample_mask(ctx, 0x3 << (i * 2));
671         util_draw_fullscreen_quad_fill(cso, value, value, value, value);
672      }
673      ctx->set_sample_mask(ctx, ~0);
674
675      cso_set_vertex_shader_handle(cso, NULL);
676      cso_set_fragment_shader_handle(cso, NULL);
677      ctx->delete_vs_state(ctx, vs);
678      ctx->delete_fs_state(ctx, fs);
679   }
680
681   if (use_fbfetch) {
682      /* Fragment shader. */
683      text = "FRAG\n"
684             "DCL OUT[0], COLOR[0]\n"
685             "DCL TEMP[0]\n"
686             "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
687
688             "FBFETCH TEMP[0], OUT[0]\n"
689             "ADD OUT[0], TEMP[0], IMM[0]\n"
690             "END\n";
691   } else {
692      struct pipe_sampler_view templ = {{0}};
693      templ.format = cb->format;
694      templ.target = cb->target;
695      templ.swizzle_r = PIPE_SWIZZLE_X;
696      templ.swizzle_g = PIPE_SWIZZLE_Y;
697      templ.swizzle_b = PIPE_SWIZZLE_Z;
698      templ.swizzle_a = PIPE_SWIZZLE_W;
699      view = ctx->create_sampler_view(ctx, cb, &templ);
700      ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, &view);
701
702      /* Fragment shader. */
703      if (num_samples > 1) {
704         text = "FRAG\n"
705                "DCL SV[0], POSITION\n"
706                "DCL SV[1], SAMPLEID\n"
707                "DCL SAMP[0]\n"
708                "DCL SVIEW[0], 2D_MSAA, FLOAT\n"
709                "DCL OUT[0], COLOR[0]\n"
710                "DCL TEMP[0]\n"
711                "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
712
713                "F2I TEMP[0].xy, SV[0].xyyy\n"
714                "MOV TEMP[0].w, SV[1].xxxx\n"
715                "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n"
716                "ADD OUT[0], TEMP[0], IMM[0]\n"
717                "END\n";
718      } else {
719         text = "FRAG\n"
720                "DCL SV[0], POSITION\n"
721                "DCL SAMP[0]\n"
722                "DCL SVIEW[0], 2D, FLOAT\n"
723                "DCL OUT[0], COLOR[0]\n"
724                "DCL TEMP[0]\n"
725                "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
726                "IMM[1] INT32 { 0, 0, 0, 0}\n"
727
728                "F2I TEMP[0].xy, SV[0].xyyy\n"
729                "MOV TEMP[0].zw, IMM[1]\n"
730                "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n"
731                "ADD OUT[0], TEMP[0], IMM[0]\n"
732                "END\n";
733      }
734   }
735
736   struct tgsi_token tokens[1000];
737   struct pipe_shader_state state;
738
739   if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
740      assert(0);
741      util_report_result_helper(FAIL, name);
742      return;
743   }
744   pipe_shader_state_from_tgsi(&state, tokens);
745
746   void *fs = ctx->create_fs_state(ctx, &state);
747   cso_set_fragment_shader_handle(cso, fs);
748
749   /* Vertex shader. */
750   void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
751
752   if (num_samples > 1 && !use_fbfetch)
753      ctx->set_min_samples(ctx, num_samples);
754
755   for (int i = 0; i < 2; i++) {
756      ctx->texture_barrier(ctx,
757                           use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER :
758                                         PIPE_TEXTURE_BARRIER_SAMPLER);
759      util_draw_fullscreen_quad(cso);
760   }
761   if (num_samples > 1 && !use_fbfetch)
762      ctx->set_min_samples(ctx, 1);
763
764   /* Probe pixels.
765    *
766    * For single sample:
767    *   result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9)
768    *
769    * For MSAA 4x:
770    *   sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8)
771    *   sample1 = sample0
772    *   sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0)
773    *   sample3 = sample2
774    *   resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9)
775    */
776   static const float expected[] = {0.3, 0.5, 0.7, 0.9};
777   bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
778                                    cb->width0, cb->height0, expected);
779
780   /* Cleanup. */
781   cso_destroy_context(cso);
782   ctx->delete_vs_state(ctx, vs);
783   ctx->delete_fs_state(ctx, fs);
784   pipe_sampler_view_reference(&view, NULL);
785   pipe_resource_reference(&cb, NULL);
786
787   util_report_result_helper(pass, name);
788}
789
790static void
791test_compute_clear_image(struct pipe_context *ctx)
792{
793   struct pipe_resource *cb;
794   const char *text;
795
796   cb = util_create_texture2d(ctx->screen, 256, 256,
797                              PIPE_FORMAT_R8G8B8A8_UNORM, 1);
798
799   /* Compute shader. */
800   text = "COMP\n"
801          "PROPERTY CS_FIXED_BLOCK_WIDTH 8\n"
802          "PROPERTY CS_FIXED_BLOCK_HEIGHT 8\n"
803          "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
804          "DCL SV[0], THREAD_ID\n"
805          "DCL SV[1], BLOCK_ID\n"
806          "DCL IMAGE[0], 2D, PIPE_FORMAT_R8G8B8A8_UNORM, WR\n"
807          "DCL TEMP[0]\n"
808          "IMM[0] UINT32 { 8, 8, 0, 0}\n"
809          "IMM[1] FLT32 { 1, 0, 0, 0}\n"
810
811          /* TEMP[0].xy = SV[1] * IMM[0] + SV[0]; */
812          "UMAD TEMP[0].xy, SV[1], IMM[0], SV[0]\n"
813          "STORE IMAGE[0], TEMP[0], IMM[1], 2D, PIPE_FORMAT_R8G8B8A8_UNORM\n"
814          "END\n";
815
816   struct tgsi_token tokens[1000];
817   if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
818      assert(0);
819      util_report_result(FAIL);
820      return;
821   }
822
823   struct pipe_compute_state state = {0};
824   state.ir_type = PIPE_SHADER_IR_TGSI;
825   state.prog = tokens;
826
827   void *compute_shader = ctx->create_compute_state(ctx, &state);
828   ctx->bind_compute_state(ctx, compute_shader);
829
830   /* Bind the image. */
831   struct pipe_image_view image = {0};
832   image.resource = cb;
833   image.shader_access = image.access = PIPE_IMAGE_ACCESS_READ_WRITE;
834   image.format = cb->format;
835
836   ctx->set_shader_images(ctx, PIPE_SHADER_COMPUTE, 0, 1, &image);
837
838   /* Dispatch compute. */
839   struct pipe_grid_info info = {0};
840   info.block[0] = 8;
841   info.block[1] = 8;
842   info.block[2] = 1;
843   info.grid[0] = cb->width0 / 8;
844   info.grid[1] = cb->height0 / 8;
845   info.grid[2] = 1;
846
847   ctx->launch_grid(ctx, &info);
848
849   /* Check pixels. */
850   static const float expected[] = {1.0, 0.0, 0.0, 0.0};
851   bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
852                                    cb->width0, cb->height0, expected);
853
854   /* Cleanup. */
855   ctx->delete_compute_state(ctx, compute_shader);
856   pipe_resource_reference(&cb, NULL);
857
858   util_report_result(pass);
859}
860
861/**
862 * Run all tests. This should be run with a clean context after
863 * context_create.
864 */
865void
866util_run_tests(struct pipe_screen *screen)
867{
868   struct pipe_context *ctx = screen->context_create(screen, NULL, 0);
869
870   null_fragment_shader(ctx);
871   tgsi_vs_window_space_position(ctx);
872   null_sampler_view(ctx, TGSI_TEXTURE_2D);
873   null_sampler_view(ctx, TGSI_TEXTURE_BUFFER);
874   util_test_constant_buffer(ctx, NULL);
875   test_sync_file_fences(ctx);
876
877   for (int i = 1; i <= 8; i = i * 2)
878      test_texture_barrier(ctx, false, i);
879   for (int i = 1; i <= 8; i = i * 2)
880      test_texture_barrier(ctx, true, i);
881   ctx->destroy(ctx);
882
883   ctx = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY);
884   test_compute_clear_image(ctx);
885   ctx->destroy(ctx);
886
887   puts("Done. Exiting..");
888   exit(0);
889}
890