Refactor bindings to allow for eliminating duplicates... (#1831)

Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
Tim Sylvester
2023-11-06 10:12:34 -08:00
committed by GitHub
parent 1670b2c3ee
commit ef69472f56
29 changed files with 441 additions and 244 deletions

View File

@@ -68,13 +68,18 @@ public:
std::shared_ptr<UniformBuffer> uniformBuffer);
/// Create and add a new buffer or update an existing one
void createOrUpdate(const StringIdentity id, const std::vector<uint8_t>& 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<uint8_t>& data,
gfx::Context&,
bool persistent = false);
void createOrUpdate(
const StringIdentity id, const void* data, std::size_t size, gfx::Context&, bool persistent = false);
template <typename T>
std::enable_if_t<!std::is_pointer_v<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&&);

View File

@@ -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<std::uint8_t> raw;
NS::UInteger size;
NS::UInteger usage;
std::uint16_t version = 0;
bool isIndexBuffer;
bool persistent;
};
} // namespace mtl

View File

@@ -30,8 +30,10 @@ namespace mtl {
class RenderPass;
class RendererBackend;
class ShaderProgram;
class VertexBufferResource;
using UniqueShaderProgram = std::unique_ptr<ShaderProgram>;
using UniqueVertexBufferResource = std::unique_ptr<VertexBufferResource>;
class Context final : public gfx::Context {
public:
@@ -44,7 +46,15 @@ public:
std::unique_ptr<gfx::CommandEncoder> 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<gfx::DrawScopeResource> createDrawScopeResource() override;
/*
UniqueFramebuffer createFramebuffer();
std::unique_ptr<uint8_t[]> 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<BufferResource> tileVertexBuffer;
std::optional<BufferResource> tileIndexBuffer;
gfx::UniqueVertexBufferResource emptyVertexBuffer;
UniqueVertexBufferResource emptyVertexBuffer;
gfx::ShaderProgramBasePtr clipMaskShader;
MTLDepthStencilStatePtr clipMaskDepthStencilState;

View File

@@ -66,16 +66,16 @@ protected:
// For testing only.
Drawable(std::unique_ptr<Impl>);
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> impl;

View File

@@ -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;

View File

@@ -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<gfx::DebugGroup<gfx::RenderPass>> debugGroups;
struct BindInfo {
const BufferResource* buf = nullptr;
NS::UInteger offset = 0;
std::uint16_t version = 0;
};
static constexpr auto maxBinds = 32;
std::array<std::optional<BindInfo>, maxBinds> vertexBinds;
std::array<std::optional<BindInfo>, maxBinds> fragmentBinds;
};
} // namespace mtl

View File

@@ -44,12 +44,14 @@ public:
std::unique_ptr<gfx::VertexBufferResource> 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<gfx::IndexBufferResource> 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);

View File

@@ -2,26 +2,30 @@
#include <mbgl/mtl/buffer_resource.hpp>
#include <memory>
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<VertexBufferResource>;
} // namespace mtl
} // namespace mbgl

View File

@@ -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 <typename T>
std::enable_if_t<!std::is_pointer_v<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

View File

@@ -8,10 +8,10 @@ namespace gfx {
class IndexBufferResource {
protected:
IndexBufferResource() = default;
IndexBufferResource() noexcept = default;
public:
virtual ~IndexBufferResource() = default;
virtual ~IndexBufferResource() noexcept = default;
};
class IndexBuffer {

View File

@@ -37,18 +37,17 @@ const std::shared_ptr<UniformBuffer>& UniformBufferArray::addOrReplace(const Str
void UniformBufferArray::createOrUpdate(const StringIdentity id,
const std::vector<uint8_t>& 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));
}
}

View File

@@ -54,8 +54,9 @@ public:
public:
template <class Vertex>
VertexBuffer<Vertex> createVertexBuffer(const VertexVector<Vertex>& 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 <class Vertex>
@@ -66,8 +67,9 @@ public:
template <class DrawMode>
IndexBuffer createIndexBuffer(IndexVector<DrawMode>&& 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 <class DrawMode>
@@ -91,13 +93,15 @@ public:
protected:
virtual std::unique_ptr<VertexBufferResource> 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<IndexBufferResource> 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:

View File

@@ -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<VertexBufferResource>;

View File

@@ -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<gl::DrawableGLBuilder>(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<gl::UniformBufferGL>(data, size);
}

View File

@@ -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;

View File

@@ -29,7 +29,8 @@ UploadPass::UploadPass(gl::CommandEncoder& commandEncoder_, const char* name)
std::unique_ptr<gfx::VertexBufferResource> 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<gfx::IndexBufferResource> 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<VertexBufferGL>();
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<VertexBufferGL*>(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) {

View File

@@ -35,11 +35,14 @@ public:
std::unique_ptr<gfx::VertexBufferResource> 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<gfx::IndexBufferResource> 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

View File

@@ -4,62 +4,158 @@
#include <mbgl/mtl/renderer_backend.hpp>
#include <Metal/MTLDevice.hpp>
#include <Metal/MTLRenderCommandEncoder.hpp>
#include <algorithm>
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<NS::UInteger>(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<const std::uint8_t*>(data), static_cast<const std::uint8_t*>(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<std::size_t>(buffer->length()) - offset);
assert(size == size_);
std::memcpy(static_cast<uint8_t*>(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<uint8_t*>(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<NS::UInteger>(offset), static_cast<NS::UInteger>(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<NS::UInteger>(offset), static_cast<NS::UInteger>(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_);
}
}

View File

@@ -64,8 +64,9 @@ std::unique_ptr<gfx::CommandEncoder> Context::createCommandEncoder() {
return std::make_unique<CommandEncoder>(*this);
}
BufferResource Context::createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const {
return {const_cast<Context&>(*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<Context&>(*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<DrawableBuilder>(std::move(name));
}
gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size) {
return std::make_shared<UniformBuffer>(createBuffer(data, size, gfx::BufferUsageType::StaticDraw));
gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size, bool persistent) {
return std::make_shared<UniformBuffer>(
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<VertexBufferResource>(createBuffer(nullptr, size, usage));
emptyVertexBuffer = std::make_unique<VertexBufferResource>(
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<const mtl::ShaderProgram&>(*clipMaskShader);
const auto& mtlRenderPass = static_cast<mtl::RenderPass&>(renderPass);
auto& mtlRenderPass = static_cast<mtl::RenderPass&>(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,

View File

@@ -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<const VertexBufferResource*>(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<const VertexBufferResource*>(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<const IndexBuffer*>(buf0)->buffer.get()) {
const auto& buf2 = buf1->getResource<IndexBufferResource>().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<Context&>(parameters.context);
const auto& renderPass = static_cast<RenderPass&>(*parameters.renderPass);
auto& renderPass = static_cast<RenderPass&>(*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<std::size_t>(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<const mtl::VertexBufferResource*>(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<const ShaderProgram&>(*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()) : "<no tile>";
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&>(*uniformBuffer.get());
const auto& resource = buffer.getBufferResource();
const auto& block = static_cast<const UniformBlock&>(*element.second);
const auto index = block.getIndex();
const auto& buffer = static_cast<UniformBuffer&>(*uniformBuffer.get());
const auto& bufferMTL = buffer.getBufferResource().getMetalBuffer().get();
const auto& block = static_cast<const UniformBlock&>(*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<const ShaderProgram&>(*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<mtl::Texture2D>(tex)->bind(renderPass, location);
static_cast<mtl::Texture2D&>(*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<mtl::Texture2D>(tex)->unbind(renderPass, location);
static_cast<mtl::Texture2D&>(*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<mtl::Texture2D>(tex)->upload();
static_cast<mtl::Texture2D&>(*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<gfx::IndexBuffer>(impl->indexes->elements(),
std::move(indexBufferResource));
auto buffer = std::make_unique<IndexBuffer>(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

View File

@@ -11,6 +11,7 @@
#include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/mtl/vertex_buffer_resource.hpp>
#include <mbgl/programs/segment.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/util/mat4.hpp>
@@ -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;

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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--;
}

View File

@@ -60,8 +60,10 @@ void UploadPass::endEncoding() {
std::unique_ptr<gfx::VertexBufferResource> UploadPass::createVertexBufferResource(const void* data,
const std::size_t size,
const gfx::BufferUsageType usage) {
return std::make_unique<VertexBufferResource>(commandEncoder.context.createBuffer(data, size, usage));
const gfx::BufferUsageType usage,
bool persistent) {
return std::make_unique<VertexBufferResource>(
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<gfx::IndexBufferResource> UploadPass::createIndexBufferResource(const void* data,
const std::size_t size,
const gfx::BufferUsageType usage) {
return std::make_unique<IndexBufferResource>(commandEncoder.context.createBuffer(data, size, usage));
const gfx::BufferUsageType usage,
bool persistent) {
return std::make_unique<IndexBufferResource>(
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<VertexBuffer>();
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<VertexBuffer*>(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) {

View File

@@ -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 {

View File

@@ -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();
}
}

View File

@@ -377,7 +377,7 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders,
/* .weight_t = */ std::get<0>(paintPropertyBinders.get<HeatmapWeight>()->interpolationFactor(zoom)),
/* .radius_t = */ std::get<0>(paintPropertyBinders.get<HeatmapRadius>()->interpolationFactor(zoom)),
/* .padding = */ {0}};
interpolateBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO));
interpolateBuffer = context.createUniformBuffer(&interpolateUBO, sizeof(interpolateUBO), false);
}
return interpolateBuffer;
};

View File

@@ -87,8 +87,10 @@ SegmentVector<HeatmapTextureAttributes> 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());