1 /* 2 * Copyright 2016 Red Hat. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "sp_context.h" 25 #include "sp_buffer.h" 26 #include "sp_texture.h" 27 28 #include "util/u_format.h" 29 30 static bool 31 get_dimensions(const struct pipe_shader_buffer *bview, 32 const struct softpipe_resource *spr, 33 unsigned *width) 34 { 35 *width = bview->buffer_size; 36 /* 37 * Bounds check the buffer size from the view 38 * and the buffer size from the underlying buffer. 39 */ 40 if (*width > spr->base.width0) 41 return false; 42 return true; 43 } 44 45 /* 46 * Implement the image LOAD operation. 47 */ 48 static void 49 sp_tgsi_load(const struct tgsi_buffer *buffer, 50 const struct tgsi_buffer_params *params, 51 const int s[TGSI_QUAD_SIZE], 52 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 53 { 54 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer; 55 struct pipe_shader_buffer *bview; 56 struct softpipe_resource *spr; 57 unsigned width; 58 int c, j; 59 unsigned char *data_ptr; 60 const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT); 61 62 if (params->unit >= PIPE_MAX_SHADER_BUFFERS) 63 goto fail_write_all_zero; 64 65 bview = &sp_buf->sp_bview[params->unit]; 66 spr = softpipe_resource(bview->buffer); 67 if (!spr) 68 goto fail_write_all_zero; 69 70 if (!get_dimensions(bview, spr, &width)) 71 return; 72 73 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 74 int s_coord; 75 bool fill_zero = false; 76 uint32_t sdata[4]; 77 78 if (!(params->execmask & (1 << j))) 79 fill_zero = true; 80 81 s_coord = s[j]; 82 if (s_coord >= width) 83 fill_zero = true; 84 85 if (fill_zero) { 86 for (c = 0; c < 4; c++) 87 rgba[c][j] = 0; 88 continue; 89 } 90 data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord; 91 for (c = 0; c < 4; c++) { 92 format_desc->fetch_rgba_uint(sdata, data_ptr, 0, 0); 93 ((uint32_t *)rgba[c])[j] = sdata[0]; 94 data_ptr += 4; 95 } 96 } 97 return; 98 fail_write_all_zero: 99 memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4); 100 return; 101 } 102 103 /* 104 * Implement the buffer STORE operation. 105 */ 106 static void 107 sp_tgsi_store(const struct tgsi_buffer *buffer, 108 const struct tgsi_buffer_params *params, 109 const int s[TGSI_QUAD_SIZE], 110 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 111 { 112 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer; 113 struct pipe_shader_buffer *bview; 114 struct softpipe_resource *spr; 115 unsigned width; 116 unsigned char *data_ptr; 117 int j, c; 118 const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT); 119 120 if (params->unit >= PIPE_MAX_SHADER_BUFFERS) 121 return; 122 123 bview = &sp_buf->sp_bview[params->unit]; 124 spr = softpipe_resource(bview->buffer); 125 if (!spr) 126 return; 127 128 if (!get_dimensions(bview, spr, &width)) 129 return; 130 131 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 132 int s_coord; 133 134 if (!(params->execmask & (1 << j))) 135 continue; 136 137 s_coord = s[j]; 138 if (s_coord >= width) 139 continue; 140 141 data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord; 142 143 for (c = 0; c < 4; c++) { 144 if (params->writemask & (1 << c)) { 145 unsigned temp[4]; 146 unsigned char *dptr = data_ptr + (c * 4); 147 temp[0] = ((uint32_t *)rgba[c])[j]; 148 format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1); 149 } 150 } 151 } 152 } 153 154 /* 155 * Implement atomic operations on unsigned integers. 156 */ 157 static void 158 handle_op_uint(const struct pipe_shader_buffer *bview, 159 bool just_read, 160 unsigned char *data_ptr, 161 uint qi, 162 unsigned opcode, 163 unsigned writemask, 164 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE], 165 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 166 { 167 uint c; 168 const struct util_format_description *format_desc = util_format_description(PIPE_FORMAT_R32_UINT); 169 unsigned sdata[4]; 170 171 for (c = 0; c < 4; c++) { 172 unsigned temp[4]; 173 unsigned char *dptr = data_ptr + (c * 4); 174 format_desc->fetch_rgba_uint(temp, dptr, 0, 0); 175 sdata[c] = temp[0]; 176 } 177 178 if (just_read) { 179 for (c = 0; c < 4; c++) { 180 ((uint32_t *)rgba[c])[qi] = sdata[c]; 181 } 182 return; 183 } 184 185 switch (opcode) { 186 case TGSI_OPCODE_ATOMUADD: 187 for (c = 0; c < 4; c++) { 188 unsigned temp = sdata[c]; 189 sdata[c] += ((uint32_t *)rgba[c])[qi]; 190 ((uint32_t *)rgba[c])[qi] = temp; 191 } 192 break; 193 case TGSI_OPCODE_ATOMXCHG: 194 for (c = 0; c < 4; c++) { 195 unsigned temp = sdata[c]; 196 sdata[c] = ((uint32_t *)rgba[c])[qi]; 197 ((uint32_t *)rgba[c])[qi] = temp; 198 } 199 break; 200 case TGSI_OPCODE_ATOMCAS: 201 for (c = 0; c < 4; c++) { 202 unsigned dst_x = sdata[c]; 203 unsigned cmp_x = ((uint32_t *)rgba[c])[qi]; 204 unsigned src_x = ((uint32_t *)rgba2[c])[qi]; 205 unsigned temp = sdata[c]; 206 sdata[c] = (dst_x == cmp_x) ? src_x : dst_x; 207 ((uint32_t *)rgba[c])[qi] = temp; 208 } 209 break; 210 case TGSI_OPCODE_ATOMAND: 211 for (c = 0; c < 4; c++) { 212 unsigned temp = sdata[c]; 213 sdata[c] &= ((uint32_t *)rgba[c])[qi]; 214 ((uint32_t *)rgba[c])[qi] = temp; 215 } 216 break; 217 case TGSI_OPCODE_ATOMOR: 218 for (c = 0; c < 4; c++) { 219 unsigned temp = sdata[c]; 220 sdata[c] |= ((uint32_t *)rgba[c])[qi]; 221 ((uint32_t *)rgba[c])[qi] = temp; 222 } 223 break; 224 case TGSI_OPCODE_ATOMXOR: 225 for (c = 0; c < 4; c++) { 226 unsigned temp = sdata[c]; 227 sdata[c] ^= ((uint32_t *)rgba[c])[qi]; 228 ((uint32_t *)rgba[c])[qi] = temp; 229 } 230 break; 231 case TGSI_OPCODE_ATOMUMIN: 232 for (c = 0; c < 4; c++) { 233 unsigned dst_x = sdata[c]; 234 unsigned src_x = ((uint32_t *)rgba[c])[qi]; 235 sdata[c] = MIN2(dst_x, src_x); 236 ((uint32_t *)rgba[c])[qi] = dst_x; 237 } 238 break; 239 case TGSI_OPCODE_ATOMUMAX: 240 for (c = 0; c < 4; c++) { 241 unsigned dst_x = sdata[c]; 242 unsigned src_x = ((uint32_t *)rgba[c])[qi]; 243 sdata[c] = MAX2(dst_x, src_x); 244 ((uint32_t *)rgba[c])[qi] = dst_x; 245 } 246 break; 247 case TGSI_OPCODE_ATOMIMIN: 248 for (c = 0; c < 4; c++) { 249 int dst_x = sdata[c]; 250 int src_x = ((uint32_t *)rgba[c])[qi]; 251 sdata[c] = MIN2(dst_x, src_x); 252 ((uint32_t *)rgba[c])[qi] = dst_x; 253 } 254 break; 255 case TGSI_OPCODE_ATOMIMAX: 256 for (c = 0; c < 4; c++) { 257 int dst_x = sdata[c]; 258 int src_x = ((uint32_t *)rgba[c])[qi]; 259 sdata[c] = MAX2(dst_x, src_x); 260 ((uint32_t *)rgba[c])[qi] = dst_x; 261 } 262 break; 263 default: 264 assert(!"Unexpected TGSI opcode in sp_tgsi_op"); 265 break; 266 } 267 268 for (c = 0; c < 4; c++) { 269 if (writemask & (1 << c)) { 270 unsigned temp[4]; 271 unsigned char *dptr = data_ptr + (c * 4); 272 temp[0] = sdata[c]; 273 format_desc->pack_rgba_uint(dptr, 0, temp, 0, 1, 1); 274 } 275 } 276 } 277 278 /* 279 * Implement atomic buffer operations. 280 */ 281 static void 282 sp_tgsi_op(const struct tgsi_buffer *buffer, 283 const struct tgsi_buffer_params *params, 284 unsigned opcode, 285 const int s[TGSI_QUAD_SIZE], 286 float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE], 287 float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE]) 288 { 289 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer; 290 struct pipe_shader_buffer *bview; 291 struct softpipe_resource *spr; 292 unsigned width; 293 int j, c; 294 unsigned char *data_ptr; 295 296 if (params->unit >= PIPE_MAX_SHADER_BUFFERS) 297 return; 298 299 bview = &sp_buf->sp_bview[params->unit]; 300 spr = softpipe_resource(bview->buffer); 301 if (!spr) 302 goto fail_write_all_zero; 303 304 if (!get_dimensions(bview, spr, &width)) 305 goto fail_write_all_zero; 306 307 for (j = 0; j < TGSI_QUAD_SIZE; j++) { 308 int s_coord; 309 bool just_read = false; 310 311 s_coord = s[j]; 312 if (s_coord >= width) { 313 for (c = 0; c < 4; c++) { 314 rgba[c][j] = 0; 315 } 316 continue; 317 } 318 319 /* just readback the value for atomic if execmask isn't set */ 320 if (!(params->execmask & (1 << j))) { 321 just_read = true; 322 } 323 324 data_ptr = (unsigned char *)spr->data + bview->buffer_offset + s_coord; 325 /* we should see atomic operations on r32 formats */ 326 327 handle_op_uint(bview, just_read, data_ptr, j, 328 opcode, params->writemask, rgba, rgba2); 329 } 330 return; 331 fail_write_all_zero: 332 memset(rgba, 0, TGSI_NUM_CHANNELS * TGSI_QUAD_SIZE * 4); 333 return; 334 } 335 336 /* 337 * return size of the attached buffer for RESQ opcode. 338 */ 339 static void 340 sp_tgsi_get_dims(const struct tgsi_buffer *buffer, 341 const struct tgsi_buffer_params *params, 342 int *dim) 343 { 344 struct sp_tgsi_buffer *sp_buf = (struct sp_tgsi_buffer *)buffer; 345 struct pipe_shader_buffer *bview; 346 struct softpipe_resource *spr; 347 348 if (params->unit >= PIPE_MAX_SHADER_BUFFERS) 349 return; 350 351 bview = &sp_buf->sp_bview[params->unit]; 352 spr = softpipe_resource(bview->buffer); 353 if (!spr) 354 return; 355 356 *dim = bview->buffer_size; 357 } 358 359 struct sp_tgsi_buffer * 360 sp_create_tgsi_buffer(void) 361 { 362 struct sp_tgsi_buffer *buf = CALLOC_STRUCT(sp_tgsi_buffer); 363 if (!buf) 364 return NULL; 365 366 buf->base.load = sp_tgsi_load; 367 buf->base.store = sp_tgsi_store; 368 buf->base.op = sp_tgsi_op; 369 buf->base.get_dims = sp_tgsi_get_dims; 370 return buf; 371 }; 372