diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a415e68b..e2db1e680 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/renderable.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/renderer_backend.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/rendering_stats.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/shader_group.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/shader_registry.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/shader.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gfx/uniform_block.hpp @@ -190,6 +191,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/renderer_observer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/renderer_state.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/shader_program_base.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/shader_group_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/shader_program_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_program_mtl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/storage/database_file_source.hpp @@ -393,6 +395,7 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/renderbuffer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/renderer_backend.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/rendering_stats.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/shader_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/shader_registry.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/stencil_mode.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/texture.hpp diff --git a/include/mbgl/gfx/gfx_types.hpp b/include/mbgl/gfx/gfx_types.hpp index b0002c4c6..a73d45241 100644 --- a/include/mbgl/gfx/gfx_types.hpp +++ b/include/mbgl/gfx/gfx_types.hpp @@ -41,6 +41,7 @@ enum class AttributeDataType : uint8_t { UShort2, UShort3, UShort4, + UShort8, Int, Int2, diff --git a/include/mbgl/gfx/shader_group.hpp b/include/mbgl/gfx/shader_group.hpp new file mode 100644 index 000000000..505a5b439 --- /dev/null +++ b/include/mbgl/gfx/shader_group.hpp @@ -0,0 +1,153 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace mbgl { +namespace gfx { + +class Context; + +/// @brief A ShaderGroup contains a collection of gfx::Shader. +/// Using the group, shaders may be dynamically registered or replaced +/// at runtime. +class ShaderGroup { +public: + ShaderGroup() = default; + ShaderGroup(const ShaderGroup&) = delete; + ShaderGroup(ShaderGroup&&) noexcept = delete; + ShaderGroup& operator=(const ShaderGroup&) = delete; + ShaderGroup& operator=(ShaderGroup&&) noexcept = delete; + virtual ~ShaderGroup() = default; + + /// @brief Checks if a shader exists in the group for the given name. + /// @param shaderName Name of shader + /// @return If a shader is found, true + [[nodiscard]] virtual bool isShader(const std::string& shaderName) const noexcept; + + /// @brief Get a shader from the group by name. + /// @param shaderName Name of shader + /// @return A `gfx::Shader` or `nullptr` if no shader is found with the + /// given name + [[nodiscard]] virtual const std::shared_ptr getShader(const std::string& shaderName) const noexcept; + + /// @brief Replace a matching shader in the group with the provided + /// instance. Shader type-names must match. + /// @param shader A `gfx::Shader`. The ShaderGroup will take ownership. + /// @return True if a match was found and the shader was replaced, false + /// otherwise. + [[nodiscard]] virtual bool replaceShader(std::shared_ptr&& shader) noexcept; + + /// @brief Replace a matching shader in the group with the provided + /// instance. Shader type-names must match. + /// This variant replaces by explicit name. + /// @param shader A `gfx::Shader`. The ShaderGroup will take ownership. + /// @param shaderName Unique name to register the shader under. + /// @return True if a match was found and the shader was replaced, false + /// otherwise. + [[nodiscard]] virtual bool replaceShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept; + + /// @brief Register a new shader with the group. If a shader is present + /// in the group with a conflicting name, registration will fail. + /// @param shader A `gfx::Shader` to register. The ShaderGroup will + /// take ownership. + /// @return True if the shader was registered, false if another shader is + /// already present with a conflicting name. + [[nodiscard]] virtual bool registerShader(std::shared_ptr&& shader) noexcept; + + /// @brief Register a new shader with the group. If a shader is present + /// in the group with a conflicting name, registration will fail. + /// This variant registers using an explicit name. + /// @param shader A `gfx::Shader` to register. The ShaderGroup will + /// take ownership. + /// @param shaderName Unique name to register the shader under. + /// @return True if the shader was registered, false if another shader is + /// already present with a conflicting name. + [[nodiscard]] virtual bool registerShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept; + + /// @brief Shorthand helper to quickly get a derived type from the group. + /// @tparam T Derived type, inheriting `gfx::Shader` + /// @param shaderName The group name to look up + /// @return T or nullptr if not found in the group + template , bool>* = nullptr> + std::shared_ptr get(const std::string& shaderName) noexcept { + auto shader = getShader(shaderName); + if (!shader || shader->typeName() != T::Name) { + return nullptr; + } + return std::static_pointer_cast(shader); + } + + /// @brief Shorthand helper to quickly get a derived type from the group. + /// This variant looks up shaders only by type name. + /// @tparam T Derived type, inheriting `gfx::Shader` + /// @return T or nullptr if not found in the group + template , bool>* = nullptr> + std::shared_ptr get() noexcept { + auto shader = getShader(std::string(T::Name)); + if (!shader || shader->typeName() != T::Name) { + return nullptr; + } + return std::static_pointer_cast(shader); + } + + /// @brief Ensure the destination 'to' is populated with the requested + /// shader. If already non-null, does nothing. + /// @tparam T Derived type, inheriting `gfx::Shader` + /// @param to Location to store the shader + /// @param shaderName The group name to look up + /// @return True if 'to' has a valid program object, false otherwise. + template , bool>* = nullptr> + bool populate(std::shared_ptr& to, const std::string& shaderName) noexcept { + if (to) { + return true; + } + + auto shader = getShader(shaderName); + if (!shader || shader->typeName() != T::Name) { + return false; + } + to = std::static_pointer_cast(shader); + return true; + } + + /// @brief Ensure the destination 'to' is populated with the requested + /// shader. If already non-null, does nothing. This variant looks up + /// shaders only by type name. + /// @tparam T Derived type, inheriting `gfx::Shader` + /// @param to Location to store the shader + /// @return True if 'to' has a valid program object, false otherwise. + template , bool>* = nullptr> + bool populate(std::shared_ptr& to) noexcept { + if (to) { + return true; + } + + auto shader = getShader(std::string(T::Name)); + if (!shader || shader->typeName() != T::Name) { + return false; + } + to = std::static_pointer_cast(shader); + return true; + } + + /// @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. + /// @return A `gfx::Shader` + virtual const std::shared_ptr getOrCreateShader(gfx::Context&, const std::vector&) { + return nullptr; + } + +private: + std::unordered_map> programs; + mutable std::shared_mutex programLock; +}; + +} // namespace gfx +} // namespace mbgl diff --git a/include/mbgl/gfx/shader_registry.hpp b/include/mbgl/gfx/shader_registry.hpp index ec3716ceb..312a3bb9e 100644 --- a/include/mbgl/gfx/shader_registry.hpp +++ b/include/mbgl/gfx/shader_registry.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -10,8 +10,10 @@ namespace mbgl { namespace gfx { -/// @brief A ShaderRegistry contains a collection of gfx::Shader instances. -/// Using the registry, shaders may be dynamically registered or replaced +using ShaderGroupPtr = std::shared_ptr; + +/// @brief A ShaderRegistry contains a collection of gfx::ShaderGroup instances. +/// Using the registry, shader groups may be dynamically registered or replaced /// at runtime. class ShaderRegistry { public: @@ -22,120 +24,44 @@ public: ShaderRegistry& operator=(ShaderRegistry&&) noexcept = delete; virtual ~ShaderRegistry() = default; - /// @brief Checks if a shader exists in the registry for the given name. - /// @param shaderName Name of shader - /// @return If a shader is found, true - [[nodiscard]] virtual bool isShader(const std::string& shaderName) const noexcept; + /// @brief Get the legacy shader group. + /// @return A `gfx::ShaderGroup` + [[nodiscard]] ShaderGroup& getLegacyGroup() noexcept; - /// @brief Get a shader from the registry by name. - /// @param shaderName Name of shader - /// @return A `gfx::Shader` or `nullptr` if no shader is found with the + /// @brief Checks if a shader group exists in the registry for the given name. + /// @param shaderGroupName Name of shader group + /// @return If a shader group is found, true + [[nodiscard]] virtual bool isShaderGroup(const std::string& shaderGroupName) const noexcept; + + /// @brief Get a shader group from the registry by name. + /// @param shaderGroupName Name of shader group + /// @return A `gfx::ShaderGroup` or `nullptr` if no shader group is found with the /// given name - [[nodiscard]] virtual const std::shared_ptr getShader(const std::string& shaderName) const noexcept; + [[nodiscard]] virtual const ShaderGroupPtr getShaderGroup(const std::string& shaderGroupName) const noexcept; - /// @brief Replace a matching shader in the registry with the provided - /// instance. Shader type-names must match. - /// @param shader A `gfx::Shader`. The ShaderRegistry will take ownership. - /// @return True if a match was found and the shader was replaced, false + /// @brief Replace a matching shader group in the registry with the provided + /// name. + /// @param shaderGroup A `gfx::ShaderGroup`. The ShaderRegistry will take ownership. + /// @param shaderGroupName Unique name to register the shader group under. + /// @return True if a match was found and the shader group was replaced, false /// otherwise. - [[nodiscard]] virtual bool replaceShader(std::shared_ptr&& shader) noexcept; + [[nodiscard]] virtual bool replaceShader(ShaderGroupPtr&& shaderGroup, const std::string& shaderName) noexcept; - /// @brief Replace a matching shader in the registry with the provided - /// instance. Shader type-names must match. - /// This variant replaces by explicit name. - /// @param shader A `gfx::Shader`. The ShaderRegistry will take ownership. - /// @param shaderName Unique name to register the shader under. - /// @return True if a match was found and the shader was replaced, false - /// otherwise. - [[nodiscard]] virtual bool replaceShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept; - - /// @brief Register a new shader with the registry. If a shader is present - /// in the registry with a conflicting name, registration will fail. - /// @param shader A `gfx::Shader` to register. The ShaderRegistry will + /// @brief Register a new shader group with the registry for the given name. + /// If a shader group is present in the registry with a conflicting name, + /// registration will fail. + /// @param shaderGroup A `gfx::ShaderGroup` to register. The ShaderRegistry will /// take ownership. - /// @return True if the shader was registered, false if another shader is + /// @param shaderGroupName Unique name to register the shader group under. + /// @return True if the shader group was registered, false if another shader group is /// already present with a conflicting name. - [[nodiscard]] virtual bool registerShader(std::shared_ptr&& shader) noexcept; - - /// @brief Register a new shader with the registry. If a shader is present - /// in the registry with a conflicting name, registration will fail. - /// This variant registers using an explicit name. - /// @param shader A `gfx::Shader` to register. The ShaderRegistry will - /// take ownership. - /// @param shaderName Unique name to register the shader under. - /// @return True if the shader was registered, false if another shader is - /// already present with a conflicting name. - [[nodiscard]] virtual bool registerShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept; - - /// @brief Shorthand helper to quickly get a derived type from the registry. - /// @tparam T Derived type, inheriting `gfx::Shader` - /// @param shaderName The registry name to look up - /// @return T or nullptr if not found in the registry - template , bool>* = nullptr> - std::shared_ptr get(const std::string& shaderName) noexcept { - auto shader = getShader(shaderName); - if (!shader || shader->typeName() != T::Name) { - return nullptr; - } - return std::static_pointer_cast(shader); - } - - /// @brief Shorthand helper to quickly get a derived type from the registry. - /// This variant looks up shaders only by type name. - /// @tparam T Derived type, inheriting `gfx::Shader` - /// @return T or nullptr if not found in the registry - template , bool>* = nullptr> - std::shared_ptr get() noexcept { - auto shader = getShader(std::string(T::Name)); - if (!shader || shader->typeName() != T::Name) { - return nullptr; - } - return std::static_pointer_cast(shader); - } - - /// @brief Ensure the destination 'to' is populated with the requested - /// shader. If already non-null, does nothing. - /// @tparam T Derived type, inheriting `gfx::Shader` - /// @param to Location to store the shader - /// @param shaderName The registry name to look up - /// @return True if 'to' has a valid program object, false otherwise. - template , bool>* = nullptr> - bool populate(std::shared_ptr& to, const std::string& shaderName) noexcept { - if (to) { - return true; - } - - auto shader = getShader(shaderName); - if (!shader || shader->typeName() != T::Name) { - return false; - } - to = std::static_pointer_cast(shader); - return true; - } - - /// @brief Ensure the destination 'to' is populated with the requested - /// shader. If already non-null, does nothing. This variant looks up - /// shaders only by type name. - /// @tparam T Derived type, inheriting `gfx::Shader` - /// @param to Location to store the shader - /// @return True if 'to' has a valid program object, false otherwise. - template , bool>* = nullptr> - bool populate(std::shared_ptr& to) noexcept { - if (to) { - return true; - } - - auto shader = getShader(std::string(T::Name)); - if (!shader || shader->typeName() != T::Name) { - return false; - } - to = std::static_pointer_cast(shader); - return true; - } + [[nodiscard]] virtual bool registerShaderGroup(ShaderGroupPtr&& shaderGroup, + const std::string& shaderGroupName) noexcept; private: - std::unordered_map> programs; - mutable std::shared_mutex programLock; + gfx::ShaderGroup legacyGroup; + std::unordered_map shaderGroups; + mutable std::shared_mutex shaderGroupLock; }; } // namespace gfx diff --git a/include/mbgl/gfx/vertex_attribute.hpp b/include/mbgl/gfx/vertex_attribute.hpp index a8fd844c2..83e651bfa 100644 --- a/include/mbgl/gfx/vertex_attribute.hpp +++ b/include/mbgl/gfx/vertex_attribute.hpp @@ -33,8 +33,10 @@ public: using int2 = std::array; using int3 = std::array; using int4 = std::array; + using ushort8 = std::array; - using ElementType = std::variant; + using ElementType = + std::variant; VertexAttribute(int index_, AttributeDataType dataType_, int size_, std::size_t count_, std::size_t stride_) : index(index_), @@ -106,6 +108,19 @@ public: rawData.clear(); } + template + inline typename std::enable_if::type set(std::size_t, std::tuple, std::size_t) {} + + template + inline typename std::enable_if < + I::type set(std::size_t i, std::tuple tuple, std::size_t tupleIndex) { + if (tupleIndex == 0) { + set(i, std::get(tuple).a1); + } else { + set(i, tuple, tupleIndex - 1); + } + } + protected: VertexAttribute& operator=(const VertexAttribute&) = default; VertexAttribute& operator=(VertexAttribute&& other) { @@ -219,6 +234,33 @@ public: return newAttrs; } + template + std::vector readDataDrivenPaintProperties(const Binders& binders, const Evaluated& evaluated) { + std::vector propertiesAsUniforms; + ( + [&](const auto& attributeNames) { + for (std::size_t attrIndex = 0; attrIndex < attributeNames.size(); ++attrIndex) { + const auto& attributeName = std::string(attributeNames[attrIndex]); + if (auto& binder = binders.template get()) { + const auto vertexCount = binder->getVertexCount(); + const auto isConstant = evaluated.template get().isConstant(); + if (vertexCount > 0 && !isConstant) { + if (auto& attr = getOrAdd("a_" + attributeName)) { + for (std::size_t i = 0; i < vertexCount; ++i) { + attr->set(i, binder->getVertexValue(i), attrIndex); + } + } + propertiesAsUniforms.emplace_back(""); + } else { + propertiesAsUniforms.emplace_back(attributeName); + } + } + } + }(DataDrivenPaintProperty::AttributeNames), + ...); + return propertiesAsUniforms; + } + protected: const std::unique_ptr& add(std::string name, std::unique_ptr&& attr) { const auto result = attrs.insert(std::make_pair(std::move(name), std::unique_ptr())); diff --git a/include/mbgl/shaders/gl/shader_group_gl.hpp b/include/mbgl/shaders/gl/shader_group_gl.hpp new file mode 100644 index 000000000..ded983f6e --- /dev/null +++ b/include/mbgl/shaders/gl/shader_group_gl.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace gl { + +template +class ShaderGroupGL final : public gfx::ShaderGroup { +public: + ShaderGroupGL(const ProgramParameters& programParameters_) + : ShaderGroup(), + programParameters(programParameters_){}; + ~ShaderGroupGL() noexcept override = default; + + const std::shared_ptr getOrCreateShader( + gfx::Context& context, const std::vector& propertiesAsUniforms) override { + const auto& name = shaders::ShaderSource::name; + const auto& vert = shaders::ShaderSource::vertex; + const auto& frag = shaders::ShaderSource::fragment; + + uint32_t key = 0; + std::string additionalDefines; + for (unsigned int i = 0; i < propertiesAsUniforms.size(); i++) { + if (propertiesAsUniforms[i].empty()) { + continue; + } + key |= 1 << i; + additionalDefines += "#define HAS_UNIFORM_u_"; + additionalDefines += propertiesAsUniforms[i]; + additionalDefines += "\n"; + } + std::string shaderName = std::string(name) + "#" + std::to_string(key); + auto shader = get(shaderName); + if (!shader) { + shader = ShaderProgramGL::create( + static_cast(context), programParameters, shaderName, vert, frag, additionalDefines); + if (!registerShader(shader, shaderName)) { + throw std::runtime_error("Failed to register " + shaderName + " with shader group!"); + } + } + return shader; + } + +private: + ProgramParameters programParameters; +}; + +} // namespace gl +} // namespace mbgl diff --git a/include/mbgl/util/vectors.hpp b/include/mbgl/util/vectors.hpp index 90371284d..26f56e639 100644 --- a/include/mbgl/util/vectors.hpp +++ b/include/mbgl/util/vectors.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace mbgl { @@ -10,4 +11,14 @@ using vec3f = std::array; using vec3i = std::array; using vec4 = std::array; -} // namespace mbgl \ No newline at end of file +template +auto concatenate(const std::array&... arrays) { + std::array result; + std::size_t index{}; + + ((std::copy_n(arrays.begin(), sizes, result.begin() + index), index += sizes), ...); + + return result; +} + +} // namespace mbgl diff --git a/src/mbgl/gfx/attribute.hpp b/src/mbgl/gfx/attribute.hpp index 16ae730c5..2ff1ef573 100644 --- a/src/mbgl/gfx/attribute.hpp +++ b/src/mbgl/gfx/attribute.hpp @@ -63,6 +63,8 @@ struct AttributeDataTypeOf : std::integral_constant struct AttributeDataTypeOf : std::integral_constant {}; template <> +struct AttributeDataTypeOf : std::integral_constant {}; +template <> struct AttributeDataTypeOf : std::integral_constant {}; template <> struct AttributeDataTypeOf : std::integral_constant {}; diff --git a/src/mbgl/gfx/shader_group.cpp b/src/mbgl/gfx/shader_group.cpp new file mode 100644 index 000000000..e30856f71 --- /dev/null +++ b/src/mbgl/gfx/shader_group.cpp @@ -0,0 +1,51 @@ +#include +#include + +namespace mbgl { +namespace gfx { + +bool ShaderGroup::isShader(const std::string& shaderName) const noexcept { + std::shared_lock readerLock(programLock); + return programs.find(shaderName) != programs.end(); +} + +const std::shared_ptr ShaderGroup::getShader(const std::string& shaderName) const noexcept { + std::shared_lock readerLock(programLock); + const auto it = programs.find(shaderName); + if (it == programs.end()) { + return nullptr; + } + + return it->second; +} + +bool ShaderGroup::replaceShader(std::shared_ptr&& shader) noexcept { + return replaceShader(std::move(shader), std::string{shader->typeName()}); +} + +bool ShaderGroup::replaceShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept { + std::unique_lock writerLock(programLock); + if (programs.find(shaderName) == programs.end()) { + return false; + } + + programs[shaderName] = std::move(shader); + return true; +} + +bool ShaderGroup::registerShader(std::shared_ptr&& shader) noexcept { + return registerShader(std::move(shader), std::string{shader->typeName()}); +} + +bool ShaderGroup::registerShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept { + std::unique_lock writerLock(programLock); + if (programs.find(shaderName) != programs.end()) { + return false; + } + + programs.emplace(shaderName, std::move(shader)); + return true; +} + +} // namespace gfx +} // namespace mbgl diff --git a/src/mbgl/gfx/shader_registry.cpp b/src/mbgl/gfx/shader_registry.cpp index 87aeed6ea..ff4ad6da6 100644 --- a/src/mbgl/gfx/shader_registry.cpp +++ b/src/mbgl/gfx/shader_registry.cpp @@ -1,51 +1,48 @@ #include -#include +#include namespace mbgl { namespace gfx { -ShaderRegistry::ShaderRegistry() {} +ShaderRegistry::ShaderRegistry() + : legacyGroup() {} -bool ShaderRegistry::isShader(const std::string& shaderName) const noexcept { - std::shared_lock readerLock(programLock); - return programs.find(shaderName) != programs.end(); +ShaderGroup& ShaderRegistry::getLegacyGroup() noexcept { + return legacyGroup; } -const std::shared_ptr ShaderRegistry::getShader(const std::string& shaderName) const noexcept { - std::shared_lock readerLock(programLock); - const auto it = programs.find(shaderName); - if (it == programs.end()) { +bool ShaderRegistry::isShaderGroup(const std::string& shaderGroupName) const noexcept { + std::shared_lock readerLock(shaderGroupLock); + return shaderGroups.find(shaderGroupName) != shaderGroups.end(); +} + +const ShaderGroupPtr ShaderRegistry::getShaderGroup(const std::string& shaderGroupName) const noexcept { + std::shared_lock readerLock(shaderGroupLock); + const auto it = shaderGroups.find(shaderGroupName); + if (it == shaderGroups.end()) { return nullptr; } return it->second; } -bool ShaderRegistry::replaceShader(std::shared_ptr&& shader) noexcept { - return replaceShader(std::move(shader), std::string{shader->typeName()}); -} - -bool ShaderRegistry::replaceShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept { - std::unique_lock writerLock(programLock); - if (programs.find(shaderName) == programs.end()) { +bool ShaderRegistry::replaceShader(ShaderGroupPtr&& shader, const std::string& shaderGroupName) noexcept { + std::unique_lock writerLock(shaderGroupLock); + if (shaderGroups.find(shaderGroupName) == shaderGroups.end()) { return false; } - programs[shaderName] = std::move(shader); + shaderGroups[shaderGroupName] = std::move(shader); return true; } -bool ShaderRegistry::registerShader(std::shared_ptr&& shader) noexcept { - return registerShader(std::move(shader), std::string{shader->typeName()}); -} - -bool ShaderRegistry::registerShader(std::shared_ptr&& shader, const std::string& shaderName) noexcept { - std::unique_lock writerLock(programLock); - if (programs.find(shaderName) != programs.end()) { +bool ShaderRegistry::registerShaderGroup(ShaderGroupPtr&& shader, const std::string& shaderGroupName) noexcept { + std::unique_lock writerLock(shaderGroupLock); + if (shaderGroups.find(shaderGroupName) != shaderGroups.end()) { return false; } - programs.emplace(shaderName, std::move(shader)); + shaderGroups.emplace(shaderGroupName, std::move(shader)); return true; } diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index d4e4fdfb8..8c766a7c0 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -468,7 +468,9 @@ gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t } gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) { - return shaders.get(name); + std::vector emptyAttributes(0); + return std::static_pointer_cast( + shaders.getShaderGroup(name)->getOrCreateShader(*this, emptyAttributes)); } TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) { diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index 918493152..aee296fb8 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -69,10 +69,9 @@ RendererBackend::~RendererBackend() = default; /// @brief Register a list of types with a shader registry instance /// @tparam ...ShaderID Pack of BuiltIn:: shader IDs /// @param registry A shader registry instance -/// @param glContext The GL context instance /// @param programParameters ProgramParameters used to initialize each instance template -void registerTypes(gfx::ShaderRegistry& registry, gl::Context& glContext, const ProgramParameters& programParameters) { +void registerTypes(gfx::ShaderRegistry& registry, const ProgramParameters& programParameters) { /// The following fold expression will create a shader for every type /// in the parameter pack and register it with the shader registry. @@ -80,15 +79,12 @@ void registerTypes(gfx::ShaderRegistry& registry, gl::Context& glContext, const /// failure, we shouldn't expect registration to faill unless the shader /// registry instance provided already has conflicting programs present. ( - [&](const std::string& name, const std::string& vert, const std::string& frag) { + [&]() { using Ty = shaders::ShaderSource; - if (!registry.registerShader(gl::ShaderProgramGL::create(glContext, programParameters, name, vert, frag), - name)) { + if (!registry.registerShaderGroup(std::make_shared>(programParameters), Ty::name)) { throw std::runtime_error("Failed to register " + std::string(Ty::name) + " with shader registry!"); } - }(shaders::ShaderSource::name, - shaders::ShaderSource::vertex, - shaders::ShaderSource::fragment), + }(), ...); } @@ -100,7 +96,7 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::FillOutlineShader, shaders::BuiltIn::FillOutlinePatternShader, shaders::BuiltIn::FillPatternShader, - shaders::BuiltIn::RasterShader>(shaders, static_cast(*context), programParameters); + shaders::BuiltIn::RasterShader>(shaders, programParameters); } } // namespace gl diff --git a/src/mbgl/programs/programs.cpp b/src/mbgl/programs/programs.cpp index a6cb91ed6..30380dcea 100644 --- a/src/mbgl/programs/programs.cpp +++ b/src/mbgl/programs/programs.cpp @@ -37,7 +37,7 @@ void registerTypes(gfx::ShaderRegistry& registry, const ProgramParameters& progr if (!expr) { throw std::runtime_error("Failed to register " + std::string(T::Name) + " with shader registry!"); } - }(registry.registerShader(std::make_shared(programParameters_))), + }(registry.getLegacyGroup().registerShader(std::make_shared(programParameters_))), ...); } diff --git a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp index 201d744da..5f6c007e4 100644 --- a/src/mbgl/renderer/layers/circle_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/circle_layer_tweaker.cpp @@ -40,17 +40,9 @@ struct alignas(16) CircleEvaluatedPropsUBO { }; static_assert(sizeof(CircleEvaluatedPropsUBO) % 16 == 0); -struct alignas(16) CircleInterpolateUBO { - float color_t; - float radius_t; - float blur_t; - float opacity_t; - float stroke_color_t; - float stroke_width_t; - float stroke_opacity_t; - float padding; -}; -static_assert(sizeof(CircleInterpolateUBO) % 16 == 0); +static constexpr std::string_view CircleDrawableUBOName = "CircleDrawableUBO"; +static constexpr std::string_view CirclePaintParamsUBOName = "CirclePaintParamsUBO"; +static constexpr std::string_view CircleEvaluatedPropsUBOName = "CircleEvaluatedPropsUBO"; void CircleLayerTweaker::execute(LayerGroup& layerGroup, const RenderTree& renderTree, @@ -66,9 +58,10 @@ void CircleLayerTweaker::execute(LayerGroup& layerGroup, const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); #endif - CirclePaintParamsUBO paintParamsUBO; - paintParamsUBO.camera_to_center_distance = parameters.state.getCameraToCenterDistance(); - paintParamsUBO.device_pixel_ratio = parameters.pixelRatio; + CirclePaintParamsUBO paintParamsUBO = { + /* .camera_to_center_distance = */ parameters.state.getCameraToCenterDistance(), + /* .device_pixel_ratio = */ parameters.pixelRatio, + /* .padding = */ {0}}; if (!paintParamsUniformBuffer) { paintParamsUniformBuffer = parameters.context.createUniformBuffer(&paintParamsUBO, sizeof(paintParamsUBO)); @@ -79,39 +72,25 @@ void CircleLayerTweaker::execute(LayerGroup& layerGroup, const bool pitchWithMap = evaluated.get() == AlignmentType::Map; if (!evaluatedPropsUniformBuffer) { - CircleEvaluatedPropsUBO evaluatedPropsUBO; - evaluatedPropsUBO.color = evaluated.get().constantOr(Color()); - evaluatedPropsUBO.radius = evaluated.get().constantOr(0); - evaluatedPropsUBO.blur = evaluated.get().constantOr(0); - evaluatedPropsUBO.opacity = evaluated.get().constantOr(0); - evaluatedPropsUBO.stroke_color = evaluated.get().constantOr(Color()); - evaluatedPropsUBO.stroke_width = evaluated.get().constantOr(0); - evaluatedPropsUBO.stroke_opacity = evaluated.get().constantOr(0); - evaluatedPropsUBO.scale_with_map = evaluated.get() == CirclePitchScaleType::Map; - evaluatedPropsUBO.pitch_with_map = pitchWithMap; + CircleEvaluatedPropsUBO evaluatedPropsUBO = { + /* .color = */ evaluated.get().constantOr(CircleColor::defaultValue()), + /* .stroke_color = */ evaluated.get().constantOr(CircleStrokeColor::defaultValue()), + /* .radius = */ evaluated.get().constantOr(CircleRadius::defaultValue()), + /* .blur = */ evaluated.get().constantOr(CircleBlur::defaultValue()), + /* .opacity = */ evaluated.get().constantOr(CircleOpacity::defaultValue()), + /* .stroke_width = */ evaluated.get().constantOr(CircleStrokeWidth::defaultValue()), + /* .stroke_opacity = */ + evaluated.get().constantOr(CircleStrokeOpacity::defaultValue()), + /* .scale_with_map = */ evaluated.get() == CirclePitchScaleType::Map, + /* .pitch_with_map = */ pitchWithMap, + /* .padding = */ 0}; evaluatedPropsUniformBuffer = parameters.context.createUniformBuffer(&evaluatedPropsUBO, sizeof(evaluatedPropsUBO)); } - CircleInterpolateUBO interpolateUBO; - interpolateUBO.color_t = 0; - interpolateUBO.radius_t = 0; - interpolateUBO.blur_t = 0; - interpolateUBO.opacity_t = 0; - interpolateUBO.stroke_color_t = 0; - interpolateUBO.stroke_width_t = 0; - interpolateUBO.stroke_opacity_t = 0; - - if (!interpolateUniformBuffer) { - interpolateUniformBuffer = parameters.context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); - } else { - interpolateUniformBuffer->update(&interpolateUBO, sizeof(CircleInterpolateUBO)); - } - layerGroup.observeDrawables([&](gfx::Drawable& drawable) { - drawable.mutableUniformBuffers().addOrReplace("CirclePaintParamsUBO", paintParamsUniformBuffer); - drawable.mutableUniformBuffers().addOrReplace("CircleEvaluatedPropsUBO", evaluatedPropsUniformBuffer); - drawable.mutableUniformBuffers().addOrReplace("CircleInterpolateUBO", interpolateUniformBuffer); + drawable.mutableUniformBuffers().addOrReplace(CirclePaintParamsUBOName, paintParamsUniformBuffer); + drawable.mutableUniformBuffers().addOrReplace(CircleEvaluatedPropsUBOName, evaluatedPropsUniformBuffer); if (!drawable.getTileID()) { return; @@ -124,20 +103,15 @@ void CircleLayerTweaker::execute(LayerGroup& layerGroup, const auto matrix = getTileMatrix( tileID, renderTree, parameters.state, translation, anchor, inViewportPixelUnits); - CircleDrawableUBO drawableUBO; - drawableUBO.matrix = util::cast(matrix); - drawableUBO.extrude_scale = - pitchWithMap - ? std::array{{tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), - tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom()))}} - : parameters.pixelsToGLUnits; + const auto pixelsToTileUnits = tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())); - if (auto& ubo = drawable.mutableUniformBuffers().get("CircleDrawableUBO")) { - ubo->update(&drawableUBO, sizeof(drawableUBO)); - } else { - auto drawableUniformBuffer = parameters.context.createUniformBuffer(&drawableUBO, sizeof(drawableUBO)); - drawable.mutableUniformBuffers().addOrReplace("CircleDrawableUBO", drawableUniformBuffer); - } + CircleDrawableUBO drawableUBO = { + /* .matrix = */ util::cast(matrix), + /* .extrude_scale = */ + pitchWithMap ? std::array{{pixelsToTileUnits}} : parameters.pixelsToGLUnits, + /* .padding = */ {0}}; + + drawable.mutableUniformBuffers().createOrUpdate(CircleDrawableUBOName, &drawableUBO, parameters.context); }); } diff --git a/src/mbgl/renderer/layers/circle_layer_tweaker.hpp b/src/mbgl/renderer/layers/circle_layer_tweaker.hpp index adf716ef8..6116275c6 100644 --- a/src/mbgl/renderer/layers/circle_layer_tweaker.hpp +++ b/src/mbgl/renderer/layers/circle_layer_tweaker.hpp @@ -23,9 +23,8 @@ public: void execute(LayerGroup&, const RenderTree&, const PaintParameters&) override; protected: - gfx::UniformBufferPtr paintParamsUniformBuffer = nullptr; - gfx::UniformBufferPtr evaluatedPropsUniformBuffer = nullptr; - gfx::UniformBufferPtr interpolateUniformBuffer = nullptr; + gfx::UniformBufferPtr paintParamsUniformBuffer; + gfx::UniformBufferPtr evaluatedPropsUniformBuffer; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 3f08a1404..f4c99cd4c 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -79,8 +79,8 @@ void RenderBackgroundLayer::render(PaintParameters& parameters) { // is drawn with glClear rather than this method. // Ensure programs are available - if (!parameters.shaders.populate(backgroundProgram)) return; - if (!parameters.shaders.populate(backgroundPatternProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(backgroundProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(backgroundPatternProgram)) return; const Properties<>::PossiblyEvaluated properties; const BackgroundProgram::Binders paintAttributeData(properties, 0); diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index c617aa023..70e17b28c 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -92,7 +94,7 @@ void RenderCircleLayer::render(PaintParameters& parameters) { return; } - if (!parameters.shaders.populate(circleProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(circleProgram)) return; const auto drawTile = [&](const RenderTile& tile, const LayerRenderData* data, const auto& segments) { auto& circleBucket = static_cast(*data->bucket); @@ -255,18 +257,37 @@ void RenderCircleLayer::removeTile(RenderPass renderPass, const OverscaledTileID stats.tileDrawablesRemoved += tileLayerGroup->removeDrawables(renderPass, tileID).size(); } +struct alignas(16) CircleInterpolateUBO { + float color_t; + float radius_t; + float blur_t; + float opacity_t; + float stroke_color_t; + float stroke_width_t; + float stroke_opacity_t; + float padding; +}; +static_assert(sizeof(CircleInterpolateUBO) % 16 == 0); + +static const std::string CircleShaderGroupName = "CircleShader"; +static constexpr std::string_view CircleInterpolateUBOName = "CircleInterpolateUBO"; + void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, - const TransformState& /*state*/, + const TransformState& state, [[maybe_unused]] const RenderTree& renderTree, UniqueChangeRequestVec& changes) { std::unique_lock guard(mutex); - if (!renderTiles || renderTiles->empty()) { + const auto removeAll = [&]() { if (tileLayerGroup) { stats.tileDrawablesRemoved += tileLayerGroup->getDrawableCount(); tileLayerGroup->clearDrawables(); } + }; + + if (!renderTiles || renderTiles->empty()) { + removeAll(); return; } @@ -280,8 +301,12 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, changes.emplace_back(std::make_unique(tileLayerGroup, /*canReplace=*/true)); } - if (!circleShader) { - circleShader = context.getGenericShader(shaders, "CircleShader"); + if (!circleShaderGroup) { + circleShaderGroup = shaders.getShaderGroup(CircleShaderGroupName); + } + if (!circleShaderGroup) { + removeAll(); + return; } std::unordered_set newTileIDs(renderTiles->size()); @@ -308,13 +333,11 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, } }); + const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); - if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { - continue; - } - const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass); if (!renderData) { removeTile(renderPass, tileID); @@ -322,6 +345,45 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, } auto& bucket = static_cast(*renderData->bucket); + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + + float zoom = static_cast(state.getZoom()); + const CircleInterpolateUBO interpolateUBO = { + /* .color_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .radius_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .blur_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .opacity_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .stroke_color_t = */ + std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .stroke_width_t = */ + std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .stroke_opacity_t = */ + std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /* .padding = */ 0}; + + tileLayerGroup->observeDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + drawable.mutableUniformBuffers().createOrUpdate(CircleInterpolateUBOName, &interpolateUBO, context); + }); + + if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) { + continue; + } + + circleVertexAttrs.clear(); + + auto propertiesAsUniforms = circleVertexAttrs.readDataDrivenPaintProperties( + paintPropertyBinders, evaluated); + + auto circleShader = circleShaderGroup->getOrCreateShader(context, propertiesAsUniforms); + if (!circleShader) { + continue; + } std::vector> rawVerts; const auto buildVertices = [&]() { @@ -333,94 +395,8 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, } }; - circleVertexAttrs.clear(); - - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); - - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_color")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& packedColor = static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set( - i, {packedColor[0], packedColor[1], packedColor[0], packedColor[1]}); - } - } - } - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_radius")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& radius = static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set(i, {radius[0], radius[0]}); - } - } - } - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_blur")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& blur = static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set(i, {blur[0], blur[0]}); - } - } - } - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_opacity")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& opacity = static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set(i, {opacity[0], opacity[0]}); - } - } - } - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_stroke_color")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& packedStrokeColor = - static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set( - i, {packedStrokeColor[0], packedStrokeColor[1], packedStrokeColor[0], packedStrokeColor[1]}); - } - } - } - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_stroke_width")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& strokeWidth = static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set(i, {strokeWidth[0], strokeWidth[0]}); - } - } - } - if (auto& binder = paintPropertyBinders.get()) { - const auto count = binder->getVertexCount(); - if (auto& attr = circleVertexAttrs.getOrAdd("a_stroke_opacity")) { - for (std::size_t i = 0; i < count; ++i) { - const auto& strokeOpacity = - static_cast>*>( - binder->getVertexValue(i)) - ->a1; - attr->set(i, {strokeOpacity[0], strokeOpacity[0]}); - } - } - } - circleBuilder = context.createDrawableBuilder("circle"); - circleBuilder->setShader(circleShader); + circleBuilder->setShader(std::static_pointer_cast(circleShader)); circleBuilder->setColorAttrMode(gfx::DrawableBuilder::ColorAttrMode::None); circleBuilder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite : gfx::DepthMaskType::ReadOnly); @@ -432,14 +408,15 @@ void RenderCircleLayer::update(gfx::ShaderRegistry& shaders, buildVertices(); circleBuilder->addVertices(rawVerts, 0, rawVerts.size()); - for (const auto& seg : bucket.segments) { - circleBuilder->addTriangles(bucket.triangles.vector(), seg.indexOffset, seg.indexLength); - } + circleBuilder->setSegments(gfx::Triangles(), + bucket.triangles.vector(), + reinterpret_cast>&>(bucket.segments)); circleBuilder->flush(); for (auto& drawable : circleBuilder->clearDrawables()) { drawable->setTileID(tileID); + drawable->mutableUniformBuffers().createOrUpdate(CircleInterpolateUBOName, &interpolateUBO, context); tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); ++stats.tileDrawablesAdded; diff --git a/src/mbgl/renderer/layers/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp index c8786cb72..da0bfb311 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.hpp +++ b/src/mbgl/renderer/layers/render_circle_layer.hpp @@ -8,6 +8,13 @@ namespace mbgl { class CircleProgram; +namespace gfx { +class ShaderGroup; +class UniformBuffer; +using ShaderGroupPtr = std::shared_ptr; +using UniformBufferPtr = std::shared_ptr; +} // namespace gfx + class RenderCircleLayer final : public RenderLayer { public: explicit RenderCircleLayer(Immutable); @@ -46,7 +53,7 @@ private: // Programs std::shared_ptr circleProgram; - gfx::ShaderProgramBasePtr circleShader; + gfx::ShaderGroupPtr circleShaderGroup; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 0af94e8c6..3f9a32db5 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -71,8 +71,8 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) { return; } - if (!parameters.shaders.populate(fillExtrusionProgram)) return; - if (!parameters.shaders.populate(fillExtrusionPatternProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(fillExtrusionProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(fillExtrusionPatternProgram)) return; const auto& evaluated = static_cast(*evaluatedProperties).evaluated; const auto& crossfade = static_cast(*evaluatedProperties).crossfade; diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 7a4ecddf2..bbb7da2b3 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -84,10 +84,10 @@ bool RenderFillLayer::hasCrossfade() const { void RenderFillLayer::render(PaintParameters& parameters) { assert(renderTiles); - if (!parameters.shaders.populate(fillProgram)) return; - if (!parameters.shaders.populate(fillPatternProgram)) return; - if (!parameters.shaders.populate(fillOutlineProgram)) return; - if (!parameters.shaders.populate(fillOutlinePatternProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(fillProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(fillPatternProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(fillOutlineProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(fillOutlinePatternProgram)) return; if (unevaluated.get().isUndefined()) { parameters.renderTileClippingMasks(renderTiles); @@ -301,10 +301,8 @@ bool bindFloat(const FloatBinder& binder, gfx::VertexAttributeArray& attrs, std: const auto count = binder.getVertexCount(); if (auto& attr = attrs.getOrAdd(std::move(attributeName))) { for (std::size_t i = 0; i < count; ++i) { - const auto& value = static_cast(binder.getVertexValue(i))->a1; - const auto& from = value; // TODO: should be two different values, right? - const auto& to = value; - attr->set(i, util::concat(from, to)); + const auto& value = std::get<0>(binder.getVertexValue(i)).a1; + attr->set(i, value); } return true; } @@ -321,10 +319,8 @@ bool bindFloatPair(const FloatPairBinder& binder, gfx::VertexAttributeArray& att // check that vertexVector.elements() == sum(segments.vertexLength) if (auto& attr = attrs.getOrAdd(std::move(attributeName))) { for (std::size_t i = 0; i < count; ++i) { - const auto& value = static_cast(binder.getVertexValue(i))->a1; - const auto& from = value; // TODO: should be two different values, right? - const auto& to = value; - attr->set(i, util::concat(from, to)); + const auto& value = std::get<0>(binder.getVertexValue(i)).a1; + attr->set(i, value); } return true; } @@ -341,10 +337,8 @@ bool bindColor(const ColorBinder& binder, gfx::VertexAttributeArray& attrs, std: // check that vertexVector.elements() == sum(segments.vertexLength) if (auto& attr = attrs.getOrAdd(std::move(attributeName))) { for (std::size_t i = 0; i < count; ++i) { - const auto& value = static_cast(binder.getVertexValue(i))->a1; - const auto& from = value; // TODO: should be two different values, right? - const auto& to = value; - attr->set(i, util::concat(from, to)); + const auto& value = std::get<0>(binder.getVertexValue(i)).a1; + attr->set(i, value); } return true; } @@ -361,8 +355,8 @@ bool bindImage(const ImageBinder& binder, gfx::VertexAttributeArray& attrs, std: // check that vertexVector.elements() == sum(segments.vertexLength) if (auto& attr = attrs.getOrAdd(std::move(attributeName))) { for (std::size_t i = 0; i < count; ++i) { - const auto& value = static_cast(binder.getVertexValue(i))->a1; - attr->set(i, util::cast(value)); + const auto& value = std::get<0>(binder.getVertexValue(i)).a1; + attr->set(i, value); } return true; } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index eda2b698d..961fc658c 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -69,8 +69,8 @@ void RenderHeatmapLayer::render(PaintParameters& parameters) { return; } - if (!parameters.shaders.populate(heatmapProgram)) return; - if (!parameters.shaders.populate(heatmapTextureProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(heatmapProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(heatmapTextureProgram)) return; if (parameters.pass == RenderPass::Pass3D) { const auto& viewportSize = parameters.staticData.backendSize; diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index 7818763de..30a60f44f 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -79,8 +79,8 @@ void RenderHillshadeLayer::render(PaintParameters& parameters) { assert(renderTiles); if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) return; - if (!parameters.shaders.populate(hillshadeProgram)) return; - if (!parameters.shaders.populate(hillshadePrepareProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(hillshadeProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(hillshadePrepareProgram)) return; const auto& evaluated = static_cast(*evaluatedProperties).evaluated; auto draw = [&](const mat4& matrix, diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 727ffed9c..477d35544 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -95,10 +95,10 @@ void RenderLineLayer::render(PaintParameters& parameters) { return; } - if (!parameters.shaders.populate(lineProgram)) return; - if (!parameters.shaders.populate(lineGradientProgram)) return; - if (!parameters.shaders.populate(lineSDFProgram)) return; - if (!parameters.shaders.populate(linePatternProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(lineProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(lineGradientProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(lineSDFProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(linePatternProgram)) return; parameters.renderTileClippingMasks(renderTiles); diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index 7de33af67..f67eeefd3 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -96,7 +96,7 @@ void RenderRasterLayer::render(PaintParameters& parameters) { return; } - if (!parameters.shaders.populate(rasterProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(rasterProgram)) return; const auto& evaluated = static_cast(*evaluatedProperties).evaluated; RasterProgram::Binders paintAttributeData{evaluated, 0}; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 6254f1369..d9e5775b1 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -359,12 +359,12 @@ void RenderSymbolLayer::render(PaintParameters& parameters) { return; } - if (!parameters.shaders.populate(programs.symbolIconProgram)) return; - if (!parameters.shaders.populate(programs.symbolSDFIconProgram)) return; - if (!parameters.shaders.populate(programs.symbolSDFTextProgram)) return; - if (!parameters.shaders.populate(programs.symbolTextAndIconProgram)) return; - if (!parameters.shaders.populate(programs.collisionBoxProgram)) return; - if (!parameters.shaders.populate(programs.collisionCircleProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(programs.symbolIconProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(programs.symbolSDFIconProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(programs.symbolSDFTextProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(programs.symbolTextAndIconProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(programs.collisionBoxProgram)) return; + if (!parameters.shaders.getLegacyGroup().populate(programs.collisionCircleProgram)) return; const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get().isUndefined(); std::multiset renderableSegments; diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index 63eac29ca..d3e4cf20f 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -138,7 +138,8 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun clearStencil(); } - auto program = staticData.shaders->get(); + auto program = staticData.shaders->getLegacyGroup().get(); + if (!program) { return; } diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 19dbcc483..7bacca46c 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -1,21 +1,20 @@ #pragma once +#include #include #include -#include #include +#include #include +#include +#include +#include +#include +#include #include #include -#include -#include -#include #include -#include -#include -#include - -#include +#include namespace mbgl { @@ -38,6 +37,9 @@ template using ZoomInterpolatedAttributeType = gfx::AttributeType; +template +using ZoomInterpolatedVertexType = typename gfx::detail::VertexType>; + inline std::array attributeValue(float v) { return {{v}}; } @@ -129,8 +131,8 @@ public: const PossiblyEvaluatedType& currentValue) const = 0; virtual std::size_t getVertexCount() const = 0; - virtual const /*std::tuple...>&*/ void* getVertexValue( - std::size_t index) const = 0; + + virtual std::tuple...> getVertexValue(std::size_t index) const = 0; static std::unique_ptr create(const PossiblyEvaluatedType& value, float zoom, T defaultValue); @@ -170,10 +172,10 @@ public: using BaseAttributeType = A; using BaseVertex = gfx::VertexType; - std::size_t getVertexCount() const override { return 1; } - const /*std::tuple>&*/ void* getVertexValue(std::size_t) const override { - convertedValue = BaseVertex{attributeValue(constant)}; - return &convertedValue; + std::size_t getVertexCount() const override { return 0; } + + std::tuple> getVertexValue(std::size_t) const override { + return {ZoomInterpolatedVertexType{0}}; } private: @@ -222,9 +224,10 @@ public: return constantPatternPositions; } - std::size_t getVertexCount() const override { return 1; } - const /*std::tuple>&*/ void* getVertexValue(std::size_t) const override { - return &constantPatternPositions; + std::size_t getVertexCount() const override { return 0; } + + std::tuple...> getVertexValue(std::size_t) const override { + return {ZoomInterpolatedVertexType{0}...}; } private: @@ -238,8 +241,6 @@ public: using BaseAttributeType = A; using BaseVertex = gfx::VertexType; - using AttributeType = ZoomInterpolatedAttributeType; - SourceFunctionPaintPropertyBinder(style::PropertyExpression expression_, T defaultValue_) : expression(std::move(expression_)), defaultValue(std::move(defaultValue_)) {} @@ -326,8 +327,10 @@ public: } std::size_t getVertexCount() const override { return vertexVector.elements(); } - const /*std::tuple>&*/ void* getVertexValue(std::size_t index) const override { - return &vertexVector.at(index); + + std::tuple> getVertexValue(std::size_t index) const override { + const BaseVertex& value = vertexVector.at(index); + return {ZoomInterpolatedVertexType{concatenate(value.a1, value.a1)}}; } private: @@ -450,8 +453,9 @@ public: } std::size_t getVertexCount() const override { return vertexVector.elements(); } - const /*std::tuple>&*/ void* getVertexValue(std::size_t index) const override { - return &vertexVector.at(index); + + std::tuple> getVertexValue(std::size_t index) const override { + return {vertexVector.at(index)}; } private: @@ -467,9 +471,6 @@ template class CompositeCrossFadedPaintPropertyBinder final : public PaintPropertyBinder, PossiblyEvaluatedPropertyValue>, A1, A2> { public: - using AttributeType = ZoomInterpolatedAttributeType; - using AttributeType2 = ZoomInterpolatedAttributeType; - using BaseAttributeType = A1; using BaseAttributeType2 = A2; @@ -564,8 +565,16 @@ public: return {}; } - std::size_t getVertexCount() const override { return 0; } - const /*std::tuple>&*/ void* getVertexValue(std::size_t) const override { return nullptr; } + std::size_t getVertexCount() const override { return patternToVertexVector.elements(); } + + std::tuple, ZoomInterpolatedVertexType> getVertexValue( + std::size_t index) const override { + const Vertex& patternValue = patternToVertexVector.at(index); + const Vertex2& zoomValue = crossfade.fromScale == 2 ? zoomInVertexVector.at(index) + : zoomOutVertexVector.at(index); + return {ZoomInterpolatedVertexType{concatenate(patternValue.a1, patternValue.a1)}, + ZoomInterpolatedVertexType{concatenate(zoomValue.a1, zoomValue.a1)}}; + } private: style::PropertyExpression expression; diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 06f7f8de6..82367822e 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -171,7 +171,7 @@ void RenderTile::finishRender(PaintParameters& parameters) const { static const style::Properties<>::PossiblyEvaluated properties{}; static const DebugProgram::Binders paintAttributeData(properties, 0); - auto program = parameters.shaders.get(); + auto program = parameters.shaders.getLegacyGroup().get(); if (!program) { return; } diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 29a786bd9..5fd73e490 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -39,7 +39,7 @@ void ImageSourceRenderData::render(PaintParameters& parameters) const { static const style::Properties<>::PossiblyEvaluated properties{}; static const DebugProgram::Binders paintAttributeData(properties, 0); - auto programInstance = parameters.shaders.get(); + auto programInstance = parameters.shaders.getLegacyGroup().get(); if (!programInstance) { return; } diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index 7d398748f..782cc4860 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -39,6 +39,8 @@ public: using AttributeList = TypeList; using Uniform = U; using UniformList = TypeList; + + static constexpr const std::array AttributeNames = {A::name()}; }; template @@ -56,6 +58,8 @@ public: using AttributeList = TypeList; using Uniform = U1; using UniformList = TypeList; + + static constexpr const std::array AttributeNames = {A1::name(), A2::name()}; }; template diff --git a/test/renderer/shader_registry.test.cpp b/test/renderer/shader_registry.test.cpp index eef5aa371..ee362370a 100644 --- a/test/renderer/shader_registry.test.cpp +++ b/test/renderer/shader_registry.test.cpp @@ -82,7 +82,7 @@ class StubShaderConsumer { public: template uint32_t useShader(gfx::ShaderRegistry& registry) { - auto program = registry.get(); + auto program = registry.getLegacyGroup().get(); return program ? program->draw() : 0; } }; @@ -94,17 +94,17 @@ TEST(ShaderRegistry, RegisterShader) { gfx::ShaderRegistry registry; // The registry should start empty - ASSERT_FALSE(registry.isShader(std::string{StubProgram_1::Name})); + ASSERT_FALSE(registry.getLegacyGroup().isShader(std::string{StubProgram_1::Name})); // Register the program auto program = std::make_shared(); - ASSERT_TRUE(registry.registerShader(program)); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(program)); // We can't re-register the same program name - ASSERT_FALSE(registry.registerShader(program)); + ASSERT_FALSE(registry.getLegacyGroup().registerShader(program)); // Ensure the shader is present in the registry now - ASSERT_TRUE(registry.isShader(std::string{StubProgram_1::Name})); + ASSERT_TRUE(registry.getLegacyGroup().isShader(std::string{StubProgram_1::Name})); // And we can fetch it - ASSERT_EQ(registry.get(), program); + ASSERT_EQ(registry.getLegacyGroup().get(), program); // Make sure downcasting to program1 works as expected StubShaderConsumer consumer; @@ -115,13 +115,13 @@ TEST(ShaderRegistry, RegisterShader) { TEST(ShaderRegistry, ReplaceShaderType) { gfx::ShaderRegistry registry; - ASSERT_FALSE(registry.isShader(std::string{StubProgram_1::Name})); + ASSERT_FALSE(registry.getLegacyGroup().isShader(std::string{StubProgram_1::Name})); auto program = std::make_shared(); - ASSERT_TRUE(registry.registerShader(program)); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(program)); // Ensure the shader is present in the registry now - ASSERT_TRUE(registry.isShader(std::string{StubProgram_1::Name})); - ASSERT_TRUE(registry.isShader(std::string{program->typeName()})); + ASSERT_TRUE(registry.getLegacyGroup().isShader(std::string{StubProgram_1::Name})); + ASSERT_TRUE(registry.getLegacyGroup().isShader(std::string{program->typeName()})); // Make sure downcasting to program1 works as expected StubShaderConsumer consumer; @@ -131,13 +131,13 @@ TEST(ShaderRegistry, ReplaceShaderType) { // and as such this replacement should fail as StubProgram_2 // has never been registered. auto program2 = std::make_shared(); - ASSERT_FALSE(registry.replaceShader(program2)); + ASSERT_FALSE(registry.getLegacyGroup().replaceShader(program2)); // Make a second instance of program1 and change the token auto program3 = std::make_shared(); program3->setToken(30); // Replace it in the registry - ASSERT_TRUE(registry.replaceShader(program3)); + ASSERT_TRUE(registry.getLegacyGroup().replaceShader(program3)); // Assert the new program downcasts from the registry as expected ASSERT_EQ(consumer.useShader(registry), 30); } @@ -156,28 +156,29 @@ TEST(ShaderRegistry, ShaderRTTI) { TEST(ShaderRegistry, MultiRegister) { gfx::ShaderRegistry registry; - ASSERT_TRUE(registry.registerShader(std::make_shared())); - ASSERT_TRUE(registry.registerShader(std::make_shared(), "SecondProgram")); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(std::make_shared())); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(std::make_shared(), "SecondProgram")); // Default option, register as the type name - ASSERT_NE(registry.get(), nullptr); + ASSERT_NE(registry.getLegacyGroup().get(), nullptr); // Register with an explicit name - ASSERT_NE(registry.get("SecondProgram"), nullptr); - ASSERT_NE(registry.get(), registry.get("SecondProgram")); + ASSERT_NE(registry.getLegacyGroup().get("SecondProgram"), nullptr); + ASSERT_NE(registry.getLegacyGroup().get(), + registry.getLegacyGroup().get("SecondProgram")); } // Test fetching TEST(ShaderRegistry, RegistryFetch) { gfx::ShaderRegistry registry; - ASSERT_TRUE(registry.registerShader(std::make_shared())); - ASSERT_TRUE(registry.registerShader(std::make_shared(), "SecondProgram")); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(std::make_shared())); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(std::make_shared(), "SecondProgram")); std::shared_ptr progA; std::shared_ptr progB; - ASSERT_TRUE(registry.populate(progA)); - ASSERT_TRUE(registry.populate(progB, "SecondProgram")); + ASSERT_TRUE(registry.getLegacyGroup().populate(progA)); + ASSERT_TRUE(registry.getLegacyGroup().populate(progB, "SecondProgram")); ASSERT_NE(progA, progB); ASSERT_NE(progA, nullptr); ASSERT_NE(progB, nullptr); @@ -188,17 +189,17 @@ TEST(ShaderRegistry, NamedReplace) { gfx::ShaderRegistry registry; // Register - ASSERT_TRUE(registry.registerShader(std::make_shared(), "CustomName")); + ASSERT_TRUE(registry.getLegacyGroup().registerShader(std::make_shared(), "CustomName")); std::shared_ptr progA; - ASSERT_TRUE(registry.populate(progA, "CustomName")); + ASSERT_TRUE(registry.getLegacyGroup().populate(progA, "CustomName")); ASSERT_NE(progA, nullptr); // Replace it with a new instance - ASSERT_TRUE(registry.replaceShader(std::make_shared(), "CustomName")); + ASSERT_TRUE(registry.getLegacyGroup().replaceShader(std::make_shared(), "CustomName")); std::shared_ptr progB; - ASSERT_TRUE(registry.populate(progB, "CustomName")); + ASSERT_TRUE(registry.getLegacyGroup().populate(progB, "CustomName")); ASSERT_NE(progB, nullptr); // Should be different instances @@ -213,7 +214,7 @@ TEST(ShaderRegistry, GLSLReplacement_NoOp) { // Just replace with a default instance observer.registerShaders = [&](gfx::ShaderRegistry& registry) { - if (!registry.replaceShader(std::make_shared(ProgramParameters(1.0f, false)))) { + if (!registry.getLegacyGroup().replaceShader(std::make_shared(ProgramParameters(1.0f, false)))) { throw std::runtime_error("Failed to register shader!"); } }; @@ -239,7 +240,7 @@ TEST(ShaderRegistry, GLSLReplacement1) { // Replace with an instance that only renders blue observer.registerShaders = [&](gfx::ShaderRegistry& registry) { - if (!registry.replaceShader(std::make_shared( + if (!registry.getLegacyGroup().replaceShader(std::make_shared( ProgramParameters(1.0f, false) .withShaderSource(ProgramParameters::ProgramSource(gfx::Backend::Type::OpenGL, "", @@ -273,7 +274,7 @@ TEST(ShaderRegistry, GLSLReplacement2) { // Replace with an instance that adds some red and green observer.registerShaders = [&](gfx::ShaderRegistry& registry) { - if (!registry.replaceShader(std::make_shared( + if (!registry.getLegacyGroup().replaceShader(std::make_shared( ProgramParameters(1.0f, false) .withShaderSource(ProgramParameters::ProgramSource(gfx::Backend::Type::OpenGL, "",