[virglrenderer-devel] [PATCH] vrend: add support for indirect draws.

Dave Airlie airlied at gmail.com
Tue Feb 13 03:58:50 UTC 2018


From: Dave Airlie <airlied at redhat.com>

These are needed for ARB_draw_indirect and GL4.0

This enables support and turns in the cap when
support is present.

This also enhances the draw packets to cover
future features, it doesn't enable or show these
yet, since other work is required in the shaders.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 src/gallium/include/pipe/p_state.h | 35 +++++++++++++++++++++++++++++++++++
 src/virgl_protocol.h               | 12 ++++++++++++
 src/vrend_decode.c                 | 20 ++++++++++++++++++--
 src/vrend_renderer.c               | 36 +++++++++++++++++++++++++++++++++---
 src/vrend_renderer.h               |  2 +-
 5 files changed, 99 insertions(+), 6 deletions(-)

diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
index 56934ed..a99b386 100644
--- a/src/gallium/include/pipe/p_state.h
+++ b/src/gallium/include/pipe/p_state.h
@@ -526,6 +526,38 @@ struct pipe_index_buffer
    const void *user_buffer;  /**< pointer to a user buffer if buffer == NULL */
 };
 
+struct pipe_draw_indirect_info
+{
+   unsigned offset; /**< must be 4 byte aligned */
+   unsigned stride; /**< must be 4 byte aligned */
+   unsigned draw_count; /**< number of indirect draws */
+   unsigned indirect_draw_count_offset; /**< must be 4 byte aligned */
+
+   /* Indirect draw parameters resource is laid out as follows:
+    *
+    * if using indexed drawing:
+    *  struct {
+    *     uint32_t count;
+    *     uint32_t instance_count;
+    *     uint32_t start;
+    *     int32_t index_bias;
+    *     uint32_t start_instance;
+    *  };
+    * otherwise:
+    *  struct {
+    *     uint32_t count;
+    *     uint32_t instance_count;
+    *     uint32_t start;
+    *     uint32_t start_instance;
+    *  };
+    */
+   struct pipe_resource *buffer;
+
+   /* Indirect draw count resource: If not NULL, contains a 32-bit value which
+    * is to be used as the real draw_count.
+    */
+   struct pipe_resource *indirect_draw_count;
+};
 
 /**
  * Information to describe a draw_vbo call.
@@ -533,6 +565,7 @@ struct pipe_index_buffer
 struct pipe_draw_info
 {
    boolean indexed;  /**< use index buffer */
+   ubyte vertices_per_patch; /**< the number of vertices per patch */
 
    unsigned mode;  /**< the mode of the primitive */
    unsigned start;  /**< the index of the first vertex */
@@ -541,6 +574,7 @@ struct pipe_draw_info
    unsigned start_instance; /**< first instance id */
    unsigned instance_count; /**< number of instances */
 
+   unsigned drawid; /**< id of this draw in a multidraw */
    /**
     * For indexed drawing, these fields apply after index lookup.
     */
@@ -554,6 +588,7 @@ struct pipe_draw_info
    boolean primitive_restart;
    unsigned restart_index;
 
+   struct pipe_draw_indirect_info indirect;
    /**
     * Stream output target. If not NULL, it's used to provide the 'count'
     * parameter based on the number vertices captured by the stream output
diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h
index a2f1e81..1430422 100644
--- a/src/virgl_protocol.h
+++ b/src/virgl_protocol.h
@@ -275,6 +275,8 @@ enum virgl_context_cmd {
 
 /* draw VBO */
 #define VIRGL_DRAW_VBO_SIZE 12
+#define VIRGL_DRAW_VBO_SIZE_TESS 14
+#define VIRGL_DRAW_VBO_SIZE_INDIRECT 20
 #define VIRGL_DRAW_VBO_START 1
 #define VIRGL_DRAW_VBO_COUNT 2
 #define VIRGL_DRAW_VBO_MODE 3
@@ -287,6 +289,16 @@ enum virgl_context_cmd {
 #define VIRGL_DRAW_VBO_MIN_INDEX 10
 #define VIRGL_DRAW_VBO_MAX_INDEX 11
 #define VIRGL_DRAW_VBO_COUNT_FROM_SO 12
+/* tess packet */
+#define VIRGL_DRAW_VBO_VERTICES_PER_PATCH 13
+#define VIRGL_DRAW_VBO_DRAWID 14
+/* indirect packet */
+#define VIRGL_DRAW_VBO_INDIRECT_HANDLE 15
+#define VIRGL_DRAW_VBO_INDIRECT_OFFSET 16
+#define VIRGL_DRAW_VBO_INDIRECT_STRIDE 17
+#define VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT 18
+#define VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT_OFFSET 19
+#define VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT_HANDLE 20
 
 /* create surface */
 #define VIRGL_OBJ_SURFACE_SIZE 5
diff --git a/src/vrend_decode.c b/src/vrend_decode.c
index e429369..3b18596 100644
--- a/src/vrend_decode.c
+++ b/src/vrend_decode.c
@@ -352,7 +352,9 @@ static int vrend_decode_draw_vbo(struct vrend_decode_ctx *ctx, int length)
 {
    struct pipe_draw_info info;
    uint32_t cso;
-   if (length != VIRGL_DRAW_VBO_SIZE)
+   uint32_t handle = 0, indirect_draw_count_handle = 0;
+   if (length != VIRGL_DRAW_VBO_SIZE && length != VIRGL_DRAW_VBO_SIZE_TESS &&
+       length != VIRGL_DRAW_VBO_SIZE_INDIRECT)
       return EINVAL;
    memset(&info, 0, sizeof(struct pipe_draw_info));
 
@@ -368,9 +370,23 @@ static int vrend_decode_draw_vbo(struct vrend_decode_ctx *ctx, int length)
    info.min_index = get_buf_entry(ctx, VIRGL_DRAW_VBO_MIN_INDEX);
    info.max_index = get_buf_entry(ctx, VIRGL_DRAW_VBO_MAX_INDEX);
 
+   if (length >= VIRGL_DRAW_VBO_SIZE_TESS) {
+      info.vertices_per_patch = get_buf_entry(ctx, VIRGL_DRAW_VBO_VERTICES_PER_PATCH);
+      info.drawid = get_buf_entry(ctx, VIRGL_DRAW_VBO_DRAWID);
+   }
+
+   if (length == VIRGL_DRAW_VBO_SIZE_INDIRECT) {
+      handle = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDIRECT_HANDLE);
+      info.indirect.offset = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDIRECT_OFFSET);
+      info.indirect.stride = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDIRECT_STRIDE);
+      info.indirect.draw_count = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT);
+      info.indirect.indirect_draw_count_offset = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT_OFFSET);
+      indirect_draw_count_handle = get_buf_entry(ctx, VIRGL_DRAW_VBO_INDIRECT_DRAW_COUNT_HANDLE);
+   }
+
    cso = get_buf_entry(ctx, VIRGL_DRAW_VBO_COUNT_FROM_SO);
 
-   vrend_draw_vbo(ctx->grctx, &info, cso);
+   vrend_draw_vbo(ctx->grctx, &info, cso, handle, indirect_draw_count_handle);
    return 0;
 }
 
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 46fc8db..087139e 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -2821,15 +2821,31 @@ static void vrend_draw_bind_ubo(struct vrend_context *ctx)
 
 void vrend_draw_vbo(struct vrend_context *ctx,
                     const struct pipe_draw_info *info,
-                    uint32_t cso)
+                    uint32_t cso, uint32_t indirect_handle,
+                    uint32_t indirect_draw_count_handle)
 {
    int i;
    bool new_program = false;
    uint32_t shader_type;
+   struct vrend_resource *indirect_res = NULL;
 
    if (ctx->in_error)
       return;
 
+   if (indirect_handle) {
+      indirect_res = vrend_renderer_ctx_res_lookup(ctx, indirect_handle);
+      if (!indirect_res) {
+         report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_handle);
+         return;
+      }
+   }
+
+   /* this must be zero until we support the feature */
+   if (indirect_draw_count_handle) {
+      report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_handle);
+      return;
+   }
+
    if (ctx->ctx_switch_pending)
       vrend_finish_context_switch(ctx);
 
@@ -2972,12 +2988,21 @@ void vrend_draw_vbo(struct vrend_context *ctx,
          glPrimitiveRestartIndex(info->restart_index);
       }
    }
+
+   if (indirect_res)
+      glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirect_res->id);
+   else
+      glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
+
    /* set the vertex state up now on a delay */
    if (!info->indexed) {
       GLenum mode = info->mode;
       int count = cso ? cso : info->count;
       int start = cso ? 0 : info->start;
-      if (info->instance_count <= 1)
+
+      if (indirect_handle)
+         glDrawArraysIndirect(mode, (GLvoid const *)(unsigned long)info->indirect.offset);
+      else if (info->instance_count <= 1)
          glDrawArrays(mode, start, count);
       else if (info->start_instance)
          glDrawArraysInstancedBaseInstance(mode, start, count, info->instance_count, info->start_instance);
@@ -2999,7 +3024,9 @@ void vrend_draw_vbo(struct vrend_context *ctx,
          break;
       }
 
-      if (info->index_bias) {
+      if (indirect_handle)
+         glDrawElementsIndirect(mode, elsz, (GLvoid const *)(unsigned long)info->indirect.offset);
+      else if (info->index_bias) {
          if (info->instance_count > 1)
             glDrawElementsInstancedBaseVertex(mode, info->count, elsz, (void *)(unsigned long)ctx->sub->ib.offset, info->instance_count, info->index_bias);
          else if (info->min_index != 0 || info->max_index != -1)
@@ -6309,6 +6336,7 @@ void vrend_renderer_fill_caps(uint32_t set, uint32_t version,
       caps->v1.bset.indep_blend_func = 1;
       caps->v1.bset.cube_map_array = 1;
       caps->v1.bset.texture_query_lod = 1;
+      caps->v1.bset.has_indirect_draw = 1;
    } else {
       if (epoxy_has_gl_extension("GL_ARB_draw_buffers_blend"))
          caps->v1.bset.indep_blend_func = 1;
@@ -6316,6 +6344,8 @@ void vrend_renderer_fill_caps(uint32_t set, uint32_t version,
          caps->v1.bset.cube_map_array = 1;
       if (epoxy_has_gl_extension("GL_ARB_texture_query_lod"))
          caps->v1.bset.texture_query_lod = 1;
+      if (epoxy_has_gl_extension("GL_ARB_indirect_draw"))
+         caps->v1.bset.has_indirect_draw = 1;
    }
 
    if (gl_ver >= 42) {
diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
index b9eeb71..9bbd9dd 100644
--- a/src/vrend_renderer.h
+++ b/src/vrend_renderer.h
@@ -124,7 +124,7 @@ void vrend_clear(struct vrend_context *ctx,
 
 void vrend_draw_vbo(struct vrend_context *ctx,
                     const struct pipe_draw_info *info,
-                    uint32_t cso);
+                    uint32_t cso, uint32_t indirect_handle, uint32_t indirect_draw_count_handle);
 
 void vrend_set_framebuffer_state(struct vrend_context *ctx,
                                  uint32_t nr_cbufs, uint32_t surf_handle[PIPE_MAX_COLOR_BUFS],
-- 
2.9.5



More information about the virglrenderer-devel mailing list