summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-07-05 17:31:37 +0300
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-07-05 18:02:59 +0300
commit4532b180530b7f0dd388610f8b26b069739b720f (patch)
tree4ca6bb00c3671e4723c99563ff858d7b1bc71b7a
parenta2f0e0662470a4433a8d09384a2d727b544de945 (diff)
downloadqtlocation-mapboxgl-4532b180530b7f0dd388610f8b26b069739b720f.tar.gz
[core] createRenderer() and createLoader() for RenderLineLayer
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp330
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.hpp21
-rw-r--r--src/mbgl/renderer/render_layer.cpp27
-rw-r--r--src/mbgl/renderer/render_layer.hpp5
4 files changed, 228 insertions, 155 deletions
diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
index 595140634d..05412fa49a 100644
--- a/src/mbgl/renderer/layers/render_line_layer.cpp
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -20,18 +20,194 @@ namespace mbgl {
using namespace style;
+ColorRampRenderData::ColorRampRenderData(const style::ColorRampPropertyValue& value)
+ : image({256, 1}) {
+ assert(!value.isUndefined());
+ const auto length = image.bytes();
+
+ for (uint32_t i = 0; i < length; i += 4) {
+ const auto color = value.evaluate(static_cast<double>(i) / length);
+ image.data[i] = std::floor(color.r * 255);
+ image.data[i + 1] = std::floor(color.g * 255);
+ image.data[i + 2] = std::floor(color.b * 255);
+ image.data[i + 3] = std::floor(color.a * 255);
+ }
+}
+
+void ColorRampRenderData::upload(gfx::UploadPass& uploadPass) {
+ if (!texture) {
+ texture = uploadPass.createTexture(image);
+ }
+}
+
inline const LineLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) {
return static_cast<const LineLayer::Impl&>(*impl);
}
RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl)
: RenderLayer(makeMutable<LineLayerProperties>(std::move(_impl))),
- unevaluated(impl(baseImpl).paint.untransitioned()),
- colorRamp({256, 1}) {
+ unevaluated(impl(baseImpl).paint.untransitioned()) {
}
RenderLineLayer::~RenderLineLayer() = default;
+LayerRenderer RenderLineLayer::createRenderer() {
+ const unsigned char kDrawPattern = 1 << 0;
+ const unsigned char kDrawGradient = 1 << 1;
+ // Minimize size of the catured parameters in order to
+ // avoid heap allocations at std::function construction.
+ unsigned char drawFlags = 0;
+
+ if (!unevaluated.get<LinePattern>().isUndefined()) {
+ drawFlags |= kDrawPattern;
+ } else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
+ drawFlags |= kDrawGradient;
+ }
+
+ return [drawFlags, colorRampData = colorRamp](PaintParameters& parameters, const LayerRenderItem& renderItem) {
+ if (parameters.pass == RenderPass::Opaque) {
+ return;
+ }
+ const auto& renderTiles = renderItem.renderTiles;
+ const auto layerId = renderItem.evaluatedProperties->baseImpl->id;
+
+ parameters.renderTileClippingMasks(renderTiles);
+
+ for (const RenderTile& tile : renderTiles) {
+ const LayerRenderData* renderData = tile.getLayerRenderData(*renderItem.evaluatedProperties->baseImpl);
+ if (!renderData) {
+ continue;
+ }
+ auto& bucket = static_cast<LineBucket&>(*renderData->bucket);
+ const auto& evaluated = getEvaluated<LineLayerProperties>(renderData->layerProperties);
+ const auto& crossfade = getCrossfade<LineLayerProperties>(renderData->layerProperties);
+
+ const bool drawDash = !evaluated.get<LineDasharray>().from.empty();
+
+ auto draw = [&](auto& programInstance,
+ auto&& uniformValues,
+ const optional<ImagePosition>& patternPositionA,
+ const optional<ImagePosition>& patternPositionB, auto&& textureBindings) {
+ const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(layerId);
+
+ paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade);
+
+ const auto allUniformValues = programInstance.computeAllUniformValues(
+ std::move(uniformValues),
+ paintPropertyBinders,
+ evaluated,
+ parameters.state.getZoom()
+ );
+ const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
+ *bucket.vertexBuffer,
+ paintPropertyBinders,
+ evaluated
+ );
+
+ renderItem.checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
+
+ programInstance.draw(
+ parameters.context,
+ *parameters.renderPass,
+ gfx::Triangles(),
+ parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
+ parameters.stencilModeForClipping(tile.id),
+ parameters.colorModeForRenderPass(),
+ gfx::CullFaceMode::disabled(),
+ *bucket.indexBuffer,
+ bucket.segments,
+ allUniformValues,
+ allAttributeBindings,
+ std::move(textureBindings),
+ layerId
+ );
+ };
+
+ if (drawDash) {
+ const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round
+ ? LinePatternCap::Round : LinePatternCap::Square;
+ LinePatternPos posA = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap);
+ LinePatternPos posB = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap);
+
+ draw(
+ parameters.programs.getLineLayerPrograms().lineSDF,
+ LineSDFProgram::layoutUniformValues(
+ evaluated,
+ parameters.pixelRatio,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits,
+ posA,
+ posB,
+ crossfade,
+ parameters.lineAtlas.getSize().width),
+ {},
+ {},
+ LineSDFProgram::TextureBindings{
+ parameters.lineAtlas.textureBinding(),
+ });
+
+ } else if (drawFlags & kDrawPattern) {
+ const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<std::basic_string<char>>{ "", ""});
+ const Size& texsize = tile.getIconAtlasTexture().size;
+
+ optional<ImagePosition> posA = tile.getPattern(linePatternValue.from);
+ optional<ImagePosition> posB = tile.getPattern(linePatternValue.to);
+
+ draw(parameters.programs.getLineLayerPrograms().linePattern,
+ LinePatternProgram::layoutUniformValues(
+ evaluated,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits,
+ parameters.pixelRatio,
+ texsize,
+ crossfade),
+ posA,
+ posB,
+ LinePatternProgram::TextureBindings{
+ textures::image::Value{ tile.getIconAtlasTexture().getResource(), gfx::TextureFilterType::Linear },
+ });
+ } else if (drawFlags & kDrawGradient) {
+ assert(colorRampData);
+ assert(colorRampData->texture);
+ draw(parameters.programs.getLineLayerPrograms().lineGradient,
+ LineGradientProgram::layoutUniformValues(
+ evaluated,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits,
+ parameters.pixelRatio),
+ {},
+ {},
+ LineGradientProgram::TextureBindings{
+ textures::image::Value{ colorRampData->texture->getResource(), gfx::TextureFilterType::Linear },
+ });
+ } else {
+ draw(parameters.programs.getLineLayerPrograms().line,
+ LineProgram::layoutUniformValues(
+ evaluated,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits,
+ parameters.pixelRatio),
+ {},
+ {},
+ LineProgram::TextureBindings{});
+ }
+ }
+ };
+}
+
+LayerUploader RenderLineLayer::createUploader() {
+ if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
+ return [colorRampData = colorRamp] (gfx::UploadPass& uploadPass) {
+ if (colorRampData) colorRampData->upload(uploadPass);
+ };
+ }
+ return {};
+}
+
void RenderLineLayer::transition(const TransitionParameters& parameters) {
unevaluated = impl(baseImpl).paint.transitioned(parameters, std::move(unevaluated));
updateColorRamp();
@@ -77,141 +253,6 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) {
}
}
-void RenderLineLayer::upload(gfx::UploadPass& uploadPass) {
- if (!unevaluated.get<LineGradient>().getValue().isUndefined() && !colorRampTexture) {
- colorRampTexture = uploadPass.createTexture(colorRamp);
- }
-}
-
-void RenderLineLayer::render(PaintParameters& parameters) {
- if (parameters.pass == RenderPass::Opaque) {
- return;
- }
-
- parameters.renderTileClippingMasks(renderTiles);
-
- for (const RenderTile& tile : renderTiles) {
- const LayerRenderData* renderData = tile.getLayerRenderData(*baseImpl);
- if (!renderData) {
- continue;
- }
- auto& bucket = static_cast<LineBucket&>(*renderData->bucket);
- const auto& evaluated = getEvaluated<LineLayerProperties>(renderData->layerProperties);
- const auto& crossfade = getCrossfade<LineLayerProperties>(renderData->layerProperties);
-
- auto draw = [&](auto& programInstance,
- auto&& uniformValues,
- const optional<ImagePosition>& patternPositionA,
- const optional<ImagePosition>& patternPositionB, auto&& textureBindings) {
- const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID());
-
- paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade);
-
- const auto allUniformValues = programInstance.computeAllUniformValues(
- std::move(uniformValues),
- paintPropertyBinders,
- evaluated,
- parameters.state.getZoom()
- );
- const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
- *bucket.vertexBuffer,
- paintPropertyBinders,
- evaluated
- );
-
- checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
-
- programInstance.draw(
- parameters.context,
- *parameters.renderPass,
- gfx::Triangles(),
- parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
- parameters.stencilModeForClipping(tile.id),
- parameters.colorModeForRenderPass(),
- gfx::CullFaceMode::disabled(),
- *bucket.indexBuffer,
- bucket.segments,
- allUniformValues,
- allAttributeBindings,
- std::move(textureBindings),
- getID()
- );
- };
-
- if (!evaluated.get<LineDasharray>().from.empty()) {
- const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round
- ? LinePatternCap::Round : LinePatternCap::Square;
- LinePatternPos posA = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap);
- LinePatternPos posB = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap);
-
- draw(parameters.programs.getLineLayerPrograms().lineSDF,
- LineSDFProgram::layoutUniformValues(
- evaluated,
- parameters.pixelRatio,
- tile,
- parameters.state,
- parameters.pixelsToGLUnits,
- posA,
- posB,
- crossfade,
- parameters.lineAtlas.getSize().width),
- {},
- {},
- LineSDFProgram::TextureBindings{
- parameters.lineAtlas.textureBinding(),
- });
-
- } else if (!unevaluated.get<LinePattern>().isUndefined()) {
- const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<std::basic_string<char>>{ "", ""});
- const Size& texsize = tile.getIconAtlasTexture().size;
-
- optional<ImagePosition> posA = tile.getPattern(linePatternValue.from);
- optional<ImagePosition> posB = tile.getPattern(linePatternValue.to);
-
- draw(parameters.programs.getLineLayerPrograms().linePattern,
- LinePatternProgram::layoutUniformValues(
- evaluated,
- tile,
- parameters.state,
- parameters.pixelsToGLUnits,
- parameters.pixelRatio,
- texsize,
- crossfade),
- posA,
- posB,
- LinePatternProgram::TextureBindings{
- textures::image::Value{ tile.getIconAtlasTexture().getResource(), gfx::TextureFilterType::Linear },
- });
- } else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
- assert(colorRampTexture);
-
- draw(parameters.programs.getLineLayerPrograms().lineGradient,
- LineGradientProgram::layoutUniformValues(
- evaluated,
- tile,
- parameters.state,
- parameters.pixelsToGLUnits,
- parameters.pixelRatio),
- {},
- {},
- LineGradientProgram::TextureBindings{
- textures::image::Value{ colorRampTexture->getResource(), gfx::TextureFilterType::Linear },
- });
- } else {
- draw(parameters.programs.getLineLayerPrograms().line,
- LineProgram::layoutUniformValues(
- evaluated,
- tile,
- parameters.state,
- parameters.pixelsToGLUnits,
- parameters.pixelRatio),
- {},
- {},
- LineProgram::TextureBindings{});
- }
- }
-}
-
optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const double offset) {
if (offset == 0) return {};
@@ -278,20 +319,7 @@ void RenderLineLayer::updateColorRamp() {
if (colorValue.isUndefined()) {
return;
}
-
- const auto length = colorRamp.bytes();
-
- for (uint32_t i = 0; i < length; i += 4) {
- const auto color = colorValue.evaluate(static_cast<double>(i) / length);
- colorRamp.data[i] = std::floor(color.r * 255);
- colorRamp.data[i + 1] = std::floor(color.g * 255);
- colorRamp.data[i + 2] = std::floor(color.b * 255);
- colorRamp.data[i + 3] = std::floor(color.a * 255);
- }
-
- if (colorRampTexture) {
- colorRampTexture = nullopt;
- }
+ colorRamp = std::make_shared<ColorRampRenderData>(colorValue);
}
float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const {
diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp
index 4454d215d9..cb2d7ebda2 100644
--- a/src/mbgl/renderer/layers/render_line_layer.hpp
+++ b/src/mbgl/renderer/layers/render_line_layer.hpp
@@ -10,19 +10,33 @@
namespace mbgl {
+namespace style {
+class ColorRampPropertyValue;
+} // namespace style
+
+class ColorRampRenderData {
+public:
+ explicit ColorRampRenderData(const style::ColorRampPropertyValue&);
+ void upload(gfx::UploadPass&);
+ const PremultipliedImage image;
+ optional<gfx::Texture> texture;
+};
+
class RenderLineLayer final : public RenderLayer {
public:
explicit RenderLineLayer(Immutable<style::LineLayer::Impl>);
~RenderLineLayer() override;
private:
+ // LayerRenderItem createRenderItem() override;
+ LayerRenderer createRenderer() override;
+ LayerUploader createUploader() override;
void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
bool hasCrossfade() const override;
void prepare(const LayerPrepareParameters&) override;
- void upload(gfx::UploadPass&) override;
- void render(PaintParameters&) override;
+ void render(PaintParameters&) override {}
bool queryIntersectsFeature(
const GeometryCoordinates&,
@@ -38,8 +52,7 @@ private:
float getLineWidth(const GeometryTileFeature&, const float) const;
void updateColorRamp();
- PremultipliedImage colorRamp;
- optional<gfx::Texture> colorRampTexture;
+ std::shared_ptr<ColorRampRenderData> colorRamp;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp
index 396fc64b2d..7d02ccb050 100644
--- a/src/mbgl/renderer/render_layer.cpp
+++ b/src/mbgl/renderer/render_layer.cpp
@@ -31,6 +31,33 @@ LayerRenderItem RenderLayer::createRenderItem() {
};
}
+void LayerRenderItem::checkRenderability(const PaintParameters& parameters,
+ const uint32_t activeBindingCount) const {
+ // Only warn once for every layer.
+ if (hasRenderFailures) {
+ return;
+ }
+ std::string layerId = evaluatedProperties->baseImpl->id;
+ if (activeBindingCount > parameters.context.maximumVertexBindingCount) {
+ Log::Info(Event::OpenGL,
+ "The layer '%s' uses more data-driven properties than the current device "
+ "supports, and will have rendering errors. To ensure compatibility with this "
+ "device, use %d fewer data driven properties in this layer.",
+ layerId.c_str(),
+ activeBindingCount - parameters.context.minimumRequiredVertexBindingCount);
+ hasRenderFailures = true;
+ } else if (activeBindingCount > parameters.context.minimumRequiredVertexBindingCount) {
+ Log::Info(Event::OpenGL,
+ "The layer '%s' uses more data-driven properties than some devices may support. "
+ "Though it will render correctly on this device, it may have rendering errors "
+ "on other devices. To ensure compatibility with all devices, use %d fewer "
+ "data-driven properties in this layer.",
+ layerId.c_str(),
+ activeBindingCount - parameters.context.minimumRequiredVertexBindingCount);
+ hasRenderFailures = true;
+ }
+}
+
LayerRenderer RenderLayer::createRenderer() {
return [this](PaintParameters& pass, const LayerRenderItem&){ render(pass); };
}
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index 6837d22072..6752fd3dc8 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -60,6 +60,7 @@ public:
LayerUploader uploader; // optionally initialized.
Immutable<style::LayerProperties> evaluatedProperties;
+ void checkRenderability(const PaintParameters&, uint32_t activeBindingCount) const;
private:
bool hasRenderPass(RenderPass pass) const override { return bool(renderPass & pass); }
void upload(gfx::UploadPass& pass) const override { if (uploader) uploader(pass);}
@@ -69,6 +70,10 @@ private:
}
const std::string& getName() const override { return evaluatedProperties->baseImpl->id; }
RenderPass renderPass;
+ // Some layers may not render correctly on some hardware when the vertex attribute limit of
+ // that GPU is exceeded. More attributes are used when adding many data driven paint properties
+ // to a layer.
+ mutable bool hasRenderFailures = false;
};
class RenderLayer {