sp_buffer.c revision b8e80941
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_atomic(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   case TGSI_OPCODE_ATOMFADD:
264      for (c = 0; c < 4; c++) {
265         float temp = uif(sdata[c]);
266         sdata[c] = fui(temp + rgba[c][qi]);
267         rgba[c][qi] = temp;
268      }
269      break;
270   default:
271      assert(!"Unexpected TGSI opcode in sp_tgsi_op");
272      break;
273   }
274
275   for (c = 0; c < 4; c++) {
276      if (writemask & (1 << c)) {
277         unsigned temp[4];
278         unsigned char *dptr = data_ptr + (c * 4);
279         temp[0] = sdata[c];
280         format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1);
281      }
282   }
283}
284
285/*
286 * Implement atomic buffer operations.
287 */
288static void
289sp_tgsi_op(const struct tgsi_buffer *buffer,
290           const struct tgsi_buffer_params *params,
291           enum tgsi_opcode opcode,
292           const int s[TGSI_QUAD_SIZE],
293           float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
294           float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
295{
296   struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
297   struct pipe_shader_buffer *bview;
298   struct softpipe_resource *spr;
299   unsigned width;
300   int j, c;
301   unsigned char *data_ptr;
302
303   if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
304      return;
305
306   bview = &sp_buf->sp_bview[params->unit];
307   spr = softpipe_resource(bview->buffer);
308   if (!spr)
309      goto fail_write_all_zero;
310
311   if (!get_dimensions(bview, spr, &width))
312      goto fail_write_all_zero;
313
314   for (j = 0; j < TGSI_QUAD_SIZE; j++) {
315      int s_coord;
316      bool just_read = false;
317
318      s_coord = s[j];
319      if (s_coord >= width) {
320         for (c = 0; c < 4; c++) {
321            rgba[c][j] = 0;
322         }
323         continue;
324      }
325
326      /* just readback the value for atomic if execmask isn't set */
327      if (!(params->execmask & (1 << j))) {
328         just_read = true;
329      }
330
331      data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
332      /* we should see atomic operations on r32 formats */
333
334      handle_op_atomic(bview, just_read, data_ptr, j,
335                       opcode, params->writemask, rgba, rgba2);
336   }
337   return;
338fail_write_all_zero:
339   memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
340   return;
341}
342
343/*
344 * return size of the attached buffer for RESQ opcode.
345 */
346static void
347sp_tgsi_get_dims(const struct tgsi_buffer *buffer,
348                 const struct tgsi_buffer_params *params,
349                 int *dim)
350{
351   struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
352   struct pipe_shader_buffer *bview;
353   struct softpipe_resource *spr;
354
355   if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
356      return;
357
358   bview = &sp_buf->sp_bview[params->unit];
359   spr = softpipe_resource(bview->buffer);
360   if (!spr)
361      return;
362
363   *dim = bview->buffer_size;
364}
365
366struct sp_tgsi_buffer *
367sp_create_tgsi_buffer(void)
368{
369   struct sp_tgsi_buffer *buf = CALLOC_STRUCT(sp_tgsi_buffer);
370   if (!buf)
371      return NULL;
372
373   buf->base.load = sp_tgsi_load;
374   buf->base.store = sp_tgsi_store;
375   buf->base.op = sp_tgsi_op;
376   buf->base.get_dims = sp_tgsi_get_dims;
377   return buf;
378};
379