1/* 2 * Copyright (C) 2011 Francisco Jerez. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27#include <fcntl.h> 28#include <stdio.h> 29#include <sys/stat.h> 30#include <inttypes.h> 31#include "pipe/p_state.h" 32#include "pipe/p_context.h" 33#include "pipe/p_screen.h" 34#include "pipe/p_defines.h" 35#include "pipe/p_shader_tokens.h" 36#include "util/u_memory.h" 37#include "util/u_inlines.h" 38#include "util/u_sampler.h" 39#include "util/u_format.h" 40#include "tgsi/tgsi_text.h" 41#include "pipe-loader/pipe_loader.h" 42 43#define MAX_RESOURCES 4 44 45struct context { 46 struct pipe_loader_device *dev; 47 struct pipe_screen *screen; 48 struct pipe_context *pipe; 49 void *hwcs; 50 void *hwsmp[MAX_RESOURCES]; 51 struct pipe_resource *tex[MAX_RESOURCES]; 52 bool tex_rw[MAX_RESOURCES]; 53 struct pipe_sampler_view *view[MAX_RESOURCES]; 54 struct pipe_surface *surf[MAX_RESOURCES]; 55}; 56 57#define DUMP_COMPUTE_PARAM(p, c) do { \ 58 uint64_t __v[4]; \ 59 int __i, __n; \ 60 \ 61 __n = ctx->screen->get_compute_param(ctx->screen, \ 62 PIPE_SHADER_IR_TGSI, \ 63 c, __v); \ 64 printf("%s: {", #c); \ 65 \ 66 for (__i = 0; __i < __n / sizeof(*__v); ++__i) \ 67 printf(" %"PRIu64, __v[__i]); \ 68 \ 69 printf(" }\n"); \ 70 } while (0) 71 72static void init_ctx(struct context *ctx) 73{ 74 int ret; 75 76 ret = pipe_loader_probe(&ctx->dev, 1); 77 assert(ret); 78 79 ctx->screen = pipe_loader_create_screen(ctx->dev); 80 assert(ctx->screen); 81 82 ctx->pipe = ctx->screen->context_create(ctx->screen, NULL, 0); 83 assert(ctx->pipe); 84 85 DUMP_COMPUTE_PARAM(p, PIPE_COMPUTE_CAP_GRID_DIMENSION); 86 DUMP_COMPUTE_PARAM(p, PIPE_COMPUTE_CAP_MAX_GRID_SIZE); 87 DUMP_COMPUTE_PARAM(p, PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE); 88} 89 90static void destroy_ctx(struct context *ctx) 91{ 92 ctx->pipe->destroy(ctx->pipe); 93 ctx->screen->destroy(ctx->screen); 94 pipe_loader_release(&ctx->dev, 1); 95 FREE(ctx); 96} 97 98static char * 99preprocess_prog(struct context *ctx, const char *src, const char *defs) 100{ 101 const char header[] = 102 "#define RGLOBAL RES[32767]\n" 103 "#define RLOCAL RES[32766]\n" 104 "#define RPRIVATE RES[32765]\n" 105 "#define RINPUT RES[32764]\n"; 106 char cmd[512]; 107 char tmp[] = "/tmp/test-compute.tgsi-XXXXXX"; 108 char *buf; 109 int fd, ret; 110 struct stat st; 111 FILE *p; 112 113 /* Open a temporary file */ 114 fd = mkstemp(tmp); 115 assert(fd >= 0); 116 snprintf(cmd, sizeof(cmd), "cpp -P -nostdinc -undef %s > %s", 117 defs ? defs : "", tmp); 118 119 /* Preprocess */ 120 p = popen(cmd, "w"); 121 fwrite(header, strlen(header), 1, p); 122 fwrite(src, strlen(src), 1, p); 123 ret = pclose(p); 124 assert(!ret); 125 126 /* Read back */ 127 ret = fstat(fd, &st); 128 assert(!ret); 129 130 buf = malloc(st.st_size + 1); 131 ret = read(fd, buf, st.st_size); 132 assert(ret == st.st_size); 133 buf[ret] = 0; 134 135 /* Clean up */ 136 close(fd); 137 unlink(tmp); 138 139 return buf; 140} 141 142static void init_prog(struct context *ctx, unsigned local_sz, 143 unsigned private_sz, unsigned input_sz, 144 const char *src, const char *defs) 145{ 146 struct pipe_context *pipe = ctx->pipe; 147 struct tgsi_token prog[1024]; 148 struct pipe_compute_state cs = { 149 .ir_type = PIPE_SHADER_IR_TGSI, 150 .prog = prog, 151 .req_local_mem = local_sz, 152 .req_private_mem = private_sz, 153 .req_input_mem = input_sz 154 }; 155 char *psrc = preprocess_prog(ctx, src, defs); 156 int ret; 157 158 ret = tgsi_text_translate(psrc, prog, ARRAY_SIZE(prog)); 159 assert(ret); 160 free(psrc); 161 162 ctx->hwcs = pipe->create_compute_state(pipe, &cs); 163 assert(ctx->hwcs); 164 165 pipe->bind_compute_state(pipe, ctx->hwcs); 166} 167 168static void destroy_prog(struct context *ctx) 169{ 170 struct pipe_context *pipe = ctx->pipe; 171 172 pipe->delete_compute_state(pipe, ctx->hwcs); 173 ctx->hwcs = NULL; 174} 175 176static void init_tex(struct context *ctx, int slot, 177 enum pipe_texture_target target, bool rw, 178 enum pipe_format format, int w, int h, 179 void (*init)(void *, int, int, int)) 180{ 181 struct pipe_context *pipe = ctx->pipe; 182 struct pipe_resource **tex = &ctx->tex[slot]; 183 struct pipe_resource ttex = { 184 .target = target, 185 .format = format, 186 .width0 = w, 187 .height0 = h, 188 .depth0 = 1, 189 .array_size = 1, 190 .bind = (PIPE_BIND_SAMPLER_VIEW | 191 PIPE_BIND_COMPUTE_RESOURCE | 192 PIPE_BIND_GLOBAL) 193 }; 194 int dx = util_format_get_blocksize(format); 195 int dy = util_format_get_stride(format, w); 196 int nx = (target == PIPE_BUFFER ? (w / dx) : 197 util_format_get_nblocksx(format, w)); 198 int ny = (target == PIPE_BUFFER ? 1 : 199 util_format_get_nblocksy(format, h)); 200 struct pipe_transfer *xfer; 201 char *map; 202 int x, y; 203 204 *tex = ctx->screen->resource_create(ctx->screen, &ttex); 205 assert(*tex); 206 207 map = pipe->transfer_map(pipe, *tex, 0, PIPE_TRANSFER_WRITE, 208 &(struct pipe_box) { .width = w, 209 .height = h, 210 .depth = 1 }, &xfer); 211 assert(xfer); 212 assert(map); 213 214 for (y = 0; y < ny; ++y) { 215 for (x = 0; x < nx; ++x) { 216 init(map + y * dy + x * dx, slot, x, y); 217 } 218 } 219 220 pipe->transfer_unmap(pipe, xfer); 221 222 ctx->tex_rw[slot] = rw; 223} 224 225static bool default_check(void *x, void *y, int sz) { 226 return !memcmp(x, y, sz); 227} 228 229static void check_tex(struct context *ctx, int slot, 230 void (*expect)(void *, int, int, int), 231 bool (*check)(void *, void *, int)) 232{ 233 struct pipe_context *pipe = ctx->pipe; 234 struct pipe_resource *tex = ctx->tex[slot]; 235 int dx = util_format_get_blocksize(tex->format); 236 int dy = util_format_get_stride(tex->format, tex->width0); 237 int nx = (tex->target == PIPE_BUFFER ? (tex->width0 / dx) : 238 util_format_get_nblocksx(tex->format, tex->width0)); 239 int ny = (tex->target == PIPE_BUFFER ? 1 : 240 util_format_get_nblocksy(tex->format, tex->height0)); 241 struct pipe_transfer *xfer; 242 char *map; 243 int x, y, i; 244 int err = 0; 245 246 if (!check) 247 check = default_check; 248 249 map = pipe->transfer_map(pipe, tex, 0, PIPE_TRANSFER_READ, 250 &(struct pipe_box) { .width = tex->width0, 251 .height = tex->height0, 252 .depth = 1 }, &xfer); 253 assert(xfer); 254 assert(map); 255 256 for (y = 0; y < ny; ++y) { 257 for (x = 0; x < nx; ++x) { 258 uint32_t exp[4]; 259 uint32_t *res = (uint32_t *)(map + y * dy + x * dx); 260 261 expect(exp, slot, x, y); 262 if (check(res, exp, dx) || (++err) > 20) 263 continue; 264 265 if (dx < 4) { 266 uint32_t u = 0, v = 0; 267 268 for (i = 0; i < dx; i++) { 269 u |= ((uint8_t *)exp)[i] << (8 * i); 270 v |= ((uint8_t *)res)[i] << (8 * i); 271 } 272 printf("(%d, %d): got 0x%x, expected 0x%x\n", 273 x, y, v, u); 274 } else { 275 for (i = 0; i < dx / 4; i++) { 276 printf("(%d, %d)[%d]: got 0x%x/%f," 277 " expected 0x%x/%f\n", x, y, i, 278 res[i], ((float *)res)[i], 279 exp[i], ((float *)exp)[i]); 280 } 281 } 282 } 283 } 284 285 pipe->transfer_unmap(pipe, xfer); 286 287 if (err) 288 printf("(%d, %d): \x1b[31mFAIL\x1b[0m (%d)\n", x, y, err); 289 else 290 printf("(%d, %d): \x1b[32mOK\x1b[0m\n", x, y); 291} 292 293static void destroy_tex(struct context *ctx) 294{ 295 int i; 296 297 for (i = 0; i < MAX_RESOURCES; ++i) { 298 if (ctx->tex[i]) 299 pipe_resource_reference(&ctx->tex[i], NULL); 300 } 301} 302 303static void init_sampler_views(struct context *ctx, const int *slots) 304{ 305 struct pipe_context *pipe = ctx->pipe; 306 struct pipe_sampler_view tview; 307 int i; 308 309 for (i = 0; *slots >= 0; ++i, ++slots) { 310 u_sampler_view_default_template(&tview, ctx->tex[*slots], 311 ctx->tex[*slots]->format); 312 313 ctx->view[i] = pipe->create_sampler_view(pipe, ctx->tex[*slots], 314 &tview); 315 assert(ctx->view[i]); 316 } 317 318 pipe->set_sampler_views(pipe, PIPE_SHADER_COMPUTE, 0, i, ctx->view); 319} 320 321static void destroy_sampler_views(struct context *ctx) 322{ 323 struct pipe_context *pipe = ctx->pipe; 324 int i; 325 326 pipe->set_sampler_views(pipe, PIPE_SHADER_COMPUTE, 0, MAX_RESOURCES, NULL); 327 328 for (i = 0; i < MAX_RESOURCES; ++i) { 329 if (ctx->view[i]) { 330 pipe->sampler_view_destroy(pipe, ctx->view[i]); 331 ctx->view[i] = NULL; 332 } 333 } 334} 335 336static void init_compute_resources(struct context *ctx, const int *slots) 337{ 338 struct pipe_context *pipe = ctx->pipe; 339 int i; 340 341 for (i = 0; *slots >= 0; ++i, ++slots) { 342 struct pipe_surface tsurf = { 343 .format = ctx->tex[*slots]->format, 344 .writable = ctx->tex_rw[*slots] 345 }; 346 347 if (ctx->tex[*slots]->target == PIPE_BUFFER) 348 tsurf.u.buf.last_element = ctx->tex[*slots]->width0 - 1; 349 350 ctx->surf[i] = pipe->create_surface(pipe, ctx->tex[*slots], 351 &tsurf); 352 assert(ctx->surf[i]); 353 } 354 355 pipe->set_compute_resources(pipe, 0, i, ctx->surf); 356} 357 358static void destroy_compute_resources(struct context *ctx) 359{ 360 struct pipe_context *pipe = ctx->pipe; 361 int i; 362 363 pipe->set_compute_resources(pipe, 0, MAX_RESOURCES, NULL); 364 365 for (i = 0; i < MAX_RESOURCES; ++i) { 366 if (ctx->surf[i]) { 367 pipe->surface_destroy(pipe, ctx->surf[i]); 368 ctx->surf[i] = NULL; 369 } 370 } 371} 372 373static void init_sampler_states(struct context *ctx, int n) 374{ 375 struct pipe_context *pipe = ctx->pipe; 376 struct pipe_sampler_state smp = { 377 .normalized_coords = 1, 378 }; 379 int i; 380 381 for (i = 0; i < n; ++i) { 382 ctx->hwsmp[i] = pipe->create_sampler_state(pipe, &smp); 383 assert(ctx->hwsmp[i]); 384 } 385 386 pipe->bind_sampler_states(pipe, PIPE_SHADER_COMPUTE, 0, i, ctx->hwsmp); 387} 388 389static void destroy_sampler_states(struct context *ctx) 390{ 391 struct pipe_context *pipe = ctx->pipe; 392 int i; 393 394 pipe->bind_sampler_states(pipe, PIPE_SHADER_COMPUTE, 395 0, MAX_RESOURCES, NULL); 396 397 for (i = 0; i < MAX_RESOURCES; ++i) { 398 if (ctx->hwsmp[i]) { 399 pipe->delete_sampler_state(pipe, ctx->hwsmp[i]); 400 ctx->hwsmp[i] = NULL; 401 } 402 } 403} 404 405static void init_globals(struct context *ctx, const int *slots, 406 uint32_t **handles) 407{ 408 struct pipe_context *pipe = ctx->pipe; 409 struct pipe_resource *res[MAX_RESOURCES]; 410 int i; 411 412 for (i = 0; *slots >= 0; ++i, ++slots) 413 res[i] = ctx->tex[*slots]; 414 415 pipe->set_global_binding(pipe, 0, i, res, handles); 416} 417 418static void destroy_globals(struct context *ctx) 419{ 420 struct pipe_context *pipe = ctx->pipe; 421 422 pipe->set_global_binding(pipe, 0, MAX_RESOURCES, NULL, NULL); 423} 424 425static void launch_grid(struct context *ctx, const uint *block_layout, 426 const uint *grid_layout, uint32_t pc, 427 void *input) 428{ 429 struct pipe_context *pipe = ctx->pipe; 430 struct pipe_grid_info info; 431 int i; 432 433 for (i = 0; i < 3; i++) { 434 info.block[i] = block_layout[i]; 435 info.grid[i] = grid_layout[i]; 436 } 437 info.pc = pc; 438 info.input = input; 439 440 pipe->launch_grid(pipe, &info); 441} 442 443static void test_default_init(void *p, int s, int x, int y) 444{ 445 *(uint32_t *)p = 0xdeadbeef; 446} 447 448/* test_system_values */ 449static void test_system_values_expect(void *p, int s, int x, int y) 450{ 451 int id = x / 16, sv = (x % 16) / 4, c = x % 4; 452 int tid[] = { id % 20, (id % 240) / 20, id / 240, 0 }; 453 int bsz[] = { 4, 3, 5, 1}; 454 int gsz[] = { 5, 4, 1, 1}; 455 456 switch (sv) { 457 case 0: 458 *(uint32_t *)p = tid[c] / bsz[c]; 459 break; 460 case 1: 461 *(uint32_t *)p = bsz[c]; 462 break; 463 case 2: 464 *(uint32_t *)p = gsz[c]; 465 break; 466 case 3: 467 *(uint32_t *)p = tid[c] % bsz[c]; 468 break; 469 } 470} 471 472static void test_system_values(struct context *ctx) 473{ 474 const char *src = "COMP\n" 475 "DCL RES[0], BUFFER, RAW, WR\n" 476 "DCL SV[0], BLOCK_ID[0]\n" 477 "DCL SV[1], BLOCK_SIZE[0]\n" 478 "DCL SV[2], GRID_SIZE[0]\n" 479 "DCL SV[3], THREAD_ID[0]\n" 480 "DCL TEMP[0], LOCAL\n" 481 "DCL TEMP[1], LOCAL\n" 482 "IMM UINT32 { 64, 0, 0, 0 }\n" 483 "IMM UINT32 { 16, 0, 0, 0 }\n" 484 "IMM UINT32 { 0, 0, 0, 0 }\n" 485 "\n" 486 "BGNSUB" 487 " UMUL TEMP[0], SV[0], SV[1]\n" 488 " UADD TEMP[0], TEMP[0], SV[3]\n" 489 " UMUL TEMP[1], SV[1], SV[2]\n" 490 " UMUL TEMP[0].w, TEMP[0], TEMP[1].zzzz\n" 491 " UMUL TEMP[0].zw, TEMP[0], TEMP[1].yyyy\n" 492 " UMUL TEMP[0].yzw, TEMP[0], TEMP[1].xxxx\n" 493 " UADD TEMP[0].xy, TEMP[0].xyxy, TEMP[0].zwzw\n" 494 " UADD TEMP[0].x, TEMP[0].xxxx, TEMP[0].yyyy\n" 495 " UMUL TEMP[0].x, TEMP[0], IMM[0]\n" 496 " STORE RES[0].xyzw, TEMP[0], SV[0]\n" 497 " UADD TEMP[0].x, TEMP[0], IMM[1]\n" 498 " STORE RES[0].xyzw, TEMP[0], SV[1]\n" 499 " UADD TEMP[0].x, TEMP[0], IMM[1]\n" 500 " STORE RES[0].xyzw, TEMP[0], SV[2]\n" 501 " UADD TEMP[0].x, TEMP[0], IMM[1]\n" 502 " STORE RES[0].xyzw, TEMP[0], SV[3]\n" 503 " RET\n" 504 "ENDSUB\n"; 505 506 printf("- %s\n", __func__); 507 508 init_prog(ctx, 0, 0, 0, src, NULL); 509 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 510 76800, 0, test_default_init); 511 init_compute_resources(ctx, (int []) { 0, -1 }); 512 launch_grid(ctx, (uint []){4, 3, 5}, (uint []){5, 4, 1}, 0, NULL); 513 check_tex(ctx, 0, test_system_values_expect, NULL); 514 destroy_compute_resources(ctx); 515 destroy_tex(ctx); 516 destroy_prog(ctx); 517} 518 519/* test_resource_access */ 520static void test_resource_access_init0(void *p, int s, int x, int y) 521{ 522 *(float *)p = 8.0 - (float)x; 523} 524 525static void test_resource_access_expect(void *p, int s, int x, int y) 526{ 527 *(float *)p = 8.0 - (float)((x + 4 * y) & 0x3f); 528} 529 530static void test_resource_access(struct context *ctx) 531{ 532 const char *src = "COMP\n" 533 "DCL RES[0], BUFFER, RAW, WR\n" 534 "DCL RES[1], 2D, RAW, WR\n" 535 "DCL SV[0], BLOCK_ID[0]\n" 536 "DCL TEMP[0], LOCAL\n" 537 "DCL TEMP[1], LOCAL\n" 538 "IMM UINT32 { 15, 0, 0, 0 }\n" 539 "IMM UINT32 { 16, 1, 0, 0 }\n" 540 "\n" 541 " BGNSUB\n" 542 " UADD TEMP[0].x, SV[0].xxxx, SV[0].yyyy\n" 543 " AND TEMP[0].x, TEMP[0], IMM[0]\n" 544 " UMUL TEMP[0].x, TEMP[0], IMM[1]\n" 545 " LOAD TEMP[0].xyzw, RES[0], TEMP[0]\n" 546 " UMUL TEMP[1], SV[0], IMM[1]\n" 547 " STORE RES[1].xyzw, TEMP[1], TEMP[0]\n" 548 " RET\n" 549 " ENDSUB\n"; 550 551 printf("- %s\n", __func__); 552 553 init_prog(ctx, 0, 0, 0, src, NULL); 554 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 555 256, 0, test_resource_access_init0); 556 init_tex(ctx, 1, PIPE_TEXTURE_2D, true, PIPE_FORMAT_R32_FLOAT, 557 60, 12, test_default_init); 558 init_compute_resources(ctx, (int []) { 0, 1, -1 }); 559 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){15, 12, 1}, 0, NULL); 560 check_tex(ctx, 1, test_resource_access_expect, NULL); 561 destroy_compute_resources(ctx); 562 destroy_tex(ctx); 563 destroy_prog(ctx); 564} 565 566/* test_function_calls */ 567static void test_function_calls_init(void *p, int s, int x, int y) 568{ 569 *(uint32_t *)p = 15 * y + x; 570} 571 572static void test_function_calls_expect(void *p, int s, int x, int y) 573{ 574 *(uint32_t *)p = (15 * y + x) < 4 ? 2 : 1 ; 575} 576 577static void test_function_calls(struct context *ctx) 578{ 579 const char *src = "COMP\n" 580 "DCL RES[0], 2D, RAW, WR\n" 581 "DCL SV[0], BLOCK_ID[0]\n" 582 "DCL SV[1], BLOCK_SIZE[0]\n" 583 "DCL SV[2], GRID_SIZE[0]\n" 584 "DCL SV[3], THREAD_ID[0]\n" 585 "DCL TEMP[0]\n" 586 "DCL TEMP[1]\n" 587 "DCL TEMP[2], LOCAL\n" 588 "IMM UINT32 { 0, 11, 22, 33 }\n" 589 "IMM FLT32 { 11, 33, 55, 99 }\n" 590 "IMM UINT32 { 4, 1, 0, 0 }\n" 591 "IMM UINT32 { 12, 0, 0, 0 }\n" 592 "\n" 593 "00: BGNSUB\n" 594 "01: UMUL TEMP[0].x, TEMP[0], TEMP[0]\n" 595 "02: UADD TEMP[1].x, TEMP[1], IMM[2].yyyy\n" 596 "03: USLT TEMP[0].x, TEMP[0], IMM[0]\n" 597 "04: RET\n" 598 "05: ENDSUB\n" 599 "06: BGNSUB\n" 600 "07: UMUL TEMP[0].x, TEMP[0], TEMP[0]\n" 601 "08: UADD TEMP[1].x, TEMP[1], IMM[2].yyyy\n" 602 "09: USLT TEMP[0].x, TEMP[0], IMM[0].yyyy\n" 603 "10: IF TEMP[0].xxxx\n" 604 "11: CAL :0\n" 605 "12: ENDIF\n" 606 "13: RET\n" 607 "14: ENDSUB\n" 608 "15: BGNSUB\n" 609 "16: UMUL TEMP[2], SV[0], SV[1]\n" 610 "17: UADD TEMP[2], TEMP[2], SV[3]\n" 611 "18: UMUL TEMP[2], TEMP[2], IMM[2]\n" 612 "00: MOV TEMP[1].x, IMM[2].wwww\n" 613 "19: LOAD TEMP[0].x, RES[0].xxxx, TEMP[2]\n" 614 "20: CAL :6\n" 615 "21: STORE RES[0].x, TEMP[2], TEMP[1].xxxx\n" 616 "22: RET\n" 617 "23: ENDSUB\n"; 618 619 printf("- %s\n", __func__); 620 621 init_prog(ctx, 0, 0, 0, src, NULL); 622 init_tex(ctx, 0, PIPE_TEXTURE_2D, true, PIPE_FORMAT_R32_FLOAT, 623 15, 12, test_function_calls_init); 624 init_compute_resources(ctx, (int []) { 0, -1 }); 625 launch_grid(ctx, (uint []){3, 3, 3}, (uint []){5, 4, 1}, 15, NULL); 626 check_tex(ctx, 0, test_function_calls_expect, NULL); 627 destroy_compute_resources(ctx); 628 destroy_tex(ctx); 629 destroy_prog(ctx); 630} 631 632/* test_input_global */ 633static void test_input_global_expect(void *p, int s, int x, int y) 634{ 635 *(uint32_t *)p = 0xdeadbeef - (x == 0 ? 0x10001 + 2 * s : 0); 636} 637 638static void test_input_global(struct context *ctx) 639{ 640 const char *src = "COMP\n" 641 "DCL SV[0], THREAD_ID[0]\n" 642 "DCL TEMP[0], LOCAL\n" 643 "DCL TEMP[1], LOCAL\n" 644 "IMM UINT32 { 8, 0, 0, 0 }\n" 645 "\n" 646 " BGNSUB\n" 647 " UMUL TEMP[0], SV[0], IMM[0]\n" 648 " LOAD TEMP[1].xy, RINPUT, TEMP[0]\n" 649 " LOAD TEMP[0].x, RGLOBAL, TEMP[1].yyyy\n" 650 " UADD TEMP[1].x, TEMP[0], -TEMP[1]\n" 651 " STORE RGLOBAL.x, TEMP[1].yyyy, TEMP[1]\n" 652 " RET\n" 653 " ENDSUB\n"; 654 uint32_t input[8] = { 0x10001, 0x10002, 0x10003, 0x10004, 655 0x10005, 0x10006, 0x10007, 0x10008 }; 656 657 printf("- %s\n", __func__); 658 659 init_prog(ctx, 0, 0, 32, src, NULL); 660 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 32, 0, 661 test_default_init); 662 init_tex(ctx, 1, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 32, 0, 663 test_default_init); 664 init_tex(ctx, 2, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 32, 0, 665 test_default_init); 666 init_tex(ctx, 3, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 32, 0, 667 test_default_init); 668 init_globals(ctx, (int []){ 0, 1, 2, 3, -1 }, 669 (uint32_t *[]){ &input[1], &input[3], 670 &input[5], &input[7] }); 671 launch_grid(ctx, (uint []){4, 1, 1}, (uint []){1, 1, 1}, 0, input); 672 check_tex(ctx, 0, test_input_global_expect, NULL); 673 check_tex(ctx, 1, test_input_global_expect, NULL); 674 check_tex(ctx, 2, test_input_global_expect, NULL); 675 check_tex(ctx, 3, test_input_global_expect, NULL); 676 destroy_globals(ctx); 677 destroy_tex(ctx); 678 destroy_prog(ctx); 679} 680 681/* test_private */ 682static void test_private_expect(void *p, int s, int x, int y) 683{ 684 *(uint32_t *)p = (x / 32) + x % 32; 685} 686 687static void test_private(struct context *ctx) 688{ 689 const char *src = "COMP\n" 690 "DCL RES[0], BUFFER, RAW, WR\n" 691 "DCL SV[0], BLOCK_ID[0]\n" 692 "DCL SV[1], BLOCK_SIZE[0]\n" 693 "DCL SV[2], THREAD_ID[0]\n" 694 "DCL TEMP[0], LOCAL\n" 695 "DCL TEMP[1], LOCAL\n" 696 "DCL TEMP[2], LOCAL\n" 697 "IMM UINT32 { 128, 0, 0, 0 }\n" 698 "IMM UINT32 { 4, 0, 0, 0 }\n" 699 "\n" 700 " BGNSUB\n" 701 " UMUL TEMP[0].x, SV[0], SV[1]\n" 702 " UADD TEMP[0].x, TEMP[0], SV[2]\n" 703 " MOV TEMP[1].x, IMM[0].wwww\n" 704 " BGNLOOP\n" 705 " USEQ TEMP[2].x, TEMP[1], IMM[0]\n" 706 " IF TEMP[2]\n" 707 " BRK\n" 708 " ENDIF\n" 709 " UDIV TEMP[2].x, TEMP[1], IMM[1]\n" 710 " UADD TEMP[2].x, TEMP[2], TEMP[0]\n" 711 " STORE RPRIVATE.x, TEMP[1], TEMP[2]\n" 712 " UADD TEMP[1].x, TEMP[1], IMM[1]\n" 713 " ENDLOOP\n" 714 " MOV TEMP[1].x, IMM[0].wwww\n" 715 " UMUL TEMP[0].x, TEMP[0], IMM[0]\n" 716 " BGNLOOP\n" 717 " USEQ TEMP[2].x, TEMP[1], IMM[0]\n" 718 " IF TEMP[2]\n" 719 " BRK\n" 720 " ENDIF\n" 721 " LOAD TEMP[2].x, RPRIVATE, TEMP[1]\n" 722 " STORE RES[0].x, TEMP[0], TEMP[2]\n" 723 " UADD TEMP[0].x, TEMP[0], IMM[1]\n" 724 " UADD TEMP[1].x, TEMP[1], IMM[1]\n" 725 " ENDLOOP\n" 726 " RET\n" 727 " ENDSUB\n"; 728 729 printf("- %s\n", __func__); 730 731 init_prog(ctx, 0, 128, 0, src, NULL); 732 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 733 32768, 0, test_default_init); 734 init_compute_resources(ctx, (int []) { 0, -1 }); 735 launch_grid(ctx, (uint []){16, 1, 1}, (uint []){16, 1, 1}, 0, NULL); 736 check_tex(ctx, 0, test_private_expect, NULL); 737 destroy_compute_resources(ctx); 738 destroy_tex(ctx); 739 destroy_prog(ctx); 740} 741 742/* test_local */ 743static void test_local_expect(void *p, int s, int x, int y) 744{ 745 *(uint32_t *)p = x & 0x20 ? 2 : 1; 746} 747 748static void test_local(struct context *ctx) 749{ 750 const char *src = "COMP\n" 751 "DCL RES[0], BUFFER, RAW, WR\n" 752 "DCL SV[0], BLOCK_ID[0]\n" 753 "DCL SV[1], BLOCK_SIZE[0]\n" 754 "DCL SV[2], THREAD_ID[0]\n" 755 "DCL TEMP[0], LOCAL\n" 756 "DCL TEMP[1], LOCAL\n" 757 "DCL TEMP[2], LOCAL\n" 758 "IMM UINT32 { 1, 0, 0, 0 }\n" 759 "IMM UINT32 { 2, 0, 0, 0 }\n" 760 "IMM UINT32 { 4, 0, 0, 0 }\n" 761 "IMM UINT32 { 32, 0, 0, 0 }\n" 762 "IMM UINT32 { 128, 0, 0, 0 }\n" 763 "\n" 764 " BGNSUB\n" 765 " UMUL TEMP[0].x, SV[2], IMM[2]\n" 766 " STORE RLOCAL.x, TEMP[0], IMM[0].wwww\n" 767 " MFENCE RLOCAL\n" 768 " USLT TEMP[1].x, SV[2], IMM[3]\n" 769 " IF TEMP[1]\n" 770 " UADD TEMP[1].x, TEMP[0], IMM[4]\n" 771 " BGNLOOP\n" 772 " LOAD TEMP[2].x, RLOCAL, TEMP[1]\n" 773 " USEQ TEMP[2].x, TEMP[2], IMM[0]\n" 774 " IF TEMP[2]\n" 775 " BRK\n" 776 " ENDIF\n" 777 " ENDLOOP\n" 778 " STORE RLOCAL.x, TEMP[0], IMM[0]\n" 779 " MFENCE RLOCAL\n" 780 " BGNLOOP\n" 781 " LOAD TEMP[2].x, RLOCAL, TEMP[1]\n" 782 " USEQ TEMP[2].x, TEMP[2], IMM[1]\n" 783 " IF TEMP[2]\n" 784 " BRK\n" 785 " ENDIF\n" 786 " ENDLOOP\n" 787 " ELSE\n" 788 " UADD TEMP[1].x, TEMP[0], -IMM[4]\n" 789 " BGNLOOP\n" 790 " LOAD TEMP[2].x, RLOCAL, TEMP[1]\n" 791 " USEQ TEMP[2].x, TEMP[2], IMM[0].wwww\n" 792 " IF TEMP[2]\n" 793 " BRK\n" 794 " ENDIF\n" 795 " ENDLOOP\n" 796 " STORE RLOCAL.x, TEMP[0], IMM[0]\n" 797 " MFENCE RLOCAL\n" 798 " BGNLOOP\n" 799 " LOAD TEMP[2].x, RLOCAL, TEMP[1]\n" 800 " USEQ TEMP[2].x, TEMP[2], IMM[0]\n" 801 " IF TEMP[2]\n" 802 " BRK\n" 803 " ENDIF\n" 804 " ENDLOOP\n" 805 " STORE RLOCAL.x, TEMP[0], IMM[1]\n" 806 " MFENCE RLOCAL\n" 807 " ENDIF\n" 808 " UMUL TEMP[1].x, SV[0], SV[1]\n" 809 " UMUL TEMP[1].x, TEMP[1], IMM[2]\n" 810 " UADD TEMP[1].x, TEMP[1], TEMP[0]\n" 811 " LOAD TEMP[0].x, RLOCAL, TEMP[0]\n" 812 " STORE RES[0].x, TEMP[1], TEMP[0]\n" 813 " RET\n" 814 " ENDSUB\n"; 815 816 printf("- %s\n", __func__); 817 818 init_prog(ctx, 256, 0, 0, src, NULL); 819 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 820 4096, 0, test_default_init); 821 init_compute_resources(ctx, (int []) { 0, -1 }); 822 launch_grid(ctx, (uint []){64, 1, 1}, (uint []){16, 1, 1}, 0, NULL); 823 check_tex(ctx, 0, test_local_expect, NULL); 824 destroy_compute_resources(ctx); 825 destroy_tex(ctx); 826 destroy_prog(ctx); 827} 828 829/* test_sample */ 830static void test_sample_init(void *p, int s, int x, int y) 831{ 832 *(float *)p = s ? 1 : x * y; 833} 834 835static void test_sample_expect(void *p, int s, int x, int y) 836{ 837 switch (x % 4) { 838 case 0: 839 *(float *)p = x / 4 * y; 840 break; 841 case 1: 842 case 2: 843 *(float *)p = 0; 844 break; 845 case 3: 846 *(float *)p = 1; 847 break; 848 } 849} 850 851static void test_sample(struct context *ctx) 852{ 853 const char *src = "COMP\n" 854 "DCL SVIEW[0], 2D, FLOAT\n" 855 "DCL RES[0], 2D, RAW, WR\n" 856 "DCL SAMP[0]\n" 857 "DCL SV[0], BLOCK_ID[0]\n" 858 "DCL TEMP[0], LOCAL\n" 859 "DCL TEMP[1], LOCAL\n" 860 "IMM UINT32 { 16, 1, 0, 0 }\n" 861 "IMM FLT32 { 128, 32, 0, 0 }\n" 862 "\n" 863 " BGNSUB\n" 864 " I2F TEMP[1], SV[0]\n" 865 " DIV TEMP[1], TEMP[1], IMM[1]\n" 866 " SAMPLE TEMP[1], TEMP[1], SVIEW[0], SAMP[0]\n" 867 " UMUL TEMP[0], SV[0], IMM[0]\n" 868 " STORE RES[0].xyzw, TEMP[0], TEMP[1]\n" 869 " RET\n" 870 " ENDSUB\n"; 871 872 printf("- %s\n", __func__); 873 874 init_prog(ctx, 0, 0, 0, src, NULL); 875 init_tex(ctx, 0, PIPE_TEXTURE_2D, true, PIPE_FORMAT_R32_FLOAT, 876 128, 32, test_sample_init); 877 init_tex(ctx, 1, PIPE_TEXTURE_2D, true, PIPE_FORMAT_R32_FLOAT, 878 512, 32, test_sample_init); 879 init_compute_resources(ctx, (int []) { 1, -1 }); 880 init_sampler_views(ctx, (int []) { 0, -1 }); 881 init_sampler_states(ctx, 2); 882 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){128, 32, 1}, 0, NULL); 883 check_tex(ctx, 1, test_sample_expect, NULL); 884 destroy_sampler_states(ctx); 885 destroy_sampler_views(ctx); 886 destroy_compute_resources(ctx); 887 destroy_tex(ctx); 888 destroy_prog(ctx); 889} 890 891/* test_many_kern */ 892static void test_many_kern_expect(void *p, int s, int x, int y) 893{ 894 *(uint32_t *)p = x; 895} 896 897static void test_many_kern(struct context *ctx) 898{ 899 const char *src = "COMP\n" 900 "DCL RES[0], BUFFER, RAW, WR\n" 901 "DCL TEMP[0], LOCAL\n" 902 "IMM UINT32 { 0, 1, 2, 3 }\n" 903 "IMM UINT32 { 4, 0, 0, 0 }\n" 904 "\n" 905 " BGNSUB\n" 906 " UMUL TEMP[0].x, IMM[0].xxxx, IMM[1].xxxx\n" 907 " STORE RES[0].x, TEMP[0], IMM[0].xxxx\n" 908 " RET\n" 909 " ENDSUB\n" 910 " BGNSUB\n" 911 " UMUL TEMP[0].x, IMM[0].yyyy, IMM[1].xxxx\n" 912 " STORE RES[0].x, TEMP[0], IMM[0].yyyy\n" 913 " RET\n" 914 " ENDSUB\n" 915 " BGNSUB\n" 916 " UMUL TEMP[0].x, IMM[0].zzzz, IMM[1].xxxx\n" 917 " STORE RES[0].x, TEMP[0], IMM[0].zzzz\n" 918 " RET\n" 919 " ENDSUB\n" 920 " BGNSUB\n" 921 " UMUL TEMP[0].x, IMM[0].wwww, IMM[1].xxxx\n" 922 " STORE RES[0].x, TEMP[0], IMM[0].wwww\n" 923 " RET\n" 924 " ENDSUB\n"; 925 926 printf("- %s\n", __func__); 927 928 init_prog(ctx, 0, 0, 0, src, NULL); 929 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 930 16, 0, test_default_init); 931 init_compute_resources(ctx, (int []) { 0, -1 }); 932 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){1, 1, 1}, 0, NULL); 933 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){1, 1, 1}, 5, NULL); 934 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){1, 1, 1}, 10, NULL); 935 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){1, 1, 1}, 15, NULL); 936 check_tex(ctx, 0, test_many_kern_expect, NULL); 937 destroy_compute_resources(ctx); 938 destroy_tex(ctx); 939 destroy_prog(ctx); 940} 941 942/* test_constant */ 943static void test_constant_init(void *p, int s, int x, int y) 944{ 945 *(float *)p = s ? 0xdeadbeef : 8.0 - (float)x; 946} 947 948static void test_constant_expect(void *p, int s, int x, int y) 949{ 950 *(float *)p = 8.0 - (float)x; 951} 952 953static void test_constant(struct context *ctx) 954{ 955 const char *src = "COMP\n" 956 "DCL RES[0], BUFFER, RAW\n" 957 "DCL RES[1], BUFFER, RAW, WR\n" 958 "DCL SV[0], BLOCK_ID[0]\n" 959 "DCL TEMP[0], LOCAL\n" 960 "DCL TEMP[1], LOCAL\n" 961 "IMM UINT32 { 4, 0, 0, 0 }\n" 962 "\n" 963 " BGNSUB\n" 964 " UMUL TEMP[0].x, SV[0], IMM[0]\n" 965 " LOAD TEMP[1].x, RES[0], TEMP[0]\n" 966 " STORE RES[1].x, TEMP[0], TEMP[1]\n" 967 " RET\n" 968 " ENDSUB\n"; 969 970 printf("- %s\n", __func__); 971 972 init_prog(ctx, 0, 0, 0, src, NULL); 973 init_tex(ctx, 0, PIPE_BUFFER, false, PIPE_FORMAT_R32_FLOAT, 974 256, 0, test_constant_init); 975 init_tex(ctx, 1, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 976 256, 0, test_constant_init); 977 init_compute_resources(ctx, (int []) { 0, 1, -1 }); 978 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){64, 1, 1}, 0, NULL); 979 check_tex(ctx, 1, test_constant_expect, NULL); 980 destroy_compute_resources(ctx); 981 destroy_tex(ctx); 982 destroy_prog(ctx); 983} 984 985/* test_resource_indirect */ 986static void test_resource_indirect_init(void *p, int s, int x, int y) 987{ 988 *(uint32_t *)p = s == 0 ? 0xdeadbeef : 989 s == 1 ? x % 2 : 990 s == 2 ? 2 * x : 991 2 * x + 1; 992} 993 994static void test_resource_indirect_expect(void *p, int s, int x, int y) 995{ 996 *(uint32_t *)p = 2 * x + (x % 2 ? 1 : 0); 997} 998 999static void test_resource_indirect(struct context *ctx) 1000{ 1001 const char *src = "COMP\n" 1002 "DCL RES[0], BUFFER, RAW, WR\n" 1003 "DCL RES[1..3], BUFFER, RAW\n" 1004 "DCL SV[0], BLOCK_ID[0]\n" 1005 "DCL TEMP[0], LOCAL\n" 1006 "DCL TEMP[1], LOCAL\n" 1007 "IMM UINT32 { 4, 0, 0, 0 }\n" 1008 "\n" 1009 " BGNSUB\n" 1010 " UMUL TEMP[0].x, SV[0], IMM[0]\n" 1011 " LOAD TEMP[1].x, RES[1], TEMP[0]\n" 1012 " LOAD TEMP[1].x, RES[TEMP[1].x+2], TEMP[0]\n" 1013 " STORE RES[0].x, TEMP[0], TEMP[1]\n" 1014 " RET\n" 1015 " ENDSUB\n"; 1016 1017 printf("- %s\n", __func__); 1018 1019 init_prog(ctx, 0, 0, 0, src, NULL); 1020 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 1021 256, 0, test_resource_indirect_init); 1022 init_tex(ctx, 1, PIPE_BUFFER, false, PIPE_FORMAT_R32_FLOAT, 1023 256, 0, test_resource_indirect_init); 1024 init_tex(ctx, 2, PIPE_BUFFER, false, PIPE_FORMAT_R32_FLOAT, 1025 256, 0, test_resource_indirect_init); 1026 init_tex(ctx, 3, PIPE_BUFFER, false, PIPE_FORMAT_R32_FLOAT, 1027 256, 0, test_resource_indirect_init); 1028 init_compute_resources(ctx, (int []) { 0, 1, 2, 3, -1 }); 1029 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){64, 1, 1}, 0, NULL); 1030 check_tex(ctx, 0, test_resource_indirect_expect, NULL); 1031 destroy_compute_resources(ctx); 1032 destroy_tex(ctx); 1033 destroy_prog(ctx); 1034} 1035 1036/* test_surface_ld */ 1037enum pipe_format surface_fmts[] = { 1038 PIPE_FORMAT_B8G8R8A8_UNORM, 1039 PIPE_FORMAT_B8G8R8X8_UNORM, 1040 PIPE_FORMAT_A8R8G8B8_UNORM, 1041 PIPE_FORMAT_X8R8G8B8_UNORM, 1042 PIPE_FORMAT_X8R8G8B8_UNORM, 1043 PIPE_FORMAT_L8_UNORM, 1044 PIPE_FORMAT_A8_UNORM, 1045 PIPE_FORMAT_I8_UNORM, 1046 PIPE_FORMAT_L8A8_UNORM, 1047 PIPE_FORMAT_R32_FLOAT, 1048 PIPE_FORMAT_R32G32_FLOAT, 1049 PIPE_FORMAT_R32G32B32A32_FLOAT, 1050 PIPE_FORMAT_R32_UNORM, 1051 PIPE_FORMAT_R32G32_UNORM, 1052 PIPE_FORMAT_R32G32B32A32_UNORM, 1053 PIPE_FORMAT_R32_SNORM, 1054 PIPE_FORMAT_R32G32_SNORM, 1055 PIPE_FORMAT_R32G32B32A32_SNORM, 1056 PIPE_FORMAT_R8_UINT, 1057 PIPE_FORMAT_R8G8_UINT, 1058 PIPE_FORMAT_R8G8B8A8_UINT, 1059 PIPE_FORMAT_R8_SINT, 1060 PIPE_FORMAT_R8G8_SINT, 1061 PIPE_FORMAT_R8G8B8A8_SINT, 1062 PIPE_FORMAT_R32_UINT, 1063 PIPE_FORMAT_R32G32_UINT, 1064 PIPE_FORMAT_R32G32B32A32_UINT, 1065 PIPE_FORMAT_R32_SINT, 1066 PIPE_FORMAT_R32G32_SINT, 1067 PIPE_FORMAT_R32G32B32A32_SINT 1068}; 1069 1070static void test_surface_ld_init0f(void *p, int s, int x, int y) 1071{ 1072 float v[] = { 1.0, -.75, .50, -.25 }; 1073 int i = 0; 1074 1075 util_format_write_4f(surface_fmts[i], v, 0, p, 0, 0, 0, 1, 1); 1076} 1077 1078static void test_surface_ld_init0i(void *p, int s, int x, int y) 1079{ 1080 int v[] = { 0xffffffff, 0xffff, 0xff, 0xf }; 1081 int i = 0; 1082 1083 util_format_write_4i(surface_fmts[i], v, 0, p, 0, 0, 0, 1, 1); 1084} 1085 1086static void test_surface_ld_expectf(void *p, int s, int x, int y) 1087{ 1088 float v[4], w[4]; 1089 int i = 0; 1090 1091 test_surface_ld_init0f(v, s, x / 4, y); 1092 util_format_read_4f(surface_fmts[i], w, 0, v, 0, 0, 0, 1, 1); 1093 *(float *)p = w[x % 4]; 1094} 1095 1096static void test_surface_ld_expecti(void *p, int s, int x, int y) 1097{ 1098 int32_t v[4], w[4]; 1099 int i = 0; 1100 1101 test_surface_ld_init0i(v, s, x / 4, y); 1102 util_format_read_4i(surface_fmts[i], w, 0, v, 0, 0, 0, 1, 1); 1103 *(uint32_t *)p = w[x % 4]; 1104} 1105 1106static void test_surface_ld(struct context *ctx) 1107{ 1108 const char *src = "COMP\n" 1109 "DCL RES[0], 2D\n" 1110 "DCL RES[1], 2D, RAW, WR\n" 1111 "DCL SV[0], BLOCK_ID[0]\n" 1112 "DCL TEMP[0], LOCAL\n" 1113 "DCL TEMP[1], LOCAL\n" 1114 "IMM UINT32 { 16, 1, 0, 0 }\n" 1115 "\n" 1116 " BGNSUB\n" 1117 " LOAD TEMP[1], RES[0], SV[0]\n" 1118 " UMUL TEMP[0], SV[0], IMM[0]\n" 1119 " STORE RES[1].xyzw, TEMP[0], TEMP[1]\n" 1120 " RET\n" 1121 " ENDSUB\n"; 1122 int i = 0; 1123 1124 printf("- %s\n", __func__); 1125 1126 init_prog(ctx, 0, 0, 0, src, NULL); 1127 1128 for (i = 0; i < ARRAY_SIZE(surface_fmts); i++) { 1129 bool is_int = util_format_is_pure_integer(surface_fmts[i]); 1130 1131 printf(" - %s\n", util_format_name(surface_fmts[i])); 1132 1133 if (!ctx->screen->is_format_supported(ctx->screen, 1134 surface_fmts[i], PIPE_TEXTURE_2D, 1, 1135 PIPE_BIND_COMPUTE_RESOURCE)) { 1136 printf("(unsupported)\n"); 1137 continue; 1138 } 1139 1140 init_tex(ctx, 0, PIPE_TEXTURE_2D, true, surface_fmts[i], 1141 128, 32, (is_int ? test_surface_ld_init0i : test_surface_ld_init0f)); 1142 init_tex(ctx, 1, PIPE_TEXTURE_2D, true, PIPE_FORMAT_R32_FLOAT, 1143 512, 32, test_default_init); 1144 init_compute_resources(ctx, (int []) { 0, 1, -1 }); 1145 init_sampler_states(ctx, 2); 1146 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){128, 32, 1}, 0, 1147 NULL); 1148 check_tex(ctx, 1, (is_int ? test_surface_ld_expecti : test_surface_ld_expectf), NULL); 1149 destroy_sampler_states(ctx); 1150 destroy_compute_resources(ctx); 1151 destroy_tex(ctx); 1152 } 1153 1154 destroy_prog(ctx); 1155} 1156 1157/* test_surface_st */ 1158static void test_surface_st_init0f(void *p, int s, int x, int y) 1159{ 1160 float v[] = { 1.0, -.75, 0.5, -.25 }; 1161 *(float *)p = v[x % 4]; 1162} 1163 1164static void test_surface_st_init0i(void *p, int s, int x, int y) 1165{ 1166 int v[] = { 0xffffffff, 0xffff, 0xff, 0xf }; 1167 *(int32_t *)p = v[x % 4]; 1168} 1169 1170static void test_surface_st_init1(void *p, int s, int x, int y) 1171{ 1172 int i = 0; 1173 memset(p, 1, util_format_get_blocksize(surface_fmts[i])); 1174} 1175 1176static void test_surface_st_expectf(void *p, int s, int x, int y) 1177{ 1178 float vf[4]; 1179 int i = 0, j; 1180 1181 for (j = 0; j < 4; j++) 1182 test_surface_st_init0f(&vf[j], s, 4 * x + j, y); 1183 util_format_write_4f(surface_fmts[i], vf, 0, p, 0, 0, 0, 1, 1); 1184} 1185 1186static void test_surface_st_expects(void *p, int s, int x, int y) 1187{ 1188 int32_t v[4]; 1189 int i = 0, j; 1190 1191 for (j = 0; j < 4; j++) 1192 test_surface_st_init0i(&v[j], s, 4 * x + j, y); 1193 util_format_write_4i(surface_fmts[i], v, 0, p, 0, 0, 0, 1, 1); 1194} 1195 1196static void test_surface_st_expectu(void *p, int s, int x, int y) 1197{ 1198 uint32_t v[4]; 1199 int i = 0, j; 1200 1201 for (j = 0; j < 4; j++) 1202 test_surface_st_init0i(&v[j], s, 4 * x + j, y); 1203 util_format_write_4ui(surface_fmts[i], v, 0, p, 0, 0, 0, 1, 1); 1204} 1205 1206static bool test_surface_st_check(void *x, void *y, int sz) 1207{ 1208 int i = 0, j; 1209 1210 if (util_format_is_float(surface_fmts[i])) { 1211 return fabs(*(float *)x - *(float *)y) < 3.92156863e-3; 1212 1213 } else if ((sz % 4) == 0) { 1214 for (j = 0; j < sz / 4; j++) 1215 if (abs(((uint32_t *)x)[j] - 1216 ((uint32_t *)y)[j]) > 1) 1217 return false; 1218 return true; 1219 } else { 1220 return !memcmp(x, y, sz); 1221 } 1222} 1223 1224static void test_surface_st(struct context *ctx) 1225{ 1226 const char *src = "COMP\n" 1227 "DCL RES[0], 2D, RAW\n" 1228 "DCL RES[1], 2D, WR\n" 1229 "DCL SV[0], BLOCK_ID[0]\n" 1230 "DCL TEMP[0], LOCAL\n" 1231 "DCL TEMP[1], LOCAL\n" 1232 "IMM UINT32 { 16, 1, 0, 0 }\n" 1233 "\n" 1234 " BGNSUB\n" 1235 " UMUL TEMP[0], SV[0], IMM[0]\n" 1236 " LOAD TEMP[1], RES[0], TEMP[0]\n" 1237 " STORE RES[1], SV[0], TEMP[1]\n" 1238 " RET\n" 1239 " ENDSUB\n"; 1240 int i = 0; 1241 1242 printf("- %s\n", __func__); 1243 1244 init_prog(ctx, 0, 0, 0, src, NULL); 1245 1246 for (i = 0; i < ARRAY_SIZE(surface_fmts); i++) { 1247 bool is_signed = (util_format_description(surface_fmts[i]) 1248 ->channel[0].type == UTIL_FORMAT_TYPE_SIGNED); 1249 bool is_int = util_format_is_pure_integer(surface_fmts[i]); 1250 1251 printf(" - %s\n", util_format_name(surface_fmts[i])); 1252 1253 if (!ctx->screen->is_format_supported(ctx->screen, 1254 surface_fmts[i], PIPE_TEXTURE_2D, 1, 1255 PIPE_BIND_COMPUTE_RESOURCE)) { 1256 printf("(unsupported)\n"); 1257 continue; 1258 } 1259 1260 init_tex(ctx, 0, PIPE_TEXTURE_2D, true, PIPE_FORMAT_R32_FLOAT, 1261 512, 32, (is_int ? test_surface_st_init0i : test_surface_st_init0f)); 1262 init_tex(ctx, 1, PIPE_TEXTURE_2D, true, surface_fmts[i], 1263 128, 32, test_surface_st_init1); 1264 init_compute_resources(ctx, (int []) { 0, 1, -1 }); 1265 init_sampler_states(ctx, 2); 1266 launch_grid(ctx, (uint []){1, 1, 1}, (uint []){128, 32, 1}, 0, 1267 NULL); 1268 check_tex(ctx, 1, (is_int && is_signed ? test_surface_st_expects : 1269 is_int && !is_signed ? test_surface_st_expectu : 1270 test_surface_st_expectf), test_surface_st_check); 1271 destroy_sampler_states(ctx); 1272 destroy_compute_resources(ctx); 1273 destroy_tex(ctx); 1274 } 1275 1276 destroy_prog(ctx); 1277} 1278 1279/* test_barrier */ 1280static void test_barrier_expect(void *p, int s, int x, int y) 1281{ 1282 *(uint32_t *)p = 31; 1283} 1284 1285static void test_barrier(struct context *ctx) 1286{ 1287 const char *src = "COMP\n" 1288 "DCL RES[0], BUFFER, RAW, WR\n" 1289 "DCL SV[0], BLOCK_ID[0]\n" 1290 "DCL SV[1], BLOCK_SIZE[0]\n" 1291 "DCL SV[2], THREAD_ID[0]\n" 1292 "DCL TEMP[0], LOCAL\n" 1293 "DCL TEMP[1], LOCAL\n" 1294 "DCL TEMP[2], LOCAL\n" 1295 "DCL TEMP[3], LOCAL\n" 1296 "IMM UINT32 { 1, 0, 0, 0 }\n" 1297 "IMM UINT32 { 4, 0, 0, 0 }\n" 1298 "IMM UINT32 { 32, 0, 0, 0 }\n" 1299 "\n" 1300 " BGNSUB\n" 1301 " UMUL TEMP[0].x, SV[2], IMM[1]\n" 1302 " MOV TEMP[1].x, IMM[0].wwww\n" 1303 " BGNLOOP\n" 1304 " BARRIER\n" 1305 " STORE RLOCAL.x, TEMP[0], TEMP[1]\n" 1306 " BARRIER\n" 1307 " MOV TEMP[2].x, IMM[0].wwww\n" 1308 " BGNLOOP\n" 1309 " UMUL TEMP[3].x, TEMP[2], IMM[1]\n" 1310 " LOAD TEMP[3].x, RLOCAL, TEMP[3]\n" 1311 " USNE TEMP[3].x, TEMP[3], TEMP[1]\n" 1312 " IF TEMP[3]\n" 1313 " END\n" 1314 " ENDIF\n" 1315 " UADD TEMP[2].x, TEMP[2], IMM[0]\n" 1316 " USEQ TEMP[3].x, TEMP[2], SV[1]\n" 1317 " IF TEMP[3]\n" 1318 " BRK\n" 1319 " ENDIF\n" 1320 " ENDLOOP\n" 1321 " UADD TEMP[1].x, TEMP[1], IMM[0]\n" 1322 " USEQ TEMP[2].x, TEMP[1], IMM[2]\n" 1323 " IF TEMP[2]\n" 1324 " BRK\n" 1325 " ENDIF\n" 1326 " ENDLOOP\n" 1327 " UMUL TEMP[1].x, SV[0], SV[1]\n" 1328 " UMUL TEMP[1].x, TEMP[1], IMM[1]\n" 1329 " UADD TEMP[1].x, TEMP[1], TEMP[0]\n" 1330 " LOAD TEMP[0].x, RLOCAL, TEMP[0]\n" 1331 " STORE RES[0].x, TEMP[1], TEMP[0]\n" 1332 " RET\n" 1333 " ENDSUB\n"; 1334 1335 printf("- %s\n", __func__); 1336 1337 init_prog(ctx, 256, 0, 0, src, NULL); 1338 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 1339 4096, 0, test_default_init); 1340 init_compute_resources(ctx, (int []) { 0, -1 }); 1341 launch_grid(ctx, (uint []){64, 1, 1}, (uint []){16, 1, 1}, 0, NULL); 1342 check_tex(ctx, 0, test_barrier_expect, NULL); 1343 destroy_compute_resources(ctx); 1344 destroy_tex(ctx); 1345 destroy_prog(ctx); 1346} 1347 1348/* test_atom_ops */ 1349static void test_atom_ops_init(void *p, int s, int x, int y) 1350{ 1351 *(uint32_t *)p = 0xbad; 1352} 1353 1354static void test_atom_ops_expect(void *p, int s, int x, int y) 1355{ 1356 switch (x) { 1357 case 0: 1358 *(uint32_t *)p = 0xce6c8eef; 1359 break; 1360 case 1: 1361 *(uint32_t *)p = 0xdeadbeef; 1362 break; 1363 case 2: 1364 *(uint32_t *)p = 0x11111111; 1365 break; 1366 case 3: 1367 *(uint32_t *)p = 0x10011001; 1368 break; 1369 case 4: 1370 *(uint32_t *)p = 0xdfbdbfff; 1371 break; 1372 case 5: 1373 *(uint32_t *)p = 0x11111111; 1374 break; 1375 case 6: 1376 *(uint32_t *)p = 0x11111111; 1377 break; 1378 case 7: 1379 *(uint32_t *)p = 0xdeadbeef; 1380 break; 1381 case 8: 1382 *(uint32_t *)p = 0xdeadbeef; 1383 break; 1384 case 9: 1385 *(uint32_t *)p = 0x11111111; 1386 break; 1387 } 1388} 1389 1390static void test_atom_ops(struct context *ctx, bool global) 1391{ 1392 const char *src = "COMP\n" 1393 "#ifdef TARGET_GLOBAL\n" 1394 "#define target RES[0]\n" 1395 "#else\n" 1396 "#define target RLOCAL\n" 1397 "#endif\n" 1398 "" 1399 "DCL RES[0], BUFFER, RAW, WR\n" 1400 "#define threadid SV[0]\n" 1401 "DCL threadid, THREAD_ID[0]\n" 1402 "" 1403 "#define offset TEMP[0]\n" 1404 "DCL offset, LOCAL\n" 1405 "#define tmp TEMP[1]\n" 1406 "DCL tmp, LOCAL\n" 1407 "" 1408 "#define k0 IMM[0]\n" 1409 "IMM UINT32 { 0, 0, 0, 0 }\n" 1410 "#define k1 IMM[1]\n" 1411 "IMM UINT32 { 1, 0, 0, 0 }\n" 1412 "#define k2 IMM[2]\n" 1413 "IMM UINT32 { 2, 0, 0, 0 }\n" 1414 "#define k3 IMM[3]\n" 1415 "IMM UINT32 { 3, 0, 0, 0 }\n" 1416 "#define k4 IMM[4]\n" 1417 "IMM UINT32 { 4, 0, 0, 0 }\n" 1418 "#define k5 IMM[5]\n" 1419 "IMM UINT32 { 5, 0, 0, 0 }\n" 1420 "#define k6 IMM[6]\n" 1421 "IMM UINT32 { 6, 0, 0, 0 }\n" 1422 "#define k7 IMM[7]\n" 1423 "IMM UINT32 { 7, 0, 0, 0 }\n" 1424 "#define k8 IMM[8]\n" 1425 "IMM UINT32 { 8, 0, 0, 0 }\n" 1426 "#define k9 IMM[9]\n" 1427 "IMM UINT32 { 9, 0, 0, 0 }\n" 1428 "#define korig IMM[10].xxxx\n" 1429 "#define karg IMM[10].yyyy\n" 1430 "IMM UINT32 { 3735928559, 286331153, 0, 0 }\n" 1431 "\n" 1432 " BGNSUB\n" 1433 " UMUL offset.x, threadid, k4\n" 1434 " STORE target.x, offset, korig\n" 1435 " USEQ tmp.x, threadid, k0\n" 1436 " IF tmp\n" 1437 " ATOMUADD tmp.x, target, offset, karg\n" 1438 " ATOMUADD tmp.x, target, offset, tmp\n" 1439 " ENDIF\n" 1440 " USEQ tmp.x, threadid, k1\n" 1441 " IF tmp\n" 1442 " ATOMXCHG tmp.x, target, offset, karg\n" 1443 " ATOMXCHG tmp.x, target, offset, tmp\n" 1444 " ENDIF\n" 1445 " USEQ tmp.x, threadid, k2\n" 1446 " IF tmp\n" 1447 " ATOMCAS tmp.x, target, offset, korig, karg\n" 1448 " ATOMCAS tmp.x, target, offset, tmp, k0\n" 1449 " ENDIF\n" 1450 " USEQ tmp.x, threadid, k3\n" 1451 " IF tmp\n" 1452 " ATOMAND tmp.x, target, offset, karg\n" 1453 " ATOMAND tmp.x, target, offset, tmp\n" 1454 " ENDIF\n" 1455 " USEQ tmp.x, threadid, k4\n" 1456 " IF tmp\n" 1457 " ATOMOR tmp.x, target, offset, karg\n" 1458 " ATOMOR tmp.x, target, offset, tmp\n" 1459 " ENDIF\n" 1460 " USEQ tmp.x, threadid, k5\n" 1461 " IF tmp\n" 1462 " ATOMXOR tmp.x, target, offset, karg\n" 1463 " ATOMXOR tmp.x, target, offset, tmp\n" 1464 " ENDIF\n" 1465 " USEQ tmp.x, threadid, k6\n" 1466 " IF tmp\n" 1467 " ATOMUMIN tmp.x, target, offset, karg\n" 1468 " ATOMUMIN tmp.x, target, offset, tmp\n" 1469 " ENDIF\n" 1470 " USEQ tmp.x, threadid, k7\n" 1471 " IF tmp\n" 1472 " ATOMUMAX tmp.x, target, offset, karg\n" 1473 " ATOMUMAX tmp.x, target, offset, tmp\n" 1474 " ENDIF\n" 1475 " USEQ tmp.x, threadid, k8\n" 1476 " IF tmp\n" 1477 " ATOMIMIN tmp.x, target, offset, karg\n" 1478 " ATOMIMIN tmp.x, target, offset, tmp\n" 1479 " ENDIF\n" 1480 " USEQ tmp.x, threadid, k9\n" 1481 " IF tmp\n" 1482 " ATOMIMAX tmp.x, target, offset, karg\n" 1483 " ATOMIMAX tmp.x, target, offset, tmp\n" 1484 " ENDIF\n" 1485 "#ifdef TARGET_LOCAL\n" 1486 " LOAD tmp.x, RLOCAL, offset\n" 1487 " STORE RES[0].x, offset, tmp\n" 1488 "#endif\n" 1489 " RET\n" 1490 " ENDSUB\n"; 1491 1492 printf("- %s (%s)\n", __func__, global ? "global" : "local"); 1493 1494 init_prog(ctx, 40, 0, 0, src, 1495 (global ? "-DTARGET_GLOBAL" : "-DTARGET_LOCAL")); 1496 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 1497 40, 0, test_atom_ops_init); 1498 init_compute_resources(ctx, (int []) { 0, -1 }); 1499 launch_grid(ctx, (uint []){10, 1, 1}, (uint []){1, 1, 1}, 0, NULL); 1500 check_tex(ctx, 0, test_atom_ops_expect, NULL); 1501 destroy_compute_resources(ctx); 1502 destroy_tex(ctx); 1503 destroy_prog(ctx); 1504} 1505 1506/* test_atom_race */ 1507static void test_atom_race_expect(void *p, int s, int x, int y) 1508{ 1509 *(uint32_t *)p = x & 0x20 ? 0x11111111 : 0xffffffff; 1510} 1511 1512static void test_atom_race(struct context *ctx, bool global) 1513{ 1514 const char *src = "COMP\n" 1515 "#ifdef TARGET_GLOBAL\n" 1516 "#define target RES[0]\n" 1517 "#else\n" 1518 "#define target RLOCAL\n" 1519 "#endif\n" 1520 "" 1521 "DCL RES[0], BUFFER, RAW, WR\n" 1522 "" 1523 "#define blockid SV[0]\n" 1524 "DCL blockid, BLOCK_ID[0]\n" 1525 "#define blocksz SV[1]\n" 1526 "DCL blocksz, BLOCK_SIZE[0]\n" 1527 "#define threadid SV[2]\n" 1528 "DCL threadid, THREAD_ID[0]\n" 1529 "" 1530 "#define offset TEMP[0]\n" 1531 "DCL offset, LOCAL\n" 1532 "#define arg TEMP[1]\n" 1533 "DCL arg, LOCAL\n" 1534 "#define count TEMP[2]\n" 1535 "DCL count, LOCAL\n" 1536 "#define vlocal TEMP[3]\n" 1537 "DCL vlocal, LOCAL\n" 1538 "#define vshared TEMP[4]\n" 1539 "DCL vshared, LOCAL\n" 1540 "#define last TEMP[5]\n" 1541 "DCL last, LOCAL\n" 1542 "#define tmp0 TEMP[6]\n" 1543 "DCL tmp0, LOCAL\n" 1544 "#define tmp1 TEMP[7]\n" 1545 "DCL tmp1, LOCAL\n" 1546 "" 1547 "#define k0 IMM[0]\n" 1548 "IMM UINT32 { 0, 0, 0, 0 }\n" 1549 "#define k1 IMM[1]\n" 1550 "IMM UINT32 { 1, 0, 0, 0 }\n" 1551 "#define k4 IMM[2]\n" 1552 "IMM UINT32 { 4, 0, 0, 0 }\n" 1553 "#define k32 IMM[3]\n" 1554 "IMM UINT32 { 32, 0, 0, 0 }\n" 1555 "#define k128 IMM[4]\n" 1556 "IMM UINT32 { 128, 0, 0, 0 }\n" 1557 "#define kdeadcafe IMM[5]\n" 1558 "IMM UINT32 { 3735931646, 0, 0, 0 }\n" 1559 "#define kallowed_set IMM[6]\n" 1560 "IMM UINT32 { 559035650, 0, 0, 0 }\n" 1561 "#define k11111111 IMM[7]\n" 1562 "IMM UINT32 { 286331153, 0, 0, 0 }\n" 1563 "\n" 1564 " BGNSUB\n" 1565 " MOV offset.x, threadid\n" 1566 "#ifdef TARGET_GLOBAL\n" 1567 " UMUL tmp0.x, blockid, blocksz\n" 1568 " UADD offset.x, offset, tmp0\n" 1569 "#endif\n" 1570 " UMUL offset.x, offset, k4\n" 1571 " USLT tmp0.x, threadid, k32\n" 1572 " STORE target.x, offset, k0\n" 1573 " BARRIER\n" 1574 " IF tmp0\n" 1575 " MOV vlocal.x, k0\n" 1576 " MOV arg.x, kdeadcafe\n" 1577 " BGNLOOP\n" 1578 " INEG arg.x, arg\n" 1579 " ATOMUADD vshared.x, target, offset, arg\n" 1580 " SFENCE target\n" 1581 " USNE tmp0.x, vshared, vlocal\n" 1582 " IF tmp0\n" 1583 " BRK\n" 1584 " ENDIF\n" 1585 " UADD vlocal.x, vlocal, arg\n" 1586 " ENDLOOP\n" 1587 " UADD vlocal.x, vshared, arg\n" 1588 " LOAD vshared.x, target, offset\n" 1589 " USEQ tmp0.x, vshared, vlocal\n" 1590 " STORE target.x, offset, tmp0\n" 1591 " ELSE\n" 1592 " UADD offset.x, offset, -k128\n" 1593 " MOV count.x, k0\n" 1594 " MOV last.x, k0\n" 1595 " BGNLOOP\n" 1596 " LOAD vshared.x, target, offset\n" 1597 " USEQ tmp0.x, vshared, kallowed_set.xxxx\n" 1598 " USEQ tmp1.x, vshared, kallowed_set.yyyy\n" 1599 " OR tmp0.x, tmp0, tmp1\n" 1600 " IF tmp0\n" 1601 " USEQ tmp0.x, vshared, last\n" 1602 " IF tmp0\n" 1603 " CONT\n" 1604 " ENDIF\n" 1605 " MOV last.x, vshared\n" 1606 " ELSE\n" 1607 " END\n" 1608 " ENDIF\n" 1609 " UADD count.x, count, k1\n" 1610 " USEQ tmp0.x, count, k128\n" 1611 " IF tmp0\n" 1612 " BRK\n" 1613 " ENDIF\n" 1614 " ENDLOOP\n" 1615 " ATOMXCHG tmp0.x, target, offset, k11111111\n" 1616 " UADD offset.x, offset, k128\n" 1617 " ATOMXCHG tmp0.x, target, offset, k11111111\n" 1618 " SFENCE target\n" 1619 " ENDIF\n" 1620 "#ifdef TARGET_LOCAL\n" 1621 " LOAD tmp0.x, RLOCAL, offset\n" 1622 " UMUL tmp1.x, blockid, blocksz\n" 1623 " UMUL tmp1.x, tmp1, k4\n" 1624 " UADD offset.x, offset, tmp1\n" 1625 " STORE RES[0].x, offset, tmp0\n" 1626 "#endif\n" 1627 " RET\n" 1628 " ENDSUB\n"; 1629 1630 printf("- %s (%s)\n", __func__, global ? "global" : "local"); 1631 1632 init_prog(ctx, 256, 0, 0, src, 1633 (global ? "-DTARGET_GLOBAL" : "-DTARGET_LOCAL")); 1634 init_tex(ctx, 0, PIPE_BUFFER, true, PIPE_FORMAT_R32_FLOAT, 1635 4096, 0, test_default_init); 1636 init_compute_resources(ctx, (int []) { 0, -1 }); 1637 launch_grid(ctx, (uint []){64, 1, 1}, (uint []){16, 1, 1}, 0, NULL); 1638 check_tex(ctx, 0, test_atom_race_expect, NULL); 1639 destroy_compute_resources(ctx); 1640 destroy_tex(ctx); 1641 destroy_prog(ctx); 1642} 1643 1644int main(int argc, char *argv[]) 1645{ 1646 struct context *ctx = CALLOC_STRUCT(context); 1647 1648 unsigned tests = (argc > 1) ? strtoul(argv[1], NULL, 0) : ~0; 1649 1650 init_ctx(ctx); 1651 1652 if (tests & (1 << 0)) 1653 test_system_values(ctx); 1654 if (tests & (1 << 1)) 1655 test_resource_access(ctx); 1656 if (tests & (1 << 2)) 1657 test_function_calls(ctx); 1658 if (tests & (1 << 3)) 1659 test_input_global(ctx); 1660 if (tests & (1 << 4)) 1661 test_private(ctx); 1662 if (tests & (1 << 5)) 1663 test_local(ctx); 1664 if (tests & (1 << 6)) 1665 test_sample(ctx); 1666 if (tests & (1 << 7)) 1667 test_many_kern(ctx); 1668 if (tests & (1 << 8)) 1669 test_constant(ctx); 1670 if (tests & (1 << 9)) 1671 test_resource_indirect(ctx); 1672 if (tests & (1 << 10)) 1673 test_surface_ld(ctx); 1674 if (tests & (1 << 11)) 1675 test_surface_st(ctx); 1676 if (tests & (1 << 12)) 1677 test_barrier(ctx); 1678 if (tests & (1 << 13)) 1679 test_atom_ops(ctx, true); 1680 if (tests & (1 << 14)) 1681 test_atom_race(ctx, true); 1682 if (tests & (1 << 15)) 1683 test_atom_ops(ctx, false); 1684 if (tests & (1 << 16)) 1685 test_atom_race(ctx, false); 1686 1687 destroy_ctx(ctx); 1688 1689 return 0; 1690} 1691