sp_buffer.c revision 01e04c3f
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
30static bool
31get_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 */
48static void
49sp_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;
98fail_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 */
106static void
107sp_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 */
157static void
158handle_op_uint(const struct pipe_shader_buffer *bview,
159               bool just_read,
160               unsigned char *data_ptr,
161               uint qi,
162               enum tgsi_opcode 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 */
281static void
282sp_tgsi_op(const struct tgsi_buffer *buffer,
283           const struct tgsi_buffer_params *params,
284           enum tgsi_opcode 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;
331fail_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 */
339static void
340sp_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
359struct sp_tgsi_buffer *
360sp_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