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