gallium: add pipe cap for scissored clears and pass scissor state to clear() hook
[mesa.git] / src / gallium / auxiliary / util / u_tests.c
index 7360eb976394d9fefa3fd1d3048fb44ea9b2a201..00f75906173154fa0a1a3ff5f30fa73536b76de9 100644 (file)
@@ -28,7 +28,7 @@
 #include "util/u_tests.h"
 
 #include "util/u_draw_quad.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 #include "util/u_simple_shaders.h"
@@ -38,6 +38,7 @@
 #include "tgsi/tgsi_strings.h"
 #include "tgsi/tgsi_text.h"
 #include "cso_cache/cso_context.h"
+#include "state_tracker/winsys_handle.h"
 #include <stdio.h>
 
 #define TOLERANCE 0.01
@@ -108,7 +109,8 @@ util_set_rasterizer_normal(struct cso_context *cso)
 
    rs.half_pixel_center = 1;
    rs.bottom_edge_rule = 1;
-   rs.depth_clip = 1;
+   rs.depth_clip_near = 1;
+   rs.depth_clip_far = 1;
 
    cso_set_rasterizer(cso, &rs);
 }
@@ -132,17 +134,17 @@ static void
 util_set_interleaved_vertex_elements(struct cso_context *cso,
                                      unsigned num_elements)
 {
+   struct cso_velems_state velem;
    unsigned i;
-   struct pipe_vertex_element *velem =
-      calloc(1, num_elements * sizeof(struct pipe_vertex_element));
 
+   memset(&velem, 0, sizeof(velem));
+   velem.count = num_elements;
    for (i = 0; i < num_elements; i++) {
-      velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
-      velem[i].src_offset = i * 16;
+      velem.velems[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+      velem.velems[i].src_offset = i * 16;
    }
 
-   cso_set_vertex_elements(cso, num_elements, velem);
-   free(velem);
+   cso_set_vertex_elements(cso, &velem);
 }
 
 static void *
@@ -175,7 +177,7 @@ util_set_common_states_and_clear(struct cso_context *cso, struct pipe_context *c
    util_set_rasterizer_normal(cso);
    util_set_max_viewport(cso, cb);
 
-   ctx->clear(ctx, PIPE_CLEAR_COLOR0, (void*)clear_color, 0, 0);
+   ctx->clear(ctx, PIPE_CLEAR_COLOR0, NULL, (void*)clear_color, 0, 0);
 }
 
 static void
@@ -227,7 +229,7 @@ util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex,
 
    map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ,
                            offx, offy, w, h, &transfer);
-   pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels);
+   pipe_get_tile_rgba(transfer, map, 0, 0, w, h, tex->format, pixels);
    pipe_transfer_unmap(ctx, transfer);
 
    for (e = 0; e < num_expected_colors; e++) {
@@ -283,7 +285,7 @@ util_report_result_helper(int status, const char *name, ...)
    va_list ap;
 
    va_start(ap, name);
-   util_vsnprintf(buf, sizeof(buf), name, ap);
+   vsnprintf(buf, sizeof(buf), name, ap);
    va_end(ap);
 
    printf("Test(%s) = %s\n", buf,
@@ -622,15 +624,15 @@ test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
 
    assert(num_samples >= 1 && num_samples <= 8);
 
-   util_snprintf(name, sizeof(name), "%s: %s, %u samples", __func__,
-                 use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1));
+   snprintf(name, sizeof(name), "%s: %s, %u samples", __func__,
+            use_fbfetch ? "FBFETCH" : "sampler", MAX2(num_samples, 1));
 
    if (!ctx->screen->get_param(ctx->screen, PIPE_CAP_TEXTURE_BARRIER)) {
       util_report_result_helper(SKIP, name);
       return;
    }
    if (use_fbfetch &&
-       !ctx->screen->get_param(ctx->screen, PIPE_CAP_TGSI_FS_FBFETCH)) {
+       !ctx->screen->get_param(ctx->screen, PIPE_CAP_FBFETCH)) {
       util_report_result_helper(SKIP, name);
       return;
    }
@@ -786,6 +788,233 @@ test_texture_barrier(struct pipe_context *ctx, bool use_fbfetch,
    util_report_result_helper(pass, name);
 }
 
+static void
+test_compute_clear_image(struct pipe_context *ctx)
+{
+   struct pipe_resource *cb;
+   const char *text;
+
+   cb = util_create_texture2d(ctx->screen, 256, 256,
+                              PIPE_FORMAT_R8G8B8A8_UNORM, 1);
+
+   /* Compute shader. */
+   text = "COMP\n"
+          "PROPERTY CS_FIXED_BLOCK_WIDTH 8\n"
+          "PROPERTY CS_FIXED_BLOCK_HEIGHT 8\n"
+          "PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"
+          "DCL SV[0], THREAD_ID\n"
+          "DCL SV[1], BLOCK_ID\n"
+          "DCL IMAGE[0], 2D, PIPE_FORMAT_R8G8B8A8_UNORM, WR\n"
+          "DCL TEMP[0]\n"
+          "IMM[0] UINT32 { 8, 8, 0, 0}\n"
+          "IMM[1] FLT32 { 1, 0, 0, 0}\n"
+
+          /* TEMP[0].xy = SV[1] * IMM[0] + SV[0]; */
+          "UMAD TEMP[0].xy, SV[1], IMM[0], SV[0]\n"
+          "STORE IMAGE[0], TEMP[0], IMM[1], 2D, PIPE_FORMAT_R8G8B8A8_UNORM\n"
+          "END\n";
+
+   struct tgsi_token tokens[1000];
+   if (!tgsi_text_translate(text, tokens, ARRAY_SIZE(tokens))) {
+      assert(0);
+      util_report_result(FAIL);
+      return;
+   }
+
+   struct pipe_compute_state state = {0};
+   state.ir_type = PIPE_SHADER_IR_TGSI;
+   state.prog = tokens;
+
+   void *compute_shader = ctx->create_compute_state(ctx, &state);
+   ctx->bind_compute_state(ctx, compute_shader);
+
+   /* Bind the image. */
+   struct pipe_image_view image = {0};
+   image.resource = cb;
+   image.shader_access = image.access = PIPE_IMAGE_ACCESS_READ_WRITE;
+   image.format = cb->format;
+
+   ctx->set_shader_images(ctx, PIPE_SHADER_COMPUTE, 0, 1, &image);
+
+   /* Dispatch compute. */
+   struct pipe_grid_info info = {0};
+   info.block[0] = 8;
+   info.block[1] = 8;
+   info.block[2] = 1;
+   info.grid[0] = cb->width0 / 8;
+   info.grid[1] = cb->height0 / 8;
+   info.grid[2] = 1;
+
+   ctx->launch_grid(ctx, &info);
+
+   /* Check pixels. */
+   static const float expected[] = {1.0, 0.0, 0.0, 0.0};
+   bool pass = util_probe_rect_rgba(ctx, cb, 0, 0,
+                                    cb->width0, cb->height0, expected);
+
+   /* Cleanup. */
+   ctx->delete_compute_state(ctx, compute_shader);
+   pipe_resource_reference(&cb, NULL);
+
+   util_report_result(pass);
+}
+
+#define NV12_WIDTH   2560
+#define NV12_HEIGHT  1440
+
+static bool
+nv12_validate_resource_fields(struct pipe_resource *tex)
+{
+   return tex->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 0) &&
+         tex->width0 == NV12_WIDTH &&
+         tex->height0 == NV12_HEIGHT &&
+         tex->last_level == 0 &&
+         tex->usage == PIPE_USAGE_DEFAULT &&
+         tex->next &&
+         tex->next->format == util_format_get_plane_format(PIPE_FORMAT_NV12, 1) &&
+         tex->next->width0 == tex->width0 / 2 &&
+         tex->next->height0 == tex->height0 / 2 &&
+         tex->next->usage == tex->usage;
+}
+
+/* This test enforces the behavior of NV12 allocation and exports. */
+static void
+test_nv12(struct pipe_screen *screen)
+{
+   struct pipe_resource *tex = util_create_texture2d(screen, NV12_WIDTH, NV12_HEIGHT,
+                                                     PIPE_FORMAT_NV12, 1);
+
+   if (!tex) {
+      printf("resource_create failed\n");
+      util_report_result(false);
+      return;
+   }
+
+   if (!nv12_validate_resource_fields(tex)) {
+      printf("incorrect pipe_resource fields\n");
+      util_report_result(false);
+      return;
+   }
+
+   /* resource_get_param */
+   if (screen->resource_get_param) {
+      struct {
+         uint64_t handle, dmabuf, offset, stride, planes;
+      } handle[3];
+
+      /* Export */
+      for (unsigned i = 0; i < 3; i++) {
+         struct pipe_resource *res = i == 2 ? tex->next : tex;
+         unsigned plane = i == 2 ? 0 : i;
+
+         if (!screen->resource_get_param(screen, NULL, res, plane, 0,
+                                         PIPE_RESOURCE_PARAM_HANDLE_TYPE_KMS,
+                                         0, &handle[i].handle)) {
+            printf("resource_get_param failed\n");
+            util_report_result(false);
+            goto cleanup;
+         }
+
+         if (!screen->resource_get_param(screen, NULL, res, plane, 0,
+                                         PIPE_RESOURCE_PARAM_HANDLE_TYPE_FD,
+                                         0, &handle[i].dmabuf)) {
+            printf("resource_get_param failed\n");
+            util_report_result(false);
+            goto cleanup;
+         }
+
+         if (!screen->resource_get_param(screen, NULL, res, plane, 0,
+                                         PIPE_RESOURCE_PARAM_OFFSET,
+                                         0, &handle[i].offset)) {
+            printf("resource_get_param failed\n");
+            util_report_result(false);
+            goto cleanup;
+         }
+
+         if (!screen->resource_get_param(screen, NULL, res, plane, 0,
+                                         PIPE_RESOURCE_PARAM_STRIDE,
+                                         0, &handle[i].stride)) {
+            printf("resource_get_param failed\n");
+            util_report_result(false);
+            goto cleanup;
+         }
+
+         if (!screen->resource_get_param(screen, NULL, res, plane, 0,
+                                         PIPE_RESOURCE_PARAM_NPLANES,
+                                         0, &handle[i].planes)) {
+            printf("resource_get_param failed\n");
+            util_report_result(false);
+            goto cleanup;
+         }
+      }
+
+      /* Validate export.  */
+      bool get_param_pass = /* Sanity checking */
+                            handle[0].handle && handle[1].handle && handle[2].handle &&
+                            handle[0].dmabuf && handle[1].dmabuf && handle[2].dmabuf &&
+                            handle[0].stride && handle[1].stride && handle[2].stride &&
+                            handle[0].planes == 2 &&
+                            handle[1].planes == 2 &&
+                            handle[2].planes == 2 &&
+                            /* Different planes */
+                            handle[0].handle == handle[1].handle &&
+                            handle[0].offset != handle[1].offset &&
+                            /* Same planes. */
+                            handle[1].handle == handle[2].handle &&
+                            handle[1].stride == handle[2].stride &&
+                            handle[1].offset == handle[2].offset;
+
+      if (!get_param_pass) {
+         printf("resource_get_param returned incorrect values\n");
+         util_report_result(false);
+         goto cleanup;
+      }
+   }
+
+   /* resource_get_handle */
+   struct winsys_handle handle[4] = {{0}};
+
+   /* Export */
+   for (unsigned i = 0; i < 4; i++) {
+      handle[i].type = i < 2 ? WINSYS_HANDLE_TYPE_KMS : WINSYS_HANDLE_TYPE_FD;
+      handle[i].plane = i % 2;
+
+      if (!screen->resource_get_handle(screen, NULL, tex, &handle[i], 0)) {
+         printf("resource_get_handle failed\n");
+         util_report_result(false);
+         goto cleanup;
+      }
+   }
+
+   /* Validate export. */
+   bool get_handle_pass = /* Sanity checking */
+                          handle[0].handle && handle[1].handle &&
+                          handle[0].stride && handle[1].stride &&
+                          handle[2].handle && handle[3].handle &&
+                          handle[2].stride && handle[3].stride &&
+                          /* KMS - different planes */
+                          handle[0].handle == handle[1].handle &&
+                          handle[0].offset != handle[1].offset &&
+                          /* DMABUF - different planes */
+                          handle[2].offset != handle[3].offset &&
+                          /* KMS and DMABUF equivalence */
+                          handle[0].offset == handle[2].offset &&
+                          handle[1].offset == handle[3].offset &&
+                          handle[0].stride == handle[2].stride &&
+                          handle[1].stride == handle[3].stride;
+
+   if (!get_handle_pass) {
+      printf("resource_get_handle returned incorrect values\n");
+      util_report_result(false);
+      goto cleanup;
+   }
+
+   util_report_result(true);
+
+cleanup:
+   pipe_resource_reference(&tex, NULL);
+}
+
 /**
  * Run all tests. This should be run with a clean context after
  * context_create.
@@ -806,9 +1035,14 @@ util_run_tests(struct pipe_screen *screen)
       test_texture_barrier(ctx, false, i);
    for (int i = 1; i <= 8; i = i * 2)
       test_texture_barrier(ctx, true, i);
+   ctx->destroy(ctx);
 
+   ctx = screen->context_create(screen, NULL, PIPE_CONTEXT_COMPUTE_ONLY);
+   test_compute_clear_image(ctx);
    ctx->destroy(ctx);
 
+   test_nv12(screen);
+
    puts("Done. Exiting..");
    exit(0);
 }