diff --git a/include/mbgl/gfx/uniform_buffer.hpp b/include/mbgl/gfx/uniform_buffer.hpp index 1e86b09b1..48a6443d7 100644 --- a/include/mbgl/gfx/uniform_buffer.hpp +++ b/include/mbgl/gfx/uniform_buffer.hpp @@ -68,13 +68,18 @@ public: std::shared_ptr uniformBuffer); /// Create and add a new buffer or update an existing one - void createOrUpdate(const StringIdentity id, const std::vector& data, gfx::Context&); - void createOrUpdate(const StringIdentity id, const void* data, std::size_t size, gfx::Context&); + void createOrUpdate(const StringIdentity id, + const std::vector& data, + gfx::Context&, + bool persistent = false); + void createOrUpdate( + const StringIdentity id, const void* data, std::size_t size, gfx::Context&, bool persistent = false); template std::enable_if_t> createOrUpdate(const StringIdentity id, const T* data, - gfx::Context& context) { - createOrUpdate(id, data, sizeof(T), context); + gfx::Context& context, + bool persistent = false) { + createOrUpdate(id, data, sizeof(T), context, persistent); } UniformBufferArray& operator=(UniformBufferArray&&); diff --git a/include/mbgl/mtl/buffer_resource.hpp b/include/mbgl/mtl/buffer_resource.hpp index 69d4b4114..4efe37a9a 100644 --- a/include/mbgl/mtl/buffer_resource.hpp +++ b/include/mbgl/mtl/buffer_resource.hpp @@ -14,37 +14,79 @@ class Context; class BufferResource { public: - BufferResource() = delete; + BufferResource() noexcept = delete; /** @brief Create a new Metal buffer @param device The Metal device on which to create the buffer. @param raw Data to use for the contents of the new buffer. May be null. @param size The minimum size of the new buffer. Must be non-zero. @param usage A `MTL::ResourceOptions` value. Currently, only `ResourceStorageModeShared` is supported. + @param isIndexBuffer True if the buffer will be used for indexes. The Metal API only accepts `MTLBuffer` + objects for drawing indexed primitives, so this constrains how the buffer can be managed. + @param persistent Performance hint, assume this buffer will be reused many times. */ - BufferResource(Context& context_, const void* raw, std::size_t size, MTL::ResourceOptions usage); - BufferResource(BufferResource&&); - virtual ~BufferResource(); + BufferResource(Context& context_, + const void* raw, + std::size_t size, + MTL::ResourceOptions usage, + bool isIndexBuffer, + bool persistent); + BufferResource(BufferResource&&) noexcept; + virtual ~BufferResource() noexcept; - BufferResource& operator=(BufferResource&&); + BufferResource& operator=(BufferResource&&) noexcept; BufferResource clone() const; - void update(const void* data, std::size_t size, std::size_t offset); + void update(const void* data, std::size_t size, std::size_t offset) noexcept; - std::size_t getSizeInBytes() const { return buffer ? buffer->length() : 0; } - void* contents() const { return buffer ? buffer->contents() : nullptr; } + std::size_t getSizeInBytes() const noexcept { return size; } + const void* contents() const noexcept { return buffer ? buffer->contents() : (raw.empty() ? nullptr : raw.data()); } - Context& getContext() const { return context; } - const MTLBufferPtr& getMetalBuffer() const { return buffer; } + Context& getContext() const noexcept { return context; } + const MTLBufferPtr& getMetalBuffer() const noexcept { return buffer; } - operator bool() const { return buffer.operator bool(); } - bool operator!() const { return !buffer.operator bool(); } + bool isValid() const noexcept { return buffer || !raw.empty(); } + operator bool() const noexcept { return isValid(); } + bool operator!() const noexcept { return !isValid(); } + + using VersionType = std::uint16_t; + + /// Used to detect whether buffer contents have changed + VersionType getVersion() const noexcept { return version; } + + /// Indicates whether this buffer needs to be re-bound from a previous binding at the given version + bool needReBind(VersionType version) const noexcept; + + /// Bind this buffer to the specified vertex buffer index + void bindVertex(const MTLRenderCommandEncoderPtr&, + std::size_t offset, + std::size_t index, + std::size_t size) const noexcept; + /// Bind this buffer to the specified fragment buffer index + void bindFragment(const MTLRenderCommandEncoderPtr&, + std::size_t offset, + std::size_t index, + std::size_t size) const noexcept; + + /// Update the offset, when this buffer is alread bound to the specified index (unchecked). + void updateVertexBindOffset(const MTLRenderCommandEncoderPtr&, + std::size_t offset, + std::size_t index, + std::size_t size) const noexcept; + void updateFragmentBindOffset(const MTLRenderCommandEncoderPtr&, + std::size_t offset, + std::size_t index, + std::size_t size) const noexcept; protected: Context& context; MTLBufferPtr buffer; + std::vector raw; NS::UInteger size; NS::UInteger usage; + std::uint16_t version = 0; + bool isIndexBuffer; + bool persistent; }; } // namespace mtl diff --git a/include/mbgl/mtl/context.hpp b/include/mbgl/mtl/context.hpp index 3efa9bbd9..4be718e8a 100644 --- a/include/mbgl/mtl/context.hpp +++ b/include/mbgl/mtl/context.hpp @@ -30,8 +30,10 @@ namespace mtl { class RenderPass; class RendererBackend; class ShaderProgram; +class VertexBufferResource; using UniqueShaderProgram = std::unique_ptr; +using UniqueVertexBufferResource = std::unique_ptr; class Context final : public gfx::Context { public: @@ -44,7 +46,15 @@ public: std::unique_ptr createCommandEncoder() override; - BufferResource createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const; + /// Create a new buffer object + /// @param data The raw data to copy, may be `nullptr` + /// @param size The size of the buffer + /// @param usage Not currently used + /// @param isIndexBuffer True if the buffer will be used for indexes. The Metal API only accepts `MTLBuffer` + /// objects for drawing indexed primitives, so this constrains how the buffer can be managed. + /// @param persistent Performance hint, assume this buffer will be reused many times. + BufferResource createBuffer( + const void* data, std::size_t size, gfx::BufferUsageType usage, bool isIndexBuffer, bool persistent) const; UniqueShaderProgram createProgram(std::string name, std::string_view source, @@ -64,7 +74,7 @@ public: void reduceMemoryUsage() override {} gfx::UniqueDrawableBuilder createDrawableBuilder(std::string name) override; - gfx::UniformBufferPtr createUniformBuffer(const void* data, std::size_t size) override; + gfx::UniformBufferPtr createUniformBuffer(const void* data, std::size_t size, bool persistent) override; gfx::ShaderProgramBasePtr getGenericShader(gfx::ShaderRegistry&, const std::string& name) override; @@ -94,10 +104,6 @@ public: Size size) override; std::unique_ptr createDrawScopeResource() override; - /* - UniqueFramebuffer createFramebuffer(); - std::unique_ptr readFramebuffer(Size, gfx::TexturePixelType, bool flip); - */ #if !defined(NDEBUG) void visualizeStencilBuffer() override; @@ -110,7 +116,10 @@ public: const gfx::StencilMode&, const gfx::Renderable&) const; - virtual bool emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr&, const void* data, std::size_t size); + virtual bool emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr&, + const void* data, + std::size_t size, + bool persistent); /// Get a reusable buffer containing the standard fixed tile vertices (+/- `util::EXTENT`) const BufferResource& getTileVertexBuffer(); @@ -119,7 +128,7 @@ public: const BufferResource& getTileIndexBuffer(); /// Get a buffer to be bound to unused vertex buffers - const gfx::UniqueVertexBufferResource& getEmptyVertexBuffer(); + const UniqueVertexBufferResource& getEmptyVertexBuffer(); bool renderTileClippingMasks(gfx::RenderPass& renderPass, RenderStaticData& staticData, @@ -132,7 +141,7 @@ private: std::optional tileVertexBuffer; std::optional tileIndexBuffer; - gfx::UniqueVertexBufferResource emptyVertexBuffer; + UniqueVertexBufferResource emptyVertexBuffer; gfx::ShaderProgramBasePtr clipMaskShader; MTLDepthStencilStatePtr clipMaskDepthStencilState; diff --git a/include/mbgl/mtl/drawable.hpp b/include/mbgl/mtl/drawable.hpp index 2d0fb7118..8c001cf93 100644 --- a/include/mbgl/mtl/drawable.hpp +++ b/include/mbgl/mtl/drawable.hpp @@ -66,16 +66,16 @@ protected: // For testing only. Drawable(std::unique_ptr); - void bindAttributes(const RenderPass& renderPass) const; - void unbindAttributes(const RenderPass& renderPass) const; + void bindAttributes(RenderPass&) const noexcept; + void unbindAttributes(RenderPass&) const noexcept {} - void bindUniformBuffers(const RenderPass& renderPass) const; - void unbindUniformBuffers(const RenderPass& renderPass) const; + void bindUniformBuffers(RenderPass&) const noexcept; + void unbindUniformBuffers(RenderPass&) const noexcept {} - void bindTextures(const RenderPass& renderPass) const; - void unbindTextures(const RenderPass& renderPass) const; + void bindTextures(RenderPass&) const noexcept; + void unbindTextures(RenderPass&) const noexcept; - void uploadTextures() const; + void uploadTextures(UploadPass&) const noexcept; class Impl; const std::unique_ptr impl; diff --git a/include/mbgl/mtl/index_buffer_resource.hpp b/include/mbgl/mtl/index_buffer_resource.hpp index 4abb7c5e6..cdbe2997e 100644 --- a/include/mbgl/mtl/index_buffer_resource.hpp +++ b/include/mbgl/mtl/index_buffer_resource.hpp @@ -8,17 +8,17 @@ namespace mtl { class IndexBufferResource : public gfx::IndexBufferResource { public: - IndexBufferResource() = default; - IndexBufferResource(BufferResource&&); - IndexBufferResource(IndexBufferResource&& other) + IndexBufferResource() noexcept = default; + IndexBufferResource(BufferResource&&) noexcept; + IndexBufferResource(IndexBufferResource&& other) noexcept : buffer(std::move(other.buffer)) {} - ~IndexBufferResource() override; + ~IndexBufferResource() noexcept override; - std::size_t getSizeInBytes() const { return buffer.getSizeInBytes(); } - void* contents() const { return buffer.contents(); } + std::size_t getSizeInBytes() const noexcept { return buffer.getSizeInBytes(); } + const void* contents() const noexcept { return buffer.contents(); } - BufferResource& get() { return buffer; } - const BufferResource& get() const { return buffer; } + BufferResource& get() noexcept { return buffer; } + const BufferResource& get() const noexcept { return buffer; } protected: BufferResource buffer; diff --git a/include/mbgl/mtl/render_pass.hpp b/include/mbgl/mtl/render_pass.hpp index 966609a58..c781560fc 100644 --- a/include/mbgl/mtl/render_pass.hpp +++ b/include/mbgl/mtl/render_pass.hpp @@ -12,6 +12,7 @@ namespace mbgl { namespace mtl { +class BufferResource; class CommandEncoder; class Context; @@ -27,6 +28,10 @@ public: void addDebugSignpost(const char* name) override; + void bindVertex(const BufferResource&, std::size_t offset, std::size_t index, std::size_t size = 0); + + void bindFragment(const BufferResource&, std::size_t offset, std::size_t index, std::size_t size = 0); + private: void pushDebugGroup(const char* name) override; void popDebugGroup() override; @@ -36,6 +41,15 @@ private: mtl::CommandEncoder& commandEncoder; MTLRenderCommandEncoderPtr encoder; std::vector> debugGroups; + + struct BindInfo { + const BufferResource* buf = nullptr; + NS::UInteger offset = 0; + std::uint16_t version = 0; + }; + static constexpr auto maxBinds = 32; + std::array, maxBinds> vertexBinds; + std::array, maxBinds> fragmentBinds; }; } // namespace mtl diff --git a/include/mbgl/mtl/upload_pass.hpp b/include/mbgl/mtl/upload_pass.hpp index 168034d81..ce6081bcc 100644 --- a/include/mbgl/mtl/upload_pass.hpp +++ b/include/mbgl/mtl/upload_pass.hpp @@ -44,12 +44,14 @@ public: std::unique_ptr createVertexBufferResource(const void* data, std::size_t size, - gfx::BufferUsageType) override; + gfx::BufferUsageType, + bool persistent) override; void updateVertexBufferResource(gfx::VertexBufferResource&, const void* data, std::size_t size) override; std::unique_ptr createIndexBufferResource(const void* data, std::size_t size, - gfx::BufferUsageType) override; + gfx::BufferUsageType, + bool persistent) override; void updateIndexBufferResource(gfx::IndexBufferResource&, const void* data, std::size_t size) override; void updateResource(BufferResource&, const void* data, std::size_t size); diff --git a/include/mbgl/mtl/vertex_buffer_resource.hpp b/include/mbgl/mtl/vertex_buffer_resource.hpp index 230aa791c..0312e8beb 100644 --- a/include/mbgl/mtl/vertex_buffer_resource.hpp +++ b/include/mbgl/mtl/vertex_buffer_resource.hpp @@ -2,26 +2,30 @@ #include +#include + namespace mbgl { namespace mtl { class VertexBufferResource : public gfx::VertexBufferResource { public: - VertexBufferResource() = default; - VertexBufferResource(BufferResource&&); - VertexBufferResource(VertexBufferResource&& other) + VertexBufferResource() noexcept = default; + VertexBufferResource(BufferResource&&) noexcept; + VertexBufferResource(VertexBufferResource&& other) noexcept : buffer(std::move(other.buffer)) {} - ~VertexBufferResource() override; + ~VertexBufferResource() noexcept override; - std::size_t getSizeInBytes() const { return buffer.getSizeInBytes(); } - void* contents() const { return buffer.contents(); } + std::size_t getSizeInBytes() const noexcept { return buffer.getSizeInBytes(); } + const void* contents() const noexcept { return buffer.contents(); } - BufferResource& get() { return buffer; } - const BufferResource& get() const { return buffer; } + BufferResource& get() noexcept { return buffer; } + const BufferResource& get() const noexcept { return buffer; } protected: BufferResource buffer; }; +using UniqueVertexBufferResource = std::unique_ptr; + } // namespace mtl } // namespace mbgl diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index c57da13f4..ce4304379 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -123,7 +123,10 @@ public: virtual UniqueDrawableBuilder createDrawableBuilder(std::string name) = 0; /// Create a new uniform buffer - virtual UniformBufferPtr createUniformBuffer(const void* data, std::size_t size) = 0; + /// @param data The data to copy, may be `nullptr` + /// @param size The size of the buffer + /// @param persistent Performance hint, optimize for few or many uses + virtual UniformBufferPtr createUniformBuffer(const void* data, std::size_t size, bool persistent = false) = 0; /// Get the generic shader with the specified name virtual gfx::ShaderProgramBasePtr getGenericShader(gfx::ShaderRegistry&, const std::string& name) = 0; @@ -147,13 +150,17 @@ public: /// Update the uniform buffer with the provided data if it already exists, otherwise create it. /// @return True if the buffer was created, false if it was updated - virtual bool emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr&, const void* data, std::size_t size) = 0; + virtual bool emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr&, + const void* data, + std::size_t size, + bool persistent = false) = 0; /// `emplaceOrUpdateUniformBuffer` with type inference template std::enable_if_t, bool> emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& ptr, - const T* data) { - return emplaceOrUpdateUniformBuffer(ptr, data, sizeof(T)); + const T* data, + bool persistent = false) { + return emplaceOrUpdateUniformBuffer(ptr, data, sizeof(T), persistent); } #endif diff --git a/src/mbgl/gfx/index_buffer.hpp b/src/mbgl/gfx/index_buffer.hpp index 27efc67cb..081ad3988 100644 --- a/src/mbgl/gfx/index_buffer.hpp +++ b/src/mbgl/gfx/index_buffer.hpp @@ -8,10 +8,10 @@ namespace gfx { class IndexBufferResource { protected: - IndexBufferResource() = default; + IndexBufferResource() noexcept = default; public: - virtual ~IndexBufferResource() = default; + virtual ~IndexBufferResource() noexcept = default; }; class IndexBuffer { diff --git a/src/mbgl/gfx/uniform_buffer.cpp b/src/mbgl/gfx/uniform_buffer.cpp index 4a0638ab1..b38b70b87 100644 --- a/src/mbgl/gfx/uniform_buffer.cpp +++ b/src/mbgl/gfx/uniform_buffer.cpp @@ -37,18 +37,17 @@ const std::shared_ptr& UniformBufferArray::addOrReplace(const Str void UniformBufferArray::createOrUpdate(const StringIdentity id, const std::vector& data, - gfx::Context& context) { - createOrUpdate(id, data.data(), data.size(), context); + gfx::Context& context, + bool persistent) { + createOrUpdate(id, data.data(), data.size(), context, persistent); } -void UniformBufferArray::createOrUpdate(const StringIdentity id, - const void* data, - const std::size_t size, - gfx::Context& context) { +void UniformBufferArray::createOrUpdate( + const StringIdentity id, const void* data, const std::size_t size, gfx::Context& context, bool persistent) { if (auto& ubo = get(id); ubo && ubo->getSize() == size) { ubo->update(data, size); } else { - add(id, context.createUniformBuffer(data, size)); + add(id, context.createUniformBuffer(data, size, persistent)); } } diff --git a/src/mbgl/gfx/upload_pass.hpp b/src/mbgl/gfx/upload_pass.hpp index d9676ddb4..a9d77d0b3 100644 --- a/src/mbgl/gfx/upload_pass.hpp +++ b/src/mbgl/gfx/upload_pass.hpp @@ -54,8 +54,9 @@ public: public: template VertexBuffer createVertexBuffer(const VertexVector& v, - const BufferUsageType usage = BufferUsageType::StaticDraw) { - return {v.elements(), createVertexBufferResource(v.data(), v.bytes(), usage)}; + const BufferUsageType usage = BufferUsageType::StaticDraw, + bool persistent = false) { + return {v.elements(), createVertexBufferResource(v.data(), v.bytes(), usage, persistent)}; } template @@ -66,8 +67,9 @@ public: template IndexBuffer createIndexBuffer(IndexVector&& v, - const BufferUsageType usage = BufferUsageType::StaticDraw) { - return {v.elements(), createIndexBufferResource(v.data(), v.bytes(), usage)}; + const BufferUsageType usage = BufferUsageType::StaticDraw, + bool persistent = false) { + return {v.elements(), createIndexBufferResource(v.data(), v.bytes(), usage, persistent)}; } template @@ -91,13 +93,15 @@ public: protected: virtual std::unique_ptr createVertexBufferResource(const void* data, std::size_t size, - BufferUsageType) = 0; + BufferUsageType, + bool persistent = false) = 0; virtual void updateVertexBufferResource(VertexBufferResource&, const void* data, std::size_t size) = 0; public: virtual std::unique_ptr createIndexBufferResource(const void* data, std::size_t size, - BufferUsageType) = 0; + BufferUsageType, + bool persistent = false) = 0; virtual void updateIndexBufferResource(IndexBufferResource&, const void* data, std::size_t size) = 0; public: diff --git a/src/mbgl/gfx/vertex_buffer.hpp b/src/mbgl/gfx/vertex_buffer.hpp index 031410faf..4814661f5 100644 --- a/src/mbgl/gfx/vertex_buffer.hpp +++ b/src/mbgl/gfx/vertex_buffer.hpp @@ -8,10 +8,10 @@ namespace gfx { class VertexBufferResource { protected: - VertexBufferResource() = default; + VertexBufferResource() noexcept = default; public: - virtual ~VertexBufferResource() = default; + virtual ~VertexBufferResource() noexcept = default; }; using UniqueVertexBufferResource = std::unique_ptr; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 0c655d0dc..d8c2aa038 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -436,12 +436,15 @@ void Context::resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) { setCullFaceMode(gfx::CullFaceMode::disabled()); } -bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, const void* data, std::size_t size) { +bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, + const void* data, + std::size_t size, + bool persistent) { if (buffer) { buffer->update(data, size); return false; } else { - buffer = createUniformBuffer(data, size); + buffer = createUniformBuffer(data, size, persistent); return true; } } @@ -487,7 +490,7 @@ gfx::UniqueDrawableBuilder Context::createDrawableBuilder(std::string name) { return std::make_unique(std::move(name)); } -gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size) { +gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size, bool /*persistent*/) { return std::make_shared(data, size); } diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 2a407b107..c1eb6ce44 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -103,7 +103,7 @@ public: #if MLN_DRAWABLE_RENDERER gfx::UniqueDrawableBuilder createDrawableBuilder(std::string name) override; - gfx::UniformBufferPtr createUniformBuffer(const void* data, std::size_t size) override; + gfx::UniformBufferPtr createUniformBuffer(const void* data, std::size_t size, bool persistent) override; gfx::ShaderProgramBasePtr getGenericShader(gfx::ShaderRegistry&, const std::string& name) override; @@ -119,7 +119,10 @@ public: void resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) override; - bool emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr&, const void* data, std::size_t size) override; + bool emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr&, + const void* data, + std::size_t size, + bool persistent) override; #endif void setDirtyState() override; diff --git a/src/mbgl/gl/upload_pass.cpp b/src/mbgl/gl/upload_pass.cpp index 2d1c1ba90..0a7cb2a36 100644 --- a/src/mbgl/gl/upload_pass.cpp +++ b/src/mbgl/gl/upload_pass.cpp @@ -29,7 +29,8 @@ UploadPass::UploadPass(gl::CommandEncoder& commandEncoder_, const char* name) std::unique_ptr UploadPass::createVertexBufferResource(const void* data, const std::size_t size, - const gfx::BufferUsageType usage) { + const gfx::BufferUsageType usage, + bool /*persistent*/) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); commandEncoder.context.renderingStats().numBuffers++; @@ -48,7 +49,8 @@ void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, std::unique_ptr UploadPass::createIndexBufferResource(const void* data, std::size_t size, - const gfx::BufferUsageType usage) { + const gfx::BufferUsageType usage, + bool /*persistent*/) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); commandEncoder.context.renderingStats().numBuffers++; @@ -161,7 +163,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe // Otherwise, create a new one if (rawBufSize > 0) { auto buffer = std::make_unique(); - buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage); + buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage, /*persistent=*/false); vec->setBuffer(std::move(buffer)); vec->setDirty(false); return static_cast(vec->getBuffer())->resource; @@ -283,7 +285,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings( assert(vertexStride * vertexCount <= allData.size()); if (!allData.empty()) { - if (auto vertBuf = createVertexBufferResource(allData.data(), allData.size(), usage)) { + if (auto vertBuf = createVertexBufferResource(allData.data(), allData.size(), usage, /*persistent=*/false)) { // Fill in the buffer in each binding that was generated without its own buffer std::for_each(bindings.begin(), bindings.end(), [&](auto& b) { if (b && !b->vertexBufferResource) { diff --git a/src/mbgl/gl/upload_pass.hpp b/src/mbgl/gl/upload_pass.hpp index 08dfcc3e6..b3b9a2bbf 100644 --- a/src/mbgl/gl/upload_pass.hpp +++ b/src/mbgl/gl/upload_pass.hpp @@ -35,11 +35,14 @@ public: std::unique_ptr createVertexBufferResource(const void* data, std::size_t size, - gfx::BufferUsageType) override; + gfx::BufferUsageType, + bool persistent) override; void updateVertexBufferResource(gfx::VertexBufferResource&, const void* data, std::size_t size) override; + std::unique_ptr createIndexBufferResource(const void* data, std::size_t size, - gfx::BufferUsageType) override; + gfx::BufferUsageType, + bool persistent) override; void updateIndexBufferResource(gfx::IndexBufferResource&, const void* data, std::size_t size) override; #if MLN_DRAWABLE_RENDERER diff --git a/src/mbgl/mtl/buffer_resource.cpp b/src/mbgl/mtl/buffer_resource.cpp index 72032bcda..c6ed8d87c 100644 --- a/src/mbgl/mtl/buffer_resource.cpp +++ b/src/mbgl/mtl/buffer_resource.cpp @@ -4,62 +4,158 @@ #include #include +#include #include namespace mbgl { namespace mtl { -BufferResource::BufferResource(Context& context_, const void* data, std::size_t size_, MTL::ResourceOptions usage_) +namespace { +// The `setVertexBytes:length:atIndex:` method is the best option for binding a very small +// amount (less than 4 KB) of dynamic buffer data to a vertex function, as shown in Listing +// 5-1. This method avoids the overhead of creating an intermediary MTLBuffer object. +// https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/BufferBindings.html +constexpr auto bufferThreshold = 4096; +} // namespace + +BufferResource::BufferResource(Context& context_, + const void* data, + std::size_t size_, + MTL::ResourceOptions usage_, + bool isIndexBuffer_, + bool persistent_) : context(context_), size(static_cast(size_)), - usage(usage_) { - auto& device = context.getBackend().getDevice(); - buffer = NS::TransferPtr((data && size) ? device->newBuffer(data, size, usage) : device->newBuffer(size, usage)); - if (buffer) { + usage(usage_), + isIndexBuffer(isIndexBuffer_), + persistent(persistent_) { + // If the buffer is small, not for indexes, and not explicitly persistent, skip the overhead of an `NSBuffer` + if (size_ < bufferThreshold && !isIndexBuffer_ && !persistent) { + if (data) { + raw.assign(static_cast(data), static_cast(data) + size); + } else { + raw.resize(size); + } + assert(raw.size() == size); + } else { + auto& device = context.getBackend().getDevice(); + buffer = NS::TransferPtr((data && size) ? device->newBuffer(data, size, usage) + : device->newBuffer(size, usage)); + } + + if (isValid()) { context.renderingStats().numBuffers++; context.renderingStats().memBuffers += size; } } -BufferResource::BufferResource(BufferResource&& other) +BufferResource::BufferResource(BufferResource&& other) noexcept : context(other.context), buffer(std::move(other.buffer)), + raw(std::move(other.raw)), size(other.size), - usage(other.usage) {} + usage(other.usage), + isIndexBuffer(other.isIndexBuffer), + persistent(other.persistent) {} -BufferResource::~BufferResource() { - if (buffer) { +BufferResource::~BufferResource() noexcept { + if (isValid()) { context.renderingStats().numBuffers--; context.renderingStats().memBuffers -= size; } } BufferResource BufferResource::clone() const { - return {context, buffer->contents(), size, usage}; + return {context, contents(), size, usage, isIndexBuffer, persistent}; } -BufferResource& BufferResource::operator=(BufferResource&& other) { +BufferResource& BufferResource::operator=(BufferResource&& other) noexcept { assert(&context == &other.context); - if (buffer) { + if (isValid()) { context.renderingStats().numBuffers--; context.renderingStats().memBuffers -= size; } buffer = std::move(other.buffer); + raw = std::move(other.raw); size = other.size; usage = other.usage; + isIndexBuffer = other.isIndexBuffer; + persistent = other.persistent; return *this; } -void BufferResource::update(const void* data, std::size_t size, std::size_t offset) { - assert(buffer && (data || size == 0)); - if (buffer && data && size > 0) { - assert(buffer->contents()); - if (void* content = buffer->contents()) { - const auto size_ = std::min(size, static_cast(buffer->length()) - offset); - assert(size == size_); - std::memcpy(static_cast(content) + offset, data, size_); +void BufferResource::update(const void* data, std::size_t updateSize, std::size_t offset) noexcept { + assert(size >= 0 && updateSize + offset <= size); + updateSize = std::min(updateSize, size - offset); + + if (updateSize > 0) { + if (buffer) { + if (auto* content = static_cast(buffer->contents())) { + std::memcpy(content + offset, data, updateSize); + } + } else { + std::memcpy(raw.data() + offset, data, updateSize); } + version++; + } +} + +bool BufferResource::needReBind(VersionType version_) const noexcept { + // If we're using a raw buffer, an update means we have to re-bind. + // For a MTLBuffer, the binding can be left alone. + return (!buffer || version != version_); +} + +void BufferResource::bindVertex(const MTLRenderCommandEncoderPtr& encoder, + const std::size_t offset, + const std::size_t index, + std::size_t size_) const noexcept { + assert(offset + size_ <= size); + if (const auto* mtlBuf = buffer.get()) { + encoder->setVertexBuffer(mtlBuf, static_cast(offset), static_cast(index)); + } else if (!raw.empty()) { + size_ = size_ ? std::min(size_, size - offset) : size - offset; + encoder->setVertexBytes(raw.data() + offset, size_, index); + } +} + +void BufferResource::bindFragment(const MTLRenderCommandEncoderPtr& encoder, + const std::size_t offset, + const std::size_t index, + std::size_t size_) const noexcept { + assert(offset + size_ <= size); + if (const auto* mtlBuf = buffer.get()) { + encoder->setFragmentBuffer(mtlBuf, static_cast(offset), static_cast(index)); + } else if (!raw.empty()) { + size_ = size_ ? std::min(size_, size - offset) : size - offset; + encoder->setFragmentBytes(raw.data() + offset, size_, index); + } +} + +void BufferResource::updateVertexBindOffset(const MTLRenderCommandEncoderPtr& encoder, + std::size_t offset, + std::size_t index, + std::size_t size_) const noexcept { + // If we're using a MTLBuffer, just update the offset. + // The documentation for `setVertexBufferOffset` indicates that it should work for buffers + // assigned using `setVertexBytes` but, in practice, it produces a validation failure: + // `Set Vertex Buffer Offset Validation index(1) must have an existing buffer.` + if (const auto* mtlBuf = buffer.get()) { + encoder->setVertexBufferOffset(offset, index); + } else { + bindVertex(encoder, offset, index, size_); + } +} + +void BufferResource::updateFragmentBindOffset(const MTLRenderCommandEncoderPtr& encoder, + std::size_t offset, + std::size_t index, + std::size_t size_) const noexcept { + if (const auto* mtlBuf = buffer.get()) { + encoder->setFragmentBufferOffset(offset, index); + } else { + bindFragment(encoder, offset, index, size_); } } diff --git a/src/mbgl/mtl/context.cpp b/src/mbgl/mtl/context.cpp index afb406d98..4e4167af8 100644 --- a/src/mbgl/mtl/context.cpp +++ b/src/mbgl/mtl/context.cpp @@ -64,8 +64,9 @@ std::unique_ptr Context::createCommandEncoder() { return std::make_unique(*this); } -BufferResource Context::createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const { - return {const_cast(*this), data, size, MTL::ResourceStorageModeShared}; +BufferResource Context::createBuffer( + const void* data, std::size_t size, gfx::BufferUsageType, bool isIndexBuffer, bool persistent) const { + return {const_cast(*this), data, size, MTL::ResourceStorageModeShared, isIndexBuffer, persistent}; } UniqueShaderProgram Context::createProgram(std::string name, @@ -170,8 +171,9 @@ gfx::UniqueDrawableBuilder Context::createDrawableBuilder(std::string name) { return std::make_unique(std::move(name)); } -gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size) { - return std::make_shared(createBuffer(data, size, gfx::BufferUsageType::StaticDraw)); +gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size, bool persistent) { + return std::make_shared( + createBuffer(data, size, gfx::BufferUsageType::StaticDraw, /*isIndexBuffer=*/false, persistent)); } gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) { @@ -198,12 +200,15 @@ RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureC void Context::resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) {} -bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, const void* data, std::size_t size) { +bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, + const void* data, + std::size_t size, + bool persistent) { if (buffer) { buffer->update(data, size); return false; } else { - buffer = createUniformBuffer(data, size); + buffer = createUniformBuffer(data, size, persistent); return true; } } @@ -212,7 +217,11 @@ const BufferResource& Context::getTileVertexBuffer() { if (!tileVertexBuffer) { const auto vertices = RenderStaticData::tileVertices(); constexpr auto vertexSize = sizeof(decltype(vertices)::Vertex::a1); - tileVertexBuffer.emplace(createBuffer(vertices.data(), vertices.bytes(), gfx::BufferUsageType::StaticDraw)); + tileVertexBuffer.emplace(createBuffer(vertices.data(), + vertices.bytes(), + gfx::BufferUsageType::StaticDraw, + /*isIndexBuffer=*/true, + /*persistent=*/true)); } return *tileVertexBuffer; } @@ -220,12 +229,16 @@ const BufferResource& Context::getTileVertexBuffer() { const BufferResource& Context::getTileIndexBuffer() { if (!tileIndexBuffer) { const auto indexes = RenderStaticData::quadTriangleIndices(); - tileIndexBuffer.emplace(createBuffer(indexes.data(), indexes.bytes(), gfx::BufferUsageType::StaticDraw)); + tileIndexBuffer.emplace(createBuffer(indexes.data(), + indexes.bytes(), + gfx::BufferUsageType::StaticDraw, + /*isIndexBuffer=*/true, + /*persistent=*/true)); } return *tileIndexBuffer; } -const gfx::UniqueVertexBufferResource& Context::getEmptyVertexBuffer() { +const UniqueVertexBufferResource& Context::getEmptyVertexBuffer() { if (!emptyVertexBuffer) { // This buffer is bound to vertex attribtue indexes when the uniforms are used instead and // shaders are expected not to access the attribute values, but Metal requires a binding. @@ -234,7 +247,8 @@ const gfx::UniqueVertexBufferResource& Context::getEmptyVertexBuffer() { // descriptors, but that isn't currently being used. constexpr std::size_t size = 32; constexpr auto usage = gfx::BufferUsageType::StaticDraw; - emptyVertexBuffer = std::make_unique(createBuffer(nullptr, size, usage)); + emptyVertexBuffer = std::make_unique( + createBuffer(nullptr, size, usage, /*isIndexBuffer=*/false, /*persistent=*/false)); } return emptyVertexBuffer; } @@ -272,7 +286,7 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, } const auto& mtlShader = static_cast(*clipMaskShader); - const auto& mtlRenderPass = static_cast(renderPass); + auto& mtlRenderPass = static_cast(renderPass); const auto& encoder = mtlRenderPass.getMetalEncoder(); const auto colorMode = gfx::ColorMode::disabled(); @@ -352,7 +366,11 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, auto& uboBuffer = clipMaskUniformsBufferUsed ? tempBuffer : clipMaskUniformsBuffer; clipMaskUniformsBufferUsed = true; if (!uboBuffer || !*uboBuffer || uboBuffer->getSizeInBytes() < bufferSize) { - uboBuffer = createBuffer(tileUBOs.data(), bufferSize, gfx::BufferUsageType::StaticDraw); + uboBuffer = createBuffer(tileUBOs.data(), + bufferSize, + gfx::BufferUsageType::StaticDraw, + /*isIndexBuffer=*/false, + /*persistent=*/!clipMaskUniformsBufferUsed); if (!uboBuffer) { return false; } @@ -361,7 +379,8 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, } encoder->setCullMode(MTL::CullModeNone); - encoder->setVertexBuffer(vertexRes.getMetalBuffer().get(), /*offset=*/0, ShaderClass::attributes[0].index); + + mtlRenderPass.bindVertex(vertexRes, /*offset=*/0, ShaderClass::attributes[0].index); // Instancing is disabled for now because the `[[stencil]]` attribute in the fragment shader output // that we need to apply a different stencil value for each tile causes a problem on some older (A8-A11) @@ -379,10 +398,10 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, /*baseVertex=*/0, /*baseInstance=*/0); #else + const auto uboIndex = ShaderClass::uniforms[0].index; for (std::size_t ii = 0; ii < tileUBOs.size(); ++ii) { encoder->setStencilReferenceValue(tileUBOs[ii].stencil_ref); - encoder->setVertexBuffer( - uboBuffer->getMetalBuffer().get(), /*offset=*/ii * uboSize, ShaderClass::uniforms[0].index); + mtlRenderPass.bindVertex(*uboBuffer, /*offset=*/ii * uboSize, uboIndex, /*size=*/uboSize); encoder->drawIndexedPrimitives(MTL::PrimitiveType::PrimitiveTypeTriangle, indexCount, MTL::IndexType::IndexTypeUInt16, diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index ba7ebe6ee..23269c40c 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -43,16 +43,6 @@ Drawable::Drawable(std::string name_) Drawable::~Drawable() {} namespace { -// Downcast a generic vertex buffer resource and extract the Metal buffer -MTL::Buffer* getMetalBuffer(const gfx::VertexBufferResource* resource_) { - if (const auto* resource = static_cast(resource_)) { - if (const auto& bufferResource = resource->get()) { - return bufferResource.getMetalBuffer().get(); - } - } - return nullptr; -} - #if !defined(NDEBUG) std::size_t getBufferSize(const gfx::VertexBufferResource* resource_) { if (const auto* resource = static_cast(resource_)) { @@ -64,7 +54,7 @@ std::size_t getBufferSize(const gfx::VertexBufferResource* resource_) { } #endif // !defined(NDEBUG) -MTL::PrimitiveType getPrimitiveType(const gfx::DrawModeType type) { +MTL::PrimitiveType getPrimitiveType(const gfx::DrawModeType type) noexcept { switch (type) { default: assert(false); @@ -88,7 +78,7 @@ std::string debugLabel(const gfx::Drawable& drawable) { } #endif // !defined(NDEBUG) -MTL::Buffer* getMetalBuffer(const gfx::IndexVectorBasePtr& indexes) { +MTL::Buffer* getMetalBuffer(const gfx::IndexVectorBasePtr& indexes) noexcept { if (const auto* buf0 = indexes->getBuffer()) { if (const auto* buf1 = static_cast(buf0)->buffer.get()) { const auto& buf2 = buf1->getResource().get(); @@ -98,7 +88,7 @@ MTL::Buffer* getMetalBuffer(const gfx::IndexVectorBasePtr& indexes) { return nullptr; } -MTL::CullMode mapCullMode(const gfx::CullFaceSideType mode) { +MTL::CullMode mapCullMode(const gfx::CullFaceSideType mode) noexcept { switch (mode) { case gfx::CullFaceSideType::Front: return MTL::CullModeFront; @@ -110,7 +100,7 @@ MTL::CullMode mapCullMode(const gfx::CullFaceSideType mode) { } } -MTL::Winding mapWindingMode(const gfx::CullFaceWindingType mode) { +MTL::Winding mapWindingMode(const gfx::CullFaceWindingType mode) noexcept { switch (mode) { case gfx::CullFaceWindingType::Clockwise: return MTL::Winding::WindingClockwise; @@ -158,7 +148,7 @@ void Drawable::draw(PaintParameters& parameters) const { } auto& context = static_cast(parameters.context); - const auto& renderPass = static_cast(*parameters.renderPass); + auto& renderPass = static_cast(*parameters.renderPass); const auto& encoder = renderPass.getMetalEncoder(); if (!encoder) { assert(false); @@ -284,16 +274,6 @@ void Drawable::draw(PaintParameters& parameters) const { assert(mlSegment.indexOffset + mlSegment.indexLength <= indexBufferLength); assert(static_cast(maxIndex) < mlSegment.vertexLength); - - 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()); - } else if (impl->noBindingBuffer) { - assert(binding->vertexStride <= impl->noBindingBuffer->length()); - } - } - } #endif encoder->drawIndexedPrimitives(primitiveType, @@ -364,103 +344,74 @@ void Drawable::setVertexAttrNameId(const StringIdentity value) { impl->idVertexAttrName = value; } -void Drawable::bindAttributes(const RenderPass& renderPass) const { +void Drawable::bindAttributes(RenderPass& renderPass) const noexcept { const auto& encoder = renderPass.getMetalEncoder(); NS::UInteger attributeIndex = 0; for (const auto& binding : impl->attributeBindings) { - if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) { + const auto* buffer = static_cast(binding ? binding->vertexBufferResource + : nullptr); + if (buffer && buffer->get()) { assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource)); - encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex); + renderPass.bindVertex(buffer->get(), /*offset=*/0, attributeIndex); } else if (impl->noBindingBuffer) { - encoder->setVertexBuffer(impl->noBindingBuffer, /*offset=*/0, attributeIndex); + renderPass.bindVertex(impl->noBindingBuffer->get(), /*offset=*/0, attributeIndex); } attributeIndex += 1; } } -void Drawable::unbindAttributes(const RenderPass& renderPass) const { - const auto& encoder = renderPass.getMetalEncoder(); - - NS::UInteger attributeIndex = 0; - for (const auto& binding : impl->attributeBindings) { - encoder->setVertexBuffer(nullptr, /*offset=*/0, attributeIndex); - attributeIndex += 1; - } -} - -void Drawable::bindUniformBuffers(const RenderPass& renderPass) const { +void Drawable::bindUniformBuffers(RenderPass& renderPass) const noexcept { if (shader) { const auto& shaderMTL = static_cast(*shader); - const auto& encoder = renderPass.getMetalEncoder(); for (const auto& element : shaderMTL.getUniformBlocks().getMap()) { const auto& uniformBuffer = getUniformBuffers().get(element.first); - if (!uniformBuffer) { - using namespace std::string_literals; - const auto tileID = getTileID() ? util::toString(*getTileID()) : ""; - const auto tileLabel = util::toString(getID()) + "/" + getName() + "/" + tileID; - Log::Error(Event::General, - "bindUniformBuffers: UBO "s + stringIndexer().get(element.first) + " not found on " + - tileLabel + ". skipping."); - assert(false); - continue; - } + assert(uniformBuffer && "UBO missing, drawable skipped"); + if (uniformBuffer) { + const auto& buffer = static_cast(*uniformBuffer.get()); + const auto& resource = buffer.getBufferResource(); + const auto& block = static_cast(*element.second); + const auto index = block.getIndex(); - const auto& buffer = static_cast(*uniformBuffer.get()); - const auto& bufferMTL = buffer.getBufferResource().getMetalBuffer().get(); - - const auto& block = static_cast(*element.second); - const auto index = block.getIndex(); - - if (block.getBindVertex()) { - encoder->setVertexBuffer(bufferMTL, /*offset=*/0, index); - } - if (block.getBindFragment()) { - encoder->setFragmentBuffer(bufferMTL, /*offset=*/0, index); + if (block.getBindVertex()) { + renderPass.bindVertex(resource, /*offset=*/0, index); + } + if (block.getBindFragment()) { + renderPass.bindFragment(resource, /*offset=*/0, index); + } } } } } -void Drawable::unbindUniformBuffers(const RenderPass& renderPass) const { - if (shader) { - const auto& shaderMTL = static_cast(*shader); - const auto& encoder = renderPass.getMetalEncoder(); - for (const auto& element : shaderMTL.getUniformBlocks().getMap()) { - const auto index = element.second->getIndex(); - encoder->setVertexBuffer(nullptr, 0, index); - } - } -} - -void Drawable::bindTextures(const RenderPass& renderPass) const { +void Drawable::bindTextures(RenderPass& renderPass) const noexcept { for (const auto& pair : textures) { if (const auto& tex = pair.second) { const auto& location = pair.first; - std::static_pointer_cast(tex)->bind(renderPass, location); + static_cast(*tex).bind(renderPass, location); } } } -void Drawable::unbindTextures(const RenderPass& renderPass) const { +void Drawable::unbindTextures(RenderPass& renderPass) const noexcept { for (const auto& pair : textures) { if (const auto& tex = pair.second) { const auto& location = pair.first; - std::static_pointer_cast(tex)->unbind(renderPass, location); + static_cast(*tex).unbind(renderPass, location); } } } -void Drawable::uploadTextures() const { +void Drawable::uploadTextures(UploadPass&) const noexcept { for (const auto& pair : textures) { if (const auto& tex = pair.second) { - std::static_pointer_cast(tex)->upload(); + static_cast(*tex).upload(); } } } namespace { -MTL::VertexFormat mtlVertexTypeOf(gfx::AttributeDataType type) { +MTL::VertexFormat mtlVertexTypeOf(gfx::AttributeDataType type) noexcept { switch (type) { case gfx::AttributeDataType::Byte: return MTL::VertexFormatChar; @@ -548,8 +499,8 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { } if (impl->indexes->getDirty()) { - auto indexBufferResource{ - uploadPass.createIndexBufferResource(impl->indexes->data(), impl->indexes->bytes(), usage)}; + auto indexBufferResource{uploadPass.createIndexBufferResource( + impl->indexes->data(), impl->indexes->bytes(), usage, /*persistent=*/false)}; auto indexBuffer = std::make_unique(impl->indexes->elements(), std::move(indexBufferResource)); auto buffer = std::make_unique(std::move(indexBuffer)); @@ -581,7 +532,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { [](const auto&, gfx::VertexAttribute& attrib) { attrib.setDirty(false); }); if (impl->attributeBindings != attributeBindings_) { - impl->attributeBindings = attributeBindings_; + impl->attributeBindings = std::move(attributeBindings_); // Create a layout descriptor for each attribute auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor()); @@ -595,7 +546,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { if (!binding->vertexBufferResource && !impl->noBindingBuffer) { if (const auto& buf = context.getEmptyVertexBuffer()) { - impl->noBindingBuffer = getMetalBuffer(buf.get()); + impl->noBindingBuffer = buf.get(); } } @@ -626,23 +577,9 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { textures.begin(), textures.end(), [](const auto& pair) { return pair.second && pair.second->needsUpload(); }); if (texturesNeedUpload) { - uploadTextures(); + uploadTextures(uploadPass); } } -/* -gfx::ColorMode Drawable::makeColorMode(PaintParameters& parameters) const { - return enableColor ? parameters.colorModeForRenderPass() : gfx::ColorMode::disabled(); -} -gfx::StencilMode Drawable::makeStencilMode(PaintParameters& parameters) const { - if (enableStencil) { - if (!is3D && tileID) { - return parameters.stencilModeForClipping(tileID->toUnwrapped()); - } - assert(false); - } - return gfx::StencilMode::disabled(); -} -*/ } // namespace mtl } // namespace mbgl diff --git a/src/mbgl/mtl/drawable_impl.hpp b/src/mbgl/mtl/drawable_impl.hpp index 0d81a2783..ad141d586 100644 --- a/src/mbgl/mtl/drawable_impl.hpp +++ b/src/mbgl/mtl/drawable_impl.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,7 @@ public: // GLfloat pointSize = 0.0f; StringIdentity idVertexAttrName = stringIndexer().get("a_pos"); - MTL::Buffer* noBindingBuffer = nullptr; + VertexBufferResource* noBindingBuffer = nullptr; gfx::AttributeBindingArray attributeBindings; diff --git a/src/mbgl/mtl/index_buffer_resource.cpp b/src/mbgl/mtl/index_buffer_resource.cpp index 0af135067..30c1644ba 100644 --- a/src/mbgl/mtl/index_buffer_resource.cpp +++ b/src/mbgl/mtl/index_buffer_resource.cpp @@ -5,18 +5,20 @@ namespace mbgl { namespace mtl { -IndexBufferResource::IndexBufferResource(BufferResource&& ptr) +IndexBufferResource::IndexBufferResource(BufferResource&& ptr) noexcept : buffer(std::move(ptr)) { if (buffer) { - buffer.getContext().renderingStats().numIndexBuffers++; - buffer.getContext().renderingStats().memIndexBuffers += buffer.getSizeInBytes(); + auto& stats = buffer.getContext().renderingStats(); + stats.numIndexBuffers++; + stats.memIndexBuffers += buffer.getSizeInBytes(); } } -IndexBufferResource::~IndexBufferResource() { +IndexBufferResource::~IndexBufferResource() noexcept { if (buffer) { - buffer.getContext().renderingStats().numIndexBuffers--; - buffer.getContext().renderingStats().memIndexBuffers -= buffer.getSizeInBytes(); + auto& stats = buffer.getContext().renderingStats(); + stats.numIndexBuffers--; + stats.memIndexBuffers -= buffer.getSizeInBytes(); } } diff --git a/src/mbgl/mtl/render_pass.cpp b/src/mbgl/mtl/render_pass.cpp index b5ed4e8e9..a8f7b7311 100644 --- a/src/mbgl/mtl/render_pass.cpp +++ b/src/mbgl/mtl/render_pass.cpp @@ -93,5 +93,45 @@ void RenderPass::addDebugSignpost(const char* name) { } } +void RenderPass::bindVertex(const BufferResource& buf, std::size_t offset, std::size_t index, std::size_t size) { + assert(0 <= index && index < maxBinds); + if (0 <= index && index < maxBinds) { + if (auto& bind = vertexBinds[index]) { + // Is this the same buffer already bound to this index? + if (bind->buf == &buf && !buf.needReBind(bind->version)) { + // Yes, but is the offset different? + if (bind->offset != offset) { + // Yes, update just the offset + buf.updateVertexBindOffset(encoder, offset, index, size); + bind->offset = offset; + } + return; + } + } + vertexBinds[index] = BindInfo{&buf, offset}; + } + buf.bindVertex(encoder, offset, index, size); +} + +void RenderPass::bindFragment(const BufferResource& buf, std::size_t offset, std::size_t index, std::size_t size) { + assert(0 <= index && index < maxBinds); + if (0 <= index && index < maxBinds) { + if (auto& bind = fragmentBinds[index]) { + // Is this the same buffer already bound to this index? + if (bind->buf == &buf && !buf.needReBind(bind->version)) { + // Yes, but is the offset different? + if (bind->offset != offset) { + // Yes, update just the offset + buf.updateFragmentBindOffset(encoder, offset, index, size); + bind->offset = offset; + } + return; + } + } + fragmentBinds[index] = BindInfo{&buf, offset}; + } + buf.bindFragment(encoder, offset, index, size); +} + } // namespace mtl } // namespace mbgl diff --git a/src/mbgl/mtl/texture2d.cpp b/src/mbgl/mtl/texture2d.cpp index 2e5ebf0a3..9aafe5450 100644 --- a/src/mbgl/mtl/texture2d.cpp +++ b/src/mbgl/mtl/texture2d.cpp @@ -201,11 +201,7 @@ void Texture2D::bind(const RenderPass& renderPass, int32_t location) noexcept { context.renderingStats().numTextureBindings++; } -void Texture2D::unbind(const RenderPass& renderPass, int32_t location) noexcept { - const auto& encoder = renderPass.getMetalEncoder(); - encoder->setFragmentTexture(nullptr, location); - encoder->setFragmentSamplerState(nullptr, location); - +void Texture2D::unbind(const RenderPass&, int32_t /*location*/) noexcept { context.renderingStats().numTextureBindings--; } diff --git a/src/mbgl/mtl/upload_pass.cpp b/src/mbgl/mtl/upload_pass.cpp index 629d1b50c..e18991579 100644 --- a/src/mbgl/mtl/upload_pass.cpp +++ b/src/mbgl/mtl/upload_pass.cpp @@ -60,8 +60,10 @@ void UploadPass::endEncoding() { std::unique_ptr UploadPass::createVertexBufferResource(const void* data, const std::size_t size, - const gfx::BufferUsageType usage) { - return std::make_unique(commandEncoder.context.createBuffer(data, size, usage)); + const gfx::BufferUsageType usage, + bool persistent) { + return std::make_unique( + commandEncoder.context.createBuffer(data, size, usage, /*isIndexBuffer=*/false, persistent)); } void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, const void* data, std::size_t size) { @@ -70,8 +72,10 @@ void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, std::unique_ptr UploadPass::createIndexBufferResource(const void* data, const std::size_t size, - const gfx::BufferUsageType usage) { - return std::make_unique(commandEncoder.context.createBuffer(data, size, usage)); + const gfx::BufferUsageType usage, + bool persistent) { + return std::make_unique( + commandEncoder.context.createBuffer(data, size, usage, /*isIndexBuffer=*/true, persistent)); } void UploadPass::updateIndexBufferResource(gfx::IndexBufferResource& resource, const void* data, std::size_t size) { @@ -137,7 +141,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe // Otherwise, create a new one if (rawBufSize > 0) { auto buffer = std::make_unique(); - buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage); + buffer->resource = createVertexBufferResource(rawBufPtr, rawBufSize, usage, /*persistent=*/false); vec->setBuffer(std::move(buffer)); vec->setDirty(false); return static_cast(vec->getBuffer())->resource; @@ -223,7 +227,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings( assert(vertexStride * vertexCount <= allData.size()); if (!allData.empty()) { - if (auto vertBuf = createVertexBufferResource(allData.data(), allData.size(), usage)) { + if (auto vertBuf = createVertexBufferResource(allData.data(), allData.size(), usage, /*persistent=*/false)) { // Fill in the buffer in each binding that was generated without its own buffer std::for_each(bindings.begin(), bindings.end(), [&](auto& b) { if (b && !b->vertexBufferResource) { diff --git a/src/mbgl/mtl/vertex_attribute.cpp b/src/mbgl/mtl/vertex_attribute.cpp index 53250cc2d..bc27acec3 100644 --- a/src/mbgl/mtl/vertex_attribute.cpp +++ b/src/mbgl/mtl/vertex_attribute.cpp @@ -85,7 +85,8 @@ const gfx::UniqueVertexBufferResource& VertexAttribute::getBuffer(gfx::VertexAtt if (attrib.sharedRawData) { return uploadPass.getBuffer(attrib.sharedRawData, usage); } else if (!attrib.rawData.empty()) { - auto buffer = uploadPass.createVertexBufferResource(attrib.rawData.data(), attrib.rawData.size(), usage); + auto buffer = uploadPass.createVertexBufferResource( + attrib.rawData.data(), attrib.rawData.size(), usage, false); attrib.setBuffer(std::move(buffer)); attrib.setRawData({}); } else { diff --git a/src/mbgl/mtl/vertex_buffer_resource.cpp b/src/mbgl/mtl/vertex_buffer_resource.cpp index c288f2a28..965fb5815 100644 --- a/src/mbgl/mtl/vertex_buffer_resource.cpp +++ b/src/mbgl/mtl/vertex_buffer_resource.cpp @@ -5,18 +5,20 @@ namespace mbgl { namespace mtl { -VertexBufferResource::VertexBufferResource(BufferResource&& ptr) +VertexBufferResource::VertexBufferResource(BufferResource&& ptr) noexcept : buffer(std::move(ptr)) { if (buffer) { - buffer.getContext().renderingStats().numVertexBuffers++; - buffer.getContext().renderingStats().memVertexBuffers += buffer.getSizeInBytes(); + auto& stats = buffer.getContext().renderingStats(); + stats.numVertexBuffers++; + stats.memVertexBuffers += buffer.getSizeInBytes(); } } -VertexBufferResource::~VertexBufferResource() { +VertexBufferResource::~VertexBufferResource() noexcept { if (buffer) { - buffer.getContext().renderingStats().numVertexBuffers--; - buffer.getContext().renderingStats().memVertexBuffers -= buffer.getSizeInBytes(); + auto& stats = buffer.getContext().renderingStats(); + stats.numVertexBuffers--; + stats.memVertexBuffers -= buffer.getSizeInBytes(); } } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index 65a8611a2..449a03bbe 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -377,7 +377,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, /* .weight_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), /* .radius_t = */ std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), /* .padding = */ {0}}; - interpolateBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO)); + interpolateBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO), false); } return interpolateBuffer; }; diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp index 13e6239d4..33d858179 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -87,8 +87,10 @@ SegmentVector RenderStaticData::heatmapTextureSegments void RenderStaticData::upload(gfx::UploadPass& uploadPass) { if (!uploaded) { // these are still used by stencil buffer rendering - tileVertexBuffer = uploadPass.createVertexBuffer(tileVertices()); - quadTriangleIndexBuffer = uploadPass.createIndexBuffer(quadTriangleIndices()); + tileVertexBuffer = uploadPass.createVertexBuffer( + tileVertices(), gfx::BufferUsageType::StaticDraw, /*persistent=*/false); + quadTriangleIndexBuffer = uploadPass.createIndexBuffer( + quadTriangleIndices(), gfx::BufferUsageType::StaticDraw, /*persistent=*/false); #if MLN_LEGACY_RENDERER rasterVertexBuffer = uploadPass.createVertexBuffer(rasterVertices()); heatmapTextureVertexBuffer = uploadPass.createVertexBuffer(heatmapTextureVertices());