iris: add conditional render support
authorDave Airlie <airlied@redhat.com>
Mon, 26 Nov 2018 23:03:16 +0000 (09:03 +1000)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 21 Feb 2019 18:26:10 +0000 (10:26 -0800)
src/gallium/drivers/iris/iris_blit.c
src/gallium/drivers/iris/iris_clear.c
src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_query.c
src/gallium/drivers/iris/iris_state.c

index c50e7958d246658c9cee7eaf9e6baad7b880dd09..729d8f7b038a3b0ee917585bbe84f38894fe2a46 100644 (file)
@@ -338,7 +338,8 @@ iris_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
    struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
 
    struct blorp_batch blorp_batch;
-   blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
+   blorp_batch_init(&ice->blorp, &blorp_batch, batch,
+                    info->render_condition_enable ? BLORP_BATCH_PREDICATE_ENABLE : 0);
 
    for (int slice = 0; slice < info->dst.box.depth; slice++) {
       iris_batch_maybe_flush(batch, 1500);
index c9c47afcaa6f2bfe5f37d48f7cafce8fe7a549ae..7f113fa36572dadbf887d13b04e683510cdd2b48 100644 (file)
@@ -56,7 +56,7 @@ iris_clear(struct pipe_context *ctx,
    iris_batch_maybe_flush(batch, 1500);
 
    struct blorp_batch blorp_batch;
-   blorp_batch_init(&ice->blorp, &blorp_batch, batch, 0);
+   blorp_batch_init(&ice->blorp, &blorp_batch, batch, BLORP_BATCH_PREDICATE_ENABLE);
 
    if (buffers & PIPE_CLEAR_DEPTHSTENCIL) {
       struct pipe_surface *psurf = cso_fb->zsbuf;
index 6cb07119efe29047ca6de1f9bb7904586fda9b52..91c0c3afcc5b9603ec223e78368185a9e41187a9 100644 (file)
@@ -211,6 +211,22 @@ enum pipe_control_flags
     PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | \
     PIPE_CONTROL_INSTRUCTION_INVALIDATE)
 
+enum iris_predicate_state {
+   /* The first two states are used if we can determine whether to draw
+    * without having to look at the values in the query object buffer. This
+    * will happen if there is no conditional render in progress, if the query
+    * object is already completed or if something else has already added
+    * samples to the preliminary result.
+    */
+   IRIS_PREDICATE_STATE_RENDER,
+   IRIS_PREDICATE_STATE_DONT_RENDER,
+
+   /* In this case whether to draw or not depends on the result of an
+    * MI_PREDICATE command so the predicate enable bit needs to be checked.
+    */
+   IRIS_PREDICATE_STATE_USE_BIT,
+};
+
 /** @} */
 
 /**
@@ -414,6 +430,7 @@ struct iris_context {
       struct iris_bo *scratch_bos[1 << 4][MESA_SHADER_STAGES];
    } shaders;
 
+   enum iris_predicate_state predicate;
    struct {
       uint64_t dirty;
       uint64_t dirty_for_nos[IRIS_NOS_COUNT];
index 62862927adc82fc3f9acf32b562e27727aae6038..27126d7f7bc7e4e2f9ece377d42ea2a4c06288ed 100644 (file)
@@ -724,6 +724,103 @@ iris_set_active_query_state(struct pipe_context *ctx, boolean enable)
                        IRIS_DIRTY_WM;
 }
 
+static void
+set_predicate_enable(struct iris_context *ice,
+                     bool value)
+{
+   if (value)
+      ice->predicate = IRIS_PREDICATE_STATE_RENDER;
+   else
+      ice->predicate = IRIS_PREDICATE_STATE_DONT_RENDER;
+}
+
+static void
+set_predicate_for_overflow(struct iris_context *ice,
+                           struct iris_query *q)
+{
+   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
+   ice->predicate = IRIS_PREDICATE_STATE_USE_BIT;
+
+   /* Needed to ensure the memory is coherent for the MI_LOAD_REGISTER_MEM
+    * command when loading the values into the predicate source registers for
+    * conditional rendering.
+    */
+   iris_emit_pipe_control_flush(batch, PIPE_CONTROL_FLUSH_ENABLE);
+
+   overflow_result_to_gpr0(ice, q);
+   ice->vtbl.load_register_reg64(batch, CS_GPR(0), MI_PREDICATE_SRC0);
+   ice->vtbl.load_register_imm64(batch, MI_PREDICATE_SRC1, 0ull);
+}
+
+static void
+set_predicate_for_occlusion(struct iris_context *ice,
+                     struct iris_query *q)
+{
+   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
+   ice->predicate = IRIS_PREDICATE_STATE_USE_BIT;
+
+   /* Needed to ensure the memory is coherent for the MI_LOAD_REGISTER_MEM
+    * command when loading the values into the predicate source registers for
+    * conditional rendering.
+    */
+   iris_emit_pipe_control_flush(batch, PIPE_CONTROL_FLUSH_ENABLE);
+
+   ice->vtbl.load_register_mem64(batch, MI_PREDICATE_SRC0, q->bo, offsetof(struct iris_query_snapshots, start));
+   ice->vtbl.load_register_mem64(batch, MI_PREDICATE_SRC1, q->bo, offsetof(struct iris_query_snapshots, end));
+}
+
+static void
+set_predicate_for_result(struct iris_context *ice,
+                         struct iris_query *q,
+                         bool condition)
+{
+   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
+   int load_op;
+
+   switch (q->type) {
+   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
+   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
+      set_predicate_for_overflow(ice, q);
+      break;
+   default:
+      set_predicate_for_occlusion(ice, q);
+      break;
+   }
+
+   if (ice->predicate == IRIS_PREDICATE_STATE_USE_BIT) {
+      if (condition)
+         load_op = MI_PREDICATE_LOADOP_LOAD;
+      else
+         load_op = MI_PREDICATE_LOADOP_LOADINV;
+
+      // batch emit
+      uint32_t predicate = MI_PREDICATE | load_op |
+                           MI_PREDICATE_COMBINEOP_SET |
+                           MI_PREDICATE_COMPAREOP_SRCS_EQUAL;
+      iris_batch_emit(batch, &predicate, sizeof(uint32_t));
+   }
+}
+
+static void
+iris_render_condition(struct pipe_context *ctx,
+                     struct pipe_query *query,
+                     boolean condition,
+                     enum pipe_render_cond_flag mode)
+{
+   struct iris_context *ice = (void *) ctx;
+   struct iris_query *q = (void *) query;
+
+   if (!q) {
+      ice->predicate = IRIS_PREDICATE_STATE_RENDER;
+      return;
+   }
+
+   if (q->result || q->ready)
+      set_predicate_enable(ice, (q->result != 0) ^ condition);
+   else
+      set_predicate_for_result(ice, q, condition);
+}
+
 void
 iris_init_query_functions(struct pipe_context *ctx)
 {
@@ -734,4 +831,5 @@ iris_init_query_functions(struct pipe_context *ctx)
    ctx->get_query_result = iris_get_query_result;
    ctx->get_query_result_resource = iris_get_query_result_resource;
    ctx->set_active_query_state = iris_set_active_query_state;
+   ctx->render_condition = iris_render_condition;
 }
index ba7c98a6fd2f2034f8ea86068355c8bf12add3fd..99073088b00e4846f083a02812f0a18bc5d34c60 100644 (file)
@@ -4542,7 +4542,7 @@ iris_upload_render_state(struct iris_context *ice,
       prim.InstanceCount = draw->instance_count;
       prim.VertexCountPerInstance = draw->count;
       prim.VertexAccessType = draw->index_size > 0 ? RANDOM : SEQUENTIAL;
-
+      prim.PredicateEnable = ice->predicate == IRIS_PREDICATE_STATE_USE_BIT ? 1 : 0;
       // XXX: this is probably bonkers.
       prim.StartVertexLocation = draw->start;