[virglrenderer-devel] [PATCH] vrend: add support for indirect draws.
Dave Airlie
airlied at gmail.com
Tue Feb 13 06:10:04 UTC 2018
Oops, I accidentally pushed to master, and can't back it off. I've
left these two patches since I was happy with them, I've reverted the
partial gs5 hacks.
Apologies,
Dave.
On 13 February 2018 at 13:58, Dave Airlie <airlied at gmail.com> wrote:
> 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
>
> _______________________________________________
> virglrenderer-devel mailing list
> virglrenderer-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/virglrenderer-devel
More information about the virglrenderer-devel
mailing list