From 4e948249a20cfeb907e5c9ce51b578488f60b47f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 6 May 2016 14:20:09 -0400 Subject: [PATCH 1/9] Fix developer error thrown on pick. WIP. --- Source/Scene/GlobeSurfaceTile.js | 23 ++++++++++++-- Source/Scene/GlobeSurfaceTileProvider.js | 40 +++++++++++++++++++----- Source/Scene/QuadtreePrimitive.js | 12 ++++++- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index 67df0beecf8e..5440bd50e607 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -241,7 +241,7 @@ define([ } }; - GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection) { + GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection, tileProvider) { var surfaceTile = tile.data; if (!defined(surfaceTile)) { surfaceTile = tile.data = new GlobeSurfaceTile(); @@ -253,7 +253,7 @@ define([ } if (tile.state === QuadtreeTileLoadState.LOADING) { - processTerrainStateMachine(tile, frameState, terrainProvider); + processTerrainStateMachine(tile, frameState, terrainProvider, tileProvider); } // The terrain is renderable as soon as we have a valid vertex array. @@ -336,7 +336,16 @@ define([ } } - function processTerrainStateMachine(tile, frameState, terrainProvider) { + function processTerrainStateMachine(tile, frameState, terrainProvider, tileProvider) { + + var drawCommands = tileProvider._drawCommands; + var length = tileProvider._usedDrawCommands; + for ( var k = 0; k < length; ++k) { + if (drawCommands[k].vertexArray.isDestroyed()) { + debugger; + } + } + var surfaceTile = tile.data; var loaded = surfaceTile.loadedTerrain; var upsampled = surfaceTile.upsampledTerrain; @@ -408,6 +417,14 @@ define([ surfaceTile.upsampledTerrain = undefined; } } + + var drawCommands = tileProvider._drawCommands; + var length = tileProvider._usedDrawCommands; + for ( var k = 0; k < length; ++k) { + if (drawCommands[k].vertexArray.isDestroyed()) { + debugger; + } + } } function getUpsampleTileDetails(tile) { diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 30b7b492b051..33580a5ad418 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -343,7 +343,9 @@ define([ * @param {FrameState} frameState The frame state. */ GlobeSurfaceTileProvider.prototype.endUpdate = function(frameState) { - if (!defined(this._renderState)) { + var passes = frameState.passes; + + if (passes.render && !defined(this._renderState)) { this._renderState = RenderState.fromCache({ // Write color and depth cull : { enabled : true @@ -366,6 +368,20 @@ define([ }); } + if (passes.pick && !defined(this._pickRenderState)) { + this._pickRenderState = RenderState.fromCache({ + colorMask : { + red : false, + green : false, + blue : false, + alpha : false + }, + depthTest : { + enabled : true + } + }); + } + // Add the tile render commands to the command list, sorted by texture count. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount; for (var textureCountIndex = 0, textureCountLength = tilesToRenderByTextureCount.length; textureCountIndex < textureCountLength; ++textureCountIndex) { @@ -438,7 +454,7 @@ define([ * @exception {DeveloperError} loadTile must not be called before the tile provider is ready. */ GlobeSurfaceTileProvider.prototype.loadTile = function(frameState, tile) { - GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers); + GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers, this); }; var boundingSphereScratch = new BoundingSphere(); @@ -963,7 +979,10 @@ define([ var firstPassRenderState = tileProvider._renderState; var otherPassesRenderState = tileProvider._blendRenderState; - var renderState = firstPassRenderState; + var pickRenderState = tileProvider._pickRenderState; + + var passes = frameState.passes; + var renderState = passes.render ? firstPassRenderState : pickRenderState; var initialColor = tileProvider._firstPassInitialColor; @@ -1035,7 +1054,7 @@ define([ var applyGamma = false; var applyAlpha = false; - while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) { + while (!passes.pick && numberOfDayTextures < maxTextures && imageryIndex < imageryLen) { var tileImagery = tileImageryCollection[imageryIndex]; var imagery = tileImagery.readyImagery; ++imageryIndex; @@ -1093,7 +1112,14 @@ define([ uniformMap.minMaxHeight.y = encoding.maximumHeight; Matrix4.clone(encoding.matrix, uniformMap.scaleAndBias); - command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); + var shaderProgram; + if (passes.render) { + shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); + } else { + shaderProgram = tileProvider._surfaceShaderSet.getPickShaderProgram(frameState, surfaceTile, useWebMercatorProjection); + } + + command.shaderProgram = shaderProgram; command.renderState = renderState; command.primitiveType = PrimitiveType.TRIANGLES; command.vertexArray = surfaceTile.vertexArray; @@ -1127,7 +1153,7 @@ define([ renderState = otherPassesRenderState; initialColor = otherPassesInitialColor; - } while (imageryIndex < imageryLen); + } while (imageryIndex < imageryLen && !passes.pick); } function addPickCommandsForTile(tileProvider, drawCommand, frameState) { @@ -1154,7 +1180,7 @@ define([ pickCommand.vertexArray = drawCommand.vertexArray; pickCommand.uniformMap = drawCommand.uniformMap; pickCommand.boundingVolume = drawCommand.boundingVolume; - pickCommand.orientedBoundingBox = pickCommand.orientedBoundingBox; + pickCommand.orientedBoundingBox = drawCommand.orientedBoundingBox; pickCommand.pass = drawCommand.pass; frameState.commandList.push(pickCommand); diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 332a787de347..f60d1abbb74a 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -285,6 +285,7 @@ define([ debug.tilesWaitingForChildren = 0; this._tileLoadQueue.length = 0; + this._tileReplacementQueue.trimTiles(this.tileCacheSize); this._tileReplacementQueue.markStartOfRenderFrame(); }; @@ -292,6 +293,7 @@ define([ * @private */ QuadtreePrimitive.prototype.update = function(frameState) { + /* var passes = frameState.passes; if (passes.render) { @@ -306,6 +308,14 @@ define([ if (passes.pick && this._tilesToRender.length > 0) { this._tileProvider.updateForPick(frameState); } + */ + + this._tileProvider.beginUpdate(frameState); + + selectTilesForRendering(this, frameState); + createRenderCommandsForSelectedTiles(this, frameState); + + this._tileProvider.endUpdate(frameState); }; /** @@ -582,7 +592,7 @@ define([ // Remove any tiles that were not used this frame beyond the number // we're allowed to keep. - primitive._tileReplacementQueue.trimTiles(primitive.tileCacheSize); + //primitive._tileReplacementQueue.trimTiles(primitive.tileCacheSize); var startTime = getTimestamp(); var timeSlice = primitive._loadQueueTimeSlice; From 14ac8eb468e506a2708cef088032abd19ad04512 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 6 May 2016 14:31:05 -0400 Subject: [PATCH 2/9] Remove debug code. Fix still WIP. --- Source/Scene/GlobeSurfaceTile.js | 23 +++-------------------- Source/Scene/GlobeSurfaceTileProvider.js | 2 +- Source/Scene/QuadtreePrimitive.js | 3 +-- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index 5440bd50e607..67df0beecf8e 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -241,7 +241,7 @@ define([ } }; - GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection, tileProvider) { + GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection) { var surfaceTile = tile.data; if (!defined(surfaceTile)) { surfaceTile = tile.data = new GlobeSurfaceTile(); @@ -253,7 +253,7 @@ define([ } if (tile.state === QuadtreeTileLoadState.LOADING) { - processTerrainStateMachine(tile, frameState, terrainProvider, tileProvider); + processTerrainStateMachine(tile, frameState, terrainProvider); } // The terrain is renderable as soon as we have a valid vertex array. @@ -336,16 +336,7 @@ define([ } } - function processTerrainStateMachine(tile, frameState, terrainProvider, tileProvider) { - - var drawCommands = tileProvider._drawCommands; - var length = tileProvider._usedDrawCommands; - for ( var k = 0; k < length; ++k) { - if (drawCommands[k].vertexArray.isDestroyed()) { - debugger; - } - } - + function processTerrainStateMachine(tile, frameState, terrainProvider) { var surfaceTile = tile.data; var loaded = surfaceTile.loadedTerrain; var upsampled = surfaceTile.upsampledTerrain; @@ -417,14 +408,6 @@ define([ surfaceTile.upsampledTerrain = undefined; } } - - var drawCommands = tileProvider._drawCommands; - var length = tileProvider._usedDrawCommands; - for ( var k = 0; k < length; ++k) { - if (drawCommands[k].vertexArray.isDestroyed()) { - debugger; - } - } } function getUpsampleTileDetails(tile) { diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 33580a5ad418..1ae9cf8b272b 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -454,7 +454,7 @@ define([ * @exception {DeveloperError} loadTile must not be called before the tile provider is ready. */ GlobeSurfaceTileProvider.prototype.loadTile = function(frameState, tile) { - GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers, this); + GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers); }; var boundingSphereScratch = new BoundingSphere(); diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index f60d1abbb74a..661f95a473ab 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -285,7 +285,6 @@ define([ debug.tilesWaitingForChildren = 0; this._tileLoadQueue.length = 0; - this._tileReplacementQueue.trimTiles(this.tileCacheSize); this._tileReplacementQueue.markStartOfRenderFrame(); }; @@ -592,7 +591,7 @@ define([ // Remove any tiles that were not used this frame beyond the number // we're allowed to keep. - //primitive._tileReplacementQueue.trimTiles(primitive.tileCacheSize); + primitive._tileReplacementQueue.trimTiles(primitive.tileCacheSize); var startTime = getTimestamp(); var timeSlice = primitive._loadQueueTimeSlice; From c3dd81a4475b565c517cad5b866d9b375154fae0 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 6 May 2016 15:12:43 -0400 Subject: [PATCH 3/9] Separate render commands from picki commands. Terrain picking WIP. --- Source/Scene/GlobeSurfaceTileProvider.js | 23 ++++++++++++----- Source/Scene/QuadtreePrimitive.js | 33 +++++++----------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 1ae9cf8b272b..2030d18a1e46 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -334,6 +334,7 @@ define([ } this._usedDrawCommands = 0; + this._usedPickCommands = 0; }; /** @@ -995,10 +996,14 @@ define([ do { var numberOfDayTextures = 0; + var storedUniformMaps = tileProvider._uniformMaps; + var storedCommands = passes.render ? tileProvider._drawCommands : tileProvider._pickCommands; + var usedCommands = passes.render ? tileProvider._usedDrawCommands : tileProvider._usedPickCommands; + var command; var uniformMap; - if (tileProvider._drawCommands.length <= tileProvider._usedDrawCommands) { + if (storedCommands.length <= usedCommands) { command = new DrawCommand(); command.owner = tile; command.cull = false; @@ -1007,16 +1012,20 @@ define([ uniformMap = createTileUniformMap(); - tileProvider._drawCommands.push(command); - tileProvider._uniformMaps.push(uniformMap); + storedCommands.push(command); + storedUniformMaps.push(uniformMap); } else { - command = tileProvider._drawCommands[tileProvider._usedDrawCommands]; - uniformMap = tileProvider._uniformMaps[tileProvider._usedDrawCommands]; + command = storedCommands[usedCommands]; + uniformMap = storedUniformMaps[usedCommands]; } - command.owner = tile; + if (passes.render) { + ++tileProvider._usedDrawCommands; + } else { + ++tileProvider._usedPickCommands; + } - ++tileProvider._usedDrawCommands; + command.owner = tile; if (tile === tileProvider._debug.boundingSphereTile) { // If a debug primitive already exists for this tile, it will not be diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 661f95a473ab..a78cb6a94d0a 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -95,6 +95,7 @@ define([ var ellipsoid = tilingScheme.ellipsoid; this._tilesToRender = []; + this._tilesToRenderForPick = []; this._tileTraversalQueue = new Queue(); this._tileLoadQueue = []; this._tileReplacementQueue = new TileReplacementQueue(); @@ -292,23 +293,6 @@ define([ * @private */ QuadtreePrimitive.prototype.update = function(frameState) { - /* - var passes = frameState.passes; - - if (passes.render) { - this._tileProvider.beginUpdate(frameState); - - selectTilesForRendering(this, frameState); - createRenderCommandsForSelectedTiles(this, frameState); - - this._tileProvider.endUpdate(frameState); - } - - if (passes.pick && this._tilesToRender.length > 0) { - this._tileProvider.updateForPick(frameState); - } - */ - this._tileProvider.beginUpdate(frameState); selectTilesForRendering(this, frameState); @@ -402,8 +386,10 @@ define([ var i; var len; + var passes = frameState.passes; + // Clear the render list. - var tilesToRender = primitive._tilesToRender; + var tilesToRender = passes.render ? primitive._tilesToRender : primitive._tilesToRenderForPick; tilesToRender.length = 0; var traversalQueue = primitive._tileTraversalQueue; @@ -479,7 +465,7 @@ define([ if (screenSpaceError(primitive, frameState, tile) < primitive.maximumScreenSpaceError) { // This tile meets SSE requirements, so render it. - addTileToRenderList(primitive, tile); + addTileToRenderList(primitive, frameState, tile); } else if (queueChildrenLoadAndDetermineIfChildrenAreAllRenderable(primitive, tile)) { // SSE is not good enough and children are loaded, so refine. var children = tile.children; @@ -493,7 +479,7 @@ define([ } } else { // SSE is not good enough but not all children are loaded, so render this tile anyway. - addTileToRenderList(primitive, tile); + addTileToRenderList(primitive, frameState, tile); } } @@ -546,8 +532,9 @@ define([ return maxGeometricError / pixelSize; } - function addTileToRenderList(primitive, tile) { - primitive._tilesToRender.push(tile); + function addTileToRenderList(primitive, frameState, tile) { + var tilesToRender = frameState.passes.render ? primitive._tilesToRender : primitive._tilesToRenderForPick; + tilesToRender.push(tile); ++primitive._debug.tilesRendered; } @@ -704,7 +691,7 @@ define([ function createRenderCommandsForSelectedTiles(primitive, frameState) { var tileProvider = primitive._tileProvider; - var tilesToRender = primitive._tilesToRender; + var tilesToRender = frameState.passes.render ? primitive._tilesToRender : primitive._tilesToRenderForPick; var tilesToUpdateHeights = primitive._tileToUpdateHeights; tilesToRender.sort(tileDistanceSortFunction); From 95cafcf0f446d86377a402ab7ccd81b513f047c1 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 6 May 2016 16:11:35 -0400 Subject: [PATCH 4/9] Remove other solution to bug as it caused other issues. Use a reference count to keep track of terrain vertex arrays. --- Source/Scene/GlobeSurfaceTile.js | 11 +- Source/Scene/GlobeSurfaceTileProvider.js | 266 +++++++++++------------ Source/Scene/QuadtreePrimitive.js | 112 +++++----- Source/Scene/TileTerrain.js | 1 + 4 files changed, 195 insertions(+), 195 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index 67df0beecf8e..683408f36a56 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -217,14 +217,21 @@ define([ if (defined(this.vertexArray)) { indexBuffer = this.vertexArray.indexBuffer; - this.vertexArray = this.vertexArray.destroy(); + //this.vertexArray = this.vertexArray.destroy(); - if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { + --this.vertexArray.referenceCount; + if (this.vertexArray.referenceCount === 0) { + this.vertexArray.destroy(); + } + + if (this.vertexArray.isDestroyed() && !indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { --indexBuffer.referenceCount; if (indexBuffer.referenceCount === 0) { indexBuffer.destroy(); } } + + this.vertexArray = undefined; } if (defined(this.wireframeVertexArray)) { diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 2030d18a1e46..4a365f1ee646 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -1,94 +1,94 @@ /*global define*/ define([ - '../Core/BoundingSphere', - '../Core/BoxOutlineGeometry', - '../Core/Cartesian2', - '../Core/Cartesian3', - '../Core/Cartesian4', - '../Core/Color', - '../Core/ColorGeometryInstanceAttribute', - '../Core/defaultValue', - '../Core/defined', - '../Core/defineProperties', - '../Core/destroyObject', - '../Core/DeveloperError', - '../Core/Event', - '../Core/FeatureDetection', - '../Core/GeometryInstance', - '../Core/GeometryPipeline', - '../Core/IndexDatatype', - '../Core/Intersect', - '../Core/Math', - '../Core/Matrix4', - '../Core/OrientedBoundingBox', - '../Core/PrimitiveType', - '../Core/Rectangle', - '../Core/SphereOutlineGeometry', - '../Core/TerrainQuantization', - '../Core/Visibility', - '../Core/WebMercatorProjection', - '../Renderer/Buffer', - '../Renderer/BufferUsage', - '../Renderer/ContextLimits', - '../Renderer/DrawCommand', - '../Renderer/RenderState', - '../Renderer/VertexArray', - '../Scene/BlendingState', - '../Scene/DepthFunction', - '../Scene/Pass', - '../Scene/PerInstanceColorAppearance', - '../Scene/Primitive', - '../ThirdParty/when', - './GlobeSurfaceTile', - './ImageryLayer', - './ImageryState', - './QuadtreeTileLoadState', - './SceneMode' - ], function( - BoundingSphere, - BoxOutlineGeometry, - Cartesian2, - Cartesian3, - Cartesian4, - Color, - ColorGeometryInstanceAttribute, - defaultValue, - defined, - defineProperties, - destroyObject, - DeveloperError, - Event, - FeatureDetection, - GeometryInstance, - GeometryPipeline, - IndexDatatype, - Intersect, - CesiumMath, - Matrix4, - OrientedBoundingBox, - PrimitiveType, - Rectangle, - SphereOutlineGeometry, - TerrainQuantization, - Visibility, - WebMercatorProjection, - Buffer, - BufferUsage, - ContextLimits, - DrawCommand, - RenderState, - VertexArray, - BlendingState, - DepthFunction, - Pass, - PerInstanceColorAppearance, - Primitive, - when, - GlobeSurfaceTile, - ImageryLayer, - ImageryState, - QuadtreeTileLoadState, - SceneMode) { + '../Core/BoundingSphere', + '../Core/BoxOutlineGeometry', + '../Core/Cartesian2', + '../Core/Cartesian3', + '../Core/Cartesian4', + '../Core/Color', + '../Core/ColorGeometryInstanceAttribute', + '../Core/defaultValue', + '../Core/defined', + '../Core/defineProperties', + '../Core/destroyObject', + '../Core/DeveloperError', + '../Core/Event', + '../Core/FeatureDetection', + '../Core/GeometryInstance', + '../Core/GeometryPipeline', + '../Core/IndexDatatype', + '../Core/Intersect', + '../Core/Math', + '../Core/Matrix4', + '../Core/OrientedBoundingBox', + '../Core/PrimitiveType', + '../Core/Rectangle', + '../Core/SphereOutlineGeometry', + '../Core/TerrainQuantization', + '../Core/Visibility', + '../Core/WebMercatorProjection', + '../Renderer/Buffer', + '../Renderer/BufferUsage', + '../Renderer/ContextLimits', + '../Renderer/DrawCommand', + '../Renderer/RenderState', + '../Renderer/VertexArray', + '../Scene/BlendingState', + '../Scene/DepthFunction', + '../Scene/Pass', + '../Scene/PerInstanceColorAppearance', + '../Scene/Primitive', + '../ThirdParty/when', + './GlobeSurfaceTile', + './ImageryLayer', + './ImageryState', + './QuadtreeTileLoadState', + './SceneMode' +], function( + BoundingSphere, + BoxOutlineGeometry, + Cartesian2, + Cartesian3, + Cartesian4, + Color, + ColorGeometryInstanceAttribute, + defaultValue, + defined, + defineProperties, + destroyObject, + DeveloperError, + Event, + FeatureDetection, + GeometryInstance, + GeometryPipeline, + IndexDatatype, + Intersect, + CesiumMath, + Matrix4, + OrientedBoundingBox, + PrimitiveType, + Rectangle, + SphereOutlineGeometry, + TerrainQuantization, + Visibility, + WebMercatorProjection, + Buffer, + BufferUsage, + ContextLimits, + DrawCommand, + RenderState, + VertexArray, + BlendingState, + DepthFunction, + Pass, + PerInstanceColorAppearance, + Primitive, + when, + GlobeSurfaceTile, + ImageryLayer, + ImageryState, + QuadtreeTileLoadState, + SceneMode) { 'use strict'; /** @@ -334,7 +334,6 @@ define([ } this._usedDrawCommands = 0; - this._usedPickCommands = 0; }; /** @@ -344,9 +343,7 @@ define([ * @param {FrameState} frameState The frame state. */ GlobeSurfaceTileProvider.prototype.endUpdate = function(frameState) { - var passes = frameState.passes; - - if (passes.render && !defined(this._renderState)) { + if (!defined(this._renderState)) { this._renderState = RenderState.fromCache({ // Write color and depth cull : { enabled : true @@ -369,20 +366,6 @@ define([ }); } - if (passes.pick && !defined(this._pickRenderState)) { - this._pickRenderState = RenderState.fromCache({ - colorMask : { - red : false, - green : false, - blue : false, - alpha : false - }, - depthTest : { - enabled : true - } - }); - } - // Add the tile render commands to the command list, sorted by texture count. var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount; for (var textureCountIndex = 0, textureCountLength = tilesToRenderByTextureCount.length; textureCountIndex < textureCountLength; ++textureCountIndex) { @@ -886,6 +869,27 @@ define([ }; })(); + function swapCommandVertexArray(command, vertexArray) { + if (defined(command.vertexArray)) { + var indexBuffer = command.vertexArray.indexBuffer; + + --command.vertexArray.referenceCount; + if (command.vertexArray.referenceCount === 0) { + command.vertexArray.destroy(); + } + + if (command.vertexArray.isDestroyed() && !indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { + --indexBuffer.referenceCount; + if (indexBuffer.referenceCount === 0) { + indexBuffer.destroy(); + } + } + } + + command.vertexArray = vertexArray; + ++command.vertexArray.referenceCount; + } + var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0); function addDrawCommandsForTile(tileProvider, tile, frameState) { @@ -980,10 +984,7 @@ define([ var firstPassRenderState = tileProvider._renderState; var otherPassesRenderState = tileProvider._blendRenderState; - var pickRenderState = tileProvider._pickRenderState; - - var passes = frameState.passes; - var renderState = passes.render ? firstPassRenderState : pickRenderState; + var renderState = firstPassRenderState; var initialColor = tileProvider._firstPassInitialColor; @@ -996,14 +997,10 @@ define([ do { var numberOfDayTextures = 0; - var storedUniformMaps = tileProvider._uniformMaps; - var storedCommands = passes.render ? tileProvider._drawCommands : tileProvider._pickCommands; - var usedCommands = passes.render ? tileProvider._usedDrawCommands : tileProvider._usedPickCommands; - var command; var uniformMap; - if (storedCommands.length <= usedCommands) { + if (tileProvider._drawCommands.length <= tileProvider._usedDrawCommands) { command = new DrawCommand(); command.owner = tile; command.cull = false; @@ -1012,21 +1009,17 @@ define([ uniformMap = createTileUniformMap(); - storedCommands.push(command); - storedUniformMaps.push(uniformMap); + tileProvider._drawCommands.push(command); + tileProvider._uniformMaps.push(uniformMap); } else { - command = storedCommands[usedCommands]; - uniformMap = storedUniformMaps[usedCommands]; - } - - if (passes.render) { - ++tileProvider._usedDrawCommands; - } else { - ++tileProvider._usedPickCommands; + command = tileProvider._drawCommands[tileProvider._usedDrawCommands]; + uniformMap = tileProvider._uniformMaps[tileProvider._usedDrawCommands]; } command.owner = tile; + ++tileProvider._usedDrawCommands; + if (tile === tileProvider._debug.boundingSphereTile) { // If a debug primitive already exists for this tile, it will not be // re-created, to avoid allocation every frame. If it were possible @@ -1063,7 +1056,7 @@ define([ var applyGamma = false; var applyAlpha = false; - while (!passes.pick && numberOfDayTextures < maxTextures && imageryIndex < imageryLen) { + while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) { var tileImagery = tileImageryCollection[imageryIndex]; var imagery = tileImagery.readyImagery; ++imageryIndex; @@ -1121,20 +1114,14 @@ define([ uniformMap.minMaxHeight.y = encoding.maximumHeight; Matrix4.clone(encoding.matrix, uniformMap.scaleAndBias); - var shaderProgram; - if (passes.render) { - shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); - } else { - shaderProgram = tileProvider._surfaceShaderSet.getPickShaderProgram(frameState, surfaceTile, useWebMercatorProjection); - } - - command.shaderProgram = shaderProgram; + command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); command.renderState = renderState; command.primitiveType = PrimitiveType.TRIANGLES; - command.vertexArray = surfaceTile.vertexArray; command.uniformMap = uniformMap; command.pass = Pass.GLOBE; + swapCommandVertexArray(command, surfaceTile.vertexArray); + if (tileProvider._debug.wireframe) { createWireframeVertexArrayIfNecessary(context, tileProvider, tile); if (defined(surfaceTile.wireframeVertexArray)) { @@ -1162,7 +1149,7 @@ define([ renderState = otherPassesRenderState; initialColor = otherPassesInitialColor; - } while (imageryIndex < imageryLen && !passes.pick); + } while (imageryIndex < imageryLen); } function addPickCommandsForTile(tileProvider, drawCommand, frameState) { @@ -1186,14 +1173,15 @@ define([ pickCommand.owner = drawCommand.owner; pickCommand.primitiveType = drawCommand.primitiveType; - pickCommand.vertexArray = drawCommand.vertexArray; pickCommand.uniformMap = drawCommand.uniformMap; pickCommand.boundingVolume = drawCommand.boundingVolume; pickCommand.orientedBoundingBox = drawCommand.orientedBoundingBox; pickCommand.pass = drawCommand.pass; + swapCommandVertexArray(pickCommand, drawCommand.vertexArray); + frameState.commandList.push(pickCommand); } return GlobeSurfaceTileProvider; -}); +}); \ No newline at end of file diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index a78cb6a94d0a..b3cf268e083f 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -1,42 +1,42 @@ /*global define*/ define([ - '../Core/Cartesian3', - '../Core/Cartographic', - '../Core/defaultValue', - '../Core/defined', - '../Core/defineProperties', - '../Core/DeveloperError', - '../Core/Event', - '../Core/getTimestamp', - '../Core/Math', - '../Core/Queue', - '../Core/Ray', - '../Core/Rectangle', - '../Core/Visibility', - './QuadtreeOccluders', - './QuadtreeTile', - './QuadtreeTileLoadState', - './SceneMode', - './TileReplacementQueue' - ], function( - Cartesian3, - Cartographic, - defaultValue, - defined, - defineProperties, - DeveloperError, - Event, - getTimestamp, - CesiumMath, - Queue, - Ray, - Rectangle, - Visibility, - QuadtreeOccluders, - QuadtreeTile, - QuadtreeTileLoadState, - SceneMode, - TileReplacementQueue) { + '../Core/Cartesian3', + '../Core/Cartographic', + '../Core/defaultValue', + '../Core/defined', + '../Core/defineProperties', + '../Core/DeveloperError', + '../Core/Event', + '../Core/getTimestamp', + '../Core/Math', + '../Core/Queue', + '../Core/Ray', + '../Core/Rectangle', + '../Core/Visibility', + './QuadtreeOccluders', + './QuadtreeTile', + './QuadtreeTileLoadState', + './SceneMode', + './TileReplacementQueue' +], function( + Cartesian3, + Cartographic, + defaultValue, + defined, + defineProperties, + DeveloperError, + Event, + getTimestamp, + CesiumMath, + Queue, + Ray, + Rectangle, + Visibility, + QuadtreeOccluders, + QuadtreeTile, + QuadtreeTileLoadState, + SceneMode, + TileReplacementQueue) { 'use strict'; /** @@ -95,7 +95,6 @@ define([ var ellipsoid = tilingScheme.ellipsoid; this._tilesToRender = []; - this._tilesToRenderForPick = []; this._tileTraversalQueue = new Queue(); this._tileLoadQueue = []; this._tileReplacementQueue = new TileReplacementQueue(); @@ -293,12 +292,20 @@ define([ * @private */ QuadtreePrimitive.prototype.update = function(frameState) { - this._tileProvider.beginUpdate(frameState); - - selectTilesForRendering(this, frameState); - createRenderCommandsForSelectedTiles(this, frameState); - - this._tileProvider.endUpdate(frameState); + var passes = frameState.passes; + + if (passes.render) { + this._tileProvider.beginUpdate(frameState); + + selectTilesForRendering(this, frameState); + createRenderCommandsForSelectedTiles(this, frameState); + + this._tileProvider.endUpdate(frameState); + } + + if (passes.pick && this._tilesToRender.length > 0) { + this._tileProvider.updateForPick(frameState); + } }; /** @@ -386,10 +393,8 @@ define([ var i; var len; - var passes = frameState.passes; - // Clear the render list. - var tilesToRender = passes.render ? primitive._tilesToRender : primitive._tilesToRenderForPick; + var tilesToRender = primitive._tilesToRender; tilesToRender.length = 0; var traversalQueue = primitive._tileTraversalQueue; @@ -465,7 +470,7 @@ define([ if (screenSpaceError(primitive, frameState, tile) < primitive.maximumScreenSpaceError) { // This tile meets SSE requirements, so render it. - addTileToRenderList(primitive, frameState, tile); + addTileToRenderList(primitive, tile); } else if (queueChildrenLoadAndDetermineIfChildrenAreAllRenderable(primitive, tile)) { // SSE is not good enough and children are loaded, so refine. var children = tile.children; @@ -479,7 +484,7 @@ define([ } } else { // SSE is not good enough but not all children are loaded, so render this tile anyway. - addTileToRenderList(primitive, frameState, tile); + addTileToRenderList(primitive, tile); } } @@ -532,9 +537,8 @@ define([ return maxGeometricError / pixelSize; } - function addTileToRenderList(primitive, frameState, tile) { - var tilesToRender = frameState.passes.render ? primitive._tilesToRender : primitive._tilesToRenderForPick; - tilesToRender.push(tile); + function addTileToRenderList(primitive, tile) { + primitive._tilesToRender.push(tile); ++primitive._debug.tilesRendered; } @@ -691,7 +695,7 @@ define([ function createRenderCommandsForSelectedTiles(primitive, frameState) { var tileProvider = primitive._tileProvider; - var tilesToRender = frameState.passes.render ? primitive._tilesToRender : primitive._tilesToRenderForPick; + var tilesToRender = primitive._tilesToRender; var tilesToUpdateHeights = primitive._tileToUpdateHeights; tilesToRender.sort(tileDistanceSortFunction); @@ -708,4 +712,4 @@ define([ } return QuadtreePrimitive; -}); +}); \ No newline at end of file diff --git a/Source/Scene/TileTerrain.js b/Source/Scene/TileTerrain.js index 073784cc5c4c..ca4ebebb4cf4 100644 --- a/Source/Scene/TileTerrain.js +++ b/Source/Scene/TileTerrain.js @@ -251,6 +251,7 @@ define([ attributes : attributes, indexBuffer : indexBuffer }); + tileTerrain.vertexArray.referenceCount = 1; tileTerrain.state = TerrainState.READY; } From 4eed2ab246c78dcbf681f8e044b04275ba1aa748 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 6 May 2016 16:12:28 -0400 Subject: [PATCH 5/9] Formatting. --- Source/Scene/GlobeSurfaceTileProvider.js | 178 +++++++++++------------ Source/Scene/QuadtreePrimitive.js | 74 +++++----- 2 files changed, 126 insertions(+), 126 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 4a365f1ee646..7f87364f2d24 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -1,94 +1,94 @@ /*global define*/ define([ - '../Core/BoundingSphere', - '../Core/BoxOutlineGeometry', - '../Core/Cartesian2', - '../Core/Cartesian3', - '../Core/Cartesian4', - '../Core/Color', - '../Core/ColorGeometryInstanceAttribute', - '../Core/defaultValue', - '../Core/defined', - '../Core/defineProperties', - '../Core/destroyObject', - '../Core/DeveloperError', - '../Core/Event', - '../Core/FeatureDetection', - '../Core/GeometryInstance', - '../Core/GeometryPipeline', - '../Core/IndexDatatype', - '../Core/Intersect', - '../Core/Math', - '../Core/Matrix4', - '../Core/OrientedBoundingBox', - '../Core/PrimitiveType', - '../Core/Rectangle', - '../Core/SphereOutlineGeometry', - '../Core/TerrainQuantization', - '../Core/Visibility', - '../Core/WebMercatorProjection', - '../Renderer/Buffer', - '../Renderer/BufferUsage', - '../Renderer/ContextLimits', - '../Renderer/DrawCommand', - '../Renderer/RenderState', - '../Renderer/VertexArray', - '../Scene/BlendingState', - '../Scene/DepthFunction', - '../Scene/Pass', - '../Scene/PerInstanceColorAppearance', - '../Scene/Primitive', - '../ThirdParty/when', - './GlobeSurfaceTile', - './ImageryLayer', - './ImageryState', - './QuadtreeTileLoadState', - './SceneMode' -], function( - BoundingSphere, - BoxOutlineGeometry, - Cartesian2, - Cartesian3, - Cartesian4, - Color, - ColorGeometryInstanceAttribute, - defaultValue, - defined, - defineProperties, - destroyObject, - DeveloperError, - Event, - FeatureDetection, - GeometryInstance, - GeometryPipeline, - IndexDatatype, - Intersect, - CesiumMath, - Matrix4, - OrientedBoundingBox, - PrimitiveType, - Rectangle, - SphereOutlineGeometry, - TerrainQuantization, - Visibility, - WebMercatorProjection, - Buffer, - BufferUsage, - ContextLimits, - DrawCommand, - RenderState, - VertexArray, - BlendingState, - DepthFunction, - Pass, - PerInstanceColorAppearance, - Primitive, - when, - GlobeSurfaceTile, - ImageryLayer, - ImageryState, - QuadtreeTileLoadState, - SceneMode) { + '../Core/BoundingSphere', + '../Core/BoxOutlineGeometry', + '../Core/Cartesian2', + '../Core/Cartesian3', + '../Core/Cartesian4', + '../Core/Color', + '../Core/ColorGeometryInstanceAttribute', + '../Core/defaultValue', + '../Core/defined', + '../Core/defineProperties', + '../Core/destroyObject', + '../Core/DeveloperError', + '../Core/Event', + '../Core/FeatureDetection', + '../Core/GeometryInstance', + '../Core/GeometryPipeline', + '../Core/IndexDatatype', + '../Core/Intersect', + '../Core/Math', + '../Core/Matrix4', + '../Core/OrientedBoundingBox', + '../Core/PrimitiveType', + '../Core/Rectangle', + '../Core/SphereOutlineGeometry', + '../Core/TerrainQuantization', + '../Core/Visibility', + '../Core/WebMercatorProjection', + '../Renderer/Buffer', + '../Renderer/BufferUsage', + '../Renderer/ContextLimits', + '../Renderer/DrawCommand', + '../Renderer/RenderState', + '../Renderer/VertexArray', + '../Scene/BlendingState', + '../Scene/DepthFunction', + '../Scene/Pass', + '../Scene/PerInstanceColorAppearance', + '../Scene/Primitive', + '../ThirdParty/when', + './GlobeSurfaceTile', + './ImageryLayer', + './ImageryState', + './QuadtreeTileLoadState', + './SceneMode' + ], function( + BoundingSphere, + BoxOutlineGeometry, + Cartesian2, + Cartesian3, + Cartesian4, + Color, + ColorGeometryInstanceAttribute, + defaultValue, + defined, + defineProperties, + destroyObject, + DeveloperError, + Event, + FeatureDetection, + GeometryInstance, + GeometryPipeline, + IndexDatatype, + Intersect, + CesiumMath, + Matrix4, + OrientedBoundingBox, + PrimitiveType, + Rectangle, + SphereOutlineGeometry, + TerrainQuantization, + Visibility, + WebMercatorProjection, + Buffer, + BufferUsage, + ContextLimits, + DrawCommand, + RenderState, + VertexArray, + BlendingState, + DepthFunction, + Pass, + PerInstanceColorAppearance, + Primitive, + when, + GlobeSurfaceTile, + ImageryLayer, + ImageryState, + QuadtreeTileLoadState, + SceneMode) { 'use strict'; /** diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index b3cf268e083f..7b1733df9717 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -1,42 +1,42 @@ /*global define*/ define([ - '../Core/Cartesian3', - '../Core/Cartographic', - '../Core/defaultValue', - '../Core/defined', - '../Core/defineProperties', - '../Core/DeveloperError', - '../Core/Event', - '../Core/getTimestamp', - '../Core/Math', - '../Core/Queue', - '../Core/Ray', - '../Core/Rectangle', - '../Core/Visibility', - './QuadtreeOccluders', - './QuadtreeTile', - './QuadtreeTileLoadState', - './SceneMode', - './TileReplacementQueue' -], function( - Cartesian3, - Cartographic, - defaultValue, - defined, - defineProperties, - DeveloperError, - Event, - getTimestamp, - CesiumMath, - Queue, - Ray, - Rectangle, - Visibility, - QuadtreeOccluders, - QuadtreeTile, - QuadtreeTileLoadState, - SceneMode, - TileReplacementQueue) { + '../Core/Cartesian3', + '../Core/Cartographic', + '../Core/defaultValue', + '../Core/defined', + '../Core/defineProperties', + '../Core/DeveloperError', + '../Core/Event', + '../Core/getTimestamp', + '../Core/Math', + '../Core/Queue', + '../Core/Ray', + '../Core/Rectangle', + '../Core/Visibility', + './QuadtreeOccluders', + './QuadtreeTile', + './QuadtreeTileLoadState', + './SceneMode', + './TileReplacementQueue' + ], function( + Cartesian3, + Cartographic, + defaultValue, + defined, + defineProperties, + DeveloperError, + Event, + getTimestamp, + CesiumMath, + Queue, + Ray, + Rectangle, + Visibility, + QuadtreeOccluders, + QuadtreeTile, + QuadtreeTileLoadState, + SceneMode, + TileReplacementQueue) { 'use strict'; /** From 16fbf8ef9d95513170fb9866b0a6314d2eee8710 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Fri, 6 May 2016 16:28:34 -0400 Subject: [PATCH 6/9] Release unused cached terrain commands every 120 frames. --- Source/Scene/GlobeSurfaceTile.js | 4 +--- Source/Scene/GlobeSurfaceTileProvider.js | 30 ++++++++++++++++++++++-- Source/Scene/QuadtreePrimitive.js | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index 683408f36a56..b58ee605c6e8 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -216,9 +216,7 @@ define([ if (defined(this.vertexArray)) { indexBuffer = this.vertexArray.indexBuffer; - - //this.vertexArray = this.vertexArray.destroy(); - + --this.vertexArray.referenceCount; if (this.vertexArray.referenceCount === 0) { this.vertexArray.destroy(); diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 7f87364f2d24..11806a71bdd5 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -149,6 +149,7 @@ define([ this._pickCommands = []; this._usedDrawCommands = 0; this._usedPickCommands = 0; + this._commandFrameCount = 0; this._debug = { wireframe : false, @@ -333,6 +334,28 @@ define([ } } + // Release unused WebGL resources from cached commands once every 120 frames + if (this._commandFrameCount++ === 120) { + this._commandFrameCount = 0; + + var j; + + var commands = this._drawCommands; + var length = commands.length; + for (j = this._usedDrawCommands; j < length; ++j) { + swapCommandVertexArray(commands[j], undefined); + } + + commands = this._pickCommands; + length = commands.length; + for (j = this._usedPickCommands; j < length; ++j) { + swapCommandVertexArray(commands[j], undefined); + } + + this._drawCommands.length = 0; + this._pickCommands.length = 0; + } + this._usedDrawCommands = 0; }; @@ -887,7 +910,10 @@ define([ } command.vertexArray = vertexArray; - ++command.vertexArray.referenceCount; + + if (defined(vertexArray)) { + ++command.vertexArray.referenceCount; + } } var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0); @@ -1184,4 +1210,4 @@ define([ } return GlobeSurfaceTileProvider; -}); \ No newline at end of file +}); diff --git a/Source/Scene/QuadtreePrimitive.js b/Source/Scene/QuadtreePrimitive.js index 7b1733df9717..332a787de347 100644 --- a/Source/Scene/QuadtreePrimitive.js +++ b/Source/Scene/QuadtreePrimitive.js @@ -712,4 +712,4 @@ define([ } return QuadtreePrimitive; -}); \ No newline at end of file +}); From 5eb5e1f0cc7bc64ff608fa3cf46290c9d312d63f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 10 May 2016 17:07:31 -0400 Subject: [PATCH 7/9] Decrement the reference count instead of destroying a vertex array when unloading. --- Source/Scene/TileTerrain.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Scene/TileTerrain.js b/Source/Scene/TileTerrain.js index ca4ebebb4cf4..b6b82aee3c4e 100644 --- a/Source/Scene/TileTerrain.js +++ b/Source/Scene/TileTerrain.js @@ -64,15 +64,19 @@ define([ if (defined(this.vertexArray)) { var indexBuffer = this.vertexArray.indexBuffer; - this.vertexArray.destroy(); - this.vertexArray = undefined; + --this.vertexArray.referenceCount; + if (this.vertexArray.referenceCount === 0) { + this.vertexArray.destroy(); + } - if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { + if (this.vertexArray.isDestroyed() && !indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { --indexBuffer.referenceCount; if (indexBuffer.referenceCount === 0) { indexBuffer.destroy(); } } + + this.vertexArray = undefined; } }; From cca9289c60d01cb472ec01e4d614401378b62a52 Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Tue, 10 May 2016 17:36:56 -0400 Subject: [PATCH 8/9] Queue vertex arrays for destruction at the begining of the frame instead or using reference counting. --- Source/Scene/GlobeSurfaceTile.js | 39 ++++++++---- Source/Scene/GlobeSurfaceTileProvider.js | 78 ++++++++---------------- Source/Scene/TileTerrain.js | 32 +++------- 3 files changed, 61 insertions(+), 88 deletions(-) diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index b58ee605c6e8..212a27aafea0 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -216,20 +216,15 @@ define([ if (defined(this.vertexArray)) { indexBuffer = this.vertexArray.indexBuffer; - - --this.vertexArray.referenceCount; - if (this.vertexArray.referenceCount === 0) { - this.vertexArray.destroy(); - } - if (this.vertexArray.isDestroyed() && !indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { + this.vertexArray = this.vertexArray.destroy(); + + if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { --indexBuffer.referenceCount; if (indexBuffer.referenceCount === 0) { indexBuffer.destroy(); } } - - this.vertexArray = undefined; } if (defined(this.wireframeVertexArray)) { @@ -246,7 +241,7 @@ define([ } }; - GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection) { + GlobeSurfaceTile.processStateMachine = function(tile, frameState, terrainProvider, imageryLayerCollection, vertexArraysToDestroy) { var surfaceTile = tile.data; if (!defined(surfaceTile)) { surfaceTile = tile.data = new GlobeSurfaceTile(); @@ -258,7 +253,7 @@ define([ } if (tile.state === QuadtreeTileLoadState.LOADING) { - processTerrainStateMachine(tile, frameState, terrainProvider); + processTerrainStateMachine(tile, frameState, terrainProvider, vertexArraysToDestroy); } // The terrain is renderable as soon as we have a valid vertex array. @@ -303,7 +298,7 @@ define([ isRenderable = isRenderable && (thisTileDoneLoading || defined(tileImagery.readyImagery)); isUpsampledOnly = isUpsampledOnly && defined(tileImagery.loadingImagery) && - (tileImagery.loadingImagery.state === ImageryState.FAILED || tileImagery.loadingImagery.state === ImageryState.INVALID); + (tileImagery.loadingImagery.state === ImageryState.FAILED || tileImagery.loadingImagery.state === ImageryState.INVALID); } tile.upsampledFromParent = isUpsampledOnly; @@ -341,7 +336,7 @@ define([ } } - function processTerrainStateMachine(tile, frameState, terrainProvider) { + function processTerrainStateMachine(tile, frameState, terrainProvider, vertexArraysToDestroy) { var surfaceTile = tile.data; var loaded = surfaceTile.loadedTerrain; var upsampled = surfaceTile.upsampledTerrain; @@ -368,6 +363,15 @@ define([ if (loaded.state === TerrainState.READY) { loaded.publishToTile(tile); + if (defined(tile.data.vertexArray)) { + // Free the tiles existing vertex array on next render. + vertexArraysToDestroy.push(tile.data.vertexArray); + } + + // Transfer ownership of the vertex array to the tile itself. + tile.data.vertexArray = loaded.vertexArray; + loaded.vertexArray = undefined; + // No further loading or upsampling is necessary. surfaceTile.pickTerrain = defaultValue(surfaceTile.loadedTerrain, surfaceTile.upsampledTerrain); surfaceTile.loadedTerrain = undefined; @@ -404,6 +408,15 @@ define([ if (upsampled.state === TerrainState.READY) { upsampled.publishToTile(tile); + if (defined(tile.data.vertexArray)) { + // Free the tiles existing vertex array on next render. + vertexArraysToDestroy.push(tile.data.vertexArray); + } + + // Transfer ownership of the vertex array to the tile itself. + tile.data.vertexArray = upsampled.vertexArray; + upsampled.vertexArray = undefined; + // No further upsampling is necessary. We need to continue loading, though. surfaceTile.pickTerrain = surfaceTile.upsampledTerrain; surfaceTile.upsampledTerrain = undefined; @@ -659,4 +672,4 @@ define([ } return GlobeSurfaceTile; -}); +}); \ No newline at end of file diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 11806a71bdd5..c45f55ada797 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -149,7 +149,8 @@ define([ this._pickCommands = []; this._usedDrawCommands = 0; this._usedPickCommands = 0; - this._commandFrameCount = 0; + + this._vertexArraysToDestroy = []; this._debug = { wireframe : false, @@ -283,6 +284,18 @@ define([ return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex; } + function freeVertexArray(vertexArray) { + var indexBuffer = vertexArray.indexBuffer; + vertexArray.destroy(); + + if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { + --indexBuffer.referenceCount; + if (indexBuffer.referenceCount === 0) { + indexBuffer.destroy(); + } + } + } + /** * Called at the beginning of each render frame, before {@link QuadtreeTileProvider#showTileThisFrame} * @param {FrameState} frameState The frame state. @@ -317,6 +330,13 @@ define([ creditDisplay.addCredit(imageryProvider.credit); } } + + var vertexArraysToDestroy = this._vertexArraysToDestroy; + var length = vertexArraysToDestroy.length; + for (var j = 0; j < length; ++j) { + freeVertexArray(vertexArraysToDestroy[j]); + } + vertexArraysToDestroy.length = 0; }; /** @@ -334,28 +354,6 @@ define([ } } - // Release unused WebGL resources from cached commands once every 120 frames - if (this._commandFrameCount++ === 120) { - this._commandFrameCount = 0; - - var j; - - var commands = this._drawCommands; - var length = commands.length; - for (j = this._usedDrawCommands; j < length; ++j) { - swapCommandVertexArray(commands[j], undefined); - } - - commands = this._pickCommands; - length = commands.length; - for (j = this._usedPickCommands; j < length; ++j) { - swapCommandVertexArray(commands[j], undefined); - } - - this._drawCommands.length = 0; - this._pickCommands.length = 0; - } - this._usedDrawCommands = 0; }; @@ -461,7 +459,7 @@ define([ * @exception {DeveloperError} loadTile must not be called before the tile provider is ready. */ GlobeSurfaceTileProvider.prototype.loadTile = function(frameState, tile) { - GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers); + GlobeSurfaceTile.processStateMachine(tile, frameState, this._terrainProvider, this._imageryLayers, this._vertexArraysToDestroy); }; var boundingSphereScratch = new BoundingSphere(); @@ -892,30 +890,6 @@ define([ }; })(); - function swapCommandVertexArray(command, vertexArray) { - if (defined(command.vertexArray)) { - var indexBuffer = command.vertexArray.indexBuffer; - - --command.vertexArray.referenceCount; - if (command.vertexArray.referenceCount === 0) { - command.vertexArray.destroy(); - } - - if (command.vertexArray.isDestroyed() && !indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { - --indexBuffer.referenceCount; - if (indexBuffer.referenceCount === 0) { - indexBuffer.destroy(); - } - } - } - - command.vertexArray = vertexArray; - - if (defined(vertexArray)) { - ++command.vertexArray.referenceCount; - } - } - var otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0); function addDrawCommandsForTile(tileProvider, tile, frameState) { @@ -1143,11 +1117,10 @@ define([ command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); command.renderState = renderState; command.primitiveType = PrimitiveType.TRIANGLES; + command.vertexArray = surfaceTile.vertexArray; command.uniformMap = uniformMap; command.pass = Pass.GLOBE; - swapCommandVertexArray(command, surfaceTile.vertexArray); - if (tileProvider._debug.wireframe) { createWireframeVertexArrayIfNecessary(context, tileProvider, tile); if (defined(surfaceTile.wireframeVertexArray)) { @@ -1199,15 +1172,14 @@ define([ pickCommand.owner = drawCommand.owner; pickCommand.primitiveType = drawCommand.primitiveType; + pickCommand.vertexArray = drawCommand.vertexArray; pickCommand.uniformMap = drawCommand.uniformMap; pickCommand.boundingVolume = drawCommand.boundingVolume; pickCommand.orientedBoundingBox = drawCommand.orientedBoundingBox; pickCommand.pass = drawCommand.pass; - swapCommandVertexArray(pickCommand, drawCommand.vertexArray); - frameState.commandList.push(pickCommand); } return GlobeSurfaceTileProvider; -}); +}); \ No newline at end of file diff --git a/Source/Scene/TileTerrain.js b/Source/Scene/TileTerrain.js index b6b82aee3c4e..bf6ad6606461 100644 --- a/Source/Scene/TileTerrain.js +++ b/Source/Scene/TileTerrain.js @@ -64,19 +64,15 @@ define([ if (defined(this.vertexArray)) { var indexBuffer = this.vertexArray.indexBuffer; - --this.vertexArray.referenceCount; - if (this.vertexArray.referenceCount === 0) { - this.vertexArray.destroy(); - } + this.vertexArray.destroy(); + this.vertexArray = undefined; - if (this.vertexArray.isDestroyed() && !indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { + if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) { --indexBuffer.referenceCount; if (indexBuffer.referenceCount === 0) { indexBuffer.destroy(); } } - - this.vertexArray = undefined; } }; @@ -97,13 +93,6 @@ define([ }); tile.data.occludeePointInScaledSpace = Cartesian3.clone(mesh.occludeePointInScaledSpace, surfaceTile.occludeePointInScaledSpace); - - // Free the tile's existing vertex array, if any. - surfaceTile.freeVertexArray(); - - // Transfer ownership of the vertex array to the tile itself. - surfaceTile.vertexArray = this.vertexArray; - this.vertexArray = undefined; }; TileTerrain.prototype.processLoadStateMachine = function(frameState, terrainProvider, x, y, level) { @@ -133,12 +122,12 @@ define([ var message = 'Failed to obtain terrain tile X: ' + x + ' Y: ' + y + ' Level: ' + level + '.'; terrainProvider._requestError = TileProviderError.handleError( - terrainProvider._requestError, - terrainProvider, - terrainProvider.errorEvent, - message, - x, y, level, - doRequest); + terrainProvider._requestError, + terrainProvider, + terrainProvider.errorEvent, + message, + x, y, level, + doRequest); } function doRequest() { @@ -255,10 +244,9 @@ define([ attributes : attributes, indexBuffer : indexBuffer }); - tileTerrain.vertexArray.referenceCount = 1; tileTerrain.state = TerrainState.READY; } return TileTerrain; -}); +}); \ No newline at end of file From 21ec084e4c13782f1b1d392b2ede11fc2fc0802f Mon Sep 17 00:00:00 2001 From: Dan Bagnell Date: Wed, 11 May 2016 17:40:21 -0400 Subject: [PATCH 9/9] Update CHANGES.md. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index f22b9125f5cf..3337986a2342 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Change Log * Fixed exaggerated terrain tiles disappearing. [#3676](https://github.com/AnalyticalGraphicsInc/cesium/issues/3676) * Fixed infinite horizontal 2D scrolling in IE/Edge. [#3893](https://github.com/AnalyticalGraphicsInc/cesium/issues/3893) * Fixed a bug that could cause incorrect normals to be computed for exaggerated terrain, especially for low-detail tiles. [#3904](https://github.com/AnalyticalGraphicsInc/cesium/pull/3904) +* Fixed a bug that was causing errors to be thrown when picking and terrain was enabled. [#3779](https://github.com/AnalyticalGraphicsInc/cesium/issues/3779) ### 1.21 - 2016-05-02