[Mesa-dev] [PATCH 4/5] gallium: add facilities for indirect drawing

Christoph Bumiller e0425955 at student.tuwien.ac.at
Fri Apr 5 05:29:36 PDT 2013


v2:
Added comments to util_draw_indirect, clarified and fixed map size.
Removed unlikely().
---
 src/gallium/auxiliary/util/u_draw.c              |   43 ++++++++++++++++++++++
 src/gallium/auxiliary/util/u_draw.h              |    8 ++++
 src/gallium/auxiliary/util/u_dump_state.c        |    3 ++
 src/gallium/docs/source/screen.rst               |    3 ++
 src/gallium/drivers/freedreno/freedreno_screen.c |    1 +
 src/gallium/drivers/i915/i915_screen.c           |    1 +
 src/gallium/drivers/llvmpipe/lp_draw_arrays.c    |    5 +++
 src/gallium/drivers/llvmpipe/lp_screen.c         |    2 +
 src/gallium/drivers/nv30/nv30_screen.c           |    1 +
 src/gallium/drivers/nv50/nv50_screen.c           |    2 +
 src/gallium/drivers/r300/r300_screen.c           |    1 +
 src/gallium/drivers/r600/r600_pipe.c             |    1 +
 src/gallium/drivers/radeonsi/radeonsi_pipe.c     |    1 +
 src/gallium/drivers/softpipe/sp_draw_arrays.c    |    6 +++
 src/gallium/drivers/softpipe/sp_screen.c         |    2 +
 src/gallium/drivers/svga/svga_screen.c           |    1 +
 src/gallium/drivers/trace/tr_dump_state.c        |    3 ++
 src/gallium/include/pipe/p_defines.h             |    3 +-
 src/gallium/include/pipe/p_state.h               |   22 +++++++++++
 19 files changed, 108 insertions(+), 1 deletions(-)

diff --git a/src/gallium/auxiliary/util/u_draw.c b/src/gallium/auxiliary/util/u_draw.c
index 83d9284..b9f8fcd 100644
--- a/src/gallium/auxiliary/util/u_draw.c
+++ b/src/gallium/auxiliary/util/u_draw.c
@@ -27,6 +27,7 @@
 
 
 #include "util/u_debug.h"
+#include "util/u_inlines.h"
 #include "util/u_math.h"
 #include "util/u_format.h"
 #include "util/u_draw.h"
@@ -123,3 +124,45 @@ util_draw_max_index(
 
    return max_index + 1;
 }
+
+
+/* This extracts the draw arguments from the info_in->indirect resource,
+ * puts them into a new instance of pipe_draw_info, and calls draw_vbo on it.
+ */
+void
+util_draw_indirect(struct pipe_context *pipe,
+                   const struct pipe_draw_info *info_in)
+{
+   struct pipe_draw_info info;
+   struct pipe_transfer *transfer;
+   uint32_t *params;
+   const unsigned num_params = info_in->indexed ? 5 : 4;
+
+   assert(info_in->indirect);
+   assert(!info_in->count_from_stream_output);
+
+   memcpy(&info, info_in, sizeof(info));
+
+   params = (uint32_t *)
+      pipe_buffer_map_range(pipe,
+                            info_in->indirect,
+                            info_in->indirect_offset,
+                            num_params * sizeof(uint32_t),
+                            PIPE_TRANSFER_READ,
+                            &transfer);
+   if (!transfer) {
+      debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__);
+      return;
+   }
+
+   info.count = params[0];
+   info.instance_count = params[1];
+   info.start = params[2];
+   info.index_bias = info_in->indexed ? params[3] : 0;
+   info.start_instance = info_in->indexed ? params[4] : params[3];
+   info.indirect = NULL;
+
+   pipe_buffer_unmap(pipe, transfer);
+
+   pipe->draw_vbo(pipe, &info);
+}
diff --git a/src/gallium/auxiliary/util/u_draw.h b/src/gallium/auxiliary/util/u_draw.h
index 3dc6918..1dd6b51 100644
--- a/src/gallium/auxiliary/util/u_draw.h
+++ b/src/gallium/auxiliary/util/u_draw.h
@@ -142,6 +142,14 @@ util_draw_range_elements(struct pipe_context *pipe,
 }
 
 
+/* This converts an indirect draw into a direct draw by mapping the indirect
+ * buffer, extracting its arguments, and calling pipe->draw_vbo.
+ */
+void
+util_draw_indirect(struct pipe_context *pipe,
+                   const struct pipe_draw_info *info);
+
+
 unsigned
 util_draw_max_index(
       const struct pipe_vertex_buffer *vertex_buffers,
diff --git a/src/gallium/auxiliary/util/u_dump_state.c b/src/gallium/auxiliary/util/u_dump_state.c
index 2f28f3c..21b6044 100644
--- a/src/gallium/auxiliary/util/u_dump_state.c
+++ b/src/gallium/auxiliary/util/u_dump_state.c
@@ -758,6 +758,9 @@ util_dump_draw_info(FILE *stream, const struct pipe_draw_info *state)
 
    util_dump_member(stream, ptr, state, count_from_stream_output);
 
+   util_dump_member(stream, ptr, state, indirect);
+   util_dump_member(stream, uint, state, indirect_offset);
+
    util_dump_struct_end(stream);
 }
 
diff --git a/src/gallium/docs/source/screen.rst b/src/gallium/docs/source/screen.rst
index d8cfb97..96f316a 100644
--- a/src/gallium/docs/source/screen.rst
+++ b/src/gallium/docs/source/screen.rst
@@ -151,6 +151,9 @@ The integer capabilities:
   dedicated memory should return 1 and all software rasterizers should return 0.
 * ``PIPE_CAP_QUERY_PIPELINE_STATISTICS``: Whether PIPE_QUERY_PIPELINE_STATISTICS
   is supported.
+* ``PIPE_CAP_DRAW_INDIRECT``: Whether the driver supports taking draw arguments
+  { count, instance_count, start, index_bias } from a PIPE_BUFFER resource.
+  See pipe_draw_info.
 
 
 .. _pipe_capf:
diff --git a/src/gallium/drivers/freedreno/freedreno_screen.c b/src/gallium/drivers/freedreno/freedreno_screen.c
index 283d07f..2b13e29 100644
--- a/src/gallium/drivers/freedreno/freedreno_screen.c
+++ b/src/gallium/drivers/freedreno/freedreno_screen.c
@@ -200,6 +200,7 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
 	case PIPE_CAP_USER_VERTEX_BUFFERS:
 	case PIPE_CAP_USER_INDEX_BUFFERS:
 	case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+	case PIPE_CAP_DRAW_INDIRECT:
 		return 0;
 
 	/* Stream output. */
diff --git a/src/gallium/drivers/i915/i915_screen.c b/src/gallium/drivers/i915/i915_screen.c
index 54b2154..5a04c42 100644
--- a/src/gallium/drivers/i915/i915_screen.c
+++ b/src/gallium/drivers/i915/i915_screen.c
@@ -213,6 +213,7 @@ i915_get_param(struct pipe_screen *screen, enum pipe_cap cap)
    case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
    case PIPE_CAP_TEXTURE_MULTISAMPLE:
    case PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT:
+   case PIPE_CAP_DRAW_INDIRECT:
       return 0;
 
    case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
index efeca25..9ae0fee 100644
--- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
+++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
@@ -60,6 +60,11 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    if (!llvmpipe_check_render_cond(lp))
       return;
 
+   if (info->indirect) {
+      util_draw_indirect(pipe, info);
+      return;
+   }
+
    if (lp->dirty)
       llvmpipe_update_derived( lp );
 
diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index 6700887..5cef99b 100644
--- a/src/gallium/drivers/llvmpipe/lp_screen.c
+++ b/src/gallium/drivers/llvmpipe/lp_screen.c
@@ -212,6 +212,8 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY:
    case PIPE_CAP_TGSI_TEXCOORD:
       return 0;
+   case PIPE_CAP_DRAW_INDIRECT:
+      return 1;
 
    case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
       return 16;
diff --git a/src/gallium/drivers/nv30/nv30_screen.c b/src/gallium/drivers/nv30/nv30_screen.c
index e33710e..06a16c8 100644
--- a/src/gallium/drivers/nv30/nv30_screen.c
+++ b/src/gallium/drivers/nv30/nv30_screen.c
@@ -123,6 +123,7 @@ nv30_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
    case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
    case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+   case PIPE_CAP_DRAW_INDIRECT:
       return 0;
    case PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY:
    case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY:
diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c
index 55081be..4da0dce 100644
--- a/src/gallium/drivers/nv50/nv50_screen.c
+++ b/src/gallium/drivers/nv50/nv50_screen.c
@@ -186,6 +186,8 @@ nv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
       return 1;
    case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
       return 0;
+   case PIPE_CAP_DRAW_INDIRECT:
+      return 0;
    default:
       NOUVEAU_ERR("unknown PIPE_CAP %d\n", param);
       return 0;
diff --git a/src/gallium/drivers/r300/r300_screen.c b/src/gallium/drivers/r300/r300_screen.c
index 3175b3b..4e29a2e 100644
--- a/src/gallium/drivers/r300/r300_screen.c
+++ b/src/gallium/drivers/r300/r300_screen.c
@@ -162,6 +162,7 @@ static int r300_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
         case PIPE_CAP_CUBE_MAP_ARRAY:
         case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
         case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
+        case PIPE_CAP_DRAW_INDIRECT:
             return 0;
 
         /* SWTCL-only features. */
diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c
index 1e4c964..0cf6ab7 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -603,6 +603,7 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
 	case PIPE_CAP_USER_VERTEX_BUFFERS:
 	case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
 	case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+	case PIPE_CAP_DRAW_INDIRECT:
 		return 0;
 
 	/* Stream output. */
diff --git a/src/gallium/drivers/radeonsi/radeonsi_pipe.c b/src/gallium/drivers/radeonsi/radeonsi_pipe.c
index 17d825b..d49cd8a 100644
--- a/src/gallium/drivers/radeonsi/radeonsi_pipe.c
+++ b/src/gallium/drivers/radeonsi/radeonsi_pipe.c
@@ -361,6 +361,7 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
 	case PIPE_CAP_CUBE_MAP_ARRAY:
 	case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
 	case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
+	case PIPE_CAP_DRAW_INDIRECT:
 		return 0;
 
 	/* Stream output. */
diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c
index ba9e781..db10c62 100644
--- a/src/gallium/drivers/softpipe/sp_draw_arrays.c
+++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c
@@ -34,6 +34,7 @@
 #include "pipe/p_defines.h"
 #include "pipe/p_context.h"
 #include "util/u_inlines.h"
+#include "util/u_draw.h"
 #include "util/u_prim.h"
 
 #include "sp_context.h"
@@ -67,6 +68,11 @@ softpipe_draw_vbo(struct pipe_context *pipe,
    if (!softpipe_check_render_cond(sp))
       return;
 
+   if (info->indirect) {
+      util_draw_indirect(pipe, info);
+      return;
+   }
+
    sp->reduced_api_prim = u_reduced_prim(info->mode);
 
    if (sp->dirty) {
diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
index 6915f91..8114165 100644
--- a/src/gallium/drivers/softpipe/sp_screen.c
+++ b/src/gallium/drivers/softpipe/sp_screen.c
@@ -178,6 +178,8 @@ softpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_TGSI_TEXCOORD:
    case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER:
       return 0;
+   case PIPE_CAP_DRAW_INDIRECT:
+      return 1;
    }
    /* should only get here on unhandled cases */
    debug_printf("Unexpected PIPE_CAP %d query\n", param);
diff --git a/src/gallium/drivers/svga/svga_screen.c b/src/gallium/drivers/svga/svga_screen.c
index 6213535..c046a4b 100644
--- a/src/gallium/drivers/svga/svga_screen.c
+++ b/src/gallium/drivers/svga/svga_screen.c
@@ -263,6 +263,7 @@ svga_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
    case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
    case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+   case PIPE_CAP_DRAW_INDIRECT:
       return 0;
    case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY:
       return 1;
diff --git a/src/gallium/drivers/trace/tr_dump_state.c b/src/gallium/drivers/trace/tr_dump_state.c
index 006082b..5ed3f91 100644
--- a/src/gallium/drivers/trace/tr_dump_state.c
+++ b/src/gallium/drivers/trace/tr_dump_state.c
@@ -708,6 +708,9 @@ void trace_dump_draw_info(const struct pipe_draw_info *state)
 
    trace_dump_member(ptr, state, count_from_stream_output);
 
+   trace_dump_member(ptr, state, indirect);
+   trace_dump_member(uint, state, indirect_offset);
+
    trace_dump_struct_end();
 }
 
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index 4c6b1f1..ebf70a2 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -506,7 +506,8 @@ enum pipe_cap {
    PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 78,
    PIPE_CAP_TGSI_TEXCOORD = 79,
    PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER = 80,
-   PIPE_CAP_QUERY_PIPELINE_STATISTICS = 81
+   PIPE_CAP_QUERY_PIPELINE_STATISTICS = 81,
+   PIPE_CAP_DRAW_INDIRECT = 82
 };
 
 /**
diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
index dfafd0b..3e96cb5 100644
--- a/src/gallium/include/pipe/p_state.h
+++ b/src/gallium/include/pipe/p_state.h
@@ -559,6 +559,28 @@ struct pipe_draw_info
     * be set via set_vertex_buffers manually.
     */
    struct pipe_stream_output_target *count_from_stream_output;
+
+   /* Indirect parameters resource: If not NULL, most values are taken
+    * from this buffer instead, which is laid out as follows:
+    *
+    * if indexed is TRUE:
+    *  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 *indirect;
+   unsigned indirect_offset; /**< must be 4 byte aligned */
 };
 
 
-- 
1.7.3.4



More information about the mesa-dev mailing list