• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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