freedreno/a6xx: disable LRZ when color channels are masked
[mesa.git] / src / gallium / drivers / zink / zink_query.c
index 3f8c640ae6550b712e743142122719bc5ad17fa8..0d0c4fe53d0265e5f328cc3da9ab0e6631db590d 100644 (file)
@@ -1,24 +1,38 @@
 #include "zink_query.h"
 
 #include "zink_context.h"
+#include "zink_fence.h"
 #include "zink_resource.h"
 #include "zink_screen.h"
 
+#include "util/hash_table.h"
+#include "util/set.h"
 #include "util/u_dump.h"
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 
+#define NUM_QUERIES 50
+
 struct zink_query {
    enum pipe_query_type type;
 
    VkQueryPool query_pool;
-   unsigned curr_query, num_queries;
+   unsigned last_checked_query, curr_query, num_queries;
 
    VkQueryType vkqtype;
+   unsigned index;
    bool use_64bit;
    bool precise;
+   bool xfb_running;
+
+   bool active; /* query is considered active by vk */
+   bool needs_reset; /* query is considered active by vk and cannot be destroyed */
+   bool dead; /* query should be destroyed when its fence finishes */
 
+   unsigned fences;
    struct list_head active_list;
+
+   union pipe_query_result accumulated_result;
 };
 
 static VkQueryType
@@ -30,6 +44,7 @@ convert_query_type(unsigned query_type, bool *use_64bit, bool *precise)
    case PIPE_QUERY_OCCLUSION_COUNTER:
       *precise = true;
       *use_64bit = true;
+      /* fallthrough */
    case PIPE_QUERY_OCCLUSION_PREDICATE:
    case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
       return VK_QUERY_TYPE_OCCLUSION;
@@ -37,7 +52,11 @@ convert_query_type(unsigned query_type, bool *use_64bit, bool *precise)
       *use_64bit = true;
       return VK_QUERY_TYPE_TIMESTAMP;
    case PIPE_QUERY_PIPELINE_STATISTICS:
+   case PIPE_QUERY_PRIMITIVES_GENERATED:
       return VK_QUERY_TYPE_PIPELINE_STATISTICS;
+   case PIPE_QUERY_PRIMITIVES_EMITTED:
+      *use_64bit = true;
+      return VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
    default:
       debug_printf("unknown query: %s\n",
                    util_str_query_type(query_type, true));
@@ -56,27 +75,31 @@ zink_create_query(struct pipe_context *pctx,
    if (!query)
       return NULL;
 
+   query->index = index;
    query->type = query_type;
    query->vkqtype = convert_query_type(query_type, &query->use_64bit, &query->precise);
    if (query->vkqtype == -1)
       return NULL;
 
-   query->num_queries = query_type == PIPE_QUERY_TIMESTAMP ? 1 : 100;
+   query->num_queries = query_type == PIPE_QUERY_TIMESTAMP ? 1 : NUM_QUERIES;
    query->curr_query = 0;
 
    pool_create.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
    pool_create.queryType = query->vkqtype;
    pool_create.queryCount = query->num_queries;
+   if (query_type == PIPE_QUERY_PRIMITIVES_GENERATED)
+     pool_create.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
 
    VkResult status = vkCreateQueryPool(screen->dev, &pool_create, NULL, &query->query_pool);
    if (status != VK_SUCCESS) {
       FREE(query);
       return NULL;
    }
+   struct zink_batch *batch = zink_batch_no_rp(zink_context(pctx));
+   vkCmdResetQueryPool(batch->cmdbuf, query->query_pool, 0, query->num_queries);
    return (struct pipe_query *)query;
 }
 
-/* TODO: rework this to be less hammer-ish using deferred destroy */
 static void
 wait_query(struct pipe_context *pctx, struct zink_query *query)
 {
@@ -90,6 +113,14 @@ wait_query(struct pipe_context *pctx, struct zink_query *query)
    }
 }
 
+static void
+destroy_query(struct zink_screen *screen, struct zink_query *query)
+{
+   assert(!p_atomic_read(&query->fences));
+   vkDestroyQueryPool(screen->dev, query->query_pool, NULL);
+   FREE(query);
+}
+
 static void
 zink_destroy_query(struct pipe_context *pctx,
                    struct pipe_query *q)
@@ -97,59 +128,196 @@ zink_destroy_query(struct pipe_context *pctx,
    struct zink_screen *screen = zink_screen(pctx->screen);
    struct zink_query *query = (struct zink_query *)q;
 
-   if (!list_is_empty(&query->active_list)) {
-      wait_query(pctx, query);
+   p_atomic_set(&query->dead, true);
+   if (p_atomic_read(&query->fences)) {
+      if (query->xfb_running)
+        wait_query(pctx, query);
+      return;
    }
 
-   vkDestroyQueryPool(screen->dev, query->query_pool, NULL);
-   FREE(query);
+   destroy_query(screen, query);
+}
+
+void
+zink_prune_queries(struct zink_screen *screen, struct zink_fence *fence)
+{
+   set_foreach(fence->active_queries, entry) {
+      struct zink_query *query = (void*)entry->key;
+      if (!p_atomic_dec_return(&query->fences)) {
+         if (p_atomic_read(&query->dead))
+            destroy_query(screen, query);
+      }
+   }
+   _mesa_set_destroy(fence->active_queries, NULL);
+   fence->active_queries = NULL;
+}
+
+static bool
+get_query_result(struct pipe_context *pctx,
+                      struct pipe_query *q,
+                      bool wait,
+                      union pipe_query_result *result)
+{
+   struct zink_screen *screen = zink_screen(pctx->screen);
+   struct zink_query *query = (struct zink_query *)q;
+   VkQueryResultFlagBits flags = 0;
+
+   if (wait)
+      flags |= VK_QUERY_RESULT_WAIT_BIT;
+
+   if (query->use_64bit)
+      flags |= VK_QUERY_RESULT_64_BIT;
+
+   if (result != &query->accumulated_result) {
+      memcpy(result, &query->accumulated_result, sizeof(query->accumulated_result));
+      util_query_clear_result(&query->accumulated_result, query->type);
+   } else {
+      assert(query->vkqtype != VK_QUERY_TYPE_TIMESTAMP);
+      flags |= VK_QUERY_RESULT_PARTIAL_BIT;
+   }
+
+   // union pipe_query_result results[NUM_QUERIES * 2];
+   /* xfb queries return 2 results */
+   uint64_t results[NUM_QUERIES * 2];
+   memset(results, 0, sizeof(results));
+   int num_results = query->curr_query - query->last_checked_query;
+   if (query->vkqtype == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
+      /* this query emits 2 values */
+      assert(query->curr_query <= ARRAY_SIZE(results) / 2);
+      VkResult status = vkGetQueryPoolResults(screen->dev, query->query_pool,
+                                              query->last_checked_query, num_results,
+                                              sizeof(results),
+                                              results,
+                                              sizeof(uint64_t),
+                                              flags);
+      if (status != VK_SUCCESS)
+         return false;
+      /* multiply for correct looping behavior below */
+      num_results *= 2;
+   } else {
+      assert(query->curr_query <= ARRAY_SIZE(results));
+      VkResult status = vkGetQueryPoolResults(screen->dev, query->query_pool,
+                                              query->last_checked_query, num_results,
+                                              sizeof(results),
+                                              results,
+                                              sizeof(uint64_t),
+                                              flags);
+      if (status != VK_SUCCESS)
+         return false;
+   }
+
+   for (int i = 0; i < num_results; ++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;
+      case PIPE_QUERY_PRIMITIVES_GENERATED:
+         result->u32 += results[i];
+         break;
+      case PIPE_QUERY_PRIMITIVES_EMITTED:
+         /* A query pool created with this type will capture 2 integers -
+          * numPrimitivesWritten and numPrimitivesNeeded -
+          * for the specified vertex stream output from the last vertex processing stage.
+          * - from VK_EXT_transform_feedback spec
+          */
+         result->u64 += results[i];
+         i++;
+         break;
+
+      default:
+         debug_printf("unhangled query type: %s\n",
+                      util_str_query_type(query->type, true));
+         unreachable("unexpected query type");
+      }
+   }
+   query->last_checked_query = query->curr_query;
+
+   return TRUE;
+}
+
+static void
+reset_pool(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q)
+{
+   /* This command must only be called outside of a render pass instance
+    *
+    * - vkCmdResetQueryPool spec
+    */
+   batch = zink_batch_no_rp(ctx);
+
+   get_query_result(&ctx->base, (struct pipe_query*)q, false, &q->accumulated_result);
+   vkCmdResetQueryPool(batch->cmdbuf, q->query_pool, 0, q->num_queries);
+   q->last_checked_query = q->curr_query = 0;
+   q->needs_reset = false;
 }
 
 static void
-begin_query(struct zink_context *ctx, struct zink_query *q)
+begin_query(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q)
 {
    VkQueryControlFlags flags = 0;
+
+   if (q->needs_reset)
+      reset_pool(ctx, batch, q);
+   assert(q->curr_query < q->num_queries);
    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);
+   if (q->vkqtype == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
+      zink_screen(ctx->base.screen)->vk_CmdBeginQueryIndexedEXT(batch->cmdbuf,
+                                                                q->query_pool,
+                                                                q->curr_query,
+                                                                flags,
+                                                                q->index);
+      q->xfb_running = true;
+   } else
+      vkCmdBeginQuery(batch->cmdbuf, q->query_pool, q->curr_query, flags);
+   q->active = true;
+   if (!batch->active_queries)
+      batch->active_queries = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal);
+   assert(batch->active_queries);
+   p_atomic_inc(&q->fences);
+   _mesa_set_add(batch->active_queries, q);
 }
 
 static bool
 zink_begin_query(struct pipe_context *pctx,
                  struct pipe_query *q)
 {
-   struct zink_context *ctx = zink_context(pctx);
    struct zink_query *query = (struct zink_query *)q;
+   struct zink_batch *batch = zink_curr_batch(zink_context(pctx));
 
    /* ignore begin_query for timestamps */
    if (query->type == PIPE_QUERY_TIMESTAMP)
       return true;
+   util_query_clear_result(&query->accumulated_result, query->type);
 
-   /* 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;
-
-   begin_query(ctx, query);
-   list_addtail(&query->active_list, &ctx->active_queries);
+   begin_query(zink_context(pctx), batch, query);
 
    return true;
 }
 
 static void
-end_query(struct zink_context *ctx, struct zink_query *q)
+end_query(struct zink_context *ctx, struct zink_batch *batch, struct zink_query *q)
 {
-   struct zink_batch *batch = zink_curr_batch(ctx);
+   struct zink_screen *screen = zink_screen(ctx->base.screen);
    assert(q->type != PIPE_QUERY_TIMESTAMP);
-   vkCmdEndQuery(batch->cmdbuf, q->query_pool, q->curr_query);
+   q->active = false;
+   if (q->vkqtype == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT)
+      screen->vk_CmdEndQueryIndexedEXT(batch->cmdbuf, q->query_pool, q->curr_query, q->index);
+   else
+      vkCmdEndQuery(batch->cmdbuf, q->query_pool, q->curr_query);
    if (++q->curr_query == q->num_queries) {
-      assert(0);
-      /* need to reset pool! */
+      /* can't do zink_batch_no_rp here because we might already be inside a zink_batch_no_rp */
+      if (batch->rp)
+         q->needs_reset = true;
+      else
+        reset_pool(ctx, batch, q);
    }
 }
 
@@ -159,16 +327,14 @@ 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->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->query_pool, 0);
-   } else {
-      end_query(ctx, query);
-      list_delinit(&query->active_list);
-   }
+   } else if (query->active)
+      end_query(ctx, batch, query);
 
    return true;
 }
@@ -179,72 +345,40 @@ zink_get_query_result(struct pipe_context *pctx,
                       bool wait,
                       union pipe_query_result *result)
 {
-   struct zink_screen *screen = zink_screen(pctx->screen);
    struct zink_query *query = (struct zink_query *)q;
-   VkQueryResultFlagBits flags = 0;
 
    if (wait) {
       wait_query(pctx, query);
-      flags |= VK_QUERY_RESULT_WAIT_BIT;
    } else
       pctx->flush(pctx, NULL, 0);
-
-   if (query->use_64bit)
-      flags |= VK_QUERY_RESULT_64_BIT;
-
-   // 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;
-
-   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;
+   return get_query_result(pctx, q, wait, result);
 }
 
 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);
+   if (!batch->active_queries)
+      return;
+   set_foreach(batch->active_queries, entry) {
+      struct zink_query *query = (void*)entry->key;
+      /* if a query isn't active here then we don't need to reactivate it on the next batch */
+      if (query->active) {
+         end_query(ctx, batch, query);
+         /* the fence is going to steal the set off the batch, so we have to copy
+          * the active queries onto a list
+          */
+         list_addtail(&query->active_list, &ctx->suspended_queries);
+      }
    }
 }
 
 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);
+   struct zink_query *query, *next;
+   LIST_FOR_EACH_ENTRY_SAFE(query, next, &ctx->suspended_queries, active_list) {
+      begin_query(ctx, batch, query);
+      list_delinit(&query->active_list);
    }
 }
 
@@ -270,7 +404,7 @@ zink_render_condition(struct pipe_context *pctx,
    struct zink_context *ctx = zink_context(pctx);
    struct zink_screen *screen = zink_screen(pctx->screen);
    struct zink_query *query = (struct zink_query *)pquery;
-   struct zink_batch *batch = zink_curr_batch(ctx);
+   struct zink_batch *batch = zink_batch_no_rp(ctx);
    VkQueryResultFlagBits flags = 0;
 
    if (query == NULL) {
@@ -299,9 +433,11 @@ zink_render_condition(struct pipe_context *pctx,
 
    if (query->use_64bit)
       flags |= VK_QUERY_RESULT_64_BIT;
-   vkCmdCopyQueryPoolResults(batch->cmdbuf, query->query_pool, 0, 1,
+   int num_results = query->curr_query - query->last_checked_query;
+   vkCmdCopyQueryPoolResults(batch->cmdbuf, query->query_pool, query->last_checked_query, num_results,
                              res->buffer, 0, 0, flags);
 
+   query->last_checked_query = query->curr_query;
    VkConditionalRenderingFlagsEXT begin_flags = 0;
    if (condition)
       begin_flags = VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT;
@@ -320,7 +456,7 @@ void
 zink_context_query_init(struct pipe_context *pctx)
 {
    struct zink_context *ctx = zink_context(pctx);
-   list_inithead(&ctx->active_queries);
+   list_inithead(&ctx->suspended_queries);
 
    pctx->create_query = zink_create_query;
    pctx->destroy_query = zink_destroy_query;