Home | History | Annotate | Download | only in softpipe
      1 /*
      2  * Copyright 2016 Red Hat.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * on the rights to use, copy, modify, merge, publish, distribute, sub
      8  * license, and/or sell copies of the Software, and to permit persons to whom
      9  * the Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
     19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 #include "sp_context.h"
     25 #include "sp_buffer.h"
     26 #include "sp_texture.h"
     27 
     28 #include "util/u_format.h"
     29 
     30 static bool
     31 get_dimensions(const struct pipe_shader_buffer *bview,
     32                const struct softpipe_resource *spr,
     33                unsigned *width)
     34 {
     35    *width = bview->buffer_size;
     36    /*
     37     * Bounds check the buffer size from the view
     38     * and the buffer size from the underlying buffer.
     39     */
     40    if (*width > spr->base.width0)
     41       return false;
     42    return true;
     43 }
     44 
     45 /*
     46  * Implement the image LOAD operation.
     47  */
     48 static void
     49 sp_tgsi_load(const struct tgsi_buffer *buffer,
     50              const struct tgsi_buffer_params *params,
     51              const int s[TGSI_QUAD_SIZE],
     52              float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
     53 {
     54    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
     55    struct pipe_shader_buffer *bview;
     56    struct softpipe_resource *spr;
     57    unsigned width;
     58    int c, j;
     59    unsigned char *data_ptr;
     60    const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT);
     61 
     62    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
     63       goto fail_write_all_zero;
     64 
     65    bview = &sp_buf->sp_bview[params->unit];
     66    spr = softpipe_resource(bview->buffer);
     67    if (!spr)
     68       goto fail_write_all_zero;
     69 
     70    if (!get_dimensions(bview, spr, &width))
     71       return;
     72 
     73    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
     74       int s_coord;
     75       bool fill_zero = false;
     76       uint32_t sdata[4];
     77 
     78       if (!(params->execmask & (1 << j)))
     79          fill_zero = true;
     80 
     81       s_coord = s[j];
     82       if (s_coord >= width)
     83          fill_zero = true;
     84 
     85       if (fill_zero) {
     86          for (c = 0; c < 4; c++)
     87             rgba[c][j] = 0;
     88          continue;
     89       }
     90       data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
     91       for (c = 0; c < 4; c++) {
     92          format_desc->fetch_rgba_uint(sdata, data_ptr, 0, 0);
     93          ((uint32_t *)rgba[c])[j] = sdata[0];
     94          data_ptr += 4;
     95       }
     96    }
     97    return;
     98 fail_write_all_zero:
     99    memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
    100    return;
    101 }
    102 
    103 /*
    104  * Implement the buffer STORE operation.
    105  */
    106 static void
    107 sp_tgsi_store(const struct tgsi_buffer *buffer,
    108               const struct tgsi_buffer_params *params,
    109               const int s[TGSI_QUAD_SIZE],
    110               float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
    111 {
    112    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
    113    struct pipe_shader_buffer *bview;
    114    struct softpipe_resource *spr;
    115    unsigned width;
    116    unsigned char *data_ptr;
    117    int j, c;
    118    const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT);
    119 
    120    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
    121       return;
    122 
    123    bview = &sp_buf->sp_bview[params->unit];
    124    spr = softpipe_resource(bview->buffer);
    125    if (!spr)
    126       return;
    127 
    128    if (!get_dimensions(bview, spr, &width))
    129       return;
    130 
    131    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
    132       int s_coord;
    133 
    134       if (!(params->execmask & (1 << j)))
    135          continue;
    136 
    137       s_coord = s[j];
    138       if (s_coord >= width)
    139          continue;
    140 
    141       data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
    142 
    143       for (c = 0; c < 4; c++) {
    144          if (params->writemask & (1 << c)) {
    145             unsigned temp[4];
    146             unsigned char *dptr = data_ptr + (c * 4);
    147             temp[0] = ((uint32_t *)rgba[c])[j];
    148             format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1);
    149          }
    150       }
    151    }
    152 }
    153 
    154 /*
    155  * Implement atomic operations on unsigned integers.
    156  */
    157 static void
    158 handle_op_uint(const struct pipe_shader_buffer *bview,
    159                bool just_read,
    160                unsigned char *data_ptr,
    161                uint qi,
    162                unsigned opcode,
    163                unsigned writemask,
    164                float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
    165                float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
    166 {
    167    uint c;
    168    const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT);
    169    unsigned sdata[4];
    170 
    171    for (c = 0; c < 4; c++) {
    172       unsigned temp[4];
    173       unsigned char *dptr = data_ptr + (c * 4);
    174       format_desc->fetch_rgba_uint(temp, dptr, 0, 0);
    175       sdata[c] = temp[0];
    176    }
    177 
    178    if (just_read) {
    179       for (c = 0; c < 4; c++) {
    180          ((uint32_t *)rgba[c])[qi] = sdata[c];
    181       }
    182       return;
    183    }
    184 
    185    switch (opcode) {
    186    case TGSI_OPCODE_ATOMUADD:
    187       for (c = 0; c < 4; c++) {
    188          unsigned temp = sdata[c];
    189          sdata[c] += ((uint32_t *)rgba[c])[qi];
    190          ((uint32_t *)rgba[c])[qi] = temp;
    191       }
    192       break;
    193    case TGSI_OPCODE_ATOMXCHG:
    194       for (c = 0; c < 4; c++) {
    195          unsigned temp = sdata[c];
    196          sdata[c] = ((uint32_t *)rgba[c])[qi];
    197          ((uint32_t *)rgba[c])[qi] = temp;
    198       }
    199       break;
    200    case TGSI_OPCODE_ATOMCAS:
    201       for (c = 0; c < 4; c++) {
    202          unsigned dst_x = sdata[c];
    203          unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
    204          unsigned src_x = ((uint32_t *)rgba2[c])[qi];
    205          unsigned temp = sdata[c];
    206          sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
    207          ((uint32_t *)rgba[c])[qi] = temp;
    208       }
    209       break;
    210    case TGSI_OPCODE_ATOMAND:
    211       for (c = 0; c < 4; c++) {
    212          unsigned temp = sdata[c];
    213          sdata[c] &= ((uint32_t *)rgba[c])[qi];
    214          ((uint32_t *)rgba[c])[qi] = temp;
    215       }
    216       break;
    217    case TGSI_OPCODE_ATOMOR:
    218       for (c = 0; c < 4; c++) {
    219          unsigned temp = sdata[c];
    220          sdata[c] |= ((uint32_t *)rgba[c])[qi];
    221          ((uint32_t *)rgba[c])[qi] = temp;
    222       }
    223       break;
    224    case TGSI_OPCODE_ATOMXOR:
    225       for (c = 0; c < 4; c++) {
    226          unsigned temp = sdata[c];
    227          sdata[c] ^= ((uint32_t *)rgba[c])[qi];
    228          ((uint32_t *)rgba[c])[qi] = temp;
    229       }
    230       break;
    231    case TGSI_OPCODE_ATOMUMIN:
    232       for (c = 0; c < 4; c++) {
    233          unsigned dst_x = sdata[c];
    234          unsigned src_x = ((uint32_t *)rgba[c])[qi];
    235          sdata[c] = MIN2(dst_x, src_x);
    236          ((uint32_t *)rgba[c])[qi] = dst_x;
    237       }
    238       break;
    239    case TGSI_OPCODE_ATOMUMAX:
    240       for (c = 0; c < 4; c++) {
    241          unsigned dst_x = sdata[c];
    242          unsigned src_x = ((uint32_t *)rgba[c])[qi];
    243          sdata[c] = MAX2(dst_x, src_x);
    244          ((uint32_t *)rgba[c])[qi] = dst_x;
    245       }
    246       break;
    247    case TGSI_OPCODE_ATOMIMIN:
    248       for (c = 0; c < 4; c++) {
    249          int dst_x = sdata[c];
    250          int src_x = ((uint32_t *)rgba[c])[qi];
    251          sdata[c] = MIN2(dst_x, src_x);
    252          ((uint32_t *)rgba[c])[qi] = dst_x;
    253       }
    254       break;
    255    case TGSI_OPCODE_ATOMIMAX:
    256       for (c = 0; c < 4; c++) {
    257          int dst_x = sdata[c];
    258          int src_x = ((uint32_t *)rgba[c])[qi];
    259          sdata[c] = MAX2(dst_x, src_x);
    260          ((uint32_t *)rgba[c])[qi] = dst_x;
    261       }
    262       break;
    263    default:
    264       assert(!"Unexpected TGSI opcode in sp_tgsi_op");
    265       break;
    266    }
    267 
    268    for (c = 0; c < 4; c++) {
    269       if (writemask & (1 << c)) {
    270          unsigned temp[4];
    271          unsigned char *dptr = data_ptr + (c * 4);
    272          temp[0] = sdata[c];
    273          format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1);
    274       }
    275    }
    276 }
    277 
    278 /*
    279  * Implement atomic buffer operations.
    280  */
    281 static void
    282 sp_tgsi_op(const struct tgsi_buffer *buffer,
    283            const struct tgsi_buffer_params *params,
    284            unsigned opcode,
    285            const int s[TGSI_QUAD_SIZE],
    286            float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
    287            float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
    288 {
    289    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
    290    struct pipe_shader_buffer *bview;
    291    struct softpipe_resource *spr;
    292    unsigned width;
    293    int j, c;
    294    unsigned char *data_ptr;
    295 
    296    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
    297       return;
    298 
    299    bview = &sp_buf->sp_bview[params->unit];
    300    spr = softpipe_resource(bview->buffer);
    301    if (!spr)
    302       goto fail_write_all_zero;
    303 
    304    if (!get_dimensions(bview, spr, &width))
    305       goto fail_write_all_zero;
    306 
    307    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
    308       int s_coord;
    309       bool just_read = false;
    310 
    311       s_coord = s[j];
    312       if (s_coord >= width) {
    313          for (c = 0; c < 4; c++) {
    314             rgba[c][j] = 0;
    315          }
    316          continue;
    317       }
    318 
    319       /* just readback the value for atomic if execmask isn't set */
    320       if (!(params->execmask & (1 << j))) {
    321          just_read = true;
    322       }
    323 
    324       data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
    325       /* we should see atomic operations on r32 formats */
    326 
    327       handle_op_uint(bview, just_read, data_ptr, j,
    328                      opcode, params->writemask, rgba, rgba2);
    329    }
    330    return;
    331 fail_write_all_zero:
    332    memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
    333    return;
    334 }
    335 
    336 /*
    337  * return size of the attached buffer for RESQ opcode.
    338  */
    339 static void
    340 sp_tgsi_get_dims(const struct tgsi_buffer *buffer,
    341                  const struct tgsi_buffer_params *params,
    342                  int *dim)
    343 {
    344    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
    345    struct pipe_shader_buffer *bview;
    346    struct softpipe_resource *spr;
    347 
    348    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
    349       return;
    350 
    351    bview = &sp_buf->sp_bview[params->unit];
    352    spr = softpipe_resource(bview->buffer);
    353    if (!spr)
    354       return;
    355 
    356    *dim = bview->buffer_size;
    357 }
    358 
    359 struct sp_tgsi_buffer *
    360 sp_create_tgsi_buffer(void)
    361 {
    362    struct sp_tgsi_buffer *buf = CALLOC_STRUCT(sp_tgsi_buffer);
    363    if (!buf)
    364       return NULL;
    365 
    366    buf->base.load = sp_tgsi_load;
    367    buf->base.store = sp_tgsi_store;
    368    buf->base.op = sp_tgsi_op;
    369    buf->base.get_dims = sp_tgsi_get_dims;
    370    return buf;
    371 };
    372