| 430 | |
| 431 | template<typename V> |
| 432 | Expected<void> VolumeMesher::addPart( const V& part ) |
| 433 | { |
| 434 | MR_TIMER; |
| 435 | |
| 436 | const int partFirstZ = nextZ_; |
| 437 | if ( part.dims.x != indexer_.dims().x || part.dims.y != indexer_.dims().y ) |
| 438 | return unexpected( "XY dimensions of a part must be equal to XY dimensions of whole volume" ); |
| 439 | if ( part.dims.z <= 1 ) |
| 440 | return unexpected( "a part must have at least two Z slices" ); |
| 441 | if ( partFirstZ + part.dims.z > indexer_.dims().z ) |
| 442 | return unexpected( "a part exceeds whole volume in Z dimension" ); |
| 443 | const int layerCount = indexer_.dims().z; |
| 444 | |
| 445 | constexpr bool binary = std::is_same_v<V, SimpleBinaryVolume>; |
| 446 | if constexpr ( binary ) |
| 447 | { |
| 448 | int fillFirstZ = partFirstZ; |
| 449 | if ( fillFirstZ ) |
| 450 | ++fillFirstZ; // skip already filled layer |
| 451 | ParallelFor( fillFirstZ, fillFirstZ + part.dims.z, [&]( size_t z ) |
| 452 | { |
| 453 | const auto layerSize = indexer_.sizeXY(); |
| 454 | BitSet layerLowerIso( layerSize ); |
| 455 | const auto firstLayerId = VoxelId( ( z - partFirstZ ) * layerSize ); |
| 456 | for ( size_t i = 0; i < layerSize; ++i ) |
| 457 | layerLowerIso.set( i, !part.data.test( firstLayerId + i ) ); |
| 458 | if ( layerLowerIso.any() ) |
| 459 | lowerIso_[z] = std::move( layerLowerIso ); |
| 460 | } ); |
| 461 | } |
| 462 | |
| 463 | const auto callingThreadId = std::this_thread::get_id(); |
| 464 | std::atomic<bool> keepGoing{ true }; |
| 465 | |
| 466 | // avoid false sharing with other local variables |
| 467 | // by putting processedBits in its own cache line |
| 468 | constexpr int hardware_destructive_interference_size = 64; |
| 469 | struct alignas(hardware_destructive_interference_size) S |
| 470 | { |
| 471 | std::atomic<int> numProcessedLayers{ 0 }; |
| 472 | } cacheLineStorage; |
| 473 | static_assert( alignof(S) == hardware_destructive_interference_size ); |
| 474 | static_assert( sizeof(S) == hardware_destructive_interference_size ); |
| 475 | |
| 476 | const int firstBlock = partFirstZ / layersPerBlock_; |
| 477 | nextZ_ = partFirstZ + part.dims.z - 1; |
| 478 | const bool lastPart = nextZ_ + 1 == indexer_.dims().z; |
| 479 | const int lastLayer = lastPart ? nextZ_ : nextZ_ - 1; |
| 480 | assert( lastLayer < layerCount ); |
| 481 | const int lastBlock = lastLayer / layersPerBlock_; |
| 482 | |
| 483 | const auto cb = subprogress( params_.cb, 0.0f, 0.3f ); |
| 484 | auto currentSubprogress = subprogress( |
| 485 | cb, |
| 486 | (float)partFirstZ / (float)indexer_.dims().z, |
| 487 | (float)lastLayer / (float)indexer_.dims().z |
| 488 | ); |
| 489 |
no test coverage detected