diff --git a/src/render/painter.js b/src/render/painter.js index 4d17669d121..e938e067b60 100644 --- a/src/render/painter.js +++ b/src/render/painter.js @@ -132,8 +132,7 @@ class Painter { quadTriangleIndexBuffer: IndexBuffer; mercatorBoundsBuffer: VertexBuffer; mercatorBoundsSegments: SegmentVector; - _tileClippingMaskIDs: Map; - _skippedStencilTileIDs: Set; + _tileClippingMaskIDs: {[_: number]: number }; stencilClearMode: StencilMode; style: Style; options: PainterOptions; @@ -186,8 +185,6 @@ class Painter { this.gpuTimers = {}; this.frameCounter = 0; this._backgroundTiles = {}; - this._tileClippingMaskIDs = new Map(); - this._skippedStencilTileIDs = new Set(); } updateTerrain(style: Style, cameraChanging: boolean) { @@ -333,8 +330,7 @@ class Painter { this.nextStencilID = 1; this.currentStencilSource = undefined; - this._tileClippingMaskIDs.clear(); - this._skippedStencilTileIDs.clear(); + this._tileClippingMaskIDs = {}; // As a temporary workaround for https://github.com/mapbox/mapbox-gl-js/issues/5490, // pending an upstream fix, we draw a fullscreen stencil=0 clipping mask here, @@ -350,8 +346,7 @@ class Painter { resetStencilClippingMasks() { if (!this.terrain) { this.currentStencilSource = undefined; - this._tileClippingMaskIDs.clear(); - this._skippedStencilTileIDs.clear(); + this._tileClippingMaskIDs = {}; } } @@ -360,69 +355,48 @@ class Painter { return; } - const renderableSkippedTileIDs = []; - let dirtyStencilClippingMasks = false; if (this._tileClippingMaskIDs && !this.terrain) { + let dirtyStencilClippingMasks = false; // Equivalent tile set is already rendered in stencil for (const coord of tileIDs) { - if (!this._tileClippingMaskIDs.has(coord.key)) { + if (this._tileClippingMaskIDs[coord.key] === undefined) { dirtyStencilClippingMasks = true; - } - if (this._skippedStencilTileIDs.has(coord.key)) { - if (!sourceCache.getTile(coord).getBucket(layer)) { - continue; - } - this._skippedStencilTileIDs.delete(coord.key); - renderableSkippedTileIDs.push(coord); + break; } } - if (!dirtyStencilClippingMasks && renderableSkippedTileIDs.length === 0) { + if (!dirtyStencilClippingMasks) { return; } } + this.currentStencilSource = sourceCache.id; + const context = this.context; const gl = context.gl; + + if (this.nextStencilID + tileIDs.length > 256) { + // we'll run out of fresh IDs so we need to clear and start from scratch + this.clearStencil(); + } + context.setColorMode(ColorMode.disabled); context.setDepthMode(DepthMode.disabled); + const program = this.useProgram('clippingMask'); - const renderStencil = (tileID) => { + this._tileClippingMaskIDs = {}; + + for (const tileID of tileIDs) { const tile = sourceCache.getTile(tileID); + const id = this._tileClippingMaskIDs[tileID.key] = this.nextStencilID++; const {tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments} = this.getTileBoundsBuffers(tile); - program.draw(context, gl.TRIANGLES, DepthMode.disabled, - // Tests will pass if the new ref is greater than the previous value, and ref value will be written to stencil buffer. - new StencilMode({func: gl.GREATER, mask: 0xFF}, this._tileClippingMaskIDs.get(tileID.key) || 0, 0xFF, gl.KEEP, gl.KEEP, gl.REPLACE), - ColorMode.disabled, CullFaceMode.disabled, clippingMaskUniformValues(tileID.projMatrix), - '$clipping', tileBoundsBuffer, - tileBoundsIndexBuffer, tileBoundsSegments); - }; - if (!dirtyStencilClippingMasks && renderableSkippedTileIDs.length > 0) { - for (const tileID of renderableSkippedTileIDs) { - renderStencil(tileID); - } - } else { - if (this._tileClippingMaskIDs.size === 0 || this.nextStencilID + tileIDs.length > 256) { - // we'll run out of fresh IDs so we need to clear and start from scratch - this.clearStencil(); - } - - this._tileClippingMaskIDs.clear(); - this._skippedStencilTileIDs.clear(); - - for (const tileID of tileIDs) { - this._tileClippingMaskIDs.set(tileID.key, this.nextStencilID++); - if (!sourceCache.getTile(tileID).getBucket(layer)) { - this._skippedStencilTileIDs.add(tileID.key); - continue; - } - renderStencil(tileID); - } - } - - if (this._skippedStencilTileIDs.size === 0) { - this.currentStencilSource = sourceCache.id; + program.draw(context, gl.TRIANGLES, DepthMode.disabled, + // Tests will always pass, and ref value will be written to stencil buffer. + new StencilMode({func: gl.ALWAYS, mask: 0}, id, 0xFF, gl.KEEP, gl.KEEP, gl.REPLACE), + ColorMode.disabled, CullFaceMode.disabled, clippingMaskUniformValues(tileID.projMatrix), + '$clipping', tileBoundsBuffer, + tileBoundsIndexBuffer, tileBoundsSegments); } } @@ -441,7 +415,7 @@ class Painter { stencilModeForClipping(tileID: OverscaledTileID): $ReadOnly { if (this.terrain) return this.terrain.stencilModeForRTTOverlap(tileID); const gl = this.context.gl; - return new StencilMode({func: gl.EQUAL, mask: 0xFF}, this._tileClippingMaskIDs.get(tileID.key) || 0, 0x00, gl.KEEP, gl.KEEP, gl.REPLACE); + return new StencilMode({func: gl.EQUAL, mask: 0xFF}, this._tileClippingMaskIDs[tileID.key], 0x00, gl.KEEP, gl.KEEP, gl.REPLACE); } /* diff --git a/src/terrain/terrain.js b/src/terrain/terrain.js index 15c39773d2e..aac936c4a8d 100644 --- a/src/terrain/terrain.js +++ b/src/terrain/terrain.js @@ -1153,7 +1153,7 @@ export class Terrain extends Elevation { // 1. overlap is handled by proxy render to texture tiles (there is no overlap there) // 2. here we handle only brief zoom out semi-transparent color intensity flickering // and that is avoided fine by stenciling primitives as part of drawing (instead of additional tile quad step). - this._overlapStencilMode.ref = this.painter._tileClippingMaskIDs.get(id.key) || 0; + this._overlapStencilMode.ref = this.painter._tileClippingMaskIDs[id.key]; } // else this._overlapStencilMode.ref is set to a single value used per proxy tile, in _setupStencil. return this._overlapStencilMode; } @@ -1162,15 +1162,14 @@ export class Terrain extends Elevation { const painter = this.painter; const context = this.painter.context; const gl = context.gl; - painter._tileClippingMaskIDs.clear(); + painter._tileClippingMaskIDs = {}; context.setColorMode(ColorMode.disabled); context.setDepthMode(DepthMode.disabled); const program = painter.useProgram('clippingMask'); for (const tileID of proxiedCoords) { - const id = --ref; - painter._tileClippingMaskIDs.set(tileID.key, id); + const id = painter._tileClippingMaskIDs[tileID.key] = --ref; program.draw(context, gl.TRIANGLES, DepthMode.disabled, // Tests will always pass, and ref value will be written to stencil buffer. new StencilMode({func: gl.ALWAYS, mask: 0}, id, 0xFF, gl.KEEP, gl.KEEP, gl.REPLACE),