[Mesa-dev] [PATCH 7/8] softpipe: add image support to softpipe
Brian Paul
brianp at vmware.com
Tue Mar 22 15:37:49 UTC 2016
A bunch of nit-picks below.
Overall, I'd like to see more comments on the new functions to explain
what's going on.
On 03/21/2016 04:02 PM, Dave Airlie wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> This adds support for ARB_shader_image_load_store to softpipe.
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
> src/gallium/auxiliary/tgsi/tgsi_exec.h | 4 +-
> src/gallium/drivers/softpipe/Makefile.sources | 2 +
> src/gallium/drivers/softpipe/sp_context.c | 20 +-
> src/gallium/drivers/softpipe/sp_context.h | 2 +
> src/gallium/drivers/softpipe/sp_flush.c | 26 +
> src/gallium/drivers/softpipe/sp_flush.h | 2 +
> src/gallium/drivers/softpipe/sp_fs_exec.c | 6 +-
> src/gallium/drivers/softpipe/sp_image.c | 643 ++++++++++++++++++++++++
> src/gallium/drivers/softpipe/sp_image.h | 37 ++
> src/gallium/drivers/softpipe/sp_state.h | 7 +-
> src/gallium/drivers/softpipe/sp_state_derived.c | 3 +-
> src/gallium/drivers/softpipe/sp_state_image.c | 57 +++
> src/gallium/drivers/softpipe/sp_texture.c | 8 +-
> src/gallium/drivers/softpipe/sp_texture.h | 4 +-
> 14 files changed, 809 insertions(+), 12 deletions(-)
> create mode 100644 src/gallium/drivers/softpipe/sp_image.c
> create mode 100644 src/gallium/drivers/softpipe/sp_image.h
> create mode 100644 src/gallium/drivers/softpipe/sp_state_image.c
>
> diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.h b/src/gallium/auxiliary/tgsi/tgsi_exec.h
> index 9ff8a72..99051ed 100644
> --- a/src/gallium/auxiliary/tgsi/tgsi_exec.h
> +++ b/src/gallium/auxiliary/tgsi/tgsi_exec.h
> @@ -518,8 +518,10 @@ tgsi_exec_get_shader_param(enum pipe_shader_cap param)
> case PIPE_SHADER_CAP_TGSI_DROUND_SUPPORTED:
> case PIPE_SHADER_CAP_TGSI_FMA_SUPPORTED:
> case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS:
> - case PIPE_SHADER_CAP_MAX_SHADER_IMAGES:
> return 0;
> + case PIPE_SHADER_CAP_MAX_SHADER_IMAGES:
> + return PIPE_MAX_SHADER_IMAGES;
> +
> case PIPE_SHADER_CAP_MAX_UNROLL_ITERATIONS_HINT:
> return 32;
> }
> diff --git a/src/gallium/drivers/softpipe/Makefile.sources b/src/gallium/drivers/softpipe/Makefile.sources
> index 2af3d6a..efe8846 100644
> --- a/src/gallium/drivers/softpipe/Makefile.sources
> +++ b/src/gallium/drivers/softpipe/Makefile.sources
> @@ -10,6 +10,7 @@ C_SOURCES := \
> sp_flush.h \
> sp_fs_exec.c \
> sp_fs.h \
> + sp_image.c \
> sp_limits.h \
> sp_prim_vbuf.c \
> sp_prim_vbuf.h \
> @@ -31,6 +32,7 @@ C_SOURCES := \
> sp_state_blend.c \
> sp_state_clip.c \
> sp_state_derived.c \
> + sp_state_image.c \
> sp_state.h \
> sp_state_rasterizer.c \
> sp_state_sampler.c \
> diff --git a/src/gallium/drivers/softpipe/sp_context.c b/src/gallium/drivers/softpipe/sp_context.c
> index d2a3220..30b0276 100644
> --- a/src/gallium/drivers/softpipe/sp_context.c
> +++ b/src/gallium/drivers/softpipe/sp_context.c
> @@ -50,7 +50,7 @@
> #include "sp_query.h"
> #include "sp_screen.h"
> #include "sp_tex_sample.h"
> -
> +#include "sp_image.h"
>
> static void
> softpipe_destroy( struct pipe_context *pipe )
> @@ -199,6 +199,10 @@ softpipe_create_context(struct pipe_screen *screen,
> softpipe->tgsi.sampler[i] = sp_create_tgsi_sampler();
> }
>
> + for (i = 0; i < PIPE_SHADER_TYPES; i++) {
> + softpipe->tgsi.image[i] = sp_create_tgsi_image();
> + }
> +
> softpipe->dump_fs = debug_get_bool_option( "SOFTPIPE_DUMP_FS", FALSE );
> softpipe->dump_gs = debug_get_bool_option( "SOFTPIPE_DUMP_GS", FALSE );
>
> @@ -216,6 +220,7 @@ softpipe_create_context(struct pipe_screen *screen,
> softpipe_init_streamout_funcs(&softpipe->pipe);
> softpipe_init_texture_funcs( &softpipe->pipe );
> softpipe_init_vertex_funcs(&softpipe->pipe);
> + softpipe_init_image_funcs(&softpipe->pipe);
>
> softpipe->pipe.set_framebuffer_state = softpipe_set_framebuffer_state;
>
> @@ -223,7 +228,8 @@ softpipe_create_context(struct pipe_screen *screen,
>
> softpipe->pipe.clear = softpipe_clear;
> softpipe->pipe.flush = softpipe_flush_wrapped;
> -
> + softpipe->pipe.texture_barrier = softpipe_texture_barrier;
> + softpipe->pipe.memory_barrier = softpipe_memory_barrier;
> softpipe->pipe.render_condition = softpipe_render_condition;
>
> /*
> @@ -272,6 +278,16 @@ softpipe_create_context(struct pipe_screen *screen,
> (struct tgsi_sampler *)
> softpipe->tgsi.sampler[PIPE_SHADER_GEOMETRY]);
>
> + draw_image(softpipe->draw,
> + PIPE_SHADER_VERTEX,
> + (struct tgsi_image *)
> + softpipe->tgsi.image[PIPE_SHADER_VERTEX]);
> +
> + draw_image(softpipe->draw,
> + PIPE_SHADER_GEOMETRY,
> + (struct tgsi_image *)
> + softpipe->tgsi.image[PIPE_SHADER_GEOMETRY]);
> +
> if (debug_get_bool_option( "SOFTPIPE_NO_RAST", FALSE ))
> softpipe->no_rast = TRUE;
>
> diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h
> index d18bbe6..20a1235 100644
> --- a/src/gallium/drivers/softpipe/sp_context.h
> +++ b/src/gallium/drivers/softpipe/sp_context.h
> @@ -83,6 +83,7 @@ struct softpipe_context {
> struct pipe_scissor_state scissors[PIPE_MAX_VIEWPORTS];
> struct pipe_sampler_view *sampler_views[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_SAMPLER_VIEWS];
>
> + struct pipe_image_view images[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES];
> struct pipe_viewport_state viewports[PIPE_MAX_VIEWPORTS];
> struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
> struct pipe_index_buffer index_buffer;
> @@ -172,6 +173,7 @@ struct softpipe_context {
> /** TGSI exec things */
> struct {
> struct sp_tgsi_sampler *sampler[PIPE_SHADER_TYPES];
> + struct sp_tgsi_image *image[PIPE_SHADER_TYPES];
> } tgsi;
>
> struct tgsi_exec_machine *fs_machine;
> diff --git a/src/gallium/drivers/softpipe/sp_flush.c b/src/gallium/drivers/softpipe/sp_flush.c
> index 5a29e26..a66f05a 100644
> --- a/src/gallium/drivers/softpipe/sp_flush.c
> +++ b/src/gallium/drivers/softpipe/sp_flush.c
> @@ -168,3 +168,29 @@ softpipe_flush_resource(struct pipe_context *pipe,
>
> return TRUE;
> }
> +
> +void softpipe_texture_barrier(struct pipe_context *pipe)
> +{
> + struct softpipe_context *softpipe = softpipe_context(pipe);
> + uint i;
> + uint sh;
You could delare i and sh one one line.
> + for (sh = 0; sh < Elements(softpipe->tex_cache); sh++) {
> + for (i = 0; i < softpipe->num_sampler_views[sh]; i++) {
> + sp_flush_tex_tile_cache(softpipe->tex_cache[sh][i]);
> + }
> + }
The indention in that loop looks off.
> +
> + for (i = 0; i < softpipe->framebuffer.nr_cbufs; i++)
> + if (softpipe->cbuf_cache[i])
> + sp_flush_tile_cache(softpipe->cbuf_cache[i]);
> +
> + if (softpipe->zsbuf_cache)
> + sp_flush_tile_cache(softpipe->zsbuf_cache);
> +
> + softpipe->dirty_render_cache = FALSE;
> +}
> +
> +void softpipe_memory_barrier(struct pipe_context *pipe, unsigned flags)
> +{
> + softpipe_texture_barrier(pipe);
> +}
> diff --git a/src/gallium/drivers/softpipe/sp_flush.h b/src/gallium/drivers/softpipe/sp_flush.h
> index ab5f77b..0674b4a 100644
> --- a/src/gallium/drivers/softpipe/sp_flush.h
> +++ b/src/gallium/drivers/softpipe/sp_flush.h
> @@ -55,4 +55,6 @@ softpipe_flush_resource(struct pipe_context *pipe,
> boolean cpu_access,
> boolean do_not_block);
>
> +void softpipe_texture_barrier(struct pipe_context *pipe);
> +void softpipe_memory_barrier(struct pipe_context *pipe, unsigned flags);
> #endif
> diff --git a/src/gallium/drivers/softpipe/sp_fs_exec.c b/src/gallium/drivers/softpipe/sp_fs_exec.c
> index 2c5bf7e..bfd9a4b 100644
> --- a/src/gallium/drivers/softpipe/sp_fs_exec.c
> +++ b/src/gallium/drivers/softpipe/sp_fs_exec.c
> @@ -62,14 +62,15 @@ sp_exec_fragment_shader(const struct sp_fragment_shader_variant *var)
> static void
> exec_prepare( const struct sp_fragment_shader_variant *var,
> struct tgsi_exec_machine *machine,
> - struct tgsi_sampler *sampler )
> + struct tgsi_sampler *sampler,
> + struct tgsi_image *image )
> {
> /*
> * Bind tokens/shader to the interpreter's machine state.
> */
> tgsi_exec_machine_bind_shader(machine,
> var->tokens,
> - sampler, NULL);
> + sampler, image);
> }
>
>
> @@ -127,6 +128,7 @@ exec_run( const struct sp_fragment_shader_variant *var,
> /* convert 0 to 1.0 and 1 to -1.0 */
> machine->Face = (float) (quad->input.facing * -2 + 1);
>
> + machine->NonHelperMask = quad->inout.mask;
> quad->inout.mask &= tgsi_exec_machine_run( machine );
> if (quad->inout.mask == 0)
> return FALSE;
> diff --git a/src/gallium/drivers/softpipe/sp_image.c b/src/gallium/drivers/softpipe/sp_image.c
> new file mode 100644
> index 0000000..e4d6631
> --- /dev/null
> +++ b/src/gallium/drivers/softpipe/sp_image.c
> @@ -0,0 +1,643 @@
> +/*
> + * Copyright 2016 Red Hat.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include "sp_context.h"
> +#include "sp_image.h"
> +#include "sp_texture.h"
> +
> +#include "util/u_format.h"
> +
> +static uint32_t get_image_offset(struct softpipe_resource *spr,
> + struct pipe_image_view *iview,
> + int format,
> + unsigned rv)
The formatting style in softpipe (and most of Mesa/gallium) is
static uint32_t
get_image_offset(struct softpipe_resource *spr,
...)
And is the format parameter's type really enum pipe_format?
Can you document what 'rv' is, or use a longer name?
> +{
> + uint32_t offset;
> + if (spr->base.target != PIPE_BUFFER) {
> + int base_layer = 0;
> +
> + if (spr->base.target == PIPE_TEXTURE_1D_ARRAY ||
> + spr->base.target == PIPE_TEXTURE_2D_ARRAY ||
> + spr->base.target == PIPE_TEXTURE_CUBE_ARRAY ||
> + spr->base.target == PIPE_TEXTURE_CUBE ||
> + spr->base.target == PIPE_TEXTURE_3D)
> + base_layer = rv + iview->u.tex.first_layer;
> + offset = softpipe_get_tex_image_offset(spr, iview->u.tex.level, base_layer);
> + } else
> + offset = iview->u.buf.first_element * util_format_get_blocksize(format);
> + return offset;
> +}
> +
> +static inline bool has_level_or_depth(int tgsi_tex_instr)
> +{
> + return (tgsi_tex_instr == TGSI_TEXTURE_3D ||
> + tgsi_tex_instr == TGSI_TEXTURE_CUBE ||
> + tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ||
> + tgsi_tex_instr == TGSI_TEXTURE_2D_ARRAY ||
> + tgsi_tex_instr == TGSI_TEXTURE_CUBE_ARRAY ||
> + tgsi_tex_instr == TGSI_TEXTURE_2D_ARRAY_MSAA);
> +}
> +
> +static inline bool has_1coord(int tgsi_tex_instr)
> +{g
> + return (tgsi_tex_instr == TGSI_TEXTURE_BUFFER || tgsi_tex_instr == TGSI_TEXTURE_1D || tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY);
wrap to 78 columns.
> +}
> +
> +static inline bool bounds_check(int width, int height, int depth,
> + int s, int t, int r)
> +{
> + if (s < 0 || s >= width)
> + return false;
> + if (t < 0 || t >= height)
> + return false;
> + if (r < 0 || r >= depth)
> + return false;
> + return true;
> +}
> +
> +static inline bool has_compat_target(int pipe_target, int tgsi_target)
We usually use unsigned for PIPE_ and TGSI_ enums.
> +{
> + switch (pipe_target) {
> + case PIPE_TEXTURE_1D:
> + if (tgsi_target == TGSI_TEXTURE_1D)
> + return true;
> + break;
> + case PIPE_TEXTURE_2D:
> + if (tgsi_target == TGSI_TEXTURE_2D)
> + return true;
> + break;
> + case PIPE_TEXTURE_RECT:
> + if (tgsi_target == TGSI_TEXTURE_RECT)
> + return true;
> + break;
> + case PIPE_TEXTURE_3D:
> + if (tgsi_target == TGSI_TEXTURE_3D || tgsi_target == TGSI_TEXTURE_2D)
> + return true;
> + break;
> + case PIPE_TEXTURE_CUBE:
> + if (tgsi_target == TGSI_TEXTURE_CUBE || tgsi_target == TGSI_TEXTURE_2D)
> + return true;
> + break;
> + case PIPE_TEXTURE_1D_ARRAY:
> + if (tgsi_target == TGSI_TEXTURE_1D || tgsi_target == TGSI_TEXTURE_1D_ARRAY)
> + return true;
> + break;
> + case PIPE_TEXTURE_2D_ARRAY:
> + if (tgsi_target == TGSI_TEXTURE_2D || tgsi_target == TGSI_TEXTURE_2D_ARRAY)
> + return true;
> + break;
> + case PIPE_TEXTURE_CUBE_ARRAY:
> + if (tgsi_target == TGSI_TEXTURE_CUBE || tgsi_target == TGSI_TEXTURE_CUBE_ARRAY ||
> + tgsi_target == TGSI_TEXTURE_2D)
> + return true;
> + break;
> + case PIPE_BUFFER:
> + return (tgsi_target == TGSI_TEXTURE_BUFFER);
> + }
> + return false;
> +}
> +
> +static void sp_tgsi_load(struct tgsi_image *image,
> + struct tgsi_image_params *params,
Can those parameters be const-qualified?
> + const int s[TGSI_QUAD_SIZE],
> + const int t[TGSI_QUAD_SIZE],
> + const int r[TGSI_QUAD_SIZE],
> + const int sample[TGSI_QUAD_SIZE],
Indentation's off by one space.
> + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
> +{
> + struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
> + struct pipe_image_view *iview;
> + struct softpipe_resource *spr;
> + int level;
> + int width;
> + int height;
> + int depth;
> + unsigned stride;
> + int c, j;
> + char *data_ptr;
> + unsigned offset = 0;
> + bool use_lvl = has_level_or_depth(params->tgsi_tex_instr);
> +
> + if (params->unit > PIPE_MAX_SHADER_IMAGES)
> + goto fail_write_all_zero;
> + iview = &sp_img->sp_iview[params->unit];
> + spr = (struct softpipe_resource *)iview->resource;
> + if (!spr)
> + goto fail_write_all_zero;
> +
> + if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
> + goto fail_write_all_zero;
> +
> + level = spr->base.target == PIPE_BUFFER ? 0 : iview->u.tex.level;
> + width = u_minify(spr->base.width0, level);
> + height = u_minify(spr->base.height0, level);
> + depth = u_minify(spr->base.depth0, level);
> +
> + if (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
> + width = iview->u.buf.last_element - iview->u.buf.first_element + 1;
> + height = 1;
> + depth = 1;
> + if (util_format_get_stride(params->format, width) > util_format_get_stride(spr->base.format, spr->base.width0))
> + return;
> + } else if (util_format_get_blocksize(params->format) > util_format_get_blocksize(spr->base.format))
> + return;
Some comments on that code would be helpful. I have no idea what's
happening there.
> +
> + stride = util_format_get_stride(params->format, width);
> +
> + for (j = 0; j < TGSI_QUAD_SIZE; j++) {
> + int tv = has_1coord(params->tgsi_tex_instr) ? 0 : t[j];
> + int rv = use_lvl ? (params->tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ? t[j] : r[j]) : 0;
> + bool fill_zero = false;
> +
> + if (!(params->execmask & (1 << j)))
> + fill_zero = true;
> +
> + if (!bounds_check(width, height, (spr->base.target == TGSI_TEXTURE_3D) ? depth : spr->base.array_size, s[j], tv, rv))
> + fill_zero = true;
> +
> + if (fill_zero) {
> + int nc = util_format_get_nr_components(params->format);
> + int ival = util_format_is_pure_integer(params->format);
> + for (c = 0; c < 4; c++) {
> + rgba[c][j] = 0;
> + if (c == 3 && nc < 4) {
> + if (ival)
> + ((int32_t *)rgba[c])[j] = 1;
> + else
> + rgba[c][j] = 1.0;
> + }
> + }
> + continue;
> + }
> + offset = get_image_offset(spr, iview, params->format, rv);
> + data_ptr = (char *)spr->data + offset;
> +
> + if (util_format_is_pure_sint(params->format)) {
> + int32_t sdata[4];
> +
> + util_format_read_4i(params->format,
> + sdata, 0,
> + data_ptr, stride,
> + s[j], tv, 1, 1);
> + for (c = 0; c < 4; c++)
> + ((int32_t *)rgba[c])[j] = sdata[c];
> + } else if (util_format_is_pure_uint(params->format)) {
> + uint32_t sdata[4];
> + util_format_read_4ui(params->format,
> + sdata, 0,
> + data_ptr, stride,
> + s[j], tv, 1, 1);
> + for (c = 0; c < 4; c++)
> + ((uint32_t *)rgba[c])[j] = sdata[c];
> + } else {
> + float sdata[4];
> + util_format_read_4f(params->format,
> + sdata, 0,
> + data_ptr, stride,
> + s[j], tv, 1, 1);
> + for (c = 0; c < 4; c++)
> + rgba[c][j] = sdata[c];
> + }
> + }
> + return;
> +fail_write_all_zero:
> + for (j = 0; j < TGSI_QUAD_SIZE; j++) {
> + for (c = 0; c < 4; c++)
> + rgba[c][j] = 0;
> + }
> + return;
> +}
> +
> +static void sp_tgsi_store(struct tgsi_image *image,
> + struct tgsi_image_params *params,
> + const int s[TGSI_QUAD_SIZE],
> + const int t[TGSI_QUAD_SIZE],
> + const int r[TGSI_QUAD_SIZE],
> + const int sample[TGSI_QUAD_SIZE],
> + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
> +{
> + struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
> + struct pipe_image_view *iview;
> + struct softpipe_resource *spr;
> + int level;
> + int width;
> + int height;
> + int depth;
> + unsigned stride;
> + char *data_ptr;
> + int j, c;
> + unsigned offset = 0;
> + bool use_lvl = has_level_or_depth(params->tgsi_tex_instr);
> +
> + if (params->unit > PIPE_MAX_SHADER_IMAGES)
> + return;
> + iview = &sp_img->sp_iview[params->unit];
> + spr = (struct softpipe_resource *)iview->resource;
> + if (!spr)
> + return;
> + if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
> + return;
> +
> + if (params->format == PIPE_FORMAT_NONE)
> + params->format = spr->base.format;
> +
> + level = spr->base.target == PIPE_BUFFER ? 0 : iview->u.tex.level;
> + width = u_minify(spr->base.width0, level);
> + height = u_minify(spr->base.height0, level);
> + depth = u_minify(spr->base.depth0, level);
> +
> + if (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
> + width = iview->u.buf.last_element - iview->u.buf.first_element + 1;
> + height = 1;
> + depth = 1;
> + if (util_format_get_stride(params->format, width) > util_format_get_stride(spr->base.format, spr->base.width0))
> + return;
> + } else if (util_format_get_blocksize(params->format) > util_format_get_blocksize(spr->base.format))
> + return;
> + stride = util_format_get_stride(params->format, width);
> +
> + for (j = 0; j < TGSI_QUAD_SIZE; j++) {
> + int tv = has_1coord(params->tgsi_tex_instr) ? 0 : t[j];
> + int rv = use_lvl ? (params->tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ? t[j] : r[j]) : 0;
> +
> + if (!(params->execmask & (1 << j)))
> + continue;
> +
> + if (!bounds_check(width, height, (spr->base.target == TGSI_TEXTURE_3D) ? depth : spr->base.array_size, s[j], tv, rv))
> + continue;
> +
> + offset = get_image_offset(spr, iview, params->format, rv);
> + data_ptr = (char *)spr->data + offset;
> +
> + if (util_format_is_pure_sint(params->format)) {
> + int32_t sdata[4];
> + for (c = 0; c < 4; c++)
> + sdata[c] = ((int32_t *)rgba[c])[j];
> + util_format_write_4i(params->format, sdata, 0, data_ptr, stride,
> + s[j], tv, 1, 1);
> + } else if (util_format_is_pure_uint(params->format)) {
> + uint32_t sdata[4];
> + for (c = 0; c < 4; c++)
> + sdata[c] = ((uint32_t *)rgba[c])[j];
> + util_format_write_4ui(params->format, sdata, 0, data_ptr, stride,
> + s[j], tv, 1, 1);
> + } else {
> + float sdata[4];
> + for (c = 0; c < 4; c++)
> + sdata[c] = rgba[c][j];
> + util_format_write_4f(params->format, sdata, 0, data_ptr, stride,
> + s[j], tv, 1, 1);
> + }
> + }
> +}
> +
> +static void handle_op_uint(struct pipe_image_view *iview,
> + bool just_read,
> + char *data_ptr,
> + uint qi,
> + unsigned stride,
> + struct tgsi_image_params *params,
> + unsigned opcode,
> + int s,
> + int t,
> + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
> + float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
> +{
> + uint c;
> + int nc = util_format_get_nr_components(params->format);
> + unsigned sdata[4];
> +
> + util_format_read_4ui(params->format,
> + sdata, 0,
> + data_ptr, stride,
> + s, t, 1, 1);
> +
> + if (just_read) {
> + for (c = 0; c < nc; c++) {
> + ((uint32_t *)rgba[c])[qi] = sdata[c];
> + }
> + return;
> + }
> + switch (opcode) {
> + case TGSI_OPCODE_ATOMUADD:
> + for (c = 0; c < nc; c++) {
> + unsigned temp = sdata[c];
> + sdata[c] += ((uint32_t *)rgba[c])[qi];
> + ((uint32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMXCHG:
> + for (c = 0; c < nc; c++) {
> + unsigned temp = sdata[c];
> + sdata[c] = ((uint32_t *)rgba[c])[qi];
> + ((uint32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMCAS:
> + for (c = 0; c < nc; c++) {
> + unsigned dst_x = sdata[c];
> + unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
> + unsigned src_x = ((uint32_t *)rgba2[c])[qi];
> + unsigned temp = sdata[c];
> + sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
> + ((uint32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMAND:
> + for (c = 0; c < nc; c++) {
> + unsigned temp = sdata[c];
> + sdata[c] &= ((uint32_t *)rgba[c])[qi];
> + ((uint32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMOR:
> + for (c = 0; c < nc; c++) {
> + unsigned temp = sdata[c];
> + sdata[c] |= ((uint32_t *)rgba[c])[qi];
> + ((uint32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMXOR:
> + for (c = 0; c < nc; c++) {
> + unsigned temp = sdata[c];
> + sdata[c] ^= ((uint32_t *)rgba[c])[qi];
> + ((uint32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMUMIN:
> + for (c = 0; c < nc; c++) {
> + unsigned dst_x = sdata[c];
> + unsigned src_x = ((uint32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x < src_x) ? dst_x : src_x;
> + ((uint32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + case TGSI_OPCODE_ATOMUMAX:
> + for (c = 0; c < nc; c++) {
> + unsigned dst_x = sdata[c];
> + unsigned src_x = ((uint32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x > src_x) ? dst_x : src_x;
> + ((uint32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + case TGSI_OPCODE_ATOMIMIN:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int src_x = ((uint32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x < src_x) ? dst_x : src_x;
> + ((uint32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + case TGSI_OPCODE_ATOMIMAX:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int src_x = ((uint32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x > src_x) ? dst_x : src_x;
> + ((uint32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + default:
> + fprintf(stderr, "TODO opcode %d\n", opcode);
> + break;
> + }
> + util_format_write_4ui(params->format, sdata, 0, data_ptr, stride,
> + s, t, 1, 1);
> +}
> +
> +static void handle_op_int(struct pipe_image_view *iview,
> + bool just_read,
> + char *data_ptr,
> + uint qi,
> + unsigned stride,
> + struct tgsi_image_params *params,
> + unsigned opcode,
> + int s,
> + int t,
> + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
> + float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
> +{
> + uint c;
> + int nc = util_format_get_nr_components(params->format);
> + int sdata[4];
> + util_format_read_4i(params->format,
> + sdata, 0,
> + data_ptr, stride,
> + s, t, 1, 1);
> +
> + if (just_read) {
> + for (c = 0; c < nc; c++) {
> + ((int32_t *)rgba[c])[qi] = sdata[c];
> + }
> + return;
> + }
> + switch (opcode) {
> + case TGSI_OPCODE_ATOMUADD:
> + for (c = 0; c < nc; c++) {
> + int temp = sdata[c];
> + sdata[c] += ((int32_t *)rgba[c])[qi];
> + ((int32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMXCHG:
> + for (c = 0; c < nc; c++) {
> + int temp = sdata[c];
> + sdata[c] = ((int32_t *)rgba[c])[qi];
> + ((int32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMCAS:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int cmp_x = ((int32_t *)rgba[c])[qi];
> + int src_x = ((int32_t *)rgba2[c])[qi];
> + int temp = sdata[c];
> + sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
> + ((int32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMAND:
> + for (c = 0; c < nc; c++) {
> + int temp = sdata[c];
> + sdata[c] &= ((int32_t *)rgba[c])[qi];
> + ((int32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMOR:
> + for (c = 0; c < nc; c++) {
> + int temp = sdata[c];
> + sdata[c] |= ((int32_t *)rgba[c])[qi];
> + ((int32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMXOR:
> + for (c = 0; c < nc; c++) {
> + int temp = sdata[c];
> + sdata[c] ^= ((int32_t *)rgba[c])[qi];
> + ((int32_t *)rgba[c])[qi] = temp;
> + }
> + break;
> + case TGSI_OPCODE_ATOMUMIN:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int src_x = ((int32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x < src_x) ? dst_x : src_x;
sdata[c] = MIN2(dst_x, src_x);
> + ((int32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + case TGSI_OPCODE_ATOMUMAX:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int src_x = ((int32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x > src_x) ? dst_x : src_x;
MAX2()
> + ((int32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + case TGSI_OPCODE_ATOMIMIN:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int src_x = ((int32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x < src_x) ? dst_x : src_x;
MIN2()
> + ((int32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + case TGSI_OPCODE_ATOMIMAX:
> + for (c = 0; c < nc; c++) {
> + int dst_x = sdata[c];
> + int src_x = ((int32_t *)rgba[c])[qi];
> + sdata[c] = (dst_x > src_x) ? dst_x : src_x;
MAX2()
> + ((int32_t *)rgba[c])[qi] = dst_x;
> + }
> + break;
> + default:
> + fprintf(stderr, "TODO opcode %d\n", opcode);
I'd go with an assertion like
assert(!"Unexpected TGSI opcode in sp_tgsi_op");
> + break;
> + }
> + util_format_write_4i(params->format, sdata, 0, data_ptr, stride,
> + s, t, 1, 1);
> +}
> +
> +static void sp_tgsi_op(struct tgsi_image *image,
> + struct tgsi_image_params *params,
> + unsigned opcode,
> + const int s[TGSI_QUAD_SIZE],
> + const int t[TGSI_QUAD_SIZE],
> + const int r[TGSI_QUAD_SIZE],
> + const int sample[TGSI_QUAD_SIZE],
> + float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
> + float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
> +{
> + struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
> + struct pipe_image_view *iview;
> + struct softpipe_resource *spr;
> + int level, width, height, depth;
> + unsigned stride;
> + int j, c;
> + bool use_lvl = has_level_or_depth(params->tgsi_tex_instr);
> + unsigned offset;
> + char *data_ptr;
> +
> + if (params->unit > PIPE_MAX_SHADER_IMAGES)
> + return;
> + iview = &sp_img->sp_iview[params->unit];
> + spr = (struct softpipe_resource *)iview->resource;
> + if (!spr)
> + goto fail_write_all_zero;
> + if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
> + goto fail_write_all_zero;
> +
> + level = spr->base.target == PIPE_BUFFER ? 0 : iview->u.tex.level;
> + width = u_minify(spr->base.width0, level);
> + height = u_minify(spr->base.height0, level);
> + depth = u_minify(spr->base.depth0, level);
> +
> + if (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
> + width = iview->u.buf.last_element - iview->u.buf.first_element + 1;
> + height = 1;
> + depth = 1;
> +
> + if (util_format_get_stride(params->format, width) > util_format_get_stride(spr->base.format, spr->base.width0))
> + return;
> + } else if (util_format_get_blocksize(params->format) > util_format_get_blocksize(spr->base.format))
> + goto fail_write_all_zero;
> +
> + stride = util_format_get_stride(spr->base.format, width);
> +
> + for (j = 0; j < TGSI_QUAD_SIZE; j++) {
> + int tv = has_1coord(params->tgsi_tex_instr) ? 0 : t[j];
> + int rv = use_lvl ? (params->tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ? t[j] : r[j]) : 0;
> + bool just_read = false;
> +
> + if (!bounds_check(width, height, (spr->base.target == TGSI_TEXTURE_3D) ? depth : spr->base.array_size, s[j], tv, rv)) {
> + int nc = util_format_get_nr_components(params->format);
> + int ival = util_format_is_pure_integer(params->format);
> + int c;
> + for (c = 0; c < 4; c++) {
> + rgba[c][j] = 0;
> + if (c == 3 && nc < 4) {
> + if (ival)
> + ((int32_t *)rgba[c])[j] = 1;
> + else
> + rgba[c][j] = 1.0;
> + }
> + }
> + continue;
> + }
> +
> + /* just readback the value for atomic if execmask isn't set */
> + if (!(params->execmask & (1 << j))) {
> + just_read = true;
> + }
> +
> + offset = get_image_offset(spr, iview, params->format, rv);
> + data_ptr = (char *)spr->data + offset;
> +
> + /* we should see atomic operations on r32 formats */
> + if (util_format_is_pure_uint(params->format))
> + handle_op_uint(iview, just_read, data_ptr, j, stride, params, opcode, s[j], tv, rgba, rgba2);
> + else if (util_format_is_pure_sint(params->format))
> + handle_op_int(iview, just_read, data_ptr, j, stride, params, opcode, s[j], tv, rgba, rgba2);
> + else
> + assert(0);
> + }
> + return;
> + fail_write_all_zero:
> + for (j = 0; j < TGSI_QUAD_SIZE; j++) {
> + for (c = 0; c < 4; c++)
> + rgba[c][j] = 0;
> + }
> + return;
> +}
> +
> +
> +struct sp_tgsi_image *
> +sp_create_tgsi_image(void)
> +{
> + struct sp_tgsi_image *img = CALLOC_STRUCT(sp_tgsi_image);
> + if (!img)
> + return NULL;
> +
> + img->base.load = sp_tgsi_load;
> + img->base.store = sp_tgsi_store;
> + img->base.op = sp_tgsi_op;
> + return img;
> +};
> diff --git a/src/gallium/drivers/softpipe/sp_image.h b/src/gallium/drivers/softpipe/sp_image.h
> new file mode 100644
> index 0000000..3c73f83
> --- /dev/null
> +++ b/src/gallium/drivers/softpipe/sp_image.h
> @@ -0,0 +1,37 @@
> +/*
> + * Copyright 2016 Red Hat.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef SP_IMAGE_H
> +#define SP_IMAGE_H
> +#include "tgsi/tgsi_exec.h"
> +
> +struct sp_tgsi_image
> +{
> + struct tgsi_image base;
> + struct pipe_image_view sp_iview[PIPE_MAX_SHADER_IMAGES];
> +};
> +
> +struct sp_tgsi_image *
> +sp_create_tgsi_image(void);
> +
> +#endif
> diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h
> index 7a2d371..570bc54 100644
> --- a/src/gallium/drivers/softpipe/sp_state.h
> +++ b/src/gallium/drivers/softpipe/sp_state.h
> @@ -56,6 +56,7 @@
>
>
> struct tgsi_sampler;
> +struct tgsi_image;
> struct tgsi_exec_machine;
> struct vertex_info;
>
> @@ -81,7 +82,8 @@ struct sp_fragment_shader_variant
>
> void (*prepare)(const struct sp_fragment_shader_variant *shader,
> struct tgsi_exec_machine *machine,
> - struct tgsi_sampler *sampler);
> + struct tgsi_sampler *sampler,
> + struct tgsi_image *image);
>
> unsigned (*run)(const struct sp_fragment_shader_variant *shader,
> struct tgsi_exec_machine *machine,
> @@ -150,6 +152,9 @@ void
> softpipe_init_vertex_funcs(struct pipe_context *pipe);
>
> void
> +softpipe_init_image_funcs(struct pipe_context *pipe);
> +
> +void
> softpipe_set_framebuffer_state(struct pipe_context *,
> const struct pipe_framebuffer_state *);
>
> diff --git a/src/gallium/drivers/softpipe/sp_state_derived.c b/src/gallium/drivers/softpipe/sp_state_derived.c
> index d4d03f1..65679e7 100644
> --- a/src/gallium/drivers/softpipe/sp_state_derived.c
> +++ b/src/gallium/drivers/softpipe/sp_state_derived.c
> @@ -343,7 +343,8 @@ update_fragment_shader(struct softpipe_context *softpipe, unsigned prim)
> softpipe->fs_variant->prepare(softpipe->fs_variant,
> softpipe->fs_machine,
> (struct tgsi_sampler *) softpipe->
> - tgsi.sampler[PIPE_SHADER_FRAGMENT]);
> + tgsi.sampler[PIPE_SHADER_FRAGMENT],
> + (struct tgsi_image *)softpipe->tgsi.image[PIPE_SHADER_FRAGMENT]);
> }
> else {
> softpipe->fs_variant = NULL;
> diff --git a/src/gallium/drivers/softpipe/sp_state_image.c b/src/gallium/drivers/softpipe/sp_state_image.c
> new file mode 100644
> index 0000000..8909fa2
> --- /dev/null
> +++ b/src/gallium/drivers/softpipe/sp_state_image.c
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright 2016 Red Hat.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include "sp_context.h"
> +#include "sp_state.h"
> +#include "sp_image.h"
> +
> +static void softpipe_set_shader_images(struct pipe_context *pipe,
> + unsigned shader,
> + unsigned start,
> + unsigned num,
> + struct pipe_image_view *images)
> +{
> + struct softpipe_context *softpipe = softpipe_context(pipe);
> + unsigned i;
> + assert(shader < PIPE_SHADER_TYPES);
> + assert(start + num <= Elements(softpipe->sampler_views[shader]));
> +
> + /* set the new images */
> + for (i = 0; i < num; i++) {
> + int idx = start + i;
> +
> + if (images) {
> + pipe_resource_reference(&softpipe->tgsi.image[shader]->sp_iview[idx].resource, images[i].resource);
> + softpipe->tgsi.image[shader]->sp_iview[idx] = images[i];
> + }
> + else {
> + pipe_resource_reference(&softpipe->tgsi.image[shader]->sp_iview[idx].resource, NULL);
> + memset(&softpipe->tgsi.image[shader]->sp_iview[idx], 0, sizeof(struct pipe_image_view));
> + }
> + }
> +}
> +
> +void softpipe_init_image_funcs(struct pipe_context *pipe)
> +{
> + pipe->set_shader_images = softpipe_set_shader_images;
> +}
> diff --git a/src/gallium/drivers/softpipe/sp_texture.c b/src/gallium/drivers/softpipe/sp_texture.c
> index 52ec373..64666fe 100644
> --- a/src/gallium/drivers/softpipe/sp_texture.c
> +++ b/src/gallium/drivers/softpipe/sp_texture.c
> @@ -270,9 +270,9 @@ softpipe_resource_get_handle(struct pipe_screen *screen,
> * Helper function to compute offset (in bytes) for a particular
> * texture level/face/slice from the start of the buffer.
> */
> -static unsigned
> -sp_get_tex_image_offset(const struct softpipe_resource *spr,
> - unsigned level, unsigned layer)
> +unsigned
> +softpipe_get_tex_image_offset(const struct softpipe_resource *spr,
> + unsigned level, unsigned layer)
> {
> unsigned offset = spr->level_offset[level];
>
> @@ -422,7 +422,7 @@ softpipe_transfer_map(struct pipe_context *pipe,
> pt->stride = spr->stride[level];
> pt->layer_stride = spr->img_stride[level];
>
> - spt->offset = sp_get_tex_image_offset(spr, level, box->z);
> + spt->offset = softpipe_get_tex_image_offset(spr, level, box->z);
>
> spt->offset +=
> box->y / util_format_get_blockheight(format) * spt->base.stride +
> diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h
> index fbf741a..450c4b1 100644
> --- a/src/gallium/drivers/softpipe/sp_texture.h
> +++ b/src/gallium/drivers/softpipe/sp_texture.h
> @@ -116,5 +116,7 @@ softpipe_init_screen_texture_funcs(struct pipe_screen *screen);
> extern void
> softpipe_init_texture_funcs(struct pipe_context *pipe);
>
> -
> +unsigned
> +softpipe_get_tex_image_offset(const struct softpipe_resource *spr,
> + unsigned level, unsigned layer);
> #endif /* SP_TEXTURE */
>
More information about the mesa-dev
mailing list