Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Preserve depth buffer between 3D layers + optimize render order (#9931)
Browse files Browse the repository at this point in the history
Port of mapbox/mapbox-gl-js#5101: adds a new render pass `Pass3D` before any other rendering wherein we render layers with 3D passes (fill-extrusion layers) to offscreen framebuffers, sharing a depth renderbuffer between those layers in order to render 3D space correctly. Those framebuffers are saved on the RenderLayers and copied back to the map during the translucent pass. Rendering to offscreen framebuffers before we do any clear + draw means we can avoid expensive framebuffer restores.
  • Loading branch information
Lauren Budorick authored Sep 21, 2017
1 parent b91d967 commit a9ddf5b
Show file tree
Hide file tree
Showing 23 changed files with 219 additions and 150 deletions.
2 changes: 2 additions & 0 deletions include/mbgl/renderer/renderer_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class RendererBackend {
// set to the current state.
virtual void bind() = 0;

virtual Size getFramebufferSize() const = 0;

protected:
// Called with the name of an OpenGL extension that should be loaded. RendererBackend implementations
// must call the API-specific version that obtains the function pointer for this function,
Expand Down
8 changes: 4 additions & 4 deletions platform/android/src/native_map_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ void NativeMapView::bind() {
setViewport(0, 0, getFramebufferSize());
}

mbgl::Size NativeMapView::getFramebufferSize() const {
return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
}

/**
* From mbgl::RendererBackend.
*/
Expand Down Expand Up @@ -1428,10 +1432,6 @@ void NativeMapView::_destroySurface() {
}
}

mbgl::Size NativeMapView::getFramebufferSize() const {
return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
}

void NativeMapView::updateAssumedState() {
assumeFramebufferBinding(0);
assumeViewport(0, 0, getFramebufferSize());
Expand Down
5 changes: 3 additions & 2 deletions platform/android/src/native_map_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class NativeMapView : public RendererBackend, public MapObserver {
// mbgl::RendererBackend //

void bind() override;

mbgl::Size getFramebufferSize() const override;

void updateAssumedState() override;

// Deprecated //
Expand Down Expand Up @@ -282,8 +285,6 @@ class NativeMapView : public RendererBackend, public MapObserver {

EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);

mbgl::Size getFramebufferSize() const;

void updateFps();

private:
Expand Down
4 changes: 4 additions & 0 deletions platform/default/mbgl/gl/headless_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ void HeadlessBackend::bind() {
context_.viewport = { 0, 0, size };
}

Size HeadlessBackend::getFramebufferSize() const {
return size;
}

void HeadlessBackend::updateAssumedState() {
// no-op
}
Expand Down
1 change: 1 addition & 0 deletions platform/default/mbgl/gl/headless_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class HeadlessBackend : public RendererBackend {
~HeadlessBackend() override;

void bind() override;
Size getFramebufferSize() const override;
void updateAssumedState() override;

void setSize(Size);
Expand Down
2 changes: 1 addition & 1 deletion platform/glfw/glfw_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class GLFWView : public mbgl::RendererBackend, public mbgl::MapObserver {
void invalidate();

mbgl::Size getSize() const;
mbgl::Size getFramebufferSize() const;
mbgl::Size getFramebufferSize() const override;

// mbgl::RendererBackend implementation
void bind() override;
Expand Down
4 changes: 4 additions & 0 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5464,6 +5464,10 @@ void bind() override {
}
}

mbgl::Size getFramebufferSize() const override {
return nativeView.framebufferSize;
}

void onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) override {
bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
[nativeView cameraWillChangeAnimated:animated];
Expand Down
4 changes: 4 additions & 0 deletions platform/macos/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2883,6 +2883,10 @@ void bind() override {
setViewport(0, 0, nativeView.framebufferSize);
}

mbgl::Size getFramebufferSize() const override {
return nativeView.framebufferSize;
}

mbgl::PremultipliedImage readStillImage() {
return readFramebuffer(nativeView.framebufferSize);
}
Expand Down
1 change: 0 additions & 1 deletion platform/node/test/ignores.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"render-tests/debug/tile": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/extent/1024-circle": "needs investigation",
"render-tests/extent/1024-symbol": "needs investigation",
"render-tests/fill-extrusion-multiple/multiple": "https://github.com/mapbox/mapbox-gl-native/issues/9894",
"render-tests/fill-extrusion-pattern/@2x": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/function-2": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/function": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
Expand Down
8 changes: 4 additions & 4 deletions platform/qt/src/qmapboxgl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1505,7 +1505,7 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin
static_cast<mbgl::GLContextMode>(settings.contextMode())),
*this);
connect(frontend.get(), SIGNAL(updated()), this, SLOT(invalidate()));

mapObj = std::make_unique<mbgl::Map>(
*frontend,
*this, sanitizedSize(size),
Expand All @@ -1528,18 +1528,18 @@ QMapboxGLPrivate::~QMapboxGLPrivate()
{
}

mbgl::Size QMapboxGLPrivate::framebufferSize() const {
mbgl::Size QMapboxGLPrivate::getFramebufferSize() const {
return sanitizedSize(fbSize);
}

void QMapboxGLPrivate::updateAssumedState() {
assumeFramebufferBinding(fbObject);
assumeViewport(0, 0, framebufferSize());
assumeViewport(0, 0, getFramebufferSize());
}

void QMapboxGLPrivate::bind() {
setFramebufferBinding(fbObject);
setViewport(0, 0, framebufferSize());
setViewport(0, 0, getFramebufferSize());
}

void QMapboxGLPrivate::invalidate()
Expand Down
2 changes: 1 addition & 1 deletion platform/qt/src/qmapboxgl_p.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class QMapboxGLPrivate : public QObject, public mbgl::RendererBackend, public mb
explicit QMapboxGLPrivate(QMapboxGL *, const QMapboxGLSettings &, const QSize &size, qreal pixelRatio);
virtual ~QMapboxGLPrivate();

mbgl::Size framebufferSize() const;

// mbgl::RendererBackend implementation.
void bind() final;
mbgl::Size getFramebufferSize() const final;
void updateAssumedState() final;
void activate() final {}
void deactivate() final {}
Expand Down
3 changes: 3 additions & 0 deletions src/mbgl/gl/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,9 @@ Framebuffer Context::createFramebuffer(const Texture& color) {
Framebuffer
Context::createFramebuffer(const Texture& color,
const Renderbuffer<RenderbufferType::DepthComponent>& depthTarget) {
if (color.size != depthTarget.size) {
throw std::runtime_error("Renderbuffer size mismatch");
}
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color.texture, 0));
Expand Down
16 changes: 15 additions & 1 deletion src/mbgl/gl/renderbuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,23 @@ namespace gl {
template <RenderbufferType renderbufferType>
class Renderbuffer {
public:
Renderbuffer(Size size_, UniqueRenderbuffer renderbuffer_, bool dirty_ = false)
: size(std::move(size_)), renderbuffer(std::move(renderbuffer_)), dirty(dirty_) {
}

using type = std::integral_constant<RenderbufferType, renderbufferType>;
Size size;
gl::UniqueRenderbuffer renderbuffer;
UniqueRenderbuffer renderbuffer;

void shouldClear(bool clear) {
dirty = clear;
}
bool needsClearing() {
return dirty;
}

private:
bool dirty;
};

} // namespace gl
Expand Down
194 changes: 91 additions & 103 deletions src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters
void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
evaluated = unevaluated.evaluate(parameters);

passes = (evaluated.get<style::FillExtrusionOpacity>() > 0) ? RenderPass::Translucent
: RenderPass::None;
passes = (evaluated.get<style::FillExtrusionOpacity>() > 0)
? (RenderPass::Translucent | RenderPass::Pass3D)
: RenderPass::None;
}

bool RenderFillExtrusionLayer::hasTransition() const {
Expand All @@ -50,113 +51,100 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
return;
}

const auto size = parameters.context.viewport.getCurrentValue().size;
if (parameters.pass == RenderPass::Pass3D) {
const auto& size = parameters.staticData.backendSize;

if (!parameters.staticData.extrusionTexture || parameters.staticData.extrusionTexture->getSize() != size) {
parameters.staticData.extrusionTexture = OffscreenTexture(parameters.context, size, OffscreenTextureAttachment::Depth);
}

parameters.staticData.extrusionTexture->bind();

parameters.context.setStencilMode(gl::StencilMode::disabled());
parameters.context.setDepthMode(parameters.depthModeForSublayer(0, gl::DepthMode::ReadWrite));
parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, {});

if (evaluated.get<FillExtrusionPattern>().from.empty()) {
for (const RenderTile& tile : renderTiles) {
assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
FillExtrusionBucket& bucket = *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));

parameters.programs.fillExtrusion.get(evaluated).draw(
parameters.context,
gl::Triangles(),
parameters.depthModeForSublayer(0, gl::DepthMode::ReadWrite),
gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
FillExtrusionUniforms::values(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
parameters.state,
parameters.evaluatedLight
),
*bucket.vertexBuffer,
*bucket.indexBuffer,
bucket.triangleSegments,
bucket.paintPropertyBinders.at(getID()),
evaluated,
parameters.state.getZoom(),
getID());
if (!renderTexture || renderTexture->getSize() != size) {
renderTexture = OffscreenTexture(parameters.context, size, *parameters.staticData.depthRenderbuffer);
}
} else {
optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().from);
optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().to);

if (!imagePosA || !imagePosB) {
return;
renderTexture->bind();

optional<float> depthClearValue = {};
if (parameters.staticData.depthRenderbuffer->needsClearing()) depthClearValue = 1.0;
// Flag the depth buffer as no longer needing to be cleared for the remainder of this pass.
parameters.staticData.depthRenderbuffer->shouldClear(false);

parameters.context.setStencilMode(gl::StencilMode::disabled());
parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {});

if (evaluated.get<FillExtrusionPattern>().from.empty()) {
for (const RenderTile& tile : renderTiles) {
assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
FillExtrusionBucket& bucket =
*reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));

parameters.programs.fillExtrusion.get(evaluated).draw(
parameters.context, gl::Triangles(),
parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
FillExtrusionUniforms::values(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
parameters.state, parameters.evaluatedLight),
*bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
getID());
}
} else {
optional<ImagePosition> imagePosA =
parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().from);
optional<ImagePosition> imagePosB =
parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().to);

if (!imagePosA || !imagePosB) {
return;
}

parameters.imageManager.bind(parameters.context, 0);

for (const RenderTile& tile : renderTiles) {
assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
FillExtrusionBucket& bucket =
*reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));

parameters.programs.fillExtrusionPattern.get(evaluated).draw(
parameters.context, gl::Triangles(),
parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
FillExtrusionPatternUniforms::values(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB,
evaluated.get<FillExtrusionPattern>(), tile.id, parameters.state,
-std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
parameters.evaluatedLight),
*bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
getID());
}
}

parameters.imageManager.bind(parameters.context, 0);

for (const RenderTile& tile : renderTiles) {
assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
FillExtrusionBucket& bucket = *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));

parameters.programs.fillExtrusionPattern.get(evaluated).draw(
parameters.context,
gl::Triangles(),
parameters.depthModeForSublayer(0, gl::DepthMode::ReadWrite),
gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
FillExtrusionPatternUniforms::values(
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
parameters.imageManager.getPixelSize(),
*imagePosA,
*imagePosB,
evaluated.get<FillExtrusionPattern>(),
tile.id,
parameters.state,
-std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
parameters.evaluatedLight
),
*bucket.vertexBuffer,
*bucket.indexBuffer,
bucket.triangleSegments,
bucket.paintPropertyBinders.at(getID()),
evaluated,
parameters.state.getZoom(),
getID());
}
}
} else if (parameters.pass == RenderPass::Translucent) {
parameters.context.bindTexture(renderTexture->getTexture());

parameters.backend.bind();
parameters.context.bindTexture(parameters.staticData.extrusionTexture->getTexture());

mat4 viewportMat;
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);

const Properties<>::PossiblyEvaluated properties;

parameters.programs.extrusionTexture.draw(
parameters.context,
gl::Triangles(),
gl::DepthMode::disabled(),
gl::StencilMode::disabled(),
parameters.colorModeForRenderPass(),
ExtrusionTextureProgram::UniformValues{
uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
uniforms::u_image::Value{ 0 },
uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() }
},
parameters.staticData.extrusionTextureVertexBuffer,
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.extrusionTextureSegments,
ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 },
properties,
parameters.state.getZoom(),
getID());
const auto& size = parameters.staticData.backendSize;

mat4 viewportMat;
matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);

const Properties<>::PossiblyEvaluated properties;

parameters.programs.extrusionTexture.draw(
parameters.context, gl::Triangles(), gl::DepthMode::disabled(),
gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
ExtrusionTextureProgram::UniformValues{
uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
uniforms::u_image::Value{ 0 },
uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } },
parameters.staticData.extrusionTextureVertexBuffer,
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.extrusionTextureSegments,
ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties,
parameters.state.getZoom(), getID());
}
}

bool RenderFillExtrusionLayer::queryIntersectsFeature(
Expand Down
Loading

0 comments on commit a9ddf5b

Please sign in to comment.