diff options
-rw-r--r-- | include/mbgl/map/map.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/gl/program.hpp | 11 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 8 | ||||
-rw-r--r-- | src/mbgl/programs/program.hpp | 35 | ||||
-rw-r--r-- | src/mbgl/programs/program_parameters.cpp | 30 | ||||
-rw-r--r-- | src/mbgl/programs/program_parameters.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/programs/programs.hpp | 26 | ||||
-rw-r--r-- | src/mbgl/programs/symbol_program.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/renderer/paint_property_binder.hpp | 60 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_background.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_circle.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_clipping.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_fill.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_fill_extrusion.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_line.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/painters/painter_symbol.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/shaders/shaders.cpp | 4 |
19 files changed, 148 insertions, 70 deletions
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 289b5e21a4..33b40a8e77 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -44,7 +44,7 @@ public: GLContextMode contextMode = GLContextMode::Unique, ConstrainMode constrainMode = ConstrainMode::HeightOnly, ViewportMode viewportMode = ViewportMode::Default, - const std::string& programCacheDir = ""); + const optional<std::string>& programCacheDir = {}); ~Map(); // Register a callback that will get called (on the render thread) when all resources have diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index c36543839c..47ad39de7c 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -50,7 +50,8 @@ public: const char* vertexSource_, const char* fragmentSource_) { #if MBGL_HAS_BINARY_PROGRAMS - if (!programParameters.cacheDir.empty() && context.supportsProgramBinaries()) { + optional<std::string> cachePath = programParameters.cachePath(name); + if (cachePath && context.supportsProgramBinaries()) { const std::string vertexSource = shaders::vertexSource(programParameters, vertexSource_); const std::string fragmentSource = @@ -58,10 +59,8 @@ public: const std::string identifier = shaders::programIdentifier(vertexSource, fragmentSource_); - const std::string cachePath = programParameters.cachePath(name); - try { - if (auto cachedBinaryProgram = util::readFile(cachePath)) { + if (auto cachedBinaryProgram = util::readFile(*cachePath)) { const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram)); if (binaryProgram.identifier() == identifier) { return Program { context, binaryProgram }; @@ -82,8 +81,8 @@ public: try { if (const auto binaryProgram = result.template get<BinaryProgram>(context, identifier)) { - util::write_file(cachePath, binaryProgram->serialize()); - Log::Warning(Event::OpenGL, "Caching program in: %s", cachePath.c_str()); + util::write_file(*cachePath, binaryProgram->serialize()); + Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str()); } } catch (std::runtime_error& error) { Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what()); diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 72fc051440..e685251b80 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -62,7 +62,7 @@ public: GLContextMode, ConstrainMode, ViewportMode, - std::string programCacheDir); + optional<std::string> programCacheDir); void onSourceChanged(style::Source&) override; void onUpdate(Update) override; @@ -88,7 +88,7 @@ public: const MapMode mode; const GLContextMode contextMode; const float pixelRatio; - const std::string programCacheDir; + const optional<std::string> programCacheDir; MapDebugOptions debugOptions { MapDebugOptions::NoDebug }; @@ -122,7 +122,7 @@ Map::Map(Backend& backend, GLContextMode contextMode, ConstrainMode constrainMode, ViewportMode viewportMode, - const std::string& programCacheDir) + const optional<std::string>& programCacheDir) : impl(std::make_unique<Impl>(*this, backend, pixelRatio, @@ -145,7 +145,7 @@ Map::Impl::Impl(Map& map_, GLContextMode contextMode_, ConstrainMode constrainMode_, ViewportMode viewportMode_, - std::string programCacheDir_) + optional<std::string> programCacheDir_) : map(map_), observer(backend_), backend(backend_), diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 3351f5eeae..36bbdf349e 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -9,18 +9,21 @@ #include <mbgl/shaders/shaders.hpp> #include <mbgl/util/io.hpp> +#include <unordered_map> + namespace mbgl { template <class Shaders, class Primitive, class LayoutAttrs, class Uniforms, - class PaintProperties> + class PaintProps> class Program { public: using LayoutAttributes = LayoutAttrs; using LayoutVertex = typename LayoutAttributes::Vertex; + using PaintProperties = PaintProps; using PaintPropertyBinders = typename PaintProperties::Binders; using PaintAttributes = typename PaintPropertyBinders::Attributes; using Attributes = gl::ConcatenateAttributes<LayoutAttributes, PaintAttributes>; @@ -71,4 +74,34 @@ public: } }; +template <class Program> +class ProgramMap { +public: + using PaintProperties = typename Program::PaintProperties; + using PaintPropertyBinders = typename Program::PaintPropertyBinders; + using Bitset = typename PaintPropertyBinders::Bitset; + + ProgramMap(gl::Context& context_, ProgramParameters parameters_) + : context(context_), + parameters(std::move(parameters_)) { + } + + Program& get(const typename PaintProperties::PossiblyEvaluated& currentProperties) { + Bitset bits = PaintPropertyBinders::constants(currentProperties); + auto it = programs.find(bits); + if (it != programs.end()) { + return it->second; + } + return programs.emplace(std::piecewise_construct, + std::forward_as_tuple(bits), + std::forward_as_tuple(context, + parameters.withAdditionalDefines(PaintPropertyBinders::defines(currentProperties)))).first->second; + } + +private: + gl::Context& context; + ProgramParameters parameters; + std::unordered_map<Bitset, Program> programs; +}; + } // namespace mbgl diff --git a/src/mbgl/programs/program_parameters.cpp b/src/mbgl/programs/program_parameters.cpp index f9f680ac1e..e76ec4be71 100644 --- a/src/mbgl/programs/program_parameters.cpp +++ b/src/mbgl/programs/program_parameters.cpp @@ -7,7 +7,7 @@ namespace mbgl { ProgramParameters::ProgramParameters(const float pixelRatio, const bool overdraw, - std::string cacheDir_) + optional<std::string> cacheDir_) : defines([&] { std::ostringstream ss; ss.imbue(std::locale("C")); @@ -18,15 +18,31 @@ ProgramParameters::ProgramParameters(const float pixelRatio, } return ss.str(); }()), - hash(std::hash<std::string>()(defines)), cacheDir(std::move(cacheDir_)) { } -std::string ProgramParameters::cachePath(const char* name) const { - std::ostringstream ss; - ss << cacheDir << "/com.mapbox.gl.shader." << name << "." << std::setfill('0') - << std::setw(sizeof(size_t) * 2) << std::hex << hash << ".pbf"; - return ss.str(); +const std::string& ProgramParameters::getDefines() const { + return defines; +} + +optional<std::string> ProgramParameters::cachePath(const char* name) const { + if (!cacheDir) { + return {}; + } else { + std::ostringstream ss; + ss << *cacheDir << "/com.mapbox.gl.shader." << name << "." << std::setfill('0') + << std::setw(sizeof(size_t) * 2) << std::hex << std::hash<std::string>()(defines) << ".pbf"; + return ss.str(); + } +} + +ProgramParameters ProgramParameters::withAdditionalDefines(const std::vector<std::string>& additionalDefines) const { + ProgramParameters result(*this); + for (const auto& define : additionalDefines) { + result.defines += define; + result.defines += "\n"; + } + return result; } } // namespace mbgl diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp index d286ff57d1..e94e61c217 100644 --- a/src/mbgl/programs/program_parameters.hpp +++ b/src/mbgl/programs/program_parameters.hpp @@ -1,21 +1,24 @@ #pragma once +#include <mbgl/util/optional.hpp> + #include <string> -#include <utility> +#include <vector> namespace mbgl { class ProgramParameters { public: - ProgramParameters(float pixelRatio, bool overdraw, std::string cacheDir); + ProgramParameters(float pixelRatio, bool overdraw, optional<std::string> cacheDir); - const std::string defines; + const std::string& getDefines() const; + optional<std::string> cachePath(const char* name) const; - std::string cachePath(const char* name) const; + ProgramParameters withAdditionalDefines(const std::vector<std::string>& defines) const; private: - const std::size_t hash; - const std::string cacheDir; + std::string defines; + optional<std::string> cacheDir; }; } // namespace mbgl diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp index b58d2e3bee..37ced32745 100644 --- a/src/mbgl/programs/programs.hpp +++ b/src/mbgl/programs/programs.hpp @@ -35,21 +35,21 @@ public: collisionBox(context, programParameters) { } - CircleProgram circle; + ProgramMap<CircleProgram> circle; ExtrusionTextureProgram extrusionTexture; - FillProgram fill; - FillExtrusionProgram fillExtrusion; - FillExtrusionPatternProgram fillExtrusionPattern; - FillPatternProgram fillPattern; - FillOutlineProgram fillOutline; - FillOutlinePatternProgram fillOutlinePattern; - LineProgram line; - LineSDFProgram lineSDF; - LinePatternProgram linePattern; + ProgramMap<FillProgram> fill; + ProgramMap<FillExtrusionProgram> fillExtrusion; + ProgramMap<FillExtrusionPatternProgram> fillExtrusionPattern; + ProgramMap<FillPatternProgram> fillPattern; + ProgramMap<FillOutlineProgram> fillOutline; + ProgramMap<FillOutlinePatternProgram> fillOutlinePattern; + ProgramMap<LineProgram> line; + ProgramMap<LineSDFProgram> lineSDF; + ProgramMap<LinePatternProgram> linePattern; RasterProgram raster; - SymbolIconProgram symbolIcon; - SymbolSDFIconProgram symbolIconSDF; - SymbolSDFTextProgram symbolGlyph; + ProgramMap<SymbolIconProgram> symbolIcon; + ProgramMap<SymbolSDFIconProgram> symbolIconSDF; + ProgramMap<SymbolSDFTextProgram> symbolGlyph; DebugProgram debug; CollisionBoxProgram collisionBox; diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 087d3a4567..358fa08ecd 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -324,7 +324,7 @@ template <class Shaders, class Primitive, class LayoutAttrs, class Uniforms, - class PaintProperties> + class PaintProps> class SymbolProgram { public: using LayoutAttributes = LayoutAttrs; @@ -332,6 +332,7 @@ public: using LayoutAndSizeAttributes = gl::ConcatenateAttributes<LayoutAttributes, SymbolSizeAttributes>; + using PaintProperties = PaintProps; using PaintPropertyBinders = typename PaintProperties::Binders; using PaintAttributes = typename PaintPropertyBinders::Attributes; using Attributes = gl::ConcatenateAttributes<LayoutAndSizeAttributes, PaintAttributes>; diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 8291301d33..91ddcac2b3 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -7,6 +7,8 @@ #include <mbgl/renderer/possibly_evaluated_property_value.hpp> #include <mbgl/renderer/paint_property_statistics.hpp> +#include <bitset> + namespace mbgl { /* @@ -55,8 +57,7 @@ std::array<float, N*2> zoomInterpolatedAttributeValue(const std::array<float, N> * For _constant_ properties -- those whose value is a constant, or the constant result of evaluating a camera function at a particular camera position -- we - don't need a vertex buffer, and can instead use a constant attribute binding - via the `glVertexAttrib*` family of functions. + don't need a vertex buffer, and instead use a uniform. * For source functions, we use a vertex buffer with a single attribute value, the evaluated result of the source function for the given feature. * For composite functions, we use a vertex buffer with two attributes: min and @@ -67,15 +68,8 @@ std::array<float, N*2> zoomInterpolatedAttributeValue(const std::array<float, N> between the min and max value at the final displayed zoom level. The use of a uniform allows us to cheaply update the value on every frame. - Note that the shader source is the same regardless of the strategy used to bind - the attribute -- in all cases the attribute is declared as a vec2, in order to - support composite min and max values (color attributes use a vec4 with special - packing). When the constant or source function strategies are used, the - interpolation uniform value is set to zero, and the second attribute element is - unused. This differs from the GL JS implementation, which dynamically generates - shader source based on the strategy used. We found that in WebGL, using - `glVertexAttrib*` was unnacceptably slow. Additionally, in GL Native we have - implemented binary shader caching, which works better if the shaders are constant. + Note that the shader source varies depending on whether we're using a uniform or + attribute. Like GL JS, we dynamically compile shaders at runtime to accomodate this. */ template <class T, class A> class PaintPropertyBinder { @@ -171,9 +165,13 @@ public: return 0.0f; } - T uniformValue(const PossiblyEvaluatedPropertyValue<T>&) const override { - // Uniform values for vertex attribute arrays are unused. - return {}; + T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + if (currentValue.isConstant()) { + return *currentValue.constant(); + } else { + // Uniform values for vertex attribute arrays are unused. + return {}; + } } private: @@ -231,9 +229,13 @@ public: return util::interpolationFactor(1.0f, std::get<0>(coveringRanges), currentZoom); } - T uniformValue(const PossiblyEvaluatedPropertyValue<T>&) const override { - // Uniform values for vertex attribute arrays are unused. - return {}; + T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { + if (currentValue.isConstant()) { + return *currentValue.constant(); + } else { + // Uniform values for vertex attribute arrays are unused. + return {}; + } } private: @@ -343,6 +345,30 @@ public: return binders.template get<P>()->statistics; } + + using Bitset = std::bitset<sizeof...(Ps)>; + + template <class EvaluatedProperties> + static Bitset constants(const EvaluatedProperties& currentProperties) { + Bitset result; + util::ignore({ + result.set(TypeIndex<Ps, Ps...>::value, + currentProperties.template get<Ps>().isConstant())... + }); + return result; + } + + template <class EvaluatedProperties> + static std::vector<std::string> defines(const EvaluatedProperties& currentProperties) { + std::vector<std::string> result; + util::ignore({ + (result.push_back(currentProperties.template get<Ps>().isConstant() + ? std::string("#define HAS_UNIFORM_") + Ps::Uniform::name() + : std::string()), 0)... + }); + return result; + } + private: Binders binders; }; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 673bf66901..1f55c168a6 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -90,7 +90,7 @@ static gl::VertexVector<ExtrusionTextureLayoutVertex> extrusionTextureVertices() Painter::Painter(gl::Context& context_, const TransformState& state_, float pixelRatio, - const std::string& programCacheDir) + const optional<std::string>& programCacheDir) : context(context_), state(state_), tileVertexBuffer(context.createVertexBuffer(tileVertices())), diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index f2d06a0e20..7e966adefa 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -70,7 +70,7 @@ struct FrameData { class Painter : private util::noncopyable { public: - Painter(gl::Context&, const TransformState&, float pixelRatio, const std::string& programCacheDir); + Painter(gl::Context&, const TransformState&, float pixelRatio, const optional<std::string>& programCacheDir); ~Painter(); void render(RenderStyle&, diff --git a/src/mbgl/renderer/painters/painter_background.cpp b/src/mbgl/renderer/painters/painter_background.cpp index 7ebb735df8..577d7d6cda 100644 --- a/src/mbgl/renderer/painters/painter_background.cpp +++ b/src/mbgl/renderer/painters/painter_background.cpp @@ -33,7 +33,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou imageManager->bind(context, 0); for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) { - parameters.programs.fillPattern.draw( + parameters.programs.fillPattern.get(properties).draw( context, gl::Triangles(), depthModeForSublayer(0, gl::DepthMode::ReadOnly), @@ -59,7 +59,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou } } else { for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) { - parameters.programs.fill.draw( + parameters.programs.fill.get(properties).draw( context, gl::Triangles(), depthModeForSublayer(0, gl::DepthMode::ReadOnly), diff --git a/src/mbgl/renderer/painters/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp index 367dd57bc7..58e384979d 100644 --- a/src/mbgl/renderer/painters/painter_circle.cpp +++ b/src/mbgl/renderer/painters/painter_circle.cpp @@ -23,7 +23,7 @@ void Painter::renderCircle(PaintParameters& parameters, const CirclePaintProperties::PossiblyEvaluated& properties = layer.evaluated; const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map; - parameters.programs.circle.draw( + parameters.programs.circle.get(properties).draw( context, gl::Triangles(), depthModeForSublayer(0, gl::DepthMode::ReadOnly), diff --git a/src/mbgl/renderer/painters/painter_clipping.cpp b/src/mbgl/renderer/painters/painter_clipping.cpp index 31e2b700b0..cad092594e 100644 --- a/src/mbgl/renderer/painters/painter_clipping.cpp +++ b/src/mbgl/renderer/painters/painter_clipping.cpp @@ -8,7 +8,7 @@ namespace mbgl { void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) { static const style::FillPaintProperties::PossiblyEvaluated properties {}; static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0); - programs->fill.draw( + programs->fill.get(properties).draw( context, gl::Triangles(), gl::DepthMode::disabled(), diff --git a/src/mbgl/renderer/painters/painter_fill.cpp b/src/mbgl/renderer/painters/painter_fill.cpp index b7e0077ed0..3a0bfed454 100644 --- a/src/mbgl/renderer/painters/painter_fill.cpp +++ b/src/mbgl/renderer/painters/painter_fill.cpp @@ -38,7 +38,7 @@ void Painter::renderFill(PaintParameters& parameters, const auto& drawMode, const auto& indexBuffer, const auto& segments) { - program.draw( + program.get(properties).draw( context, drawMode, depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite), @@ -86,7 +86,7 @@ void Painter::renderFill(PaintParameters& parameters, const auto& drawMode, const auto& indexBuffer, const auto& segments) { - program.draw( + program.get(properties).draw( context, drawMode, depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite), diff --git a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp index 55e56554dc..165476944b 100644 --- a/src/mbgl/renderer/painters/painter_fill_extrusion.cpp +++ b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp @@ -34,7 +34,7 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, imageManager->bind(context, 0); - parameters.programs.fillExtrusionPattern.draw( + parameters.programs.fillExtrusionPattern.get(properties).draw( context, gl::Triangles(), depthModeForSublayer(0, gl::DepthMode::ReadWrite), @@ -61,7 +61,7 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, state.getZoom()); } else { - parameters.programs.fillExtrusion.draw( + parameters.programs.fillExtrusion.get(properties).draw( context, gl::Triangles(), depthModeForSublayer(0, gl::DepthMode::ReadWrite), diff --git a/src/mbgl/renderer/painters/painter_line.cpp b/src/mbgl/renderer/painters/painter_line.cpp index ea2a63529d..49fee36925 100644 --- a/src/mbgl/renderer/painters/painter_line.cpp +++ b/src/mbgl/renderer/painters/painter_line.cpp @@ -24,7 +24,7 @@ void Painter::renderLine(PaintParameters& parameters, const LinePaintProperties::PossiblyEvaluated& properties = layer.evaluated; auto draw = [&] (auto& program, auto&& uniformValues) { - program.draw( + program.get(properties).draw( context, gl::Triangles(), depthModeForSublayer(0, gl::DepthMode::ReadOnly), diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index 58700fc4e8..ee5e8c7e2f 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -40,7 +40,7 @@ void Painter::renderSymbol(PaintParameters& parameters, // We clip symbols to their tile extent in still mode. const bool needsClipping = frame.mapMode == MapMode::Still; - program.draw( + program.get(paintProperties).draw( context, gl::Triangles(), values_.pitchAlignment == AlignmentType::Map diff --git a/src/mbgl/shaders/shaders.cpp b/src/mbgl/shaders/shaders.cpp index 93e273f985..31ff405f02 100644 --- a/src/mbgl/shaders/shaders.cpp +++ b/src/mbgl/shaders/shaders.cpp @@ -10,11 +10,11 @@ namespace mbgl { namespace shaders { std::string fragmentSource(const ProgramParameters& parameters, const char* fragmentSource) { - return parameters.defines + fragmentPrelude + fragmentSource; + return parameters.getDefines() + fragmentPrelude + fragmentSource; } std::string vertexSource(const ProgramParameters& parameters, const char* vertexSource) { - return parameters.defines + vertexPrelude + vertexSource; + return parameters.getDefines() + vertexPrelude + vertexSource; } std::string programIdentifier(const std::string& vertexSource, const std::string& fragmentSource) { |