• 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/format/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 
60    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
61       goto fail_write_all_zero;
62 
63    bview = &sp_buf->sp_bview[params->unit];
64    spr = softpipe_resource(bview->buffer);
65    if (!spr)
66       goto fail_write_all_zero;
67 
68    if (!get_dimensions(bview, spr, &width))
69       return;
70 
71    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
72       int s_coord;
73       bool fill_zero = false;
74 
75       if (!(params->execmask & (1 << j)))
76          fill_zero = true;
77 
78       s_coord = s[j];
79       if (s_coord >= width)
80          fill_zero = true;
81 
82       if (fill_zero) {
83          for (c = 0; c < 4; c++)
84             rgba[c][j] = 0;
85          continue;
86       }
87       uint32_t *src = (uint32_t *)((unsigned char *)spr->data +
88                                    bview->buffer_offset + s_coord);
89       for (c = 0; c < 4; c++) {
90          memcpy(&rgba[c][j], &src[c], 4);
91       }
92    }
93    return;
94 fail_write_all_zero:
95    memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
96    return;
97 }
98 
99 /*
100  * Implement the buffer STORE operation.
101  */
102 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])103 sp_tgsi_store(const struct tgsi_buffer *buffer,
104               const struct tgsi_buffer_params *params,
105               const int s[TGSI_QUAD_SIZE],
106               float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
107 {
108    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
109    struct pipe_shader_buffer *bview;
110    struct softpipe_resource *spr;
111    unsigned width;
112    int j, c;
113 
114    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
115       return;
116 
117    bview = &sp_buf->sp_bview[params->unit];
118    spr = softpipe_resource(bview->buffer);
119    if (!spr)
120       return;
121 
122    if (!get_dimensions(bview, spr, &width))
123       return;
124 
125    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
126       int s_coord;
127 
128       if (!(params->execmask & (1 << j)))
129          continue;
130 
131       s_coord = s[j];
132       if (s_coord >= width)
133          continue;
134 
135       uint32_t *dst = (uint32_t *)((unsigned char *)spr->data +
136                                    bview->buffer_offset + s_coord);
137 
138       for (c = 0; c < 4; c++) {
139          if (params->writemask & (1 << c))
140             memcpy(&dst[c], &rgba[c][j], 4);
141       }
142    }
143 }
144 
145 /*
146  * Implement atomic operations on unsigned integers.
147  */
148 static void
handle_op_atomic(const struct pipe_shader_buffer * bview,bool just_read,unsigned char * data_ptr,uint qi,enum tgsi_opcode opcode,unsigned writemask,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])149 handle_op_atomic(const struct pipe_shader_buffer *bview,
150                  bool just_read,
151                  unsigned char *data_ptr,
152                  uint qi,
153                  enum tgsi_opcode opcode,
154                  unsigned writemask,
155                  float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
156                  float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
157 {
158    uint c = 0; /* SSBO atomics are always on the .x channel. */
159    unsigned sdata;
160 
161    memcpy(&sdata, data_ptr + (c * 4), 4);
162 
163    if (just_read) {
164       ((uint32_t *)rgba[c])[qi] = sdata;
165       return;
166    }
167 
168    switch (opcode) {
169    case TGSI_OPCODE_ATOMUADD: {
170       unsigned temp = sdata;
171       sdata += ((uint32_t *)rgba[c])[qi];
172       ((uint32_t *)rgba[c])[qi] = temp;
173       break;
174    }
175    case TGSI_OPCODE_ATOMXCHG: {
176       unsigned temp = sdata;
177       sdata = ((uint32_t *)rgba[c])[qi];
178       ((uint32_t *)rgba[c])[qi] = temp;
179       break;
180    }
181    case TGSI_OPCODE_ATOMCAS: {
182       unsigned dst_x = sdata;
183       unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
184       unsigned src_x = ((uint32_t *)rgba2[c])[qi];
185       unsigned temp = sdata;
186       sdata = (dst_x == cmp_x) ? src_x : dst_x;
187       ((uint32_t *)rgba[c])[qi] = temp;
188       break;
189    }
190    case TGSI_OPCODE_ATOMAND: {
191       unsigned temp = sdata;
192       sdata &= ((uint32_t *)rgba[c])[qi];
193       ((uint32_t *)rgba[c])[qi] = temp;
194       break;
195    }
196    case TGSI_OPCODE_ATOMOR: {
197       unsigned temp = sdata;
198       sdata |= ((uint32_t *)rgba[c])[qi];
199       ((uint32_t *)rgba[c])[qi] = temp;
200       break;
201    }
202    case TGSI_OPCODE_ATOMXOR: {
203       unsigned temp = sdata;
204       sdata ^= ((uint32_t *)rgba[c])[qi];
205       ((uint32_t *)rgba[c])[qi] = temp;
206       break;
207    }
208    case TGSI_OPCODE_ATOMUMIN: {
209       unsigned dst_x = sdata;
210       unsigned src_x = ((uint32_t *)rgba[c])[qi];
211       sdata = MIN2(dst_x, src_x);
212       ((uint32_t *)rgba[c])[qi] = dst_x;
213       break;
214    }
215    case TGSI_OPCODE_ATOMUMAX: {
216       unsigned dst_x = sdata;
217       unsigned src_x = ((uint32_t *)rgba[c])[qi];
218       sdata = MAX2(dst_x, src_x);
219       ((uint32_t *)rgba[c])[qi] = dst_x;
220       break;
221    }
222    case TGSI_OPCODE_ATOMIMIN: {
223       int dst_x = sdata;
224       int src_x = ((uint32_t *)rgba[c])[qi];
225       sdata = MIN2(dst_x, src_x);
226       ((uint32_t *)rgba[c])[qi] = dst_x;
227       break;
228    }
229    case TGSI_OPCODE_ATOMIMAX: {
230       int dst_x = sdata;
231       int src_x = ((uint32_t *)rgba[c])[qi];
232       sdata = MAX2(dst_x, src_x);
233       ((uint32_t *)rgba[c])[qi] = dst_x;
234       break;
235    }
236    case TGSI_OPCODE_ATOMFADD: {
237       float temp = uif(sdata);
238       sdata = fui(temp + rgba[c][qi]);
239       rgba[c][qi] = temp;
240       break;
241    }
242    default:
243       assert(!"Unexpected TGSI opcode in sp_tgsi_op");
244       break;
245    }
246 
247    if (writemask & TGSI_WRITEMASK_X) {
248       memcpy(data_ptr + (c * 4), &sdata, 4);
249    }
250 }
251 
252 /*
253  * Implement atomic buffer operations.
254  */
255 static void
sp_tgsi_op(const struct tgsi_buffer * buffer,const struct tgsi_buffer_params * params,enum tgsi_opcode opcode,const int s[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])256 sp_tgsi_op(const struct tgsi_buffer *buffer,
257            const struct tgsi_buffer_params *params,
258            enum tgsi_opcode opcode,
259            const int s[TGSI_QUAD_SIZE],
260            float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
261            float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
262 {
263    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
264    struct pipe_shader_buffer *bview;
265    struct softpipe_resource *spr;
266    unsigned width;
267    int j, c;
268    unsigned char *data_ptr;
269 
270    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
271       return;
272 
273    bview = &sp_buf->sp_bview[params->unit];
274    spr = softpipe_resource(bview->buffer);
275    if (!spr)
276       goto fail_write_all_zero;
277 
278    if (!get_dimensions(bview, spr, &width))
279       goto fail_write_all_zero;
280 
281    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
282       int s_coord;
283       bool just_read = false;
284 
285       s_coord = s[j];
286       if (s_coord >= width) {
287          for (c = 0; c < 4; c++) {
288             rgba[c][j] = 0;
289          }
290          continue;
291       }
292 
293       /* just readback the value for atomic if execmask isn't set */
294       if (!(params->execmask & (1 << j))) {
295          just_read = true;
296       }
297 
298       data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
299       /* we should see atomic operations on r32 formats */
300 
301       handle_op_atomic(bview, just_read, data_ptr, j,
302                        opcode, params->writemask, rgba, rgba2);
303    }
304    return;
305 fail_write_all_zero:
306    memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
307    return;
308 }
309 
310 /*
311  * return size of the attached buffer for RESQ opcode.
312  */
313 static void
sp_tgsi_get_dims(const struct tgsi_buffer * buffer,const struct tgsi_buffer_params * params,int * dim)314 sp_tgsi_get_dims(const struct tgsi_buffer *buffer,
315                  const struct tgsi_buffer_params *params,
316                  int *dim)
317 {
318    struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
319    struct pipe_shader_buffer *bview;
320    struct softpipe_resource *spr;
321 
322    if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
323       return;
324 
325    bview = &sp_buf->sp_bview[params->unit];
326    spr = softpipe_resource(bview->buffer);
327    if (!spr)
328       return;
329 
330    *dim = bview->buffer_size;
331 }
332 
333 struct sp_tgsi_buffer *
sp_create_tgsi_buffer(void)334 sp_create_tgsi_buffer(void)
335 {
336    struct sp_tgsi_buffer *buf = CALLOC_STRUCT(sp_tgsi_buffer);
337    if (!buf)
338       return NULL;
339 
340    buf->base.load = sp_tgsi_load;
341    buf->base.store = sp_tgsi_store;
342    buf->base.op = sp_tgsi_op;
343    buf->base.get_dims = sp_tgsi_get_dims;
344    return buf;
345 };
346