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

Framebuffer refactor #5793

Merged
merged 7 commits into from
Dec 7, 2017
Merged

Framebuffer refactor #5793

merged 7 commits into from
Dec 7, 2017

Conversation

lbud
Copy link
Contributor

@lbud lbud commented Dec 2, 2017

Primary changes:

  • Refactors all render calls that render to offscreen framebuffers (fill-extrusion, heatmap, hillshade) into one offscreen pass (fixes Render to heatmap framebuffer in separate pass #5803)
  • Makes Context responsible for all framebuffer + renderbuffer creation
  • Introduces Framebuffer class, responsible for managing its color and/or depth attachment states, retaining size info, and cleaning up its attachments with gl.delete* calls when destroyed
    • Framebuffers still need to be bound and unbound (by setting context.bindFramebuffer) in render code in order to specify the intended rendering target, but do not need to be manually bound in order to change their attachments: attachment values handle the necessary bindings when set
  • Eliminates RenderTexture class

Minor changes:

  • Moves GL extensions stored on the painter to the context object
  • Caches tile-sized framebuffers on the painter when unloaded (from hillshade layers) for reuse in new loaded hillshade tiles
  • Updates heatmap-radius/antimeridian render test (Framebuffer refactor #5793 (comment))

Benchmark results: https://bl.ocks.org/anonymous/raw/3d9a8aa509b5dc8d0c1d97c6e5f6110f/

Refs #145.

@lbud lbud requested a review from jfirebaugh December 2, 2017 00:45
@lbud lbud force-pushed the state-framebuffers branch from 17d1dc0 to a541fae Compare December 2, 2017 02:03
Copy link
Contributor

@jfirebaugh jfirebaugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good direction here. Aside from a few places the type annotations could be improved, the main thing I'm wondering about is whether we can make the ownership conventions clearer. Can the the Framebuffer itself own the attachments and be responsible for releasing them in a Framebuffer#destroy method comparable to Texture#destroy and VertexArrayObject#destroy? Or does the need for shared attachments prevent that?

src/gl/value.js Outdated

constructor(context: Context) {
constructor(context: Context, parent: ?any) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding an any-typed parameter and member in the base class, override the constructor in ColorAttachment and DepthAttachment.

@@ -87,6 +87,7 @@ class Tile {
needsHillshadePrepare: ?boolean
request: any;
texture: any;
fbo: any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fbo: Framebuffer

@lbud
Copy link
Contributor Author

lbud commented Dec 5, 2017

Note that the test updated in 3577b7c changed because it had been incorrectly overdrawing before: drawHeatmap was previously using painter.isOpaquePass, which we deprecated a little while ago in favor of a painter.pass enum.

@mourner
Copy link
Member

mourner commented Dec 5, 2017

@lbud the heatmap drawing changes look great to me!

@lbud lbud force-pushed the state-framebuffers branch from 3577b7c to 880b481 Compare December 5, 2017 21:53
@lbud
Copy link
Contributor Author

lbud commented Dec 5, 2017

Can the the Framebuffer itself own the attachments and be responsible for releasing them in a Framebuffer#destroy method comparable to Texture#destroy and VertexArrayObject#destroy? Or does the need for shared attachments prevent that?

Yes, good idea — addressed this in 470e764. Per the WebGL spec, "If the renderbuffer has already been deleted the call has no effect," so shared renderbuffer attachments won't cause a problem (confirmed on a debug map).

@lbud lbud requested a review from jfirebaugh December 6, 2017 22:32
return false;
}

resize(gl: WebGLRenderingContext) { // eslint-disable-line
resize() { // eslint-disable-line
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eslint-disable-line was probably for the unused parameter and can be removed too.

@@ -20,9 +21,11 @@ function draw(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLa
return;
}

if (painter.renderPass === '3d') {
if (painter.renderPass === 'offscreen') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One rule of thumb that I try to follow is that if you have a series of conditionals, it's good for comprehensibility if you can make the bodies of each branch parallel in form (same principle as parallelism in grammar). Here, for instance, I would rename setupFramebuffer to drawExtrusionFramebuffer and move the code just above and below the call into the function, so that the two branch bodes are both a single drawExtrusion*(...) expression.

@@ -42,7 +42,7 @@ class StyleLayer extends Evented {
_transitioningPaint: Transitioning<any>;
+paint: mixed;

viewportFrame: ?RenderTexture;
viewportFrame: ?Framebuffer;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this declaration be pushed down hierarchy, into FillExtrusionStyleLayer?

@@ -116,6 +116,10 @@ class RasterDEMTileSource extends RasterTileSource implements Source {

unloadTile(tile: Tile) {
if (tile.demTexture) this.map.painter.saveTileTexture(tile.demTexture);
if (tile.fbo) {
this.map.painter.saveTileFramebuffer(tile.fbo);
Copy link
Contributor

@jfirebaugh jfirebaugh Dec 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much of a performance difference does caching framebuffers make? If it's not too big a difference, I think it would be good to keep things simple and create a fresh framebuffer for each new DEM tile.

@lbud lbud force-pushed the state-framebuffers branch from 6a2216c to 3a5a0aa Compare December 7, 2017 19:09
@lbud lbud merged commit 22ffd3f into master Dec 7, 2017
@lbud lbud deleted the state-framebuffers branch December 7, 2017 19:30
@mourner
Copy link
Member

mourner commented Jan 10, 2018

@lbud are you planning to do a similar refactor (consolidating offscreen rendering into an "offscreen" pass) on the gl-native side?

@lbud
Copy link
Contributor Author

lbud commented Jan 10, 2018

@mourner we should use the same process (an offscreen pass to render to all offscreen framebuffers) on native. I haven't yet started something like this there, although at the moment fill-extrusion layers are the only offscreen layer type on master, so if I were to do so right now it would just be a minor refactor (moving extrusion depth buffer setup into render_fill_extrusion.cpp and renaming "3d" to "offscreen"). I know you and @mollymerp have heatmap/hillshade branches in progress — not sure how far along you are; if it's convenient for you to render those in the 3d pass feel free to make those changes, but if not it shouldn't be a big deal to refactor afterward as we did in gl-js.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Render to heatmap framebuffer in separate pass
3 participants