Drawable LayerGroup sorting, depth buffer, split view (#1173)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
mwilsnd
2023-05-25 15:32:21 -05:00
committed by Bart Louwers
parent 1c8304a609
commit f63fa49152
17 changed files with 244 additions and 89 deletions

View File

@@ -9,6 +9,7 @@
namespace mbgl {
class ChangeRequest;
class LayerGroup;
class TileLayerGroup;
class RenderOrchestrator;
using ChangeRequestPtr = std::shared_ptr<ChangeRequest>;
@@ -76,4 +77,16 @@ protected:
int32_t layerIndex;
};
class UpdateLayerGroupIndexRequest : public ChangeRequest {
public:
UpdateLayerGroupIndexRequest(std::shared_ptr<TileLayerGroup> tileLayerGroup_, int32_t newLayerIndex_);
UpdateLayerGroupIndexRequest(const UpdateLayerGroupIndexRequest &) = delete;
void execute(RenderOrchestrator &) override;
protected:
std::shared_ptr<TileLayerGroup> tileLayerGroup;
int32_t newLayerIndex;
};
} // namespace mbgl

View File

@@ -76,6 +76,7 @@ public:
TileLayerGroup(int32_t layerIndex, std::size_t initialCapacity);
~TileLayerGroup() override;
void updateLayerIndex(int32_t newLayerIndex);
std::size_t getDrawableCount() const;
const gfx::UniqueDrawable& getDrawable(mbgl::RenderPass, const OverscaledTileID&) const;

View File

@@ -54,10 +54,6 @@ void TileLayerGroupGL::upload(gfx::Context& context, gfx::UploadPass& uploadPass
void TileLayerGroupGL::render(RenderOrchestrator&, PaintParameters& parameters) {
auto& context = parameters.context;
// TODO: figure out how to make drawables participate in the depth system
// Maybe make it a function mapping draw priority to the depth range (always (0,1)?)
parameters.depthRangeSize = 1 - (1 + 2) * parameters.numSublayers * parameters.depthEpsilon;
// TODO: Render tile masks
// for (auto& layer : renderLayers) {
// parameters.renderTileClippingMasks(renderTiles);

View File

@@ -18,4 +18,16 @@ void RemoveLayerGroupRequest::execute(RenderOrchestrator &orchestrator) {
orchestrator.removeLayerGroup(layerIndex);
}
UpdateLayerGroupIndexRequest::UpdateLayerGroupIndexRequest(std::shared_ptr<TileLayerGroup> tileLayerGroup_,
int32_t newLayerIndex_)
: tileLayerGroup(std::move(tileLayerGroup_)),
newLayerIndex(newLayerIndex_) {}
void UpdateLayerGroupIndexRequest::execute(RenderOrchestrator &orchestrator) {
// Update the index of a tile layer group and indicate to the orchestator that it must rebuild the map of ordered
// layer groups
tileLayerGroup->updateLayerIndex(newLayerIndex);
orchestrator.markLayerGroupOrderDirty();
}
} // namespace mbgl

View File

@@ -38,6 +38,13 @@ TileLayerGroup::TileLayerGroup(int32_t layerIndex_, std::size_t initialCapacity)
TileLayerGroup::~TileLayerGroup() {}
void TileLayerGroup::updateLayerIndex(int32_t newLayerIndex) {
layerIndex = newLayerIndex;
for (auto& it : impl->tileDrawables) {
it.second->setLayerIndex(newLayerIndex);
}
}
std::size_t TileLayerGroup::getDrawableCount() const {
return impl->tileDrawables.size();
}

View File

@@ -75,16 +75,10 @@ bool RenderBackgroundLayer::hasCrossfade() const {
return getCrossfade<BackgroundLayerProperties>(evaluatedProperties).t != 1;
}
static bool enableDefaultRender = false;
void RenderBackgroundLayer::render(PaintParameters& parameters) {
// Note that for bottommost layers without a pattern, the background color
// is drawn with glClear rather than this method.
if (!enableDefaultRender) {
return;
}
// Ensure programs are available
if (!parameters.shaders.populate(backgroundProgram)) return;
if (!parameters.shaders.populate(backgroundPatternProgram)) return;
@@ -181,8 +175,7 @@ std::optional<Color> RenderBackgroundLayer::getSolidBackground() const {
return std::nullopt;
}
return std::nullopt;
// return { evaluated.get<BackgroundColor>() * evaluated.get<BackgroundOpacity>() };
return {evaluated.get<BackgroundColor>() * evaluated.get<BackgroundOpacity>()};
}
namespace {
@@ -213,15 +206,11 @@ void RenderBackgroundLayer::layerRemoved(UniqueChangeRequestVec& changes) {
}
}
void RenderBackgroundLayer::update(const int32_t layerIndex,
gfx::ShaderRegistry& shaders,
void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& state,
UniqueChangeRequestVec& changes) {
if (enableDefaultRender) {
return;
}
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
if (!shader) {
@@ -271,7 +260,6 @@ void RenderBackgroundLayer::update(const int32_t layerIndex,
return;
}
tileLayerGroup->setLayerTweaker(std::make_shared<BackgroundLayerTweaker>(evaluatedProperties));
changes.emplace_back(std::make_unique<AddLayerGroupRequest>(tileLayerGroup, /*canReplace=*/true));
}
// Drawables per overscaled or canonical tile?

View File

@@ -26,10 +26,10 @@ public:
void layerRemoved(UniqueChangeRequestVec&) override;
/// Generate any changes needed by the layer
void update(int32_t layerIndex,
gfx::ShaderRegistry&,
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const RenderTree&,
UniqueChangeRequestVec&) override;
private:

View File

@@ -85,15 +85,9 @@ bool RenderCircleLayer::hasCrossfade() const {
return false;
}
static bool enableDefaultRender = false;
void RenderCircleLayer::render(PaintParameters& parameters) {
assert(renderTiles);
if (!enableDefaultRender) {
return;
}
if (parameters.pass == RenderPass::Opaque) {
return;
}
@@ -261,15 +255,11 @@ void RenderCircleLayer::removeTile(RenderPass renderPass, const OverscaledTileID
stats.tileDrawablesRemoved += tileLayerGroup->removeDrawables(renderPass, tileID).size();
}
void RenderCircleLayer::update(const int32_t layerIndex,
gfx::ShaderRegistry& shaders,
void RenderCircleLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& /*state*/,
[[maybe_unused]] const RenderTree& renderTree,
UniqueChangeRequestVec& changes) {
if (enableDefaultRender) {
return;
}
std::unique_lock<std::mutex> guard(mutex);
if (!renderTiles || renderTiles->empty()) {

View File

@@ -16,10 +16,10 @@ public:
void layerRemoved(UniqueChangeRequestVec&) override;
/// Generate any changes needed by the layer
void update(int32_t layerIndex,
gfx::ShaderRegistry&,
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const RenderTree&,
UniqueChangeRequestVec&) override;
private:

View File

@@ -78,15 +78,9 @@ bool RenderFillLayer::hasCrossfade() const {
return getCrossfade<FillLayerProperties>(evaluatedProperties).t != 1;
}
static bool enableDefaultRender = false;
void RenderFillLayer::render(PaintParameters& parameters) {
assert(renderTiles);
if (!enableDefaultRender) {
return;
}
if (!parameters.shaders.populate(fillProgram)) return;
if (!parameters.shaders.populate(fillPatternProgram)) return;
if (!parameters.shaders.populate(fillOutlineProgram)) return;
@@ -284,15 +278,11 @@ void RenderFillLayer::removeTile(RenderPass renderPass, const OverscaledTileID&
stats.tileDrawablesRemoved += tileLayerGroup->removeDrawables(renderPass, tileID).size();
}
void RenderFillLayer::update(const int32_t layerIndex,
gfx::ShaderRegistry& shaders,
void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState& /*state*/,
UniqueChangeRequestVec& changes) {
if (enableDefaultRender) {
return;
}
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
if (!renderTiles || renderTiles->empty()) {
@@ -310,7 +300,6 @@ void RenderFillLayer::update(const int32_t layerIndex,
return;
}
tileLayerGroup->setLayerTweaker(std::make_shared<FillLayerTweaker>(evaluatedProperties));
changes.emplace_back(std::make_unique<AddLayerGroupRequest>(tileLayerGroup, /*canReplace=*/true));
}
if (!fillShader) {

View File

@@ -25,10 +25,10 @@ public:
void layerRemoved(UniqueChangeRequestVec&) override;
/// Generate any changes needed by the layer
void update(int32_t layerIndex,
gfx::ShaderRegistry&,
void update(gfx::ShaderRegistry&,
gfx::Context&,
const TransformState&,
const RenderTree&,
UniqueChangeRequestVec&) override;
private:

View File

@@ -1,5 +1,6 @@
#include <mbgl/renderer/change_request.hpp>
#include <mbgl/renderer/render_layer.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
@@ -31,6 +32,10 @@ const std::string& RenderLayer::getID() const {
return baseImpl->id;
}
int32_t RenderLayer::getLayerIndex() const noexcept {
return layerIndex;
}
bool RenderLayer::hasRenderPass(RenderPass pass) const {
return passes & pass;
}
@@ -107,4 +112,32 @@ const LayerRenderData* RenderLayer::getRenderDataForPass(const RenderTile& tile,
return nullptr;
}
void RenderLayer::layerIndexChanged(int32_t newLayerIndex, UniqueChangeRequestVec& changes) {
layerIndex = newLayerIndex;
// Submit a change request to update the layer index of our tile layer group
if (tileLayerGroup) {
changes.emplace_back(std::make_unique<UpdateLayerGroupIndexRequest>(tileLayerGroup, newLayerIndex));
}
}
void RenderLayer::markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes) {
if (!tileLayerGroup) {
return;
}
if (isRenderable == willRender) {
return;
}
// This layer is either being freshly included in the renderable set or excluded
isRenderable = willRender;
if (willRender) {
// The RenderTree has determined this layer should be included in the renderable set for a frame
changes.emplace_back(std::make_unique<AddLayerGroupRequest>(tileLayerGroup, /*canReplace=*/true));
} else {
// The RenderTree is informing us we should not render anything
changes.emplace_back(std::make_unique<RemoveLayerGroupRequest>(tileLayerGroup->getLayerIndex()));
}
}
} // namespace mbgl

View File

@@ -21,6 +21,7 @@ class PropertyEvaluationParameters;
class PaintParameters;
class PatternAtlas;
class RenderTile;
class RenderTree;
class SymbolBucket;
class TileLayerGroup;
class TransformState;
@@ -101,6 +102,8 @@ public:
const std::string& getID() const;
int32_t getLayerIndex() const noexcept;
// Checks whether this layer needs to be rendered in the given render pass.
bool hasRenderPass(RenderPass) const;
@@ -143,10 +146,22 @@ public:
/// Generate any changes needed by the layer
virtual void update(
int32_t /*layerIndex*/, gfx::ShaderRegistry&, gfx::Context&, const TransformState&, UniqueChangeRequestVec&) {}
gfx::ShaderRegistry&, gfx::Context&, const TransformState&, const RenderTree&, UniqueChangeRequestVec&) {}
virtual void layerRemoved(UniqueChangeRequestVec&) {}
/// @brief Called by the RenderOrchestrator during RenderTree construction.
/// This event is run when a layer is added or removed from the style.
/// @param newLayerIndex The new layer index for this layer
/// @param changes The collection of current pending change requests
virtual void layerIndexChanged(int32_t newLayerIndex, UniqueChangeRequestVec& changes);
/// @brief Called by the RenderOrchestrator during RenderTree construction.
/// This event is run to indicate if the layer should render or not for the current frame.
/// @param willRender Indicates if this layer should render or not
/// @param changes The collection of current pending change requests
virtual void markLayerRenderable(bool willRender, UniqueChangeRequestVec& changes);
protected:
// Checks whether the current hardware can render this layer. If it can't,
// we'll show a warning in the console to inform the developer.
@@ -167,6 +182,10 @@ protected:
LayerPlacementData placementData;
TileLayerGroupPtr tileLayerGroup;
// Current layer index as specified by the layerIndexChanged event
int32_t layerIndex{0};
// Current renderable status as specified by the markLayerRenderable event
bool isRenderable{false};
std::mutex mutex;

View File

@@ -233,8 +233,6 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
}
}
addChanges(changes);
// Create render layers for newly added layers.
for (const auto& entry : layerDiff.added) {
auto renderLayer = LayerManager::get()->createRenderLayer(entry.second);
@@ -250,10 +248,14 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
if (layersAddedOrRemoved) {
orderedLayers.clear();
orderedLayers.reserve(layerImpls->size());
int32_t layerIndex = 0;
for (const auto& layerImpl : *layerImpls) {
RenderLayer* layer = renderLayers.at(layerImpl->id).get();
assert(layer);
orderedLayers.emplace_back(*layer);
// We're mutating the list of ordered layers and must notify them of their new assigned indices
layer->layerIndexChanged(layerIndex++, changes);
}
}
assert(orderedLayers.size() == renderLayers.size());
@@ -336,6 +338,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
}
}
}
continue;
}
@@ -357,6 +360,18 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
filteredLayersForSource.clear();
}
// Mark layers included in the renderable set as renderable
// @TODO: Optimize this logic, combine with the above
for (size_t i = 0; i < orderedLayers.size(); ++i) {
RenderLayer& layer = orderedLayers[i];
layer.markLayerRenderable(
layerRenderItems.find(LayerRenderItem(layer, nullptr, static_cast<uint32_t>(i))) != layerRenderItems.end(),
changes);
}
// Add all change requests up to this point
addChanges(changes);
renderTreeParameters->loaded = updateParameters->styleLoaded && isLoaded();
if (!isMapModeContinuous && !renderTreeParameters->loaded) {
return nullptr;
@@ -778,6 +793,16 @@ const gfx::DrawablePtr& RenderOrchestrator::getDrawable(const util::SimpleIdenti
void RenderOrchestrator::onRemoveLayerGroup(LayerGroup&) {}
void RenderOrchestrator::updateLayerGroupOrder() {
// In the event layer indices change for layer groups, we must re-sort them
LayerGroupMap newMap;
for (auto& it : layerGroupsByLayerIndex) {
newMap.emplace(it.second->getLayerIndex(), it.second);
}
layerGroupsByLayerIndex = std::move(newMap);
layerGroupOrderDirty = false;
}
bool RenderOrchestrator::addLayerGroup(LayerGroupPtr layerGroup, const bool replace) {
const auto index = layerGroup->getLayerIndex();
const auto result = layerGroupsByLayerIndex.insert(std::make_pair(index, LayerGroupPtr{}));
@@ -808,6 +833,10 @@ bool RenderOrchestrator::removeLayerGroup(const int32_t layerIndex) {
}
}
size_t RenderOrchestrator::numLayerGroups() const noexcept {
return layerGroupsByLayerIndex.size();
}
static const LayerGroupPtr no_group;
const LayerGroupPtr& RenderOrchestrator::getLayerGroup(const int32_t layerIndex) const {
@@ -847,15 +876,9 @@ void RenderOrchestrator::updateLayers(gfx::ShaderRegistry& shaders,
};
std::vector<std::unique_ptr<ChangeRequest>> changes;
// Layer index, similar but not identical to `layerRenderItems` index in render_impl
// int32_t i = static_cast<int32_t>(layerRenderItems.size()) - 1;
// for (auto it = layerRenderItems.begin(); it != layerRenderItems.end() && i >= 0; ++it, --i) {
auto index = static_cast<int32_t>(renderTree.getLayerRenderItems().size()) - 1;
for (const auto& item : renderTree.getLayerRenderItems()) {
auto& renderLayer = static_cast<const LayerRenderItem&>(item.get()).layer.get();
renderLayer.update(index--, shaders, context, state, changes);
renderLayer.update(shaders, context, state, renderTree, changes);
}
addChanges(changes);
@@ -866,6 +889,14 @@ void RenderOrchestrator::processChanges() {
for (auto& change : localChanges) {
change->execute(*this);
}
if (layerGroupOrderDirty) {
updateLayerGroupOrder();
}
}
void RenderOrchestrator::markLayerGroupOrderDirty() {
layerGroupOrderDirty = true;
}
void RenderOrchestrator::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {

View File

@@ -105,6 +105,7 @@ public:
bool addLayerGroup(LayerGroupPtr, bool replace);
bool removeLayerGroup(const int32_t layerIndex);
size_t numLayerGroups() const noexcept;
const LayerGroupPtr& getLayerGroup(const int32_t layerIndex) const;
void observeLayerGroups(std::function<void(LayerGroup&)>);
void observeLayerGroups(std::function<void(const LayerGroup&)>) const;
@@ -116,6 +117,8 @@ public:
const RenderTree&);
void processChanges();
/// @brief Indicate that the orchestrator needs to re-sort layer groups when processing changes
void markLayerGroupOrderDirty();
const ZoomHistory& getZoomHistory() const { return zoomHistory; }
@@ -153,6 +156,8 @@ private:
void onRemoveLayerGroup(LayerGroup&);
void updateLayerGroupOrder();
RendererObserver* observer;
ZoomHistory zoomHistory;
@@ -189,6 +194,7 @@ private:
using LayerGroupMap = std::map<int32_t, LayerGroupPtr>;
LayerGroupMap layerGroupsByLayerIndex;
bool layerGroupOrderDirty = false;
};
} // namespace mbgl

View File

@@ -21,6 +21,16 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/logging.hpp>
// DEBUG: Enable a debugging split view to compare drawables and vanilla rendering pathways
// Drawables will be on the left, vanilla rendering on the right
// #define SPLIT_VIEW
// If using SPLIT_VIEW, QUAD_SPLIT_VIEW will split each half, showing just the opaque
// pass on top and then a composited opaque+translucent pass on the bottom
// #define QUAD_SPLIT_VIEW
#ifdef SPLIT_VIEW
#include <mbgl/gl/context.hpp>
#endif
namespace mbgl {
using namespace style;
@@ -184,25 +194,45 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
"main buffer", {parameters.backend.getDefaultRenderable(), color, 1.0f, 0});
}
{
// Actually render the layers
// Drawables
const auto drawableOpaquePass = [&] {
const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-opaque"));
parameters.pass = RenderPass::Opaque;
parameters.currentLayer = 0;
parameters.opaquePassCutoff = 1;
parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * parameters.numSublayers *
parameters.depthEpsilon;
// draw layer groups, opaque pass
const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-opaque"));
orchestrator.observeLayerGroups([&](LayerGroup& layerGroup) {
layerGroup.render(orchestrator, parameters);
parameters.currentLayer++;
});
};
orchestrator.observeLayerGroups([&](LayerGroup& layerGroup) { layerGroup.render(orchestrator, parameters); });
}
const auto drawableTranslucentPass = [&] {
const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-translucent"));
parameters.pass = RenderPass::Translucent;
parameters.currentLayer = static_cast<int32_t>(orchestrator.numLayerGroups()) - 1;
parameters.depthRangeSize = 1 - (orchestrator.numLayerGroups() + 2) * parameters.numSublayers *
parameters.depthEpsilon;
// Actually render the layers
parameters.opaquePassCutoff = renderTreeParameters.opaquePassCutOff;
parameters.depthRangeSize = 1 - (layerRenderItems.size() + 2) * parameters.numSublayers * parameters.depthEpsilon;
// draw layer groups, translucent pass
orchestrator.observeLayerGroups([&](LayerGroup& layerGroup) {
layerGroup.render(orchestrator, parameters);
if (parameters.currentLayer != 0) {
parameters.currentLayer--;
}
});
};
// - OPAQUE PASS -------------------------------------------------------------------------------
// Render everything top-to-bottom by using reverse iterators. Render opaque objects first.
{
const auto renderLayerOpaquePass = [&] {
const auto debugGroup(parameters.renderPass->createDebugGroup("opaque"));
parameters.pass = RenderPass::Opaque;
parameters.depthRangeSize = 1 -
(layerRenderItems.size() + 2) * parameters.numSublayers * parameters.depthEpsilon;
uint32_t i = 0;
for (auto it = layerRenderItems.rbegin(); it != layerRenderItems.rend(); ++it, ++i) {
@@ -213,25 +243,14 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
renderItem.render(parameters);
}
}
}
};
{
parameters.pass = RenderPass::Translucent;
parameters.currentLayer = 1;
parameters.opaquePassCutoff = 1;
// draw layer groups, translucent pass
const auto debugGroup(parameters.renderPass->createDebugGroup("drawables-translucent"));
orchestrator.observeLayerGroups([&](LayerGroup& layerGroup) { layerGroup.render(orchestrator, parameters); });
parameters.opaquePassCutoff = renderTreeParameters.opaquePassCutOff;
}
// - TRANSLUCENT PASS --------------------------------------------------------------------------
// Make a second pass, rendering translucent objects. This time, we render bottom-to-top.
{
const auto renderLayerTranslucentPass = [&] {
const auto debugGroup(parameters.renderPass->createDebugGroup("translucent"));
parameters.pass = RenderPass::Translucent;
parameters.depthRangeSize = 1 -
(layerRenderItems.size() + 2) * parameters.numSublayers * parameters.depthEpsilon;
int32_t i = static_cast<int32_t>(layerRenderItems.size()) - 1;
for (auto it = layerRenderItems.begin(); it != layerRenderItems.end() && i >= 0; ++it, --i) {
@@ -242,7 +261,57 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
renderItem.render(parameters);
}
}
}
};
#ifdef SPLIT_VIEW
[[maybe_unused]] const auto W = backend.getDefaultRenderable().getSize().width;
[[maybe_unused]] const auto H = backend.getDefaultRenderable().getSize().height;
[[maybe_unused]] const auto halfW = static_cast<platform::GLsizei>(backend.getDefaultRenderable().getSize().width *
0.5f);
[[maybe_unused]] const auto halfH = static_cast<platform::GLsizei>(backend.getDefaultRenderable().getSize().height *
0.5f);
platform::glEnable(GL_SCISSOR_TEST);
#ifdef QUAD_SPLIT_VIEW
// Drawable LayerGroups on the left
// Opaque only on top
platform::glScissor(0, 0, halfW, H);
drawableOpaquePass();
// Composite (Opaque+Translucent) on bottom
platform::glScissor(0, 0, halfW, halfH);
drawableTranslucentPass();
// RenderLayers on the right
// Opaque only on top
platform::glScissor(halfW, 0, halfW, H);
renderLayerOpaquePass();
// Composite (Opaque+Translucent) on bottom
platform::glScissor(halfW, 0, halfW, halfH);
renderLayerTranslucentPass();
#else
// Drawable LayerGroups on the left
platform::glScissor(0, 0, halfW, H);
drawableOpaquePass();
drawableTranslucentPass();
// RenderLayers on the right
platform::glScissor(halfW, 0, W, H);
renderLayerOpaquePass();
renderLayerTranslucentPass();
#endif
// Reset viewport
platform::glScissor(0, 0, W, H);
platform::glDisable(GL_SCISSOR_TEST);
#else // ifdef SPLIT_VIEW
// Do RenderLayers first, drawables last
renderLayerOpaquePass();
drawableOpaquePass();
renderLayerTranslucentPass();
drawableTranslucentPass();
#endif
// - DEBUG PASS --------------------------------------------------------------------------------
// Renders debug overlays.

1
vendor/mapbox-gl-native-curl vendored Submodule

Submodule vendor/mapbox-gl-native-curl added at 674a741b1b