diff options
author | Dave Airlie <[email protected]> | 2016-03-22 07:59:35 +1000 |
---|---|---|
committer | Dave Airlie <[email protected]> | 2016-03-31 09:14:16 +1000 |
commit | eb9ad9faa3975fc4f044b81d3b4b793866ef5563 (patch) | |
tree | ab644c9094434e86972502d324af0c94d3371b73 /src/gallium/drivers/softpipe/sp_image.c | |
parent | 0d1f679dedfb47944259e846d7f2eadbcf0907ca (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.c | 762 |
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; +}; |