[virglrenderer-devel] [PATCH 6/6] renderer: add shader_storage_buffer_object support. (v2)

Dave Airlie airlied at gmail.com
Wed Jul 18 17:58:10 UTC 2018


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)

v2: fix buffer creation paths, limit maximums, handle indirect
(don't pass -1 into gl funcs when we don't need to).

Co-authors: Gurchetan Singh <gurchetansingh at chromium.org>
---
 src/virgl_hw.h       |   1 +
 src/virgl_protocol.h |  10 +++++
 src/vrend_decode.c   |  33 ++++++++++++++++
 src/vrend_renderer.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/vrend_renderer.h |   6 +++
 5 files changed, 155 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..11fe149 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..dc0829b 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,26 @@ 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);
+         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 +1129,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 +2289,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 +3208,32 @@ 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);
+      if (ctx->sub->prog->ssbo_locs[shader_type][i] != -1)
+         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 +3241,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 +4640,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 +4943,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)
@@ -5091,7 +5182,7 @@ int vrend_renderer_resource_create(struct vrend_renderer_resource_create_args *a
    } else if (args->bind == VREND_RES_BIND_CONSTANT_BUFFER) {
       gr->target = GL_UNIFORM_BUFFER;
       vrend_create_buffer(gr, args->width);
-   } else if (args->target == PIPE_BUFFER && args->bind == 0) {
+   } else if (args->target == PIPE_BUFFER && (args->bind == 0 || args->bind == VREND_RES_BIND_SHADER_BUFFER)) {
       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)) {
@@ -7579,7 +7670,19 @@ 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);
+      if (max > PIPE_MAX_SHADER_BUFFERS)
+         max = PIPE_MAX_SHADER_BUFFERS;
+      caps->v2.shader_storage_buffer_object_maximums = (max << 16);
+      glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &max);
+      if (max > PIPE_MAX_SHADER_BUFFERS)
+         max = PIPE_MAX_SHADER_BUFFERS;
+      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..c51ea68 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.14.3



More information about the virglrenderer-devel mailing list