[virglrenderer-devel] [PATCH 4/4] renderer: add shader_storage_buffer_object support. (v2)
Dave Airlie
airlied at gmail.com
Wed Jul 18 02:26:20 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).
---
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..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..00a4e2a 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..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.14.3
More information about the virglrenderer-devel
mailing list