Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert stencil mask skipping optimization #11848

Merged
merged 1 commit into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 27 additions & 53 deletions src/render/painter.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ class Painter {
quadTriangleIndexBuffer: IndexBuffer;
mercatorBoundsBuffer: VertexBuffer;
mercatorBoundsSegments: SegmentVector;
_tileClippingMaskIDs: Map<number, number>;
_skippedStencilTileIDs: Set<number>;
_tileClippingMaskIDs: {[_: number]: number };
stencilClearMode: StencilMode;
style: Style;
options: PainterOptions;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -350,8 +346,7 @@ class Painter {
resetStencilClippingMasks() {
if (!this.terrain) {
this.currentStencilSource = undefined;
this._tileClippingMaskIDs.clear();
this._skippedStencilTileIDs.clear();
this._tileClippingMaskIDs = {};
}
}

Expand All @@ -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);
}
}

Expand All @@ -441,7 +415,7 @@ class Painter {
stencilModeForClipping(tileID: OverscaledTileID): $ReadOnly<StencilMode> {
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);
}

/*
Expand Down
7 changes: 3 additions & 4 deletions src/terrain/terrain.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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),
Expand Down