util: Merge util_format_write_4* functions.
[mesa.git] / src / gallium / drivers / softpipe / sp_image.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_image.h"
26 #include "sp_texture.h"
27
28 #include "util/format/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
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
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
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
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
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
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
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
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
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 uint32_t sdata[4];
356 for (c = 0; c < 4; c++)
357 sdata[c] = ((uint32_t *)rgba[c])[j];
358 util_format_write_4(pformat, sdata, 0, data_ptr, stride,
359 s_coord, t_coord, 1, 1);
360 }
361 }
362
363 /*
364 * Implement atomic operations on unsigned integers.
365 */
366 static void
367 handle_op_uint(const struct pipe_image_view *iview,
368 const struct tgsi_image_params *params,
369 bool just_read,
370 char *data_ptr,
371 uint qi,
372 unsigned stride,
373 enum tgsi_opcode opcode,
374 int s,
375 int t,
376 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
377 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
378 {
379 uint c;
380 int nc = util_format_get_nr_components(params->format);
381 unsigned sdata[4];
382
383 util_format_read_4ui(params->format,
384 sdata, 0,
385 data_ptr, stride,
386 s, t, 1, 1);
387
388 if (just_read) {
389 for (c = 0; c < nc; c++) {
390 ((uint32_t *)rgba[c])[qi] = sdata[c];
391 }
392 return;
393 }
394 switch (opcode) {
395 case TGSI_OPCODE_ATOMUADD:
396 for (c = 0; c < nc; c++) {
397 unsigned temp = sdata[c];
398 sdata[c] += ((uint32_t *)rgba[c])[qi];
399 ((uint32_t *)rgba[c])[qi] = temp;
400 }
401 break;
402 case TGSI_OPCODE_ATOMXCHG:
403 for (c = 0; c < nc; c++) {
404 unsigned temp = sdata[c];
405 sdata[c] = ((uint32_t *)rgba[c])[qi];
406 ((uint32_t *)rgba[c])[qi] = temp;
407 }
408 break;
409 case TGSI_OPCODE_ATOMCAS:
410 for (c = 0; c < nc; c++) {
411 unsigned dst_x = sdata[c];
412 unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
413 unsigned src_x = ((uint32_t *)rgba2[c])[qi];
414 unsigned temp = sdata[c];
415 sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
416 ((uint32_t *)rgba[c])[qi] = temp;
417 }
418 break;
419 case TGSI_OPCODE_ATOMAND:
420 for (c = 0; c < nc; c++) {
421 unsigned temp = sdata[c];
422 sdata[c] &= ((uint32_t *)rgba[c])[qi];
423 ((uint32_t *)rgba[c])[qi] = temp;
424 }
425 break;
426 case TGSI_OPCODE_ATOMOR:
427 for (c = 0; c < nc; c++) {
428 unsigned temp = sdata[c];
429 sdata[c] |= ((uint32_t *)rgba[c])[qi];
430 ((uint32_t *)rgba[c])[qi] = temp;
431 }
432 break;
433 case TGSI_OPCODE_ATOMXOR:
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_ATOMUMIN:
441 for (c = 0; c < nc; c++) {
442 unsigned dst_x = sdata[c];
443 unsigned src_x = ((uint32_t *)rgba[c])[qi];
444 sdata[c] = MIN2(dst_x, src_x);
445 ((uint32_t *)rgba[c])[qi] = dst_x;
446 }
447 break;
448 case TGSI_OPCODE_ATOMUMAX:
449 for (c = 0; c < nc; c++) {
450 unsigned dst_x = sdata[c];
451 unsigned src_x = ((uint32_t *)rgba[c])[qi];
452 sdata[c] = MAX2(dst_x, src_x);
453 ((uint32_t *)rgba[c])[qi] = dst_x;
454 }
455 break;
456 case TGSI_OPCODE_ATOMIMIN:
457 for (c = 0; c < nc; c++) {
458 int dst_x = sdata[c];
459 int src_x = ((uint32_t *)rgba[c])[qi];
460 sdata[c] = MIN2(dst_x, src_x);
461 ((uint32_t *)rgba[c])[qi] = dst_x;
462 }
463 break;
464 case TGSI_OPCODE_ATOMIMAX:
465 for (c = 0; c < nc; c++) {
466 int dst_x = sdata[c];
467 int src_x = ((uint32_t *)rgba[c])[qi];
468 sdata[c] = MAX2(dst_x, src_x);
469 ((uint32_t *)rgba[c])[qi] = dst_x;
470 }
471 break;
472 default:
473 assert(!"Unexpected TGSI opcode in sp_tgsi_op");
474 break;
475 }
476 util_format_write_4(params->format, sdata, 0, data_ptr, stride,
477 s, t, 1, 1);
478 }
479
480 /*
481 * Implement atomic operations on signed integers.
482 */
483 static void
484 handle_op_int(const struct pipe_image_view *iview,
485 const struct tgsi_image_params *params,
486 bool just_read,
487 char *data_ptr,
488 uint qi,
489 unsigned stride,
490 enum tgsi_opcode opcode,
491 int s,
492 int t,
493 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
494 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
495 {
496 uint c;
497 int nc = util_format_get_nr_components(params->format);
498 int sdata[4];
499 util_format_read_4i(params->format,
500 sdata, 0,
501 data_ptr, stride,
502 s, t, 1, 1);
503
504 if (just_read) {
505 for (c = 0; c < nc; c++) {
506 ((int32_t *)rgba[c])[qi] = sdata[c];
507 }
508 return;
509 }
510 switch (opcode) {
511 case TGSI_OPCODE_ATOMUADD:
512 for (c = 0; c < nc; c++) {
513 int temp = sdata[c];
514 sdata[c] += ((int32_t *)rgba[c])[qi];
515 ((int32_t *)rgba[c])[qi] = temp;
516 }
517 break;
518 case TGSI_OPCODE_ATOMXCHG:
519 for (c = 0; c < nc; c++) {
520 int temp = sdata[c];
521 sdata[c] = ((int32_t *)rgba[c])[qi];
522 ((int32_t *)rgba[c])[qi] = temp;
523 }
524 break;
525 case TGSI_OPCODE_ATOMCAS:
526 for (c = 0; c < nc; c++) {
527 int dst_x = sdata[c];
528 int cmp_x = ((int32_t *)rgba[c])[qi];
529 int src_x = ((int32_t *)rgba2[c])[qi];
530 int temp = sdata[c];
531 sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
532 ((int32_t *)rgba[c])[qi] = temp;
533 }
534 break;
535 case TGSI_OPCODE_ATOMAND:
536 for (c = 0; c < nc; c++) {
537 int temp = sdata[c];
538 sdata[c] &= ((int32_t *)rgba[c])[qi];
539 ((int32_t *)rgba[c])[qi] = temp;
540 }
541 break;
542 case TGSI_OPCODE_ATOMOR:
543 for (c = 0; c < nc; c++) {
544 int temp = sdata[c];
545 sdata[c] |= ((int32_t *)rgba[c])[qi];
546 ((int32_t *)rgba[c])[qi] = temp;
547 }
548 break;
549 case TGSI_OPCODE_ATOMXOR:
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_ATOMUMIN:
557 for (c = 0; c < nc; c++) {
558 int dst_x = sdata[c];
559 int src_x = ((int32_t *)rgba[c])[qi];
560 sdata[c] = MIN2(dst_x, src_x);
561 ((int32_t *)rgba[c])[qi] = dst_x;
562 }
563 break;
564 case TGSI_OPCODE_ATOMUMAX:
565 for (c = 0; c < nc; c++) {
566 int dst_x = sdata[c];
567 int src_x = ((int32_t *)rgba[c])[qi];
568 sdata[c] = MAX2(dst_x, src_x);
569 ((int32_t *)rgba[c])[qi] = dst_x;
570 }
571 break;
572 case TGSI_OPCODE_ATOMIMIN:
573 for (c = 0; c < nc; c++) {
574 int dst_x = sdata[c];
575 int src_x = ((int32_t *)rgba[c])[qi];
576 sdata[c] = MIN2(dst_x, src_x);
577 ((int32_t *)rgba[c])[qi] = dst_x;
578 }
579 break;
580 case TGSI_OPCODE_ATOMIMAX:
581 for (c = 0; c < nc; c++) {
582 int dst_x = sdata[c];
583 int src_x = ((int32_t *)rgba[c])[qi];
584 sdata[c] = MAX2(dst_x, src_x);
585 ((int32_t *)rgba[c])[qi] = dst_x;
586 }
587 break;
588 default:
589 assert(!"Unexpected TGSI opcode in sp_tgsi_op");
590 break;
591 }
592 util_format_write_4(params->format, sdata, 0, data_ptr, stride,
593 s, t, 1, 1);
594 }
595
596 /* GLES OES_shader_image_atomic.txt allows XCHG on R32F */
597 static void
598 handle_op_r32f_xchg(const struct pipe_image_view *iview,
599 const struct tgsi_image_params *params,
600 bool just_read,
601 char *data_ptr,
602 uint qi,
603 unsigned stride,
604 enum tgsi_opcode opcode,
605 int s,
606 int t,
607 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
608 {
609 float sdata[4];
610 uint c;
611 int nc = 1;
612 util_format_read_4f(params->format,
613 sdata, 0,
614 data_ptr, stride,
615 s, t, 1, 1);
616 if (just_read) {
617 for (c = 0; c < nc; c++) {
618 ((int32_t *)rgba[c])[qi] = sdata[c];
619 }
620 return;
621 }
622
623 for (c = 0; c < nc; c++) {
624 int temp = sdata[c];
625 sdata[c] = ((float *)rgba[c])[qi];
626 ((float *)rgba[c])[qi] = temp;
627 }
628 util_format_write_4(params->format, sdata, 0, data_ptr, stride,
629 s, t, 1, 1);
630 }
631
632 /*
633 * Implement atomic image operations.
634 */
635 static void
636 sp_tgsi_op(const struct tgsi_image *image,
637 const struct tgsi_image_params *params,
638 enum tgsi_opcode opcode,
639 const int s[TGSI_QUAD_SIZE],
640 const int t[TGSI_QUAD_SIZE],
641 const int r[TGSI_QUAD_SIZE],
642 const int sample[TGSI_QUAD_SIZE],
643 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
644 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
645 {
646 struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
647 struct pipe_image_view *iview;
648 struct softpipe_resource *spr;
649 unsigned width, height, depth;
650 unsigned stride;
651 int j, c;
652 unsigned offset;
653 char *data_ptr;
654
655 if (params->unit >= PIPE_MAX_SHADER_IMAGES)
656 return;
657 iview = &sp_img->sp_iview[params->unit];
658 spr = (struct softpipe_resource *)iview->resource;
659 if (!spr)
660 goto fail_write_all_zero;
661 if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
662 goto fail_write_all_zero;
663
664 if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
665 params->format, &width, &height, &depth))
666 goto fail_write_all_zero;
667
668 stride = util_format_get_stride(spr->base.format, width);
669
670 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
671 int s_coord, t_coord, r_coord;
672 bool just_read = false;
673
674 fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
675 if (!bounds_check(width, height, depth,
676 s_coord, t_coord, r_coord)) {
677 int nc = util_format_get_nr_components(params->format);
678 int ival = util_format_is_pure_integer(params->format);
679 int c;
680 for (c = 0; c < 4; c++) {
681 rgba[c][j] = 0;
682 if (c == 3 && nc < 4) {
683 if (ival)
684 ((int32_t *)rgba[c])[j] = 1;
685 else
686 rgba[c][j] = 1.0;
687 }
688 }
689 continue;
690 }
691
692 /* just readback the value for atomic if execmask isn't set */
693 if (!(params->execmask & (1 << j))) {
694 just_read = true;
695 }
696
697 offset = get_image_offset(spr, iview, params->format, r_coord);
698 data_ptr = (char *)spr->data + offset;
699
700 /* we should see atomic operations on r32 formats */
701 if (util_format_is_pure_uint(params->format))
702 handle_op_uint(iview, params, just_read, data_ptr, j, stride,
703 opcode, s_coord, t_coord, rgba, rgba2);
704 else if (util_format_is_pure_sint(params->format))
705 handle_op_int(iview, params, just_read, data_ptr, j, stride,
706 opcode, s_coord, t_coord, rgba, rgba2);
707 else if (params->format == PIPE_FORMAT_R32_FLOAT &&
708 opcode == TGSI_OPCODE_ATOMXCHG)
709 handle_op_r32f_xchg(iview, params, just_read, data_ptr, j, stride,
710 opcode, s_coord, t_coord, rgba);
711 else
712 assert(0);
713 }
714 return;
715 fail_write_all_zero:
716 for (j = 0; j < TGSI_QUAD_SIZE; j++) {
717 for (c = 0; c < 4; c++)
718 rgba[c][j] = 0;
719 }
720 return;
721 }
722
723 static void
724 sp_tgsi_get_dims(const struct tgsi_image *image,
725 const struct tgsi_image_params *params,
726 int dims[4])
727 {
728 struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
729 struct pipe_image_view *iview;
730 struct softpipe_resource *spr;
731 int level;
732
733 if (params->unit >= PIPE_MAX_SHADER_IMAGES)
734 return;
735 iview = &sp_img->sp_iview[params->unit];
736 spr = (struct softpipe_resource *)iview->resource;
737 if (!spr)
738 return;
739
740 if (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
741 dims[0] = iview->u.buf.size / util_format_get_blocksize(iview->format);
742 dims[1] = dims[2] = dims[3] = 0;
743 return;
744 }
745
746 level = iview->u.tex.level;
747 dims[0] = u_minify(spr->base.width0, level);
748 switch (params->tgsi_tex_instr) {
749 case TGSI_TEXTURE_1D_ARRAY:
750 dims[1] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
751 /* fallthrough */
752 case TGSI_TEXTURE_1D:
753 return;
754 case TGSI_TEXTURE_2D_ARRAY:
755 dims[2] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
756 /* fallthrough */
757 case TGSI_TEXTURE_2D:
758 case TGSI_TEXTURE_CUBE:
759 case TGSI_TEXTURE_RECT:
760 dims[1] = u_minify(spr->base.height0, level);
761 return;
762 case TGSI_TEXTURE_3D:
763 dims[1] = u_minify(spr->base.height0, level);
764 dims[2] = u_minify(spr->base.depth0, level);
765 return;
766 case TGSI_TEXTURE_CUBE_ARRAY:
767 dims[1] = u_minify(spr->base.height0, level);
768 dims[2] = (iview->u.tex.last_layer - iview->u.tex.first_layer + 1) / 6;
769 break;
770 default:
771 assert(!"unexpected texture target in sp_get_dims()");
772 return;
773 }
774 }
775
776 struct sp_tgsi_image *
777 sp_create_tgsi_image(void)
778 {
779 struct sp_tgsi_image *img = CALLOC_STRUCT(sp_tgsi_image);
780 if (!img)
781 return NULL;
782
783 img->base.load = sp_tgsi_load;
784 img->base.store = sp_tgsi_store;
785 img->base.op = sp_tgsi_op;
786 img->base.get_dims = sp_tgsi_get_dims;
787 return img;
788 };