diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f35ec847..d67f539df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1110,6 +1110,7 @@ if(MLN_WITH_OPENGL) list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/background_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/circle_layer_ubo.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/collision_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/fill_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/fill_extrusion_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/heatmap_layer_ubo.hpp @@ -1174,6 +1175,8 @@ if(MBGL_WITH_METAL) ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/circle.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/clipping_mask.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/common.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/collision_box.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/collision_circle.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill_extrusion.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp @@ -1210,6 +1213,25 @@ if(MBGL_WITH_METAL) ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/upload_pass.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/vertex_attribute.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/background.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/background_pattern.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/circle.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/collision_box.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/collision_circle.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/clipping_mask.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/fill.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/fill_extrusion.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/fill_extrusion_pattern.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/heatmap.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/heatmap_texture.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/hillshade.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/hillshade_prepare.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/line.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/line_gradient.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/raster.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/symbol_icon.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/symbol_sdf.cpp + ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/symbol_text_and_icon.cpp ] ) endif() diff --git a/bazel/core.bzl b/bazel/core.bzl index 6329df8eb..9a13789fa 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -961,6 +961,7 @@ MLN_DRAWABLES_HEADERS = [ "include/mbgl/renderer/render_target.hpp", "include/mbgl/shaders/background_layer_ubo.hpp", "include/mbgl/shaders/circle_layer_ubo.hpp", + "include/mbgl/shaders/collision_layer_ubo.hpp", "include/mbgl/shaders/fill_layer_ubo.hpp", "include/mbgl/shaders/fill_extrusion_layer_ubo.hpp", "include/mbgl/shaders/heatmap_layer_ubo.hpp", @@ -1019,6 +1020,25 @@ MLN_DRAWABLES_MTL_SOURCE = [ "src/mbgl/mtl/upload_pass.cpp", "src/mbgl/mtl/vertex_attribute.cpp", "src/mbgl/shaders/mtl/shader_program.cpp", + "src/mbgl/shaders/mtl/background.cpp", + "src/mbgl/shaders/mtl/background_pattern.cpp", + "src/mbgl/shaders/mtl/circle.cpp", + "src/mbgl/shaders/mtl/collision_box.cpp", + "src/mbgl/shaders/mtl/collision_circle.cpp", + "src/mbgl/shaders/mtl/clipping_mask.cpp", + "src/mbgl/shaders/mtl/fill.cpp", + "src/mbgl/shaders/mtl/fill_extrusion.cpp", + "src/mbgl/shaders/mtl/fill_extrusion_pattern.cpp", + "src/mbgl/shaders/mtl/heatmap.cpp", + "src/mbgl/shaders/mtl/heatmap_texture.cpp", + "src/mbgl/shaders/mtl/hillshade.cpp", + "src/mbgl/shaders/mtl/hillshade_prepare.cpp", + "src/mbgl/shaders/mtl/line.cpp", + "src/mbgl/shaders/mtl/line_gradient.cpp", + "src/mbgl/shaders/mtl/raster.cpp", + "src/mbgl/shaders/mtl/symbol_icon.cpp", + "src/mbgl/shaders/mtl/symbol_sdf.cpp", + "src/mbgl/shaders/mtl/symbol_text_and_icon.cpp", ] MLN_DRAWABLES_MTL_HEADERS = [ @@ -1045,6 +1065,8 @@ MLN_DRAWABLES_MTL_HEADERS = [ "include/mbgl/shaders/mtl/background_pattern.hpp", "include/mbgl/shaders/mtl/circle.hpp", "include/mbgl/shaders/mtl/clipping_mask.hpp", + "include/mbgl/shaders/mtl/collision_box.hpp", + "include/mbgl/shaders/mtl/collision_circle.hpp", "include/mbgl/shaders/mtl/common.hpp", "include/mbgl/shaders/mtl/fill.hpp", "include/mbgl/shaders/mtl/fill_extrusion.hpp", diff --git a/include/mbgl/gfx/backend.hpp b/include/mbgl/gfx/backend.hpp index bc79032b7..859bc5f23 100644 --- a/include/mbgl/gfx/backend.hpp +++ b/include/mbgl/gfx/backend.hpp @@ -19,7 +19,7 @@ public: #if MLN_RENDER_BACKEND_METAL static constexpr Type DefaultType = Type::Metal; -#else // assume MLN_RENDER_BACKEND_METAL +#else // assume MLN_RENDER_BACKEND_OPENGL static constexpr Type DefaultType = Type::OpenGL; #endif @@ -33,7 +33,11 @@ public: template static std::unique_ptr Create(Args... args) { +#if MLN_RENDER_BACKEND_METAL + return Create(std::forward(args)...); +#else // assume MLN_RENDER_BACKEND_OPENGL return Create(std::forward(args)...); +#endif } private: diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 13feb6e59..56a140b3f 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -134,7 +134,7 @@ public: bool getEnableStencil() const { return enableStencil; } /// Set stencil usage - void setEnableStencil(bool value) { enableStencil = value; } + virtual void setEnableStencil(bool value) { enableStencil = value; } /// not used for anything yet DrawPriority getDrawPriority() const { return drawPriority; } @@ -142,19 +142,19 @@ public: /// Whether to enable depth testing bool getEnableDepth() { return enableDepth; } - void setEnableDepth(bool value) { enableDepth = value; } + virtual void setEnableDepth(bool value) { enableDepth = value; } /// Determines depth range within the layer for 2D drawables int32_t getSubLayerIndex() const { return subLayerIndex; } /// Set sub-layer index - void setSubLayerIndex(int32_t value) { subLayerIndex = value; } + virtual void setSubLayerIndex(int32_t value) { subLayerIndex = value; } /// Depth writability for 2D drawables DepthMaskType getDepthType() const { return depthType; } /// Set depth type - void setDepthType(DepthMaskType value) { depthType = value; } + virtual void setDepthType(DepthMaskType value) { depthType = value; } /// Uses 3D depth mode bool getIs3D() const { return is3D; } diff --git a/include/mbgl/gfx/shader_group.hpp b/include/mbgl/gfx/shader_group.hpp index cf1fd9b27..3aa8760dd 100644 --- a/include/mbgl/gfx/shader_group.hpp +++ b/include/mbgl/gfx/shader_group.hpp @@ -6,9 +6,12 @@ #include #include #include -#include +#include namespace mbgl { + +using StringIdentity = std::size_t; + namespace gfx { class Context; @@ -138,12 +141,13 @@ public: /// @brief Get a shader from the group by its set of data driven properties as uniforms. /// if no shader is found, create and register the shader. - /// @param propertiesAsUniforms Vector of data driven properties as uniforms. + /// @param propertiesAsUniforms Set of data driven properties as uniforms. /// @param firstAttribName Name of the first attribute /// @return A `gfx::ShaderPtr` - virtual gfx::ShaderPtr getOrCreateShader(gfx::Context&, - [[maybe_unused]] const std::vector& propertiesAsUniforms, - [[maybe_unused]] std::string_view firstAttribName = "a_pos") { + virtual gfx::ShaderPtr getOrCreateShader( + gfx::Context&, + [[maybe_unused]] const std::unordered_set& propertiesAsUniforms, + [[maybe_unused]] std::string_view firstAttribName = "a_pos") { return {}; } diff --git a/include/mbgl/gfx/types.hpp b/include/mbgl/gfx/types.hpp index 7d77fe014..0dabb1619 100644 --- a/include/mbgl/gfx/types.hpp +++ b/include/mbgl/gfx/types.hpp @@ -113,6 +113,7 @@ enum class TexturePixelType : uint8_t { enum class TextureChannelDataType : uint8_t { UnsignedByte, ///< 8 bit unsigned byte HalfFloat, ///< 16 bit "half-float" + Float, ///< 32 bit float }; /// Texture mip map type diff --git a/include/mbgl/gfx/vertex_attribute.hpp b/include/mbgl/gfx/vertex_attribute.hpp index 17c0c53e4..4ce7dc0d9 100644 --- a/include/mbgl/gfx/vertex_attribute.hpp +++ b/include/mbgl/gfx/vertex_attribute.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -364,9 +365,15 @@ public: } /// Specialized DataDrivenPaintProperty reader + /// @param binders Property binders for the target shader + /// @param evaluated Evaluated properties + /// @param propertiesAsUniforms [out] A set of string identities for the properties which will be constant, not + /// attributes. + /// @details The property name IDs refer to the "a\_" prefixed values to match the shader definitions. template - std::vector readDataDrivenPaintProperties(const Binders& binders, const Evaluated& evaluated) { - std::vector propertiesAsUniforms; + void readDataDrivenPaintProperties(const Binders& binders, + const Evaluated& evaluated, + std::unordered_set& propertiesAsUniforms) { propertiesAsUniforms.reserve(sizeof...(DataDrivenPaintProperty)); ( [&](const auto& attributeNames) { @@ -377,15 +384,14 @@ public: using Type = typename Attribute::Type; // ::mbgl::gfx::AttributeType using InterpType = ZoomInterpolatedAttributeType; + auto& attributeNameID = DataDrivenPaintProperty::AttributeNameIDs[attrIndex]; + if (!attributeNameID) { + attributeNameID = StringIndexer::get(attributePrefix + attributeName.data()); + } + const auto vertexCount = binder->getVertexCount(); const auto isConstant = evaluated.template get().isConstant(); if (vertexCount > 0 && !isConstant) { - auto& attributeNameID = DataDrivenPaintProperty::AttributeNameIDs[attrIndex]; - if (!attributeNameID) { - static const std::string attributePrefix = "a_"; - attributeNameID = StringIndexer::get(attributePrefix + attributeName.data()); - } - if (auto& attr = getOrAdd(*attributeNameID)) { if (const auto& sharedVector = binder->getSharedVertexVector()) { const auto rawSize = static_cast(sharedVector->getRawSize()); @@ -402,15 +408,13 @@ public: } } } - propertiesAsUniforms.emplace_back(std::string()); } else { - propertiesAsUniforms.emplace_back(attributeName); + propertiesAsUniforms.emplace(*attributeNameID); } } } }(DataDrivenPaintProperty::AttributeNames), ...); - return propertiesAsUniforms; } /// Copy another collection into this one @@ -435,7 +439,8 @@ protected: protected: AttributeMap attrs; - static std::unique_ptr nullref; + static const std::unique_ptr nullref; + static const std::string attributePrefix; }; } // namespace gfx diff --git a/include/mbgl/mtl/context.hpp b/include/mbgl/mtl/context.hpp index 7e47a7695..2b6129339 100644 --- a/include/mbgl/mtl/context.hpp +++ b/include/mbgl/mtl/context.hpp @@ -78,6 +78,8 @@ public: void setDirtyState() override; + std::unique_ptr createOffscreenTexture(Size, gfx::TextureChannelDataType, bool, bool); + std::unique_ptr createOffscreenTexture(Size, gfx::TextureChannelDataType) override; std::unique_ptr createTextureResource(Size, diff --git a/include/mbgl/mtl/drawable.hpp b/include/mbgl/mtl/drawable.hpp index c2e96608d..2d0fb7118 100644 --- a/include/mbgl/mtl/drawable.hpp +++ b/include/mbgl/mtl/drawable.hpp @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include @@ -59,6 +57,11 @@ public: void setShader(gfx::ShaderProgramBasePtr) override; + void setEnableStencil(bool) override; + void setEnableDepth(bool) override; + void setSubLayerIndex(int32_t) override; + void setDepthType(gfx::DepthMaskType) override; + protected: // For testing only. Drawable(std::unique_ptr); @@ -76,12 +79,6 @@ protected: class Impl; const std::unique_ptr impl; - - gfx::AttributeBindingArray attributeBindings; - - mutable MTLRenderPipelineStatePtr pipelineState; - - mutable std::optional renderPassDescriptor; }; } // namespace mtl diff --git a/include/mbgl/mtl/offscreen_texture.hpp b/include/mbgl/mtl/offscreen_texture.hpp index c131838b9..f291a7a90 100644 --- a/include/mbgl/mtl/offscreen_texture.hpp +++ b/include/mbgl/mtl/offscreen_texture.hpp @@ -11,7 +11,7 @@ class Texture2D; class OffscreenTexture final : public gfx::OffscreenTexture { public: - OffscreenTexture(Context&, Size size, gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte); + OffscreenTexture(Context&, Size size, gfx::TextureChannelDataType type, bool depth, bool stencil); bool isRenderable() override; diff --git a/include/mbgl/mtl/renderable_resource.hpp b/include/mbgl/mtl/renderable_resource.hpp index f469f0a34..d8620d636 100644 --- a/include/mbgl/mtl/renderable_resource.hpp +++ b/include/mbgl/mtl/renderable_resource.hpp @@ -23,7 +23,7 @@ public: virtual const mbgl::mtl::RendererBackend& getBackend() const = 0; virtual const mbgl::mtl::MTLCommandBufferPtr& getCommandBuffer() const = 0; virtual mbgl::mtl::MTLBlitPassDescriptorPtr getUploadPassDescriptor() const = 0; - virtual mbgl::mtl::MTLRenderPassDescriptorPtr getRenderPassDescriptor() const = 0; + virtual const mbgl::mtl::MTLRenderPassDescriptorPtr& getRenderPassDescriptor() const = 0; }; } // namespace mtl diff --git a/include/mbgl/renderer/layer_tweaker.hpp b/include/mbgl/renderer/layer_tweaker.hpp index 4eba01e09..1f00a8b6f 100644 --- a/include/mbgl/renderer/layer_tweaker.hpp +++ b/include/mbgl/renderer/layer_tweaker.hpp @@ -1,26 +1,31 @@ #pragma once +#include #include #include #include #include -#include +#include namespace mbgl { + namespace gfx { class Drawable; class UniformBuffer; using UniformBufferPtr = std::shared_ptr; } // namespace gfx + namespace shaders { enum class AttributeSource : int32_t; struct ExpressionInputsUBO; } // namespace shaders + namespace style { class LayerProperties; enum class TranslateAnchorType : bool; } // namespace style + class TransformState; class LayerGroupBase; class PaintParameters; @@ -28,6 +33,7 @@ class RenderTree; class UnwrappedTileID; using mat4 = std::array; +using StringIdentity = std::size_t; /** Base class for layer tweakers, which manipulate layer group per frame @@ -47,19 +53,21 @@ public: static shaders::ExpressionInputsUBO buildExpressionUBO(double zoom, uint64_t frameCount); /// @brief Check whether a property name exists within the previously set collection. - /// @details The string value provided is expected to have the "a_" prefix, as defined in the shader classes. - bool hasPropertyAsUniform(std::string_view) const; - shaders::AttributeSource getAttributeSource(const std::string_view& attribName) const; + bool hasPropertyAsUniform(StringIdentity) const; + shaders::AttributeSource getAttributeSource(StringIdentity) const; + + template + shaders::AttributeSource getAttributeSource(size_t index) { + using ShaderClass = shaders::ShaderSource; + return getAttributeSource(ShaderClass::attributes[index].nameID); + } #endif // MLN_RENDER_BACKEND_METAL /// @brief Set the collection of attribute names which will be provided at uniform values rather than per-vertex /// attributes. /// @details These values should not have "a_" prefixes, as produced by `readDataDrivenPaintProperties`. -#if MLN_RENDER_BACKEND_OPENGL - void setPropertiesAsUniforms(const std::vector&) {} -#else - void setPropertiesAsUniforms(std::vector); -#endif + void setPropertiesAsUniforms(const std::unordered_set&); + const std::unordered_set& getPropertiesAsUniforms() const; void enableOverdrawInspector(bool); @@ -90,7 +98,7 @@ protected: #if MLN_RENDER_BACKEND_METAL // For Metal, whether a property is provided through attribtues or uniforms is specified in // a uniform buffer rather than by a shader compiled with different preprocessor definitions. - std::vector propertiesAsUniforms; + std::unordered_set propertiesAsUniforms; #endif // MLN_RENDER_BACKEND_METAL // Indicates that the evaluated properties have changed diff --git a/include/mbgl/shaders/collision_layer_ubo.hpp b/include/mbgl/shaders/collision_layer_ubo.hpp new file mode 100644 index 000000000..ac7d762d0 --- /dev/null +++ b/include/mbgl/shaders/collision_layer_ubo.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace mbgl { +namespace shaders { + +struct alignas(16) CollisionUBO { + std::array matrix; + std::array extrude_scale; + float camera_to_center_distance; + float overscale_factor; +}; +static_assert(sizeof(CollisionUBO) % 16 == 0); +static_assert(sizeof(CollisionUBO) == 80); + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/shader_group_gl.hpp b/include/mbgl/shaders/gl/shader_group_gl.hpp index cec5740f7..9c54ed5ea 100644 --- a/include/mbgl/shaders/gl/shader_group_gl.hpp +++ b/include/mbgl/shaders/gl/shader_group_gl.hpp @@ -4,6 +4,10 @@ #include #include #include +#include + +#include +#include namespace mbgl { namespace gl { @@ -13,40 +17,61 @@ class ShaderGroupGL final : public gfx::ShaderGroup { public: ShaderGroupGL(const ProgramParameters& programParameters_) : ShaderGroup(), - programParameters(programParameters_){}; + programParameters(programParameters_) {} ~ShaderGroupGL() noexcept override = default; gfx::ShaderPtr getOrCreateShader(gfx::Context& context, - const std::vector& propertiesAsUniforms, + const std::unordered_set& propertiesAsUniforms, std::string_view firstAttribName) override { - constexpr auto& name = shaders::ShaderSource::name; constexpr auto& vert = shaders::ShaderSource::vertex; constexpr auto& frag = shaders::ShaderSource::fragment; - uint32_t key = 0; + // Generate a map key for the specified combination of properties + const size_t key = util::order_independent_hash(propertiesAsUniforms.begin(), propertiesAsUniforms.end()); + + // We could cache these by key here to avoid creating a string key each time, but we + // would need another mutex. We could also push string IDs down into `ShaderGroup`. + const std::string shaderName = getShaderName(key); + auto shader = get(shaderName); + if (shader) { + return shader; + } + + // No match, we need to create the shader. std::string additionalDefines; - for (unsigned int i = 0; i < propertiesAsUniforms.size(); i++) { - if (propertiesAsUniforms[i].empty()) { - continue; + additionalDefines.reserve(propertiesAsUniforms.size() * 48); + for (const auto nameID : propertiesAsUniforms) { + // We expect the names to be prefixed by "a_", but we need just the base here. + const auto prefixedAttrName = StringIndexer::get(nameID); + const auto* prefix = prefixedAttrName.data(); + if (prefix[0] == 'a' && prefix[1] == '_') { + prefix += 2; } - key |= 1 << i; + additionalDefines += "#define HAS_UNIFORM_u_"; - additionalDefines += propertiesAsUniforms[i]; + additionalDefines += prefix; additionalDefines += "\n"; } - const std::string shaderName = std::string(name) + "#" + std::to_string(key); - auto shader = get(shaderName); - if (!shader) { - auto& glContext = static_cast(context); - shader = ShaderProgramGL::create( - glContext, programParameters, shaderName, firstAttribName, vert, frag, additionalDefines); - if (!shader || !registerShader(shader, shaderName)) { - throw std::runtime_error("Failed to register " + shaderName + " with shader group!"); - } + + auto& glContext = static_cast(context); + shader = ShaderProgramGL::create( + glContext, programParameters, shaderName, firstAttribName, vert, frag, additionalDefines); + if (!shader || !registerShader(shader, shaderName)) { + throw std::runtime_error("Failed to register " + shaderName + " with shader group!"); } return shader; } +protected: + std::string getShaderName(std::size_t key) { + constexpr auto& name = shaders::ShaderSource::name; + + // This could be more efficient. + std::ostringstream stream; + stream << name << '#' << key; + return stream.str(); + } + private: ProgramParameters programParameters; }; diff --git a/include/mbgl/shaders/layer_ubo.hpp b/include/mbgl/shaders/layer_ubo.hpp index 7caac8f20..ea69aa070 100644 --- a/include/mbgl/shaders/layer_ubo.hpp +++ b/include/mbgl/shaders/layer_ubo.hpp @@ -5,8 +5,6 @@ #include #include -#define MLN_STRINGIZE(X) #X - namespace mbgl { namespace shaders { diff --git a/include/mbgl/shaders/mtl/background.hpp b/include/mbgl/shaders/mtl/background.hpp index b5e799fca..5dc954ebe 100644 --- a/include/mbgl/shaders/mtl/background.hpp +++ b/include/mbgl/shaders/mtl/background.hpp @@ -14,14 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Float3, 1, "a_pos"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(1, true, true, BackgroundLayerUBO), - MLN_MTL_UNIFORM_BLOCK(2, true, false, BackgroundDrawableUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( #include diff --git a/include/mbgl/shaders/mtl/background_pattern.hpp b/include/mbgl/shaders/mtl/background_pattern.hpp index 428fb855a..8cbd69f68 100644 --- a/include/mbgl/shaders/mtl/background_pattern.hpp +++ b/include/mbgl/shaders/mtl/background_pattern.hpp @@ -9,11 +9,7 @@ template <> struct ShaderSource : public ShaderSource { static constexpr auto name = "BackgroundPatternShader"; - static constexpr UniformBlockInfo uniforms[] = { - {1, sizeof(BackgroundLayerUBO), true, false, "BackgroundLayerUBO"}, - {2, sizeof(BackgroundDrawableUBO), true, false, "BackgroundDrawableUBO"}, - {3, sizeof(BackgroundPatternLayerUBO), true, false, "BackgroundPatternLayerUBO"}, - }; + static const std::array uniforms; }; } // namespace shaders diff --git a/include/mbgl/shaders/mtl/circle.hpp b/include/mbgl/shaders/mtl/circle.hpp index 42eb9fc18..fc049990c 100644 --- a/include/mbgl/shaders/mtl/circle.hpp +++ b/include/mbgl/shaders/mtl/circle.hpp @@ -14,25 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Float2, 1, "a_color"}, - {2, gfx::AttributeDataType::Float2, 1, "a_radius"}, - {3, gfx::AttributeDataType::Float2, 1, "a_blur"}, - {4, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - {5, gfx::AttributeDataType::Float4, 1, "a_stroke_color"}, - {6, gfx::AttributeDataType::Float2, 1, "a_stroke_width"}, - {7, gfx::AttributeDataType::Float2, 1, "a_stroke_opacity"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(8, true, false, CircleDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(9, true, true, CirclePaintParamsUBO), - MLN_MTL_UNIFORM_BLOCK(10, true, true, CircleEvaluatedPropsUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, false, CircleInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(12, true, true, CirclePermutationUBO), - MLN_MTL_UNIFORM_BLOCK(13, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( diff --git a/include/mbgl/shaders/mtl/clipping_mask.hpp b/include/mbgl/shaders/mtl/clipping_mask.hpp index 5c62c52a7..e86707dfe 100644 --- a/include/mbgl/shaders/mtl/clipping_mask.hpp +++ b/include/mbgl/shaders/mtl/clipping_mask.hpp @@ -20,13 +20,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Float3, 1, "a_pos"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(1, true, false, ClipUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( #include diff --git a/include/mbgl/shaders/mtl/collision_box.hpp b/include/mbgl/shaders/mtl/collision_box.hpp new file mode 100644 index 000000000..a26249fcd --- /dev/null +++ b/include/mbgl/shaders/mtl/collision_box.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr auto name = "CollisionBoxShader"; + static constexpr auto vertexMainFunction = "vertexMain"; + static constexpr auto fragmentMainFunction = "fragmentMain"; + + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; + + static constexpr auto source = R"( + +struct VertexStage { + short2 pos [[attribute(0)]]; + short2 anchor_pos [[attribute(1)]]; + short2 extrude [[attribute(2)]]; + uchar2 placed [[attribute(3)]]; + float2 shift [[attribute(4)]]; +}; + +struct FragmentStage { + float4 position [[position, invariant]]; + float placed; + float notUsed; +}; + +struct alignas(16) CollisionBoxUBO { + float4x4 matrix; + float2 extrude_scale; + float camera_to_center_distance; + float pad1; +}; + +FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], + device const CollisionBoxUBO& drawable [[buffer(5)]]) { + + float4 projectedPoint = drawable.matrix * float4(float2(vertx.anchor_pos), 0, 1); + float camera_to_anchor_distance = projectedPoint.w; + float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (drawable.camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles + 4.0); + + float4 position = drawable.matrix * float4(float2(vertx.pos), 0.0, 1.0); + position.xy += (float2(vertx.extrude) + vertx.shift) * drawable.extrude_scale * position.w * collision_perspective_ratio; + + float placed = float(vertx.placed.x); + float notUsed = float(vertx.placed.y); + + return { + .position = position, + .placed = placed, + .notUsed = notUsed, + }; +} + +half4 fragment fragmentMain(FragmentStage in [[stage_in]], + device const CollisionBoxUBO& drawable [[buffer(5)]]) { + + float alpha = 0.5; + + // Red = collision, hide label + float4 color = float4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (in.placed > 0.5) { + color = float4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (in.notUsed > 0.5) { + // This box not used, fade it out + color *= 0.1; + } + + return half4(color); +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/mtl/collision_circle.hpp b/include/mbgl/shaders/mtl/collision_circle.hpp new file mode 100644 index 000000000..39822a7bb --- /dev/null +++ b/include/mbgl/shaders/mtl/collision_circle.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr auto name = "CollisionCircleShader"; + static constexpr auto vertexMainFunction = "vertexMain"; + static constexpr auto fragmentMainFunction = "fragmentMain"; + + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; + + static constexpr auto source = R"( + +struct VertexStage { + short2 pos [[attribute(0)]]; + short2 anchor_pos [[attribute(1)]]; + short2 extrude [[attribute(2)]]; + uchar2 placed [[attribute(3)]]; +}; + +struct FragmentStage { + float4 position [[position, invariant]]; + float placed; + float notUsed; + float radius; + float2 extrude; + float2 extrude_scale; +}; + +struct alignas(16) CollisionCircleUBO { + float4x4 matrix; + float2 extrude_scale; + float camera_to_center_distance; + float overscale_factor; +}; + +FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], + device const CollisionCircleUBO& drawable [[buffer(4)]]) { + + float4 projectedPoint = drawable.matrix * float4(float2(vertx.anchor_pos), 0, 1); + float camera_to_anchor_distance = projectedPoint.w; + float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (drawable.camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles + 4.0); + + float4 position = drawable.matrix * float4(float2(vertx.pos), 0.0, 1.0); + + float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur + position.xy += float2(vertx.extrude) * drawable.extrude_scale * padding_factor * position.w * collision_perspective_ratio; + + float placed = float(vertx.placed.x); + float notUsed = float(vertx.placed.y); + float radius = abs(float(vertx.extrude.y)); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius + + float2 extrude = float2(vertx.extrude) * padding_factor; + float2 extrude_scale = drawable.extrude_scale * drawable.camera_to_center_distance * collision_perspective_ratio; + + return { + .position = position, + .placed = placed, + .notUsed = notUsed, + .radius = radius, + .extrude = extrude, + .extrude_scale = extrude_scale, + }; +} + +half4 fragment fragmentMain(FragmentStage in [[stage_in]], + device const CollisionCircleUBO& drawable [[buffer(4)]]) { + + float alpha = 0.5; + + // Red = collision, hide label + float4 color = float4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (in.placed > 0.5) { + color = float4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (in.notUsed > 0.5) { + // This box not used, fade it out + color *= 0.2; + } + + float extrude_scale_length = length(in.extrude_scale); + float extrude_length = length(in.extrude) * extrude_scale_length; + float stroke_width = 15.0 * extrude_scale_length / drawable.overscale_factor; + float radius = in.radius * extrude_scale_length; + + float distance_to_edge = abs(extrude_length - radius); + float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge); + + return half4(opacity_t * color); +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/mtl/common.hpp b/include/mbgl/shaders/mtl/common.hpp index 04257e9d6..de61c8a0c 100644 --- a/include/mbgl/shaders/mtl/common.hpp +++ b/include/mbgl/shaders/mtl/common.hpp @@ -1,8 +1,5 @@ #pragma once -#define MLN_MTL_UNIFORM_BLOCK(idx, vert, frag, struc) \ - { idx, vert, frag, sizeof(struc), MLN_STRINGIZE(struc) } - namespace mbgl { namespace shaders { diff --git a/include/mbgl/shaders/mtl/fill.hpp b/include/mbgl/shaders/mtl/fill.hpp index 472e579b0..e16881ac9 100644 --- a/include/mbgl/shaders/mtl/fill.hpp +++ b/include/mbgl/shaders/mtl/fill.hpp @@ -14,24 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Float2, 1, "a_color"}, - {2, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - - // This shader doesn't use it, but we need this so that the layer can assign the same - // attributes to all the drawables. If/When `VertexAttributeArray::resolve` allows it, - // this can be removed. - {8, gfx::AttributeDataType::Float2, 1, "a_outline_color"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(3, true, false, FillDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(4, true, true, FillEvaluatedPropsUBO), - MLN_MTL_UNIFORM_BLOCK(5, true, false, FillInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(6, true, true, FillPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(7, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( @@ -104,22 +89,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Float2, 1, "a_outline_color"}, - {2, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - - // See `a_outline_color` in FillShader - {8, gfx::AttributeDataType::Float2, 1, "a_color"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(3, true, false, FillOutlineDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(4, true, true, FillOutlineEvaluatedPropsUBO), - MLN_MTL_UNIFORM_BLOCK(5, true, false, FillOutlineInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(6, true, true, FillOutlinePermutationUBO), - MLN_MTL_UNIFORM_BLOCK(7, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( @@ -203,24 +175,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::UShort4, 1, "a_pattern_from"}, - {2, gfx::AttributeDataType::UShort4, 1, "a_pattern_to"}, - {3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(4, true, true, FillPatternDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(5, true, false, FillPatternTilePropsUBO), - MLN_MTL_UNIFORM_BLOCK(6, true, true, FillPatternEvaluatedPropsUBO), - MLN_MTL_UNIFORM_BLOCK(7, true, false, FillPatternInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(8, true, true, FillPatternPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(9, true, false, ExpressionInputsUBO), - }; - - static constexpr TextureInfo textures[] = { - {0, "u_image"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( @@ -341,24 +298,9 @@ struct ShaderSource attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( diff --git a/include/mbgl/shaders/mtl/fill_extrusion.hpp b/include/mbgl/shaders/mtl/fill_extrusion.hpp index 22a751df0..da20b28cf 100644 --- a/include/mbgl/shaders/mtl/fill_extrusion.hpp +++ b/include/mbgl/shaders/mtl/fill_extrusion.hpp @@ -14,21 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Short4, 1, "a_normal_ed"}, - {2, gfx::AttributeDataType::Float4, 1, "a_color"}, - {3, gfx::AttributeDataType::Float, 1, "a_base"}, - {4, gfx::AttributeDataType::Float, 1, "a_height"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(5, true, false, FillExtrusionDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(6, true, false, FillExtrusionDrawablePropsUBO), - MLN_MTL_UNIFORM_BLOCK(7, true, false, FillExtrusionInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(8, true, false, FillExtrusionPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(9, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( struct alignas(16) FillExtrusionInterpolateUBO { diff --git a/include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp b/include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp index ec96161af..20904c7fa 100644 --- a/include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp +++ b/include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp @@ -14,9 +14,9 @@ struct ShaderSource attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( )"; diff --git a/include/mbgl/shaders/mtl/heatmap.hpp b/include/mbgl/shaders/mtl/heatmap.hpp index 9aef72564..8ea16d229 100644 --- a/include/mbgl/shaders/mtl/heatmap.hpp +++ b/include/mbgl/shaders/mtl/heatmap.hpp @@ -14,19 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Float2, 1, "a_weight"}, - {2, gfx::AttributeDataType::Float2, 1, "a_radius"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(3, true, false, HeatmapDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(4, true, true, HeatmapEvaluatedPropsUBO), - MLN_MTL_UNIFORM_BLOCK(5, true, false, HeatmapInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(6, true, true, HeatmapPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(7, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( diff --git a/include/mbgl/shaders/mtl/heatmap_texture.hpp b/include/mbgl/shaders/mtl/heatmap_texture.hpp index 3c4873f8f..d9a621489 100644 --- a/include/mbgl/shaders/mtl/heatmap_texture.hpp +++ b/include/mbgl/shaders/mtl/heatmap_texture.hpp @@ -14,16 +14,10 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(1, true, true, HeatmapTextureDrawableUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_image"}, - {1, "u_color_ramp"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; + static constexpr auto source = R"( struct VertexStage { diff --git a/include/mbgl/shaders/mtl/hillshade.hpp b/include/mbgl/shaders/mtl/hillshade.hpp index 1fa97b3b8..4248ce134 100644 --- a/include/mbgl/shaders/mtl/hillshade.hpp +++ b/include/mbgl/shaders/mtl/hillshade.hpp @@ -14,17 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Short2, 1, "a_texture_pos"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(2, true, true, HillshadeDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(3, false, true, HillshadeEvaluatedPropsUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_image"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( diff --git a/include/mbgl/shaders/mtl/hillshade_prepare.hpp b/include/mbgl/shaders/mtl/hillshade_prepare.hpp index be57aef91..532f9f579 100644 --- a/include/mbgl/shaders/mtl/hillshade_prepare.hpp +++ b/include/mbgl/shaders/mtl/hillshade_prepare.hpp @@ -14,16 +14,10 @@ struct ShaderSource static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Short2, 1, "a_texture_pos"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(2, true, true, HillshadePrepareDrawableUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_image"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; + static constexpr auto source = R"( struct VertexStage { diff --git a/include/mbgl/shaders/mtl/line.hpp b/include/mbgl/shaders/mtl/line.hpp index 9fed89140..e5b44db07 100644 --- a/include/mbgl/shaders/mtl/line.hpp +++ b/include/mbgl/shaders/mtl/line.hpp @@ -14,24 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos_normal"}, - {1, gfx::AttributeDataType::UByte4, 1, "a_data"}, - {2, gfx::AttributeDataType::Float4, 1, "a_color"}, - {3, gfx::AttributeDataType::Float2, 1, "a_blur"}, - {4, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - {5, gfx::AttributeDataType::Float2, 1, "a_gapwidth"}, - {6, gfx::AttributeDataType::Float2, 1, "a_offset"}, - {7, gfx::AttributeDataType::Float2, 1, "a_width"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(8, true, true, LineUBO), - MLN_MTL_UNIFORM_BLOCK(9, true, false, LinePropertiesUBO), - MLN_MTL_UNIFORM_BLOCK(10, true, false, LineInterpolationUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, true, LinePermutationUBO), - MLN_MTL_UNIFORM_BLOCK(12, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = {}; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( @@ -143,28 +128,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos_normal"}, - {1, gfx::AttributeDataType::UByte4, 1, "a_data"}, - {2, gfx::AttributeDataType::Float2, 1, "a_blur"}, - {3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - {4, gfx::AttributeDataType::Float2, 1, "a_gapwidth"}, - {5, gfx::AttributeDataType::Float2, 1, "a_offset"}, - {6, gfx::AttributeDataType::Float2, 1, "a_width"}, - {7, gfx::AttributeDataType::UShort4, 1, "a_pattern_from"}, - {8, gfx::AttributeDataType::UShort4, 1, "a_pattern_to"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(9, true, true, LinePatternUBO), - MLN_MTL_UNIFORM_BLOCK(10, true, false, LinePatternPropertiesUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, false, LinePatternInterpolationUBO), - MLN_MTL_UNIFORM_BLOCK(12, true, false, LinePatternTilePropertiesUBO), - MLN_MTL_UNIFORM_BLOCK(13, true, true, LinePermutationUBO), - MLN_MTL_UNIFORM_BLOCK(14, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_image"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( diff --git a/include/mbgl/shaders/mtl/line_gradient.hpp b/include/mbgl/shaders/mtl/line_gradient.hpp index 6d2b90416..ca718159c 100644 --- a/include/mbgl/shaders/mtl/line_gradient.hpp +++ b/include/mbgl/shaders/mtl/line_gradient.hpp @@ -14,25 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos_normal"}, - {1, gfx::AttributeDataType::UByte4, 1, "a_data"}, - {2, gfx::AttributeDataType::Float2, 1, "a_blur"}, - {3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, - {4, gfx::AttributeDataType::Float2, 1, "a_gapwidth"}, - {5, gfx::AttributeDataType::Float2, 1, "a_offset"}, - {6, gfx::AttributeDataType::Float2, 1, "a_width"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(7, true, true, LineGradientUBO), - MLN_MTL_UNIFORM_BLOCK(8, true, false, LineGradientPropertiesUBO), - MLN_MTL_UNIFORM_BLOCK(9, true, false, LineGradientInterpolationUBO), - MLN_MTL_UNIFORM_BLOCK(10, true, true, LinePermutationUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_image"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( struct VertexStage { diff --git a/include/mbgl/shaders/mtl/raster.hpp b/include/mbgl/shaders/mtl/raster.hpp index ca9f6b3a1..4b9022991 100644 --- a/include/mbgl/shaders/mtl/raster.hpp +++ b/include/mbgl/shaders/mtl/raster.hpp @@ -14,17 +14,10 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, - {1, gfx::AttributeDataType::Short2, 1, "a_texture_pos"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(2, true, true, RasterDrawableUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_image0"}, - {1, "u_image1"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; + static constexpr auto source = R"( struct VertexStage { diff --git a/include/mbgl/shaders/mtl/shader_group.hpp b/include/mbgl/shaders/mtl/shader_group.hpp index 05a402a85..40aa8a977 100644 --- a/include/mbgl/shaders/mtl/shader_group.hpp +++ b/include/mbgl/shaders/mtl/shader_group.hpp @@ -22,32 +22,20 @@ public: ~ShaderGroup() noexcept override = default; gfx::ShaderPtr getOrCreateShader(gfx::Context& gfxContext, - const std::vector& propertiesAsUniforms, + const std::unordered_set& propertiesAsUniforms, std::string_view /*firstAttribName*/) override { constexpr auto& name = shaders::ShaderSource::name; constexpr auto& source = shaders::ShaderSource::source; constexpr auto& vertMain = shaders::ShaderSource::vertexMainFunction; constexpr auto& fragMain = shaders::ShaderSource::fragmentMainFunction; - uint32_t key = 0; - assert(propertiesAsUniforms.size() < 32); - std::unordered_map additionalDefines(propertiesAsUniforms.size()); - for (unsigned int i = 0; i < propertiesAsUniforms.size(); i++) { - if (!propertiesAsUniforms[i].empty()) { - key |= 1U << i; - auto name = std::string("HAS_UNIFORM_u_") + propertiesAsUniforms[i]; - additionalDefines.insert(std::make_pair(std::move(name), "1")); - } - } - - const std::string shaderName = std::string(name); // + "#" + std::to_string(key); + const std::string shaderName = std::string(name); const auto shaderSource = std::string(shaders::prelude) + source; auto shader = get(shaderName); if (!shader) { auto& context = static_cast(gfxContext); - shader = context.createProgram( - shaderName, shaderSource, vertMain, fragMain, programParameters, additionalDefines); + shader = context.createProgram(shaderName, shaderSource, vertMain, fragMain, programParameters, {}); assert(shader); if (!shader || !registerShader(shader, shaderName)) { assert(false); diff --git a/include/mbgl/shaders/mtl/shader_program.hpp b/include/mbgl/shaders/mtl/shader_program.hpp index 11ea96bc4..772f1dc2d 100644 --- a/include/mbgl/shaders/mtl/shader_program.hpp +++ b/include/mbgl/shaders/mtl/shader_program.hpp @@ -15,21 +15,27 @@ namespace mbgl { namespace shaders { struct AttributeInfo { + AttributeInfo(std::size_t index, gfx::AttributeDataType dataType, std::size_t count, std::string_view name); std::size_t index; gfx::AttributeDataType dataType; std::size_t count; std::string_view name; + StringIdentity nameID; }; struct UniformBlockInfo { + UniformBlockInfo(std::size_t index, bool vertex, bool fragment, std::size_t size, std::string_view name); std::size_t index; bool vertex; bool fragment; std::size_t size; std::string_view name; + StringIdentity nameID; }; struct TextureInfo { + TextureInfo(std::size_t index, std::string_view name); std::size_t index; std::string_view name; + StringIdentity nameID; }; } // namespace shaders namespace mtl { diff --git a/include/mbgl/shaders/mtl/symbol_icon.hpp b/include/mbgl/shaders/mtl/symbol_icon.hpp index 5f307c164..0cd4ada77 100644 --- a/include/mbgl/shaders/mtl/symbol_icon.hpp +++ b/include/mbgl/shaders/mtl/symbol_icon.hpp @@ -14,28 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - // always attributes - {0, gfx::AttributeDataType::Short4, 1, "a_pos_offset"}, - {1, gfx::AttributeDataType::UShort4, 1, "a_data"}, - {2, gfx::AttributeDataType::Short4, 1, "a_pixeloffset"}, - {3, gfx::AttributeDataType::Float3, 1, "a_projected_pos"}, - {4, gfx::AttributeDataType::Float, 1, "a_fade_opacity"}, - - // sometimes uniforms - {5, gfx::AttributeDataType::Float, 1, "a_opacity"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(8, true, true, SymbolDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(9, true, true, SymbolDrawablePaintUBO), - MLN_MTL_UNIFORM_BLOCK(10, true, false, SymbolDrawableTilePropsUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, false, SymbolDrawableInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(12, true, true, SymbolPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(13, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_texture"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( struct VertexStage { diff --git a/include/mbgl/shaders/mtl/symbol_sdf.hpp b/include/mbgl/shaders/mtl/symbol_sdf.hpp index c1e8db6ee..c9858636b 100644 --- a/include/mbgl/shaders/mtl/symbol_sdf.hpp +++ b/include/mbgl/shaders/mtl/symbol_sdf.hpp @@ -14,32 +14,9 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - // always attributes - {0, gfx::AttributeDataType::Short4, 1, "a_pos_offset"}, - {1, gfx::AttributeDataType::UShort4, 1, "a_data"}, - {2, gfx::AttributeDataType::Short4, 1, "a_pixeloffset"}, - {3, gfx::AttributeDataType::Float3, 1, "a_projected_pos"}, - {4, gfx::AttributeDataType::Float, 1, "a_fade_opacity"}, - - // sometimes uniforms - {5, gfx::AttributeDataType::Float4, 1, "a_fill_color"}, - {6, gfx::AttributeDataType::Float4, 1, "a_halo_color"}, - {7, gfx::AttributeDataType::Float, 1, "a_opacity"}, - {8, gfx::AttributeDataType::Float, 1, "a_halo_width"}, - {9, gfx::AttributeDataType::Float, 1, "a_halo_blur"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(10, true, true, SymbolDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, false, SymbolDrawablePaintUBO), - MLN_MTL_UNIFORM_BLOCK(12, true, true, SymbolDrawableTilePropsUBO), - MLN_MTL_UNIFORM_BLOCK(13, true, false, SymbolDrawableInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(14, true, true, SymbolPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(15, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_texture"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( struct VertexStage { diff --git a/include/mbgl/shaders/mtl/symbol_text_and_icon.hpp b/include/mbgl/shaders/mtl/symbol_text_and_icon.hpp index b9d7bdfb7..f0d68a52f 100644 --- a/include/mbgl/shaders/mtl/symbol_text_and_icon.hpp +++ b/include/mbgl/shaders/mtl/symbol_text_and_icon.hpp @@ -14,32 +14,9 @@ struct ShaderSource static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static constexpr AttributeInfo attributes[] = { - // always attributes - {0, gfx::AttributeDataType::Short4, 1, "a_pos_offset"}, - {1, gfx::AttributeDataType::UShort4, 1, "a_data"}, - {2, gfx::AttributeDataType::Float3, 1, "a_projected_pos"}, - {3, gfx::AttributeDataType::Float, 1, "a_fade_opacity"}, - - // sometimes uniforms - {4, gfx::AttributeDataType::Float4, 1, "a_fill_color"}, - {5, gfx::AttributeDataType::Float4, 1, "a_halo_color"}, - {6, gfx::AttributeDataType::Float, 1, "a_opacity"}, - {7, gfx::AttributeDataType::Float, 1, "a_halo_width"}, - {8, gfx::AttributeDataType::Float, 1, "a_halo_blur"}, - }; - static constexpr UniformBlockInfo uniforms[] = { - MLN_MTL_UNIFORM_BLOCK(9, true, true, SymbolDrawableUBO), - MLN_MTL_UNIFORM_BLOCK(10, true, false, SymbolDrawablePaintUBO), - MLN_MTL_UNIFORM_BLOCK(11, true, true, SymbolDrawableTilePropsUBO), - MLN_MTL_UNIFORM_BLOCK(12, true, false, SymbolDrawableInterpolateUBO), - MLN_MTL_UNIFORM_BLOCK(13, true, true, SymbolPermutationUBO), - MLN_MTL_UNIFORM_BLOCK(14, true, false, ExpressionInputsUBO), - }; - static constexpr TextureInfo textures[] = { - {0, "u_texture"}, - {1, "u_texture_icon"}, - }; + static const std::array attributes; + static const std::array uniforms; + static const std::array textures; static constexpr auto source = R"( #define SDF 1.0 @@ -141,7 +118,7 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], const float2x2 rotation_matrix = float2x2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); const float4 projected_pos = drawable.label_plane_matrix * float4(vertx.projected_pos.xy, 0.0, 1.0); - const float2 pos_rot = a_offset / 32.0 * fontScale + a_pxoffset; + const float2 pos_rot = a_offset / 32.0 * fontScale; const float2 pos0 = projected_pos.xy / projected_pos.w + rotation_matrix * pos_rot; const float4 position = drawable.coord_matrix * float4(pos0, 0.0, 1.0); const float gamma_scale = position.w; @@ -178,7 +155,7 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]], if (in.data1.w == ICON) { const float2 tex_icon = in.data0.zw; - const float alpha = opacity * fade_opacity; + const float alpha = in.opacity * fade_opacity; return half4(icon_image.sample(icon_sampler, tex_icon) * alpha); } diff --git a/include/mbgl/util/string_indexer.hpp b/include/mbgl/util/string_indexer.hpp index 8cd5afbd3..cf4f5b6c7 100644 --- a/include/mbgl/util/string_indexer.hpp +++ b/include/mbgl/util/string_indexer.hpp @@ -11,7 +11,7 @@ namespace mbgl { -using StringIdentity = size_t; +using StringIdentity = std::size_t; class StringIndexer { public: diff --git a/platform/default/BUILD.bazel b/platform/default/BUILD.bazel index b76d6f17c..2d3cd2ad7 100644 --- a/platform/default/BUILD.bazel +++ b/platform/default/BUILD.bazel @@ -55,7 +55,7 @@ cc_library( "src/mbgl/util/thread_local.cpp", "src/mbgl/util/utf.cpp", ] + select({ - "//:metal_renderer": [], + "//:metal_renderer": ["src/mbgl/mtl/headless_backend.cpp"], "//conditions:default": ["src/mbgl/gl/headless_backend.cpp"], }) + select({ "//:linux": [ @@ -89,7 +89,7 @@ cc_library( "include/mbgl/storage/sqlite3.hpp", "include/mbgl/text/unaccent.hpp", ] + select({ - "//:metal_renderer": [], + "//:metal_renderer": ["include/mbgl/mtl/headless_backend.hpp"], "//conditions:default": ["include/mbgl/gl/headless_backend.hpp"], }), copts = CPP_FLAGS + MAPLIBRE_FLAGS, diff --git a/platform/default/include/mbgl/gfx/headless_backend.hpp b/platform/default/include/mbgl/gfx/headless_backend.hpp index a2656c431..1dc775531 100644 --- a/platform/default/include/mbgl/gfx/headless_backend.hpp +++ b/platform/default/include/mbgl/gfx/headless_backend.hpp @@ -24,11 +24,7 @@ public: static std::unique_ptr Create(const Size size = {256, 256}, SwapBehaviour swapBehavior = SwapBehaviour::NoFlush, const gfx::ContextMode contextMode = gfx::ContextMode::Unique) { -#if MLN_RENDER_BACKEND_METAL - throw std::runtime_error("Not yet implemented"); -#else // MLN_RENDER_BACKEND_OPENGL return Backend::Create(size, swapBehavior, contextMode); -#endif } virtual PremultipliedImage readStillImage() = 0; diff --git a/platform/default/include/mbgl/mtl/headless_backend.hpp b/platform/default/include/mbgl/mtl/headless_backend.hpp new file mode 100644 index 000000000..af7d1aa7e --- /dev/null +++ b/platform/default/include/mbgl/mtl/headless_backend.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace mtl { + +class HeadlessBackend final : public mtl::RendererBackend, public gfx::HeadlessBackend { +public: + HeadlessBackend(Size = {256, 256}, + SwapBehaviour = SwapBehaviour::NoFlush, + gfx::ContextMode = gfx::ContextMode::Unique); + ~HeadlessBackend() override; + void updateAssumedState() override; + gfx::Renderable& getDefaultRenderable() override; + PremultipliedImage readStillImage() override; + RendererBackend* getRendererBackend() override; + SwapBehaviour getSwapBehaviour(); + +private: + void activate() override; + void deactivate() override; + +private: + bool active = false; + SwapBehaviour swapBehaviour = SwapBehaviour::NoFlush; +}; + +} // namespace mtl +} // namespace mbgl diff --git a/platform/default/src/mbgl/mtl/headless_backend.cpp b/platform/default/src/mbgl/mtl/headless_backend.cpp new file mode 100644 index 000000000..2f83829aa --- /dev/null +++ b/platform/default/src/mbgl/mtl/headless_backend.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace mbgl { +namespace mtl { + +class HeadlessRenderableResource final : public mtl::RenderableResource { +public: + HeadlessRenderableResource(HeadlessBackend& backend_, mtl::Context& context_, Size size) + : backend(backend_), + context(context_) { + offscreenTexture = context.createOffscreenTexture(size, gfx::TextureChannelDataType::UnsignedByte, true, true); + } + + ~HeadlessRenderableResource() noexcept override = default; + + void bind() override { offscreenTexture->getResource().bind(); } + + void swap() override { offscreenTexture->getResource().swap(); } + + PremultipliedImage readStillImage() { return offscreenTexture->readStillImage(); } + + const RendererBackend& getBackend() const override { return context.getBackend(); } + + const MTLCommandBufferPtr& getCommandBuffer() const override { + return offscreenTexture->getResource().getCommandBuffer(); + } + + MTLBlitPassDescriptorPtr getUploadPassDescriptor() const override { + return offscreenTexture->getResource().getUploadPassDescriptor(); + } + + const MTLRenderPassDescriptorPtr& getRenderPassDescriptor() const override { + return offscreenTexture->getResource().getRenderPassDescriptor(); + } + + HeadlessBackend& backend; + Context& context; + std::unique_ptr offscreenTexture; +}; + +HeadlessBackend::HeadlessBackend(const Size size_, + gfx::HeadlessBackend::SwapBehaviour swapBehaviour_, + const gfx::ContextMode contextMode_) + : mbgl::mtl::RendererBackend(contextMode_), + mbgl::gfx::HeadlessBackend(size_), + swapBehaviour(swapBehaviour_) {} + +HeadlessBackend::~HeadlessBackend() { + gfx::BackendScope guard{*this, gfx::BackendScope::ScopeType::Implicit}; + // Explicitly reset the renderable resource + resource.reset(); + // Explicitly reset the context + context.reset(); +} + +void HeadlessBackend::activate() { + active = true; +} + +void HeadlessBackend::deactivate() { + active = false; +} + +gfx::Renderable& HeadlessBackend::getDefaultRenderable() { + if (!resource) { + resource = std::make_unique(*this, static_cast(getContext()), size); + } + return *this; +} + +void HeadlessBackend::updateAssumedState() { + // no-op +} + +PremultipliedImage HeadlessBackend::readStillImage() { + return getResource().readStillImage(); +} + +RendererBackend* HeadlessBackend::getRendererBackend() { + return this; +} + +HeadlessBackend::SwapBehaviour HeadlessBackend::getSwapBehaviour() { + return swapBehaviour; +} + +} // namespace mtl + +namespace gfx { + +template <> +std::unique_ptr Backend::Create( + const Size size, gfx::HeadlessBackend::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode) { + return std::make_unique(size, swapBehavior, contextMode); +} + +} // namespace gfx +} // namespace mbgl diff --git a/platform/ios/app/MBXFrameTimeGraphView.m b/platform/ios/app/MBXFrameTimeGraphView.m index e881eb9f4..4efb1d542 100644 --- a/platform/ios/app/MBXFrameTimeGraphView.m +++ b/platform/ios/app/MBXFrameTimeGraphView.m @@ -1,6 +1,6 @@ #import "MBXFrameTimeGraphView.h" -const CGFloat MBXFrameTimeExaggeration = 4.f * 1000.f; +const CGFloat MBXFrameTimeExaggeration = 10.f; const CGFloat MBXFrameTimeBarWidth = 4.f; @interface MBXFrameTimeGraphView () @@ -58,7 +58,7 @@ const CGFloat MBXFrameTimeBarWidth = 4.f; if (!CGRectEqualToRect(self.scrollLayer.frame, self.bounds)) { self.scrollLayer.frame = self.bounds; - CGRect thresholdLineRect = CGRectMake(0, self.frame.size.height - [self renderDurationTargetMilliseconds], self.frame.size.width, 1); + CGRect thresholdLineRect = CGRectMake(0, self.frame.size.height - self.frame.size.height * MBXFrameTimeExaggeration * [self renderDurationTargetMilliseconds], self.frame.size.width, 1); { CGPathRef path = CGPathCreateWithRect(thresholdLineRect, nil); @@ -96,8 +96,8 @@ const CGFloat MBXFrameTimeBarWidth = 4.f; maximumFramesPerSecond = 60; } - CGFloat target = (1.0 / maximumFramesPerSecond) * MBXFrameTimeExaggeration; - return [self roundedFloat:target]; + CGFloat target = (1.0 / maximumFramesPerSecond); + return target; } - (CGFloat)roundedFloat:(CGFloat)f { @@ -112,7 +112,7 @@ const CGFloat MBXFrameTimeBarWidth = 4.f; - (CAShapeLayer *)barWithFrameDuration:(CFTimeInterval)frameDuration { CAShapeLayer *bar = [CAShapeLayer layer]; - CGRect barRect = CGRectMake(0, 0, MBXFrameTimeBarWidth, -(fminf(frameDuration * MBXFrameTimeExaggeration, self.frame.size.height))); + CGRect barRect = CGRectMake(0, 0, MBXFrameTimeBarWidth, -(fminf(frameDuration * MBXFrameTimeExaggeration * self.frame.size.height, self.frame.size.height))); UIBezierPath *barPath = [UIBezierPath bezierPathWithRect:barRect]; bar.path = barPath.CGPath; bar.fillColor = [self colorForFrameDuration:frameDuration].CGColor; @@ -121,15 +121,15 @@ const CGFloat MBXFrameTimeBarWidth = 4.f; } - (UIColor *)colorForFrameDuration:(CFTimeInterval)frameDuration { - CGFloat renderDurationTargetMilliseconds = [self renderDurationTargetMilliseconds]; - frameDuration *= MBXFrameTimeExaggeration; + const double greenLevel = [self renderDurationTargetMilliseconds]; + const double yellowLevel = greenLevel * 3.0; - if (frameDuration < renderDurationTargetMilliseconds && frameDuration > (renderDurationTargetMilliseconds * 0.75)) { - return self.warningColor; - } else if (frameDuration > renderDurationTargetMilliseconds) { - return self.dangerColor; - } else { + if (frameDuration <= greenLevel) { return self.safeColor; + } else if (frameDuration <= yellowLevel) { + return self.warningColor; + } else { + return self.dangerColor; } } diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 0b57ed0de..9ec99f894 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -69,6 +69,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) { MBXSettingsAnnotations10000Sprites, MBXSettingsAnnotationAnimation, MBXSettingsAnnotationsTestShapes, + MBXSettingsAnnotationsManyTestShapes, MBXSettingsAnnotationsCustomCallout, MBXSettingsAnnotationsQueryAnnotations, MBXSettingsAnnotationsCustomUserDot, @@ -400,6 +401,7 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { @"Add 10,000 Sprites", @"Animate an Annotation View", @"Add Test Shapes", + @"Add 10x Test Shapes", @"Add Point With Custom Callout", @"Query Annotations", [NSString stringWithFormat:@"%@ Custom User Dot", (_customUserLocationAnnnotationEnabled ? @"Disable" : @"Enable")], @@ -548,7 +550,10 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { [self animateAnnotationView]; break; case MBXSettingsAnnotationsTestShapes: - [self addTestShapes]; + [self addTestShapes:1]; + break; + case MBXSettingsAnnotationsManyTestShapes: + [self addTestShapes:10]; break; case MBXSettingsAnnotationsCustomCallout: [self addAnnotationWithCustomCallout]; @@ -881,102 +886,107 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { }); }; -- (void)addTestShapes +- (void)addTestShapes:(NSUInteger)featuresCount { - // Pacific Northwest triangle - // - CLLocationCoordinate2D triangleCoordinates[3] = - { - CLLocationCoordinate2DMake(44, -122), - CLLocationCoordinate2DMake(46, -122), - CLLocationCoordinate2DMake(46, -121) - }; - - MLNPolygon *triangle = [MLNPolygon polygonWithCoordinates:triangleCoordinates count:3]; - - [self.mapView addAnnotation:triangle]; - - // West coast polyline - // - CLLocationCoordinate2D lineCoordinates[4] = { - CLLocationCoordinate2DMake(47.6025, -122.3327), - CLLocationCoordinate2DMake(45.5189, -122.6726), - CLLocationCoordinate2DMake(37.7790, -122.4177), - CLLocationCoordinate2DMake(34.0532, -118.2349) - }; - MLNPolyline *line = [MLNPolyline polylineWithCoordinates:lineCoordinates count:4]; - [self.mapView addAnnotation:line]; - - // Orcas Island, WA hike polyline - // - NSDictionary *hike = [NSJSONSerialization JSONObjectWithData: - [NSData dataWithContentsOfFile: - [[NSBundle mainBundle] pathForResource:@"polyline" ofType:@"geojson"]] - options:0 - error:nil]; - - NSArray *hikeCoordinatePairs = hike[@"features"][0][@"geometry"][@"coordinates"]; - - CLLocationCoordinate2D *polylineCoordinates = (CLLocationCoordinate2D *)malloc([hikeCoordinatePairs count] * sizeof(CLLocationCoordinate2D)); - - for (NSUInteger i = 0; i < [hikeCoordinatePairs count]; i++) - { - polylineCoordinates[i] = CLLocationCoordinate2DMake([hikeCoordinatePairs[i][1] doubleValue], [hikeCoordinatePairs[i][0] doubleValue]); - } - - MLNPolyline *polyline = [MLNPolyline polylineWithCoordinates:polylineCoordinates - count:[hikeCoordinatePairs count]]; - - [self.mapView addAnnotation:polyline]; - - free(polylineCoordinates); - - // PA/NJ/DE polygons - // - NSDictionary *threestates = [NSJSONSerialization JSONObjectWithData: - [NSData dataWithContentsOfFile: - [[NSBundle mainBundle] pathForResource:@"threestates" ofType:@"geojson"]] - options:0 - error:nil]; - - for (NSDictionary *feature in threestates[@"features"]) - { - NSArray *stateCoordinatePairs = feature[@"geometry"][@"coordinates"]; - - while ([stateCoordinatePairs count] == 1) stateCoordinatePairs = stateCoordinatePairs[0]; - - CLLocationCoordinate2D *polygonCoordinates = (CLLocationCoordinate2D *)malloc([stateCoordinatePairs count] * sizeof(CLLocationCoordinate2D)); - - for (NSUInteger i = 0; i < [stateCoordinatePairs count]; i++) + for (int featureIndex = 0; featureIndex < featuresCount; ++featureIndex) { + double deltaLongitude = featureIndex * 0.01; + double deltaLatitude = -featureIndex * 0.01; + + // Pacific Northwest triangle + // + CLLocationCoordinate2D triangleCoordinates[3] = { - polygonCoordinates[i] = CLLocationCoordinate2DMake([stateCoordinatePairs[i][1] doubleValue], [stateCoordinatePairs[i][0] doubleValue]); + CLLocationCoordinate2DMake(44 + deltaLatitude, -122 + deltaLongitude), + CLLocationCoordinate2DMake(46 + deltaLatitude, -122 + deltaLongitude), + CLLocationCoordinate2DMake(46 + deltaLatitude, -121 + deltaLongitude) + }; + + MLNPolygon *triangle = [MLNPolygon polygonWithCoordinates:triangleCoordinates count:3]; + + [self.mapView addAnnotation:triangle]; + + // West coast polyline + // + CLLocationCoordinate2D lineCoordinates[4] = { + CLLocationCoordinate2DMake(47.6025 + deltaLatitude, -122.3327 + deltaLongitude), + CLLocationCoordinate2DMake(45.5189 + deltaLatitude, -122.6726 + deltaLongitude), + CLLocationCoordinate2DMake(37.7790 + deltaLatitude, -122.4177 + deltaLongitude), + CLLocationCoordinate2DMake(34.0532 + deltaLatitude, -118.2349 + deltaLongitude) + }; + MLNPolyline *line = [MLNPolyline polylineWithCoordinates:lineCoordinates count:4]; + [self.mapView addAnnotation:line]; + + // Orcas Island, WA hike polyline + // + NSDictionary *hike = [NSJSONSerialization JSONObjectWithData: + [NSData dataWithContentsOfFile: + [[NSBundle mainBundle] pathForResource:@"polyline" ofType:@"geojson"]] + options:0 + error:nil]; + + NSArray *hikeCoordinatePairs = hike[@"features"][0][@"geometry"][@"coordinates"]; + + CLLocationCoordinate2D *polylineCoordinates = (CLLocationCoordinate2D *)malloc([hikeCoordinatePairs count] * sizeof(CLLocationCoordinate2D)); + + for (NSUInteger i = 0; i < [hikeCoordinatePairs count]; i++) + { + polylineCoordinates[i] = CLLocationCoordinate2DMake([hikeCoordinatePairs[i][1] doubleValue] + deltaLatitude, [hikeCoordinatePairs[i][0] doubleValue] + deltaLongitude); } - - MLNPolygon *polygon = [MLNPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]]; - polygon.title = feature[@"properties"][@"NAME"]; - - [self.mapView addAnnotation:polygon]; - - free(polygonCoordinates); + + MLNPolyline *polyline = [MLNPolyline polylineWithCoordinates:polylineCoordinates + count:[hikeCoordinatePairs count]]; + + [self.mapView addAnnotation:polyline]; + + free(polylineCoordinates); + + // PA/NJ/DE polygons + // + NSDictionary *threestates = [NSJSONSerialization JSONObjectWithData: + [NSData dataWithContentsOfFile: + [[NSBundle mainBundle] pathForResource:@"threestates" ofType:@"geojson"]] + options:0 + error:nil]; + + for (NSDictionary *feature in threestates[@"features"]) + { + NSArray *stateCoordinatePairs = feature[@"geometry"][@"coordinates"]; + + while ([stateCoordinatePairs count] == 1) stateCoordinatePairs = stateCoordinatePairs[0]; + + CLLocationCoordinate2D *polygonCoordinates = (CLLocationCoordinate2D *)malloc([stateCoordinatePairs count] * sizeof(CLLocationCoordinate2D)); + + for (NSUInteger i = 0; i < [stateCoordinatePairs count]; i++) + { + polygonCoordinates[i] = CLLocationCoordinate2DMake([stateCoordinatePairs[i][1] doubleValue] + deltaLatitude, [stateCoordinatePairs[i][0] doubleValue] + deltaLongitude); + } + + MLNPolygon *polygon = [MLNPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]]; + polygon.title = feature[@"properties"][@"NAME"]; + + [self.mapView addAnnotation:polygon]; + + free(polygonCoordinates); + } + + // Null Island polygon with an interior hole + // + CLLocationCoordinate2D innerCoordinates[] = { + CLLocationCoordinate2DMake(-5 + deltaLatitude, -5 + deltaLongitude), + CLLocationCoordinate2DMake(-5 + deltaLatitude, 5 + deltaLongitude), + CLLocationCoordinate2DMake(5 + deltaLatitude, 5 + deltaLongitude), + CLLocationCoordinate2DMake(5 + deltaLatitude, -5 + deltaLongitude), + }; + MLNPolygon *innerPolygon = [MLNPolygon polygonWithCoordinates:innerCoordinates count:sizeof(innerCoordinates) / sizeof(innerCoordinates[0])]; + CLLocationCoordinate2D outerCoordinates[] = { + CLLocationCoordinate2DMake(-10 + deltaLatitude, -10 + deltaLongitude), + CLLocationCoordinate2DMake(-10 + deltaLatitude, 10 + deltaLongitude), + CLLocationCoordinate2DMake(10 + deltaLatitude, 10 + deltaLongitude), + CLLocationCoordinate2DMake(10 + deltaLatitude, -10 + deltaLongitude), + }; + MLNPolygon *outerPolygon = [MLNPolygon polygonWithCoordinates:outerCoordinates count:sizeof(outerCoordinates) / sizeof(outerCoordinates[0]) interiorPolygons:@[innerPolygon]]; + [self.mapView addAnnotation:outerPolygon]; } - - // Null Island polygon with an interior hole - // - CLLocationCoordinate2D innerCoordinates[] = { - CLLocationCoordinate2DMake(-5, -5), - CLLocationCoordinate2DMake(-5, 5), - CLLocationCoordinate2DMake(5, 5), - CLLocationCoordinate2DMake(5, -5), - }; - MLNPolygon *innerPolygon = [MLNPolygon polygonWithCoordinates:innerCoordinates count:sizeof(innerCoordinates) / sizeof(innerCoordinates[0])]; - CLLocationCoordinate2D outerCoordinates[] = { - CLLocationCoordinate2DMake(-10, -10), - CLLocationCoordinate2DMake(-10, 10), - CLLocationCoordinate2DMake(10, 10), - CLLocationCoordinate2DMake(10, -10), - }; - MLNPolygon *outerPolygon = [MLNPolygon polygonWithCoordinates:outerCoordinates count:sizeof(outerCoordinates) / sizeof(outerCoordinates[0]) interiorPolygons:@[innerPolygon]]; - [self.mapView addAnnotation:outerPolygon]; } - (void)addAnnotationWithCustomCallout @@ -2439,9 +2449,9 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { return features; } -- (void)mapViewDidFinishRenderingFrame:(MLNMapView *)mapView fullyRendered:(BOOL)fullyRendered { +- (void)mapViewDidFinishRenderingFrame:(MLNMapView *)mapView fullyRendered:(BOOL)fullyRendered frameTime:(double)frameTime { if (self.frameTimeGraphEnabled) { - [self.frameTimeGraphView updatePathWithFrameDuration:mapView.frameTime]; + [self.frameTimeGraphView updatePathWithFrameDuration:frameTime]; } } diff --git a/platform/ios/benchmark/assets/glyphs/.gitignore b/platform/ios/benchmark/assets/glyphs/.gitignore new file mode 100644 index 000000000..939526608 --- /dev/null +++ b/platform/ios/benchmark/assets/glyphs/.gitignore @@ -0,0 +1,2 @@ +*/*.pbf + diff --git a/platform/ios/benchmark/assets/tiles/.gitignore b/platform/ios/benchmark/assets/tiles/.gitignore new file mode 100644 index 000000000..854104c6a --- /dev/null +++ b/platform/ios/benchmark/assets/tiles/.gitignore @@ -0,0 +1,2 @@ +tiles/ + diff --git a/platform/ios/src/MLNMapView+Metal.mm b/platform/ios/src/MLNMapView+Metal.mm index 8ae82c32f..d8614c920 100644 --- a/platform/ios/src/MLNMapView+Metal.mm +++ b/platform/ios/src/MLNMapView+Metal.mm @@ -69,8 +69,12 @@ public: return NS::TransferPtr(MTL::BlitPassDescriptor::alloc()->init()); } - mbgl::mtl::MTLRenderPassDescriptorPtr getRenderPassDescriptor() const override { - return NS::RetainPtr((__bridge MTL::RenderPassDescriptor*)mtlView.currentRenderPassDescriptor); + const mbgl::mtl::MTLRenderPassDescriptorPtr& getRenderPassDescriptor() const override { + if (!cachedRenderPassDescriptor) { + auto* mtlDesc = mtlView.currentRenderPassDescriptor; + cachedRenderPassDescriptor = NS::RetainPtr((__bridge MTL::RenderPassDescriptor*)mtlDesc); + } + return cachedRenderPassDescriptor; } void swap() override { @@ -83,6 +87,8 @@ public: commandBuffer = nil; commandBufferPtr.reset(); + + cachedRenderPassDescriptor.reset(); } mbgl::Size framebufferSize() { @@ -94,6 +100,7 @@ public: private: MLNMapViewMetalImpl& backend; mbgl::mtl::MTLCommandBufferPtr commandBufferPtr; + mutable mbgl::mtl::MTLRenderPassDescriptorPtr cachedRenderPassDescriptor; public: MLNMapViewImplDelegate* delegate = nil; diff --git a/src/mbgl/gfx/vertex_attribute.cpp b/src/mbgl/gfx/vertex_attribute.cpp index a1862fef9..b1e6c3c5d 100644 --- a/src/mbgl/gfx/vertex_attribute.cpp +++ b/src/mbgl/gfx/vertex_attribute.cpp @@ -17,7 +17,8 @@ std::size_t VertexAttribute::getCount() const { return sharedRawData ? sharedRawData->getRawCount() : items.size(); } -std::unique_ptr VertexAttributeArray::nullref = nullptr; +const std::unique_ptr VertexAttributeArray::nullref; +const std::string VertexAttributeArray::attributePrefix = "a_"; VertexAttributeArray::VertexAttributeArray(VertexAttributeArray&& other) : attrs(std::move(other.attrs)) {} diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 82cef14a2..1eecdd458 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -489,12 +489,11 @@ gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t } gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) { - std::vector emptyProperties(0); auto shaderGroup = shaders.getShaderGroup(name); if (!shaderGroup) { return nullptr; } - return std::static_pointer_cast(shaderGroup->getOrCreateShader(*this, emptyProperties)); + return std::static_pointer_cast(shaderGroup->getOrCreateShader(*this, {})); } TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) { diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index 314243ff0..fdc9e3f39 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -122,10 +122,10 @@ void DrawableGL::bindUniformBuffers() const { const auto& uniformBuffer = getUniformBuffers().get(element.first); if (!uniformBuffer) { using namespace std::string_literals; - const auto tileID = getTileID() ? util::toString(*getTileID()) : ""; + const auto tileIDStr = getTileID() ? util::toString(*getTileID()) : ""; Log::Error(Event::General, "bindUniformBuffers: UBO "s + std::string(StringIndexer::get(element.first)) + - " not found for " + util::toString(getID()) + " / " + getName() + " / " + tileID + + " not found for " + util::toString(getID()) + " / " + getName() + " / " + tileIDStr + ". skipping."); assert(false); continue; diff --git a/src/mbgl/gl/enum.cpp b/src/mbgl/gl/enum.cpp index 060435e28..d59306c4f 100644 --- a/src/mbgl/gl/enum.cpp +++ b/src/mbgl/gl/enum.cpp @@ -397,6 +397,15 @@ platform::GLenum Enum::sizedFor<>(const gfx::TexturePixel default: break; } + break; + } + case gfx::TextureChannelDataType::Float: { + switch (value) { + case gfx::TexturePixelType::RGBA: + return GL_RGBA32F; + default: + break; + } } } @@ -410,6 +419,8 @@ gfx::TextureChannelDataType Enum::from(const platfo return gfx::TextureChannelDataType::UnsignedByte; case GL_HALF_FLOAT: return gfx::TextureChannelDataType::HalfFloat; + case GL_FLOAT: + return gfx::TextureChannelDataType::Float; } return {}; } @@ -421,6 +432,8 @@ platform::GLenum Enum::to(const gfx::TextureChannel return GL_UNSIGNED_BYTE; case gfx::TextureChannelDataType::HalfFloat: return GL_HALF_FLOAT; + case gfx::TextureChannelDataType::Float: + return GL_FLOAT; } return GL_INVALID_ENUM; } diff --git a/src/mbgl/mtl/context.cpp b/src/mbgl/mtl/context.cpp index b92adf543..186079043 100644 --- a/src/mbgl/mtl/context.cpp +++ b/src/mbgl/mtl/context.cpp @@ -151,12 +151,9 @@ gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t } gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) { - std::vector emptyProperties(0); - auto shaderGroup = shaders.getShaderGroup(name); - if (!shaderGroup) { - return nullptr; - } - return std::static_pointer_cast(shaderGroup->getOrCreateShader(*this, emptyProperties)); + const auto shaderGroup = shaders.getShaderGroup(name); + auto shader = shaderGroup ? shaderGroup->getOrCreateShader(*this, {}) : gfx::ShaderProgramBasePtr{}; + return std::static_pointer_cast(std::move(shader)); } TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) { @@ -189,8 +186,15 @@ bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, const void Context::setDirtyState() {} +std::unique_ptr Context::createOffscreenTexture(Size size, + gfx::TextureChannelDataType type, + bool depth, + bool stencil) { + return std::make_unique(*this, size, type, depth, stencil); +} + std::unique_ptr Context::createOffscreenTexture(Size size, gfx::TextureChannelDataType type) { - return std::make_unique(*this, size, type); + return createOffscreenTexture(size, type, false, false); } std::unique_ptr Context::createTextureResource(Size, diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index 89e36092b..752dd8b88 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -123,12 +123,32 @@ MTL::Winding mapWindingMode(const gfx::CullFaceWindingType mode) { } // namespace void Drawable::setColorMode(const gfx::ColorMode& value) { - pipelineState.reset(); + impl->pipelineState.reset(); gfx::Drawable::setColorMode(value); } +void Drawable::setEnableStencil(bool value) { + gfx::Drawable::setEnableStencil(value); + impl->depthStencilState.reset(); +} + +void Drawable::setEnableDepth(bool value) { + gfx::Drawable::setEnableDepth(value); + impl->depthStencilState.reset(); +} + +void Drawable::setSubLayerIndex(int32_t value) { + gfx::Drawable::setSubLayerIndex(value); + impl->depthStencilState.reset(); +} + +void Drawable::setDepthType(gfx::DepthMaskType value) { + gfx::Drawable::setDepthType(value); + impl->depthStencilState.reset(); +} + void Drawable::setShader(gfx::ShaderProgramBasePtr value) { - pipelineState.reset(); + impl->pipelineState.reset(); gfx::Drawable::setShader(value); } @@ -151,13 +171,12 @@ void Drawable::draw(PaintParameters& parameters) const { return; } - if (renderPassDescriptor.has_value() && renderPass.getDescriptor() != renderPassDescriptor.value()) { - pipelineState.reset(); + const auto& descriptor = renderPass.getDescriptor(); + if (impl->renderPassDescriptor && descriptor != *impl->renderPassDescriptor) { + impl->pipelineState.reset(); } - renderPassDescriptor.emplace(gfx::RenderPassDescriptor{renderPass.getDescriptor().renderable, - renderPass.getDescriptor().clearColor, - renderPass.getDescriptor().clearDepth, - renderPass.getDescriptor().clearStencil}); + impl->renderPassDescriptor.emplace(gfx::RenderPassDescriptor{ + descriptor.renderable, descriptor.clearColor, descriptor.clearDepth, descriptor.clearStencil}); const auto& shaderMTL = static_cast(*shader); @@ -165,23 +184,6 @@ void Drawable::draw(PaintParameters& parameters) const { const auto debugGroup = parameters.encoder->createDebugGroup(debugLabel(*this)); #endif - /* - context.setDepthMode(getIs3D() ? parameters.depthModeFor3D() - : parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType())); - - // force disable depth test for debugging - // context.setDepthMode({gfx::DepthFunctionType::Always, gfx::DepthMaskType::ReadOnly, {0,1}}); - - // For 3D mode, stenciling is handled by the layer group - if (!is3D) { - context.setStencilMode(makeStencilMode(parameters)); - } - - context.setColorMode(getColorMode()); - context.setCullFaceMode(getCullFaceMode()); - - */ - bindAttributes(renderPass); bindUniformBuffers(renderPass); bindTextures(renderPass); @@ -207,11 +209,11 @@ void Drawable::draw(PaintParameters& parameters) const { encoder->setCullMode(cullMode.enabled ? mapCullMode(cullMode.side) : MTL::CullModeNone); encoder->setFrontFacingWinding(mapWindingMode(cullMode.winding)); - if (!pipelineState) { - pipelineState = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode()); + if (!impl->pipelineState) { + impl->pipelineState = shaderMTL.getRenderPipelineState(renderPassDescriptor, impl->vertexDesc, getColorMode()); } - if (pipelineState) { - encoder->setRenderPipelineState(pipelineState.get()); + if (impl->pipelineState) { + encoder->setRenderPipelineState(impl->pipelineState.get()); } else { assert(!"Failed to create render pipeline state"); return; @@ -219,12 +221,30 @@ void Drawable::draw(PaintParameters& parameters) const { // For 3D mode, stenciling is handled by the layer group if (!is3D) { - const auto depthMode = parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()); - const auto stencilMode = enableStencil ? parameters.stencilModeForClipping(tileID->toUnwrapped()) - : gfx::StencilMode::disabled(); - if (auto depthStencilState = context.makeDepthStencilState(depthMode, stencilMode, renderPass)) { - encoder->setDepthStencilState(depthStencilState.get()); - encoder->setStencilReferenceValue(stencilMode.ref); + std::optional newStencilMode; + + // If we have a stencil state, we may be able to reuse it, if the tile masks haven't changed. + // We assume that only the reference value needs to be compared. + if (impl->depthStencilState && enableStencil) { + newStencilMode = parameters.stencilModeForClipping(tileID->toUnwrapped()); + if (newStencilMode->ref != impl->previousStencilMode.ref) { + // No, need to rebuild it + impl->depthStencilState.reset(); + } + } + if (!impl->depthStencilState) { + if (enableStencil && !newStencilMode) { + newStencilMode = parameters.stencilModeForClipping(tileID->toUnwrapped()); + } + const auto depthMode = parameters.depthModeForSublayer(getSubLayerIndex(), getDepthType()); + const auto stencilMode = enableStencil ? parameters.stencilModeForClipping(tileID->toUnwrapped()) + : gfx::StencilMode::disabled(); + impl->depthStencilState = context.makeDepthStencilState(depthMode, stencilMode, renderPass); + impl->previousStencilMode = *newStencilMode; + } + if (impl->depthStencilState) { + encoder->setDepthStencilState(impl->depthStencilState.get()); + encoder->setStencilReferenceValue(impl->previousStencilMode.ref); } } @@ -266,7 +286,7 @@ void Drawable::draw(PaintParameters& parameters) const { assert(mlSegment.indexOffset + mlSegment.indexLength <= indexBufferLength); assert(static_cast(maxIndex) < mlSegment.vertexLength); - for (const auto& binding : attributeBindings) { + for (const auto& binding : impl->attributeBindings) { if (binding) { if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) { assert((maxIndex + mlSegment.vertexOffset) * binding->vertexStride <= buffer->length()); @@ -348,7 +368,7 @@ void Drawable::bindAttributes(const RenderPass& renderPass) const { const auto& encoder = renderPass.getMetalEncoder(); NS::UInteger attributeIndex = 0; - for (const auto& binding : attributeBindings) { + for (const auto& binding : impl->attributeBindings) { if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) { assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource)); encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex); @@ -363,7 +383,7 @@ void Drawable::unbindAttributes(const RenderPass& renderPass) const { const auto& encoder = renderPass.getMetalEncoder(); NS::UInteger attributeIndex = 0; - for (const auto& binding : attributeBindings) { + for (const auto& binding : impl->attributeBindings) { encoder->setVertexBuffer(nullptr, /*offset=*/0, attributeIndex); attributeIndex += 1; } @@ -560,14 +580,14 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { impl->vertexAttributes.visitAttributes( [](const auto&, gfx::VertexAttribute& attrib) { attrib.setDirty(false); }); - if (attributeBindings != attributeBindings_) { - attributeBindings = attributeBindings_; + if (impl->attributeBindings != attributeBindings_) { + impl->attributeBindings = attributeBindings_; // Create a layout descriptor for each attribute auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor()); NS::UInteger index = 0; - for (auto& binding : attributeBindings) { + for (auto& binding : impl->attributeBindings) { if (!binding) { assert("Missing attribute binding"); continue; @@ -597,7 +617,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { } impl->vertexDesc = std::move(vertDesc); - pipelineState.reset(); + impl->pipelineState.reset(); } } diff --git a/src/mbgl/mtl/drawable_impl.hpp b/src/mbgl/mtl/drawable_impl.hpp index ef386fe44..a0face522 100644 --- a/src/mbgl/mtl/drawable_impl.hpp +++ b/src/mbgl/mtl/drawable_impl.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,15 @@ public: StringIdentity idVertexAttrName = StringIndexer::get("a_pos"); gfx::UniqueVertexBufferResource noBindingBuffer; + + gfx::AttributeBindingArray attributeBindings; + + MTLRenderPipelineStatePtr pipelineState; + + std::optional renderPassDescriptor; + + MTLDepthStencilStatePtr depthStencilState; + gfx::StencilMode previousStencilMode; }; struct Drawable::DrawSegment final : public gfx::Drawable::DrawSegment { diff --git a/src/mbgl/mtl/offscreen_texture.cpp b/src/mbgl/mtl/offscreen_texture.cpp index 11895f807..03e52915c 100644 --- a/src/mbgl/mtl/offscreen_texture.cpp +++ b/src/mbgl/mtl/offscreen_texture.cpp @@ -11,18 +11,39 @@ namespace mtl { class OffscreenTextureResource final : public RenderableResource { public: - OffscreenTextureResource(Context& context_, const Size size_, const gfx::TextureChannelDataType type_) + OffscreenTextureResource( + Context& context_, const Size size_, const gfx::TextureChannelDataType type_, bool depth, bool stencil) : context(context_), size(size_), type(type_) { assert(!size.isEmpty()); - texture = context.createTexture2D(); - texture->setSize(size); - texture->setFormat(gfx::TexturePixelType::RGBA, type); - texture->setSamplerConfiguration( + colorTexture = context.createTexture2D(); + colorTexture->setSize(size); + colorTexture->setFormat(gfx::TexturePixelType::RGBA, type); + colorTexture->setSamplerConfiguration( {gfx::TextureFilterType::Nearest, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); - static_cast(texture.get()) + static_cast(colorTexture.get()) ->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite | MTL::TextureUsageRenderTarget); + + if (depth) { + depthTexture = context.createTexture2D(); + depthTexture->setSize(size); + depthTexture->setFormat(gfx::TexturePixelType::Depth, gfx::TextureChannelDataType::Float); + depthTexture->setSamplerConfiguration( + {gfx::TextureFilterType::Nearest, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); + static_cast(depthTexture.get()) + ->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite | MTL::TextureUsageRenderTarget); + } + + if (stencil) { + stencilTexture = context.createTexture2D(); + stencilTexture->setSize(size); + stencilTexture->setFormat(gfx::TexturePixelType::Stencil, gfx::TextureChannelDataType::UnsignedByte); + stencilTexture->setSamplerConfiguration( + {gfx::TextureFilterType::Nearest, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); + static_cast(stencilTexture.get()) + ->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite | MTL::TextureUsageRenderTarget); + } } ~OffscreenTextureResource() noexcept override = default; @@ -30,7 +51,25 @@ public: void bind() override { assert(context.getBackend().getCommandQueue()); commandBuffer = NS::RetainPtr(context.getBackend().getCommandQueue()->commandBuffer()); - texture->create(); + colorTexture->create(); + + renderPassDescriptor = NS::TransferPtr(MTL::RenderPassDescriptor::alloc()->init()); + if (auto* colorTarget = renderPassDescriptor->colorAttachments()->object(0)) { + colorTarget->setTexture(static_cast(colorTexture.get())->getMetalTexture()); + } + + if (depthTexture) { + depthTexture->create(); + if (auto* depthTarget = renderPassDescriptor->depthAttachment()) { + depthTarget->setTexture(static_cast(depthTexture.get())->getMetalTexture()); + } + } + if (stencilTexture) { + stencilTexture->create(); + if (auto* stencilTarget = renderPassDescriptor->stencilAttachment()) { + stencilTarget->setTexture(static_cast(stencilTexture.get())->getMetalTexture()); + } + } } void swap() override { @@ -38,16 +77,24 @@ public: commandBuffer->commit(); commandBuffer->waitUntilCompleted(); commandBuffer.reset(); + renderPassDescriptor.reset(); } PremultipliedImage readStillImage() { - assert(false); - return PremultipliedImage(); + assert(static_cast(colorTexture.get())->getMetalTexture()); + + auto data = std::make_unique(colorTexture->getDataSize()); + MTL::Region region = MTL::Region::Make2D(0, 0, size.width, size.height); + NS::UInteger bytesPerRow = size.width * colorTexture->getPixelStride(); + + static_cast(colorTexture.get())->getMetalTexture()->getBytes(data.get(), bytesPerRow, region, 0); + + return {size, std::move(data)}; } gfx::Texture2DPtr& getTexture() { - assert(texture); - return texture; + assert(colorTexture); + return colorTexture; } const RendererBackend& getBackend() const override { return context.getBackend(); } @@ -55,15 +102,11 @@ public: const MTLCommandBufferPtr& getCommandBuffer() const override { return commandBuffer; } MTLBlitPassDescriptorPtr getUploadPassDescriptor() const override { - assert(false); return NS::TransferPtr(MTL::BlitPassDescriptor::alloc()->init()); } - MTLRenderPassDescriptorPtr getRenderPassDescriptor() const override { - auto renderPassDescriptor = NS::TransferPtr(MTL::RenderPassDescriptor::alloc()->init()); - if (auto* colorTarget = renderPassDescriptor->colorAttachments()->object(0)) { - colorTarget->setTexture(static_cast(texture.get())->getMetalTexture()); - } + const MTLRenderPassDescriptorPtr& getRenderPassDescriptor() const override { + assert(renderPassDescriptor); return renderPassDescriptor; } @@ -71,12 +114,16 @@ private: Context& context; const Size size; const gfx::TextureChannelDataType type; - gfx::Texture2DPtr texture; + gfx::Texture2DPtr colorTexture; + gfx::Texture2DPtr depthTexture; + gfx::Texture2DPtr stencilTexture; MTLCommandBufferPtr commandBuffer; + MTLRenderPassDescriptorPtr renderPassDescriptor; }; -OffscreenTexture::OffscreenTexture(Context& context, const Size size_, const gfx::TextureChannelDataType type) - : gfx::OffscreenTexture(size, std::make_unique(context, size_, type)) {} +OffscreenTexture::OffscreenTexture( + Context& context, const Size size_, const gfx::TextureChannelDataType type, bool depth, bool stencil) + : gfx::OffscreenTexture(size, std::make_unique(context, size_, type, depth, stencil)) {} bool OffscreenTexture::isRenderable() { assert(false); diff --git a/src/mbgl/mtl/renderer_backend.cpp b/src/mbgl/mtl/renderer_backend.cpp index b290e605a..deb9cc781 100644 --- a/src/mbgl/mtl/renderer_backend.cpp +++ b/src/mbgl/mtl/renderer_backend.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -124,6 +126,8 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::BackgroundPatternShader, shaders::BuiltIn::CircleShader, shaders::BuiltIn::ClippingMaskProgram, + shaders::BuiltIn::CollisionBoxShader, + shaders::BuiltIn::CollisionCircleShader, shaders::BuiltIn::FillShader, shaders::BuiltIn::FillOutlineShader, shaders::BuiltIn::FillOutlinePatternShader, diff --git a/src/mbgl/mtl/texture2d.cpp b/src/mbgl/mtl/texture2d.cpp index fe0e541d2..6abdfc1bb 100644 --- a/src/mbgl/mtl/texture2d.cpp +++ b/src/mbgl/mtl/texture2d.cpp @@ -56,6 +56,8 @@ size_t Texture2D::getPixelStride() const noexcept { return 1 * numChannels(); case gfx::TextureChannelDataType::HalfFloat: return 2 * numChannels(); + case gfx::TextureChannelDataType::Float: + return 4 * numChannels(); } } @@ -65,6 +67,10 @@ size_t Texture2D::numChannels() const noexcept { return 4; case gfx::TexturePixelType::Alpha: return 1; + case gfx::TexturePixelType::Stencil: + return 1; + case gfx::TexturePixelType::Depth: + return 1; default: return 0; } @@ -78,6 +84,8 @@ MTL::PixelFormat Texture2D::getMetalPixelFormat() const noexcept { return MTL::PixelFormat::PixelFormatRGBA8Unorm; case gfx::TexturePixelType::Alpha: return MTL::PixelFormat::PixelFormatA8Unorm; + case gfx::TexturePixelType::Stencil: + return MTL::PixelFormat::PixelFormatStencil8; default: assert(false); return MTL::PixelFormat::PixelFormatInvalid; @@ -92,6 +100,18 @@ MTL::PixelFormat Texture2D::getMetalPixelFormat() const noexcept { assert(false); return MTL::PixelFormat::PixelFormatInvalid; } + case gfx::TextureChannelDataType::Float: + switch (pixelFormat) { + case gfx::TexturePixelType::RGBA: + return MTL::PixelFormat::PixelFormatRGBA32Float; + case gfx::TexturePixelType::Alpha: + return MTL::PixelFormat::PixelFormatR32Float; + case gfx::TexturePixelType::Depth: + return MTL::PixelFormat::PixelFormatDepth32Float; + default: + assert(false); + return MTL::PixelFormat::PixelFormatInvalid; + } default: assert(false); return MTL::PixelFormat::PixelFormatInvalid; diff --git a/src/mbgl/renderer/layer_tweaker.cpp b/src/mbgl/renderer/layer_tweaker.cpp index fe299946f..682445df7 100644 --- a/src/mbgl/renderer/layer_tweaker.cpp +++ b/src/mbgl/renderer/layer_tweaker.cpp @@ -66,30 +66,39 @@ shaders::ExpressionInputsUBO LayerTweaker::buildExpressionUBO(double zoom, uint6 0}; } -#if !MLN_RENDER_BACKEND_OPENGL -void LayerTweaker::setPropertiesAsUniforms(std::vector props) { - if (props != propertiesAsUniforms) { - propertiesAsUniforms = std::move(props); - permutationUpdated = true; - } -} -#endif - -bool LayerTweaker::hasPropertyAsUniform(const std::string_view attrName) const { - // `attrName` is expected to have the "a_" prefix, while the values in `propertiesAsUniforms` - // do not. Search for the former within the latter without allocating temporary strings. - return propertiesAsUniforms.end() != - std::find_if(propertiesAsUniforms.begin(), propertiesAsUniforms.end(), [&](const auto& name) { - return name.size() + 2 == attrName.size() && 0 == std::strcmp(name.data(), attrName.data() + 2); - }); +bool LayerTweaker::hasPropertyAsUniform(const StringIdentity attrNameID) const { + return propertiesAsUniforms.find(attrNameID) != propertiesAsUniforms.end(); } using namespace shaders; -AttributeSource LayerTweaker::getAttributeSource(const std::string_view& attribName) const { - return hasPropertyAsUniform(attribName) ? AttributeSource::Constant : AttributeSource::PerVertex; +AttributeSource LayerTweaker::getAttributeSource(const StringIdentity attribNameID) const { + return hasPropertyAsUniform(attribNameID) ? AttributeSource::Constant : AttributeSource::PerVertex; } #endif // MLN_RENDER_BACKEND_METAL +void LayerTweaker::setPropertiesAsUniforms([[maybe_unused]] const std::unordered_set& props) { +#if MLN_RENDER_BACKEND_METAL + if (props != propertiesAsUniforms) { + propertiesAsUniforms = props; + permutationUpdated = true; + } +#endif +} + +#if !MLN_RENDER_BACKEND_METAL +namespace { +const std::unordered_set emptyIDSet; +} +#endif + +const std::unordered_set& LayerTweaker::getPropertiesAsUniforms() const { +#if MLN_RENDER_BACKEND_METAL + return propertiesAsUniforms; +#else + return emptyIDSet; +#endif +} + void LayerTweaker::enableOverdrawInspector(bool value) { if (overdrawInspector != value) { overdrawInspector = value; diff --git a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp index f328743b5..cfd1889c7 100644 --- a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp @@ -60,20 +60,15 @@ void CircleLayerTweaker::execute(LayerGroupBase& layerGroup, const auto zoom = parameters.state.getZoom(); #if MLN_RENDER_BACKEND_METAL - using ShaderClass = shaders::ShaderSource; if (permutationUpdated) { - const auto source = [this](const std::string_view& attrName) { - return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; - }; - const CirclePermutationUBO permutationUBO = { - /* .color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, - /* .radius = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, - /* .blur = */ {/*.source=*/source(ShaderClass::attributes[3].name), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[4].name), /*.expression=*/{}}, - /* .stroke_color = */ {/*.source=*/source(ShaderClass::attributes[5].name), /*.expression=*/{}}, - /* .stroke_width = */ {/*.source=*/source(ShaderClass::attributes[6].name), /*.expression=*/{}}, - /* .stroke_opacity = */ {/*.source=*/source(ShaderClass::attributes[7].name), /*.expression=*/{}}, + /* .color = */ {/*.source=*/getAttributeSource(1), /*.expression=*/{}}, + /* .radius = */ {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, + /* .blur = */ {/*.source=*/getAttributeSource(3), /*.expression=*/{}}, + /* .opacity = */ {/*.source=*/getAttributeSource(4), /*.expression=*/{}}, + /* .stroke_color = */ {/*.source=*/getAttributeSource(5), /*.expression=*/{}}, + /* .stroke_width = */ {/*.source=*/getAttributeSource(6), /*.expression=*/{}}, + /* .stroke_opacity = */ {/*.source=*/getAttributeSource(7), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, /* .pad = */ 0, 0, diff --git a/src/mbgl/renderer/layers/collision_layer_tweaker.cpp b/src/mbgl/renderer/layers/collision_layer_tweaker.cpp index 508f16888..d46a60aae 100644 --- a/src/mbgl/renderer/layers/collision_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/collision_layer_tweaker.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -18,18 +19,7 @@ namespace mbgl { using namespace style; - -namespace { - -struct alignas(16) CollisionUBO { - std::array matrix; - std::array extrude_scale; - float camera_to_center_distance; - float overscale_factor; -}; -static_assert(sizeof(CollisionUBO) == 20 * 4); - -} // namespace +using namespace shaders; const StringIdentity CollisionLayerTweaker::idCollisionCircleUBOName = StringIndexer::get(CollisionCircleUBOName); const StringIdentity CollisionLayerTweaker::idCollisionBoxUBOName = StringIndexer::get(CollisionBoxUBOName); diff --git a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp index f5add4533..660572e03 100644 --- a/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_extrusion_layer_tweaker.cpp @@ -16,6 +16,10 @@ #include #include +#if MLN_RENDER_BACKEND_METAL +#include +#endif + namespace mbgl { using namespace shaders; @@ -79,9 +83,9 @@ void FillExtrusionLayerTweaker::execute(LayerGroupBase& layerGroup, const auto zoom = parameters.state.getZoom(); if (permutationUpdated) { const FillExtrusionPermutationUBO permutationUBO = { - /* .color = */ {/*.source=*/getAttributeSource("a_color"), /*.expression=*/{}}, - /* .base = */ {/*.source=*/getAttributeSource("a_base"), /*.expression=*/{}}, - /* .height = */ {/*.source=*/getAttributeSource("a_height"), /*.expression=*/{}}, + /* .color = */ {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, + /* .base = */ {/*.source=*/getAttributeSource(3), /*.expression=*/{}}, + /* .height = */ {/*.source=*/getAttributeSource(4), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, /* .pad = */ 0, 0, diff --git a/src/mbgl/renderer/layers/fill_layer_tweaker.cpp b/src/mbgl/renderer/layers/fill_layer_tweaker.cpp index f7ed4cd0a..fa2907533 100644 --- a/src/mbgl/renderer/layers/fill_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/fill_layer_tweaker.cpp @@ -77,26 +77,21 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); #endif -#if MLN_RENDER_BACKEND_METAL - const auto source = [this](const std::string_view& attrName) { - return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; - }; -#endif - + // Only run each update function once bool fillUniformBufferUpdated = false; bool fillOutlineUniformBufferUpdated = false; bool fillPatternUniformBufferUpdated = false; bool fillOutlinePatternUniformBufferUpdated = false; - auto UpdateFillUniformBuffers = [&]() { + const auto UpdateFillUniformBuffers = [&]() { if (fillUniformBufferUpdated) return; + fillUniformBufferUpdated = true; #if MLN_RENDER_BACKEND_METAL - using ShaderClass = ShaderSource; if (permutationUpdated || !fillPermutationUniformBuffer) { const FillPermutationUBO permutationUBO = { - /* .color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, + /* .color = */ {/*.source=*/getAttributeSource(1), /*.expression=*/{}}, + /* .opacity = */ {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, 0, 0, @@ -106,16 +101,11 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, 0, }; - if (fillPermutationUniformBuffer) { - fillPermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO)); - } else { - fillPermutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); - } - fillUniformBufferUpdated = true; + context.emplaceOrUpdateUniformBuffer(fillPermutationUniformBuffer, &permutationUBO); } #endif - if (!fillPropsUniformBuffer) { + if (!fillPropsUniformBuffer || propertiesUpdated) { const FillEvaluatedPropsUBO paramsUBO = { /* .color = */ evaluated.get().constantOr(FillColor::defaultValue()), /* .opacity = */ evaluated.get().constantOr(FillOpacity::defaultValue()), @@ -123,19 +113,20 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, 0, 0, }; - fillPropsUniformBuffer = context.createUniformBuffer(¶msUBO, sizeof(paramsUBO)); + context.emplaceOrUpdateUniformBuffer(fillPropsUniformBuffer, ¶msUBO); } }; - auto UpdateFillOutlineUniformBuffers = [&]() { + const auto UpdateFillOutlineUniformBuffers = [&]() { if (fillOutlineUniformBufferUpdated) return; + fillOutlineUniformBufferUpdated = true; #if MLN_RENDER_BACKEND_METAL - using ShaderClass = ShaderSource; if (permutationUpdated || !fillOutlinePermutationUniformBuffer) { const FillOutlinePermutationUBO permutationUBO = { - /* .outline_color = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, + /* .outline_color = */ {/*.source=*/getAttributeSource(1), + /*.expression=*/{}}, + /* .opacity = */ {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, 0, 0, @@ -144,17 +135,11 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, 0, 0, }; - - if (fillOutlinePermutationUniformBuffer) { - fillOutlinePermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO)); - } else { - fillOutlinePermutationUniformBuffer = context.createUniformBuffer(&permutationUBO, - sizeof(permutationUBO)); - } + context.emplaceOrUpdateUniformBuffer(fillOutlinePermutationUniformBuffer, &permutationUBO); } #endif - if (!fillOutlinePropsUniformBuffer) { + if (!fillOutlinePropsUniformBuffer || propertiesUpdated) { const FillOutlineEvaluatedPropsUBO paramsUBO = { /* .outline_color = */ evaluated.get().constantOr(FillOutlineColor::defaultValue()), /* .opacity = */ evaluated.get().constantOr(FillOpacity::defaultValue()), @@ -162,118 +147,104 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, 0, 0, }; - fillOutlinePropsUniformBuffer = context.createUniformBuffer(¶msUBO, sizeof(paramsUBO)); + context.emplaceOrUpdateUniformBuffer(fillOutlinePropsUniformBuffer, ¶msUBO); } - - fillOutlineUniformBufferUpdated = true; }; - auto UpdateFillPatternUniformBuffers = [&]() { + const auto UpdateFillPatternUniformBuffers = [&]() { if (fillPatternUniformBufferUpdated) return; + fillPatternUniformBufferUpdated = true; #if MLN_RENDER_BACKEND_METAL - using ShaderClass = ShaderSource; if (permutationUpdated || !fillPatternPermutationUniformBuffer) { const FillPatternPermutationUBO permutationUBO = { - /* .pattern_from = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, - /* .pattern_to = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[3].name), /*.expression=*/{}}, + /* .pattern_from = */ {/*.source=*/getAttributeSource(1), + /*.expression=*/{}}, + /* .pattern_to = */ + {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, + /* .opacity = */ + {/*.source=*/getAttributeSource(3), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, 0, 0, 0, 0, }; - - if (fillPatternPermutationUniformBuffer) { - fillPatternPermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO)); - } else { - fillPatternPermutationUniformBuffer = context.createUniformBuffer(&permutationUBO, - sizeof(permutationUBO)); - } + context.emplaceOrUpdateUniformBuffer(fillPatternPermutationUniformBuffer, &permutationUBO); } #endif - if (!fillPatternPropsUniformBuffer) { + if (!fillPatternPropsUniformBuffer || propertiesUpdated) { const FillPatternEvaluatedPropsUBO paramsUBO = { /* .opacity = */ evaluated.get().constantOr(FillOpacity::defaultValue()), /* .fade = */ crossfade.t, 0, 0, }; - fillPatternPropsUniformBuffer = context.createUniformBuffer(¶msUBO, sizeof(paramsUBO)); + context.emplaceOrUpdateUniformBuffer(fillPatternPropsUniformBuffer, ¶msUBO); } - - fillPatternUniformBufferUpdated = true; }; - auto UpdateFillOutlinePatternUniformBuffers = [&]() { + const auto UpdateFillOutlinePatternUniformBuffers = [&]() { if (fillOutlinePatternUniformBufferUpdated) return; + fillOutlinePatternUniformBufferUpdated = true; #if MLN_RENDER_BACKEND_METAL - using ShaderClass = ShaderSource; if (permutationUpdated || !fillOutlinePatternPermutationUniformBuffer) { const FillOutlinePatternPermutationUBO permutationUBO = { - /* .pattern_from = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, - /* .pattern_to = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/source(ShaderClass::attributes[3].name), /*.expression=*/{}}, + /* .pattern_from = */ {/*.source=*/getAttributeSource(1), + /*.expression=*/{}}, + /* .pattern_to = */ + {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, + /* .opacity = */ + {/*.source=*/getAttributeSource(3), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, 0, 0, 0, 0, }; - - if (fillOutlinePatternPermutationUniformBuffer) { - fillOutlinePatternPermutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO)); - } else { - fillOutlinePatternPermutationUniformBuffer = context.createUniformBuffer(&permutationUBO, - sizeof(permutationUBO)); - } + context.emplaceOrUpdateUniformBuffer(fillOutlinePatternPermutationUniformBuffer, &permutationUBO); } #endif - if (!fillOutlinePatternPropsUniformBuffer) { + if (!fillOutlinePatternPropsUniformBuffer || propertiesUpdated) { const FillOutlinePatternEvaluatedPropsUBO paramsUBO = { /* .opacity = */ evaluated.get().constantOr(FillOpacity::defaultValue()), /* .fade = */ crossfade.t, 0, 0, }; - fillOutlinePatternPropsUniformBuffer = context.createUniformBuffer(¶msUBO, sizeof(paramsUBO)); + context.emplaceOrUpdateUniformBuffer(fillOutlinePatternPropsUniformBuffer, ¶msUBO); } - - fillOutlinePatternUniformBufferUpdated = true; }; #if MLN_RENDER_BACKEND_METAL - if (!expressionUniformBuffer) { - const auto zoom = parameters.state.getZoom(); - const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); - expressionUniformBuffer = context.createUniformBuffer(&expressionUBO, sizeof(expressionUBO)); - } + const auto zoom = parameters.state.getZoom(); + const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); + context.emplaceOrUpdateUniformBuffer(expressionUniformBuffer, &expressionUBO); #endif + const auto& translation = evaluated.get(); + const auto anchor = evaluated.get(); + + const auto renderableSize = parameters.backend.getDefaultRenderable().getSize(); + const auto intZoom = parameters.state.getIntegerZoom(); + const auto pixelRatio = parameters.pixelRatio; + layerGroup.visitDrawables([&](gfx::Drawable& drawable) { if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { return; } - auto& uniforms = drawable.mutableUniformBuffers(); - // auto& drawableType = drawable.getShader()->typeName(); - const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); - const auto& translation = evaluated.get(); - const auto anchor = evaluated.get(); constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix constexpr bool nearClipped = false; const auto matrix = getTileMatrix( tileID, renderTree, parameters.state, translation, anchor, nearClipped, inViewportPixelUnits); // from FillPatternProgram::layoutUniformValues - const auto renderableSize = parameters.backend.getDefaultRenderable().getSize(); - const auto intZoom = parameters.state.getIntegerZoom(); const auto tileRatio = 1.0f / tileID.pixelsToTileUnits(1.0f, intZoom); const int32_t tileSizeAtNearestZoom = static_cast( util::tileSize_D * parameters.state.zoomScale(intZoom - tileID.canonical.z)); @@ -281,7 +252,6 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * parameters.state.zoomScale(tileID.canonical.z))); const int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; - const auto pixelRatio = parameters.pixelRatio; Size textureSize = {0, 0}; if (const auto shader = drawable.getShader()) { @@ -292,12 +262,13 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, } } + auto& uniforms = drawable.mutableUniformBuffers(); if (uniforms.get(idFillInterpolateUBOName)) { UpdateFillUniformBuffers(); uniforms.addOrReplace(idFillEvaluatedPropsUBOName, fillPropsUniformBuffer); - const FillDrawableUBO drawableUBO = {/*.matrix=*/util::cast(matrix)}; + const FillDrawableUBO drawableUBO = {/*.matrix=*/util::cast(matrix)}; uniforms.createOrUpdate(idFillDrawableUBOName, &drawableUBO, context); #if MLN_RENDER_BACKEND_METAL @@ -307,12 +278,12 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, UpdateFillOutlineUniformBuffers(); uniforms.addOrReplace(idFillOutlineEvaluatedPropsUBOName, fillOutlinePropsUniformBuffer); + const FillOutlineDrawableUBO drawableUBO = { /*.matrix=*/util::cast(matrix), /*.world=*/{(float)renderableSize.width, (float)renderableSize.height}, /* pad1 */ 0, /* pad2 */ 0}; - uniforms.createOrUpdate(idFillOutlineDrawableUBOName, &drawableUBO, context); #if MLN_RENDER_BACKEND_METAL @@ -322,6 +293,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, UpdateFillPatternUniformBuffers(); uniforms.addOrReplace(idFillPatternEvaluatedPropsUBOName, fillPatternPropsUniformBuffer); + const FillPatternDrawableUBO drawableUBO = { /*.matrix=*/util::cast(matrix), /*.scale=*/{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale}, @@ -331,7 +303,6 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, 0, 0, }; - uniforms.createOrUpdate(idFillPatternDrawableUBOName, &drawableUBO, context); #if MLN_RENDER_BACKEND_METAL @@ -341,6 +312,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, UpdateFillOutlinePatternUniformBuffers(); uniforms.addOrReplace(idFillOutlinePatternEvaluatedPropsUBOName, fillOutlinePatternPropsUniformBuffer); + const FillOutlinePatternDrawableUBO drawableUBO = { /*.matrix=*/util::cast(matrix), /*.scale=*/{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale}, @@ -349,7 +321,6 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, /*.pixel_coord_lower=*/{static_cast(pixelX & 0xFFFF), static_cast(pixelY & 0xFFFF)}, /*.texsize=*/{static_cast(textureSize.width), static_cast(textureSize.height)}, }; - uniforms.createOrUpdate(idFillOutlinePatternDrawableUBOName, &drawableUBO, context); #if MLN_RENDER_BACKEND_METAL @@ -363,6 +334,7 @@ void FillLayerTweaker::execute(LayerGroupBase& layerGroup, }); permutationUpdated = false; + propertiesUpdated = false; } } // namespace mbgl diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp index f4b44c468..16a76661e 100644 --- a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp @@ -43,15 +43,10 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, const auto zoom = parameters.state.getZoom(); #if MLN_RENDER_BACKEND_METAL - using ShaderClass = shaders::ShaderSource; if (permutationUpdated) { - const auto source = [this](const std::string_view& attrName) { - return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; - }; - const HeatmapPermutationUBO permutationUBO = { - /* .weight = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, - /* .radius = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, + /* .weight = */ {/*.source=*/getAttributeSource(1), /*.expression=*/{}}, + /* .radius = */ {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, /* .pad1/2/3 = */ 0, 0, diff --git a/src/mbgl/renderer/layers/line_layer_tweaker.cpp b/src/mbgl/renderer/layers/line_layer_tweaker.cpp index 9bd15fac5..c2373f20d 100644 --- a/src/mbgl/renderer/layers/line_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/line_layer_tweaker.cpp @@ -112,19 +112,14 @@ void LineLayerTweaker::execute(LayerGroupBase& layerGroup, }; #if MLN_RENDER_BACKEND_METAL - using LineShaderClass = shaders::ShaderSource; if (permutationUpdated) { - const auto source = [this](const std::string_view& attrName) { - return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; - }; - const LinePermutationUBO permutationUBO = { - /* .color = */ {/*.source=*/source(LineShaderClass::attributes[2].name), /*.expression=*/{}}, - /* .blur = */ {/*.source=*/source(LineShaderClass::attributes[3].name), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/source(LineShaderClass::attributes[4].name), /*.expression=*/{}}, - /* .gapwidth = */ {/*.source=*/source(LineShaderClass::attributes[5].name), /*.expression=*/{}}, - /* .offset = */ {/*.source=*/source(LineShaderClass::attributes[6].name), /*.expression=*/{}}, - /* .width = */ {/*.source=*/source(LineShaderClass::attributes[7].name), /*.expression=*/{}}, + /* .color = */ {/*.source=*/getAttributeSource(2), /*.expression=*/{}}, + /* .blur = */ {/*.source=*/getAttributeSource(3), /*.expression=*/{}}, + /* .opacity = */ {/*.source=*/getAttributeSource(4), /*.expression=*/{}}, + /* .gapwidth = */ {/*.source=*/getAttributeSource(5), /*.expression=*/{}}, + /* .offset = */ {/*.source=*/getAttributeSource(6), /*.expression=*/{}}, + /* .width = */ {/*.source=*/getAttributeSource(7), /*.expression=*/{}}, /* .floorwidth = */ {/*.source=*/AttributeSource::Constant, /*.expression=*/{}}, /* .pattern_from = */ {/*.source=*/AttributeSource::Constant, /*.expression=*/{}}, /* .pattern_to = */ {/*.source=*/AttributeSource::Constant, /*.expression=*/{}}, diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index 27aa14606..f2e83ea1e 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -327,6 +327,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, [&](gfx::Drawable& drawable) { return drawable.getTileID() && !hasRenderTile(*drawable.getTileID()); }); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + std::unordered_set propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -378,15 +379,16 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, const auto interpBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); + propertiesAsUniforms.clear(); gfx::VertexAttributeArray circleVertexAttrs; - auto propertiesAsUniforms = circleVertexAttrs.readDataDrivenPaintProperties( - paintPropertyBinders, evaluated); + circleVertexAttrs.readDataDrivenPaintProperties( + paintPropertyBinders, evaluated, propertiesAsUniforms); if (!circleShaderGroup) { continue; @@ -397,7 +399,7 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, } if (layerTweaker) { - layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } if (const auto& attr = circleVertexAttrs.add(idVertexAttribName)) { diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 62b5c477c..8b1200b4e 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -341,6 +341,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, return; } + std::unordered_set propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -412,16 +413,17 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, continue; } - gfx::VertexAttributeArray vertexAttrs; - const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(binders, - evaluated); - if (!shaderGroup) { continue; } + + gfx::VertexAttributeArray vertexAttrs; + propertiesAsUniforms.clear(); + vertexAttrs.readDataDrivenPaintProperties(binders, evaluated, propertiesAsUniforms); + const auto shader = std::static_pointer_cast( shaderGroup->getOrCreateShader(context, propertiesAsUniforms)); if (!shader) { @@ -429,7 +431,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, } if (layerTweaker) { - layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } // The non-pattern path in `render()` only uses two-pass rendering if there's translucency. diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 02176fdb7..4063c23c4 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -103,9 +103,8 @@ void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) { evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (layerGroup) { - auto newTweaker = std::make_shared(getID(), evaluatedProperties); - replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); + if (layerTweaker) { + layerTweaker->updateProperties(evaluatedProperties); } #endif } @@ -373,6 +372,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, return tileID && !hasRenderTile(*tileID); }); + std::unordered_set propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -503,9 +503,9 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders, // `Fill*Program` all use `style::FillPaintProperties` gfx::VertexAttributeArray vertexAttrs; - const auto propertiesAsUniforms = - vertexAttrs.readDataDrivenPaintProperties(binders, - evaluated); + propertiesAsUniforms.clear(); + vertexAttrs.readDataDrivenPaintProperties( + binders, evaluated, propertiesAsUniforms); if (layerTweaker) { layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index aade91552..7189c99d4 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -353,6 +353,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, [&](gfx::Drawable& drawable) { return drawable.getTileID() && !hasRenderTile(*drawable.getTileID()); }); const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + std::unordered_set propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -389,9 +390,10 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, }; gfx::VertexAttributeArray heatmapVertexAttrs; - const auto propertiesAsUniforms = - heatmapVertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, - evaluated); + propertiesAsUniforms.clear(); + heatmapVertexAttrs.readDataDrivenPaintProperties( + paintPropertyBinders, evaluated, propertiesAsUniforms); + if (layerTweaker) { layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 9f0760312..ee8f692ff 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -83,6 +83,12 @@ void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { #if MLN_DRAWABLE_RENDERER if (layerGroup) { auto newTweaker = std::make_shared(getID(), evaluatedProperties); + + // propertiesAsUniforms isn't recalculated every update, so carry it over + if (layerTweaker) { + newTweaker->setPropertiesAsUniforms(layerTweaker->getPropertiesAsUniforms()); + } + replaceTweaker(layerTweaker, std::move(newTweaker), {layerGroup}); } #endif @@ -459,6 +465,7 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, builder->setSegments(gfx::Triangles(), bucket.sharedTriangles, bucket.segments.data(), bucket.segments.size()); }; + std::unordered_set propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -565,6 +572,8 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, else if (shaderUniforms.get(idLineSDFInterpolationUBOName)) { drawableUniforms.createOrUpdate(idLineSDFInterpolationUBOName, &lineSDFInterpolationUBO, context); } + + // TODO: vertex attributes or `propertiesAsUniforms` updated, is that needed? }); if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { @@ -572,27 +581,29 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } if (!evaluated.get().from.empty()) { - // dash array line (SDF) - gfx::VertexAttributeArray vertexAttrs; - auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, - evaluated); - if (!lineSDFShaderGroup) { continue; } + + // dash array line (SDF) + propertiesAsUniforms.clear(); + gfx::VertexAttributeArray vertexAttrs; + vertexAttrs.readDataDrivenPaintProperties( + paintPropertyBinders, evaluated, propertiesAsUniforms); + auto shader = lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } if (layerTweaker) { - layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } auto builder = createLineBuilder("lineSDF", std::move(shader)); @@ -617,27 +628,26 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, ++stats.drawablesAdded; } } else if (!unevaluated.get().isUndefined()) { - // pattern line - gfx::VertexAttributeArray vertexAttrs; - paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); - auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, - evaluated); - if (!linePatternShaderGroup) { continue; } + + // pattern line + paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); + + propertiesAsUniforms.clear(); + gfx::VertexAttributeArray vertexAttrs; + vertexAttrs + .readDataDrivenPaintProperties( + paintPropertyBinders, evaluated, propertiesAsUniforms); + auto shader = linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } if (layerTweaker) { - layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } auto builder = createLineBuilder("linePattern", std::move(shader)); @@ -678,22 +688,23 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } } } else if (!unevaluated.get().getValue().isUndefined()) { - // gradient line - gfx::VertexAttributeArray vertexAttrs; - auto propertiesAsUniforms = - vertexAttrs.readDataDrivenPaintProperties( - paintPropertyBinders, evaluated); - if (!lineGradientShaderGroup) { continue; } + + // gradient line + propertiesAsUniforms.clear(); + gfx::VertexAttributeArray vertexAttrs; + vertexAttrs.readDataDrivenPaintProperties( + paintPropertyBinders, evaluated, propertiesAsUniforms); + auto shader = lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } if (layerTweaker) { - layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } auto builder = createLineBuilder("lineGradient", std::move(shader)); @@ -731,33 +742,25 @@ void RenderLineLayer::update(gfx::ShaderRegistry& shaders, } } } - } else { - // simple line - gfx::VertexAttributeArray vertexAttrs; - const auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, - evaluated); - - assert(6 == propertiesAsUniforms.size()); - assert(vertexAttrs.size() == (size_t)std::count_if(propertiesAsUniforms.begin(), - propertiesAsUniforms.end(), - [](const auto& s) { return s.empty(); })); - if (!lineShaderGroup) { continue; } + + // simple line + propertiesAsUniforms.clear(); + gfx::VertexAttributeArray vertexAttrs; + vertexAttrs + .readDataDrivenPaintProperties( + paintPropertyBinders, evaluated, propertiesAsUniforms); + auto shader = lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms); if (!shader) { continue; } if (layerTweaker) { - layerTweaker->setPropertiesAsUniforms(std::move(propertiesAsUniforms)); + layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } auto builder = createLineBuilder("line", std::move(shader)); diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index f32d91a31..22562ab09 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -749,19 +749,21 @@ SymbolDrawableTilePropsUBO buildTileUBO(const SymbolBucket& bucket, }; } -static const StringIdentity idDataAttibName = StringIndexer::get("a_data"); -static const StringIdentity idPosOffsetAttribName = StringIndexer::get("a_pos_offset"); -static const StringIdentity idPixOffsetAttribName = StringIndexer::get("a_pixeloffset"); -static const StringIdentity idProjPosAttribName = StringIndexer::get("a_projected_pos"); -static const StringIdentity idFadeOpacityAttribName = StringIndexer::get("a_fade_opacity"); -static const StringIdentity idTexUniformName = StringIndexer::get("u_texture"); -static const StringIdentity idTexIconUniformName = StringIndexer::get("u_texture_icon"); +static const auto idDataAttibName = StringIndexer::get("a_data"); +static const auto posOffsetAttribName = "a_pos_offset"; +static const auto idPosOffsetAttribName = StringIndexer::get(posOffsetAttribName); +static const auto idPixOffsetAttribName = StringIndexer::get("a_pixeloffset"); +static const auto idProjPosAttribName = StringIndexer::get("a_projected_pos"); +static const auto idFadeOpacityAttribName = StringIndexer::get("a_fade_opacity"); +static const auto idTexUniformName = StringIndexer::get("u_texture"); +static const auto idTexIconUniformName = StringIndexer::get("u_texture_icon"); -std::vector updateTileAttributes(const SymbolBucket::Buffer& buffer, - const bool isText, - const SymbolBucket::PaintProperties& paintProps, - const SymbolPaintProperties::PossiblyEvaluated& evaluated, - gfx::VertexAttributeArray& attribs) { +void updateTileAttributes(const SymbolBucket::Buffer& buffer, + const bool isText, + const SymbolBucket::PaintProperties& paintProps, + const SymbolPaintProperties::PossiblyEvaluated& evaluated, + gfx::VertexAttributeArray& attribs, + std::unordered_set& propertiesAsUniforms) { if (const auto& attr = attribs.getOrAdd(idPosOffsetAttribName)) { attr->setSharedRawData(buffer.sharedVertices, offsetof(SymbolLayoutVertex, a1), @@ -801,13 +803,13 @@ std::vector updateTileAttributes(const SymbolBucket::Buffer& buffer gfx::AttributeDataType::Float); } - return isText - ? attribs - .readDataDrivenPaintProperties( - paintProps.textBinders, evaluated) - : attribs - .readDataDrivenPaintProperties( - paintProps.iconBinders, evaluated); + if (isText) { + attribs.readDataDrivenPaintProperties( + paintProps.textBinders, evaluated, propertiesAsUniforms); + } else { + attribs.readDataDrivenPaintProperties( + paintProps.iconBinders, evaluated, propertiesAsUniforms); + } } void updateTileDrawable(gfx::Drawable& drawable, @@ -817,7 +819,8 @@ void updateTileDrawable(gfx::Drawable& drawable, const SymbolPaintProperties::PossiblyEvaluated& evaluated, const TransformState& state, gfx::UniformBufferPtr& textInterpUBO, - gfx::UniformBufferPtr& iconInterpUBO) { + gfx::UniformBufferPtr& iconInterpUBO, + std::unordered_set& propertiesAsUniforms) { if (!drawable.getData()) { return; } @@ -859,7 +862,7 @@ void updateTileDrawable(gfx::Drawable& drawable, // See `Placement::updateBucketDynamicVertices` gfx::VertexAttributeArray attribs; - updateTileAttributes(buffer, isText, paintProps, evaluated, attribs); + updateTileAttributes(buffer, isText, paintProps, evaluated, attribs, propertiesAsUniforms); drawable.setVertexAttributes(std::move(attribs)); } @@ -1086,6 +1089,7 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, collisionBuilder->setColorMode(gfx::ColorMode::alphaBlended()); collisionBuilder->setVertexAttrNameId(idCollisionPosAttribName); + std::unordered_set propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -1196,8 +1200,16 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, } const auto& evaluated = getEvaluated(renderData.layerProperties); - updateTileDrawable( - drawable, context, bucket, bucketPaintProperties, evaluated, state, textInterpUBO, iconInterpUBO); + propertiesAsUniforms.clear(); + updateTileDrawable(drawable, + context, + bucket, + bucketPaintProperties, + evaluated, + state, + textInterpUBO, + iconInterpUBO, + propertiesAsUniforms); }); // re-create collision drawables @@ -1281,9 +1293,9 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, const auto vertexCount = buffer.vertices().elements(); + propertiesAsUniforms.clear(); gfx::VertexAttributeArray attribs; - const auto propertiesAsUniforms = updateTileAttributes( - buffer, isText, bucketPaintProperties, evaluated, attribs); + updateTileAttributes(buffer, isText, bucketPaintProperties, evaluated, attribs, propertiesAsUniforms); if (layerTweaker) { layerTweaker->setPropertiesAsUniforms(propertiesAsUniforms); } @@ -1355,8 +1367,8 @@ void RenderSymbolLayer::update(gfx::ShaderRegistry& shaders, if (!shaderGroup) { return; } - const auto shader = std::static_pointer_cast(shaderGroup->getOrCreateShader( - context, propertiesAsUniforms, StringIndexer::get(idPosOffsetAttribName))); + const auto shader = std::static_pointer_cast( + shaderGroup->getOrCreateShader(context, propertiesAsUniforms, posOffsetAttribName)); if (!shader) { return; } diff --git a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp index 21ad4983b..f2141af17 100644 --- a/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -19,6 +19,7 @@ #if MLN_RENDER_BACKEND_METAL #include +#include #endif // MLN_RENDER_BACKEND_METAL namespace mbgl { @@ -92,11 +93,11 @@ void SymbolLayerTweaker::execute(LayerGroupBase& layerGroup, #if MLN_RENDER_BACKEND_METAL if (permutationUpdated) { const SymbolPermutationUBO permutationUBO = { - /* .fill_color = */ {/*.source=*/getAttributeSource("a_fill_color"), /*.expression=*/{}}, - /* .halo_color = */ {/*.source=*/getAttributeSource("a_halo_color"), /*.expression=*/{}}, - /* .opacity = */ {/*.source=*/getAttributeSource("a_opacity"), /*.expression=*/{}}, - /* .halo_width = */ {/*.source=*/getAttributeSource("a_halo_width"), /*.expression=*/{}}, - /* .halo_blur = */ {/*.source=*/getAttributeSource("a_halo_blur"), /*.expression=*/{}}, + /* .fill_color = */ {/*.source=*/getAttributeSource(5), /*.expression=*/{}}, + /* .halo_color = */ {/*.source=*/getAttributeSource(6), /*.expression=*/{}}, + /* .opacity = */ {/*.source=*/getAttributeSource(7), /*.expression=*/{}}, + /* .halo_width = */ {/*.source=*/getAttributeSource(8), /*.expression=*/{}}, + /* .halo_blur = */ {/*.source=*/getAttributeSource(9), /*.expression=*/{}}, /* .overdrawInspector = */ overdrawInspector, /* .pad = */ 0, 0, diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index 1b2a14615..65d404368 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -157,6 +157,24 @@ void PaintParameters::clearTileClippingMasks() { } } +#if MLN_RENDER_BACKEND_METAL +namespace { +const auto clipMaskStencilMode = gfx::StencilMode{ + /*.test=*/gfx::StencilMode::Always(), + /*.ref=*/0, + /*.mask=*/0b11111111, + /*.fail=*/gfx::StencilOpType::Keep, + /*.depthFail=*/gfx::StencilOpType::Keep, + /*.pass=*/gfx::StencilOpType::Replace, +}; +const auto clipMaskDepthMode = gfx::DepthMode{ + /*.func=*/gfx::DepthFunctionType::Always, + /*.mask=*/gfx::DepthMaskType::ReadOnly, + /*.range=*/{0, 1}, +}; +} // namespace +#endif // MLN_RENDER_BACKEND_METAL + template void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFunc&& f, bool clear) { if (tileIDsIdentical(beg, end, f, tileClippingMaskIDs)) { @@ -238,32 +256,13 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun // gfx::CullFaceMode::disabled(); encoder->setCullMode(MTL::CullModeNone); - auto stencilDescriptor = NS::TransferPtr(MTL::StencilDescriptor::alloc()->init()); - if (!stencilDescriptor) { + if (auto depthStencilState = mtlContext.makeDepthStencilState( + clipMaskDepthMode, clipMaskStencilMode, mtlRenderPass)) { + encoder->setDepthStencilState(depthStencilState.get()); + } else { + assert(!"Failed to create depth-stencil state"); return; } - stencilDescriptor->setStencilCompareFunction(MTL::CompareFunction::CompareFunctionAlways); - stencilDescriptor->setStencilFailureOperation(MTL::StencilOperation::StencilOperationKeep); - stencilDescriptor->setDepthFailureOperation(MTL::StencilOperation::StencilOperationKeep); - stencilDescriptor->setDepthStencilPassOperation(MTL::StencilOperation::StencilOperationReplace); - stencilDescriptor->setReadMask(0); - stencilDescriptor->setWriteMask(0b11111111); - - auto depthStencilDescriptor = NS::TransferPtr(MTL::DepthStencilDescriptor::alloc()->init()); - if (!depthStencilDescriptor) { - return; - } - depthStencilDescriptor->setDepthCompareFunction(MTL::CompareFunction::CompareFunctionAlways); - depthStencilDescriptor->setDepthWriteEnabled(false); - depthStencilDescriptor->setFrontFaceStencil(stencilDescriptor.get()); - depthStencilDescriptor->setBackFaceStencil(stencilDescriptor.get()); - - auto& device = mtlContext.getBackend().getDevice(); - auto depthStencilState = NS::TransferPtr(device->newDepthStencilState(depthStencilDescriptor.get())); - if (!depthStencilState) { - return; - } - encoder->setDepthStencilState(depthStencilState.get()); // Create a render pipeline state, telling Metal how to render the primitives const auto& renderPassDescriptor = mtlRenderPass.getDescriptor(); diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index c917bdf69..33bdca101 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -392,10 +392,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, // Ends the RenderPass parameters.renderPass.reset(); - const bool isMapModeContinuous = renderTreeParameters.mapMode == MapMode::Continuous; - if (isMapModeContinuous) { - parameters.encoder->present(parameters.backend.getDefaultRenderable()); - } + parameters.encoder->present(parameters.backend.getDefaultRenderable()); // CommandEncoder destructor submits render commands. parameters.encoder.reset(); diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 5fd73e490..6c23c386c 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -24,11 +24,13 @@ void ImageSourceRenderData::upload(gfx::UploadPass& uploadPass) const { bucket->upload(uploadPass); } +#if MLN_LEGACY_RENDERER if (!debugTexture) { std::array data{{0, 0, 0, 0}}; static const PremultipliedImage emptyImage{Size(1, 1), data.data(), data.size()}; debugTexture = uploadPass.createTexture(emptyImage); } +#endif } void ImageSourceRenderData::render(PaintParameters& parameters) const { diff --git a/src/mbgl/shaders/mtl/background.cpp b/src/mbgl/shaders/mtl/background.cpp new file mode 100644 index 000000000..9eec3d3c1 --- /dev/null +++ b/src/mbgl/shaders/mtl/background.cpp @@ -0,0 +1,17 @@ +#include +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Float3, 1, "a_pos"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{1, true, true, sizeof(BackgroundLayerUBO), "BackgroundLayerUBO"}, + UniformBlockInfo{2, true, false, sizeof(BackgroundDrawableUBO), "BackgroundDrawableUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/background_pattern.cpp b/src/mbgl/shaders/mtl/background_pattern.cpp new file mode 100644 index 000000000..88aff4809 --- /dev/null +++ b/src/mbgl/shaders/mtl/background_pattern.cpp @@ -0,0 +1,14 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array + ShaderSource::uniforms = { + UniformBlockInfo{1, sizeof(BackgroundLayerUBO), true, false, "BackgroundLayerUBO"}, + UniformBlockInfo{2, sizeof(BackgroundDrawableUBO), true, false, "BackgroundDrawableUBO"}, + UniformBlockInfo{3, sizeof(BackgroundPatternLayerUBO), true, false, "BackgroundLayerUBO"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/circle.cpp b/src/mbgl/shaders/mtl/circle.cpp new file mode 100644 index 000000000..cdf6c06cf --- /dev/null +++ b/src/mbgl/shaders/mtl/circle.cpp @@ -0,0 +1,27 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Float2, 1, "a_color"}, + AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_radius"}, + AttributeInfo{3, gfx::AttributeDataType::Float2, 1, "a_blur"}, + AttributeInfo{4, gfx::AttributeDataType::Float2, 1, "a_opacity"}, + AttributeInfo{5, gfx::AttributeDataType::Float4, 1, "a_stroke_color"}, + AttributeInfo{6, gfx::AttributeDataType::Float2, 1, "a_stroke_width"}, + AttributeInfo{7, gfx::AttributeDataType::Float2, 1, "a_stroke_opacity"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{8, true, false, sizeof(CircleDrawableUBO), "CircleDrawableUBO"}, + UniformBlockInfo{9, true, true, sizeof(CirclePaintParamsUBO), "CirclePaintParamsUBO"}, + UniformBlockInfo{10, true, true, sizeof(CircleEvaluatedPropsUBO), "CircleEvaluatedPropsUBO"}, + UniformBlockInfo{11, true, false, sizeof(CircleInterpolateUBO), "CircleInterpolateUBO"}, + UniformBlockInfo{12, true, true, sizeof(CirclePermutationUBO), "CirclePermutationUBO"}, + UniformBlockInfo{13, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/clipping_mask.cpp b/src/mbgl/shaders/mtl/clipping_mask.cpp new file mode 100644 index 000000000..9cd391a1e --- /dev/null +++ b/src/mbgl/shaders/mtl/clipping_mask.cpp @@ -0,0 +1,16 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Float3, 1, "a_pos"}, +}; +const std::array ShaderSource::uniforms = + { + UniformBlockInfo{1, true, false, sizeof(ClipUBO), "ClipUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/collision_box.cpp b/src/mbgl/shaders/mtl/collision_box.cpp new file mode 100644 index 000000000..66cbbef9a --- /dev/null +++ b/src/mbgl/shaders/mtl/collision_box.cpp @@ -0,0 +1,19 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Short2, 1, "a_anchor_pos"}, + AttributeInfo{2, gfx::AttributeDataType::Short2, 1, "a_extrude"}, + AttributeInfo{3, gfx::AttributeDataType::UByte2, 1, "a_placed"}, + AttributeInfo{4, gfx::AttributeDataType::Float2, 1, "a_shift"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{5, true, true, sizeof(CollisionUBO), "CollisionBoxUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/collision_circle.cpp b/src/mbgl/shaders/mtl/collision_circle.cpp new file mode 100644 index 000000000..9eb6934ab --- /dev/null +++ b/src/mbgl/shaders/mtl/collision_circle.cpp @@ -0,0 +1,20 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = + { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Short2, 1, "a_anchor_pos"}, + AttributeInfo{2, gfx::AttributeDataType::Short2, 1, "a_extrude"}, + AttributeInfo{3, gfx::AttributeDataType::UByte2, 1, "a_placed"}, +}; +const std::array + ShaderSource::uniforms = { + UniformBlockInfo{5, true, true, sizeof(CollisionUBO), "CollisionCircleUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/fill.cpp b/src/mbgl/shaders/mtl/fill.cpp new file mode 100644 index 000000000..448a8786d --- /dev/null +++ b/src/mbgl/shaders/mtl/fill.cpp @@ -0,0 +1,82 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Float2, 1, "a_color"}, + AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_opacity"}, + + // This shader doesn't use it, but we need this so that the layer can assign the same + // attributes to all the drawables. If/When `VertexAttributeArray::resolve` allows it, + // this can be removed. + AttributeInfo{8, gfx::AttributeDataType::Float2, 1, "a_outline_color"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{3, true, false, sizeof(FillDrawableUBO), "FillDrawableUBO"}, + UniformBlockInfo{4, true, true, sizeof(FillEvaluatedPropsUBO), "FillEvaluatedPropsUBO"}, + UniformBlockInfo{5, true, false, sizeof(FillInterpolateUBO), "FillInterpolateUBO"}, + UniformBlockInfo{6, true, true, sizeof(FillPermutationUBO), "FillPermutationUBO"}, + UniformBlockInfo{7, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = {}; + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Float2, 1, "a_outline_color"}, + AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_opacity"}, + + // See `a_outline_color` in FillShader + AttributeInfo{8, gfx::AttributeDataType::Float2, 1, "a_color"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{3, true, false, sizeof(FillOutlineDrawableUBO), "FillOutlineDrawableUBO"}, + UniformBlockInfo{4, true, true, sizeof(FillOutlineEvaluatedPropsUBO), "FillOutlineEvaluatedPropsUBO"}, + UniformBlockInfo{5, true, false, sizeof(FillOutlineInterpolateUBO), "FillOutlineInterpolateUBO"}, + UniformBlockInfo{6, true, true, sizeof(FillOutlinePermutationUBO), "FillOutlinePermutationUBO"}, + UniformBlockInfo{7, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = {}; + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::UShort4, 1, "a_pattern_from"}, + AttributeInfo{2, gfx::AttributeDataType::UShort4, 1, "a_pattern_to"}, + AttributeInfo{3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{4, true, true, sizeof(FillPatternDrawableUBO), "FillPatternDrawableUBO"}, + UniformBlockInfo{5, true, false, sizeof(FillPatternTilePropsUBO), "FillPatternTilePropsUBO"}, + UniformBlockInfo{6, true, true, sizeof(FillPatternEvaluatedPropsUBO), "FillPatternEvaluatedPropsUBO"}, + UniformBlockInfo{7, true, false, sizeof(FillPatternInterpolateUBO), "FillPatternInterpolateUBO"}, + UniformBlockInfo{8, true, true, sizeof(FillPatternPermutationUBO), "FillPatternPermutationUBO"}, + UniformBlockInfo{9, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image"}, +}; + +const std::array + ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::UShort4, 1, "a_pattern_from"}, + AttributeInfo{2, gfx::AttributeDataType::UShort4, 1, "a_pattern_to"}, + AttributeInfo{3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{4, true, true, sizeof(FillOutlinePatternDrawableUBO), "FillOutlinePatternDrawableUBO"}, + UniformBlockInfo{5, true, false, sizeof(FillOutlinePatternTilePropsUBO), "FillOutlinePatternTilePropsUBO"}, + UniformBlockInfo{6, true, true, sizeof(FillOutlinePatternEvaluatedPropsUBO), "FillOutlinePatternEvaluatedPropsUBO"}, + UniformBlockInfo{7, true, false, sizeof(FillOutlinePatternInterpolateUBO), "FillOutlinePatternInterpolateUBO"}, + UniformBlockInfo{8, true, true, sizeof(FillOutlinePatternPermutationUBO), "FillOutlinePatternPermutationUBO"}, + UniformBlockInfo{9, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = + { + TextureInfo{0, "u_image"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/fill_extrusion.cpp b/src/mbgl/shaders/mtl/fill_extrusion.cpp new file mode 100644 index 000000000..a320f95e8 --- /dev/null +++ b/src/mbgl/shaders/mtl/fill_extrusion.cpp @@ -0,0 +1,24 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Short4, 1, "a_normal_ed"}, + AttributeInfo{2, gfx::AttributeDataType::Float4, 1, "a_color"}, + AttributeInfo{3, gfx::AttributeDataType::Float, 1, "a_base"}, + AttributeInfo{4, gfx::AttributeDataType::Float, 1, "a_height"}, +}; +const std::array ShaderSource::uniforms = + { + UniformBlockInfo{5, true, false, sizeof(FillExtrusionDrawableUBO), "FillExtrusionDrawableUBO"}, + UniformBlockInfo{6, true, false, sizeof(FillExtrusionDrawablePropsUBO), "FillExtrusionDrawablePropsUBO"}, + UniformBlockInfo{7, true, false, sizeof(FillExtrusionInterpolateUBO), "FillExtrusionInterpolateUBO"}, + UniformBlockInfo{8, true, false, sizeof(FillExtrusionPermutationUBO), "FillExtrusionPermutationUBO"}, + UniformBlockInfo{9, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/fill_extrusion_pattern.cpp b/src/mbgl/shaders/mtl/fill_extrusion_pattern.cpp new file mode 100644 index 000000000..70e90f5f9 --- /dev/null +++ b/src/mbgl/shaders/mtl/fill_extrusion_pattern.cpp @@ -0,0 +1,14 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array + ShaderSource::attributes = {}; +const std::array + ShaderSource::uniforms = {}; +const std::array + ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/heatmap.cpp b/src/mbgl/shaders/mtl/heatmap.cpp new file mode 100644 index 000000000..b6a42f3f4 --- /dev/null +++ b/src/mbgl/shaders/mtl/heatmap.cpp @@ -0,0 +1,21 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Float2, 1, "a_weight"}, + AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_radius"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{3, true, false, sizeof(HeatmapDrawableUBO), "HeatmapDrawableUBO"}, + UniformBlockInfo{4, true, true, sizeof(HeatmapEvaluatedPropsUBO), "HeatmapEvaluatedPropsUBO"}, + UniformBlockInfo{5, true, false, sizeof(HeatmapInterpolateUBO), "HeatmapInterpolateUBO"}, + UniformBlockInfo{6, true, true, sizeof(HeatmapPermutationUBO), "HeatmapPermutationUBO"}, + UniformBlockInfo{7, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = {}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/heatmap_texture.cpp b/src/mbgl/shaders/mtl/heatmap_texture.cpp new file mode 100644 index 000000000..6d9546363 --- /dev/null +++ b/src/mbgl/shaders/mtl/heatmap_texture.cpp @@ -0,0 +1,20 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = + { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, +}; +const std::array ShaderSource::uniforms = + { + UniformBlockInfo{1, true, true, sizeof(HeatmapTextureDrawableUBO), "HeatmapTextureDrawableUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image"}, + TextureInfo{1, "u_color_ramp"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/hillshade.cpp b/src/mbgl/shaders/mtl/hillshade.cpp new file mode 100644 index 000000000..a7b0f32a5 --- /dev/null +++ b/src/mbgl/shaders/mtl/hillshade.cpp @@ -0,0 +1,19 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Short2, 1, "a_texture_pos"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{2, true, true, sizeof(HillshadeDrawableUBO), "HillshadeDrawableUBO"}, + UniformBlockInfo{3, false, true, sizeof(HillshadeEvaluatedPropsUBO), "HillshadeEvaluatedPropsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/hillshade_prepare.cpp b/src/mbgl/shaders/mtl/hillshade_prepare.cpp new file mode 100644 index 000000000..6ae470498 --- /dev/null +++ b/src/mbgl/shaders/mtl/hillshade_prepare.cpp @@ -0,0 +1,20 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array + ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Short2, 1, "a_texture_pos"}, +}; +const std::array + ShaderSource::uniforms = { + UniformBlockInfo{2, true, true, sizeof(HillshadePrepareDrawableUBO), "HillshadePrepareDrawableUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/line.cpp b/src/mbgl/shaders/mtl/line.cpp new file mode 100644 index 000000000..514cf2f55 --- /dev/null +++ b/src/mbgl/shaders/mtl/line.cpp @@ -0,0 +1,49 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos_normal"}, + AttributeInfo{1, gfx::AttributeDataType::UByte4, 1, "a_data"}, + AttributeInfo{2, gfx::AttributeDataType::Float4, 1, "a_color"}, + AttributeInfo{3, gfx::AttributeDataType::Float2, 1, "a_blur"}, + AttributeInfo{4, gfx::AttributeDataType::Float2, 1, "a_opacity"}, + AttributeInfo{5, gfx::AttributeDataType::Float2, 1, "a_gapwidth"}, + AttributeInfo{6, gfx::AttributeDataType::Float2, 1, "a_offset"}, + AttributeInfo{7, gfx::AttributeDataType::Float2, 1, "a_width"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{8, true, true, sizeof(LineUBO), "LineUBO"}, + UniformBlockInfo{9, true, false, sizeof(LinePropertiesUBO), "LinePropertiesUBO"}, + UniformBlockInfo{10, true, false, sizeof(LineInterpolationUBO), "LineInterpolationUBO"}, + UniformBlockInfo{11, true, true, sizeof(LinePermutationUBO), "LinePermutationUBO"}, + UniformBlockInfo{12, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = {}; + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos_normal"}, + AttributeInfo{1, gfx::AttributeDataType::UByte4, 1, "a_data"}, + AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_blur"}, + AttributeInfo{3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, + AttributeInfo{4, gfx::AttributeDataType::Float2, 1, "a_gapwidth"}, + AttributeInfo{5, gfx::AttributeDataType::Float2, 1, "a_offset"}, + AttributeInfo{6, gfx::AttributeDataType::Float2, 1, "a_width"}, + AttributeInfo{7, gfx::AttributeDataType::UShort4, 1, "a_pattern_from"}, + AttributeInfo{8, gfx::AttributeDataType::UShort4, 1, "a_pattern_to"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{9, true, true, sizeof(LinePatternUBO), "LinePatternUBO"}, + UniformBlockInfo{10, true, false, sizeof(LinePatternPropertiesUBO), "LinePatternPropertiesUBO"}, + UniformBlockInfo{11, true, false, sizeof(LinePatternInterpolationUBO), "LinePatternInterpolationUBO"}, + UniformBlockInfo{12, true, false, sizeof(LinePatternTilePropertiesUBO), "LinePatternTilePropertiesUBO"}, + UniformBlockInfo{13, true, true, sizeof(LinePermutationUBO), "LinePermutationUBO"}, + UniformBlockInfo{14, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/line_gradient.cpp b/src/mbgl/shaders/mtl/line_gradient.cpp new file mode 100644 index 000000000..fc980003e --- /dev/null +++ b/src/mbgl/shaders/mtl/line_gradient.cpp @@ -0,0 +1,27 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos_normal"}, + AttributeInfo{1, gfx::AttributeDataType::UByte4, 1, "a_data"}, + AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_blur"}, + AttributeInfo{3, gfx::AttributeDataType::Float2, 1, "a_opacity"}, + AttributeInfo{4, gfx::AttributeDataType::Float2, 1, "a_gapwidth"}, + AttributeInfo{5, gfx::AttributeDataType::Float2, 1, "a_offset"}, + AttributeInfo{6, gfx::AttributeDataType::Float2, 1, "a_width"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{7, true, true, sizeof(LineGradientUBO), "LineGradientUBO"}, + UniformBlockInfo{8, true, false, sizeof(LineGradientPropertiesUBO), "LineGradientPropertiesUBO"}, + UniformBlockInfo{9, true, false, sizeof(LineGradientInterpolationUBO), "LineGradientInterpolationUBO"}, + UniformBlockInfo{10, true, true, sizeof(LinePermutationUBO), "LinePermutationUBO"}, + UniformBlockInfo{11, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/raster.cpp b/src/mbgl/shaders/mtl/raster.cpp new file mode 100644 index 000000000..c0ba80422 --- /dev/null +++ b/src/mbgl/shaders/mtl/raster.cpp @@ -0,0 +1,19 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + AttributeInfo{1, gfx::AttributeDataType::Short2, 1, "a_texture_pos"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{2, true, true, sizeof(RasterDrawableUBO), "RasterDrawableUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_image0"}, + TextureInfo{1, "u_image1"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/shader_program.cpp b/src/mbgl/shaders/mtl/shader_program.cpp index bb07378ae..545b9c75e 100644 --- a/src/mbgl/shaders/mtl/shader_program.cpp +++ b/src/mbgl/shaders/mtl/shader_program.cpp @@ -22,8 +22,32 @@ using namespace std::string_literals; namespace mbgl { -namespace mtl { +shaders::AttributeInfo::AttributeInfo(std::size_t index_, + gfx::AttributeDataType dataType_, + std::size_t count_, + std::string_view name_) + : index(index_), + dataType(dataType_), + count(count_), + name(name_), + nameID(StringIndexer::get(name_)) {} + +shaders::UniformBlockInfo::UniformBlockInfo( + std::size_t index_, bool vertex_, bool fragment_, std::size_t size_, std::string_view name_) + : index(index_), + vertex(vertex_), + fragment(fragment_), + size(size_), + name(name_), + nameID(StringIndexer::get(name_)) {} + +shaders::TextureInfo::TextureInfo(std::size_t index_, std::string_view name_) + : index(index_), + name(name_), + nameID(StringIndexer::get(name_)) {} + +namespace mtl { namespace { MTL::BlendOperation metalBlendOperation(const gfx::ColorBlendEquationType& colorBlend) { switch (colorBlend) { diff --git a/src/mbgl/shaders/mtl/symbol_icon.cpp b/src/mbgl/shaders/mtl/symbol_icon.cpp new file mode 100644 index 000000000..7a2b8242e --- /dev/null +++ b/src/mbgl/shaders/mtl/symbol_icon.cpp @@ -0,0 +1,30 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = { + // always attributes + AttributeInfo{0, gfx::AttributeDataType::Short4, 1, "a_pos_offset"}, + AttributeInfo{1, gfx::AttributeDataType::UShort4, 1, "a_data"}, + AttributeInfo{2, gfx::AttributeDataType::Short4, 1, "a_pixeloffset"}, + AttributeInfo{3, gfx::AttributeDataType::Float3, 1, "a_projected_pos"}, + AttributeInfo{4, gfx::AttributeDataType::Float, 1, "a_fade_opacity"}, + + // sometimes uniforms + AttributeInfo{5, gfx::AttributeDataType::Float, 1, "a_opacity"}, +}; +const std::array ShaderSource::uniforms = { + UniformBlockInfo{8, true, true, sizeof(SymbolDrawableUBO), "SymbolDrawableUBO"}, + UniformBlockInfo{9, true, true, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"}, + UniformBlockInfo{10, true, false, sizeof(SymbolDrawableTilePropsUBO), "SymbolDrawableTilePropsUBO"}, + UniformBlockInfo{11, true, false, sizeof(SymbolDrawableInterpolateUBO), "SymbolDrawableInterpolateUBO"}, + UniformBlockInfo{12, true, true, sizeof(SymbolPermutationUBO), "SymbolPermutationUBO"}, + UniformBlockInfo{13, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_texture"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/symbol_sdf.cpp b/src/mbgl/shaders/mtl/symbol_sdf.cpp new file mode 100644 index 000000000..b1cf6d428 --- /dev/null +++ b/src/mbgl/shaders/mtl/symbol_sdf.cpp @@ -0,0 +1,36 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::attributes = + { + // always attributes + AttributeInfo{0, gfx::AttributeDataType::Short4, 1, "a_pos_offset"}, + AttributeInfo{1, gfx::AttributeDataType::UShort4, 1, "a_data"}, + AttributeInfo{2, gfx::AttributeDataType::Short4, 1, "a_pixeloffset"}, + AttributeInfo{3, gfx::AttributeDataType::Float3, 1, "a_projected_pos"}, + AttributeInfo{4, gfx::AttributeDataType::Float, 1, "a_fade_opacity"}, + + // sometimes uniforms + AttributeInfo{5, gfx::AttributeDataType::Float4, 1, "a_fill_color"}, + AttributeInfo{6, gfx::AttributeDataType::Float4, 1, "a_halo_color"}, + AttributeInfo{7, gfx::AttributeDataType::Float, 1, "a_opacity"}, + AttributeInfo{8, gfx::AttributeDataType::Float, 1, "a_halo_width"}, + AttributeInfo{9, gfx::AttributeDataType::Float, 1, "a_halo_blur"}, +}; +const std::array ShaderSource::uniforms = + { + UniformBlockInfo{10, true, true, sizeof(SymbolDrawableUBO), "SymbolDrawableUBO"}, + UniformBlockInfo{11, true, false, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"}, + UniformBlockInfo{12, true, true, sizeof(SymbolDrawableTilePropsUBO), "SymbolDrawableTilePropsUBO"}, + UniformBlockInfo{13, true, false, sizeof(SymbolDrawableInterpolateUBO), "SymbolDrawableInterpolateUBO"}, + UniformBlockInfo{14, true, true, sizeof(SymbolPermutationUBO), "SymbolPermutationUBO"}, + UniformBlockInfo{15, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_texture"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/mtl/symbol_text_and_icon.cpp b/src/mbgl/shaders/mtl/symbol_text_and_icon.cpp new file mode 100644 index 000000000..d735e1862 --- /dev/null +++ b/src/mbgl/shaders/mtl/symbol_text_and_icon.cpp @@ -0,0 +1,36 @@ +#include + +namespace mbgl { +namespace shaders { + +const std::array + ShaderSource::attributes = { + // always attributes + AttributeInfo{0, gfx::AttributeDataType::Short4, 1, "a_pos_offset"}, + AttributeInfo{1, gfx::AttributeDataType::UShort4, 1, "a_data"}, + AttributeInfo{2, gfx::AttributeDataType::Float3, 1, "a_projected_pos"}, + AttributeInfo{3, gfx::AttributeDataType::Float, 1, "a_fade_opacity"}, + + // sometimes uniforms + AttributeInfo{4, gfx::AttributeDataType::Float4, 1, "a_fill_color"}, + AttributeInfo{5, gfx::AttributeDataType::Float4, 1, "a_halo_color"}, + AttributeInfo{6, gfx::AttributeDataType::Float, 1, "a_opacity"}, + AttributeInfo{7, gfx::AttributeDataType::Float, 1, "a_halo_width"}, + AttributeInfo{8, gfx::AttributeDataType::Float, 1, "a_halo_blur"}, +}; +const std::array + ShaderSource::uniforms = { + UniformBlockInfo{9, true, true, sizeof(SymbolDrawableUBO), "SymbolDrawableUBO"}, + UniformBlockInfo{10, true, false, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"}, + UniformBlockInfo{11, true, true, sizeof(SymbolDrawableTilePropsUBO), "SymbolDrawableTilePropsUBO"}, + UniformBlockInfo{12, true, false, sizeof(SymbolDrawableInterpolateUBO), "SymbolDrawableInterpolateUBO"}, + UniformBlockInfo{13, true, true, sizeof(SymbolPermutationUBO), "SymbolPermutationUBO"}, + UniformBlockInfo{14, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, "u_texture"}, + TextureInfo{1, "u_texture_icon"}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/util/hash.hpp b/src/mbgl/util/hash.hpp index cb92fe9be..299d018dd 100644 --- a/src/mbgl/util/hash.hpp +++ b/src/mbgl/util/hash.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace mbgl { namespace util { @@ -19,5 +20,24 @@ std::size_t hash(Args&&... args) { return seed; } +namespace detail { +template +using TIterVal = std::enable_if_t::value, typename TIter::value_type>; +} // namespace detail + +/// Generate a hash key from a collection of integer values which doesn't depend on their order. +/// Adapted from https://stackoverflow.com/a/76993810/135138 +/// Default factor prime value from 64-bit FNV hash. +template , TKey factor = 1099511628211LL> +TKey order_independent_hash(TIter cur, const TIter end) { + detail::TIterVal sum = 0, product = 1; + for (; cur != end; ++cur) { + const auto& value = *cur; + sum += value; + product *= (1 + value) * factor; + } + return sum ^ product; +} + } // namespace util } // namespace mbgl diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c12e11f13..a11b58587 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -88,6 +88,7 @@ add_library( ${PROJECT_SOURCE_DIR}/test/util/dtoa.test.cpp ${PROJECT_SOURCE_DIR}/test/util/geo.test.cpp ${PROJECT_SOURCE_DIR}/test/util/grid_index.test.cpp + ${PROJECT_SOURCE_DIR}/test/util/hash.test.cpp ${PROJECT_SOURCE_DIR}/test/util/http_timeout.test.cpp ${PROJECT_SOURCE_DIR}/test/util/image.test.cpp ${PROJECT_SOURCE_DIR}/test/util/mapbox.test.cpp @@ -128,6 +129,7 @@ if(MLN_WITH_OPENGL) PRIVATE ${PROJECT_SOURCE_DIR}/test/api/custom_layer.test.cpp ${PROJECT_SOURCE_DIR}/test/gl/bucket.test.cpp + ${PROJECT_SOURCE_DIR}/test/gl/enum.test.cpp ${PROJECT_SOURCE_DIR}/test/gl/context.test.cpp ${PROJECT_SOURCE_DIR}/test/gl/gl_functions.test.cpp ${PROJECT_SOURCE_DIR}/test/gl/object.test.cpp @@ -236,4 +238,4 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux) mbgl-test PRIVATE USE_CPP_TEST_SERVER ) -endif() \ No newline at end of file +endif() diff --git a/test/gl/context.test.cpp b/test/gl/context.test.cpp index c8bc88fd6..e04d08f3b 100644 --- a/test/gl/context.test.cpp +++ b/test/gl/context.test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +115,9 @@ TEST(GLContextMode, Shared) { MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos)); MBGL_CHECK_ERROR(glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3)); + + frontend.getRenderer()->reduceMemoryUse(); + ASSERT_TRUE(static_cast(frontend.getBackend()->getContext()).empty()); } test::checkImage("test/fixtures/shared_context", frontend.render(map).image, 0.5, 0.1); diff --git a/test/gl/enum.test.cpp b/test/gl/enum.test.cpp new file mode 100644 index 000000000..ab4a95153 --- /dev/null +++ b/test/gl/enum.test.cpp @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#include + +using namespace mbgl; +using namespace mbgl::gfx; +using namespace mbgl::gl; + +TEST(GL, DrawModeType) { + ASSERT_EQ(GL_POINTS, Enum::to(DrawModeType::Points)); + ASSERT_EQ(GL_LINES, Enum::to(DrawModeType::Lines)); + ASSERT_EQ(GL_LINE_LOOP, Enum::to(DrawModeType::LineLoop)); + ASSERT_EQ(GL_LINE_STRIP, Enum::to(DrawModeType::LineStrip)); + ASSERT_EQ(GL_TRIANGLES, Enum::to(DrawModeType::Triangles)); + ASSERT_EQ(GL_TRIANGLE_STRIP, Enum::to(DrawModeType::TriangleStrip)); + ASSERT_EQ(GL_TRIANGLE_FAN, Enum::to(DrawModeType::TriangleFan)); + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); +} + +namespace { +template +auto enumIdentity(T x) { + return Enum::from(Enum::to(x)); +} +} // namespace + +TEST(GL, ColorBlendEquationType) { + // const auto identity = [](auto x){ return Enum::from(Enum::to(x)); + // }; + ASSERT_EQ(ColorBlendEquationType::Add, enumIdentity(ColorBlendEquationType::Add)); + ASSERT_EQ(ColorBlendEquationType::Subtract, enumIdentity(ColorBlendEquationType::Subtract)); + ASSERT_EQ(ColorBlendEquationType::ReverseSubtract, enumIdentity(ColorBlendEquationType::ReverseSubtract)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(ColorBlendEquationType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, ColorBlendFactorType) { + ASSERT_EQ(ColorBlendFactorType::Zero, enumIdentity(ColorBlendFactorType::Zero)); + ASSERT_EQ(ColorBlendFactorType::One, enumIdentity(ColorBlendFactorType::One)); + ASSERT_EQ(ColorBlendFactorType::SrcColor, enumIdentity(ColorBlendFactorType::SrcColor)); + ASSERT_EQ(ColorBlendFactorType::OneMinusSrcColor, enumIdentity(ColorBlendFactorType::OneMinusSrcColor)); + ASSERT_EQ(ColorBlendFactorType::DstColor, enumIdentity(ColorBlendFactorType::DstColor)); + ASSERT_EQ(ColorBlendFactorType::OneMinusDstColor, enumIdentity(ColorBlendFactorType::OneMinusDstColor)); + ASSERT_EQ(ColorBlendFactorType::SrcAlpha, enumIdentity(ColorBlendFactorType::SrcAlpha)); + ASSERT_EQ(ColorBlendFactorType::OneMinusSrcAlpha, enumIdentity(ColorBlendFactorType::OneMinusSrcAlpha)); + ASSERT_EQ(ColorBlendFactorType::DstAlpha, enumIdentity(ColorBlendFactorType::DstAlpha)); + ASSERT_EQ(ColorBlendFactorType::OneMinusDstAlpha, enumIdentity(ColorBlendFactorType::OneMinusDstAlpha)); + ASSERT_EQ(ColorBlendFactorType::ConstantColor, enumIdentity(ColorBlendFactorType::ConstantColor)); + ASSERT_EQ(ColorBlendFactorType::OneMinusConstantColor, enumIdentity(ColorBlendFactorType::OneMinusConstantColor)); + ASSERT_EQ(ColorBlendFactorType::ConstantAlpha, enumIdentity(ColorBlendFactorType::ConstantAlpha)); + ASSERT_EQ(ColorBlendFactorType::OneMinusConstantAlpha, enumIdentity(ColorBlendFactorType::OneMinusConstantAlpha)); + ASSERT_EQ(ColorBlendFactorType::SrcAlphaSaturate, enumIdentity(ColorBlendFactorType::SrcAlphaSaturate)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(ColorBlendFactorType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, DepthFunctionType) { + ASSERT_EQ(DepthFunctionType::Never, enumIdentity(DepthFunctionType::Never)); + ASSERT_EQ(DepthFunctionType::Less, enumIdentity(DepthFunctionType::Less)); + ASSERT_EQ(DepthFunctionType::Equal, enumIdentity(DepthFunctionType::Equal)); + ASSERT_EQ(DepthFunctionType::LessEqual, enumIdentity(DepthFunctionType::LessEqual)); + ASSERT_EQ(DepthFunctionType::Greater, enumIdentity(DepthFunctionType::Greater)); + ASSERT_EQ(DepthFunctionType::NotEqual, enumIdentity(DepthFunctionType::NotEqual)); + ASSERT_EQ(DepthFunctionType::GreaterEqual, enumIdentity(DepthFunctionType::GreaterEqual)); + ASSERT_EQ(DepthFunctionType::Always, enumIdentity(DepthFunctionType::Always)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(DepthFunctionType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, DepthMaskType) { + ASSERT_EQ(DepthMaskType::ReadOnly, enumIdentity(DepthMaskType::ReadOnly)); + ASSERT_EQ(DepthMaskType::ReadWrite, enumIdentity(DepthMaskType::ReadWrite)); + + // anything non-zero is true, there's no way to represent invalid + ASSERT_EQ(GL_TRUE, Enum::to(static_cast(-1))); +} + +TEST(GL, StencilFunctionType) { + ASSERT_EQ(StencilFunctionType::Never, enumIdentity(StencilFunctionType::Never)); + ASSERT_EQ(StencilFunctionType::Less, enumIdentity(StencilFunctionType::Less)); + ASSERT_EQ(StencilFunctionType::Equal, enumIdentity(StencilFunctionType::Equal)); + ASSERT_EQ(StencilFunctionType::LessEqual, enumIdentity(StencilFunctionType::LessEqual)); + ASSERT_EQ(StencilFunctionType::Greater, enumIdentity(StencilFunctionType::Greater)); + ASSERT_EQ(StencilFunctionType::NotEqual, enumIdentity(StencilFunctionType::NotEqual)); + ASSERT_EQ(StencilFunctionType::GreaterEqual, enumIdentity(StencilFunctionType::GreaterEqual)); + ASSERT_EQ(StencilFunctionType::Always, enumIdentity(StencilFunctionType::Always)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(StencilFunctionType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, StencilOpType) { + ASSERT_EQ(StencilOpType::Keep, enumIdentity(StencilOpType::Keep)); + ASSERT_EQ(StencilOpType::Zero, enumIdentity(StencilOpType::Zero)); + ASSERT_EQ(StencilOpType::Replace, enumIdentity(StencilOpType::Replace)); + ASSERT_EQ(StencilOpType::Increment, enumIdentity(StencilOpType::Increment)); + ASSERT_EQ(StencilOpType::IncrementWrap, enumIdentity(StencilOpType::IncrementWrap)); + ASSERT_EQ(StencilOpType::Decrement, enumIdentity(StencilOpType::Decrement)); + ASSERT_EQ(StencilOpType::DecrementWrap, enumIdentity(StencilOpType::DecrementWrap)); + ASSERT_EQ(StencilOpType::Invert, enumIdentity(StencilOpType::Invert)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(StencilOpType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, CullFaceSideType) { + ASSERT_EQ(CullFaceSideType::Front, enumIdentity(CullFaceSideType::Front)); + ASSERT_EQ(CullFaceSideType::Back, enumIdentity(CullFaceSideType::Back)); + ASSERT_EQ(CullFaceSideType::FrontAndBack, enumIdentity(CullFaceSideType::FrontAndBack)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(CullFaceSideType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, CullFaceWindingType) { + ASSERT_EQ(CullFaceWindingType::Clockwise, enumIdentity(CullFaceWindingType::Clockwise)); + ASSERT_EQ(CullFaceWindingType::CounterClockwise, enumIdentity(CullFaceWindingType::CounterClockwise)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(CullFaceWindingType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, BufferUsageType) { + ASSERT_EQ(BufferUsageType::StreamDraw, enumIdentity(BufferUsageType::StreamDraw)); + ASSERT_EQ(BufferUsageType::StaticDraw, enumIdentity(BufferUsageType::StaticDraw)); + ASSERT_EQ(BufferUsageType::DynamicDraw, enumIdentity(BufferUsageType::DynamicDraw)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(BufferUsageType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, TexturePixelType) { + ASSERT_EQ(TexturePixelType::RGBA, enumIdentity(TexturePixelType::RGBA)); + ASSERT_EQ(TexturePixelType::Alpha, enumIdentity(TexturePixelType::Alpha)); + ASSERT_EQ(TexturePixelType::Stencil, enumIdentity(TexturePixelType::Stencil)); + ASSERT_EQ(TexturePixelType::Depth, enumIdentity(TexturePixelType::Depth)); + ASSERT_EQ(TexturePixelType::Luminance, enumIdentity(TexturePixelType::Luminance)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(TexturePixelType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, TextureChannelDataType) { + ASSERT_EQ(TextureChannelDataType::UnsignedByte, enumIdentity(TextureChannelDataType::UnsignedByte)); + ASSERT_EQ(TextureChannelDataType::HalfFloat, enumIdentity(TextureChannelDataType::HalfFloat)); + ASSERT_EQ(TextureChannelDataType::Float, enumIdentity(TextureChannelDataType::Float)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(TextureChannelDataType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, RenderbufferPixelType) { + ASSERT_EQ(RenderbufferPixelType::RGBA, enumIdentity(RenderbufferPixelType::RGBA)); + ASSERT_EQ(RenderbufferPixelType::Depth, enumIdentity(RenderbufferPixelType::Depth)); + ASSERT_EQ(RenderbufferPixelType::DepthStencil, enumIdentity(RenderbufferPixelType::DepthStencil)); + + ASSERT_EQ(GL_INVALID_ENUM, Enum::to(static_cast(-1))); + ASSERT_EQ(RenderbufferPixelType{}, Enum::from(GL_RGBA8)); +} + +TEST(GL, sizedFor) { + ASSERT_EQ(GL_RGBA, + Enum::sizedFor(TexturePixelType::RGBA, TextureChannelDataType::UnsignedByte)); + ASSERT_EQ(GL_RGBA16F, + Enum::sizedFor(TexturePixelType::RGBA, TextureChannelDataType::HalfFloat)); + ASSERT_EQ(GL_INVALID_ENUM, + Enum::sizedFor(TexturePixelType::Alpha, TextureChannelDataType::HalfFloat)); + ASSERT_EQ(GL_RGBA32F, Enum::sizedFor(TexturePixelType::RGBA, TextureChannelDataType::Float)); + ASSERT_EQ(GL_INVALID_ENUM, + Enum::sizedFor(TexturePixelType::Alpha, TextureChannelDataType::Float)); + ASSERT_EQ(GL_INVALID_ENUM, + Enum::sizedFor(TexturePixelType::RGBA, static_cast(-1))); +} diff --git a/test/renderer/shader_registry.test.cpp b/test/renderer/shader_registry.test.cpp index ee362370a..d9ecd1ee3 100644 --- a/test/renderer/shader_registry.test.cpp +++ b/test/renderer/shader_registry.test.cpp @@ -207,7 +207,11 @@ TEST(ShaderRegistry, NamedReplace) { } // Test replacing an actual program instance with a similar instance +#if MLN_LEGACY_RENDERER TEST(ShaderRegistry, GLSLReplacement_NoOp) { +#else +TEST(ShaderRegistry, DISABLED_GLSLReplacement_NoOp) { +#endif MapInstance::ShaderAndStyleObserver observer; util::RunLoop runLoop; auto map = MapInstance(1.0f, observer); @@ -233,7 +237,11 @@ TEST(ShaderRegistry, GLSLReplacement_NoOp) { // Test replacing an actual program with a similar instance using a different // fragment shader +#if MLN_LEGACY_RENDERER TEST(ShaderRegistry, GLSLReplacement1) { +#else +TEST(ShaderRegistry, DISABLED_GLSLReplacement1) { +#endif MapInstance::ShaderAndStyleObserver observer; util::RunLoop runLoop; auto map = MapInstance(1.0f, observer); @@ -267,7 +275,11 @@ void main() { // Test replacing an actual program with a similar instance using a different // fragment shader +#if MLN_LEGACY_RENDERER TEST(ShaderRegistry, GLSLReplacement2) { +#else +TEST(ShaderRegistry, DISABLED_GLSLReplacement2) { +#endif MapInstance::ShaderAndStyleObserver observer; util::RunLoop runLoop; auto map = MapInstance(1.0f, observer); diff --git a/test/util/hash.test.cpp b/test/util/hash.test.cpp new file mode 100644 index 000000000..203dacd39 --- /dev/null +++ b/test/util/hash.test.cpp @@ -0,0 +1,54 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace mbgl; + +TEST(OrderIndependentHash, Permutations) { + // Try collections of up to this many elements + constexpr int maxSize = 6; + // Try this many different sets of values for each size + constexpr int iterations = 10; + // Use values up to this large + constexpr size_t maxVal = 10; + + std::seed_seq seed{0xf00dLL}; + std::default_random_engine engine(seed); + std::uniform_int_distribution distribution(0, maxVal); + + for (int curSize = 1; curSize <= maxSize; ++curSize) { + for (int ii = 0; ii < iterations; ++ii) { + // Generate `curSize` random values + std::vector values; + for (int jj = 0; jj < curSize; ++jj) { + values.push_back(distribution(engine)); + } + + // Generate the hash for each permutation, comparing subsequent values to the first one. + bool isFirst = true; + size_t initialValue = 0; + do { + const auto curValue = util::order_independent_hash(values.begin(), values.end()); + if (isFirst || curValue != initialValue) { + for (auto v : values) { + std::cout << v << ","; + } + std::cout << " - " << std::hex << curValue << std::endl; + } + if (isFirst) { + initialValue = curValue; + isFirst = false; + } else { + EXPECT_EQ(initialValue, curValue); + } + } while (std::next_permutation(values.begin(), values.end())); + } + } +} diff --git a/test/util/offscreen_texture.test.cpp b/test/util/offscreen_texture.test.cpp index adf3f3dce..282579101 100644 --- a/test/util/offscreen_texture.test.cpp +++ b/test/util/offscreen_texture.test.cpp @@ -4,12 +4,17 @@ #include #include #include -#include #include #include #include #include +#if MLN_LEGACY_RENDERER +#include +#else +#include +#endif + using namespace mbgl; using namespace mbgl::platform; @@ -75,11 +80,7 @@ struct Buffer { GLuint buffer = 0; }; -#if MLN_LEGACY_RENDERER TEST(OffscreenTexture, RenderToTexture) { -#else -TEST(OffscreenTexture, DISABLED_RenderToTexture) { -#endif if (gfx::Backend::GetType() != gfx::Backend::Type::OpenGL) { return; } @@ -145,13 +146,13 @@ void main() { // Then, create a texture, bind it, and render yellow to that texture. This // should not affect the originally bound FBO. - gl::OffscreenTexture texture(context, {128, 128}); + gl::OffscreenTexture offscreenTexture(context, {128, 128}); // Scissor test shouldn't leak after OffscreenTexture::bind(). MBGL_CHECK_ERROR(glScissor(32, 32, 64, 64)); context.scissorTest.setCurrentValue(true); - texture.getResource().bind(); + offscreenTexture.getResource().bind(); context.clear(Color(), {}, {}); @@ -161,7 +162,7 @@ void main() { MBGL_CHECK_ERROR(glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr)); MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3)); - auto image = texture.readStillImage(); + auto image = offscreenTexture.readStillImage(); test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0); // Now reset the FBO back to normal and retrieve the original (restored) framebuffer. @@ -172,12 +173,13 @@ void main() { // Now, composite the Framebuffer texture we've rendered to onto the main FBO. #if MLN_LEGACY_RENDERER - gl::bindTexture(context, 0, {texture.getTexture().getResource(), gfx::TextureFilterType::Linear}); + gl::bindTexture(context, 0, {offscreenTexture.getTexture().getResource(), gfx::TextureFilterType::Linear}); + MBGL_CHECK_ERROR(glUniform1i(u_texture, 0)); #else - // TODO: Implement based on gfx::Texture2D + offscreenTexture.getTexture()->setSamplerConfiguration({gfx::TextureFilterType::Linear}); + std::static_pointer_cast(offscreenTexture.getTexture())->bind(u_texture, 0); #endif MBGL_CHECK_ERROR(glUseProgram(compositeShader.program)); - MBGL_CHECK_ERROR(glUniform1i(u_texture, 0)); MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer)); MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos)); MBGL_CHECK_ERROR(glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));