softpipe: add image support to softpipe (v3)
authorDave Airlie <airlied@redhat.com>
Mon, 21 Mar 2016 21:59:35 +0000 (07:59 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 30 Mar 2016 23:14:16 +0000 (09:14 +1000)
This adds support for ARB_shader_image_load_store to softpipe.

v2: add RESQ support (Ilia)
v3: constify, cleanup internals, add some comments (Brian).

Reviewed-by: Brian Paul <brianp@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
14 files changed:
src/gallium/auxiliary/tgsi/tgsi_exec.h
src/gallium/drivers/softpipe/Makefile.sources
src/gallium/drivers/softpipe/sp_context.c
src/gallium/drivers/softpipe/sp_context.h
src/gallium/drivers/softpipe/sp_flush.c
src/gallium/drivers/softpipe/sp_flush.h
src/gallium/drivers/softpipe/sp_fs_exec.c
src/gallium/drivers/softpipe/sp_image.c [new file with mode: 0644]
src/gallium/drivers/softpipe/sp_image.h [new file with mode: 0644]
src/gallium/drivers/softpipe/sp_state.h
src/gallium/drivers/softpipe/sp_state_derived.c
src/gallium/drivers/softpipe/sp_state_image.c [new file with mode: 0644]
src/gallium/drivers/softpipe/sp_texture.c
src/gallium/drivers/softpipe/sp_texture.h

index 2c81d5e827d12faa4a945cdc74a74b3023686934..45fb8d43c88e586d3ed596024a2196b880451102 100644 (file)
@@ -497,8 +497,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;
    }
index 2af3d6af21a05b50b6ebf7a63ed28312d822ccfa..efe88468e3f9d9bae37ef405010d431958daaaa4 100644 (file)
@@ -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 \
index d2a32200e475814871def457da1563ff47508c95..30b0276cfe046484ab4da57d9d4847ca7932e373 100644 (file)
@@ -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;
 
index d18bbe693f3ba38f7b5a92777e68e737fb805c86..20a12353b381f5ae1d3a59163bfdafe6b3e36ce0 100644 (file)
@@ -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;
index 5a29e26517dbaa3fc7805ed6fe12d157894d2b10..59b8ad696ecc18faacad1167576df0503dc4859a 100644 (file)
@@ -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, sh;
+
+   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]);
+      }
+   }
+
+   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);
+}
index ab5f77be2647f7bd656da43a4b06f1ece6311e13..0674b4a7e4891898112e7e6ba689ce3ba6eeddd3 100644 (file)
@@ -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
index 2c5bf7ef5c9979dace1faa76fdef90158a2cb595..bfd9a4b74968dedfe2720b8da1b5918a8f4ee3a2 100644 (file)
@@ -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 (file)
index 0000000..3488fa8
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ * 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"
+
+/*
+ * Get the offset into the base image
+ * first element for a buffer or layer/level for texture.
+ */
+static uint32_t
+get_image_offset(const struct softpipe_resource *spr,
+                 const struct pipe_image_view *iview,
+                 enum pipe_format format, unsigned r_coord)
+{
+   int base_layer = 0;
+
+   if (spr->base.target == PIPE_BUFFER)
+      return iview->u.buf.first_element * util_format_get_blocksize(format);
+
+   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 = r_coord + iview->u.tex.first_layer;
+   return softpipe_get_tex_image_offset(spr, iview->u.tex.level, base_layer);
+}
+
+/*
+ * Does this texture instruction have a layer or depth parameter.
+ */
+static inline bool
+has_layer_or_depth(unsigned 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);
+}
+
+/*
+ * Is this texture instruction a single non-array coordinate.
+ */
+static inline bool
+has_1coord(unsigned tgsi_tex_instr)
+{
+   return (tgsi_tex_instr == TGSI_TEXTURE_BUFFER ||
+           tgsi_tex_instr == TGSI_TEXTURE_1D ||
+           tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY);
+}
+
+/*
+ * check the bounds vs w/h/d
+ */
+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;
+}
+
+/*
+ * Checks if the texture target compatible with the image resource
+ * pipe target.
+ */
+static inline bool
+has_compat_target(unsigned pipe_target, unsigned tgsi_target)
+{
+   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 bool
+get_dimensions(const struct pipe_image_view *iview,
+               const struct softpipe_resource *spr,
+               unsigned tgsi_tex_instr,
+               enum pipe_format pformat,
+               unsigned *width,
+               unsigned *height,
+               unsigned *depth)
+{
+   if (tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
+      *width = iview->u.buf.last_element - iview->u.buf.first_element + 1;
+      *height = 1;
+      *depth = 1;
+      /*
+       * Bounds check the buffer size from the view
+       * and the buffer size from the underlying buffer.
+       */
+      if (util_format_get_stride(pformat, *width) >
+          util_format_get_stride(spr->base.format, spr->base.width0))
+         return false;
+   } else {
+      unsigned level;
+
+      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);
+
+      if (spr->base.target == TGSI_TEXTURE_3D)
+         *depth = u_minify(spr->base.depth0, level);
+      else
+         *depth = spr->base.array_size;
+
+      /* Make sure the resource and view have compatiable formats */
+      if (util_format_get_blocksize(pformat) >
+          util_format_get_blocksize(spr->base.format))
+         return false;
+   }
+   return true;
+}
+
+static void
+fill_coords(const struct tgsi_image_params *params,
+            unsigned index,
+            const int s[TGSI_QUAD_SIZE],
+            const int t[TGSI_QUAD_SIZE],
+            const int r[TGSI_QUAD_SIZE],
+            int *s_coord, int *t_coord, int *r_coord)
+{
+   *s_coord = s[index];
+   *t_coord = has_1coord(params->tgsi_tex_instr) ? 0 : t[index];
+   *r_coord = has_layer_or_depth(params->tgsi_tex_instr) ?
+      (params->tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ? t[index] : r[index]) : 0;
+}
+/*
+ * Implement the image LOAD operation.
+ */
+static void
+sp_tgsi_load(const struct tgsi_image *image,
+             const 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;
+   unsigned width, height, depth;
+   unsigned stride;
+   int c, j;
+   char *data_ptr;
+   unsigned offset = 0;
+
+   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;
+
+   if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
+                       params->format, &width, &height, &depth))
+      return;
+
+   stride = util_format_get_stride(params->format, width);
+
+   for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+      int s_coord, t_coord, r_coord;
+      bool fill_zero = false;
+
+      if (!(params->execmask & (1 << j)))
+         fill_zero = true;
+
+      fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
+      if (!bounds_check(width, height, depth,
+                        s_coord, t_coord, r_coord))
+         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, r_coord);
+      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_coord, t_coord, 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_coord, t_coord, 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_coord, t_coord, 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;
+}
+
+/*
+ * Implement the image STORE operation.
+ */
+static void
+sp_tgsi_store(const struct tgsi_image *image,
+              const 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;
+   unsigned width, height, depth;
+   unsigned stride;
+   char *data_ptr;
+   int j, c;
+   unsigned offset = 0;
+   unsigned pformat = params->format;
+
+   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)
+      pformat = spr->base.format;
+
+   if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
+                       pformat, &width, &height, &depth))
+      return;
+
+   stride = util_format_get_stride(pformat, width);
+
+   for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+      int s_coord, t_coord, r_coord;
+
+      if (!(params->execmask & (1 << j)))
+         continue;
+
+      fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
+      if (!bounds_check(width, height, depth,
+                        s_coord, t_coord, r_coord))
+         continue;
+
+      offset = get_image_offset(spr, iview, pformat, r_coord);
+      data_ptr = (char *)spr->data + offset;
+
+      if (util_format_is_pure_sint(pformat)) {
+         int32_t sdata[4];
+         for (c = 0; c < 4; c++)
+            sdata[c] = ((int32_t *)rgba[c])[j];
+         util_format_write_4i(pformat, sdata, 0, data_ptr, stride,
+                              s_coord, t_coord, 1, 1);
+      } else if (util_format_is_pure_uint(pformat)) {
+         uint32_t sdata[4];
+         for (c = 0; c < 4; c++)
+            sdata[c] = ((uint32_t *)rgba[c])[j];
+         util_format_write_4ui(pformat, sdata, 0, data_ptr, stride,
+                               s_coord, t_coord, 1, 1);
+      } else {
+         float sdata[4];
+         for (c = 0; c < 4; c++)
+            sdata[c] = rgba[c][j];
+         util_format_write_4f(pformat, sdata, 0, data_ptr, stride,
+                              s_coord, t_coord, 1, 1);
+      }
+   }
+}
+
+/*
+ * Implement atomic operations on unsigned integers.
+ */
+static void
+handle_op_uint(const struct pipe_image_view *iview,
+               const struct tgsi_image_params *params,
+               bool just_read,
+               char *data_ptr,
+               uint qi,
+               unsigned stride,
+               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] = MIN2(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] = MAX2(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] = MIN2(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] = MAX2(dst_x, src_x);
+         ((uint32_t *)rgba[c])[qi] = dst_x;
+      }
+      break;
+   default:
+      assert(!"Unexpected TGSI opcode in sp_tgsi_op");
+      break;
+   }
+   util_format_write_4ui(params->format, sdata, 0, data_ptr, stride,
+                         s, t, 1, 1);
+}
+
+/*
+ * Implement atomic operations on signed integers.
+ */
+static void
+handle_op_int(const struct pipe_image_view *iview,
+              const struct tgsi_image_params *params,
+              bool just_read,
+              char *data_ptr,
+              uint qi,
+              unsigned stride,
+              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] = 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] = MAX2(dst_x, src_x);
+         ((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] = MIN2(dst_x, src_x);
+         ((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] = MAX2(dst_x, src_x);
+         ((int32_t *)rgba[c])[qi] = dst_x;
+      }
+      break;
+   default:
+      assert(!"Unexpected TGSI opcode in sp_tgsi_op");
+      break;
+   }
+   util_format_write_4i(params->format, sdata, 0, data_ptr, stride,
+                        s, t, 1, 1);
+}
+
+/*
+ * Implement atomic image operations.
+ */
+static void
+sp_tgsi_op(const struct tgsi_image *image,
+           const 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;
+   unsigned width, height, depth;
+   unsigned stride;
+   int j, c;
+   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;
+
+   if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
+                       params->format, &width, &height, &depth))
+      goto fail_write_all_zero;
+
+   stride = util_format_get_stride(spr->base.format, width);
+
+   for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+      int s_coord, t_coord, r_coord;
+      bool just_read = false;
+
+      fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
+      if (!bounds_check(width, height, depth,
+                        s_coord, t_coord, r_coord)) {
+         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, r_coord);
+      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, params, just_read, data_ptr, j, stride,
+                        opcode, s_coord, t_coord, rgba, rgba2);
+      else if (util_format_is_pure_sint(params->format))
+         handle_op_int(iview, params, just_read, data_ptr, j, stride,
+                       opcode, s_coord, t_coord, 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;
+}
+
+static void
+sp_tgsi_get_dims(const struct tgsi_image *image,
+                 const struct tgsi_image_params *params,
+                 int dims[4])
+{
+   struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
+   struct pipe_image_view *iview;
+   struct softpipe_resource *spr;
+   int level;
+
+   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 (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
+      dims[0] = iview->u.buf.last_element - iview->u.buf.first_element + 1;
+      dims[1] = dims[2] = dims[3] = 0;
+      return;
+   }
+
+   level = iview->u.tex.level;
+   dims[0] = u_minify(spr->base.width0, level);
+   switch (params->tgsi_tex_instr) {
+   case TGSI_TEXTURE_1D_ARRAY:
+      dims[1] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
+      /* fallthrough */
+   case TGSI_TEXTURE_1D:
+      return;
+   case TGSI_TEXTURE_2D_ARRAY:
+      dims[2] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
+      /* fallthrough */
+   case TGSI_TEXTURE_2D:
+   case TGSI_TEXTURE_CUBE:
+   case TGSI_TEXTURE_RECT:
+      dims[1] = u_minify(spr->base.height0, level);
+      return;
+   case TGSI_TEXTURE_3D:
+      dims[1] = u_minify(spr->base.height0, level);
+      dims[2] = u_minify(spr->base.depth0, level);
+      return;
+   case TGSI_TEXTURE_CUBE_ARRAY:
+      dims[1] = u_minify(spr->base.height0, level);
+      dims[2] = (iview->u.tex.last_layer - iview->u.tex.first_layer + 1) / 6;
+      break;
+   default:
+      assert(!"unexpected texture target in sp_get_dims()");
+      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;
+   img->base.get_dims = sp_tgsi_get_dims;
+   return img;
+};
diff --git a/src/gallium/drivers/softpipe/sp_image.h b/src/gallium/drivers/softpipe/sp_image.h
new file mode 100644 (file)
index 0000000..3c73f83
--- /dev/null
@@ -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
index 7a2d3715f8bb8ccfd6582409137d42ce4425ecad..570bc549cc437b592e9fc30de129d479a54691d3 100644 (file)
@@ -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,
@@ -149,6 +151,9 @@ softpipe_init_streamout_funcs(struct pipe_context *pipe);
 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 *);
index d4d03f1be500ee8dd604db1a5037242b29c434ff..65679e73515d90b3475a4163bdeb9d4c1d09c0fd 100644 (file)
@@ -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 (file)
index 0000000..8909fa2
--- /dev/null
@@ -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;
+}
index 52ec373f8f2d6c8a4a481cc7b8010405eb9c37b4..64666fee03f82a3b25377572fc8a630cf73fa853 100644 (file)
@@ -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 +
index fbf741a9c7240d198cae9d4193664e252a56907f..450c4b1cefc23f6c37bd2bdbe08fbbadad2ec2ed 100644 (file)
@@ -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 */