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