summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauren Budorick <lauren@mapbox.com>2017-09-21 14:26:48 -0700
committerGitHub <noreply@github.com>2017-09-21 14:26:48 -0700
commita9ddf5b7fd311ffb9215a682ab2387181189071e (patch)
tree50e31aa30c8f58e6a82e6ff6dc2f5896ea963889
parentb91d9676a60204f2c9ee8803dec243d49f97e599 (diff)
downloadqtlocation-mapboxgl-a9ddf5b7fd311ffb9215a682ab2387181189071e.tar.gz
Preserve depth buffer between 3D layers + optimize render order (#9931)
Port of https://github.com/mapbox/mapbox-gl-js/pull/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.
-rw-r--r--include/mbgl/renderer/renderer_backend.hpp2
-rwxr-xr-xplatform/android/src/native_map_view.cpp8
-rwxr-xr-xplatform/android/src/native_map_view.hpp5
-rw-r--r--platform/default/mbgl/gl/headless_backend.cpp4
-rw-r--r--platform/default/mbgl/gl/headless_backend.hpp1
-rw-r--r--platform/glfw/glfw_view.hpp2
-rw-r--r--platform/ios/src/MGLMapView.mm4
-rw-r--r--platform/macos/src/MGLMapView.mm4
-rw-r--r--platform/node/test/ignores.json1
-rw-r--r--platform/qt/src/qmapboxgl.cpp8
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp2
-rw-r--r--src/mbgl/gl/context.cpp3
-rw-r--r--src/mbgl/gl/renderbuffer.hpp16
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp194
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp4
-rw-r--r--src/mbgl/renderer/paint_parameters.cpp4
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp1
-rw-r--r--src/mbgl/renderer/render_pass.hpp1
-rw-r--r--src/mbgl/renderer/render_static_data.hpp5
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp47
-rw-r--r--src/mbgl/util/offscreen_texture.cpp30
-rw-r--r--src/mbgl/util/offscreen_texture.hpp11
-rw-r--r--test/renderer/backend_scope.test.cpp12
23 files changed, 219 insertions, 150 deletions
diff --git a/include/mbgl/renderer/renderer_backend.hpp b/include/mbgl/renderer/renderer_backend.hpp
index f7d19a1791..295838c71b 100644
--- a/include/mbgl/renderer/renderer_backend.hpp
+++ b/include/mbgl/renderer/renderer_backend.hpp
@@ -35,6 +35,8 @@ public:
// 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,
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index d859d929d3..fb00cec1e2 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -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.
*/
@@ -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());
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index 24c88f4e3f..bfd928d347 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -58,6 +58,9 @@ public:
// mbgl::RendererBackend //
void bind() override;
+
+ mbgl::Size getFramebufferSize() const override;
+
void updateAssumedState() override;
// Deprecated //
@@ -282,8 +285,6 @@ private:
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
- mbgl::Size getFramebufferSize() const;
-
void updateFps();
private:
diff --git a/platform/default/mbgl/gl/headless_backend.cpp b/platform/default/mbgl/gl/headless_backend.cpp
index fe77b80985..edf637a560 100644
--- a/platform/default/mbgl/gl/headless_backend.cpp
+++ b/platform/default/mbgl/gl/headless_backend.cpp
@@ -64,6 +64,10 @@ void HeadlessBackend::bind() {
context_.viewport = { 0, 0, size };
}
+Size HeadlessBackend::getFramebufferSize() const {
+ return size;
+}
+
void HeadlessBackend::updateAssumedState() {
// no-op
}
diff --git a/platform/default/mbgl/gl/headless_backend.hpp b/platform/default/mbgl/gl/headless_backend.hpp
index 8d86ea8c47..66f861e213 100644
--- a/platform/default/mbgl/gl/headless_backend.hpp
+++ b/platform/default/mbgl/gl/headless_backend.hpp
@@ -15,6 +15,7 @@ public:
~HeadlessBackend() override;
void bind() override;
+ Size getFramebufferSize() const override;
void updateAssumedState() override;
void setSize(Size);
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index ccde4f027f..42d287142d 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -37,7 +37,7 @@ public:
void invalidate();
mbgl::Size getSize() const;
- mbgl::Size getFramebufferSize() const;
+ mbgl::Size getFramebufferSize() const override;
// mbgl::RendererBackend implementation
void bind() override;
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index d9d03ea478..49ef2bfb81 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -5464,6 +5464,10 @@ public:
}
}
+ 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];
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 5dbb134ef5..eb4099f330 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -2883,6 +2883,10 @@ public:
setViewport(0, 0, nativeView.framebufferSize);
}
+ mbgl::Size getFramebufferSize() const override {
+ return nativeView.framebufferSize;
+ }
+
mbgl::PremultipliedImage readStillImage() {
return readFramebuffer(nativeView.framebufferSize);
}
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index 50e1defa85..1084a5c923 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -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",
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index c7c4cf1e4a..e79c6af56a 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -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),
@@ -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()
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index 7b0dd8c192..eb86870c10 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -20,10 +20,10 @@ public:
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 {}
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 49bfe30e91..b8a0502178 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -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));
diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp
index cc8ff13268..0592557a7f 100644
--- a/src/mbgl/gl/renderbuffer.hpp
+++ b/src/mbgl/gl/renderbuffer.hpp
@@ -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
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index 6295f62b21..fbd6160e8a 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -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 {
@@ -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(
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
index a53e00ca6f..838494cf91 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
@@ -3,6 +3,8 @@
#include <mbgl/renderer/render_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/offscreen_texture.hpp>
namespace mbgl {
@@ -30,6 +32,8 @@ public:
style::FillExtrusionPaintProperties::PossiblyEvaluated evaluated;
const style::FillExtrusionLayer::Impl& impl() const;
+
+ optional<OffscreenTexture> renderTexture;
};
template <>
diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp
index 584dcdf118..299db844bc 100644
--- a/src/mbgl/renderer/paint_parameters.cpp
+++ b/src/mbgl/renderer/paint_parameters.cpp
@@ -62,6 +62,10 @@ gl::DepthMode PaintParameters::depthModeForSublayer(uint8_t n, gl::DepthMode::Ma
return gl::DepthMode { gl::DepthMode::LessEqual, mask, { nearDepth, farDepth } };
}
+gl::DepthMode PaintParameters::depthModeFor3D(gl::DepthMode::Mask mask) const {
+ return gl::DepthMode { gl::DepthMode::LessEqual, mask, { 0.0, 1.0 } };
+}
+
gl::StencilMode PaintParameters::stencilModeForClipping(const ClipID& id) const {
return gl::StencilMode {
gl::StencilMode::Equal { static_cast<uint32_t>(id.mask.to_ulong()) },
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
index eb1ad73ad5..4a2c2c6f12 100644
--- a/src/mbgl/renderer/paint_parameters.hpp
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -60,6 +60,7 @@ public:
Programs& programs;
gl::DepthMode depthModeForSublayer(uint8_t n, gl::DepthMode::Mask) const;
+ gl::DepthMode depthModeFor3D(gl::DepthMode::Mask) const;
gl::StencilMode stencilModeForClipping(const ClipID&) const;
gl::ColorMode colorModeForRenderPass() const;
diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp
index ae2b923ba1..5d18304129 100644
--- a/src/mbgl/renderer/render_pass.hpp
+++ b/src/mbgl/renderer/render_pass.hpp
@@ -11,6 +11,7 @@ enum class RenderPass : uint8_t {
None = 0,
Opaque = 1 << 0,
Translucent = 1 << 1,
+ Pass3D = 1 << 2,
};
MBGL_CONSTEXPR RenderPass operator|(RenderPass a, RenderPass b) {
diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp
index 07a47b4c8f..cf58c31f4d 100644
--- a/src/mbgl/renderer/render_static_data.hpp
+++ b/src/mbgl/renderer/render_static_data.hpp
@@ -4,7 +4,6 @@
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/programs/programs.hpp>
#include <mbgl/util/optional.hpp>
-#include <mbgl/util/offscreen_texture.hpp>
#include <string>
@@ -26,7 +25,9 @@ public:
SegmentVector<RasterAttributes> rasterSegments;
SegmentVector<ExtrusionTextureAttributes> extrusionTextureSegments;
- optional<OffscreenTexture> extrusionTexture;
+ optional<gl::Renderbuffer<gl::RenderbufferType::DepthComponent>> depthRenderbuffer;
+ bool has3D = false;
+ Size backendSize;
Programs programs;
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index a5d23333ac..c45295b693 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -13,6 +13,7 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/renderer/layers/render_background_layer.hpp>
#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
#include <mbgl/renderer/style_diff.hpp>
#include <mbgl/renderer/query.hpp>
#include <mbgl/renderer/backend_scope.hpp>
@@ -276,6 +277,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
RenderLayer* layer = getRenderLayer(layerImpl->id);
assert(layer);
+ if (!parameters.staticData.has3D && layer->is<RenderFillExtrusionLayer>()) {
+ parameters.staticData.has3D = true;
+ }
+
if (!layer->needsRendering(zoomHistory.lastZoom)) {
continue;
}
@@ -372,6 +377,39 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
parameters.imageManager.upload(parameters.context, 0);
parameters.lineAtlas.upload(parameters.context, 0);
parameters.frameHistory.upload(parameters.context, 0);
+
+ // Update all clipping IDs + upload buckets.
+ for (const auto& entry : renderSources) {
+ if (entry.second->isEnabled()) {
+ entry.second->startRender(parameters);
+ }
+ }
+ }
+
+ // - 3D PASS -------------------------------------------------------------------------------------
+ // Renders any 3D layers bottom-to-top to unique FBOs with texture attachments, but share the same
+ // depth rbo between them.
+ if (parameters.staticData.has3D) {
+ parameters.staticData.backendSize = parameters.backend.getFramebufferSize();
+
+ MBGL_DEBUG_GROUP(parameters.context, "3d");
+ parameters.pass = RenderPass::Pass3D;
+
+ if (!parameters.staticData.depthRenderbuffer ||
+ parameters.staticData.depthRenderbuffer->size != parameters.staticData.backendSize) {
+ parameters.staticData.depthRenderbuffer =
+ parameters.context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(parameters.staticData.backendSize);
+ }
+ parameters.staticData.depthRenderbuffer->shouldClear(true);
+
+ uint32_t i = static_cast<uint32_t>(order.size()) - 1;
+ for (auto it = order.begin(); it != order.end(); ++it, --i) {
+ parameters.currentLayer = i;
+ if (it->layer.hasRenderPass(parameters.pass)) {
+ MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
+ it->layer.render(parameters, it->source);
+ }
+ }
}
// - CLEAR -------------------------------------------------------------------------------------
@@ -390,15 +428,6 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
// - CLIPPING MASKS ----------------------------------------------------------------------------
// Draws the clipping masks to the stencil buffer.
{
- MBGL_DEBUG_GROUP(parameters.context, "clip");
-
- // Update all clipping IDs.
- for (const auto& entry : renderSources) {
- if (entry.second->isEnabled()) {
- entry.second->startRender(parameters);
- }
- }
-
MBGL_DEBUG_GROUP(parameters.context, "clipping masks");
static const style::FillPaintProperties::PossiblyEvaluated properties {};
diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp
index d8a68b9a4a..339e74b250 100644
--- a/src/mbgl/util/offscreen_texture.cpp
+++ b/src/mbgl/util/offscreen_texture.cpp
@@ -11,20 +11,22 @@ OffscreenTexture& OffscreenTexture::operator=(OffscreenTexture&&) = default;
class OffscreenTexture::Impl {
public:
- Impl(gl::Context& context_, const Size size_, OffscreenTextureAttachment type_)
- : context(context_), size(std::move(size_)), type(type_) {
+ Impl(gl::Context& context_, const Size size_)
+ : context(context_), size(std::move(size_)) {
+ assert(!size.isEmpty());
+ }
+ Impl(gl::Context& context_,
+ const Size size_,
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& depth_)
+ : context(context_), size(std::move(size_)), depth(&depth_) {
assert(!size.isEmpty());
}
void bind() {
if (!framebuffer) {
texture = context.createTexture(size, gl::TextureFormat::RGBA);
-
- if (type == OffscreenTextureAttachment::Depth) {
- gl::Renderbuffer<gl::RenderbufferType::DepthComponent> depth =
- context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(size);
- framebuffer = context.createFramebuffer(*texture, depth);
-
+ if (depth) {
+ framebuffer = context.createFramebuffer(*texture, *depth);
} else {
framebuffer = context.createFramebuffer(*texture);
}
@@ -53,15 +55,21 @@ public:
private:
gl::Context& context;
const Size size;
- OffscreenTextureAttachment type;
optional<gl::Framebuffer> framebuffer;
optional<gl::Texture> texture;
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>* depth = nullptr;
};
OffscreenTexture::OffscreenTexture(gl::Context& context,
+ const Size size)
+ : impl(std::make_unique<Impl>(context, std::move(size))) {
+ assert(!size.isEmpty());
+}
+
+OffscreenTexture::OffscreenTexture(gl::Context& context,
const Size size,
- OffscreenTextureAttachment type)
- : impl(std::make_unique<Impl>(context, std::move(size), type)) {
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& renderbuffer)
+ : impl(std::make_unique<Impl>(context, std::move(size), renderbuffer)) {
assert(!size.isEmpty());
}
diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp
index 0353f3f9c5..7f7e0f0338 100644
--- a/src/mbgl/util/offscreen_texture.hpp
+++ b/src/mbgl/util/offscreen_texture.hpp
@@ -9,16 +9,13 @@ class Context;
class Texture;
} // namespace gl
-enum class OffscreenTextureAttachment {
- None,
- Depth,
-};
-
class OffscreenTexture {
public:
OffscreenTexture(gl::Context&,
- Size size = { 256, 256 },
- OffscreenTextureAttachment type = OffscreenTextureAttachment::None);
+ Size size = { 256, 256 });
+ OffscreenTexture(gl::Context&,
+ Size size,
+ gl::Renderbuffer<gl::RenderbufferType::DepthComponent>&);
~OffscreenTexture();
OffscreenTexture(OffscreenTexture&&);
OffscreenTexture& operator=(OffscreenTexture&&);
diff --git a/test/renderer/backend_scope.test.cpp b/test/renderer/backend_scope.test.cpp
index 06bf1e7750..66cf88a9c6 100644
--- a/test/renderer/backend_scope.test.cpp
+++ b/test/renderer/backend_scope.test.cpp
@@ -12,6 +12,10 @@ public:
void bind() override {
}
+ mbgl::Size getFramebufferSize() const override {
+ return mbgl::Size{};
+ }
+
void activate() override {
if (activateFunction) activateFunction();
}
@@ -87,15 +91,15 @@ TEST(BackendScope, NestedScopes) {
TEST(BackendScope, ChainedScopes) {
bool activatedA = false;
bool activatedB = false;
-
+
StubRendererBackend backendA;
backendA.activateFunction = [&] { activatedA = true; };
backendA.deactivateFunction = [&] { activatedA = false; };
-
+
StubRendererBackend backendB;
backendB.activateFunction = [&] { activatedB = true; };
backendB.deactivateFunction = [&] { activatedB = false; };
-
+
{
BackendScope scopeA { backendA };
ASSERT_TRUE(activatedA);
@@ -107,7 +111,7 @@ TEST(BackendScope, ChainedScopes) {
ASSERT_FALSE(activatedB);
ASSERT_TRUE(activatedA);
}
-
+
ASSERT_FALSE(activatedA);
ASSERT_FALSE(activatedB);
}