Drawable Renderer (#1570), Evaluate and apply color
This commit is contained in:
committed by
Bart Louwers
parent
8a42b2fa5f
commit
010b8f9280
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user