From c81c665538a56bbcf161b8a1e7a3520092e51bb2 Mon Sep 17 00:00:00 2001 From: Tim Sylvester Date: Mon, 22 May 2023 12:23:29 -0700 Subject: [PATCH] Drawable Renderer (#1570), Add fill-outline drawables --- include/mbgl/gfx/drawable.hpp | 10 + include/mbgl/gfx/drawable_builder.hpp | 10 + include/mbgl/renderer/layer_group.hpp | 4 +- src/mbgl/gfx/drawable_builder.cpp | 2 + src/mbgl/gl/drawable_gl.cpp | 2 +- src/mbgl/gl/drawable_gl_impl.hpp | 4 +- src/mbgl/renderer/layer_group.cpp | 30 +-- .../layers/render_background_layer.cpp | 2 +- .../renderer/layers/render_fill_layer.cpp | 193 ++++++++++-------- 9 files changed, 151 insertions(+), 106 deletions(-) diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 5cea68315..c316bc0b0 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -66,6 +66,10 @@ public: return (mbgl::underlying_type(renderPass) & underlying_value) == underlying_value; } + /// Width for lines + int32_t getLineWidth() const { return lineWidth; } + void setLineWidth(int32_t value) { lineWidth = value; } + /// not used for anything yet DrawPriority getDrawPriority() const { return drawPriority; } void setDrawPriority(DrawPriority value) { drawPriority = value; } @@ -74,6 +78,10 @@ public: int32_t getLayerIndex() const { return layerIndex; } void setLayerIndex(int32_t value) { layerIndex = value; } + /// Determines depth range within the layer + int32_t getSubLayerIndex() const { return subLayerIndex; } + void setSubLayerIndex(int32_t value) { subLayerIndex = value; } + std::optional getTileID() const { return tileID; } void setTileID(OverscaledTileID value) { tileID = value; } @@ -129,7 +137,9 @@ protected: mat4 matrix; //= matrix::identity4(); std::optional tileID; DrawPriority drawPriority = 0; + int32_t lineWidth = 1; int32_t layerIndex = -1; + int32_t subLayerIndex = 0; DepthMaskType depthType; // = DepthMaskType::ReadOnly; std::vector tweakers; diff --git a/include/mbgl/gfx/drawable_builder.hpp b/include/mbgl/gfx/drawable_builder.hpp index 6925e839c..79160d45c 100644 --- a/include/mbgl/gfx/drawable_builder.hpp +++ b/include/mbgl/gfx/drawable_builder.hpp @@ -61,6 +61,10 @@ public: int32_t getLayerIndex() const { return layerIndex; } void setLayerIndex(int32_t value) { layerIndex = value; } + /// The layer index assigned to generated drawables + int32_t getSubLayerIndex() const { return subLayerIndex; } + void setSubLayerIndex(int32_t value) { subLayerIndex = value; } + /// Set the draw priority on all drawables including those already generated void resetDrawPriority(DrawPriority); @@ -77,6 +81,10 @@ public: /// This should not be changed while a build is in progress void setColorMode(ColorMode mode) { colorMode = mode; } + /// Width for lines + int32_t getLineWidth() const { return lineWidth; } + void setLineWidth(int32_t value) { lineWidth = value; } + DepthMaskType getDepthType() const { return depthType; } void setDepthType(DepthMaskType value) { depthType = value; } @@ -150,8 +158,10 @@ protected: std::string vertexAttrName; std::string colorAttrName; mbgl::RenderPass renderPass; + int32_t lineWidth = 1; DrawPriority drawPriority = 0; int32_t layerIndex = -1; + int32_t subLayerIndex = 0; DepthMaskType depthType = DepthMaskType::ReadOnly; gfx::ShaderProgramBasePtr shader; mat4 matrix; diff --git a/include/mbgl/renderer/layer_group.hpp b/include/mbgl/renderer/layer_group.hpp index fbc95f55a..e62c560a8 100644 --- a/include/mbgl/renderer/layer_group.hpp +++ b/include/mbgl/renderer/layer_group.hpp @@ -69,8 +69,8 @@ public: std::size_t getDrawableCount() const; const gfx::UniqueDrawable& getDrawable(mbgl::RenderPass, const OverscaledTileID&) const; - gfx::UniqueDrawable removeDrawable(mbgl::RenderPass, const OverscaledTileID&); - bool addDrawable(mbgl::RenderPass, const OverscaledTileID&, gfx::UniqueDrawable&&); + std::vector removeDrawables(mbgl::RenderPass, const OverscaledTileID&); + void addDrawable(mbgl::RenderPass, const OverscaledTileID&, gfx::UniqueDrawable&&); void observeDrawables(std::function) override; void observeDrawables(std::function) const override; diff --git a/src/mbgl/gfx/drawable_builder.cpp b/src/mbgl/gfx/drawable_builder.cpp index 22a78765d..bb3a4b8e3 100644 --- a/src/mbgl/gfx/drawable_builder.cpp +++ b/src/mbgl/gfx/drawable_builder.cpp @@ -33,9 +33,11 @@ const UniqueDrawable& DrawableBuilder::getCurrentDrawable(bool createIfNone) { void DrawableBuilder::flush() { if (!impl->vertices.empty()) { const auto& draw = getCurrentDrawable(/*createIfNone=*/true); + draw->setLineWidth(lineWidth); draw->setRenderPass(renderPass); draw->setDrawPriority(drawPriority); draw->setLayerIndex(layerIndex); + draw->setSubLayerIndex(subLayerIndex); draw->setDepthType(depthType); draw->setShader(shader); draw->setMatrix(matrix); diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index b630d6a94..3cd7c16e3 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -19,7 +19,7 @@ DrawableGL::~DrawableGL() { void DrawableGL::draw(const PaintParameters& parameters) const { bindUniformBuffers(); - impl->draw(parameters); + impl->draw(parameters, lineWidth); unbindUniformBuffers(); } diff --git a/src/mbgl/gl/drawable_gl_impl.hpp b/src/mbgl/gl/drawable_gl_impl.hpp index f5745e1fa..c039d3a03 100644 --- a/src/mbgl/gl/drawable_gl_impl.hpp +++ b/src/mbgl/gl/drawable_gl_impl.hpp @@ -27,13 +27,13 @@ public: Impl() = default; ~Impl() = default; - void draw(const PaintParameters& parameters) const { + void draw(const PaintParameters& parameters, int32_t lineWidth) const { auto& glContext = static_cast(parameters.context); if (!triangleIndexes.empty()) { glContext.draw(gfx::Triangles(), lineIndexes.size(), triangleIndexes.size()); } if (!lineIndexes.empty()) { - glContext.draw(gfx::Lines(1), 0, lineIndexes.size()); + glContext.draw(gfx::Lines(lineWidth), 0, lineIndexes.size()); } } diff --git a/src/mbgl/renderer/layer_group.cpp b/src/mbgl/renderer/layer_group.cpp index 87add04de..d92edb1e7 100644 --- a/src/mbgl/renderer/layer_group.cpp +++ b/src/mbgl/renderer/layer_group.cpp @@ -25,7 +25,7 @@ struct TileLayerGroup::Impl { Impl(std::size_t capacity) : tileDrawables(capacity) {} - using TileMap = std::unordered_map; + using TileMap = std::unordered_multimap; TileMap tileDrawables; }; @@ -49,27 +49,17 @@ const gfx::UniqueDrawable& TileLayerGroup::getDrawable(mbgl::RenderPass pass, co return (hit == impl->tileDrawables.end()) ? no_tile : hit->second; } -gfx::UniqueDrawable TileLayerGroup::removeDrawable(mbgl::RenderPass pass, const OverscaledTileID& id) { - const auto hit = impl->tileDrawables.find({pass, id}); - if (hit == impl->tileDrawables.end()) { - return {}; - } - auto drawable = std::move(hit->second); - impl->tileDrawables.erase(hit); - return drawable; +std::vector TileLayerGroup::removeDrawables(mbgl::RenderPass pass, const OverscaledTileID& id) { + const auto range = impl->tileDrawables.equal_range({pass, id}); + std::vector result(std::distance(range.first, range.second)); + std::transform(std::make_move_iterator(range.first), std::make_move_iterator(range.second), + result.begin(), [](auto&& pair) { return std::move(pair.second); }); + impl->tileDrawables.erase(range.first, range.second); + return result; } -bool TileLayerGroup::addDrawable(mbgl::RenderPass pass, const OverscaledTileID& id, gfx::UniqueDrawable&& drawable) { - const auto result = impl->tileDrawables.insert( - std::make_pair(TileLayerGroupTileKey{pass, id}, gfx::UniqueDrawable())); - if (result.second) { - // New item inserted, move the drawable into it - result.first->second = std::move(drawable); - return true; - } else { - // Not inserted - return false; - } +void TileLayerGroup::addDrawable(mbgl::RenderPass pass, const OverscaledTileID& id, gfx::UniqueDrawable&& drawable) { + impl->tileDrawables.insert(std::make_pair(TileLayerGroupTileKey{pass, id}, std::move(drawable))); } void TileLayerGroup::observeDrawables(std::function f) { diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 6aa435319..c882f2f08 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -298,7 +298,7 @@ void RenderBackgroundLayer::update(const int32_t layerIndex, if (!(renderPass & drawPasses)) { // Not in this pass if (tileDrawable) { - tileLayerGroup->removeDrawable(renderPass, tileID); + tileLayerGroup->removeDrawables(renderPass, tileID); ++stats.tileDrawablesRemoved; } continue; diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 31819c589..baf75ef0a 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -315,9 +315,11 @@ void RenderFillLayer::update(const int32_t layerIndex, std::inserter(newTileIDs, newTileIDs.begin()), [](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); }); - std::unique_ptr builder; + std::unique_ptr fillBuilder; + std::unique_ptr outlineBuilder; std::vector newTiles; - gfx::VertexAttributeArray vertexAttrs; + gfx::VertexAttributeArray fillVertexAttrs; + gfx::VertexAttributeArray outlineVertexAttrs; for (const auto renderPass : {RenderPass::Opaque, RenderPass::Translucent}) { if (!(mbgl::underlying_type(renderPass) & evaluatedProperties->renderPasses)) { @@ -343,7 +345,8 @@ void RenderFillLayer::update(const int32_t layerIndex, const auto removeTile = [&]() { if (tileDrawable) { - tileLayerGroup->removeDrawable(renderPass, tileID); + // Remove and discard all drawables for the tile + tileLayerGroup->removeDrawables(renderPass, tileID); ++stats.tileDrawablesRemoved; } }; @@ -359,44 +362,63 @@ void RenderFillLayer::update(const int32_t layerIndex, const auto evalColor = evaluated.get().constantOr(Color()); const auto fillOpacity = evaluated.get().constantOr(0); const auto fillColor = evalColor * (fillOpacity > 0.0f ? fillOpacity : 1.0f); - const auto fillAA = evaluated.get(); - const auto fillRenderPass = (fillColor.a >= 1.0f /* && parameters.currentLayer >= parameters.opaquePassCutoff*/) ? RenderPass::Opaque : RenderPass::Translucent; + const auto doFill = fillRenderPass == renderPass; + const auto doOutline = evaluated.get() && renderPass == RenderPass::Translucent; - if (fillRenderPass != renderPass) { + if (!doFill && !doOutline) { removeTile(); continue; } - vertexAttrs.clear(); + fillVertexAttrs.clear(); + outlineVertexAttrs.clear(); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); - if (auto& p1 = paintPropertyBinders.get()) { - const auto count = p1->getVertexCount(); - // check that vertexVector.elements() == sum(segments.vertexLength) - if (auto& attr = vertexAttrs.getOrAdd("a_color")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& packed = - static_cast>*>( - p1->getVertexValue(i)) - ->a1; - attr->set(i, {packed[0], packed[1], packed[0], packed[1]}); + if (doFill) { + if (auto& binder = paintPropertyBinders.get()) { + const auto count = binder->getVertexCount(); + // check that vertexVector.elements() == sum(segments.vertexLength) + if (auto& attr = fillVertexAttrs.getOrAdd("a_color")) { + for (std::size_t i = 0; i < count; ++i) { + const auto& packed = + static_cast>*>( + binder->getVertexValue(i)) + ->a1; + attr->set(i, {packed[0], packed[1], packed[0], packed[1]}); + } } } } - if (auto& p1 = paintPropertyBinders.get()) { - const auto count = p1->getVertexCount(); - if (auto& attr = vertexAttrs.getOrAdd("a_opacity")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& opacity = - static_cast>*>( - p1->getVertexValue(i)) - ->a1; - attr->set(i, {opacity[0], opacity[0]}); + if (doOutline) { + if (auto& binder = paintPropertyBinders.get()) { + const auto count = binder->getVertexCount(); + if (auto& attr = outlineVertexAttrs.getOrAdd("a_outline_color")) { + for (std::size_t i = 0; i < count; ++i) { + const auto& packed = + static_cast>*>( + binder->getVertexValue(i)) + ->a1; + attr->set(i, {packed[0], packed[1], packed[0], packed[1]}); + } + } + } + } + if (auto& binder = paintPropertyBinders.get()) { + const auto count = binder->getVertexCount(); + for (auto& attrs : {std::reference_wrapper(fillVertexAttrs), std::reference_wrapper(outlineVertexAttrs)}) { + if (auto& attr = attrs.get().getOrAdd("a_opacity")) { + for (std::size_t i = 0; i < count; ++i) { + const auto& opacity = + static_cast>*>( + binder->getVertexValue(i)) + ->a1; + attr->set(i, {opacity[0], opacity[0]}); + } } } } @@ -414,56 +436,32 @@ void RenderFillLayer::update(const int32_t layerIndex, continue; } - if (!builder) { - builder = context.createDrawableBuilder("fill"); - builder->setShader(fillShader); - builder->addTweaker(context.createDrawableTweaker()); - builder->setColorMode(gfx::DrawableBuilder::ColorMode::None); - builder->setDepthType(gfx::DepthMaskType::ReadWrite); - builder->setLayerIndex(layerIndex); + if (doFill && !fillBuilder) { + fillBuilder = context.createDrawableBuilder("fill"); + fillBuilder->setShader(fillShader); + //fillBuilder->addTweaker(context.createDrawableTweaker()); + fillBuilder->setColorMode(gfx::DrawableBuilder::ColorMode::None); + fillBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite : gfx::DepthMaskType::ReadOnly); + fillBuilder->setDepthType(gfx::DepthMaskType::ReadWrite); + fillBuilder->setLayerIndex(layerIndex); + } + if (doOutline && !outlineBuilder) { + outlineBuilder = context.createDrawableBuilder("fill-outline"); + outlineBuilder->setShader(outlineShader); + //outlineBuilder->addTweaker(context.createDrawableTweaker()); + outlineBuilder->setColorMode(gfx::DrawableBuilder::ColorMode::None); + outlineBuilder->setLineWidth(2); + outlineBuilder->setDepthType(gfx::DepthMaskType::ReadOnly); + outlineBuilder->setLayerIndex(layerIndex); + outlineBuilder->setSubLayerIndex(unevaluated.get().isUndefined() ? 2 : 0); } - // tile.translatedMatrix(evaluated.get(), evaluated.get(), - // parameters.state) - - builder->setRenderPass(renderPass); - builder->setVertexAttributes(vertexAttrs); - - const std::vector>>::Vertex>& - verts = bucket.vertices.vector(); - std::vector> rawVerts(verts.size()); - std::transform(verts.begin(), verts.end(), rawVerts.begin(), [](const auto& x) { return x.a1; }); - - builder->addVertices(rawVerts, 0, rawVerts.size()); - - for (const auto& seg : bucket.triangleSegments) { - builder->addTriangles(bucket.triangles.vector(), seg.indexOffset, seg.indexLength); - } - - if (fillAA) { - // TODO: Different drawable? Multiple concurrent builders? - for (const auto& seg : bucket.lineSegments) { - builder->addLines(bucket.lines.vector(), seg.indexOffset, seg.indexLength); - } - } // evaluated.get(), // evaluated.get(), // parameters.stencilModeForClipping(tile.id), // parameters.colorModeForRenderPass(), // gfx::CullFaceMode::disabled(), // - // const auto isOpaque = (evaluated.get().constantOr(Color()).a >= 1.0f && - // evaluated.get().constantOr(0) >= 1.0f - // );// && layerIndex >= parameters.opaquePassCutoff); - // const auto fillRenderPass = isOpaque ? RenderPass::Opaque : RenderPass::Translucent; - // - // if (renderPass == fillRenderPass) { - // } - - // const auto depthMask = (renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite - // : gfx::DepthMaskType::ReadOnly; - - // const auto depthMode = parameters.depthModeForSublayer(1, depthMask); // if (evaluated.get() && parameters.pass == RenderPass::Translucent) { // draw(*fillOutlineProgram, @@ -476,22 +474,57 @@ void RenderFillLayer::update(const int32_t layerIndex, // FillOutlineProgram::TextureBindings{}); // } - builder->flush(); + // tile.translatedMatrix(evaluated.get(), evaluated.get(), + // parameters.state) - auto newDrawables = builder->clearDrawables(); - if (!newDrawables.empty()) { - auto& drawable = newDrawables[0]; - drawable->setTileID(tileID); - // drawable->mutableUniformBuffers().addOrReplace("FillLayerUBO", uniformBuffer); + if (fillBuilder) { + fillBuilder->setRenderPass(renderPass); + fillBuilder->setVertexAttributes(fillVertexAttrs); + } + if (outlineBuilder) { + outlineBuilder->setRenderPass(renderPass); + outlineBuilder->setVertexAttributes(outlineVertexAttrs); + } - // Track it. - tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); - ++stats.tileDrawablesAdded; - // Log::Warning(Event::General, "Adding drawable for " + util::toString(tileID) + " total " + - // std::to_string(stats.tileDrawablesAdded+1)); + const std::vector>>::Vertex>& + verts = bucket.vertices.vector(); + std::vector> rawVerts(verts.size()); + std::transform(verts.begin(), verts.end(), rawVerts.begin(), [](const auto& x) { return x.a1; }); + + if (fillBuilder) { + fillBuilder->addVertices(rawVerts, 0, rawVerts.size()); + + for (const auto& seg : bucket.triangleSegments) { + fillBuilder->addTriangles(bucket.triangles.vector(), seg.indexOffset, seg.indexLength); + } + + fillBuilder->flush(); + + for (auto& drawable : fillBuilder->clearDrawables()) { + drawable->setTileID(tileID); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.tileDrawablesAdded; + } + } + if (outlineBuilder) { + outlineBuilder->addVertices(rawVerts, 0, rawVerts.size()); + + for (const auto& seg : bucket.lineSegments) { + outlineBuilder->addLines(bucket.lines.vector(), seg.indexOffset, seg.indexLength); + } + + outlineBuilder->flush(); + + for (auto& drawable : outlineBuilder->clearDrawables()) { + drawable->setTileID(tileID); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.tileDrawablesAdded; + } } } - } else { + } else { // FillPattern is defined // if (parameters.pass != RenderPass::Translucent) { // return; // }