softpipe/buffer: load only as many components as the the buffer resource type provides
[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/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 unsigned ncomp;
59 unsigned c, j;
60 unsigned char *data_ptr;
61 const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT);
62
63 if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
64 goto fail_write_all_zero;
65
66 bview = &sp_buf->sp_bview[params->unit];
67 ncomp = util_format_get_nr_components(bview->buffer->format);
68
69 spr = softpipe_resource(bview->buffer);
70 if (!spr)
71 goto fail_write_all_zero;
72
73 if (!get_dimensions(bview, spr, &width))
74 return;
75
76 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
77 int s_coord;
78 bool fill_zero = false;
79 uint32_t sdata[4];
80
81 if (!(params->execmask & (1 << j)))
82 fill_zero = true;
83
84 s_coord = s[j];
85 if (s_coord >= width)
86 fill_zero = true;
87
88 if (fill_zero) {
89 for (c = 0; c < 4; c++)
90 rgba[c][j] = 0;
91 continue;
92 }
93 data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
94 for (c = 0; c < ncomp; c++) {
95 format_desc->fetch_rgba_uint(sdata, data_ptr, 0, 0);
96 ((uint32_t *)rgba[c])[j] = sdata[0];
97 data_ptr += 4;
98 }
99 }
100 return;
101 fail_write_all_zero:
102 memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
103 return;
104 }
105
106 /*
107 * Implement the buffer STORE operation.
108 */
109 static void
110 sp_tgsi_store(const struct tgsi_buffer *buffer,
111 const struct tgsi_buffer_params *params,
112 const int s[TGSI_QUAD_SIZE],
113 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
114 {
115 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
116 struct pipe_shader_buffer *bview;
117 struct softpipe_resource *spr;
118 unsigned width;
119 unsigned char *data_ptr;
120 int j, c;
121 const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT);
122
123 if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
124 return;
125
126 bview = &sp_buf->sp_bview[params->unit];
127 spr = softpipe_resource(bview->buffer);
128 if (!spr)
129 return;
130
131 if (!get_dimensions(bview, spr, &width))
132 return;
133
134 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
135 int s_coord;
136
137 if (!(params->execmask & (1 << j)))
138 continue;
139
140 s_coord = s[j];
141 if (s_coord >= width)
142 continue;
143
144 data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
145
146 for (c = 0; c < 4; c++) {
147 if (params->writemask & (1 << c)) {
148 unsigned temp[4];
149 unsigned char *dptr = data_ptr + (c * 4);
150 temp[0] = ((uint32_t *)rgba[c])[j];
151 format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1);
152 }
153 }
154 }
155 }
156
157 /*
158 * Implement atomic operations on unsigned integers.
159 */
160 static void
161 handle_op_atomic(const struct pipe_shader_buffer *bview,
162 bool just_read,
163 unsigned char *data_ptr,
164 uint qi,
165 enum tgsi_opcode opcode,
166 unsigned writemask,
167 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
168 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
169 {
170 uint c;
171 const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT);
172 unsigned sdata[4];
173
174 for (c = 0; c < 4; c++) {
175 unsigned temp[4];
176 unsigned char *dptr = data_ptr + (c * 4);
177 format_desc->fetch_rgba_uint(temp, dptr, 0, 0);
178 sdata[c] = temp[0];
179 }
180
181 if (just_read) {
182 for (c = 0; c < 4; c++) {
183 ((uint32_t *)rgba[c])[qi] = sdata[c];
184 }
185 return;
186 }
187
188 switch (opcode) {
189 case TGSI_OPCODE_ATOMUADD:
190 for (c = 0; c < 4; c++) {
191 unsigned temp = sdata[c];
192 sdata[c] += ((uint32_t *)rgba[c])[qi];
193 ((uint32_t *)rgba[c])[qi] = temp;
194 }
195 break;
196 case TGSI_OPCODE_ATOMXCHG:
197 for (c = 0; c < 4; c++) {
198 unsigned temp = sdata[c];
199 sdata[c] = ((uint32_t *)rgba[c])[qi];
200 ((uint32_t *)rgba[c])[qi] = temp;
201 }
202 break;
203 case TGSI_OPCODE_ATOMCAS:
204 for (c = 0; c < 4; c++) {
205 unsigned dst_x = sdata[c];
206 unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
207 unsigned src_x = ((uint32_t *)rgba2[c])[qi];
208 unsigned temp = sdata[c];
209 sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
210 ((uint32_t *)rgba[c])[qi] = temp;
211 }
212 break;
213 case TGSI_OPCODE_ATOMAND:
214 for (c = 0; c < 4; c++) {
215 unsigned temp = sdata[c];
216 sdata[c] &= ((uint32_t *)rgba[c])[qi];
217 ((uint32_t *)rgba[c])[qi] = temp;
218 }
219 break;
220 case TGSI_OPCODE_ATOMOR:
221 for (c = 0; c < 4; c++) {
222 unsigned temp = sdata[c];
223 sdata[c] |= ((uint32_t *)rgba[c])[qi];
224 ((uint32_t *)rgba[c])[qi] = temp;
225 }
226 break;
227 case TGSI_OPCODE_ATOMXOR:
228 for (c = 0; c < 4; c++) {
229 unsigned temp = sdata[c];
230 sdata[c] ^= ((uint32_t *)rgba[c])[qi];
231 ((uint32_t *)rgba[c])[qi] = temp;
232 }
233 break;
234 case TGSI_OPCODE_ATOMUMIN:
235 for (c = 0; c < 4; c++) {
236 unsigned dst_x = sdata[c];
237 unsigned src_x = ((uint32_t *)rgba[c])[qi];
238 sdata[c] = MIN2(dst_x, src_x);
239 ((uint32_t *)rgba[c])[qi] = dst_x;
240 }
241 break;
242 case TGSI_OPCODE_ATOMUMAX:
243 for (c = 0; c < 4; c++) {
244 unsigned dst_x = sdata[c];
245 unsigned src_x = ((uint32_t *)rgba[c])[qi];
246 sdata[c] = MAX2(dst_x, src_x);
247 ((uint32_t *)rgba[c])[qi] = dst_x;
248 }
249 break;
250 case TGSI_OPCODE_ATOMIMIN:
251 for (c = 0; c < 4; c++) {
252 int dst_x = sdata[c];
253 int src_x = ((uint32_t *)rgba[c])[qi];
254 sdata[c] = MIN2(dst_x, src_x);
255 ((uint32_t *)rgba[c])[qi] = dst_x;
256 }
257 break;
258 case TGSI_OPCODE_ATOMIMAX:
259 for (c = 0; c < 4; c++) {
260 int dst_x = sdata[c];
261 int src_x = ((uint32_t *)rgba[c])[qi];
262 sdata[c] = MAX2(dst_x, src_x);
263 ((uint32_t *)rgba[c])[qi] = dst_x;
264 }
265 break;
266 case TGSI_OPCODE_ATOMFADD:
267 for (c = 0; c < 4; c++) {
268 float temp = uif(sdata[c]);
269 sdata[c] = fui(temp + rgba[c][qi]);
270 rgba[c][qi] = temp;
271 }
272 break;
273 default:
274 assert(!"Unexpected TGSI opcode in sp_tgsi_op");
275 break;
276 }
277
278 for (c = 0; c < 4; c++) {
279 if (writemask & (1 << c)) {
280 unsigned temp[4];
281 unsigned char *dptr = data_ptr + (c * 4);
282 temp[0] = sdata[c];
283 format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1);
284 }
285 }
286 }
287
288 /*
289 * Implement atomic buffer operations.
290 */
291 static void
292 sp_tgsi_op(const struct tgsi_buffer *buffer,
293 const struct tgsi_buffer_params *params,
294 enum tgsi_opcode opcode,
295 const int s[TGSI_QUAD_SIZE],
296 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
297 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
298 {
299 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
300 struct pipe_shader_buffer *bview;
301 struct softpipe_resource *spr;
302 unsigned width;
303 int j, c;
304 unsigned char *data_ptr;
305
306 if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
307 return;
308
309 bview = &sp_buf->sp_bview[params->unit];
310 spr = softpipe_resource(bview->buffer);
311 if (!spr)
312 goto fail_write_all_zero;
313
314 if (!get_dimensions(bview, spr, &width))
315 goto fail_write_all_zero;
316
317 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
318 int s_coord;
319 bool just_read = false;
320
321 s_coord = s[j];
322 if (s_coord >= width) {
323 for (c = 0; c < 4; c++) {
324 rgba[c][j] = 0;
325 }
326 continue;
327 }
328
329 /* just readback the value for atomic if execmask isn't set */
330 if (!(params->execmask & (1 << j))) {
331 just_read = true;
332 }
333
334 data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord;
335 /* we should see atomic operations on r32 formats */
336
337 handle_op_atomic(bview, just_read, data_ptr, j,
338 opcode, params->writemask, rgba, rgba2);
339 }
340 return;
341 fail_write_all_zero:
342 memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4);
343 return;
344 }
345
346 /*
347 * return size of the attached buffer for RESQ opcode.
348 */
349 static void
350 sp_tgsi_get_dims(const struct tgsi_buffer *buffer,
351 const struct tgsi_buffer_params *params,
352 int *dim)
353 {
354 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer;
355 struct pipe_shader_buffer *bview;
356 struct softpipe_resource *spr;
357
358 if (params->unit >= PIPE_MAX_SHADER_BUFFERS)
359 return;
360
361 bview = &sp_buf->sp_bview[params->unit];
362 spr = softpipe_resource(bview->buffer);
363 if (!spr)
364 return;
365
366 *dim = bview->buffer_size;
367 }
368
369 struct sp_tgsi_buffer *
370 sp_create_tgsi_buffer(void)
371 {
372 struct sp_tgsi_buffer *buf = CALLOC_STRUCT(sp_tgsi_buffer);
373 if (!buf)
374 return NULL;
375
376 buf->base.load = sp_tgsi_load;
377 buf->base.store = sp_tgsi_store;
378 buf->base.op = sp_tgsi_op;
379 buf->base.get_dims = sp_tgsi_get_dims;
380 return buf;
381 };