HACK: zink: suspend / resume queries on batch-boundaries
authorErik Faye-Lund <erik.faye-lund@collabora.com>
Tue, 16 Jul 2019 11:29:06 +0000 (13:29 +0200)
committerErik Faye-Lund <erik.faye-lund@collabora.com>
Mon, 28 Oct 2019 08:51:47 +0000 (08:51 +0000)
HACK because we assert that we don't overrun the pool. We need a
fallback here instead.

Acked-by: Jordan Justen <jordan.l.justen@intel.com>
src/gallium/drivers/zink/zink_batch.c
src/gallium/drivers/zink/zink_context.h
src/gallium/drivers/zink/zink_query.c
src/gallium/drivers/zink/zink_query.h [new file with mode: 0644]

index 2a1e7f8e65b97c8ac57c90f0252a10ffcef1e244..74700acb3405921201e24c1f65938aa46cce9153 100644 (file)
@@ -3,6 +3,7 @@
 #include "zink_context.h"
 #include "zink_fence.h"
 #include "zink_framebuffer.h"
+#include "zink_query.h"
 #include "zink_render_pass.h"
 #include "zink_resource.h"
 #include "zink_screen.h"
@@ -58,11 +59,17 @@ zink_start_batch(struct zink_context *ctx, struct zink_batch *batch)
    cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    if (vkBeginCommandBuffer(batch->cmdbuf, &cbbi) != VK_SUCCESS)
       debug_printf("vkBeginCommandBuffer failed\n");
+
+   if (!ctx->queries_disabled)
+      zink_resume_queries(ctx, batch);
 }
 
 void
 zink_end_batch(struct zink_context *ctx, struct zink_batch *batch)
 {
+   if (!ctx->queries_disabled)
+      zink_suspend_queries(ctx, batch);
+
    if (vkEndCommandBuffer(batch->cmdbuf) != VK_SUCCESS) {
       debug_printf("vkEndCommandBuffer failed\n");
       return;
index 445579c59b98c53d5b054c1e104d40674b61ff58..147f35f6d18a2ffd65ace3cf848dcc095ff1a534 100644 (file)
 #include "pipe/p_state.h"
 
 #include "util/slab.h"
+#include "util/list.h"
 
 #include <vulkan/vulkan.h>
 
 struct blitter_context;
 struct primconvert_context;
+struct list_head;
 
 struct zink_blend_state;
 struct zink_depth_stencil_alpha_state;
@@ -106,6 +108,9 @@ struct zink_context {
    float blend_constants[4];
 
    struct pipe_stencil_ref stencil_ref;
+
+   struct list_head active_queries;
+   bool queries_disabled;
 };
 
 static inline struct zink_context *
index d5fc800591576c0f3b59564f1c5d2eb2ce828822..615bd2b936853bc44f0daa55160072c6f1ba7d9b 100644 (file)
@@ -1,16 +1,23 @@
+#include "zink_query.h"
 
 #include "zink_context.h"
 #include "zink_screen.h"
 
-#include "util/u_memory.h"
 #include "util/u_dump.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
 
 struct zink_query {
    enum pipe_query_type type;
-   VkQueryPool queryPool;
+
+   VkQueryPool query_pool;
+   unsigned curr_query, num_queries;
+
    VkQueryType vkqtype;
    bool use_64bit;
    bool precise;
+
+   struct list_head active_list;
 };
 
 static VkQueryType
@@ -53,11 +60,14 @@ zink_create_query(struct pipe_context *pctx,
    if (query->vkqtype == -1)
       return NULL;
 
+   query->num_queries = query_type == PIPE_QUERY_TIMESTAMP ? 1 : 100;
+   query->curr_query = 0;
+
    pool_create.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
    pool_create.queryType = query->vkqtype;
-   pool_create.queryCount = 1;
+   pool_create.queryCount = query->num_queries;
 
-   VkResult status = vkCreateQueryPool(screen->dev, &pool_create, NULL, &query->queryPool);
+   VkResult status = vkCreateQueryPool(screen->dev, &pool_create, NULL, &query->query_pool);
    if (status != VK_SUCCESS) {
       FREE(query);
       return NULL;
@@ -72,7 +82,18 @@ zink_destroy_query(struct pipe_context *pctx,
    struct zink_screen *screen = zink_screen(pctx->screen);
    struct zink_query *query = CALLOC_STRUCT(zink_query);
 
-   vkDestroyQueryPool(screen->dev, query->queryPool, NULL);
+   vkDestroyQueryPool(screen->dev, query->query_pool, NULL);
+}
+
+static void
+begin_query(struct zink_context *ctx, struct zink_query *q)
+{
+   VkQueryControlFlags flags = 0;
+   if (q->precise)
+      flags |= VK_QUERY_CONTROL_PRECISE_BIT;
+
+   struct zink_batch *batch = zink_curr_batch(ctx);
+   vkCmdBeginQuery(batch->cmdbuf, q->query_pool, q->curr_query, flags);
 }
 
 static bool
@@ -82,19 +103,36 @@ zink_begin_query(struct pipe_context *pctx,
    struct zink_context *ctx = zink_context(pctx);
    struct zink_query *query = (struct zink_query *)q;
 
-   if (query->vkqtype == VK_QUERY_TYPE_TIMESTAMP)
+   /* ignore begin_query for timestamps */
+   if (query->type == PIPE_QUERY_TIMESTAMP)
       return true;
 
-   VkQueryControlFlags flags = 0;
-   if (query->precise)
-      flags |= VK_QUERY_CONTROL_PRECISE_BIT;
+   /* TODO: resetting on begin isn't ideal, as it forces render-pass exit...
+    * should instead reset on creation (if possible?)... Or perhaps maintain
+    * the pool in the batch instead?
+    */
+   struct zink_batch *batch = zink_batch_no_rp(zink_context(pctx));
+   vkCmdResetQueryPool(batch->cmdbuf, query->query_pool, 0, query->curr_query);
+   query->curr_query = 0;
 
-   struct zink_batch *batch = zink_curr_batch(ctx);
-   vkCmdBeginQuery(batch->cmdbuf, query->queryPool, 0, flags);
+   begin_query(ctx, query);
+   list_addtail(&query->active_list, &ctx->active_queries);
 
    return true;
 }
 
+static void
+end_query(struct zink_context *ctx, struct zink_query *q)
+{
+   struct zink_batch *batch = zink_curr_batch(ctx);
+   assert(q->type != PIPE_QUERY_TIMESTAMP);
+   vkCmdEndQuery(batch->cmdbuf, q->query_pool, q->curr_query);
+   if (++q->curr_query == q->num_queries) {
+      assert(0);
+      /* need to reset pool! */
+   }
+}
+
 static bool
 zink_end_query(struct pipe_context *pctx,
                struct pipe_query *q)
@@ -102,12 +140,16 @@ zink_end_query(struct pipe_context *pctx,
    struct zink_context *ctx = zink_context(pctx);
    struct zink_query *query = (struct zink_query *)q;
 
-   struct zink_batch *batch = zink_curr_batch(ctx);
-   if (query->vkqtype == VK_QUERY_TYPE_TIMESTAMP)
+   if (query->type == PIPE_QUERY_TIMESTAMP) {
+      assert(query->curr_query == 0);
+      struct zink_batch *batch = zink_curr_batch(ctx);
       vkCmdWriteTimestamp(batch->cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
-                          query->queryPool, 0);
-   else
-      vkCmdEndQuery(batch->cmdbuf, query->queryPool, 0);
+                          query->query_pool, 0);
+   } else {
+      end_query(ctx, query);
+      list_delinit(&query->active_list);
+   }
+
    return true;
 }
 
@@ -121,43 +163,96 @@ zink_get_query_result(struct pipe_context *pctx,
    struct zink_query *query = (struct zink_query *)q;
    VkQueryResultFlagBits flags = 0;
 
-   pctx->flush(pctx, NULL, 0);
-
-   if (wait)
+   if (wait) {
+      struct pipe_fence_handle *fence = NULL;
+      pctx->flush(pctx, &fence, PIPE_FLUSH_HINT_FINISH);
+      if (fence) {
+         pctx->screen->fence_finish(pctx->screen, NULL, fence,
+                                    PIPE_TIMEOUT_INFINITE);
+         pctx->screen->fence_reference(pctx->screen, &fence, NULL);
+      }
       flags |= VK_QUERY_RESULT_WAIT_BIT;
+   } else
+      pctx->flush(pctx, NULL, 0);
 
    if (query->use_64bit)
       flags |= VK_QUERY_RESULT_64_BIT;
 
-   if (vkGetQueryPoolResults(screen->dev, query->queryPool,
-                             0, 1, sizeof(*result), result,
-                             0, flags) != VK_SUCCESS)
+   // TODO: handle curr_query > 100
+   // union pipe_query_result results[100];
+   uint64_t results[100];
+   memset(results, 0, sizeof(results));
+   assert(query->curr_query <= ARRAY_SIZE(results));
+   if (vkGetQueryPoolResults(screen->dev, query->query_pool,
+                             0, query->curr_query,
+                             sizeof(results),
+                             results,
+                             sizeof(uint64_t),
+                             flags) != VK_SUCCESS)
       return false;
 
-   switch (query->type) {
-   case PIPE_QUERY_OCCLUSION_PREDICATE:
-   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
-   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
-   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
-   case PIPE_QUERY_GPU_FINISHED:
-      /* fixup bool-queries */
-      result->b = result->u32 != 0;
-      break;
-   default:
-      ; /* nothing */
+   util_query_clear_result(result, query->type);
+   for (int i = 0; i < query->curr_query; ++i) {
+      switch (query->type) {
+      case PIPE_QUERY_OCCLUSION_PREDICATE:
+      case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
+      case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
+      case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
+      case PIPE_QUERY_GPU_FINISHED:
+         result->b |= results[i] != 0;
+         break;
+
+      case PIPE_QUERY_OCCLUSION_COUNTER:
+         result->u64 += results[i];
+         break;
+
+      default:
+         debug_printf("unhangled query type: %s\n",
+                      util_str_query_type(query->type, true));
+         unreachable("unexpected query type");
+      }
    }
 
    return TRUE;
 }
 
+void
+zink_suspend_queries(struct zink_context *ctx, struct zink_batch *batch)
+{
+   struct zink_query *query;
+   LIST_FOR_EACH_ENTRY(query, &ctx->active_queries, active_list) {
+      end_query(ctx, query);
+   }
+}
+
+void
+zink_resume_queries(struct zink_context *ctx, struct zink_batch *batch)
+{
+   struct zink_query *query;
+   LIST_FOR_EACH_ENTRY(query, &ctx->active_queries, active_list) {
+      begin_query(ctx, query);
+   }
+}
+
 static void
 zink_set_active_query_state(struct pipe_context *pctx, bool enable)
 {
+   struct zink_context *ctx = zink_context(pctx);
+   ctx->queries_disabled = !enable;
+
+   struct zink_batch *batch = zink_curr_batch(ctx);
+   if (ctx->queries_disabled)
+      zink_suspend_queries(ctx, batch);
+   else
+      zink_resume_queries(ctx, batch);
 }
 
 void
 zink_context_query_init(struct pipe_context *pctx)
 {
+   struct zink_context *ctx = zink_context(pctx);
+   list_inithead(&ctx->active_queries);
+
    pctx->create_query = zink_create_query;
    pctx->destroy_query = zink_destroy_query;
    pctx->begin_query = zink_begin_query;
diff --git a/src/gallium/drivers/zink/zink_query.h b/src/gallium/drivers/zink/zink_query.h
new file mode 100644 (file)
index 0000000..4b26b44
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ZINK_QUERY_H
+#define ZINK_QUERY_H
+
+struct zink_batch;
+struct zink_context;
+
+void
+zink_suspend_queries(struct zink_context *ctx, struct zink_batch *batch);
+
+void
+zink_resume_queries(struct zink_context *ctx, struct zink_batch *batch);
+
+#endif