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.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -64,6 +64,10 @@ void HeadlessBackend::bind() {
|
||||
context_.viewport = { 0, 0, size };
|
||||
}
|
||||
|
||||
Size HeadlessBackend::getFramebufferSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
void HeadlessBackend::updateAssumedState() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
~HeadlessBackend() override;
|
||||
|
||||
void bind() override;
|
||||
Size getFramebufferSize() const override;
|
||||
void updateAssumedState() override;
|
||||
|
||||
void setSize(Size);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
if (!renderTexture || renderTexture->getSize() != size) {
|
||||
renderTexture = OffscreenTexture(parameters.context, size, *parameters.staticData.depthRenderbuffer);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
} else if (parameters.pass == RenderPass::Translucent) {
|
||||
parameters.context.bindTexture(renderTexture->getTexture());
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
} 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.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());
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
bool RenderFillExtrusionLayer::queryIntersectsFeature(
|
||||
|
||||
@@ -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 <>
|
||||
|
||||
@@ -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()) },
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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&&);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user