[virglrenderer-devel] [PATCH 3/3] renderer: add shader_storage_buffer_object support.

Gurchetan Singh gurchetansingh at chromium.org
Wed Jul 18 00:11:47 UTC 2018


On Tue, Jul 17, 2018 at 12:48 AM Dave Airlie <airlied at gmail.com> wrote:
>
> From: Dave Airlie <airlied at redhat.com>
>
> This pulls the code out from the gles31 development,
> and modifies the caps to support two different limits
>
> (so far I've only found fs/cs vs everyone else limits differ)
> ---
>  src/virgl_hw.h       |   1 +
>  src/virgl_protocol.h |  10 +++++
>  src/vrend_decode.c   |  33 ++++++++++++++
>  src/vrend_renderer.c | 105 ++++++++++++++++++++++++++++++++++++++++++-
>  src/vrend_renderer.h |   6 +++
>  5 files changed, 153 insertions(+), 2 deletions(-)
>
> diff --git a/src/virgl_hw.h b/src/virgl_hw.h
> index cd828ed..a85a14d 100644
> --- a/src/virgl_hw.h
> +++ b/src/virgl_hw.h
> @@ -307,6 +307,7 @@ struct virgl_caps_v2 {
>          uint32_t capability_bits;
>          uint32_t sample_locations[8];
>          uint32_t max_vertex_attrib_stride;
> +        uint32_t shader_storage_buffer_object_maximums; /* 0:15 bits for FS/CS; 16:31 bits for all other stages */
>  };
>
>  union virgl_caps {
> diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h
> index a0b6984..6c73dfb 100644
> --- a/src/virgl_protocol.h
> +++ b/src/virgl_protocol.h
> @@ -85,6 +85,7 @@ enum virgl_context_cmd {
>     VIRGL_CCMD_BIND_SHADER,
>     VIRGL_CCMD_SET_TESS_STATE,
>     VIRGL_CCMD_SET_MIN_SAMPLES,
> +   VIRGL_CCMD_SET_SHADER_BUFFERS,
>  };
>
>  /*
> @@ -490,4 +491,13 @@ enum virgl_context_cmd {
>  #define VIRGL_SET_MIN_SAMPLES_SIZE 1
>  #define VIRGL_SET_MIN_SAMPLES_MASK 1
>
> +/* set shader buffers */
> +#define VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE 3
> +#define VIRGL_SET_SHADER_BUFFER_SIZE(x) (VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE * (x)) + 2
> +#define VIRGL_SET_SHADER_BUFFER_SHADER_TYPE 1
> +#define VIRGL_SET_SHADER_BUFFER_START_SLOT 2
> +#define VIRGL_SET_SHADER_BUFFER_OFFSET(x) ((x) * VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 2)
> +#define VIRGL_SET_SHADER_BUFFER_LENGTH(x) ((x) * VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 3)
> +#define VIRGL_SET_SHADER_BUFFER_RES_HANDLE(x) ((x) * VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 4)
> +
>  #endif
> diff --git a/src/vrend_decode.c b/src/vrend_decode.c
> index 2432938..df516a0 100644
> --- a/src/vrend_decode.c
> +++ b/src/vrend_decode.c
> @@ -1077,6 +1077,36 @@ static int vrend_decode_set_tess_state(struct vrend_decode_ctx *ctx,
>     return 0;
>  }
>
> +static int vrend_decode_set_shader_buffers(struct vrend_decode_ctx *ctx, uint16_t length)
> +{
> +   int num_ssbo;
> +   uint32_t shader_type, start_slot;
> +
> +   if (length < 2)
> +      return EINVAL;
> +
> +   num_ssbo = (length - 2) / VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE;
> +   shader_type = get_buf_entry(ctx, VIRGL_SET_SHADER_BUFFER_SHADER_TYPE);
> +   start_slot = get_buf_entry(ctx, VIRGL_SET_SHADER_BUFFER_START_SLOT);
> +   if (shader_type >= PIPE_SHADER_TYPES)
> +      return EINVAL;
> +
> +   if (num_ssbo < 1)
> +      return 0;
> +
> +   if (start_slot + num_ssbo > PIPE_MAX_SHADER_BUFFERS)
> +      return EINVAL;
> +
> +   for (int i = 0; i < num_ssbo; i++) {
> +      uint32_t offset = get_buf_entry(ctx, i * VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 3);
> +      uint32_t buf_len = get_buf_entry(ctx, i * VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 4);
> +      uint32_t handle = get_buf_entry(ctx, i * VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 5);
> +      vrend_set_single_ssbo(ctx->grctx, shader_type, start_slot + i, offset, buf_len,
> +                           handle);
> +   }
> +   return 0;
> +}
> +
>  static int vrend_decode_set_streamout_targets(struct vrend_decode_ctx *ctx,
>                                                uint16_t length)
>  {
> @@ -1305,6 +1335,9 @@ int vrend_decode_block(uint32_t ctx_id, uint32_t *block, int ndw)
>        case VIRGL_CCMD_SET_TESS_STATE:
>           ret = vrend_decode_set_tess_state(gdctx, len);
>           break;
> +      case VIRGL_CCMD_SET_SHADER_BUFFERS:
> +         ret = vrend_decode_set_shader_buffers(gdctx, len);
> +         break;
>        default:
>           ret = EINVAL;
>        }
> diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
> index 69f1da3..ce4d744 100644
> --- a/src/vrend_renderer.c
> +++ b/src/vrend_renderer.c
> @@ -119,6 +119,7 @@ struct global_renderer_state {
>     bool have_texture_storage;
>     bool have_tessellation;
>     bool have_texture_view;
> +   bool have_ssbo;
>
>     /* these appeared broken on at least one driver */
>     bool use_explicit_locations;
> @@ -166,6 +167,9 @@ struct vrend_linked_shader_program {
>     GLint fs_stipple_loc;
>
>     GLuint clip_locs[8];
> +
> +   uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
> +   GLuint *ssbo_locs[PIPE_SHADER_TYPES];
>  };
>
>  struct vrend_shader {
> @@ -243,6 +247,12 @@ struct vrend_sampler_view {
>     struct vrend_resource *texture;
>  };
>
> +struct vrend_ssbo {
> +   struct vrend_resource *res;
> +   unsigned buffer_size;
> +   unsigned buffer_offset;
> +};
> +
>  struct vrend_vertex_element {
>     struct pipe_vertex_element base;
>     GLenum type;
> @@ -381,6 +391,9 @@ struct vrend_sub_context {
>
>     uint32_t cond_render_q_id;
>     GLenum cond_render_gl_mode;
> +
> +   struct vrend_ssbo ssbo[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
> +   uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
>  };
>
>  struct vrend_context {
> @@ -951,6 +964,29 @@ static void bind_ubo_locs(struct vrend_linked_shader_program *sprog,
>        sprog->ubo_locs[id] = NULL;
>  }
>
> +static void bind_ssbo_locs(struct vrend_linked_shader_program *sprog,
> +                          int id)
> +{
> +   int i;
> +   char name[32];
> +   if (sprog->ss[id]->sel->sinfo.ssbo_used_mask) {
> +      const char *prefix = pipe_shader_to_prefix(id);
> +      uint32_t mask = sprog->ss[id]->sel->sinfo.ssbo_used_mask;
> +      sprog->ssbo_locs[id] = calloc(util_last_bit(mask), sizeof(uint32_t));
> +
> +      while (mask) {
> +        i = u_bit_scan(&mask);
> +        if (0)//sprog->ss[id]->sel->sinfo.ssbo_indirect)
> +           snprintf(name, 32, "%sssbo[%d]", prefix, i);

nit: if (0) case looks useless

Other than that, this series is:

Reviewed-by: Gurchetan Singh <gurchetansingh at chromium.org>

> +        else
> +           snprintf(name, 32, "%sssbo%d", prefix, i);
> +        sprog->ssbo_locs[id][i] = glGetProgramResourceIndex(sprog->id, GL_SHADER_STORAGE_BLOCK, name);
> +      }
> +   } else
> +      sprog->ssbo_locs[id] = NULL;
> +   sprog->ssbo_used_mask[id] = sprog->ss[id]->sel->sinfo.ssbo_used_mask;
> +}
> +
>  static struct vrend_linked_shader_program *add_shader_program(struct vrend_context *ctx,
>                                                                struct vrend_shader *vs,
>                                                                struct vrend_shader *fs,
> @@ -1096,6 +1132,7 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
>        bind_sampler_locs(sprog, id);
>        bind_const_locs(sprog, id);
>        bind_ubo_locs(sprog, id);
> +      bind_ssbo_locs(sprog, id);
>     }
>
>     if (!vrend_state.have_gles31_vertex_attrib_binding) {
> @@ -2255,6 +2292,32 @@ void vrend_set_num_sampler_views(struct vrend_context *ctx,
>     ctx->sub->views[shader_type].num_views = last_slot;
>  }
>
> +void vrend_set_single_ssbo(struct vrend_context *ctx,
> +                          uint32_t shader_type,
> +                          int index,
> +                          uint32_t offset, uint32_t length,
> +                          uint32_t handle)
> +{
> +   struct vrend_ssbo *ssbo = &ctx->sub->ssbo[shader_type][index];
> +   struct vrend_resource *res;
> +   if (handle) {
> +      res = vrend_renderer_ctx_res_lookup(ctx, handle);
> +      if (!res) {
> +        report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, handle);
> +        return;
> +      }
> +      ssbo->buffer_offset = offset;
> +      ssbo->buffer_size = length;
> +      ssbo->res = res;
> +      ctx->sub->ssbo_used_mask[shader_type] |= (1 << index);
> +   } else {
> +      ssbo->res = 0;
> +      ssbo->buffer_offset = 0;
> +      ssbo->buffer_size = 0;
> +      ctx->sub->ssbo_used_mask[shader_type] &= ~(1 << index);
> +   }
> +}
> +
>  static void vrend_destroy_shader_object(void *obj_ptr)
>  {
>     struct vrend_shader_selector *state = obj_ptr;
> @@ -3148,6 +3211,31 @@ static void vrend_draw_bind_const_shader(struct vrend_context *ctx,
>     }
>  }
>
> +static void vrend_draw_bind_ssbo_shader(struct vrend_context *ctx, int shader_type)
> +{
> +   uint32_t mask;
> +   struct vrend_ssbo *ssbo;
> +   struct vrend_resource *res;
> +   int i;
> +
> +   if (!ctx->sub->prog->ssbo_locs[shader_type])
> +      return;
> +
> +   if (!ctx->sub->ssbo_used_mask[shader_type])
> +      return;
> +
> +   mask = ctx->sub->ssbo_used_mask[shader_type];
> +   while (mask) {
> +      i = u_bit_scan(&mask);
> +
> +      ssbo = &ctx->sub->ssbo[shader_type][i];
> +      res = (struct vrend_resource *)ssbo->res;
> +      glBindBufferRange(GL_SHADER_STORAGE_BUFFER, i, res->id,
> +                        ssbo->buffer_offset, ssbo->buffer_size);
> +      glShaderStorageBlockBinding(ctx->sub->prog->id, ctx->sub->prog->ssbo_locs[shader_type][i], i);
> +   }
> +}
> +
>  static void vrend_draw_bind_objects(struct vrend_context *ctx, bool new_program)
>  {
>     int ubo_id = 0, sampler_id = 0;
> @@ -3155,6 +3243,7 @@ static void vrend_draw_bind_objects(struct vrend_context *ctx, bool new_program)
>        vrend_draw_bind_ubo_shader(ctx, shader_type, &ubo_id);
>        vrend_draw_bind_const_shader(ctx, shader_type, new_program);
>        vrend_draw_bind_samplers_shader(ctx, shader_type, &sampler_id);
> +      vrend_draw_bind_ssbo_shader(ctx, shader_type);
>     }
>
>     if (vrend_state.use_core_profile && ctx->sub->prog->fs_stipple_loc != -1) {
> @@ -4553,6 +4642,9 @@ int vrend_renderer_init(struct vrend_if_cbs *cbs, uint32_t flags)
>     if (gl_ver >= 43 || epoxy_has_gl_extension("GL_ARB_texture_view"))
>        vrend_state.have_texture_view = true;
>
> +   if (gl_ver >= 43 || epoxy_has_gl_extension("GL_ARB_shader_storage_buffer_object"))
> +      vrend_state.have_ssbo = true;
> +
>     if (gl_ver >= 46 || epoxy_has_gl_extension("GL_ARB_polygon_offset_clamp"))
>        vrend_state.have_polygon_offset_clamp = true;
>
> @@ -4853,7 +4945,8 @@ static int check_resource_valid(struct vrend_renderer_resource_create_args *args
>         args->bind == VREND_RES_BIND_INDEX_BUFFER ||
>         args->bind == VREND_RES_BIND_STREAM_OUTPUT ||
>         args->bind == VREND_RES_BIND_VERTEX_BUFFER ||
> -       args->bind == VREND_RES_BIND_CONSTANT_BUFFER) {
> +       args->bind == VREND_RES_BIND_CONSTANT_BUFFER ||
> +       args->bind == VREND_RES_BIND_SHADER_BUFFER) {
>        if (args->target != PIPE_BUFFER)
>           return -1;
>        if (args->height != 1 || args->depth != 1)
> @@ -5094,7 +5187,7 @@ int vrend_renderer_resource_create(struct vrend_renderer_resource_create_args *a
>     } else if (args->target == PIPE_BUFFER && args->bind == 0) {
>        gr->target = GL_ARRAY_BUFFER_ARB;
>        vrend_create_buffer(gr, args->width);
> -   } else if (args->target == PIPE_BUFFER && (args->bind & VREND_RES_BIND_SAMPLER_VIEW)) {
> +   } else if (args->target == PIPE_BUFFER && (args->bind == 0 || args->bind == VREND_RES_BIND_SHADER_BUFFER)) {
>        /*
>         * On Desktop we use GL_ARB_texture_buffer_object on GLES we use
>         * GL_EXT_texture_buffer (it is in the ANDRIOD extension pack).
> @@ -7579,7 +7672,15 @@ void vrend_renderer_fill_caps(uint32_t set, uint32_t version,
>
>     if (gl_ver >= 43) {
>        glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.texture_buffer_offset_alignment);
> +   }
> +
> +   if (gl_ver >= 43 || epoxy_has_gl_extension("GL_ARB_shader_storage_buffer_object")) {
>        glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.shader_buffer_offset_alignment);
> +
> +      glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &max);
> +      caps->v2.shader_storage_buffer_object_maximums = (max << 16);
> +      glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &max);
> +      caps->v2.shader_storage_buffer_object_maximums |= max & 0xffff;
>     }
>
>     caps->v1.max_samples = vrend_renderer_query_multisample_caps(max, &caps->v2);
> diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
> index b2c2fd8..a3160bb 100644
> --- a/src/vrend_renderer.h
> +++ b/src/vrend_renderer.h
> @@ -154,6 +154,7 @@ void vrend_renderer_context_destroy(uint32_t handle);
>  #define VREND_RES_BIND_INDEX_BUFFER  (1 << 5)
>  #define VREND_RES_BIND_CONSTANT_BUFFER (1 << 6)
>  #define VREND_RES_BIND_STREAM_OUTPUT (1 << 11)
> +#define VREND_RES_BIND_SHADER_BUFFER (1 << 14)
>  #define VREND_RES_BIND_CURSOR        (1 << 16)
>  #define VREND_RES_BIND_CUSTOM        (1 << 17)
>
> @@ -246,6 +247,11 @@ void vrend_set_index_buffer(struct vrend_context *ctx,
>                              uint32_t res_handle,
>                              uint32_t index_size,
>                              uint32_t offset);
> +void vrend_set_single_ssbo(struct vrend_context *ctx,
> +                          uint32_t shader_type,
> +                          int index,
> +                          uint32_t offset, uint32_t length,
> +                          uint32_t handle);
>
>  #define VREND_TRANSFER_WRITE 1
>  #define VREND_TRANSFER_READ 2
> --
> 2.17.1
>
> _______________________________________________
> 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