From df46b3d196eb4f4f55efa6e1da4398c0e1dbc923 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 26 Jun 2019 15:57:30 +1000 Subject: [PATCH] llvmpipe: add support for shader buffer binding. This add support for setting shader buffers and passing them to draw or binding them to the fragment shader jit. Reviewed-by: Roland Scheidegger --- src/gallium/drivers/llvmpipe/lp_context.h | 2 + src/gallium/drivers/llvmpipe/lp_setup.c | 49 +++++++++++++++++++ src/gallium/drivers/llvmpipe/lp_setup.h | 5 ++ .../drivers/llvmpipe/lp_setup_context.h | 7 ++- src/gallium/drivers/llvmpipe/lp_state.h | 1 + .../drivers/llvmpipe/lp_state_derived.c | 5 ++ src/gallium/drivers/llvmpipe/lp_state_fs.c | 30 ++++++++++++ src/gallium/drivers/llvmpipe/lp_texture.c | 3 +- 8 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h index 7a2f2539842..8127b16261b 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.h +++ b/src/gallium/drivers/llvmpipe/lp_context.h @@ -82,6 +82,8 @@ struct llvmpipe_context { struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS]; struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; + struct pipe_shader_buffer ssbos[PIPE_SHADER_TYPES][LP_MAX_TGSI_SHADER_BUFFERS]; + unsigned num_samplers[PIPE_SHADER_TYPES]; unsigned num_sampler_views[PIPE_SHADER_TYPES]; diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index e72e119c8a1..a3c9960bcaf 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -664,6 +664,26 @@ lp_setup_set_fs_constants(struct lp_setup_context *setup, setup->dirty |= LP_SETUP_NEW_CONSTANTS; } +void +lp_setup_set_fs_ssbos(struct lp_setup_context *setup, + unsigned num, + struct pipe_shader_buffer *buffers) +{ + unsigned i; + + LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffers); + + assert(num <= ARRAY_SIZE(setup->ssbos)); + + for (i = 0; i < num; ++i) { + util_copy_shader_buffer(&setup->ssbos[i].current, &buffers[i]); + } + for (; i < ARRAY_SIZE(setup->ssbos); i++) { + util_copy_shader_buffer(&setup->ssbos[i].current, NULL); + } + setup->dirty |= LP_SETUP_NEW_SSBOS; +} + void lp_setup_set_alpha_ref_value( struct lp_setup_context *setup, @@ -992,6 +1012,11 @@ lp_setup_is_resource_referenced( const struct lp_setup_context *setup, } } + for (i = 0; i < ARRAY_SIZE(setup->ssbos); i++) { + if (setup->ssbos[i].current.buffer == texture) + return LP_REFERENCED_FOR_READ | LP_REFERENCED_FOR_WRITE; + } + return LP_UNREFERENCED; } @@ -1135,7 +1160,27 @@ try_update_scene_state( struct lp_setup_context *setup ) } } + if (setup->dirty & LP_SETUP_NEW_SSBOS) { + for (i = 0; i < ARRAY_SIZE(setup->ssbos); ++i) { + struct pipe_resource *buffer = setup->ssbos[i].current.buffer; + const ubyte *current_data = NULL; + + if (!buffer) + continue; + /* resource buffer */ + current_data = (ubyte *) llvmpipe_resource_data(buffer); + if (current_data) { + current_data += setup->ssbos[i].current.buffer_offset; + setup->fs.current.jit_context.ssbos[i] = (const uint32_t *)current_data; + setup->fs.current.jit_context.num_ssbos[i] = setup->ssbos[i].current.buffer_size; + } else { + setup->fs.current.jit_context.ssbos[i] = NULL; + setup->fs.current.jit_context.num_ssbos[i] = 0; + } + setup->dirty |= LP_SETUP_NEW_FS; + } + } if (setup->dirty & LP_SETUP_NEW_FS) { if (!setup->fs.stored || memcmp(setup->fs.stored, @@ -1287,6 +1332,10 @@ lp_setup_destroy( struct lp_setup_context *setup ) pipe_resource_reference(&setup->constants[i].current.buffer, NULL); } + for (i = 0; i < ARRAY_SIZE(setup->ssbos); i++) { + pipe_resource_reference(&setup->ssbos[i].current.buffer, NULL); + } + /* free the scenes in the 'empty' queue */ for (i = 0; i < ARRAY_SIZE(setup->scenes); i++) { struct lp_scene *scene = setup->scenes[i]; diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h index a42df2dc9e0..7ee50718b66 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.h +++ b/src/gallium/drivers/llvmpipe/lp_setup.h @@ -104,6 +104,11 @@ lp_setup_set_fs_constants(struct lp_setup_context *setup, unsigned num, struct pipe_constant_buffer *buffers); +void +lp_setup_set_fs_ssbos(struct lp_setup_context *setup, + unsigned num, + struct pipe_shader_buffer *buffers); + void lp_setup_set_alpha_ref_value( struct lp_setup_context *setup, float alpha_ref_value ); diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h index 4b55fd922c8..9c8dde5b6ae 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h @@ -49,7 +49,7 @@ #define LP_SETUP_NEW_BLEND_COLOR 0x04 #define LP_SETUP_NEW_SCISSOR 0x08 #define LP_SETUP_NEW_VIEWPORTS 0x10 - +#define LP_SETUP_NEW_SSBOS 0x20 struct lp_setup_variant; @@ -143,6 +143,11 @@ struct lp_setup_context const void *stored_data; } constants[LP_MAX_TGSI_CONST_BUFFERS]; + /** fragment shader buffers */ + struct { + struct pipe_shader_buffer current; + } ssbos[LP_MAX_TGSI_SHADER_BUFFERS]; + struct { struct pipe_blend_color current; uint8_t *stored; diff --git a/src/gallium/drivers/llvmpipe/lp_state.h b/src/gallium/drivers/llvmpipe/lp_state.h index f15d70df7d0..1c3191b983f 100644 --- a/src/gallium/drivers/llvmpipe/lp_state.h +++ b/src/gallium/drivers/llvmpipe/lp_state.h @@ -56,6 +56,7 @@ #define LP_NEW_GS 0x10000 #define LP_NEW_SO 0x20000 #define LP_NEW_SO_BUFFERS 0x40000 +#define LP_NEW_FS_SSBOS 0x80000 diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c index 4bcca907244..f93bc434c64 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_derived.c +++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c @@ -255,6 +255,11 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe ) ARRAY_SIZE(llvmpipe->constants[PIPE_SHADER_FRAGMENT]), llvmpipe->constants[PIPE_SHADER_FRAGMENT]); + if (llvmpipe->dirty & LP_NEW_FS_SSBOS) + lp_setup_set_fs_ssbos(llvmpipe->setup, + ARRAY_SIZE(llvmpipe->ssbos[PIPE_SHADER_FRAGMENT]), + llvmpipe->ssbos[PIPE_SHADER_FRAGMENT]); + if (llvmpipe->dirty & (LP_NEW_SAMPLER_VIEW)) lp_setup_set_fragment_sampler_views(llvmpipe->setup, llvmpipe->num_sampler_views[PIPE_SHADER_FRAGMENT], diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c index cf54d034fa5..6934c12c243 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c @@ -3141,6 +3141,34 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe, } } +static void +llvmpipe_set_shader_buffers(struct pipe_context *pipe, + enum pipe_shader_type shader, unsigned start_slot, + unsigned count, const struct pipe_shader_buffer *buffers, + unsigned writable_bitmask) +{ + struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); + unsigned i, idx; + for (i = start_slot, idx = 0; i < start_slot + count; i++, idx++) { + const struct pipe_shader_buffer *buffer = buffers ? &buffers[idx] : NULL; + + util_copy_shader_buffer(&llvmpipe->ssbos[shader][i], buffer); + + if (shader == PIPE_SHADER_VERTEX || + shader == PIPE_SHADER_GEOMETRY) { + const unsigned size = buffer ? buffer->buffer_size : 0; + const ubyte *data = NULL; + if (buffer && buffer->buffer) + data = (ubyte *) llvmpipe_resource_data(buffer->buffer); + if (data) + data += buffer->buffer_offset; + draw_set_mapped_shader_buffer(llvmpipe->draw, shader, + i, data, size); + } else if (shader == PIPE_SHADER_FRAGMENT) { + llvmpipe->dirty |= LP_NEW_FS_SSBOS; + } + } +} /** * Return the blend factor equivalent to a destination alpha of one. @@ -3484,6 +3512,8 @@ llvmpipe_init_fs_funcs(struct llvmpipe_context *llvmpipe) llvmpipe->pipe.delete_fs_state = llvmpipe_delete_fs_state; llvmpipe->pipe.set_constant_buffer = llvmpipe_set_constant_buffer; + + llvmpipe->pipe.set_shader_buffers = llvmpipe_set_shader_buffers; } diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c index 89852cc95c3..4dc7eb39f8f 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture.c +++ b/src/gallium/drivers/llvmpipe/lp_texture.c @@ -646,7 +646,8 @@ llvmpipe_is_resource_referenced( struct pipe_context *pipe, struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET | - PIPE_BIND_SAMPLER_VIEW))) + PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_SHADER_BUFFER))) return LP_UNREFERENCED; return lp_setup_is_resource_referenced(llvmpipe->setup, presource); -- 2.30.2