util: Move gallium's PIPE_FORMAT utils to /util/format/
[mesa.git] / src / gallium / drivers / softpipe / sp_buffer.c
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
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
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
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
158 handle_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 */
288 static void
289 sp_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;
338 fail_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 */
346 static void
347 sp_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
366 struct sp_tgsi_buffer *
367 sp_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 };