Drawable Renderer (#1570), Evaluate and apply color

This commit is contained in:
Tim Sylvester
2023-04-28 12:12:56 -07:00
committed by Bart Louwers
parent 8a42b2fa5f
commit 010b8f9280
14 changed files with 179 additions and 45 deletions

View File

@@ -11,6 +11,7 @@
namespace mbgl {
class Color;
class PaintParameters;
namespace gfx {
@@ -71,6 +72,9 @@ public:
/// Get the tweakers attached to this drawable
const std::vector<DrawableTweakerPtr>& getTweakers() const { return tweakers; }
// Reset a single color attribute for all vertexes
virtual void resetColor(const Color&) = 0;
protected:
util::SimpleIdentity uniqueID;
gfx::ShaderProgramBasePtr shader;

View File

@@ -60,6 +60,11 @@ public:
const Color& getColor() const;
void setColor(const Color& value);
enum class ColorMode { PerDrawable, PerVertex };
/// Set how the color value is used
/// This should not be changed while a build is in progress
void setColorMode(ColorMode mode) { colorMode = mode; }
DepthMaskType getDepthType() const { return depthType; }
void setDepthType(DepthMaskType value) { depthType = value; }
@@ -98,6 +103,7 @@ protected:
DrawablePtr currentDrawable;
std::vector<DrawablePtr> drawables;
std::vector<DrawableTweakerPtr> tweakers;
ColorMode colorMode = ColorMode::PerVertex;
struct Impl;
std::unique_ptr<Impl> impl;

View File

@@ -70,16 +70,38 @@ public:
const ElementType& get(std::size_t i) const { return items[i]; }
void reserve(std::size_t count) { items.reserve(count); }
template <typename T>
const ElementType& set(std::size_t i, T value) {
dirty = true; // need to rebuild the raw data next time
items.resize(std::max(items.size(), i + 1));
if (items.size() < i + 1) {
items.resize(std::max(items.size(), i + 1));
setDirty(); // need to rebuild the raw data next time
}
if (!isDirty()) {
if (std::holds_alternative<T>(items[i])) {
// TODO: epsilon for floats?
if (std::get<T>(items[i]) != value) {
setDirty();
}
} else {
// different types
setDirty();
}
}
return items[i] = value;
}
bool getDirty() const { return dirty; }
void clearDirty() {
dirty = false;
void clear() {
if (!items.empty()) {
setDirty();
}
items.clear();
}
bool isDirty() const { return dirty; }
void setDirty() {
dirty = true;
rawData.clear();
}
@@ -159,8 +181,10 @@ public:
}
/// Indicates whether any values have changed
bool isDirty() const;
void resetDirty();
bool isDirty() const {
return std::any_of(attrs.begin(), attrs.end(),
[](const auto& kv){ return kv.second && kv.second->isDirty(); });
}
using ResolveDelegate = std::function<void(const std::string&, const VertexAttribute&, const VertexAttribute*)>;
/// Call the provided delegate with each value, providing the override if one exists.

View File

@@ -2,11 +2,11 @@
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/gl/vertex_attribute_gl.hpp>
#include <mbgl/util/color.hpp>
#include <memory>
namespace mbgl {
namespace gfx {
class IndexBuffer;
@@ -43,7 +43,17 @@ public:
const gfx::UniqueVertexBufferResource& getBuffer() const;
const gfx::IndexBuffer& getIndexBuffer() const;
/// Reset a single color attribute for all vertexes
void resetColor(const Color&) override;
static gfx::VertexAttribute::float4 colorAttrValue(const Color& color) {
const auto components = color.toArray();
return { static_cast<float>(components[0]/255.0),
static_cast<float>(components[1]/255.0),
static_cast<float>(components[2]/255.0),
static_cast<float>(components[3]) };
}
protected:
class Impl;
const std::unique_ptr<Impl> impl;

View File

@@ -1,5 +1,6 @@
#pragma once
#include <mbgl/util/color.hpp>
#include <mbgl/util/identity.hpp>
#include <memory>
@@ -34,6 +35,17 @@ using ChangeRequestPtr = std::shared_ptr<ChangeRequest>;
using UniqueChangeRequest = std::unique_ptr<ChangeRequest>;
using UniqueChangeRequestVec = std::vector<UniqueChangeRequest>;
/**
Base for drawable-related change requests
*/
class DrawableRefChangeRequest : public ChangeRequest {
protected:
DrawableRefChangeRequest(util::SimpleIdentity id) : drawableID(id) { }
DrawableRefChangeRequest(const DrawableRefChangeRequest&) = default;
util::SimpleIdentity drawableID;
};
/**
Add a new drawable to the scene
@@ -57,16 +69,30 @@ protected:
/**
Remove a drawable from the scene
*/
class RemoveDrawableRequest : public ChangeRequest {
class RemoveDrawableRequest : public DrawableRefChangeRequest {
public:
RemoveDrawableRequest(util::SimpleIdentity drawableId_) : drawableId(drawableId_) { }
RemoveDrawableRequest(const RemoveDrawableRequest& other) : drawableId(other.drawableId) { }
RemoveDrawableRequest(util::SimpleIdentity id) : DrawableRefChangeRequest(id) { }
RemoveDrawableRequest(const RemoveDrawableRequest&) = default;
void execute(RenderOrchestrator &) override;
};
/**
Change the color of all vertexes
*/
class ResetColorRequest : public DrawableRefChangeRequest {
public:
ResetColorRequest(util::SimpleIdentity id, Color color) :
DrawableRefChangeRequest(id),
newColor(color)
{ }
ResetColorRequest(const ResetColorRequest& other) = default;
void execute(RenderOrchestrator &) override;
protected:
util::SimpleIdentity drawableId;
Color newColor;
};
} // namespace mbgl

View File

@@ -69,14 +69,18 @@ void DrawableBuilder::addTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1
impl->vertices.emplace_back(Impl::VT({{{ x1, y1 }}}));
impl->vertices.emplace_back(Impl::VT({{{ x2, y2 }}}));
impl->indexes.emplace_back(n, n+1, n+2);
impl->colors.insert(impl->colors.end(), 3, impl->currentColor);
if (colorMode == ColorMode::PerVertex) {
impl->colors.insert(impl->colors.end(), 3, impl->currentColor);
}
}
void DrawableBuilder::appendTriangle(int16_t x0, int16_t y0) {
const auto n = (uint16_t)impl->vertices.elements();
impl->vertices.emplace_back(Impl::VT({{{ x0, y0 }}}));
impl->indexes.emplace_back(n-2, n-1, n);
impl->colors.emplace_back(impl->currentColor);
if (colorMode == ColorMode::PerVertex) {
impl->colors.emplace_back(impl->currentColor);
}
}
void DrawableBuilder::addQuad(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {

View File

@@ -68,5 +68,12 @@ void DrawableGL::setVertexArray(gl::VertexArray&& vertexArray_,
impl->indexBuffer = std::move(indexBuffer_);
}
void DrawableGL::resetColor(const Color& newColor) {
if (auto* colorAttr = impl->vertexAttributes.get("a_color")) {
colorAttr->clear();
colorAttr->set(0, colorAttrValue(newColor));
}
}
} // namespace gl
} // namespace mbgl

View File

@@ -22,15 +22,20 @@ void DrawableGLBuilder::init() {
}
}
if (auto colorAttr = attrs.getOrAdd("a_color")) {
std::size_t index = 0;
for (const auto& color : impl->colors) {
const auto comp = color.toArray();
colorAttr->set(index++, gfx::VertexAttribute::float4 {
static_cast<float>(comp[0]/255.0),
static_cast<float>(comp[1]/255.0),
static_cast<float>(comp[2]/255.0),
static_cast<float>(comp[3]),
});
// We should have either a single color or one per vertex. Otherwise,
// the color mode was probably changed after vertexes were added.
if (impl->colors.size() > 1 && impl->colors.size() != impl->vertices.elements()) {
impl->colors.clear();
}
if (impl->colors.empty()) {
colorAttr->set(0, DrawableGL::colorAttrValue(getColor()));
} else {
std::size_t index = 0;
colorAttr->reserve(impl->colors.size());
for (const auto& color : impl->colors) {
colorAttr->set(index++, DrawableGL::colorAttrValue(color));
}
}
}

View File

@@ -8,7 +8,13 @@ void AddDrawableRequest::execute(RenderOrchestrator &orchestrator) {
}
void RemoveDrawableRequest::execute(RenderOrchestrator &orchestrator) {
orchestrator.removeDrawable(drawableId);
orchestrator.removeDrawable(drawableID);
}
void ResetColorRequest::execute(RenderOrchestrator &orchestrator) {
if (auto& drawable = orchestrator.getDrawable(drawableID)) {
drawable->resetColor(newColor);
}
}
} // namespace mbgl

View File

@@ -770,6 +770,12 @@ void RenderOrchestrator::removeDrawable(const util::SimpleIdentity& drawableId)
drawables.erase(drawableId);
}
const gfx::DrawablePtr noDrawable;
const gfx::DrawablePtr& RenderOrchestrator::getDrawable(const util::SimpleIdentity& id) {
const auto hit = drawables.find(id);
return (hit != drawables.end()) ? hit->second : noDrawable;
}
void RenderOrchestrator::updateLayers(gfx::ShaderRegistry& shaders,
const TransformState& state,
const PropertyEvaluationParameters& evalParameters) {

View File

@@ -99,6 +99,8 @@ public:
void addDrawable(gfx::DrawablePtr);
void removeDrawable(const util::SimpleIdentity& drawableId);
const gfx::DrawablePtr& getDrawable(const util::SimpleIdentity&);
void updateLayers(gfx::ShaderRegistry&,
const TransformState&,
const PropertyEvaluationParameters&);

View File

@@ -117,7 +117,8 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
auto& shader = drawable.getShader();
// Generate a vertex array object for the drawable state, if necessary
if (shader && !drawableGL.getVertexArray().isValid()) {
if (shader && (!drawableGL.getVertexArray().isValid() ||
drawableGL.getVertexAttributes().isDirty())) {
const auto usage = gfx::BufferUsageType::StaticDraw;
// Build index buffer

View File

@@ -18,10 +18,10 @@ namespace style {
BackgroundLayer::Impl::Impl(const Impl& other) :
Layer::Impl(other),
shader(other.shader),
tileDrawables(other.tileDrawables),
lastColor(other.lastColor),
paint(other.paint)
{
// mutex, drawables, stats not copied
}
bool BackgroundLayer::Impl::hasLayoutDifference(const Layer::Impl&) const {
@@ -46,17 +46,18 @@ void BackgroundLayer::Impl::layerAdded(gfx::ShaderRegistry& shaders,
}
void BackgroundLayer::Impl::layerRemoved(UniqueChangeRequestVec& changes) const {
// TODO: This isn't happening on style change, so old tile drawables are being left active
// Remove everything
decltype(tileDrawables) localDrawables;
{
std::unique_lock<std::mutex> guard(mutex);
localDrawables = std::move(tileDrawables);
}
for (auto& kv : localDrawables) {
auto& drawable = kv.second;
changes.emplace_back(std::make_unique<RemoveDrawableRequest>(drawable->getId()));
}
removeDrawables<decltype(localDrawables)::const_iterator>(
localDrawables.cbegin(), localDrawables.cend(), changes,
[](auto& ii) { return ii->second->getId(); });
}
void BackgroundLayer::Impl::update(const TransformState& state,
@@ -64,8 +65,10 @@ void BackgroundLayer::Impl::update(const TransformState& state,
UniqueChangeRequestVec& changes) const {
std::unique_lock<std::mutex> guard(mutex);
const auto uneval = paint.untransitioned();
const auto eval = uneval.evaluate(evalParameters);
if (!unevaluated) {
unevaluated = paint.untransitioned();
}
const auto evaluated = unevaluated->evaluate(evalParameters);
//const auto passes = eval.get<style::BackgroundOpacity>() == 0.0f
// ? RenderPass::None
@@ -79,13 +82,25 @@ void BackgroundLayer::Impl::update(const TransformState& state,
//getCrossfade<BackgroundLayerProperties>(evaluatedProperties).t != 1;
std::optional<Color> color;
if (eval.get<BackgroundPattern>().from.empty()) {
const auto opacity = eval.get<style::BackgroundOpacity>();
if (evaluated.get<BackgroundPattern>().from.empty()) {
const auto opacity = evaluated.get<style::BackgroundOpacity>();
if (opacity > 0.0f) {
color = eval.get<BackgroundColor>() * eval.get<BackgroundOpacity>();
color = evaluated.get<BackgroundColor>() * evaluated.get<BackgroundOpacity>();
}
}
// If the result is transparent or missing, just remove any existing drawables and stop
if (!color) {
removeDrawables<decltype(tileDrawables)::const_iterator>(
tileDrawables.cbegin(), tileDrawables.cend(), changes,
[](auto& ii) { return ii->second->getId(); });
tileDrawables.clear();
return;
}
const bool colorChange = (color != lastColor);
lastColor = color;
const auto zoom = state.getIntegerZoom();
const auto tileCover = util::tileCover(state, zoom);
@@ -99,21 +114,24 @@ void BackgroundLayer::Impl::update(const TransformState& state,
// For each existing tile drawable...
for (auto iter = tileDrawables.begin(); iter != tileDrawables.end(); ) {
const auto& drawable = iter->second;
// Has this tile dropped out of the cover set?
if (newTileIDs.find(iter->first) == newTileIDs.end()) {
// remove it
const auto& drawable = iter->second;
changes.emplace_back(std::make_unique<RemoveDrawableRequest>(drawable->getId()));
//Log::Warning(Event::General, "Removing drawable for " + util::toString(iter->first) + " total " + std::to_string(stats.tileDrawablesRemoved+1));
iter = tileDrawables.erase(iter);
++stats.tileDrawablesRemoved;
} else {
++iter;
continue;
}
}
++iter;
if (!color) {
return;
// If the color evaluated to a new value, emit a change request updating all vertexes of
// the existing drawable to the new color.
if (colorChange) {
changes.emplace_back(std::make_unique<ResetColorRequest>(drawable->getId(), *color));
}
}
std::unique_ptr<gfx::DrawableBuilder> builder;
@@ -134,6 +152,7 @@ void BackgroundLayer::Impl::update(const TransformState& state,
builder->setShader(shader);
builder->addTweaker(std::make_shared<gl::DrawableGLTweaker>()); // generally shared across drawables
builder->setColor(*color);
builder->setColorMode(gfx::DrawableBuilder::ColorMode::PerDrawable);
builder->setDepthType(gfx::DepthMaskType::ReadWrite);
}

View File

@@ -1,5 +1,7 @@
#pragma once
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/renderer/change_request.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_properties.hpp>
@@ -43,15 +45,27 @@ public:
UniqueChangeRequestVec&) const override;
private:
// Add a deletion change request for each drawable in a collection
template <typename T>
static void removeDrawables(T beg, const T end, UniqueChangeRequestVec& changes,
std::function<util::SimpleIdentity(const T&)> f) {
for (; beg != end; ++beg) {
changes.emplace_back(std::make_unique<RemoveDrawableRequest>(f(beg)));
}
}
mutable std::mutex mutex;
mutable gfx::ShaderProgramBasePtr shader;
mutable std::unordered_map<OverscaledTileID, gfx::DrawablePtr> tileDrawables;
mutable std::optional<Color> lastColor;
mutable struct Stats {
size_t tileDrawablesAdded = 0;
size_t tileDrawablesRemoved = 0;
} stats;
mutable std::optional<BackgroundPaintProperties::Unevaluated> unevaluated;
public:
BackgroundPaintProperties::Transitionable paint;