1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can 5 * be found in the LICENSE file. 6 * 7 */ 8 9 #pragma once 10 11 // 12 // 13 // 14 15 #include <string.h> 16 #include <assert.h> 17 #include <stdbool.h> 18 19 #include "grid.h" 20 #include "macros.h" 21 #include "runtime_cl_12.h" 22 23 // 24 // SKC grid dependencies can be represented with a DAG. 25 // 26 // This dependency graph may be modified to include some sort of block 27 // pool barrier to make block recovery explicit (and guaranteed safe). 28 // 29 // 30 // PATH BUILDER 31 // | 32 // | 33 // | 34 // v 35 // RASTER BUILDER 36 // | 37 // +----+ | +----+ 38 // Set Ops | | | | | Set Ops 39 // | v v v | 40 // +--COMPOSITION STYLING--+ 41 // | | 42 // | +--------+ 43 // | | 44 // v v 45 // SURFACE 46 // 47 // 48 // STAGE DEPENDENCIES 49 // ============== ============================ 50 // PATH BUILDER - 51 // RASTER BUILDER PATH BUILDER 52 // COMPOSITION RASTER BUILDER, *COMPOSITION 53 // STYLING -, *STYLING 54 // SURFACE COMPOSITION, STYLING 55 // 56 57 // 58 // How many active grids can/should we have? 59 // 60 // FIXME -- we'll need to provide a small level of indirection if we 61 // want to support a much larger number of work-in-progress grids 62 // 63 // For now and for simplicity, unify all grid ids in one set. 64 // 65 66 typedef skc_uchar skc_grid_id_t; // 256 values 67 #define SKC_GRID_ID_INVALID SKC_UCHAR_MAX // 255 68 69 #define SKC_GRID_SIZE_IDS (SKC_GRID_ID_INVALID-1) 70 #define SKC_GRID_SIZE_WORDS ((SKC_GRID_SIZE_IDS+31)/32) 71 72 // 73 // 74 // 75 76 typedef enum skc_grid_state_e { 77 78 SKC_GRID_STATE_READY, 79 SKC_GRID_STATE_WAITING, 80 SKC_GRID_STATE_FORCED, 81 SKC_GRID_STATE_EXECUTING, 82 SKC_GRID_STATE_COMPLETE, 83 SKC_GRID_STATE_DETACHED, 84 85 SKC_GRID_STATE_COUNT 86 87 } skc_grid_state_e; 88 89 // 90 // 91 // 92 93 struct skc_grid_pfn_name 94 { 95 skc_grid_pfn pfn; 96 char const * name; 97 }; 98 99 // 100 // 101 // 102 103 struct skc_grid 104 { 105 skc_grid_state_e state; 106 skc_uint id; 107 108 struct skc_grid_deps * deps; // backpointer to deps 109 void * * addr; // pointer to invalidate 110 111 void * data; 112 113 struct skc_grid_pfn_name waiting; // optional - if defined, typically used to yank the grid away from host 114 struct skc_grid_pfn_name execute; // optional - starts execution of waiting grid 115 struct skc_grid_pfn_name dispose; // optional - invoked when grid is complete 116 117 struct { 118 skc_uint words[SKC_GRID_SIZE_WORDS]; // 0:inactive, 1:active 119 skc_uint count; 120 } before; 121 122 struct { 123 skc_uint words[SKC_GRID_SIZE_WORDS]; // 0:inactive, 1:active 124 skc_uint count; 125 } after; 126 }; 127 128 // 129 // 130 // 131 132 struct skc_grid_deps 133 { 134 struct skc_runtime * runtime; 135 struct skc_scheduler * scheduler; 136 137 skc_grid_id_t * handle_map; 138 139 struct skc_grid grids [SKC_GRID_SIZE_IDS]; // deps + pfns + data 140 skc_uint active[SKC_GRID_SIZE_WORDS]; // 1:inactive, 0:active 141 142 skc_uint count; // number of active ids 143 }; 144 145 // 146 // 147 // 148 149 static 150 void 151 skc_grid_call(skc_grid_t const grid, struct skc_grid_pfn_name const * const pn) 152 { 153 if (pn->pfn != NULL) { 154 pn->pfn(grid); 155 } 156 } 157 158 static 159 void 160 skc_grid_schedule(skc_grid_t const grid, struct skc_grid_pfn_name const * const pn) 161 { 162 if (pn->pfn != NULL) { 163 skc_scheduler_schedule(grid->deps->scheduler,pn->pfn,grid,pn->name); 164 } 165 } 166 167 // 168 // 169 // 170 171 static 172 void 173 skc_grid_invalidate(skc_grid_t const grid) 174 { 175 if (grid->addr != NULL) { 176 *grid->addr = NULL; 177 } 178 } 179 180 // 181 // 182 // 183 184 #if 0 185 skc_grid_t 186 skc_grid_move(skc_grid_t const grid, 187 skc_grid_state_e * const state, 188 skc_grid_t * const addr, 189 void * const data) 190 { 191 skc_grid_invalidate(grid); 192 193 grid->state = state; 194 grid->addr = addr; 195 grid->data = data; 196 197 return grid; 198 } 199 #endif 200 201 void * 202 skc_grid_get_data(skc_grid_t const grid) 203 { 204 return grid->data; 205 } 206 207 void 208 skc_grid_set_data(skc_grid_t const grid, void * const data) 209 { 210 grid->data = data; 211 } 212 213 // 214 // 215 // 216 217 skc_grid_deps_t 218 skc_grid_deps_create(struct skc_runtime * const runtime, 219 struct skc_scheduler * const scheduler, 220 skc_uint const handle_pool_size) 221 { 222 struct skc_grid_deps * const deps = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,sizeof(*deps)); 223 224 // save runtime 225 deps->runtime = runtime; 226 deps->scheduler = scheduler; 227 228 size_t const handle_map_size = sizeof(*deps->handle_map) * handle_pool_size; 229 230 // allocate handle map 231 deps->handle_map = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,handle_map_size); 232 233 // initialize handle map 234 memset(deps->handle_map,0xFF,handle_map_size); 235 236 // grids 237 struct skc_grid * const grids = deps->grids; 238 239 #if 0 // DELETE ME LATER 240 // initalize ids once -- could always infer id using offsetof() 241 for (skc_uint id=0; id < SKC_GRID_SIZE_IDS; id++) 242 grids[id].id = id; 243 #endif 244 245 // mark all grids inactive except for last bit -- 1:inactive / 0:active 246 for (skc_uint ii=0; ii < SKC_GRID_SIZE_WORDS-1; ii++) 247 deps->active[ii] = 0xFFFFFFFF; 248 249 // last bit is marked active so that it is never allocated 250 deps->active[SKC_GRID_SIZE_WORDS-1] = 0x7FFFFFFF; 251 252 // nothing active 253 deps->count = 1; 254 255 return deps; 256 } 257 258 void 259 skc_grid_deps_dispose(skc_grid_deps_t const deps) 260 { 261 // 262 // FIXME -- debug checks for active grids 263 // 264 skc_runtime_host_perm_free(deps->runtime,deps->handle_map); 265 skc_runtime_host_perm_free(deps->runtime,deps); 266 } 267 268 // 269 // 270 // 271 272 #ifndef NDEBUG 273 274 void 275 skc_grid_deps_debug(struct skc_grid_deps const * const deps) 276 { 277 fprintf(stderr, 278 "00000000000000001111111111111111\n" 279 "0123456789ABCDEF0123456789ABCDEF\n" 280 "--------------------------------\n"); 281 282 for (skc_uint ii=0; ii<SKC_GRID_SIZE_WORDS; ii++) 283 { 284 skc_uint const a = deps->active[ii]; 285 fprintf(stderr, 286 "%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u" 287 "%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u\n", 288 (a>>0x00)&1,(a>>0x01)&1,(a>>0x02)&1,(a>>0x03)&1, 289 (a>>0x04)&1,(a>>0x05)&1,(a>>0x06)&1,(a>>0x07)&1, 290 (a>>0x08)&1,(a>>0x09)&1,(a>>0x0A)&1,(a>>0x0B)&1, 291 (a>>0x0C)&1,(a>>0x0D)&1,(a>>0x0E)&1,(a>>0x0F)&1, 292 (a>>0x10)&1,(a>>0x11)&1,(a>>0x12)&1,(a>>0x13)&1, 293 (a>>0x14)&1,(a>>0x15)&1,(a>>0x16)&1,(a>>0x17)&1, 294 (a>>0x18)&1,(a>>0x19)&1,(a>>0x1A)&1,(a>>0x1B)&1, 295 (a>>0x1C)&1,(a>>0x1D)&1,(a>>0x1E)&1,(a>>0x1F)&1); 296 } 297 298 fprintf(stderr,"\n"); 299 } 300 301 #endif 302 303 // 304 // 305 // 306 307 skc_grid_t 308 skc_grid_deps_attach(skc_grid_deps_t const deps, 309 skc_grid_t * const addr, 310 void * const data, 311 skc_grid_pfn waiting_pfn, // upon READY > WAITING 312 skc_grid_pfn execute_pfn, // upon READY/WAITING > EXECUTING 313 skc_grid_pfn dispose_pfn, // upon EXECUTING > COMPLETE 314 char const * const waiting_name, 315 char const * const execute_name, 316 char const * const dispose_name) 317 { 318 // 319 // FIXME -- no more ids -- either fatal or flush & wait for grids to be released 320 // 321 // assert(deps->count < SKC_GRID_SIZE_IDS); 322 // 323 while (deps->count == SKC_GRID_SIZE_IDS) 324 skc_scheduler_wait_one(deps->scheduler); 325 326 // otherwise, an id exists so decrement count 327 deps->count += 1; 328 329 // find first set bit (1:inactive) 330 skc_uint * active = deps->active; 331 skc_uint first = 0; 332 333 while (1) 334 { 335 skc_uint const idx = SKC_LZCNT_32(*active); 336 337 first += idx; 338 339 if (idx < 32) 340 { 341 // make inactive bit active: 1 -> 0 342 *active &= ~(0x80000000 >> idx); // 0:active 343 break; 344 } 345 346 // otherwise, inspect next word for inactive bit 347 active += 1; 348 } 349 350 struct skc_grid * const grid = deps->grids + first; 351 352 // save grid pointer 353 if (addr != NULL) 354 *addr = grid; 355 356 // initialize elem 357 *grid = (struct skc_grid){ 358 .state = SKC_GRID_STATE_READY, 359 .id = first, 360 .deps = deps, 361 .addr = addr, 362 .data = data, 363 .waiting = { .pfn = waiting_pfn, .name = waiting_name }, 364 .execute = { .pfn = execute_pfn, .name = execute_name }, 365 .dispose = { .pfn = dispose_pfn, .name = dispose_name }, 366 .before = { { 0 }, 0 }, 367 .after = { { 0 }, 0 } 368 }; 369 370 return grid; 371 } 372 373 // 374 // 375 // 376 377 static 378 skc_bool 379 skc_grid_words_set(skc_uint ids[SKC_GRID_SIZE_WORDS], skc_uint const id) 380 { 381 skc_uint * const ptr = ids + (id/32); 382 skc_uint const pre = *ptr; 383 skc_uint const post = pre | (0x80000000 >> (id & 0x1F)); // set 384 385 *ptr = post; 386 387 return pre != post; 388 } 389 390 static 391 skc_bool 392 skc_grid_words_clear(skc_uint ids[SKC_GRID_SIZE_WORDS], skc_uint const id) 393 { 394 skc_uint * const ptr = ids + (id/32); 395 skc_uint const pre = *ptr; 396 skc_uint const post = pre & ~(0x80000000 >> (id & 0x1F)); // clear 397 398 *ptr = post; 399 400 return pre != post; 401 } 402 403 // 404 // we may want to allow the host to detach a grid 405 // 406 407 static 408 void 409 skc_grid_detach(skc_grid_t const grid) 410 { 411 // for now make sure grid is complete 412 // assert(grid->state == SKC_GRID_STATE_COMPLETE); 413 414 // transition state 415 grid->state = SKC_GRID_STATE_DETACHED; 416 417 // 418 // FIXME -- save profiling info 419 // 420 421 // cleanup 422 if (skc_grid_words_set(grid->deps->active,grid->id)) // 1:inactive 423 grid->deps->count -= 1; 424 } 425 426 // 427 // 428 // 429 430 void 431 skc_grid_map(skc_grid_t const grid, skc_handle_t const handle) 432 { 433 grid->deps->handle_map[handle] = grid->id; 434 } 435 436 // 437 // 438 // 439 440 void 441 skc_grid_deps_force(skc_grid_deps_t const deps, 442 skc_handle_t const * const handles, 443 skc_uint const count) 444 { 445 // 446 // FIXME -- test to make sure handles aren't completely out of range integers 447 // 448 skc_grid_id_t * const handle_map = deps->handle_map; 449 450 for (skc_uint ii=0; ii<count; ii++) 451 { 452 skc_grid_id_t grid_id = handle_map[SKC_TYPED_HANDLE_TO_HANDLE(handles[ii])]; 453 454 if (grid_id < SKC_GRID_ID_INVALID) 455 { 456 skc_grid_t const grid = deps->grids + grid_id; 457 458 skc_grid_force(grid); 459 460 while (grid->state >= SKC_GRID_STATE_COMPLETE) 461 skc_scheduler_wait_one(deps->scheduler); 462 } 463 } 464 } 465 466 void 467 skc_grid_deps_unmap(skc_grid_deps_t const deps, 468 skc_handle_t const * const handles, 469 skc_uint const count) 470 { 471 skc_grid_id_t * const handle_map = deps->handle_map; 472 473 for (skc_uint ii=0; ii<count; ii++) 474 handle_map[handles[ii]] = SKC_GRID_ID_INVALID; 475 } 476 477 // 478 // NOTE: We want this routine to be very very fast. The array of bit 479 // flags is probably as fast as we can go for a modest number of 480 // grids. 481 // 482 // NOTE: The before grid should never be NULL. This means the grid's 483 // lifecycle should match the lifetime of the object it represents. 484 // This also means the grid "invalidation upon start" feature should 485 // be well understood before using it to clear the skc_grid_t. 486 // 487 488 void 489 skc_grid_happens_after_grid(skc_grid_t const after, 490 skc_grid_t const before) 491 { 492 // declarations can't be made on non-ready grids 493 assert(after->state == SKC_GRID_STATE_READY); 494 495 if (before->state >= SKC_GRID_STATE_COMPLETE) 496 return; 497 498 if (skc_grid_words_set(after->before.words,before->id)) 499 after->before.count += 1; 500 501 if (skc_grid_words_set(before->after.words,after->id)) 502 before->after.count += 1; 503 } 504 505 void 506 skc_grid_happens_after_handle(skc_grid_t const after, skc_handle_t const before) 507 { 508 assert(after->state == SKC_GRID_STATE_READY); 509 510 skc_uint const id_before = after->deps->handle_map[before]; 511 512 if (id_before >= SKC_GRID_ID_INVALID) 513 return; 514 515 if (skc_grid_words_set(after->before.words,id_before)) 516 after->before.count += 1; 517 518 skc_grid_t const grid_before = after->deps->grids + id_before; 519 520 if (skc_grid_words_set(grid_before->after.words,after->id)) 521 grid_before->after.count += 1; 522 } 523 524 // 525 // Remove dependency from grid 526 // 527 528 static 529 void 530 skc_grid_clear_dependency(skc_grid_t const after, skc_uint const before) 531 { 532 skc_bool const is_change = skc_grid_words_clear(after->before.words,before); 533 534 assert(is_change); // for now let's make sure this is a rising edge 535 536 after->before.count -= 1; 537 538 if ((after->before.count == 0) && ((after->state == SKC_GRID_STATE_WAITING) || 539 (after->state == SKC_GRID_STATE_FORCED))) 540 { 541 // schedule grid for execution 542 after->state = SKC_GRID_STATE_EXECUTING; 543 skc_grid_schedule(after,&after->execute); 544 } 545 } 546 547 // 548 // Start the ready grid and wait for dependencies to complete 549 // 550 551 void 552 skc_grid_start(skc_grid_t const grid) 553 { 554 // nothing to do if this grid isn't in a ready state 555 if (grid->state != SKC_GRID_STATE_READY) 556 return; 557 558 // record transition through waiting state 559 grid->state = SKC_GRID_STATE_WAITING; 560 561 // the waiting pfn may be null -- e.g. the path builder 562 // skc_grid_schedule(grid,&grid->waiting); 563 skc_grid_call(grid,&grid->waiting); 564 565 // clear the reference 566 skc_grid_invalidate(grid); 567 568 // execute if there are no dependencies 569 if (grid->before.count == 0) 570 { 571 // tell grid it can execute 572 grid->state = SKC_GRID_STATE_EXECUTING; 573 skc_grid_schedule(grid,&grid->execute); 574 } 575 } 576 577 // 578 // Start this grid and all its ready dependencies 579 // 580 581 void 582 skc_grid_force(skc_grid_t const grid) 583 { 584 // return if this grid was forced, executing or complete 585 if (grid->state >= SKC_GRID_STATE_FORCED) 586 return; 587 588 // if ready then move to waiting state 589 if (grid->state == SKC_GRID_STATE_READY) 590 { 591 // tell grid to wait for execution 592 grid->state = SKC_GRID_STATE_WAITING; 593 594 // the waiting pfn may be null -- e.g. the path builder 595 // skc_grid_schedule(grid,&grid->waiting); 596 skc_grid_call(grid,&grid->waiting); 597 598 // clear the reference 599 skc_grid_invalidate(grid); 600 } 601 602 skc_uint before_count = grid->before.count; 603 604 // if there are no grid dependencies then execute 605 if (before_count == 0) 606 { 607 // tell grid it can execute 608 grid->state = SKC_GRID_STATE_EXECUTING; 609 skc_grid_schedule(grid,&grid->execute); 610 } 611 else // otherwise, start or make waiting all dependencies 612 { 613 grid->state = SKC_GRID_STATE_FORCED; 614 615 struct skc_grid * before = grid->deps->grids; 616 skc_uint * before_words = grid->before.words; 617 skc_uint active = *before_words++; 618 619 while (true) 620 { 621 // find first active 622 skc_uint const idx = SKC_LZCNT_32(active); 623 624 // no bits set so inspect next word 625 if (idx == 32) 626 { 627 active = *before_words++; 628 before += 1; 629 continue; 630 } 631 else // clear active 632 { 633 active &= ~(0x80000000 >> idx); 634 before_count -= 1; 635 } 636 637 // otherwise, force this elem with dependent 638 skc_grid_force(before+idx); 639 640 // no more bits? 641 if (before_count == 0) 642 break; 643 } 644 } 645 } 646 647 // 648 // Notify grids dependent on this grid that this grid is complete 649 // 650 651 void 652 skc_grid_complete(skc_grid_t const grid) 653 { 654 // debug: grid was executing 655 assert(grid->state == SKC_GRID_STATE_EXECUTING); 656 657 // move grid to completion and dispose after notifying dependents 658 grid->state = SKC_GRID_STATE_COMPLETE; 659 660 skc_uint after_count = grid->after.count; 661 662 if (after_count > 0) 663 { 664 // find set bits 665 struct skc_grid * after = grid->deps->grids; 666 skc_uint * after_words = grid->after.words; 667 skc_uint active = *after_words++; 668 669 while (true) 670 { 671 // find first active 672 skc_uint const idx = SKC_LZCNT_32(active); 673 674 // no bits set so inspect next word 675 if (idx == 32) 676 { 677 active = *after_words++; 678 after += 32; 679 continue; 680 } 681 else // clear active 682 { 683 active &= ~(0x80000000 >> idx); 684 after_count -= 1; 685 } 686 687 // otherwise, clear this dependency 688 skc_grid_clear_dependency(after+idx,grid->id); 689 690 // no more bits? 691 if (after_count == 0) 692 break; 693 } 694 } 695 696 // dispose of resources 697 skc_grid_call(grid,&grid->dispose); 698 699 // we don't need to hang on to this grid id any longer 700 skc_grid_detach(grid); 701 } 702 703 /////////////////////////////////////////////////////////////////////////// 704 // 705 // ALTERNATIVE IMPLEMENTATION WOULD SUPPORT A VARIABLE NUMBER OF 706 // ACTIVE GRIDS PER STAGE PRESUMABLY RESULTING IN SLIGHTLY LESS MEMORY 707 // USAGE. 708 // 709 // THE #1 OBJECTIVE OF THE GRID IMPLEMENTATION IS TO ENSURE THAT THE 710 // "HAPPENS-BEFORE" DECLARATION REMAINS ***FAST*** SINCE IT WILL BE 711 // CALLED FREQUENTLY. THUS THE |GRIDS|^2 BIT ARRAY... 712 // 713 // WE DON'T NEED THIS RIGHT NOW... 714 // 715 716 #if 0 717 718 // 719 // For now, make them all the same size 720 // 721 722 #define SKC_GRID_STAGE_WORDS_PATH_BUILDER SKC_GRID_MASK_WORDS 723 #define SKC_GRID_STAGE_WORDS_RASTER_BUILDER SKC_GRID_MASK_WORDS 724 #define SKC_GRID_STAGE_WORDS_COMPOSITION SKC_GRID_MASK_WORDS 725 #define SKC_GRID_STAGE_WORDS_STYLING SKC_GRID_MASK_WORDS 726 #define SKC_GRID_STAGE_WORDS_SURFACE_COMPOSITION SKC_GRID_MASK_WORDS 727 #define SKC_GRID_STAGE_WORDS_SURFACE_STYLING SKC_GRID_MASK_WORDS 728 729 // 730 // 731 // 732 733 typedef enum skc_grid_stage_type { 734 735 SKC_GRID_STAGE_TYPE_PATH_BUILDER, 736 SKC_GRID_STAGE_TYPE_RASTER_BUILDER, 737 SKC_GRID_STAGE_TYPE_COMPOSITION, 738 SKC_GRID_STAGE_TYPE_STYLING, 739 SKC_GRID_STAGE_TYPE_SURFACE_COMPOSITION, 740 SKC_GRID_STAGE_TYPE_SURFACE_STYLING, 741 742 SKC_GRID_STAGE_TYPE_COUNT 743 744 } skc_grid_stage_type; 745 746 // 747 // 748 // 749 750 union skc_grid_id 751 { 752 skc_grid_id_t u32; 753 754 struct { 755 skc_ushort index; 756 skc_ushort stage; 757 }; 758 } 759 760 SKC_STATIC_ASSERT(sizeof(union skc_grid_id) == sizeof(skc_uint)); 761 762 // 763 // 764 // 765 766 #endif 767 768 // 769 // 770 // 771