summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/softpipe/sp_image.c
diff options
context:
space:
mode:
authorDave Airlie <[email protected]>2016-03-22 07:59:35 +1000
committerDave Airlie <[email protected]>2016-03-31 09:14:16 +1000
commiteb9ad9faa3975fc4f044b81d3b4b793866ef5563 (patch)
treeab644c9094434e86972502d324af0c94d3371b73 /src/gallium/drivers/softpipe/sp_image.c
parent0d1f679dedfb47944259e846d7f2eadbcf0907ca (diff)
softpipe: add image support to softpipe (v3)
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 <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
Diffstat (limited to 'src/gallium/drivers/softpipe/sp_image.c')
-rw-r--r--src/gallium/drivers/softpipe/sp_image.c762
1 files changed, 762 insertions, 0 deletions
diff --git a/src/gallium/drivers/softpipe/sp_image.c b/src/gallium/drivers/softpipe/sp_image.c
new file mode 100644
index 00000000000..3488fa83185
--- /dev/null
+++ b/src/gallium/drivers/softpipe/sp_image.c
@@ -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;
+};