Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1676:5e76d5e8167a
limit the amount of frames to be prefetched
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 23 Nov 2020 18:49:42 +0100 |
parents | 6fa05252b085 |
children | 51bab5188a13 |
comparison
equal
deleted
inserted
replaced
1675:6fa05252b085 | 1676:5e76d5e8167a |
---|---|
1225 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 1225 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
1226 } | 1226 } |
1227 | 1227 |
1228 assert(converted.get() != NULL); | 1228 assert(converted.get() != NULL); |
1229 GetViewport().RenderCurrentSceneFromCommand(*converted, sopInstanceUid_, frameNumber_, DisplayedFrameQuality_Low); | 1229 GetViewport().RenderCurrentSceneFromCommand(*converted, sopInstanceUid_, frameNumber_, DisplayedFrameQuality_Low); |
1230 GetViewport().cache_->Acquire(sopInstanceUid_, frameNumber_, converted.release(), QUALITY_JPEG); | 1230 GetViewport().framesCache_->Acquire(sopInstanceUid_, frameNumber_, converted.release(), QUALITY_JPEG); |
1231 | 1231 |
1232 if (isPrefetch_) | 1232 if (isPrefetch_) |
1233 { | 1233 { |
1234 GetViewport().ScheduleNextPrefetch(); | 1234 GetViewport().ScheduleNextPrefetch(); |
1235 } | 1235 } |
1318 Orthanc::ImageProcessing::ShiftScale2(*converted, b, a, false); | 1318 Orthanc::ImageProcessing::ShiftScale2(*converted, b, a, false); |
1319 } | 1319 } |
1320 | 1320 |
1321 assert(converted.get() != NULL); | 1321 assert(converted.get() != NULL); |
1322 viewport.RenderCurrentSceneFromCommand(*converted, sopInstanceUid, frameNumber, DisplayedFrameQuality_High); | 1322 viewport.RenderCurrentSceneFromCommand(*converted, sopInstanceUid, frameNumber, DisplayedFrameQuality_High); |
1323 viewport.cache_->Acquire(sopInstanceUid, frameNumber, converted.release(), QUALITY_FULL); | 1323 viewport.framesCache_->Acquire(sopInstanceUid, frameNumber, converted.release(), QUALITY_FULL); |
1324 } | 1324 } |
1325 }; | 1325 }; |
1326 | 1326 |
1327 | 1327 |
1328 class PrefetchItem | 1328 class PrefetchItem |
1354 std::unique_ptr<IObserver> observer_; | 1354 std::unique_ptr<IObserver> observer_; |
1355 OrthancStone::WebAssemblyLoadersContext& context_; | 1355 OrthancStone::WebAssemblyLoadersContext& context_; |
1356 boost::shared_ptr<OrthancStone::WebAssemblyViewport> viewport_; | 1356 boost::shared_ptr<OrthancStone::WebAssemblyViewport> viewport_; |
1357 boost::shared_ptr<OrthancStone::DicomResourcesLoader> loader_; | 1357 boost::shared_ptr<OrthancStone::DicomResourcesLoader> loader_; |
1358 OrthancStone::DicomSource source_; | 1358 OrthancStone::DicomSource source_; |
1359 boost::shared_ptr<FramesCache> cache_; | 1359 boost::shared_ptr<FramesCache> framesCache_; |
1360 std::unique_ptr<OrthancStone::SortedFrames> frames_; | 1360 std::unique_ptr<OrthancStone::SortedFrames> frames_; |
1361 std::unique_ptr<SeriesCursor> cursor_; | 1361 std::unique_ptr<SeriesCursor> cursor_; |
1362 float windowingCenter_; | 1362 float windowingCenter_; |
1363 float windowingWidth_; | 1363 float windowingWidth_; |
1364 float defaultWindowingCenter_; | 1364 float defaultWindowingCenter_; |
1388 | 1388 |
1389 const std::string sopInstanceUid = frames_->GetInstanceOfFrame(cursorIndex).GetSopInstanceUid(); | 1389 const std::string sopInstanceUid = frames_->GetInstanceOfFrame(cursorIndex).GetSopInstanceUid(); |
1390 unsigned int frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); | 1390 unsigned int frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); |
1391 | 1391 |
1392 { | 1392 { |
1393 FramesCache::Accessor accessor(*cache_, sopInstanceUid, frameNumber); | 1393 FramesCache::Accessor accessor(*framesCache_, sopInstanceUid, frameNumber); |
1394 if (!accessor.IsValid() || | 1394 if (!accessor.IsValid() || |
1395 (isFullQuality && accessor.GetQuality() == 0)) | 1395 (isFullQuality && accessor.GetQuality() == 0)) |
1396 { | 1396 { |
1397 if (isFullQuality) | 1397 if (isFullQuality) |
1398 { | 1398 { |
1451 layer.GetWindowing(windowingCenter_, windowingWidth_); | 1451 layer.GetWindowing(windowingCenter_, windowingWidth_); |
1452 } | 1452 } |
1453 } | 1453 } |
1454 | 1454 |
1455 | 1455 |
1456 void SetupPrefetchAfterRendering(DisplayedFrameQuality quality) | 1456 /** |
1457 { | 1457 * NB: "frame" is only used to estimate the memory size to store 1 |
1458 * frame, in order to avoid prefetching too much data. | |
1459 **/ | |
1460 void SetupPrefetchAfterRendering(const Orthanc::ImageAccessor& frame, | |
1461 DisplayedFrameQuality quality) | |
1462 { | |
1463 const size_t frameSize = frame.GetPitch() * frame.GetHeight(); | |
1458 const size_t cursorIndex = cursor_->GetCurrentIndex(); | 1464 const size_t cursorIndex = cursor_->GetCurrentIndex(); |
1459 | 1465 |
1460 // Prepare prefetching | 1466 // Prepare prefetching |
1461 prefetchQueue_.clear(); | 1467 prefetchQueue_.clear(); |
1462 | 1468 |
1463 if (1) // TODO - DISABLE PREFETCHING | 1469 size_t prefetchedSize = 0; |
1464 { | 1470 |
1465 for (size_t i = 0; i < cursor_->GetPrefetchSize() && i < 16; i++) | 1471 if (1) // DISABLE PREFETCHING |
1472 { | |
1473 for (size_t i = 0; i < cursor_->GetPrefetchSize() && i < 16 && | |
1474 prefetchedSize <= framesCache_->GetMaximumSize() / 2; i++) | |
1466 { | 1475 { |
1467 size_t a = cursor_->GetPrefetchIndex(i); | 1476 size_t a = cursor_->GetPrefetchIndex(i); |
1468 if (a != cursorIndex) | 1477 if (a != cursorIndex) |
1469 { | 1478 { |
1470 prefetchQueue_.push_back(PrefetchItem(a, i < 2)); | 1479 prefetchQueue_.push_back(PrefetchItem(a, i < 2)); |
1480 prefetchedSize += frameSize; | |
1471 } | 1481 } |
1472 } | 1482 } |
1473 } | 1483 } |
1474 | 1484 |
1475 ScheduleNextPrefetch(); | 1485 ScheduleNextPrefetch(); |
1591 { | 1601 { |
1592 const OrthancStone::CoordinateSystem3D plane = frames_->GetFrameGeometry(cursorIndex); | 1602 const OrthancStone::CoordinateSystem3D plane = frames_->GetFrameGeometry(cursorIndex); |
1593 | 1603 |
1594 if (quality == DisplayedFrameQuality_Low) | 1604 if (quality == DisplayedFrameQuality_Low) |
1595 { | 1605 { |
1596 FramesCache::Accessor accessor(*cache_, instance.GetSopInstanceUid(), frameNumber); | 1606 FramesCache::Accessor accessor(*framesCache_, instance.GetSopInstanceUid(), frameNumber); |
1597 if (accessor.IsValid() && | 1607 if (accessor.IsValid() && |
1598 accessor.GetQuality() == QUALITY_FULL) | 1608 accessor.GetQuality() == QUALITY_FULL) |
1599 { | 1609 { |
1600 // A high-res image was downloaded in between: Use this cached image instead of the low-res | 1610 // A high-res image was downloaded in between: Use this cached image instead of the low-res |
1601 RenderCurrentScene(accessor.GetImage(), instance, plane); | 1611 RenderCurrentScene(accessor.GetImage(), instance, plane); |
1602 SetupPrefetchAfterRendering(DisplayedFrameQuality_High); | 1612 SetupPrefetchAfterRendering(frame, DisplayedFrameQuality_High); |
1603 } | 1613 } |
1604 else | 1614 else |
1605 { | 1615 { |
1606 // This frame is only available in low-res: Download the full DICOM | 1616 // This frame is only available in low-res: Download the full DICOM |
1607 RenderCurrentScene(frame, instance, plane); | 1617 RenderCurrentScene(frame, instance, plane); |
1608 SetupPrefetchAfterRendering(quality); | 1618 SetupPrefetchAfterRendering(frame, quality); |
1609 | 1619 |
1610 /** | 1620 /** |
1611 * The command "SetupPrefetchAfterRendering()" must be | 1621 * The command "SetupPrefetchAfterRendering()" must be |
1612 * after "SetupPrefetchAfterRendering(quality)", as the | 1622 * after "SetupPrefetchAfterRendering(quality)", as the |
1613 * DICOM instance might already be cached by the oracle, | 1623 * DICOM instance might already be cached by the oracle, |
1619 } | 1629 } |
1620 } | 1630 } |
1621 else | 1631 else |
1622 { | 1632 { |
1623 assert(quality == DisplayedFrameQuality_High); | 1633 assert(quality == DisplayedFrameQuality_High); |
1624 SetupPrefetchAfterRendering(quality); | 1634 SetupPrefetchAfterRendering(frame, quality); |
1625 RenderCurrentScene(frame, instance, plane); | 1635 RenderCurrentScene(frame, instance, plane); |
1626 } | 1636 } |
1627 } | 1637 } |
1628 } | 1638 } |
1629 } | 1639 } |
1742 const std::string& canvas, | 1752 const std::string& canvas, |
1743 boost::shared_ptr<FramesCache> cache, | 1753 boost::shared_ptr<FramesCache> cache, |
1744 bool softwareRendering) : | 1754 bool softwareRendering) : |
1745 context_(context), | 1755 context_(context), |
1746 source_(source), | 1756 source_(source), |
1747 cache_(cache), | 1757 framesCache_(cache), |
1748 fitNextContent_(true), | 1758 fitNextContent_(true), |
1749 isCtrlDown_(false), | 1759 isCtrlDown_(false), |
1750 flipX_(false), | 1760 flipX_(false), |
1751 flipY_(false), | 1761 flipY_(false), |
1752 hasFocusOnInstance_(false), | 1762 hasFocusOnInstance_(false), |
1753 focusFrameNumber_(0) | 1763 focusFrameNumber_(0) |
1754 { | 1764 { |
1755 if (!cache_) | 1765 if (!framesCache_) |
1756 { | 1766 { |
1757 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 1767 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
1758 } | 1768 } |
1759 | 1769 |
1760 if (softwareRendering) | 1770 if (softwareRendering) |
1966 const size_t cursorIndex = cursor_->GetCurrentIndex(); | 1976 const size_t cursorIndex = cursor_->GetCurrentIndex(); |
1967 | 1977 |
1968 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex); | 1978 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex); |
1969 const size_t frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); | 1979 const size_t frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); |
1970 | 1980 |
1971 FramesCache::Accessor accessor(*cache_, instance.GetSopInstanceUid(), frameNumber); | 1981 FramesCache::Accessor accessor(*framesCache_, instance.GetSopInstanceUid(), frameNumber); |
1972 if (accessor.IsValid()) | 1982 if (accessor.IsValid()) |
1973 { | 1983 { |
1974 RenderCurrentScene(accessor.GetImage(), instance, frames_->GetFrameGeometry(cursorIndex)); | 1984 RenderCurrentScene(accessor.GetImage(), instance, frames_->GetFrameGeometry(cursorIndex)); |
1975 | 1985 |
1976 DisplayedFrameQuality quality; | 1986 DisplayedFrameQuality quality; |
1984 else | 1994 else |
1985 { | 1995 { |
1986 quality = DisplayedFrameQuality_High; | 1996 quality = DisplayedFrameQuality_High; |
1987 } | 1997 } |
1988 | 1998 |
1989 SetupPrefetchAfterRendering(quality); | 1999 SetupPrefetchAfterRendering(accessor.GetImage(), quality); |
1990 } | 2000 } |
1991 else | 2001 else |
1992 { | 2002 { |
1993 // This frame is not cached yet: Load it | 2003 // This frame is not cached yet: Load it |
1994 if (source_.HasDicomWebRendered()) | 2004 if (source_.HasDicomWebRendered()) |
2465 }; | 2475 }; |
2466 | 2476 |
2467 | 2477 |
2468 | 2478 |
2469 static OrthancStone::DicomSource source_; | 2479 static OrthancStone::DicomSource source_; |
2470 static boost::shared_ptr<FramesCache> cache_; | 2480 static boost::shared_ptr<FramesCache> framesCache_; |
2471 static boost::shared_ptr<OrthancStone::WebAssemblyLoadersContext> context_; | 2481 static boost::shared_ptr<OrthancStone::WebAssemblyLoadersContext> context_; |
2472 static std::string stringBuffer_; | 2482 static std::string stringBuffer_; |
2473 static bool softwareRendering_ = false; | 2483 static bool softwareRendering_ = false; |
2474 static WebViewerAction leftButtonAction_ = WebViewerAction_GrayscaleWindowing; | 2484 static WebViewerAction leftButtonAction_ = WebViewerAction_GrayscaleWindowing; |
2475 static WebViewerAction middleButtonAction_ = WebViewerAction_Pan; | 2485 static WebViewerAction middleButtonAction_ = WebViewerAction_Pan; |
2515 { | 2525 { |
2516 Viewports::iterator found = allViewports_.find(canvas); | 2526 Viewports::iterator found = allViewports_.find(canvas); |
2517 if (found == allViewports_.end()) | 2527 if (found == allViewports_.end()) |
2518 { | 2528 { |
2519 boost::shared_ptr<ViewerViewport> viewport( | 2529 boost::shared_ptr<ViewerViewport> viewport( |
2520 ViewerViewport::Create(*context_, source_, canvas, cache_, softwareRendering_)); | 2530 ViewerViewport::Create(*context_, source_, canvas, framesCache_, softwareRendering_)); |
2521 viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_); | 2531 viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_); |
2522 viewport->AcquireObserver(new WebAssemblyObserver); | 2532 viewport->AcquireObserver(new WebAssemblyObserver); |
2523 viewport->SetAnnotations(annotations_); | 2533 viewport->SetAnnotations(annotations_); |
2524 allViewports_[canvas] = viewport; | 2534 allViewports_[canvas] = viewport; |
2525 return viewport; | 2535 return viewport; |
2541 //Orthanc::Logging::EnableTraceLevel(true); | 2551 //Orthanc::Logging::EnableTraceLevel(true); |
2542 | 2552 |
2543 context_.reset(new OrthancStone::WebAssemblyLoadersContext(1, 4, 1)); | 2553 context_.reset(new OrthancStone::WebAssemblyLoadersContext(1, 4, 1)); |
2544 context_->SetDicomCacheSize(128 * 1024 * 1024); // 128MB | 2554 context_->SetDicomCacheSize(128 * 1024 * 1024); // 128MB |
2545 | 2555 |
2546 cache_.reset(new FramesCache); | 2556 framesCache_.reset(new FramesCache); |
2547 annotations_.reset(new OrthancStone::OsiriX::CollectionOfAnnotations); | 2557 annotations_.reset(new OrthancStone::OsiriX::CollectionOfAnnotations); |
2548 | 2558 |
2549 DISPATCH_JAVASCRIPT_EVENT("StoneInitialized"); | 2559 DISPATCH_JAVASCRIPT_EVENT("StoneInitialized"); |
2550 } | 2560 } |
2551 | 2561 |