• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
get_dimensions(const struct pipe_shader_buffer * bview,const struct softpipe_resource * spr,unsigned * width)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
sp_tgsi_load(const struct tgsi_buffer * buffer,const struct tgsi_buffer_params * params,const int s[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])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
sp_tgsi_store(const struct tgsi_buffer * buffer,const struct tgsi_buffer_params * params,const int s[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])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
handle_op_uint(const struct pipe_shader_buffer * bview,bool just_read,unsigned char * data_ptr,uint qi,unsigned opcode,unsigned writemask,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])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
sp_tgsi_op(const struct tgsi_buffer * buffer,const struct tgsi_buffer_params * params,unsigned opcode,const int s[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])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
sp_tgsi_get_dims(const struct tgsi_buffer * buffer,const struct tgsi_buffer_params * params,int * dim)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 *
sp_create_tgsi_buffer(void)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