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