-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Use stencil test instead of tile mask approach #9012
Conversation
Improvement in frame rendering time, when all the tile are loaded is measurable: Mac Mini 3.2 GHz 6-Core Intel Core i7, Intel UHD Graphics 630 1536 MB, 3440 x 1440 monitor. using debug/satellite.html page with master: 42 - 48 FPS |
In another measurement, used two satellite layers, and measured difference when second raster one is semi transparent vs opaque. In this case it renders two satellite layers and there is a significant contribution of time spent on preparing and issuing draw calls but, should the depth test work, we could compare impact of fragment shading. patch semi-transparent overlay: ~47 FPS Patch used in measurement:
|
Patch, 2 layers, second (semi-transparent) layer has every other tile stenciled out: 47 FPS
Master, 2 layers, second (semi-transparent) layer has every other tile with ColorMode.disabled: 34 FPS
debug/satellite.html changed to display 2 raster layers
|
src/render/painter.js
Outdated
const getStencilMode = (coord) => { | ||
stencilMode.ref = painter.nextStencilID + coord.overscaledZ - minTileZ; | ||
return stencilMode; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of providing a callback function to generate the value, can we just return an array with all precomputed StencilMode objects? This would also allow us to update the nextStencilID
to the final value immediately rather than having a done
callback. I believe that this makes the code easier to follow and has less side effects, e.g. when forgetting to call done
during a refactor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used object for mapping Z to StencilMode.
2d37174
to
34d67dd
Compare
Remove tile masks for raster. Rendering happens in Z-descending order. All the tiles with the same Z use the same stencil value. Parent uses lower stencil value so that the area covered by children gets masked. Stencil ref values continue range used in _tileClippingMaskIDs.
Return map z -> StencilMode instead of using callbacks. overlapping-vector uses vector layer between two raster to guard against side effects when refactoring stencil usage.
34d67dd
to
22f1de7
Compare
Remove tile masks for raster and hillshade. Rendering happens in Z-descending order.
All the tiles with the same Z use the same stencil value. Parent uses lower stencil value so that the area covered by children gets masked.
Stencil ref values continue the range used in _tileClippingMaskIDs.
To understand if this patch makes sense, I measured the time spent in updateTileMasks for simple user interaction: drag map and wait few seconds. Used this patch for measurements.
Measurements of time spent in updateTileMasks:
Chrome on Nexus 5:
Average 1.1ms per frame. Max, per 100 frames is in range [7ms - 30ms]. Average 9 tiles per frame processed. See the screenshot for illustration.
Firefox on Mac Mini 3.2 GHz 6-Core Intel Core i7, 1440p screen. Example measurements, in milliseconds:
The patch moves the masking handling from CPU to GPU. As the behavior of early depth test varies on different hardware, this PR requires FPS measurement (on browser) to rule out performance regression.
Improves file size:
Size - JS — -1.6 kB -0.220% (729 kB)
FPS Measurement on Mac Mini 3.2 GHz 6-Core Intel Core i7
Comparison shows that for large number of raster tiles, using stencil to stencil out tiles on GPU performs significantly than current tile mask computation as the cost of tile mast computation surpasses the cost of extra fragment shading.
Patch, 2 layers, second (semi-transparent) layer has every other tile stenciled out: 47 FPS
Mac Mini 3.2 GHz 6-Core Intel Core i7, Intel UHD Graphics 630 1536 MB, 3440 x 1440 monitor. using debug/satellite.html page with map.repaint = true.
URL: http://localhost:9966/debug/satellite.html#12.64/38.88229/-75.67545/0/60
Master, 2 layers, second (semi-transparent) layer has every other tile with ColorMode.disabled: 34 FPS
debug/satellite.html changed to display 2 raster layers
Loaded map rendering improvement measured using Chrome FPS counter on :
master: 42-48 FPS
patch: 58-60 FPS
Measured effect of shading multiple times by rendering second, semi-transparent or opaque satellite layer above:
patch semi-transparent overlay: ~47 FPS
patch opaque overlay: ~47 FPS
master (irrelevant measurement as it includes tile mask + overdraw): ~31FPS in both cases
Nexus 5 (larger fluctuations in measured values but the trend is noticeable)
Launch Checklist
@mapbox/gl-native
if this PR includes shader changes or needs a native port