101e04c3fSmrg/**************************************************************************
201e04c3fSmrg *
301e04c3fSmrg * Copyright 2014 Advanced Micro Devices, Inc.
401e04c3fSmrg * All Rights Reserved.
501e04c3fSmrg *
601e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
701e04c3fSmrg * copy of this software and associated documentation files (the
801e04c3fSmrg * "Software"), to deal in the Software without restriction, including
901e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish,
1001e04c3fSmrg * distribute, sub license, and/or sell copies of the Software, and to
1101e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to
1201e04c3fSmrg * the following conditions:
1301e04c3fSmrg *
1401e04c3fSmrg * The above copyright notice and this permission notice (including the
1501e04c3fSmrg * next paragraph) shall be included in all copies or substantial portions
1601e04c3fSmrg * of the Software.
1701e04c3fSmrg *
1801e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1901e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2001e04c3fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2101e04c3fSmrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
2201e04c3fSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2301e04c3fSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2401e04c3fSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2501e04c3fSmrg *
2601e04c3fSmrg **************************************************************************/
2701e04c3fSmrg
2801e04c3fSmrg#include "util/u_tests.h"
2901e04c3fSmrg
3001e04c3fSmrg#include "util/u_draw_quad.h"
317ec681f3Smrg#include "util/format/u_format.h"
3201e04c3fSmrg#include "util/u_inlines.h"
3301e04c3fSmrg#include "util/u_memory.h"
3401e04c3fSmrg#include "util/u_simple_shaders.h"
3501e04c3fSmrg#include "util/u_surface.h"
3601e04c3fSmrg#include "util/u_string.h"
3701e04c3fSmrg#include "util/u_tile.h"
3801e04c3fSmrg#include "tgsi/tgsi_strings.h"
3901e04c3fSmrg#include "tgsi/tgsi_text.h"
4001e04c3fSmrg#include "cso_cache/cso_context.h"
417ec681f3Smrg#include "frontend/winsys_handle.h"
4201e04c3fSmrg#include <stdio.h>
4301e04c3fSmrg
4401e04c3fSmrg#define TOLERANCE 0.01
4501e04c3fSmrg
4601e04c3fSmrgstatic struct pipe_resource *
4701e04c3fSmrgutil_create_texture2d(struct pipe_screen *screen, unsigned width,
4801e04c3fSmrg                      unsigned height, enum pipe_format format,
4901e04c3fSmrg                      unsigned num_samples)
5001e04c3fSmrg{
517ec681f3Smrg   struct pipe_resource templ = {0};
5201e04c3fSmrg
5301e04c3fSmrg   templ.target = PIPE_TEXTURE_2D;
5401e04c3fSmrg   templ.width0 = width;
5501e04c3fSmrg   templ.height0 = height;
5601e04c3fSmrg   templ.depth0 = 1;
5701e04c3fSmrg   templ.array_size = 1;
5801e04c3fSmrg   templ.nr_samples = num_samples;
5901e04c3fSmrg   templ.nr_storage_samples = num_samples;
6001e04c3fSmrg   templ.format = format;
6101e04c3fSmrg   templ.usage = PIPE_USAGE_DEFAULT;
6201e04c3fSmrg   templ.bind = PIPE_BIND_SAMPLER_VIEW |
6301e04c3fSmrg                (util_format_is_depth_or_stencil(format) ?
6401e04c3fSmrg                    PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET);
6501e04c3fSmrg
6601e04c3fSmrg   return screen->resource_create(screen, &templ);
6701e04c3fSmrg}
6801e04c3fSmrg
6901e04c3fSmrgstatic void
7001e04c3fSmrgutil_set_framebuffer_cb0(struct cso_context *cso, struct pipe_context *ctx,
7101e04c3fSmrg			 struct pipe_resource *tex)
7201e04c3fSmrg{
7301e04c3fSmrg   struct pipe_surface templ = {{0}}, *surf;
7401e04c3fSmrg   struct pipe_framebuffer_state fb = {0};
7501e04c3fSmrg
7601e04c3fSmrg   templ.format = tex->format;
7701e04c3fSmrg   surf = ctx->create_surface(ctx, tex, &templ);
7801e04c3fSmrg
7901e04c3fSmrg   fb.width = tex->width0;
8001e04c3fSmrg   fb.height = tex->height0;
8101e04c3fSmrg   fb.cbufs[0] = surf;
8201e04c3fSmrg   fb.nr_cbufs = 1;
8301e04c3fSmrg
8401e04c3fSmrg   cso_set_framebuffer(cso, &fb);
8501e04c3fSmrg   pipe_surface_reference(&surf, NULL);
8601e04c3fSmrg}
8701e04c3fSmrg
8801e04c3fSmrgstatic void
8901e04c3fSmrgutil_set_blend_normal(struct cso_context *cso)
9001e04c3fSmrg{
9101e04c3fSmrg   struct pipe_blend_state blend = {0};
9201e04c3fSmrg
9301e04c3fSmrg   blend.rt[0].colormask = PIPE_MASK_RGBA;
9401e04c3fSmrg   cso_set_blend(cso, &blend);
9501e04c3fSmrg}
9601e04c3fSmrg
9701e04c3fSmrgstatic void
9801e04c3fSmrgutil_set_dsa_disable(struct cso_context *cso)
9901e04c3fSmrg{
1007ec681f3Smrg   struct pipe_depth_stencil_alpha_state dsa = {{{0}}};
10101e04c3fSmrg
10201e04c3fSmrg   cso_set_depth_stencil_alpha(cso, &dsa);
10301e04c3fSmrg}
10401e04c3fSmrg
10501e04c3fSmrgstatic void
10601e04c3fSmrgutil_set_rasterizer_normal(struct cso_context *cso)
10701e04c3fSmrg{
10801e04c3fSmrg   struct pipe_rasterizer_state rs = {0};
10901e04c3fSmrg
11001e04c3fSmrg   rs.half_pixel_center = 1;
11101e04c3fSmrg   rs.bottom_edge_rule = 1;
11201e04c3fSmrg   rs.depth_clip_near = 1;
11301e04c3fSmrg   rs.depth_clip_far = 1;
11401e04c3fSmrg
11501e04c3fSmrg   cso_set_rasterizer(cso, &rs);
11601e04c3fSmrg}
11701e04c3fSmrg
11801e04c3fSmrgstatic void
11901e04c3fSmrgutil_set_max_viewport(struct cso_context *cso, struct pipe_resource *tex)
12001e04c3fSmrg{
12101e04c3fSmrg   struct pipe_viewport_state viewport;
12201e04c3fSmrg
12301e04c3fSmrg   viewport.scale[0] = 0.5f * tex->width0;
12401e04c3fSmrg   viewport.scale[1] = 0.5f * tex->height0;
12501e04c3fSmrg   viewport.scale[2] = 1.0f;
12601e04c3fSmrg   viewport.translate[0] = 0.5f * tex->width0;
12701e04c3fSmrg   viewport.translate[1] = 0.5f * tex->height0;
12801e04c3fSmrg   viewport.translate[2] = 0.0f;
1297ec681f3Smrg   viewport.swizzle_x = PIPE_VIEWPORT_SWIZZLE_POSITIVE_X;
1307ec681f3Smrg   viewport.swizzle_y = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Y;
1317ec681f3Smrg   viewport.swizzle_z = PIPE_VIEWPORT_SWIZZLE_POSITIVE_Z;
1327ec681f3Smrg   viewport.swizzle_w = PIPE_VIEWPORT_SWIZZLE_POSITIVE_W;
13301e04c3fSmrg
13401e04c3fSmrg   cso_set_viewport(cso, &viewport);
13501e04c3fSmrg}
13601e04c3fSmrg
13701e04c3fSmrgstatic void
13801e04c3fSmrgutil_set_interleaved_vertex_elements(struct cso_context *cso,
13901e04c3fSmrg                                     unsigned num_elements)
14001e04c3fSmrg{
1417ec681f3Smrg   struct cso_velems_state velem;
14201e04c3fSmrg   unsigned i;
14301e04c3fSmrg
1447ec681f3Smrg   memset(&velem, 0, sizeof(velem));
1457ec681f3Smrg   velem.count = num_elements;
14601e04c3fSmrg   for (i = 0; i < num_elements; i++) {
1477ec681f3Smrg      velem.velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
1487ec681f3Smrg      velem.velems[i].src_offset = i * 16;
14901e04c3fSmrg   }
15001e04c3fSmrg
1517ec681f3Smrg   cso_set_vertex_elements(cso, &velem);
15201e04c3fSmrg}
15301e04c3fSmrg
15401e04c3fSmrgstatic void *
15501e04c3fSmrgutil_set_passthrough_vertex_shader(struct cso_context *cso,
15601e04c3fSmrg                                   struct pipe_context *ctx,
15701e04c3fSmrg                                   bool window_space)
15801e04c3fSmrg{
15901e04c3fSmrg   static const enum tgsi_semantic vs_attribs[] = {
16001e04c3fSmrg      TGSI_SEMANTIC_POSITION,
16101e04c3fSmrg      TGSI_SEMANTIC_GENERIC
16201e04c3fSmrg   };
16301e04c3fSmrg   static const uint vs_indices[] = {0, 0};
16401e04c3fSmrg   void *vs;
16501e04c3fSmrg
16601e04c3fSmrg   vs = util_make_vertex_passthrough_shader(ctx, 2, vs_attribs, vs_indices,
16701e04c3fSmrg                                            window_space);
16801e04c3fSmrg   cso_set_vertex_shader_handle(cso, vs);
16901e04c3fSmrg   return vs;
17001e04c3fSmrg}
17101e04c3fSmrg
17201e04c3fSmrgstatic void
17301e04c3fSmrgutil_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *ctx,
17401e04c3fSmrg                                 struct pipe_resource *cb)
17501e04c3fSmrg{
17601e04c3fSmrg   static const float clear_color[] = {0.1, 0.1, 0.1, 0.1};
17701e04c3fSmrg
17801e04c3fSmrg   util_set_framebuffer_cb0(cso, ctx, cb);
17901e04c3fSmrg   util_set_blend_normal(cso);
18001e04c3fSmrg   util_set_dsa_disable(cso);
18101e04c3fSmrg   util_set_rasterizer_normal(cso);
18201e04c3fSmrg   util_set_max_viewport(cso, cb);
18301e04c3fSmrg
1847ec681f3Smrg   ctx->clear(ctx, PIPE_CLEAR_COLOR0, NULL, (void*)clear_color, 0, 0);
18501e04c3fSmrg}
18601e04c3fSmrg
18701e04c3fSmrgstatic void
18801e04c3fSmrgutil_draw_fullscreen_quad(struct cso_context *cso)
18901e04c3fSmrg{
19001e04c3fSmrg   static float vertices[] = {
19101e04c3fSmrg     -1, -1, 0, 1,   0, 0, 0, 0,
19201e04c3fSmrg     -1,  1, 0, 1,   0, 1, 0, 0,
19301e04c3fSmrg      1,  1, 0, 1,   1, 1, 0, 0,
19401e04c3fSmrg      1, -1, 0, 1,   1, 0, 0, 0
19501e04c3fSmrg   };
19601e04c3fSmrg   util_set_interleaved_vertex_elements(cso, 2);
19701e04c3fSmrg   util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
19801e04c3fSmrg}
19901e04c3fSmrg
20001e04c3fSmrgstatic void
20101e04c3fSmrgutil_draw_fullscreen_quad_fill(struct cso_context *cso,
20201e04c3fSmrg                               float r, float g, float b, float a)
20301e04c3fSmrg{
20401e04c3fSmrg   float vertices[] = {
20501e04c3fSmrg     -1, -1, 0, 1,   r, g, b, a,
20601e04c3fSmrg     -1,  1, 0, 1,   r, g, b, a,
20701e04c3fSmrg      1,  1, 0, 1,   r, g, b, a,
20801e04c3fSmrg      1, -1, 0, 1,   r, g, b, a,
20901e04c3fSmrg   };
21001e04c3fSmrg   util_set_interleaved_vertex_elements(cso, 2);
21101e04c3fSmrg   util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
21201e04c3fSmrg}
21301e04c3fSmrg
21401e04c3fSmrg/**
21501e04c3fSmrg * Probe and test if the rectangle contains the expected color.
21601e04c3fSmrg *
21701e04c3fSmrg * If "num_expected_colors" > 1, at least one expected color must match
21801e04c3fSmrg * the probed color. "expected" should be an array of 4*num_expected_colors
21901e04c3fSmrg * floats.
22001e04c3fSmrg */
22101e04c3fSmrgstatic bool
22201e04c3fSmrgutil_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
22301e04c3fSmrg                           unsigned offx, unsigned offy, unsigned w,
22401e04c3fSmrg                           unsigned h,
22501e04c3fSmrg                           const float *expected,
22601e04c3fSmrg                           unsigned num_expected_colors)
22701e04c3fSmrg{
22801e04c3fSmrg   struct pipe_transfer *transfer;
22901e04c3fSmrg   void *map;
23001e04c3fSmrg   float *pixels = malloc(w * h * 4 * sizeof(float));
23101e04c3fSmrg   unsigned x,y,e,c;
23201e04c3fSmrg   bool pass = true;
23301e04c3fSmrg
2347ec681f3Smrg   map = pipe_texture_map(ctx, tex, 0, 0, PIPE_MAP_READ,
23501e04c3fSmrg                           offx, offy, w, h, &transfer);
2367ec681f3Smrg   pipe_get_tile_rgba(transfer, map, 0, 0, w, h, tex->format, pixels);
2377ec681f3Smrg   pipe_texture_unmap(ctx, transfer);
23801e04c3fSmrg
23901e04c3fSmrg   for (e = 0; e < num_expected_colors; e++) {
24001e04c3fSmrg      for (y = 0; y < h; y++) {
24101e04c3fSmrg         for (x = 0; x < w; x++) {
24201e04c3fSmrg            float *probe = &pixels[(y*w + x)*4];
24301e04c3fSmrg
24401e04c3fSmrg            for (c = 0; c < 4; c++) {
24501e04c3fSmrg               if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) {
24601e04c3fSmrg                  if (e < num_expected_colors-1)
24701e04c3fSmrg                     goto next_color; /* test the next expected color */
24801e04c3fSmrg
24901e04c3fSmrg                  printf("Probe color at (%i,%i),  ", offx+x, offy+y);
25001e04c3fSmrg                  printf("Expected: %.3f, %.3f, %.3f, %.3f,  ",
25101e04c3fSmrg                         expected[e*4], expected[e*4+1],
25201e04c3fSmrg                         expected[e*4+2], expected[e*4+3]);
25301e04c3fSmrg                  printf("Got: %.3f, %.3f, %.3f, %.3f\n",
25401e04c3fSmrg                         probe[0], probe[1], probe[2], probe[3]);
25501e04c3fSmrg                  pass = false;
25601e04c3fSmrg                  goto done;
25701e04c3fSmrg               }
25801e04c3fSmrg            }
25901e04c3fSmrg         }
26001e04c3fSmrg      }
26101e04c3fSmrg      break; /* this color was successful */
26201e04c3fSmrg
26301e04c3fSmrg   next_color:;
26401e04c3fSmrg   }
26501e04c3fSmrgdone:
26601e04c3fSmrg
26701e04c3fSmrg   free(pixels);
26801e04c3fSmrg   return pass;
26901e04c3fSmrg}
27001e04c3fSmrg
27101e04c3fSmrgstatic bool
27201e04c3fSmrgutil_probe_rect_rgba(struct pipe_context *ctx, struct pipe_resource *tex,
27301e04c3fSmrg                     unsigned offx, unsigned offy, unsigned w, unsigned h,
27401e04c3fSmrg                     const float *expected)
27501e04c3fSmrg{
27601e04c3fSmrg   return util_probe_rect_rgba_multi(ctx, tex, offx, offy, w, h, expected, 1);
27701e04c3fSmrg}
27801e04c3fSmrg
27901e04c3fSmrgenum {
28001e04c3fSmrg   SKIP = -1,
28101e04c3fSmrg   FAIL = 0, /* also "false" */
28201e04c3fSmrg   PASS = 1 /* also "true" */
28301e04c3fSmrg};
28401e04c3fSmrg
28501e04c3fSmrgstatic void
28601e04c3fSmrgutil_report_result_helper(int status, const char *name, ...)
28701e04c3fSmrg{
28801e04c3fSmrg   char buf[256];
28901e04c3fSmrg   va_list ap;
29001e04c3fSmrg
29101e04c3fSmrg   va_start(ap, name);
2927ec681f3Smrg   vsnprintf(buf, sizeof(buf), name, ap);
29301e04c3fSmrg   va_end(ap);
29401e04c3fSmrg
29501e04c3fSmrg   printf("Test(%s) = %s\n", buf,
29601e04c3fSmrg          status == SKIP ? "skip" :
29701e04c3fSmrg          status == PASS ? "pass" : "fail");
29801e04c3fSmrg}
29901e04c3fSmrg
30001e04c3fSmrg#define util_report_result(status) util_report_result_helper(status, __func__)
30101e04c3fSmrg
30201e04c3fSmrg/**
30301e04c3fSmrg * Test TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION.
30401e04c3fSmrg *
30501e04c3fSmrg * The viewport state is set as usual, but it should have no effect.
30601e04c3fSmrg * Clipping should also be disabled.
30701e04c3fSmrg *
30801e04c3fSmrg * POSITION.xyz should already be multiplied by 1/w and POSITION.w should
30901e04c3fSmrg * contain 1/w. By setting w=0, we can test that POSITION.xyz isn't
31001e04c3fSmrg * multiplied by 1/w (otherwise nothing would be rendered).
31101e04c3fSmrg *
31201e04c3fSmrg * TODO: Whether the value of POSITION.w is correctly interpreted as 1/w
31301e04c3fSmrg *       during perspective interpolation is not tested.
31401e04c3fSmrg */
31501e04c3fSmrgstatic void
31601e04c3fSmrgtgsi_vs_window_space_position(struct pipe_context *ctx)
31701e04c3fSmrg{
31801e04c3fSmrg   struct cso_context *cso;
31901e04c3fSmrg   struct pipe_resource *cb;
32001e04c3fSmrg   void *fs, *vs;
32101e04c3fSmrg   bool pass = true;
32201e04c3fSmrg   static const float red[] = {1, 0, 0, 1};
32301e04c3fSmrg
32401e04c3fSmrg   if (!ctx->screen->get_param(ctx->screen,
32501e04c3fSmrg                               PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) {
32601e04c3fSmrg      util_report_result(SKIP);
32701e04c3fSmrg      return;
32801e04c3fSmrg   }
32901e04c3fSmrg
33001e04c3fSmrg   cso = cso_create_context(ctx, 0);
33101e04c3fSmrg   cb = util_create_texture2d(ctx->screen, 256, 256,
33201e04c3fSmrg                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
33301e04c3fSmrg   util_set_common_states_and_clear(cso, ctx, cb);
33401e04c3fSmrg
33501e04c3fSmrg   /* Fragment shader. */
33601e04c3fSmrg   fs = util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
33701e04c3fSmrg                                       TGSI_INTERPOLATE_LINEAR, TRUE);
33801e04c3fSmrg   cso_set_fragment_shader_handle(cso, fs);
33901e04c3fSmrg
34001e04c3fSmrg   /* Vertex shader. */
34101e04c3fSmrg   vs = util_set_passthrough_vertex_shader(cso, ctx, true);
34201e04c3fSmrg
34301e04c3fSmrg   /* Draw. */
34401e04c3fSmrg   {
34501e04c3fSmrg      static float vertices[] = {
34601e04c3fSmrg          0,   0, 0, 0,   1,  0, 0, 1,
34701e04c3fSmrg          0, 256, 0, 0,   1,  0, 0, 1,
34801e04c3fSmrg        256, 256, 0, 0,   1,  0, 0, 1,
34901e04c3fSmrg        256,   0, 0, 0,   1,  0, 0, 1,
35001e04c3fSmrg      };
35101e04c3fSmrg      util_set_interleaved_vertex_elements(cso, 2);
35201e04c3fSmrg      util_draw_user_vertex_buffer(cso, vertices, PIPE_PRIM_QUADS, 4, 2);
35301e04c3fSmrg   }
35401e04c3fSmrg
35501e04c3fSmrg   /* Probe pixels. */
35601e04c3fSmrg   pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0,
35701e04c3fSmrg                                       cb->width0, cb->height0, red);
35801e04c3fSmrg
35901e04c3fSmrg   /* Cleanup. */
36001e04c3fSmrg   cso_destroy_context(cso);
36101e04c3fSmrg   ctx->delete_vs_state(ctx, vs);
36201e04c3fSmrg   ctx->delete_fs_state(ctx, fs);
36301e04c3fSmrg   pipe_resource_reference(&cb, NULL);
36401e04c3fSmrg
36501e04c3fSmrg   util_report_result(pass);
36601e04c3fSmrg}
36701e04c3fSmrg
36801e04c3fSmrgstatic void
36901e04c3fSmrgnull_sampler_view(struct pipe_context *ctx, unsigned tgsi_tex_target)
37001e04c3fSmrg{
37101e04c3fSmrg   struct cso_context *cso;
37201e04c3fSmrg   struct pipe_resource *cb;
37301e04c3fSmrg   void *fs, *vs;
37401e04c3fSmrg   bool pass = true;
37501e04c3fSmrg   /* 2 expected colors: */
37601e04c3fSmrg   static const float expected_tex[] = {0, 0, 0, 1,
37701e04c3fSmrg                                        0, 0, 0, 0};
37801e04c3fSmrg   static const float expected_buf[] = {0, 0, 0, 0};
37901e04c3fSmrg   const float *expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ?
38001e04c3fSmrg                              expected_buf : expected_tex;
38101e04c3fSmrg   unsigned num_expected = tgsi_tex_target == TGSI_TEXTURE_BUFFER ? 1 : 2;
38201e04c3fSmrg
38301e04c3fSmrg   if (tgsi_tex_target == TGSI_TEXTURE_BUFFER &&
38401e04c3fSmrg       !ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS)) {
38501e04c3fSmrg      util_report_result_helper(SKIP, "%s: %s", __func__,
38601e04c3fSmrg                                tgsi_texture_names[tgsi_tex_target]);
38701e04c3fSmrg      return;
38801e04c3fSmrg   }
38901e04c3fSmrg
39001e04c3fSmrg   cso = cso_create_context(ctx, 0);
39101e04c3fSmrg   cb = util_create_texture2d(ctx->screen, 256, 256,
39201e04c3fSmrg                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
39301e04c3fSmrg   util_set_common_states_and_clear(cso, ctx, cb);
39401e04c3fSmrg
3957ec681f3Smrg   ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0, 1, false, NULL);
39601e04c3fSmrg
39701e04c3fSmrg   /* Fragment shader. */
39801e04c3fSmrg   fs = util_make_fragment_tex_shader(ctx, tgsi_tex_target,
39901e04c3fSmrg                                      TGSI_INTERPOLATE_LINEAR,
40001e04c3fSmrg                                      TGSI_RETURN_TYPE_FLOAT,
40101e04c3fSmrg                                      TGSI_RETURN_TYPE_FLOAT, false, false);
40201e04c3fSmrg   cso_set_fragment_shader_handle(cso, fs);
40301e04c3fSmrg
40401e04c3fSmrg   /* Vertex shader. */
40501e04c3fSmrg   vs = util_set_passthrough_vertex_shader(cso, ctx, false);
40601e04c3fSmrg   util_draw_fullscreen_quad(cso);
40701e04c3fSmrg
40801e04c3fSmrg   /* Probe pixels. */
40901e04c3fSmrg   pass = pass && util_probe_rect_rgba_multi(ctx, cb, 0, 0,
41001e04c3fSmrg                                  cb->width0, cb->height0, expected,
41101e04c3fSmrg                                  num_expected);
41201e04c3fSmrg
41301e04c3fSmrg   /* Cleanup. */
41401e04c3fSmrg   cso_destroy_context(cso);
41501e04c3fSmrg   ctx->delete_vs_state(ctx, vs);
41601e04c3fSmrg   ctx->delete_fs_state(ctx, fs);
41701e04c3fSmrg   pipe_resource_reference(&cb, NULL);
41801e04c3fSmrg
41901e04c3fSmrg   util_report_result_helper(pass, "%s: %s", __func__,
42001e04c3fSmrg                             tgsi_texture_names[tgsi_tex_target]);
42101e04c3fSmrg}
42201e04c3fSmrg
42301e04c3fSmrgvoid
42401e04c3fSmrgutil_test_constant_buffer(struct pipe_context *ctx,
42501e04c3fSmrg                          struct pipe_resource *constbuf)
42601e04c3fSmrg{
42701e04c3fSmrg   struct cso_context *cso;
42801e04c3fSmrg   struct pipe_resource *cb;
42901e04c3fSmrg   void *fs, *vs;
43001e04c3fSmrg   bool pass = true;
43101e04c3fSmrg   static const float zero[] = {0, 0, 0, 0};
43201e04c3fSmrg
43301e04c3fSmrg   cso = cso_create_context(ctx, 0);
43401e04c3fSmrg   cb = util_create_texture2d(ctx->screen, 256, 256,
43501e04c3fSmrg                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
43601e04c3fSmrg   util_set_common_states_and_clear(cso, ctx, cb);
43701e04c3fSmrg
43801e04c3fSmrg   pipe_set_constant_buffer(ctx, PIPE_SHADER_FRAGMENT, 0, constbuf);
43901e04c3fSmrg
44001e04c3fSmrg   /* Fragment shader. */
44101e04c3fSmrg   {
44201e04c3fSmrg      static const char *text = /* I don't like ureg... */
44301e04c3fSmrg            "FRAG\n"
44401e04c3fSmrg            "DCL CONST[0][0]\n"
44501e04c3fSmrg            "DCL OUT[0], COLOR\n"
44601e04c3fSmrg
44701e04c3fSmrg            "MOV OUT[0], CONST[0][0]\n"
44801e04c3fSmrg            "END\n";
44901e04c3fSmrg      struct tgsi_token tokens[1000];
4507ec681f3Smrg      struct pipe_shader_state state = {0};
45101e04c3fSmrg
45201e04c3fSmrg      if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
45301e04c3fSmrg         puts("Can't compile a fragment shader.");
45401e04c3fSmrg         util_report_result(FAIL);
45501e04c3fSmrg         return;
45601e04c3fSmrg      }
45701e04c3fSmrg      pipe_shader_state_from_tgsi(&state, tokens);
45801e04c3fSmrg      fs = ctx->create_fs_state(ctx, &state);
45901e04c3fSmrg      cso_set_fragment_shader_handle(cso, fs);
46001e04c3fSmrg   }
46101e04c3fSmrg
46201e04c3fSmrg   /* Vertex shader. */
46301e04c3fSmrg   vs = util_set_passthrough_vertex_shader(cso, ctx, false);
46401e04c3fSmrg   util_draw_fullscreen_quad(cso);
46501e04c3fSmrg
46601e04c3fSmrg   /* Probe pixels. */
46701e04c3fSmrg   pass = pass && util_probe_rect_rgba(ctx, cb, 0, 0, cb->width0,
46801e04c3fSmrg                                       cb->height0, zero);
46901e04c3fSmrg
47001e04c3fSmrg   /* Cleanup. */
47101e04c3fSmrg   cso_destroy_context(cso);
47201e04c3fSmrg   ctx->delete_vs_state(ctx, vs);
47301e04c3fSmrg   ctx->delete_fs_state(ctx, fs);
47401e04c3fSmrg   pipe_resource_reference(&cb, NULL);
47501e04c3fSmrg
47601e04c3fSmrg   util_report_result(pass);
47701e04c3fSmrg}
47801e04c3fSmrg
47901e04c3fSmrgstatic void
4807ec681f3Smrgdisabled_fragment_shader(struct pipe_context *ctx)
48101e04c3fSmrg{
48201e04c3fSmrg   struct cso_context *cso;
48301e04c3fSmrg   struct pipe_resource *cb;
48401e04c3fSmrg   void *vs;
48501e04c3fSmrg   struct pipe_rasterizer_state rs = {0};
48601e04c3fSmrg   struct pipe_query *query;
48701e04c3fSmrg   union pipe_query_result qresult;
48801e04c3fSmrg
48901e04c3fSmrg   cso = cso_create_context(ctx, 0);
49001e04c3fSmrg   cb = util_create_texture2d(ctx->screen, 256, 256,
49101e04c3fSmrg                              PIPE_FORMAT_R8G8B8A8_UNORM, 0);
49201e04c3fSmrg   util_set_common_states_and_clear(cso, ctx, cb);
49301e04c3fSmrg
49401e04c3fSmrg   /* No rasterization. */
49501e04c3fSmrg   rs.rasterizer_discard = 1;
49601e04c3fSmrg   cso_set_rasterizer(cso, &rs);
49701e04c3fSmrg
49801e04c3fSmrg   vs = util_set_passthrough_vertex_shader(cso, ctx, false);
49901e04c3fSmrg
5007ec681f3Smrg   void *fs = util_make_empty_fragment_shader(ctx);
5017ec681f3Smrg   cso_set_fragment_shader_handle(cso, fs);
5027ec681f3Smrg
50301e04c3fSmrg   query = ctx->create_query(ctx, PIPE_QUERY_PRIMITIVES_GENERATED, 0);
50401e04c3fSmrg   ctx->begin_query(ctx, query);
50501e04c3fSmrg   util_draw_fullscreen_quad(cso);
50601e04c3fSmrg   ctx->end_query(ctx, query);
50701e04c3fSmrg   ctx->get_query_result(ctx, query, true, &qresult);
50801e04c3fSmrg
50901e04c3fSmrg   /* Cleanup. */
51001e04c3fSmrg   cso_destroy_context(cso);
51101e04c3fSmrg   ctx->delete_vs_state(ctx, vs);
5127ec681f3Smrg   ctx->delete_fs_state(ctx, fs);
51301e04c3fSmrg   ctx->destroy_query(ctx, query);
51401e04c3fSmrg   pipe_resource_reference(&cb, NULL);
51501e04c3fSmrg
51601e04c3fSmrg   /* Check PRIMITIVES_GENERATED. */
51701e04c3fSmrg   util_report_result(qresult.u64 == 2);
51801e04c3fSmrg}
51901e04c3fSmrg
52001e04c3fSmrg#if defined(PIPE_OS_LINUX) && defined(HAVE_LIBDRM)
52101e04c3fSmrg#include <libsync.h>
52201e04c3fSmrg#else
52301e04c3fSmrg#define sync_merge(str, fd1, fd2) (-1)
52401e04c3fSmrg#define sync_wait(fd, timeout) (-1)
52501e04c3fSmrg#endif
52601e04c3fSmrg
52701e04c3fSmrgstatic void
52801e04c3fSmrgtest_sync_file_fences(struct pipe_context *ctx)
52901e04c3fSmrg{
53001e04c3fSmrg   struct pipe_screen *screen = ctx->screen;
53101e04c3fSmrg   bool pass = true;
53201e04c3fSmrg   enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC;
53301e04c3fSmrg
53401e04c3fSmrg   if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD))
53501e04c3fSmrg      return;
53601e04c3fSmrg
53701e04c3fSmrg   struct cso_context *cso = cso_create_context(ctx, 0);
53801e04c3fSmrg   struct pipe_resource *buf =
53901e04c3fSmrg      pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024);
54001e04c3fSmrg   struct pipe_resource *tex =
54101e04c3fSmrg      util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0);
54201e04c3fSmrg   struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL;
54301e04c3fSmrg
54401e04c3fSmrg   /* Run 2 clears, get fencess. */
54501e04c3fSmrg   uint32_t value = 0;
54601e04c3fSmrg   ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
54701e04c3fSmrg   ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD);
54801e04c3fSmrg
54901e04c3fSmrg   struct pipe_box box;
55001e04c3fSmrg   u_box_2d(0, 0, tex->width0, tex->height0, &box);
55101e04c3fSmrg   ctx->clear_texture(ctx, tex, 0, &box, &value);
55201e04c3fSmrg   ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD);
55301e04c3fSmrg   pass = pass && buf_fence && tex_fence;
55401e04c3fSmrg
55501e04c3fSmrg   /* Export fences. */
55601e04c3fSmrg   int buf_fd = screen->fence_get_fd(screen, buf_fence);
55701e04c3fSmrg   int tex_fd = screen->fence_get_fd(screen, tex_fence);
55801e04c3fSmrg   pass = pass && buf_fd >= 0 && tex_fd >= 0;
55901e04c3fSmrg
56001e04c3fSmrg   /* Merge fences. */
56101e04c3fSmrg   int merged_fd = sync_merge("test", buf_fd, tex_fd);
56201e04c3fSmrg   pass = pass && merged_fd >= 0;
56301e04c3fSmrg
56401e04c3fSmrg   /* (Re)import all fences. */
56501e04c3fSmrg   struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL;
56601e04c3fSmrg   struct pipe_fence_handle *merged_fence = NULL;
56701e04c3fSmrg   ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type);
56801e04c3fSmrg   ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type);
56901e04c3fSmrg   ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type);
57001e04c3fSmrg   pass = pass && re_buf_fence && re_tex_fence && merged_fence;
57101e04c3fSmrg
57201e04c3fSmrg   /* Run another clear after waiting for everything. */
57301e04c3fSmrg   struct pipe_fence_handle *final_fence = NULL;
57401e04c3fSmrg   ctx->fence_server_sync(ctx, merged_fence);
57501e04c3fSmrg   value = 0xff;
57601e04c3fSmrg   ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value));
57701e04c3fSmrg   ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD);
57801e04c3fSmrg   pass = pass && final_fence;
57901e04c3fSmrg
58001e04c3fSmrg   /* Wait for the last fence. */
58101e04c3fSmrg   int final_fd = screen->fence_get_fd(screen, final_fence);
58201e04c3fSmrg   pass = pass && final_fd >= 0;
58301e04c3fSmrg   pass = pass && sync_wait(final_fd, -1) == 0;
58401e04c3fSmrg
58501e04c3fSmrg   /* Check that all fences are signalled. */
58601e04c3fSmrg   pass = pass && sync_wait(buf_fd, 0) == 0;
58701e04c3fSmrg   pass = pass && sync_wait(tex_fd, 0) == 0;
58801e04c3fSmrg   pass = pass && sync_wait(merged_fd, 0) == 0;
58901e04c3fSmrg
59001e04c3fSmrg   pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0);
59101e04c3fSmrg   pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0);
59201e04c3fSmrg   pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0);
59301e04c3fSmrg   pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0);
59401e04c3fSmrg   pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0);
59501e04c3fSmrg   pass = pass && screen->fence_finish(screen, NULL, final_fence, 0);
59601e04c3fSmrg
59701e04c3fSmrg   /* Cleanup. */
59801e04c3fSmrg#ifndef PIPE_OS_WINDOWS
59901e04c3fSmrg   if (buf_fd >= 0)
60001e04c3fSmrg      close(buf_fd);
60101e04c3fSmrg   if (tex_fd >= 0)
60201e04c3fSmrg      close(tex_fd);
60301e04c3fSmrg   if (merged_fd >= 0)
60401e04c3fSmrg      close(merged_fd);
60501e04c3fSmrg   if (final_fd >= 0)
60601e04c3fSmrg      close(final_fd);
60701e04c3fSmrg#endif
60801e04c3fSmrg
60901e04c3fSmrg   screen->fence_reference(screen, &buf_fence, NULL);
61001e04c3fSmrg   screen->fence_reference(screen, &tex_fence, NULL);
61101e04c3fSmrg   screen->fence_reference(screen, &re_buf_fence, NULL);
61201e04c3fSmrg   screen->fence_reference(screen, &re_tex_fence, NULL);
61301e04c3fSmrg   screen->fence_reference(screen, &merged_fence, NULL);
61401e04c3fSmrg   screen->fence_reference(screen, &final_fence, NULL);
61501e04c3fSmrg
61601e04c3fSmrg   cso_destroy_context(cso);
61701e04c3fSmrg   pipe_resource_reference(&buf, NULL);
61801e04c3fSmrg   pipe_resource_reference(&tex, NULL);
61901e04c3fSmrg
62001e04c3fSmrg   util_report_result(pass);
62101e04c3fSmrg}
62201e04c3fSmrg
62301e04c3fSmrgstatic void
62401e04c3fSmrgtest_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
62501e04c3fSmrg                     unsigned num_samples)
62601e04c3fSmrg{
62701e04c3fSmrg   struct cso_context *cso;
62801e04c3fSmrg   struct pipe_resource *cb;
62901e04c3fSmrg   struct pipe_sampler_view *view = NULL;
63001e04c3fSmrg   char name[256];
63101e04c3fSmrg   const char *text;
63201e04c3fSmrg
63301e04c3fSmrg   assert(num_samples >= 1 && num_samples <= 8);
63401e04c3fSmrg
6357ec681f3Smrg   snprintf(name, sizeof(name), "%s: %s, %u samples", __func__,
6367ec681f3Smrg            use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1));
63701e04c3fSmrg
63801e04c3fSmrg   if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) {
63901e04c3fSmrg      util_report_result_helper(SKIP, name);
64001e04c3fSmrg      return;
64101e04c3fSmrg   }
64201e04c3fSmrg   if (use_fbfetch &&
6437ec681f3Smrg       !ctx->screen->get_param(ctx->screen, PIPE_CAP_FBFETCH)) {
64401e04c3fSmrg      util_report_result_helper(SKIP, name);
64501e04c3fSmrg      return;
64601e04c3fSmrg   }
64701e04c3fSmrg
64801e04c3fSmrg   cso = cso_create_context(ctx, 0);
64901e04c3fSmrg   cb = util_create_texture2d(ctx->screen, 256, 256,
65001e04c3fSmrg                              PIPE_FORMAT_R8G8B8A8_UNORM, num_samples);
65101e04c3fSmrg   util_set_common_states_and_clear(cso, ctx, cb);
65201e04c3fSmrg
65301e04c3fSmrg   /* Clear each sample to a different value. */
65401e04c3fSmrg   if (num_samples > 1) {
65501e04c3fSmrg      void *fs =
65601e04c3fSmrg         util_make_fragment_passthrough_shader(ctx, TGSI_SEMANTIC_GENERIC,
65701e04c3fSmrg                                               TGSI_INTERPOLATE_LINEAR, TRUE);
65801e04c3fSmrg      cso_set_fragment_shader_handle(cso, fs);
65901e04c3fSmrg
66001e04c3fSmrg      /* Vertex shader. */
66101e04c3fSmrg      void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
66201e04c3fSmrg
66301e04c3fSmrg      for (unsigned i = 0; i < num_samples / 2; i++) {
66401e04c3fSmrg         float value;
66501e04c3fSmrg
66601e04c3fSmrg         /* 2 consecutive samples should have the same color to test MSAA
66701e04c3fSmrg          * compression properly.
66801e04c3fSmrg          */
66901e04c3fSmrg         if (num_samples == 2) {
67001e04c3fSmrg            value = 0.1;
67101e04c3fSmrg         } else {
67201e04c3fSmrg            /* The average value must be 0.1 */
67301e04c3fSmrg            static const float values[] = {
67401e04c3fSmrg               0.0, 0.2, 0.05, 0.15
67501e04c3fSmrg            };
67601e04c3fSmrg            value = values[i];
67701e04c3fSmrg         }
67801e04c3fSmrg
67901e04c3fSmrg         ctx->set_sample_mask(ctx, 0x3 << (i * 2));
68001e04c3fSmrg         util_draw_fullscreen_quad_fill(cso, value, value, value, value);
68101e04c3fSmrg      }
68201e04c3fSmrg      ctx->set_sample_mask(ctx, ~0);
68301e04c3fSmrg
68401e04c3fSmrg      cso_set_vertex_shader_handle(cso, NULL);
68501e04c3fSmrg      cso_set_fragment_shader_handle(cso, NULL);
68601e04c3fSmrg      ctx->delete_vs_state(ctx, vs);
68701e04c3fSmrg      ctx->delete_fs_state(ctx, fs);
68801e04c3fSmrg   }
68901e04c3fSmrg
69001e04c3fSmrg   if (use_fbfetch) {
69101e04c3fSmrg      /* Fragment shader. */
69201e04c3fSmrg      text = "FRAG\n"
69301e04c3fSmrg             "DCL OUT[0], COLOR[0]\n"
69401e04c3fSmrg             "DCL TEMP[0]\n"
69501e04c3fSmrg             "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
69601e04c3fSmrg
69701e04c3fSmrg             "FBFETCH TEMP[0], OUT[0]\n"
69801e04c3fSmrg             "ADD OUT[0], TEMP[0], IMM[0]\n"
69901e04c3fSmrg             "END\n";
70001e04c3fSmrg   } else {
7017ec681f3Smrg      struct pipe_sampler_view templ = {0};
70201e04c3fSmrg      templ.format = cb->format;
70301e04c3fSmrg      templ.target = cb->target;
70401e04c3fSmrg      templ.swizzle_r = PIPE_SWIZZLE_X;
70501e04c3fSmrg      templ.swizzle_g = PIPE_SWIZZLE_Y;
70601e04c3fSmrg      templ.swizzle_b = PIPE_SWIZZLE_Z;
70701e04c3fSmrg      templ.swizzle_a = PIPE_SWIZZLE_W;
70801e04c3fSmrg      view = ctx->create_sampler_view(ctx, cb, &templ);
7097ec681f3Smrg      ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 1, 0, false, &view);
71001e04c3fSmrg
71101e04c3fSmrg      /* Fragment shader. */
71201e04c3fSmrg      if (num_samples > 1) {
71301e04c3fSmrg         text = "FRAG\n"
71401e04c3fSmrg                "DCL SV[0], POSITION\n"
71501e04c3fSmrg                "DCL SV[1], SAMPLEID\n"
71601e04c3fSmrg                "DCL SAMP[0]\n"
71701e04c3fSmrg                "DCL SVIEW[0], 2D_MSAA, FLOAT\n"
71801e04c3fSmrg                "DCL OUT[0], COLOR[0]\n"
71901e04c3fSmrg                "DCL TEMP[0]\n"
72001e04c3fSmrg                "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
72101e04c3fSmrg
72201e04c3fSmrg                "F2I TEMP[0].xy, SV[0].xyyy\n"
72301e04c3fSmrg                "MOV TEMP[0].w, SV[1].xxxx\n"
72401e04c3fSmrg                "TXF TEMP[0], TEMP[0], SAMP[0], 2D_MSAA\n"
72501e04c3fSmrg                "ADD OUT[0], TEMP[0], IMM[0]\n"
72601e04c3fSmrg                "END\n";
72701e04c3fSmrg      } else {
72801e04c3fSmrg         text = "FRAG\n"
72901e04c3fSmrg                "DCL SV[0], POSITION\n"
73001e04c3fSmrg                "DCL SAMP[0]\n"
73101e04c3fSmrg                "DCL SVIEW[0], 2D, FLOAT\n"
73201e04c3fSmrg                "DCL OUT[0], COLOR[0]\n"
73301e04c3fSmrg                "DCL TEMP[0]\n"
73401e04c3fSmrg                "IMM[0] FLT32 { 0.1, 0.2, 0.3, 0.4}\n"
73501e04c3fSmrg                "IMM[1] INT32 { 0, 0, 0, 0}\n"
73601e04c3fSmrg
73701e04c3fSmrg                "F2I TEMP[0].xy, SV[0].xyyy\n"
73801e04c3fSmrg                "MOV TEMP[0].zw, IMM[1]\n"
73901e04c3fSmrg                "TXF TEMP[0], TEMP[0], SAMP[0], 2D\n"
74001e04c3fSmrg                "ADD OUT[0], TEMP[0], IMM[0]\n"
74101e04c3fSmrg                "END\n";
74201e04c3fSmrg      }
74301e04c3fSmrg   }
74401e04c3fSmrg
74501e04c3fSmrg   struct tgsi_token tokens[1000];
7467ec681f3Smrg   struct pipe_shader_state state = {0};
74701e04c3fSmrg
74801e04c3fSmrg   if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
74901e04c3fSmrg      assert(0);
75001e04c3fSmrg      util_report_result_helper(FAIL, name);
75101e04c3fSmrg      return;
75201e04c3fSmrg   }
75301e04c3fSmrg   pipe_shader_state_from_tgsi(&state, tokens);
75401e04c3fSmrg
75501e04c3fSmrg   void *fs = ctx->create_fs_state(ctx, &state);
75601e04c3fSmrg   cso_set_fragment_shader_handle(cso, fs);
75701e04c3fSmrg
75801e04c3fSmrg   /* Vertex shader. */
75901e04c3fSmrg   void *vs = util_set_passthrough_vertex_shader(cso, ctx, false);
76001e04c3fSmrg
76101e04c3fSmrg   if (num_samples > 1 && !use_fbfetch)
76201e04c3fSmrg      ctx->set_min_samples(ctx, num_samples);
76301e04c3fSmrg
76401e04c3fSmrg   for (int i = 0; i < 2; i++) {
76501e04c3fSmrg      ctx->texture_barrier(ctx,
76601e04c3fSmrg                           use_fbfetch ? PIPE_TEXTURE_BARRIER_FRAMEBUFFER :
76701e04c3fSmrg                                         PIPE_TEXTURE_BARRIER_SAMPLER);
76801e04c3fSmrg      util_draw_fullscreen_quad(cso);
76901e04c3fSmrg   }
77001e04c3fSmrg   if (num_samples > 1 && !use_fbfetch)
77101e04c3fSmrg      ctx->set_min_samples(ctx, 1);
77201e04c3fSmrg
77301e04c3fSmrg   /* Probe pixels.
77401e04c3fSmrg    *
77501e04c3fSmrg    * For single sample:
77601e04c3fSmrg    *   result = 0.1 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.3, 0.5, 0.7, 0.9)
77701e04c3fSmrg    *
77801e04c3fSmrg    * For MSAA 4x:
77901e04c3fSmrg    *   sample0 = 0.0 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.2, 0.4, 0.6, 0.8)
78001e04c3fSmrg    *   sample1 = sample0
78101e04c3fSmrg    *   sample2 = 0.2 (clear) + (0.1, 0.2, 0.3, 0.4) * 2 = (0.4, 0.6, 0.8, 1.0)
78201e04c3fSmrg    *   sample3 = sample2
78301e04c3fSmrg    *   resolved = sum(sample[0:3]) / 4 = (0.3, 0.5, 0.7, 0.9)
78401e04c3fSmrg    */
78501e04c3fSmrg   static const float expected[] = {0.3, 0.5, 0.7, 0.9};
78601e04c3fSmrg   bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
78701e04c3fSmrg                                    cb->width0, cb->height0, expected);
78801e04c3fSmrg
78901e04c3fSmrg   /* Cleanup. */
79001e04c3fSmrg   cso_destroy_context(cso);
79101e04c3fSmrg   ctx->delete_vs_state(ctx, vs);
79201e04c3fSmrg   ctx->delete_fs_state(ctx, fs);
79301e04c3fSmrg   pipe_sampler_view_reference(&view, NULL);
79401e04c3fSmrg   pipe_resource_reference(&cb, NULL);
79501e04c3fSmrg
79601e04c3fSmrg   util_report_result_helper(pass, name);
79701e04c3fSmrg}
79801e04c3fSmrg
799361fc4cbSmayastatic void
800361fc4cbSmayatest_compute_clear_image(struct pipe_context *ctx)
801361fc4cbSmaya{
802361fc4cbSmaya   struct pipe_resource *cb;
803361fc4cbSmaya   const char *text;
804361fc4cbSmaya
805361fc4cbSmaya   cb = util_create_texture2d(ctx->screen, 256, 256,
806361fc4cbSmaya                              PIPE_FORMAT_R8G8B8A8_UNORM, 1);
807361fc4cbSmaya
808361fc4cbSmaya   /* Compute shader. */
809361fc4cbSmaya   text = "COMP\n"
810361fc4cbSmaya          "PROPERTY CS_FIXED_BLOCK_WIDTH 8\n"
811361fc4cbSmaya          "PROPERTY CS_FIXED_BLOCK_HEIGHT 8\n"
812361fc4cbSmaya          "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
813361fc4cbSmaya          "DCL SV[0], THREAD_ID\n"
814361fc4cbSmaya          "DCL SV[1], BLOCK_ID\n"
815361fc4cbSmaya          "DCL IMAGE[0], 2D, PIPE_FORMAT_R8G8B8A8_UNORM, WR\n"
816361fc4cbSmaya          "DCL TEMP[0]\n"
817361fc4cbSmaya          "IMM[0] UINT32 { 8, 8, 0, 0}\n"
818361fc4cbSmaya          "IMM[1] FLT32 { 1, 0, 0, 0}\n"
819361fc4cbSmaya
820361fc4cbSmaya          /* TEMP[0].xy = SV[1] * IMM[0] + SV[0]; */
821361fc4cbSmaya          "UMAD TEMP[0].xy, SV[1], IMM[0], SV[0]\n"
822361fc4cbSmaya          "STORE IMAGE[0], TEMP[0], IMM[1], 2D, PIPE_FORMAT_R8G8B8A8_UNORM\n"
823361fc4cbSmaya          "END\n";
824361fc4cbSmaya
825361fc4cbSmaya   struct tgsi_token tokens[1000];
826361fc4cbSmaya   if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
827361fc4cbSmaya      assert(0);
828361fc4cbSmaya      util_report_result(FAIL);
829361fc4cbSmaya      return;
830361fc4cbSmaya   }
831361fc4cbSmaya
832361fc4cbSmaya   struct pipe_compute_state state = {0};
833361fc4cbSmaya   state.ir_type = PIPE_SHADER_IR_TGSI;
834361fc4cbSmaya   state.prog = tokens;
835361fc4cbSmaya
836361fc4cbSmaya   void *compute_shader = ctx->create_compute_state(ctx, &state);
837361fc4cbSmaya   ctx->bind_compute_state(ctx, compute_shader);
838361fc4cbSmaya
839361fc4cbSmaya   /* Bind the image. */
840361fc4cbSmaya   struct pipe_image_view image = {0};
841361fc4cbSmaya   image.resource = cb;
842361fc4cbSmaya   image.shader_access = image.access = PIPE_IMAGE_ACCESS_READ_WRITE;
843361fc4cbSmaya   image.format = cb->format;
844361fc4cbSmaya
8457ec681f3Smrg   ctx->set_shader_images(ctx, PIPE_SHADER_COMPUTE, 0, 1, 0, &image);
846361fc4cbSmaya
847361fc4cbSmaya   /* Dispatch compute. */
848361fc4cbSmaya   struct pipe_grid_info info = {0};
849361fc4cbSmaya   info.block[0] = 8;
850361fc4cbSmaya   info.block[1] = 8;
851361fc4cbSmaya   info.block[2] = 1;
852361fc4cbSmaya   info.grid[0] = cb->width0 / 8;
853361fc4cbSmaya   info.grid[1] = cb->height0 / 8;
854361fc4cbSmaya   info.grid[2] = 1;
855361fc4cbSmaya
856361fc4cbSmaya   ctx->launch_grid(ctx, &info);
857361fc4cbSmaya
858361fc4cbSmaya   /* Check pixels. */
859361fc4cbSmaya   static const float expected[] = {1.0, 0.0, 0.0, 0.0};
860361fc4cbSmaya   bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
861361fc4cbSmaya                                    cb->width0, cb->height0, expected);
862361fc4cbSmaya
863361fc4cbSmaya   /* Cleanup. */
864361fc4cbSmaya   ctx->delete_compute_state(ctx, compute_shader);
865361fc4cbSmaya   pipe_resource_reference(&cb, NULL);
866361fc4cbSmaya
867361fc4cbSmaya   util_report_result(pass);
868361fc4cbSmaya}
869361fc4cbSmaya
8707ec681f3Smrg#define NV12_WIDTH   2560
8717ec681f3Smrg#define NV12_HEIGHT  1440
8727ec681f3Smrg
8737ec681f3Smrgstatic bool
8747ec681f3Smrgnv12_validate_resource_fields(struct pipe_resource *tex)
8757ec681f3Smrg{
8767ec681f3Smrg   return tex->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 0) &&
8777ec681f3Smrg         tex->width0 == NV12_WIDTH &&
8787ec681f3Smrg         tex->height0 == NV12_HEIGHT &&
8797ec681f3Smrg         tex->last_level == 0 &&
8807ec681f3Smrg         tex->usage == PIPE_USAGE_DEFAULT &&
8817ec681f3Smrg         tex->next &&
8827ec681f3Smrg         tex->next->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 1) &&
8837ec681f3Smrg         tex->next->width0 == tex->width0 / 2 &&
8847ec681f3Smrg         tex->next->height0 == tex->height0 / 2 &&
8857ec681f3Smrg         tex->next->usage == tex->usage;
8867ec681f3Smrg}
8877ec681f3Smrg
8887ec681f3Smrg/* This test enforces the behavior of NV12 allocation and exports. */
8897ec681f3Smrgstatic void
8907ec681f3Smrgtest_nv12(struct pipe_screen *screen)
8917ec681f3Smrg{
8927ec681f3Smrg   struct pipe_resource *tex = util_create_texture2d(screen, NV12_WIDTH, NV12_HEIGHT,
8937ec681f3Smrg                                                     PIPE_FORMAT_NV12, 1);
8947ec681f3Smrg
8957ec681f3Smrg   if (!tex) {
8967ec681f3Smrg      printf("resource_create failed\n");
8977ec681f3Smrg      util_report_result(false);
8987ec681f3Smrg      return;
8997ec681f3Smrg   }
9007ec681f3Smrg
9017ec681f3Smrg   if (!nv12_validate_resource_fields(tex)) {
9027ec681f3Smrg      printf("incorrect pipe_resource fields\n");
9037ec681f3Smrg      util_report_result(false);
9047ec681f3Smrg      return;
9057ec681f3Smrg   }
9067ec681f3Smrg
9077ec681f3Smrg   /* resource_get_param */
9087ec681f3Smrg   if (screen->resource_get_param) {
9097ec681f3Smrg      struct {
9107ec681f3Smrg         uint64_t handle, dmabuf, offset, stride, planes;
9117ec681f3Smrg      } handle[3];
9127ec681f3Smrg
9137ec681f3Smrg      /* Export */
9147ec681f3Smrg      for (unsigned i = 0; i < 3; i++) {
9157ec681f3Smrg         struct pipe_resource *res = i == 2 ? tex->next : tex;
9167ec681f3Smrg         unsigned plane = i == 2 ? 0 : i;
9177ec681f3Smrg
9187ec681f3Smrg         if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
9197ec681f3Smrg                                         PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS,
9207ec681f3Smrg                                         0, &handle[i].handle)) {
9217ec681f3Smrg            printf("resource_get_param failed\n");
9227ec681f3Smrg            util_report_result(false);
9237ec681f3Smrg            goto cleanup;
9247ec681f3Smrg         }
9257ec681f3Smrg
9267ec681f3Smrg         if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
9277ec681f3Smrg                                         PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD,
9287ec681f3Smrg                                         0, &handle[i].dmabuf)) {
9297ec681f3Smrg            printf("resource_get_param failed\n");
9307ec681f3Smrg            util_report_result(false);
9317ec681f3Smrg            goto cleanup;
9327ec681f3Smrg         }
9337ec681f3Smrg
9347ec681f3Smrg         if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
9357ec681f3Smrg                                         PIPE_RESOURCE_PARAM_OFFSET,
9367ec681f3Smrg                                         0, &handle[i].offset)) {
9377ec681f3Smrg            printf("resource_get_param failed\n");
9387ec681f3Smrg            util_report_result(false);
9397ec681f3Smrg            goto cleanup;
9407ec681f3Smrg         }
9417ec681f3Smrg
9427ec681f3Smrg         if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
9437ec681f3Smrg                                         PIPE_RESOURCE_PARAM_STRIDE,
9447ec681f3Smrg                                         0, &handle[i].stride)) {
9457ec681f3Smrg            printf("resource_get_param failed\n");
9467ec681f3Smrg            util_report_result(false);
9477ec681f3Smrg            goto cleanup;
9487ec681f3Smrg         }
9497ec681f3Smrg
9507ec681f3Smrg         if (!screen->resource_get_param(screen, NULL, res, plane, 0, 0,
9517ec681f3Smrg                                         PIPE_RESOURCE_PARAM_NPLANES,
9527ec681f3Smrg                                         0, &handle[i].planes)) {
9537ec681f3Smrg            printf("resource_get_param failed\n");
9547ec681f3Smrg            util_report_result(false);
9557ec681f3Smrg            goto cleanup;
9567ec681f3Smrg         }
9577ec681f3Smrg      }
9587ec681f3Smrg
9597ec681f3Smrg      /* Validate export.  */
9607ec681f3Smrg      bool get_param_pass = /* Sanity checking */
9617ec681f3Smrg                            handle[0].handle && handle[1].handle && handle[2].handle &&
9627ec681f3Smrg                            handle[0].dmabuf && handle[1].dmabuf && handle[2].dmabuf &&
9637ec681f3Smrg                            handle[0].stride && handle[1].stride && handle[2].stride &&
9647ec681f3Smrg                            handle[0].planes == 2 &&
9657ec681f3Smrg                            handle[1].planes == 2 &&
9667ec681f3Smrg                            handle[2].planes == 2 &&
9677ec681f3Smrg                            /* Different planes */
9687ec681f3Smrg                            handle[0].handle == handle[1].handle &&
9697ec681f3Smrg                            handle[0].offset != handle[1].offset &&
9707ec681f3Smrg                            /* Same planes. */
9717ec681f3Smrg                            handle[1].handle == handle[2].handle &&
9727ec681f3Smrg                            handle[1].stride == handle[2].stride &&
9737ec681f3Smrg                            handle[1].offset == handle[2].offset;
9747ec681f3Smrg
9757ec681f3Smrg      if (!get_param_pass) {
9767ec681f3Smrg         printf("resource_get_param returned incorrect values\n");
9777ec681f3Smrg         util_report_result(false);
9787ec681f3Smrg         goto cleanup;
9797ec681f3Smrg      }
9807ec681f3Smrg   }
9817ec681f3Smrg
9827ec681f3Smrg   /* resource_get_handle */
9837ec681f3Smrg   struct winsys_handle handle[4] = {{0}};
9847ec681f3Smrg
9857ec681f3Smrg   /* Export */
9867ec681f3Smrg   for (unsigned i = 0; i < 4; i++) {
9877ec681f3Smrg      handle[i].type = i < 2 ? WINSYS_HANDLE_TYPE_KMS : WINSYS_HANDLE_TYPE_FD;
9887ec681f3Smrg      handle[i].plane = i % 2;
9897ec681f3Smrg
9907ec681f3Smrg      if (!screen->resource_get_handle(screen, NULL, tex, &handle[i], 0)) {
9917ec681f3Smrg         printf("resource_get_handle failed\n");
9927ec681f3Smrg         util_report_result(false);
9937ec681f3Smrg         goto cleanup;
9947ec681f3Smrg      }
9957ec681f3Smrg   }
9967ec681f3Smrg
9977ec681f3Smrg   /* Validate export. */
9987ec681f3Smrg   bool get_handle_pass = /* Sanity checking */
9997ec681f3Smrg                          handle[0].handle && handle[1].handle &&
10007ec681f3Smrg                          handle[0].stride && handle[1].stride &&
10017ec681f3Smrg                          handle[2].handle && handle[3].handle &&
10027ec681f3Smrg                          handle[2].stride && handle[3].stride &&
10037ec681f3Smrg                          /* KMS - different planes */
10047ec681f3Smrg                          handle[0].handle == handle[1].handle &&
10057ec681f3Smrg                          handle[0].offset != handle[1].offset &&
10067ec681f3Smrg                          /* DMABUF - different planes */
10077ec681f3Smrg                          handle[2].offset != handle[3].offset &&
10087ec681f3Smrg                          /* KMS and DMABUF equivalence */
10097ec681f3Smrg                          handle[0].offset == handle[2].offset &&
10107ec681f3Smrg                          handle[1].offset == handle[3].offset &&
10117ec681f3Smrg                          handle[0].stride == handle[2].stride &&
10127ec681f3Smrg                          handle[1].stride == handle[3].stride;
10137ec681f3Smrg
10147ec681f3Smrg   if (!get_handle_pass) {
10157ec681f3Smrg      printf("resource_get_handle returned incorrect values\n");
10167ec681f3Smrg      util_report_result(false);
10177ec681f3Smrg      goto cleanup;
10187ec681f3Smrg   }
10197ec681f3Smrg
10207ec681f3Smrg   util_report_result(true);
10217ec681f3Smrg
10227ec681f3Smrgcleanup:
10237ec681f3Smrg   pipe_resource_reference(&tex, NULL);
10247ec681f3Smrg}
10257ec681f3Smrg
102601e04c3fSmrg/**
102701e04c3fSmrg * Run all tests. This should be run with a clean context after
102801e04c3fSmrg * context_create.
102901e04c3fSmrg */
103001e04c3fSmrgvoid
103101e04c3fSmrgutil_run_tests(struct pipe_screen *screen)
103201e04c3fSmrg{
103301e04c3fSmrg   struct pipe_context *ctx = screen->context_create(screen, NULL, 0);
103401e04c3fSmrg
10357ec681f3Smrg   disabled_fragment_shader(ctx);
103601e04c3fSmrg   tgsi_vs_window_space_position(ctx);
103701e04c3fSmrg   null_sampler_view(ctx, TGSI_TEXTURE_2D);
103801e04c3fSmrg   null_sampler_view(ctx, TGSI_TEXTURE_BUFFER);
103901e04c3fSmrg   util_test_constant_buffer(ctx, NULL);
104001e04c3fSmrg   test_sync_file_fences(ctx);
104101e04c3fSmrg
104201e04c3fSmrg   for (int i = 1; i <= 8; i = i * 2)
104301e04c3fSmrg      test_texture_barrier(ctx, false, i);
104401e04c3fSmrg   for (int i = 1; i <= 8; i = i * 2)
104501e04c3fSmrg      test_texture_barrier(ctx, true, i);
1046361fc4cbSmaya   ctx->destroy(ctx);
104701e04c3fSmrg
1048361fc4cbSmaya   ctx = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY);
1049361fc4cbSmaya   test_compute_clear_image(ctx);
105001e04c3fSmrg   ctx->destroy(ctx);
105101e04c3fSmrg
10527ec681f3Smrg   test_nv12(screen);
10537ec681f3Smrg
105401e04c3fSmrg   puts("Done. Exiting..");
105501e04c3fSmrg   exit(0);
105601e04c3fSmrg}
1057