From aa770ace91840b29799d977dddca3f6d9dfe827a Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Jan 2019 13:43:09 +0100 Subject: [PATCH] Avoid loading of unnecessary buckets (#3656) * clear priority queue on each bucket tick, synchronize prefetching to layer rendering manager * update changelog * remove maximumPickerTickCount and neededAtPickerTick --- CHANGELOG.md | 1 + .../model/bucket_data_handling/bucket.js | 5 --- .../layer_rendering_manager.js | 1 + .../model/bucket_data_handling/pullqueue.js | 36 +++++-------------- .../oxalis/model/sagas/prefetch_saga.js | 26 +++++++++++--- 5 files changed, 32 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29a6e7af3a5..25225e5bf90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.md). - Fixed a rendering bug which caused data to be clipped in certain scenarios for datasets with anisotropic resolutions. [#3609](https://github.com/scalableminds/webknossos/pull/3609) - Fixed a bug where saving tracings failed after they were open for >24h. [#3633](https://github.com/scalableminds/webknossos/pull/3633) +- Fixed a bug that resulted in slow data loading when moving quickly through a dataset. [#3656](https://github.com/scalableminds/webknossos/pull/3656) - Fixed a bug which caused the wrong magnification to be rendered when zooming out very far. [#3609](https://github.com/scalableminds/webknossos/pull/3641/files) ### Removed diff --git a/app/assets/javascripts/oxalis/model/bucket_data_handling/bucket.js b/app/assets/javascripts/oxalis/model/bucket_data_handling/bucket.js index 11f5da856b4..3e037b69c8f 100644 --- a/app/assets/javascripts/oxalis/model/bucket_data_handling/bucket.js +++ b/app/assets/javascripts/oxalis/model/bucket_data_handling/bucket.js @@ -47,7 +47,6 @@ export class DataBucket { BYTE_OFFSET: number; visualizedMesh: ?Object; visualizationColor: number; - neededAtPickerTick: ?number; state: BucketStateEnumType; dirty: boolean; @@ -348,10 +347,6 @@ export class DataBucket { } } - setNeededAtPickerTick(tick: number) { - this.neededAtPickerTick = tick; - } - // The following three methods can be used for debugging purposes. // The bucket will be rendered in the 3D scene as a wireframe geometry. visualize() { diff --git a/app/assets/javascripts/oxalis/model/bucket_data_handling/layer_rendering_manager.js b/app/assets/javascripts/oxalis/model/bucket_data_handling/layer_rendering_manager.js index 311295adb4a..9cac6e530b4 100644 --- a/app/assets/javascripts/oxalis/model/bucket_data_handling/layer_rendering_manager.js +++ b/app/assets/javascripts/oxalis/model/bucket_data_handling/layer_rendering_manager.js @@ -196,6 +196,7 @@ export default class LayerRenderingManager { this.lastIsInvisible = isInvisible; this.needsRefresh = false; this.currentBucketPickerTick++; + this.pullQueue.clear(); const bucketQueue = new PriorityQueue({ // small priorities take precedence diff --git a/app/assets/javascripts/oxalis/model/bucket_data_handling/pullqueue.js b/app/assets/javascripts/oxalis/model/bucket_data_handling/pullqueue.js index 4fcf7a2056e..67e4e8aa281 100644 --- a/app/assets/javascripts/oxalis/model/bucket_data_handling/pullqueue.js +++ b/app/assets/javascripts/oxalis/model/bucket_data_handling/pullqueue.js @@ -15,7 +15,6 @@ import { requestWithFallback } from "oxalis/model/bucket_data_handling/wkstore_a import ConnectionInfo from "oxalis/model/data_connection_info"; import Constants, { type Vector3, type Vector4 } from "oxalis/constants"; import type DataCube from "oxalis/model/bucket_data_handling/data_cube"; -import Model from "oxalis/model"; import Store, { type DataStoreInfo, type DataLayerType } from "oxalis/store"; export type PullQueueItem = { @@ -37,8 +36,6 @@ const createPriorityQueue = () => }); const BATCH_SIZE = 3; -// If ${maximumPickerTickCount} bucket picker ticks didn't select a bucket, that bucket is discarded from the pullqueue -const maximumPickerTickCount = 5; class PullQueue { cube: DataCube; @@ -70,9 +67,6 @@ class PullQueue { pull(): Array> { // Starting to download some buckets - const layerRenderingManager = Model.getLayerRenderingManagerByName(this.layerName); - const { currentBucketPickerTick } = layerRenderingManager; - const promises = []; while (this.batchCount < PullQueueConstants.BATCH_LIMIT && this.priorityQueue.length > 0) { const batch = []; @@ -81,15 +75,8 @@ class PullQueue { const bucket = this.cube.getOrCreateBucket(address); if (bucket.type === "data" && bucket.needsRequest()) { - const isOutdated = - bucket.neededAtPickerTick != null && - currentBucketPickerTick - bucket.neededAtPickerTick > maximumPickerTickCount; - if (!isOutdated) { - batch.push(address); - bucket.pull(); - } else { - bucket.unvisualize(); - } + batch.push(address); + bucket.pull(); } } @@ -192,27 +179,20 @@ class PullQueue { } } - add(item: PullQueueItem, currentBucketPickerTick?: number): void { - const bucket = this.cube.getOrCreateBucket(item.bucket); - if (bucket.type === "data") { - if (currentBucketPickerTick == null) { - const layerRenderingManager = Model.getLayerRenderingManagerByName(this.layerName); - currentBucketPickerTick = layerRenderingManager.currentBucketPickerTick; - } - bucket.setNeededAtPickerTick(currentBucketPickerTick); - } - + add(item: PullQueueItem): void { this.priorityQueue.queue(item); } addAll(items: Array): void { - const layerRenderingManager = Model.getLayerRenderingManagerByName(this.layerName); - const { currentBucketPickerTick } = layerRenderingManager; for (const item of items) { - this.add(item, currentBucketPickerTick); + this.add(item); } } + clear() { + this.priorityQueue.clear(); + } + maybeWhitenEmptyBucket(bucketData: Uint8Array) { if (!this.whitenEmptyBuckets) { return; diff --git a/app/assets/javascripts/oxalis/model/sagas/prefetch_saga.js b/app/assets/javascripts/oxalis/model/sagas/prefetch_saga.js index 658f05b7133..ab57761ad59 100644 --- a/app/assets/javascripts/oxalis/model/sagas/prefetch_saga.js +++ b/app/assets/javascripts/oxalis/model/sagas/prefetch_saga.js @@ -103,11 +103,19 @@ export function* prefetchForPlaneMode(layer: DataLayer, previousProperties: Obje const zoomStep = yield* select(state => getRequestLogZoomStep(state)); const activePlane = yield* select(state => state.viewModeData.plane.activeViewport); const tracingTypes = yield* select(getTracingTypes); - const { lastPosition, lastDirection, lastZoomStep } = previousProperties; + const { lastPosition, lastDirection, lastZoomStep, lastBucketPickerTick } = previousProperties; const direction = getTraceDirection(position, lastPosition, lastDirection); const resolutions = yield* select(state => getResolutions(state.dataset)); + const layerRenderingManager = yield* call( + [Model, Model.getLayerRenderingManagerByName], + layer.name, + ); + const { currentBucketPickerTick } = layerRenderingManager; - if (position !== lastPosition || zoomStep !== lastZoomStep) { + if ( + currentBucketPickerTick !== lastBucketPickerTick && + (position !== lastPosition || zoomStep !== lastZoomStep) + ) { const areas = yield* select(state => getAreas(state)); for (const strategy of prefetchStrategiesPlane) { if ( @@ -141,6 +149,7 @@ export function* prefetchForPlaneMode(layer: DataLayer, previousProperties: Obje previousProperties.lastPosition = position; previousProperties.lastZoomStep = zoomStep; previousProperties.lastDirection = direction; + previousProperties.lastBucketPickerTick = currentBucketPickerTick; } } @@ -153,10 +162,18 @@ export function* prefetchForArbitraryMode( const zoomStep = yield* select(state => getRequestLogZoomStep(state)); const tracingTypes = yield* select(getTracingTypes); const resolutions = yield* select(state => getResolutions(state.dataset)); - const { lastMatrix, lastZoomStep } = previousProperties; + const layerRenderingManager = yield* call( + [Model, Model.getLayerRenderingManagerByName], + layer.name, + ); + const { currentBucketPickerTick } = layerRenderingManager; + const { lastMatrix, lastZoomStep, lastBucketPickerTick } = previousProperties; const { connectionInfo, pullQueue, cube } = Model.dataLayers[layer.name]; - if (matrix !== lastMatrix || zoomStep !== lastZoomStep) { + if ( + currentBucketPickerTick !== lastBucketPickerTick && + (matrix !== lastMatrix || zoomStep !== lastZoomStep) + ) { for (const strategy of prefetchStrategiesArbitrary) { if ( strategy.forContentType(tracingTypes) && @@ -181,6 +198,7 @@ export function* prefetchForArbitraryMode( pullQueue.pull(); previousProperties.lastMatrix = matrix; previousProperties.lastZoomStep = zoomStep; + previousProperties.lastBucketPickerTick = currentBucketPickerTick; } export default {};