• 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/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
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       uint32_t sdata[4];
266       util_format_read_4(params->format,
267                          sdata, 0,
268                          data_ptr, stride,
269                          s_coord, t_coord, 1, 1);
270       for (c = 0; c < 4; c++)
271          ((uint32_t *)rgba[c])[j] = sdata[c];
272    }
273    return;
274 fail_write_all_zero:
275    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
276       for (c = 0; c < 4; c++)
277          rgba[c][j] = 0;
278    }
279    return;
280 }
281 
282 /*
283  * Implement the image STORE operation.
284  */
285 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])286 sp_tgsi_store(const struct tgsi_image *image,
287               const struct tgsi_image_params *params,
288               const int s[TGSI_QUAD_SIZE],
289               const int t[TGSI_QUAD_SIZE],
290               const int r[TGSI_QUAD_SIZE],
291               const int sample[TGSI_QUAD_SIZE],
292               float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
293 {
294    struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
295    struct pipe_image_view *iview;
296    struct softpipe_resource *spr;
297    unsigned width, height, depth;
298    unsigned stride;
299    char *data_ptr;
300    int j, c;
301    unsigned offset = 0;
302    unsigned pformat = params->format;
303 
304    if (params->unit >= PIPE_MAX_SHADER_IMAGES)
305       return;
306    iview = &sp_img->sp_iview[params->unit];
307    spr = (struct softpipe_resource *)iview->resource;
308    if (!spr)
309       return;
310    if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
311       return;
312 
313    if (params->format == PIPE_FORMAT_NONE)
314       pformat = spr->base.format;
315 
316    if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
317                        pformat, &width, &height, &depth))
318       return;
319 
320    stride = util_format_get_stride(pformat, width);
321 
322    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
323       int s_coord, t_coord, r_coord;
324 
325       if (!(params->execmask & (1 << j)))
326          continue;
327 
328       fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
329       if (!bounds_check(width, height, depth,
330                         s_coord, t_coord, r_coord))
331          continue;
332 
333       offset = get_image_offset(spr, iview, pformat, r_coord);
334       data_ptr = (char *)spr->data + offset;
335 
336       uint32_t sdata[4];
337       for (c = 0; c < 4; c++)
338          sdata[c] = ((uint32_t *)rgba[c])[j];
339       util_format_write_4(pformat, sdata, 0, data_ptr, stride,
340                           s_coord, t_coord, 1, 1);
341    }
342 }
343 
344 /*
345  * Implement atomic operations on unsigned integers.
346  */
347 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,enum tgsi_opcode opcode,int s,int t,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])348 handle_op_uint(const struct pipe_image_view *iview,
349                const struct tgsi_image_params *params,
350                bool just_read,
351                char *data_ptr,
352                uint qi,
353                unsigned stride,
354                enum tgsi_opcode opcode,
355                int s,
356                int t,
357                float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
358                float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
359 {
360    uint c;
361    int nc = util_format_get_nr_components(params->format);
362    unsigned sdata[4];
363 
364    util_format_read_4(params->format,
365                       sdata, 0,
366                       data_ptr, stride,
367                       s, t, 1, 1);
368 
369    if (just_read) {
370       for (c = 0; c < nc; c++) {
371          ((uint32_t *)rgba[c])[qi] = sdata[c];
372       }
373       return;
374    }
375    switch (opcode) {
376    case TGSI_OPCODE_ATOMUADD:
377       for (c = 0; c < nc; c++) {
378          unsigned temp = sdata[c];
379          sdata[c] += ((uint32_t *)rgba[c])[qi];
380          ((uint32_t *)rgba[c])[qi] = temp;
381       }
382       break;
383    case TGSI_OPCODE_ATOMXCHG:
384       for (c = 0; c < nc; c++) {
385          unsigned temp = sdata[c];
386          sdata[c] = ((uint32_t *)rgba[c])[qi];
387          ((uint32_t *)rgba[c])[qi] = temp;
388       }
389       break;
390    case TGSI_OPCODE_ATOMCAS:
391       for (c = 0; c < nc; c++) {
392          unsigned dst_x = sdata[c];
393          unsigned cmp_x = ((uint32_t *)rgba[c])[qi];
394          unsigned src_x = ((uint32_t *)rgba2[c])[qi];
395          unsigned temp = sdata[c];
396          sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
397          ((uint32_t *)rgba[c])[qi] = temp;
398       }
399       break;
400    case TGSI_OPCODE_ATOMAND:
401       for (c = 0; c < nc; c++) {
402          unsigned temp = sdata[c];
403          sdata[c] &= ((uint32_t *)rgba[c])[qi];
404          ((uint32_t *)rgba[c])[qi] = temp;
405       }
406       break;
407    case TGSI_OPCODE_ATOMOR:
408       for (c = 0; c < nc; c++) {
409          unsigned temp = sdata[c];
410          sdata[c] |= ((uint32_t *)rgba[c])[qi];
411          ((uint32_t *)rgba[c])[qi] = temp;
412       }
413       break;
414    case TGSI_OPCODE_ATOMXOR:
415       for (c = 0; c < nc; c++) {
416          unsigned temp = sdata[c];
417          sdata[c] ^= ((uint32_t *)rgba[c])[qi];
418          ((uint32_t *)rgba[c])[qi] = temp;
419       }
420       break;
421    case TGSI_OPCODE_ATOMUMIN:
422       for (c = 0; c < nc; c++) {
423          unsigned dst_x = sdata[c];
424          unsigned src_x = ((uint32_t *)rgba[c])[qi];
425          sdata[c] = MIN2(dst_x, src_x);
426          ((uint32_t *)rgba[c])[qi] = dst_x;
427       }
428       break;
429    case TGSI_OPCODE_ATOMUMAX:
430       for (c = 0; c < nc; c++) {
431          unsigned dst_x = sdata[c];
432          unsigned src_x = ((uint32_t *)rgba[c])[qi];
433          sdata[c] = MAX2(dst_x, src_x);
434          ((uint32_t *)rgba[c])[qi] = dst_x;
435       }
436       break;
437    case TGSI_OPCODE_ATOMIMIN:
438       for (c = 0; c < nc; c++) {
439          int dst_x = sdata[c];
440          int src_x = ((uint32_t *)rgba[c])[qi];
441          sdata[c] = MIN2(dst_x, src_x);
442          ((uint32_t *)rgba[c])[qi] = dst_x;
443       }
444       break;
445    case TGSI_OPCODE_ATOMIMAX:
446       for (c = 0; c < nc; c++) {
447          int dst_x = sdata[c];
448          int src_x = ((uint32_t *)rgba[c])[qi];
449          sdata[c] = MAX2(dst_x, src_x);
450          ((uint32_t *)rgba[c])[qi] = dst_x;
451       }
452       break;
453    default:
454       assert(!"Unexpected TGSI opcode in sp_tgsi_op");
455       break;
456    }
457    util_format_write_4(params->format, sdata, 0, data_ptr, stride,
458                        s, t, 1, 1);
459 }
460 
461 /*
462  * Implement atomic operations on signed integers.
463  */
464 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,enum tgsi_opcode opcode,int s,int t,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])465 handle_op_int(const struct pipe_image_view *iview,
466               const struct tgsi_image_params *params,
467               bool just_read,
468               char *data_ptr,
469               uint qi,
470               unsigned stride,
471               enum tgsi_opcode opcode,
472               int s,
473               int t,
474               float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
475               float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
476 {
477    uint c;
478    int nc = util_format_get_nr_components(params->format);
479    int sdata[4];
480    util_format_read_4(params->format,
481                       sdata, 0,
482                       data_ptr, stride,
483                       s, t, 1, 1);
484 
485    if (just_read) {
486       for (c = 0; c < nc; c++) {
487          ((int32_t *)rgba[c])[qi] = sdata[c];
488       }
489       return;
490    }
491    switch (opcode) {
492    case TGSI_OPCODE_ATOMUADD:
493       for (c = 0; c < nc; c++) {
494          int temp = sdata[c];
495          sdata[c] += ((int32_t *)rgba[c])[qi];
496          ((int32_t *)rgba[c])[qi] = temp;
497       }
498       break;
499    case TGSI_OPCODE_ATOMXCHG:
500       for (c = 0; c < nc; c++) {
501          int temp = sdata[c];
502          sdata[c] = ((int32_t *)rgba[c])[qi];
503          ((int32_t *)rgba[c])[qi] = temp;
504       }
505       break;
506    case TGSI_OPCODE_ATOMCAS:
507       for (c = 0; c < nc; c++) {
508          int dst_x = sdata[c];
509          int cmp_x = ((int32_t *)rgba[c])[qi];
510          int src_x = ((int32_t *)rgba2[c])[qi];
511          int temp = sdata[c];
512          sdata[c] = (dst_x == cmp_x) ? src_x : dst_x;
513          ((int32_t *)rgba[c])[qi] = temp;
514       }
515       break;
516    case TGSI_OPCODE_ATOMAND:
517       for (c = 0; c < nc; c++) {
518          int temp = sdata[c];
519          sdata[c] &= ((int32_t *)rgba[c])[qi];
520          ((int32_t *)rgba[c])[qi] = temp;
521       }
522       break;
523    case TGSI_OPCODE_ATOMOR:
524       for (c = 0; c < nc; c++) {
525          int temp = sdata[c];
526          sdata[c] |= ((int32_t *)rgba[c])[qi];
527          ((int32_t *)rgba[c])[qi] = temp;
528       }
529       break;
530    case TGSI_OPCODE_ATOMXOR:
531       for (c = 0; c < nc; c++) {
532          int temp = sdata[c];
533          sdata[c] ^= ((int32_t *)rgba[c])[qi];
534          ((int32_t *)rgba[c])[qi] = temp;
535       }
536       break;
537    case TGSI_OPCODE_ATOMUMIN:
538       for (c = 0; c < nc; c++) {
539          int dst_x = sdata[c];
540          int src_x = ((int32_t *)rgba[c])[qi];
541          sdata[c] = MIN2(dst_x, src_x);
542          ((int32_t *)rgba[c])[qi] = dst_x;
543       }
544       break;
545    case TGSI_OPCODE_ATOMUMAX:
546       for (c = 0; c < nc; c++) {
547          int dst_x = sdata[c];
548          int src_x = ((int32_t *)rgba[c])[qi];
549          sdata[c] = MAX2(dst_x, src_x);
550          ((int32_t *)rgba[c])[qi] = dst_x;
551       }
552       break;
553    case TGSI_OPCODE_ATOMIMIN:
554       for (c = 0; c < nc; c++) {
555          int dst_x = sdata[c];
556          int src_x = ((int32_t *)rgba[c])[qi];
557          sdata[c] = MIN2(dst_x, src_x);
558          ((int32_t *)rgba[c])[qi] = dst_x;
559       }
560       break;
561    case TGSI_OPCODE_ATOMIMAX:
562       for (c = 0; c < nc; c++) {
563          int dst_x = sdata[c];
564          int src_x = ((int32_t *)rgba[c])[qi];
565          sdata[c] = MAX2(dst_x, src_x);
566          ((int32_t *)rgba[c])[qi] = dst_x;
567       }
568       break;
569    default:
570       assert(!"Unexpected TGSI opcode in sp_tgsi_op");
571       break;
572    }
573    util_format_write_4(params->format, sdata, 0, data_ptr, stride,
574                        s, t, 1, 1);
575 }
576 
577 /* GLES OES_shader_image_atomic.txt allows XCHG on R32F */
578 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,enum tgsi_opcode opcode,int s,int t,float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])579 handle_op_r32f_xchg(const struct pipe_image_view *iview,
580                     const struct tgsi_image_params *params,
581                     bool just_read,
582                     char *data_ptr,
583                     uint qi,
584                     unsigned stride,
585                     enum tgsi_opcode opcode,
586                     int s,
587                     int t,
588                     float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
589 {
590    float sdata[4];
591    uint c;
592    int nc = 1;
593    util_format_read_4(params->format,
594                       sdata, 0,
595                       data_ptr, stride,
596                       s, t, 1, 1);
597    if (just_read) {
598       for (c = 0; c < nc; c++) {
599          ((int32_t *)rgba[c])[qi] = sdata[c];
600       }
601       return;
602    }
603 
604    for (c = 0; c < nc; c++) {
605       int temp = sdata[c];
606       sdata[c] = ((float *)rgba[c])[qi];
607       ((float *)rgba[c])[qi] = temp;
608    }
609    util_format_write_4(params->format, sdata, 0, data_ptr, stride,
610                        s, t, 1, 1);
611 }
612 
613 /*
614  * Implement atomic image operations.
615  */
616 static void
sp_tgsi_op(const struct tgsi_image * image,const struct tgsi_image_params * params,enum tgsi_opcode 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])617 sp_tgsi_op(const struct tgsi_image *image,
618            const struct tgsi_image_params *params,
619            enum tgsi_opcode opcode,
620            const int s[TGSI_QUAD_SIZE],
621            const int t[TGSI_QUAD_SIZE],
622            const int r[TGSI_QUAD_SIZE],
623            const int sample[TGSI_QUAD_SIZE],
624            float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE],
625            float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE])
626 {
627    struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
628    struct pipe_image_view *iview;
629    struct softpipe_resource *spr;
630    unsigned width, height, depth;
631    unsigned stride;
632    int j, c;
633    unsigned offset;
634    char *data_ptr;
635 
636    if (params->unit >= PIPE_MAX_SHADER_IMAGES)
637       return;
638    iview = &sp_img->sp_iview[params->unit];
639    spr = (struct softpipe_resource *)iview->resource;
640    if (!spr)
641       goto fail_write_all_zero;
642    if (!has_compat_target(spr->base.target, params->tgsi_tex_instr))
643       goto fail_write_all_zero;
644 
645    if (!get_dimensions(iview, spr, params->tgsi_tex_instr,
646                        params->format, &width, &height, &depth))
647       goto fail_write_all_zero;
648 
649    stride = util_format_get_stride(spr->base.format, width);
650 
651    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
652       int s_coord, t_coord, r_coord;
653       bool just_read = false;
654 
655       fill_coords(params, j, s, t, r, &s_coord, &t_coord, &r_coord);
656       if (!bounds_check(width, height, depth,
657                         s_coord, t_coord, r_coord)) {
658          int nc = util_format_get_nr_components(params->format);
659          int ival = util_format_is_pure_integer(params->format);
660          int c;
661          for (c = 0; c < 4; c++) {
662             rgba[c][j] = 0;
663             if (c == 3 && nc < 4) {
664                if (ival)
665                   ((int32_t *)rgba[c])[j] = 1;
666                else
667                   rgba[c][j] = 1.0;
668             }
669          }
670          continue;
671       }
672 
673       /* just readback the value for atomic if execmask isn't set */
674       if (!(params->execmask & (1 << j))) {
675          just_read = true;
676       }
677 
678       offset = get_image_offset(spr, iview, params->format, r_coord);
679       data_ptr = (char *)spr->data + offset;
680 
681       /* we should see atomic operations on r32 formats */
682       if (util_format_is_pure_uint(params->format))
683          handle_op_uint(iview, params, just_read, data_ptr, j, stride,
684                         opcode, s_coord, t_coord, rgba, rgba2);
685       else if (util_format_is_pure_sint(params->format))
686          handle_op_int(iview, params, just_read, data_ptr, j, stride,
687                        opcode, s_coord, t_coord, rgba, rgba2);
688       else if (params->format == PIPE_FORMAT_R32_FLOAT &&
689                opcode == TGSI_OPCODE_ATOMXCHG)
690          handle_op_r32f_xchg(iview, params, just_read, data_ptr, j, stride,
691                              opcode, s_coord, t_coord, rgba);
692       else
693          assert(0);
694    }
695    return;
696 fail_write_all_zero:
697    for (j = 0; j < TGSI_QUAD_SIZE; j++) {
698       for (c = 0; c < 4; c++)
699          rgba[c][j] = 0;
700    }
701    return;
702 }
703 
704 static void
sp_tgsi_get_dims(const struct tgsi_image * image,const struct tgsi_image_params * params,int dims[4])705 sp_tgsi_get_dims(const struct tgsi_image *image,
706                  const struct tgsi_image_params *params,
707                  int dims[4])
708 {
709    struct sp_tgsi_image *sp_img = (struct sp_tgsi_image *)image;
710    struct pipe_image_view *iview;
711    struct softpipe_resource *spr;
712    int level;
713 
714    if (params->unit >= PIPE_MAX_SHADER_IMAGES)
715       return;
716    iview = &sp_img->sp_iview[params->unit];
717    spr = (struct softpipe_resource *)iview->resource;
718    if (!spr)
719       return;
720 
721    if (params->tgsi_tex_instr == TGSI_TEXTURE_BUFFER) {
722       dims[0] = iview->u.buf.size / util_format_get_blocksize(iview->format);
723       dims[1] = dims[2] = dims[3] = 0;
724       return;
725    }
726 
727    level = iview->u.tex.level;
728    dims[0] = u_minify(spr->base.width0, level);
729    switch (params->tgsi_tex_instr) {
730    case TGSI_TEXTURE_1D_ARRAY:
731       dims[1] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
732       /* fallthrough */
733    case TGSI_TEXTURE_1D:
734       return;
735    case TGSI_TEXTURE_2D_ARRAY:
736       dims[2] = iview->u.tex.last_layer - iview->u.tex.first_layer + 1;
737       /* fallthrough */
738    case TGSI_TEXTURE_2D:
739    case TGSI_TEXTURE_CUBE:
740    case TGSI_TEXTURE_RECT:
741       dims[1] = u_minify(spr->base.height0, level);
742       return;
743    case TGSI_TEXTURE_3D:
744       dims[1] = u_minify(spr->base.height0, level);
745       dims[2] = u_minify(spr->base.depth0, level);
746       return;
747    case TGSI_TEXTURE_CUBE_ARRAY:
748       dims[1] = u_minify(spr->base.height0, level);
749       dims[2] = (iview->u.tex.last_layer - iview->u.tex.first_layer + 1) / 6;
750       break;
751    default:
752       assert(!"unexpected texture target in sp_get_dims()");
753       return;
754    }
755 }
756 
757 struct sp_tgsi_image *
sp_create_tgsi_image(void)758 sp_create_tgsi_image(void)
759 {
760    struct sp_tgsi_image *img = CALLOC_STRUCT(sp_tgsi_image);
761    if (!img)
762       return NULL;
763 
764    img->base.load = sp_tgsi_load;
765    img->base.store = sp_tgsi_store;
766    img->base.op = sp_tgsi_op;
767    img->base.get_dims = sp_tgsi_get_dims;
768    return img;
769 };
770