diff --git a/CHANGELOG.md b/CHANGELOG.md index 43454081e43..0a59a48d81b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.md). ### Fixed - Fixed a bug which caused data to not be displayed correctly if adjacent data does not exist.[#3270](https://github.com/scalableminds/webknossos/pull/3270) +- Fixed a bug which caused initial rendering to sometimes miss some buckets. [#3262](https://github.com/scalableminds/webknossos/pull/3262) ### Removed diff --git a/app/assets/javascripts/libs/UpdatableTexture.js b/app/assets/javascripts/libs/UpdatableTexture.js index 5261bdd5b57..2c8333dba6e 100644 --- a/app/assets/javascripts/libs/UpdatableTexture.js +++ b/app/assets/javascripts/libs/UpdatableTexture.js @@ -49,24 +49,24 @@ UpdatableTexture.prototype.constructor = UpdatableTexture; UpdatableTexture.prototype.isUpdatableTexture = true; -UpdatableTexture.prototype.setRenderer = function(renderer) { +UpdatableTexture.prototype.setRenderer = function setRenderer(renderer) { this.renderer = renderer; this.gl = this.renderer.getContext(); this.utils = THREE.WebGLUtils(this.gl, this.renderer.extensions); }; -UpdatableTexture.prototype.setSize = function(width, height) { +UpdatableTexture.prototype.setSize = function setSize(width, height) { if (width === this.width && height === this.height) return; - const textureProperties = this.renderer.properties.get(this); - if (!textureProperties.__webglTexture) return; + if (!this.isInitialized()) return; this.width = width; this.height = height; const activeTexture = this.gl.getParameter(this.gl.TEXTURE_BINDING_2D); + const textureProperties = this.renderer.properties.get(this); this.gl.bindTexture(this.gl.TEXTURE_2D, textureProperties.__webglTexture); - if (!textureProperties.__webglTexture) this.width = null; + if (!this.isInitialized()) this.width = null; this.gl.texImage2D( this.gl.TEXTURE_2D, 0, @@ -81,12 +81,19 @@ UpdatableTexture.prototype.setSize = function(width, height) { this.gl.bindTexture(this.gl.TEXTURE_2D, activeTexture); }; -UpdatableTexture.prototype.update = function(src, x, y, width, height) { +UpdatableTexture.prototype.isInitialized = function isInitialized() { + return this.renderer.properties.get(this).__webglTexture != null; +}; + +UpdatableTexture.prototype.update = function update(src, x, y, width, height) { this.setSize(width, width); - const textureProperties = this.renderer.properties.get(this); - if (!textureProperties.__webglTexture) return; + if (!this.isInitialized()) { + console.warn("Update called before texture was initialized. This update is discarded"); + return; + } const activeTexture = this.gl.getParameter(this.gl.TEXTURE_BINDING_2D); + const textureProperties = this.renderer.properties.get(this); this.gl.bindTexture(this.gl.TEXTURE_2D, textureProperties.__webglTexture); this.gl.texSubImage2D( this.gl.TEXTURE_2D, diff --git a/app/assets/javascripts/libs/utils.js b/app/assets/javascripts/libs/utils.js index 5e5c6061678..f480b023abd 100644 --- a/app/assets/javascripts/libs/utils.js +++ b/app/assets/javascripts/libs/utils.js @@ -458,6 +458,17 @@ export function sortArray8(arr: Array): void { swap(arr, 3, 4); } +export function waitForCondition(pred: () => boolean): Promise { + const tryToResolve = resolve => { + if (pred()) { + resolve(); + } else { + window.requestAnimationFrame(() => tryToResolve(resolve)); + } + }; + return new Promise(tryToResolve); +} + export function waitForSelector(selector: string): Promise<*> { const tryToResolve = resolve => { const el = document.querySelector(selector); diff --git a/app/assets/javascripts/oxalis/model/bucket_data_handling/texture_bucket_manager.js b/app/assets/javascripts/oxalis/model/bucket_data_handling/texture_bucket_manager.js index bad2bd7ae29..a947b096b97 100644 --- a/app/assets/javascripts/oxalis/model/bucket_data_handling/texture_bucket_manager.js +++ b/app/assets/javascripts/oxalis/model/bucket_data_handling/texture_bucket_manager.js @@ -8,6 +8,7 @@ import UpdatableTexture from "libs/UpdatableTexture"; import window from "libs/window"; import { createUpdatableTexture } from "oxalis/geometries/materials/abstract_plane_material_factory"; import { getRenderer } from "oxalis/controller/renderer"; +import { waitForCondition } from "libs/utils"; // A TextureBucketManager instance is responsible for making buckets available // to the GPU. @@ -74,6 +75,12 @@ export default class TextureBucketManager { this.freeIndexSet = new Set(_.range(this.maximumCapacity)); this.dataTextures = []; + } + + async startRAFLoops() { + await waitForCondition( + () => this.lookUpTexture.isInitialized() && this.dataTextures[0].isInitialized(), + ); this.keepLookUpBufferUpToDate(); this.processWriterQueue(); @@ -207,6 +214,8 @@ export default class TextureBucketManager { getRenderer(), ); this.lookUpTexture = lookUpTexture; + + this.startRAFLoops(); } getLookUpBuffer() { diff --git a/app/assets/javascripts/oxalis/model/data_layer.js b/app/assets/javascripts/oxalis/model/data_layer.js index 0dc6d750889..06bcf371594 100644 --- a/app/assets/javascripts/oxalis/model/data_layer.js +++ b/app/assets/javascripts/oxalis/model/data_layer.js @@ -13,6 +13,7 @@ import { getLayerBoundaries, getBitDepth, } from "oxalis/model/accessors/dataset_accessor"; +import ErrorHandling from "libs/error_handling"; // TODO: Non-reactive class DataLayer { @@ -37,6 +38,8 @@ class DataLayer { const { dataset } = Store.getState(); const bitDepth = getBitDepth(getLayerByName(dataset, this.name)); + ErrorHandling.assert(layerInfo.resolutions.length > 0, "Resolutions for layer cannot be empty"); + this.cube = new DataCube( getLayerBoundaries(dataset, this.name).upperBoundary, layerInfo.resolutions.length, diff --git a/app/assets/javascripts/test/model/texture_bucket_manager.spec.js b/app/assets/javascripts/test/model/texture_bucket_manager.spec.js index 22707f44b4d..62122b1ca0c 100644 --- a/app/assets/javascripts/test/model/texture_bucket_manager.spec.js +++ b/app/assets/javascripts/test/model/texture_bucket_manager.spec.js @@ -26,6 +26,10 @@ mock( this.width = width; this.height = height; } + + isInitialized() { + return true; + } }, );