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_image.h"
26 #include "sp_texture.h"
27
28 #include "util/u_format.h"
29
30 /*
31 * Get the offset into the base image
32 * first element for a buffer or layer/level for texture.
33 */
34 static uint32_t
get_image_offset(const struct softpipe_resource * spr,const struct pipe_image_view * iview,enum pipe_format format,unsigned r_coord)35 get_image_offset(const struct softpipe_resource *spr,
36 const struct pipe_image_view *iview,
37 enum pipe_format format, unsigned r_coord)
38 {
39 int base_layer = 0;
40
41 if (spr->base.target == PIPE_BUFFER)
42 return iview->u.buf.offset;
43
44 if (spr->base.target == PIPE_TEXTURE_1D_ARRAY ||
45 spr->base.target == PIPE_TEXTURE_2D_ARRAY ||
46 spr->base.target == PIPE_TEXTURE_CUBE_ARRAY ||
47 spr->base.target == PIPE_TEXTURE_CUBE ||
48 spr->base.target == PIPE_TEXTURE_3D)
49 base_layer = r_coord + iview->u.tex.first_layer;
50 return softpipe_get_tex_image_offset(spr, iview->u.tex.level, base_layer);
51 }
52
53 /*
54 * Does this texture instruction have a layer or depth parameter.
55 */
56 static inline bool
has_layer_or_depth(unsigned tgsi_tex_instr)57 has_layer_or_depth(unsigned tgsi_tex_instr)
58 {
59 return (tgsi_tex_instr == TGSI_TEXTURE_3D ||
60 tgsi_tex_instr == TGSI_TEXTURE_CUBE ||
61 tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ||
62 tgsi_tex_instr == TGSI_TEXTURE_2D_ARRAY ||
63 tgsi_tex_instr == TGSI_TEXTURE_CUBE_ARRAY ||
64 tgsi_tex_instr == TGSI_TEXTURE_2D_ARRAY_MSAA);
65 }
66
67 /*
68 * Is this texture instruction a single non-array coordinate.
69 */
70 static inline bool
has_1coord(unsigned tgsi_tex_instr)71 has_1coord(unsigned tgsi_tex_instr)
72 {
73 return (tgsi_tex_instr == TGSI_TEXTURE_BUFFER ||
74 tgsi_tex_instr == TGSI_TEXTURE_1D ||
75 tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY);
76 }
77
78 /*
79 * check the bounds vs w/h/d
80 */
81 static inline bool
bounds_check(int width,int height,int depth,int s,int t,int r)82 bounds_check(int width, int height, int depth,
83 int s, int t, int r)
84 {
85 if (s < 0 || s >= width)
86 return false;
87 if (t < 0 || t >= height)
88 return false;
89 if (r < 0 || r >= depth)
90 return false;
91 return true;
92 }
93
94 /*
95 * Checks if the texture target compatible with the image resource
96 * pipe target.
97 */
98 static inline bool
has_compat_target(unsigned pipe_target,unsigned tgsi_target)99 has_compat_target(unsigned pipe_target, unsigned tgsi_target)
100 {
101 switch (pipe_target) {
102 case PIPE_TEXTURE_1D:
103 if (tgsi_target == TGSI_TEXTURE_1D)
104 return true;
105 break;
106 case PIPE_TEXTURE_2D:
107 if (tgsi_target == TGSI_TEXTURE_2D)
108 return true;
109 break;
110 case PIPE_TEXTURE_RECT:
111 if (tgsi_target == TGSI_TEXTURE_RECT)
112 return true;
113 break;
114 case PIPE_TEXTURE_3D:
115 if (tgsi_target == TGSI_TEXTURE_3D ||
116 tgsi_target == TGSI_TEXTURE_2D)
117 return true;
118 break;
119 case PIPE_TEXTURE_CUBE:
120 if (tgsi_target == TGSI_TEXTURE_CUBE ||
121 tgsi_target == TGSI_TEXTURE_2D)
122 return true;
123 break;
124 case PIPE_TEXTURE_1D_ARRAY:
125 if (tgsi_target == TGSI_TEXTURE_1D ||
126 tgsi_target == TGSI_TEXTURE_1D_ARRAY)
127 return true;
128 break;
129 case PIPE_TEXTURE_2D_ARRAY:
130 if (tgsi_target == TGSI_TEXTURE_2D ||
131 tgsi_target == TGSI_TEXTURE_2D_ARRAY)
132 return true;
133 break;
134 case PIPE_TEXTURE_CUBE_ARRAY:
135 if (tgsi_target == TGSI_TEXTURE_CUBE ||
136 tgsi_target == TGSI_TEXTURE_CUBE_ARRAY ||
137 tgsi_target == TGSI_TEXTURE_2D)
138 return true;
139 break;
140 case PIPE_BUFFER:
141 return (tgsi_target == TGSI_TEXTURE_BUFFER);
142 }
143 return false;
144 }
145
146 static bool
get_dimensions(const struct pipe_image_view * iview,const struct softpipe_resource * spr,unsigned tgsi_tex_instr,enum pipe_format pformat,unsigned * width,unsigned * height,unsigned * depth)147 get_dimensions(const struct pipe_image_view *iview,
148 const struct softpipe_resource *spr,
149 unsigned tgsi_tex_instr,
150 enum pipe_format pformat,
151 unsigned *width,
152 unsigned *height,
153 unsigned *depth)
154 {
155 if (tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
156 *width = iview->u.buf.size / util_format_get_blocksize(pformat);
157 *height = 1;
158 *depth = 1;
159 /*
160 * Bounds check the buffer size from the view
161 * and the buffer size from the underlying buffer.
162 */
163 if (util_format_get_stride(pformat, *width) >
164 util_format_get_stride(spr->base.format, spr->base.width0))
165 return false;
166 } else {
167 unsigned level;
168
169 level = spr->base.target == PIPE_BUFFER ? 0 : iview->u.tex.level;
170 *width = u_minify(spr->base.width0, level);
171 *height = u_minify(spr->base.height0, level);
172
173 if (spr->base.target == PIPE_TEXTURE_3D)
174 *depth = u_minify(spr->base.depth0, level);
175 else
176 *depth = spr->base.array_size;
177
178 /* Make sure the resource and view have compatiable formats */
179 if (util_format_get_blocksize(pformat) >
180 util_format_get_blocksize(spr->base.format))
181 return false;
182 }
183 return true;
184 }
185
186 static void
fill_coords(const struct tgsi_image_params * params,unsigned index,const int s[TGSI_QUAD_SIZE],const int t[TGSI_QUAD_SIZE],const int r[TGSI_QUAD_SIZE],int * s_coord,int * t_coord,int * r_coord)187 fill_coords(const struct tgsi_image_params *params,
188 unsigned index,
189 const int s[TGSI_QUAD_SIZE],
190 const int t[TGSI_QUAD_SIZE],
191 const int r[TGSI_QUAD_SIZE],
192 int *s_coord, int *t_coord, int *r_coord)
193 {
194 *s_coord = s[index];
195 *t_coord = has_1coord(params->tgsi_tex_instr) ? 0 : t[index];
196 *r_coord = has_layer_or_depth(params->tgsi_tex_instr) ?
197 (params->tgsi_tex_instr == TGSI_TEXTURE_1D_ARRAY ? t[index] : r[index]) : 0;
198 }
199 /*
200 * Implement the image LOAD operation.
201 */
202 static void
sp_tgsi_load(const struct tgsi_image * image,const struct tgsi_image_params * params,const int s[TGSI_QUAD_SIZE],const int t[TGSI_QUAD_SIZE],const int r[TGSI_QUAD_SIZE],const int sample[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])203 sp_tgsi_load(const struct tgsi_image *image,
204 const struct tgsi_image_params *params,
205 const int s[TGSI_QUAD_SIZE],
206 const int t[TGSI_QUAD_SIZE],
207 const int r[TGSI_QUAD_SIZE],
208 const int sample[TGSI_QUAD_SIZE],
209 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
210 {
211 struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
212 struct pipe_image_view *iview;
213 struct softpipe_resource *spr;
214 unsigned width, height, depth;
215 unsigned stride;
216 int c, j;
217 char *data_ptr;
218 unsigned offset = 0;
219
220 if (params->unit >= PIPE_MAX_SHADER_IMAGES)
221 goto fail_write_all_zero;
222 iview = &sp_img->sp_iview[params->unit];
223 spr = (struct softpipe_resource *)iview->resource;
224 if (!spr)
225 goto fail_write_all_zero;
226
227 if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
228 goto fail_write_all_zero;
229
230 if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
231 params->format, &width, &height, &depth))
232 return;
233
234 stride = util_format_get_stride(params->format, width);
235
236 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
237 int s_coord, t_coord, r_coord;
238 bool fill_zero = false;
239
240 if (!(params->execmask & (1 << j)))
241 fill_zero = true;
242
243 fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
244 if (!bounds_check(width, height, depth,
245 s_coord, t_coord, r_coord))
246 fill_zero = true;
247
248 if (fill_zero) {
249 int nc = util_format_get_nr_components(params->format);
250 int ival = util_format_is_pure_integer(params->format);
251 for (c = 0; c < 4; c++) {
252 rgba[c][j] = 0;
253 if (c == 3 && nc < 4) {
254 if (ival)
255 ((int32_t *)rgba[c])[j] = 1;
256 else
257 rgba[c][j] = 1.0;
258 }
259 }
260 continue;
261 }
262 offset = get_image_offset(spr, iview, params->format, r_coord);
263 data_ptr = (char *)spr->data + offset;
264
265 if (util_format_is_pure_sint(params->format)) {
266 int32_t sdata[4];
267
268 util_format_read_4i(params->format,
269 sdata, 0,
270 data_ptr, stride,
271 s_coord, t_coord, 1, 1);
272 for (c = 0; c < 4; c++)
273 ((int32_t *)rgba[c])[j] = sdata[c];
274 } else if (util_format_is_pure_uint(params->format)) {
275 uint32_t sdata[4];
276 util_format_read_4ui(params->format,
277 sdata, 0,
278 data_ptr, stride,
279 s_coord, t_coord, 1, 1);
280 for (c = 0; c < 4; c++)
281 ((uint32_t *)rgba[c])[j] = sdata[c];
282 } else {
283 float sdata[4];
284 util_format_read_4f(params->format,
285 sdata, 0,
286 data_ptr, stride,
287 s_coord, t_coord, 1, 1);
288 for (c = 0; c < 4; c++)
289 rgba[c][j] = sdata[c];
290 }
291 }
292 return;
293 fail_write_all_zero:
294 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
295 for (c = 0; c < 4; c++)
296 rgba[c][j] = 0;
297 }
298 return;
299 }
300
301 /*
302 * Implement the image STORE operation.
303 */
304 static void
sp_tgsi_store(const struct tgsi_image * image,const struct tgsi_image_params * params,const int s[TGSI_QUAD_SIZE],const int t[TGSI_QUAD_SIZE],const int r[TGSI_QUAD_SIZE],const int sample[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])305 sp_tgsi_store(const struct tgsi_image *image,
306 const struct tgsi_image_params *params,
307 const int s[TGSI_QUAD_SIZE],
308 const int t[TGSI_QUAD_SIZE],
309 const int r[TGSI_QUAD_SIZE],
310 const int sample[TGSI_QUAD_SIZE],
311 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
312 {
313 struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
314 struct pipe_image_view *iview;
315 struct softpipe_resource *spr;
316 unsigned width, height, depth;
317 unsigned stride;
318 char *data_ptr;
319 int j, c;
320 unsigned offset = 0;
321 unsigned pformat = params->format;
322
323 if (params->unit >= PIPE_MAX_SHADER_IMAGES)
324 return;
325 iview = &sp_img->sp_iview[params->unit];
326 spr = (struct softpipe_resource *)iview->resource;
327 if (!spr)
328 return;
329 if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
330 return;
331
332 if (params->format == PIPE_FORMAT_NONE)
333 pformat = spr->base.format;
334
335 if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
336 pformat, &width, &height, &depth))
337 return;
338
339 stride = util_format_get_stride(pformat, width);
340
341 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
342 int s_coord, t_coord, r_coord;
343
344 if (!(params->execmask & (1 << j)))
345 continue;
346
347 fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
348 if (!bounds_check(width, height, depth,
349 s_coord, t_coord, r_coord))
350 continue;
351
352 offset = get_image_offset(spr, iview, pformat, r_coord);
353 data_ptr = (char *)spr->data + offset;
354
355 if (util_format_is_pure_sint(pformat)) {
356 int32_t sdata[4];
357 for (c = 0; c < 4; c++)
358 sdata[c] = ((int32_t *)rgba[c])[j];
359 util_format_write_4i(pformat, sdata, 0, data_ptr, stride,
360 s_coord, t_coord, 1, 1);
361 } else if (util_format_is_pure_uint(pformat)) {
362 uint32_t sdata[4];
363 for (c = 0; c < 4; c++)
364 sdata[c] = ((uint32_t *)rgba[c])[j];
365 util_format_write_4ui(pformat, sdata, 0, data_ptr, stride,
366 s_coord, t_coord, 1, 1);
367 } else {
368 float sdata[4];
369 for (c = 0; c < 4; c++)
370 sdata[c] = rgba[c][j];
371 util_format_write_4f(pformat, sdata, 0, data_ptr, stride,
372 s_coord, t_coord, 1, 1);
373 }
374 }
375 }
376
377 /*
378 * Implement atomic operations on unsigned integers.
379 */
380 static void
handle_op_uint(const struct pipe_image_view * iview,const struct tgsi_image_params * params,bool just_read,char * data_ptr,uint qi,unsigned stride,unsigned opcode,int s,int t,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])381 handle_op_uint(const struct pipe_image_view *iview,
382 const struct tgsi_image_params *params,
383 bool just_read,
384 char *data_ptr,
385 uint qi,
386 unsigned stride,
387 unsigned opcode,
388 int s,
389 int t,
390 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
391 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
392 {
393 uint c;
394 int nc = util_format_get_nr_components(params->format);
395 unsigned sdata[4];
396
397 util_format_read_4ui(params->format,
398 sdata, 0,
399 data_ptr, stride,
400 s, t, 1, 1);
401
402 if (just_read) {
403 for (c = 0; c < nc; c++) {
404 ((uint32_t *)rgba[c])[qi] = sdata[c];
405 }
406 return;
407 }
408 switch (opcode) {
409 case TGSI_OPCODE_ATOMUADD:
410 for (c = 0; c < nc; c++) {
411 unsigned temp = sdata[c];
412 sdata[c] += ((uint32_t *)rgba[c])[qi];
413 ((uint32_t *)rgba[c])[qi] = temp;
414 }
415 break;
416 case TGSI_OPCODE_ATOMXCHG:
417 for (c = 0; c < nc; c++) {
418 unsigned temp = sdata[c];
419 sdata[c] = ((uint32_t *)rgba[c])[qi];
420 ((uint32_t *)rgba[c])[qi] = temp;
421 }
422 break;
423 case TGSI_OPCODE_ATOMCAS:
424 for (c = 0; c < nc; c++) {
425 unsigned dst_x = sdata[c];
426 unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
427 unsigned src_x = ((uint32_t *)rgba2[c])[qi];
428 unsigned temp = sdata[c];
429 sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
430 ((uint32_t *)rgba[c])[qi] = temp;
431 }
432 break;
433 case TGSI_OPCODE_ATOMAND:
434 for (c = 0; c < nc; c++) {
435 unsigned temp = sdata[c];
436 sdata[c] &= ((uint32_t *)rgba[c])[qi];
437 ((uint32_t *)rgba[c])[qi] = temp;
438 }
439 break;
440 case TGSI_OPCODE_ATOMOR:
441 for (c = 0; c < nc; c++) {
442 unsigned temp = sdata[c];
443 sdata[c] |= ((uint32_t *)rgba[c])[qi];
444 ((uint32_t *)rgba[c])[qi] = temp;
445 }
446 break;
447 case TGSI_OPCODE_ATOMXOR:
448 for (c = 0; c < nc; c++) {
449 unsigned temp = sdata[c];
450 sdata[c] ^= ((uint32_t *)rgba[c])[qi];
451 ((uint32_t *)rgba[c])[qi] = temp;
452 }
453 break;
454 case TGSI_OPCODE_ATOMUMIN:
455 for (c = 0; c < nc; c++) {
456 unsigned dst_x = sdata[c];
457 unsigned src_x = ((uint32_t *)rgba[c])[qi];
458 sdata[c] = MIN2(dst_x, src_x);
459 ((uint32_t *)rgba[c])[qi] = dst_x;
460 }
461 break;
462 case TGSI_OPCODE_ATOMUMAX:
463 for (c = 0; c < nc; c++) {
464 unsigned dst_x = sdata[c];
465 unsigned src_x = ((uint32_t *)rgba[c])[qi];
466 sdata[c] = MAX2(dst_x, src_x);
467 ((uint32_t *)rgba[c])[qi] = dst_x;
468 }
469 break;
470 case TGSI_OPCODE_ATOMIMIN:
471 for (c = 0; c < nc; c++) {
472 int dst_x = sdata[c];
473 int src_x = ((uint32_t *)rgba[c])[qi];
474 sdata[c] = MIN2(dst_x, src_x);
475 ((uint32_t *)rgba[c])[qi] = dst_x;
476 }
477 break;
478 case TGSI_OPCODE_ATOMIMAX:
479 for (c = 0; c < nc; c++) {
480 int dst_x = sdata[c];
481 int src_x = ((uint32_t *)rgba[c])[qi];
482 sdata[c] = MAX2(dst_x, src_x);
483 ((uint32_t *)rgba[c])[qi] = dst_x;
484 }
485 break;
486 default:
487 assert(!"Unexpected TGSI opcode in sp_tgsi_op");
488 break;
489 }
490 util_format_write_4ui(params->format, sdata, 0, data_ptr, stride,
491 s, t, 1, 1);
492 }
493
494 /*
495 * Implement atomic operations on signed integers.
496 */
497 static void
handle_op_int(const struct pipe_image_view * iview,const struct tgsi_image_params * params,bool just_read,char * data_ptr,uint qi,unsigned stride,unsigned opcode,int s,int t,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])498 handle_op_int(const struct pipe_image_view *iview,
499 const struct tgsi_image_params *params,
500 bool just_read,
501 char *data_ptr,
502 uint qi,
503 unsigned stride,
504 unsigned opcode,
505 int s,
506 int t,
507 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
508 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
509 {
510 uint c;
511 int nc = util_format_get_nr_components(params->format);
512 int sdata[4];
513 util_format_read_4i(params->format,
514 sdata, 0,
515 data_ptr, stride,
516 s, t, 1, 1);
517
518 if (just_read) {
519 for (c = 0; c < nc; c++) {
520 ((int32_t *)rgba[c])[qi] = sdata[c];
521 }
522 return;
523 }
524 switch (opcode) {
525 case TGSI_OPCODE_ATOMUADD:
526 for (c = 0; c < nc; c++) {
527 int temp = sdata[c];
528 sdata[c] += ((int32_t *)rgba[c])[qi];
529 ((int32_t *)rgba[c])[qi] = temp;
530 }
531 break;
532 case TGSI_OPCODE_ATOMXCHG:
533 for (c = 0; c < nc; c++) {
534 int temp = sdata[c];
535 sdata[c] = ((int32_t *)rgba[c])[qi];
536 ((int32_t *)rgba[c])[qi] = temp;
537 }
538 break;
539 case TGSI_OPCODE_ATOMCAS:
540 for (c = 0; c < nc; c++) {
541 int dst_x = sdata[c];
542 int cmp_x = ((int32_t *)rgba[c])[qi];
543 int src_x = ((int32_t *)rgba2[c])[qi];
544 int temp = sdata[c];
545 sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
546 ((int32_t *)rgba[c])[qi] = temp;
547 }
548 break;
549 case TGSI_OPCODE_ATOMAND:
550 for (c = 0; c < nc; c++) {
551 int temp = sdata[c];
552 sdata[c] &= ((int32_t *)rgba[c])[qi];
553 ((int32_t *)rgba[c])[qi] = temp;
554 }
555 break;
556 case TGSI_OPCODE_ATOMOR:
557 for (c = 0; c < nc; c++) {
558 int temp = sdata[c];
559 sdata[c] |= ((int32_t *)rgba[c])[qi];
560 ((int32_t *)rgba[c])[qi] = temp;
561 }
562 break;
563 case TGSI_OPCODE_ATOMXOR:
564 for (c = 0; c < nc; c++) {
565 int temp = sdata[c];
566 sdata[c] ^= ((int32_t *)rgba[c])[qi];
567 ((int32_t *)rgba[c])[qi] = temp;
568 }
569 break;
570 case TGSI_OPCODE_ATOMUMIN:
571 for (c = 0; c < nc; c++) {
572 int dst_x = sdata[c];
573 int src_x = ((int32_t *)rgba[c])[qi];
574 sdata[c] = MIN2(dst_x, src_x);
575 ((int32_t *)rgba[c])[qi] = dst_x;
576 }
577 break;
578 case TGSI_OPCODE_ATOMUMAX:
579 for (c = 0; c < nc; c++) {
580 int dst_x = sdata[c];
581 int src_x = ((int32_t *)rgba[c])[qi];
582 sdata[c] = MAX2(dst_x, src_x);
583 ((int32_t *)rgba[c])[qi] = dst_x;
584 }
585 break;
586 case TGSI_OPCODE_ATOMIMIN:
587 for (c = 0; c < nc; c++) {
588 int dst_x = sdata[c];
589 int src_x = ((int32_t *)rgba[c])[qi];
590 sdata[c] = MIN2(dst_x, src_x);
591 ((int32_t *)rgba[c])[qi] = dst_x;
592 }
593 break;
594 case TGSI_OPCODE_ATOMIMAX:
595 for (c = 0; c < nc; c++) {
596 int dst_x = sdata[c];
597 int src_x = ((int32_t *)rgba[c])[qi];
598 sdata[c] = MAX2(dst_x, src_x);
599 ((int32_t *)rgba[c])[qi] = dst_x;
600 }
601 break;
602 default:
603 assert(!"Unexpected TGSI opcode in sp_tgsi_op");
604 break;
605 }
606 util_format_write_4i(params->format, sdata, 0, data_ptr, stride,
607 s, t, 1, 1);
608 }
609
610 /* GLES OES_shader_image_atomic.txt allows XCHG on R32F */
611 static void
handle_op_r32f_xchg(const struct pipe_image_view * iview,const struct tgsi_image_params * params,bool just_read,char * data_ptr,uint qi,unsigned stride,unsigned opcode,int s,int t,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])612 handle_op_r32f_xchg(const struct pipe_image_view *iview,
613 const struct tgsi_image_params *params,
614 bool just_read,
615 char *data_ptr,
616 uint qi,
617 unsigned stride,
618 unsigned opcode,
619 int s,
620 int t,
621 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
622 {
623 float sdata[4];
624 uint c;
625 int nc = 1;
626 util_format_read_4f(params->format,
627 sdata, 0,
628 data_ptr, stride,
629 s, t, 1, 1);
630 if (just_read) {
631 for (c = 0; c < nc; c++) {
632 ((int32_t *)rgba[c])[qi] = sdata[c];
633 }
634 return;
635 }
636
637 for (c = 0; c < nc; c++) {
638 int temp = sdata[c];
639 sdata[c] = ((float *)rgba[c])[qi];
640 ((float *)rgba[c])[qi] = temp;
641 }
642 util_format_write_4f(params->format, sdata, 0, data_ptr, stride,
643 s, t, 1, 1);
644 }
645
646 /*
647 * Implement atomic image operations.
648 */
649 static void
sp_tgsi_op(const struct tgsi_image * image,const struct tgsi_image_params * params,unsigned opcode,const int s[TGSI_QUAD_SIZE],const int t[TGSI_QUAD_SIZE],const int r[TGSI_QUAD_SIZE],const int sample[TGSI_QUAD_SIZE],float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])650 sp_tgsi_op(const struct tgsi_image *image,
651 const struct tgsi_image_params *params,
652 unsigned opcode,
653 const int s[TGSI_QUAD_SIZE],
654 const int t[TGSI_QUAD_SIZE],
655 const int r[TGSI_QUAD_SIZE],
656 const int sample[TGSI_QUAD_SIZE],
657 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
658 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
659 {
660 struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
661 struct pipe_image_view *iview;
662 struct softpipe_resource *spr;
663 unsigned width, height, depth;
664 unsigned stride;
665 int j, c;
666 unsigned offset;
667 char *data_ptr;
668
669 if (params->unit >= PIPE_MAX_SHADER_IMAGES)
670 return;
671 iview = &sp_img->sp_iview[params->unit];
672 spr = (struct softpipe_resource *)iview->resource;
673 if (!spr)
674 goto fail_write_all_zero;
675 if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
676 goto fail_write_all_zero;
677
678 if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
679 params->format, &width, &height, &depth))
680 goto fail_write_all_zero;
681
682 stride = util_format_get_stride(spr->base.format, width);
683
684 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
685 int s_coord, t_coord, r_coord;
686 bool just_read = false;
687
688 fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
689 if (!bounds_check(width, height, depth,
690 s_coord, t_coord, r_coord)) {
691 int nc = util_format_get_nr_components(params->format);
692 int ival = util_format_is_pure_integer(params->format);
693 int c;
694 for (c = 0; c < 4; c++) {
695 rgba[c][j] = 0;
696 if (c == 3 && nc < 4) {
697 if (ival)
698 ((int32_t *)rgba[c])[j] = 1;
699 else
700 rgba[c][j] = 1.0;
701 }
702 }
703 continue;
704 }
705
706 /* just readback the value for atomic if execmask isn't set */
707 if (!(params->execmask & (1 << j))) {
708 just_read = true;
709 }
710
711 offset = get_image_offset(spr, iview, params->format, r_coord);
712 data_ptr = (char *)spr->data + offset;
713
714 /* we should see atomic operations on r32 formats */
715 if (util_format_is_pure_uint(params->format))
716 handle_op_uint(iview, params, just_read, data_ptr, j, stride,
717 opcode, s_coord, t_coord, rgba, rgba2);
718 else if (util_format_is_pure_sint(params->format))
719 handle_op_int(iview, params, just_read, data_ptr, j, stride,
720 opcode, s_coord, t_coord, rgba, rgba2);
721 else if (params->format == PIPE_FORMAT_R32_FLOAT &&
722 opcode == TGSI_OPCODE_ATOMXCHG)
723 handle_op_r32f_xchg(iview, params, just_read, data_ptr, j, stride,
724 opcode, s_coord, t_coord, rgba);
725 else
726 assert(0);
727 }
728 return;
729 fail_write_all_zero:
730 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
731 for (c = 0; c < 4; c++)
732 rgba[c][j] = 0;
733 }
734 return;
735 }
736
737 static void
sp_tgsi_get_dims(const struct tgsi_image * image,const struct tgsi_image_params * params,int dims[4])738 sp_tgsi_get_dims(const struct tgsi_image *image,
739 const struct tgsi_image_params *params,
740 int dims[4])
741 {
742 struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
743 struct pipe_image_view *iview;
744 struct softpipe_resource *spr;
745 int level;
746
747 if (params->unit >= PIPE_MAX_SHADER_IMAGES)
748 return;
749 iview = &sp_img->sp_iview[params->unit];
750 spr = (struct softpipe_resource *)iview->resource;
751 if (!spr)
752 return;
753
754 if (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
755 dims[0] = iview->u.buf.size / util_format_get_blocksize(iview->format);
756 dims[1] = dims[2] = dims[3] = 0;
757 return;
758 }
759
760 level = iview->u.tex.level;
761 dims[0] = u_minify(spr->base.width0, level);
762 switch (params->tgsi_tex_instr) {
763 case TGSI_TEXTURE_1D_ARRAY:
764 dims[1] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
765 /* fallthrough */
766 case TGSI_TEXTURE_1D:
767 return;
768 case TGSI_TEXTURE_2D_ARRAY:
769 dims[2] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
770 /* fallthrough */
771 case TGSI_TEXTURE_2D:
772 case TGSI_TEXTURE_CUBE:
773 case TGSI_TEXTURE_RECT:
774 dims[1] = u_minify(spr->base.height0, level);
775 return;
776 case TGSI_TEXTURE_3D:
777 dims[1] = u_minify(spr->base.height0, level);
778 dims[2] = u_minify(spr->base.depth0, level);
779 return;
780 case TGSI_TEXTURE_CUBE_ARRAY:
781 dims[1] = u_minify(spr->base.height0, level);
782 dims[2] = (iview->u.tex.last_layer - iview->u.tex.first_layer + 1) / 6;
783 break;
784 default:
785 assert(!"unexpected texture target in sp_get_dims()");
786 return;
787 }
788 }
789
790 struct sp_tgsi_image *
sp_create_tgsi_image(void)791 sp_create_tgsi_image(void)
792 {
793 struct sp_tgsi_image *img = CALLOC_STRUCT(sp_tgsi_image);
794 if (!img)
795 return NULL;
796
797 img->base.load = sp_tgsi_load;
798 img->base.store = sp_tgsi_store;
799 img->base.op = sp_tgsi_op;
800 img->base.get_dims = sp_tgsi_get_dims;
801 return img;
802 };
803