Metal stats (#1781)

This commit is contained in:
Tim Sylvester
2023-10-20 15:45:08 -07:00
committed by GitHub
parent 07c70fe1c8
commit 1a1c826fa4
28 changed files with 347 additions and 116 deletions

View File

@@ -1216,6 +1216,7 @@ if(MBGL_WITH_METAL)
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_impl.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_builder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_builder.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/index_buffer_resource.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/layer_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/layer_group.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/mtl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/mtl.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/offscreen_texture.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/offscreen_texture.cpp
@@ -1227,6 +1228,7 @@ if(MBGL_WITH_METAL)
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/uniform_buffer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/uniform_buffer.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/upload_pass.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/upload_pass.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/vertex_attribute.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/vertex_attribute.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/mtl/vertex_buffer_resource.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program.cpp
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/background.cpp ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/background.cpp
${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/background_pattern.cpp ${PROJECT_SOURCE_DIR}src/mbgl/shaders/mtl/background_pattern.cpp

View File

@@ -895,7 +895,7 @@ MLN_OPENGL_HEADERS = [
"include/mbgl/gl/renderable_resource.hpp", "include/mbgl/gl/renderable_resource.hpp",
"include/mbgl/gl/renderer_backend.hpp", "include/mbgl/gl/renderer_backend.hpp",
"include/mbgl/layermanager/location_indicator_layer_factory.hpp", "include/mbgl/layermanager/location_indicator_layer_factory.hpp",
"include/mbgl/platform/gl_functions.hpp" "include/mbgl/platform/gl_functions.hpp",
] ]
MLN_DRAWABLES_SOURCE = [ MLN_DRAWABLES_SOURCE = [
@@ -1009,7 +1009,7 @@ MLN_DRAWABLES_GL_HEADERS = [
"include/mbgl/gl/vertex_attribute_gl.hpp", "include/mbgl/gl/vertex_attribute_gl.hpp",
"include/mbgl/gl/texture2d.hpp", "include/mbgl/gl/texture2d.hpp",
"include/mbgl/shaders/gl/shader_program_gl.hpp", "include/mbgl/shaders/gl/shader_program_gl.hpp",
"include/mbgl/shaders/gl/shader_group_gl.hpp" "include/mbgl/shaders/gl/shader_group_gl.hpp",
] ]
MLN_DRAWABLES_MTL_SOURCE = [ MLN_DRAWABLES_MTL_SOURCE = [
@@ -1019,6 +1019,7 @@ MLN_DRAWABLES_MTL_SOURCE = [
"src/mbgl/mtl/drawable.cpp", "src/mbgl/mtl/drawable.cpp",
"src/mbgl/mtl/drawable_impl.hpp", "src/mbgl/mtl/drawable_impl.hpp",
"src/mbgl/mtl/drawable_builder.cpp", "src/mbgl/mtl/drawable_builder.cpp",
"src/mbgl/mtl/index_buffer_resource.cpp",
"src/mbgl/mtl/layer_group.cpp", "src/mbgl/mtl/layer_group.cpp",
"src/mbgl/mtl/mtl.cpp", "src/mbgl/mtl/mtl.cpp",
"src/mbgl/mtl/offscreen_texture.cpp", "src/mbgl/mtl/offscreen_texture.cpp",
@@ -1030,6 +1031,7 @@ MLN_DRAWABLES_MTL_SOURCE = [
"src/mbgl/mtl/uniform_buffer.cpp", "src/mbgl/mtl/uniform_buffer.cpp",
"src/mbgl/mtl/upload_pass.cpp", "src/mbgl/mtl/upload_pass.cpp",
"src/mbgl/mtl/vertex_attribute.cpp", "src/mbgl/mtl/vertex_attribute.cpp",
"src/mbgl/mtl/vertex_buffer_resource.cpp",
"src/mbgl/shaders/mtl/shader_program.cpp", "src/mbgl/shaders/mtl/shader_program.cpp",
"src/mbgl/shaders/mtl/background.cpp", "src/mbgl/shaders/mtl/background.cpp",
"src/mbgl/shaders/mtl/background_pattern.cpp", "src/mbgl/shaders/mtl/background_pattern.cpp",

View File

@@ -1,5 +1,8 @@
#pragma once #pragma once
#include <cstddef>
#include <string>
namespace mbgl { namespace mbgl {
namespace gfx { namespace gfx {
@@ -7,38 +10,44 @@ struct RenderingStats {
RenderingStats() = default; RenderingStats() = default;
bool isZero() const; bool isZero() const;
int numDrawCalls; int numFrames = 0;
int numActiveTextures; int numDrawCalls = 0;
int numCreatedTextures; int totalDrawCalls = 0;
int numBuffers;
int numFrameBuffers;
int memTextures; int numCreatedTextures = 0;
int memIndexBuffers; int numActiveTextures = 0;
int memVertexBuffers; int numTextureBindings = 0;
int numTextureUpdates = 0;
std::size_t textureUpdateBytes = 0;
int numBuffers = 0;
int numFrameBuffers = 0;
int numIndexBuffers = 0;
std::size_t indexUpdateBytes = 0;
int numVertexBuffers = 0;
std::size_t vertexUpdateBytes = 0;
int numUniformBuffers = 0;
int numUniformUpdates = 0;
std::size_t uniformUpdateBytes = 0;
int memTextures = 0;
int memBuffers = 0;
int memIndexBuffers = 0;
int memVertexBuffers = 0;
int memUniformBuffers = 0;
int stencilClears = 0; int stencilClears = 0;
int stencilUpdates = 0; int stencilUpdates = 0;
RenderingStats& operator+=(const RenderingStats& right); RenderingStats& operator+=(const RenderingStats&);
#if !defined(NDEBUG)
std::string toString(std::string_view separator) const;
#endif
}; };
inline RenderingStats& RenderingStats::operator+=(const RenderingStats& r) {
numDrawCalls += r.numDrawCalls;
numActiveTextures += r.numActiveTextures;
numCreatedTextures += r.numCreatedTextures;
numBuffers += r.numBuffers;
numFrameBuffers += r.numFrameBuffers;
memTextures += r.memTextures;
memIndexBuffers += r.memIndexBuffers;
memVertexBuffers += r.memVertexBuffers;
stencilClears += r.stencilClears;
stencilUpdates += r.stencilUpdates;
return *this;
}
} // namespace gfx } // namespace gfx
} // namespace mbgl } // namespace mbgl

View File

@@ -22,7 +22,8 @@ class UniformBuffer {
protected: protected:
UniformBuffer(std::size_t size_) UniformBuffer(std::size_t size_)
: size(size_) {} : size(size_) {}
UniformBuffer(const UniformBuffer&) = default; UniformBuffer(const UniformBuffer& other)
: size(other.size) {}
UniformBuffer(UniformBuffer&& other) UniformBuffer(UniformBuffer&& other)
: size(other.size) {} : size(other.size) {}
@@ -32,8 +33,9 @@ public:
std::size_t getSize() const { return size; } std::size_t getSize() const { return size; }
UniformBuffer& operator=(const UniformBuffer&) = delete;
protected: protected:
UniformBuffer& operator=(const UniformBuffer&) = default;
UniformBuffer& operator=(UniformBuffer&& other) { UniformBuffer& operator=(UniformBuffer&& other) {
size = other.size; size = other.size;
return *this; return *this;

View File

@@ -7,10 +7,10 @@ namespace mbgl {
namespace gl { namespace gl {
class UniformBufferGL final : public gfx::UniformBuffer { class UniformBufferGL final : public gfx::UniformBuffer {
UniformBufferGL(const UniformBufferGL&);
public: public:
UniformBufferGL(const void* data, std::size_t size_); UniformBufferGL(const void* data, std::size_t size_);
UniformBufferGL(const UniformBufferGL& other)
: UniformBuffer(other) {}
UniformBufferGL(UniformBufferGL&& other) UniformBufferGL(UniformBufferGL&& other)
: UniformBuffer(std::move(other)) {} : UniformBuffer(std::move(other)) {}
~UniformBufferGL() override; ~UniformBufferGL() override;
@@ -18,6 +18,8 @@ public:
BufferID getID() const { return id; } BufferID getID() const { return id; }
void update(const void* data, std::size_t size_) override; void update(const void* data, std::size_t size_) override;
UniformBufferGL clone() const { return {*this}; }
protected: protected:
BufferID id = 0; BufferID id = 0;
uint32_t hash; uint32_t hash;
@@ -42,7 +44,7 @@ public:
private: private:
std::unique_ptr<gfx::UniformBuffer> copy(const gfx::UniformBuffer& uniformBuffers) override { std::unique_ptr<gfx::UniformBuffer> copy(const gfx::UniformBuffer& uniformBuffers) override {
return std::make_unique<UniformBufferGL>(static_cast<const UniformBufferGL&>(uniformBuffers)); return std::make_unique<UniformBufferGL>(static_cast<const UniformBufferGL&>(uniformBuffers).clone());
} }
}; };

View File

@@ -10,32 +10,40 @@
namespace mbgl { namespace mbgl {
namespace mtl { namespace mtl {
class Context;
class BufferResource { class BufferResource {
public: public:
BufferResource() = default; BufferResource() = delete;
/** @brief Create a new Metal buffer /** @brief Create a new Metal buffer
@param device The Metal device on which to create the 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 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 size The minimum size of the new buffer. Must be non-zero.
@param usage A `MTL::ResourceOptions` value. Currently, only `ResourceStorageModeShared` is supported. @param usage A `MTL::ResourceOptions` value. Currently, only `ResourceStorageModeShared` is supported.
*/ */
BufferResource(MTLDevicePtr device, const void* raw, std::size_t size, MTL::ResourceOptions usage); BufferResource(Context& context_, const void* raw, std::size_t size, MTL::ResourceOptions usage);
BufferResource(const BufferResource&);
BufferResource(BufferResource&&); BufferResource(BufferResource&&);
virtual ~BufferResource();
BufferResource& operator=(BufferResource&&); BufferResource& operator=(BufferResource&&);
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);
std::size_t getSizeInBytes() const { return buffer ? buffer->length() : 0; } std::size_t getSizeInBytes() const { return buffer ? buffer->length() : 0; }
void* contents() const { return buffer ? buffer->contents() : nullptr; } void* contents() const { return buffer ? buffer->contents() : nullptr; }
Context& getContext() const { return context; }
const MTLBufferPtr& getMetalBuffer() const { return buffer; } const MTLBufferPtr& getMetalBuffer() const { return buffer; }
operator bool() const { return buffer.operator bool(); } operator bool() const { return buffer.operator bool(); }
bool operator!() const { return !buffer.operator bool(); }
protected: protected:
MTLDevicePtr device; Context& context;
MTLBufferPtr buffer; MTLBufferPtr buffer;
NS::UInteger size;
NS::UInteger usage; NS::UInteger usage;
}; };

View File

@@ -44,9 +44,6 @@ public:
std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override; std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override;
gfx::RenderingStats& renderingStats() { return stats; }
const gfx::RenderingStats& renderingStats() const override { return stats; }
BufferResource createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const; BufferResource createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const;
UniqueShaderProgram createProgram(std::string name, UniqueShaderProgram createProgram(std::string name,
@@ -59,6 +56,8 @@ public:
MTLTexturePtr createMetalTexture(MTLTextureDescriptorPtr textureDescriptor) const; MTLTexturePtr createMetalTexture(MTLTextureDescriptorPtr textureDescriptor) const;
MTLSamplerStatePtr createMetalSamplerState(MTLSamplerDescriptorPtr samplerDescriptor) const; MTLSamplerStatePtr createMetalSamplerState(MTLSamplerDescriptorPtr samplerDescriptor) const;
void clear();
// Actually remove the objects we marked as abandoned with the above methods. // Actually remove the objects we marked as abandoned with the above methods.
void performCleanup() override; void performCleanup() override;
@@ -119,6 +118,9 @@ public:
/// Get a reusable buffer containing the standard fixed tile indexes /// Get a reusable buffer containing the standard fixed tile indexes
const BufferResource& getTileIndexBuffer(); const BufferResource& getTileIndexBuffer();
/// Get a buffer to be bound to unused vertex buffers
const gfx::UniqueVertexBufferResource& getEmptyVertexBuffer();
bool renderTileClippingMasks(gfx::RenderPass& renderPass, bool renderTileClippingMasks(gfx::RenderPass& renderPass,
RenderStaticData& staticData, RenderStaticData& staticData,
const std::vector<shaders::ClipUBO>& tileUBOs); const std::vector<shaders::ClipUBO>& tileUBOs);
@@ -130,14 +132,14 @@ private:
std::optional<BufferResource> tileVertexBuffer; std::optional<BufferResource> tileVertexBuffer;
std::optional<BufferResource> tileIndexBuffer; std::optional<BufferResource> tileIndexBuffer;
gfx::UniqueVertexBufferResource emptyVertexBuffer;
gfx::ShaderProgramBasePtr clipMaskShader; gfx::ShaderProgramBasePtr clipMaskShader;
MTLDepthStencilStatePtr clipMaskDepthStencilState; MTLDepthStencilStatePtr clipMaskDepthStencilState;
MTLRenderPipelineStatePtr clipMaskPipelineState; MTLRenderPipelineStatePtr clipMaskPipelineState;
BufferResource clipMaskUniformsBuffer; std::optional<BufferResource> clipMaskUniformsBuffer;
bool clipMaskUniformsBufferUsed = false; bool clipMaskUniformsBufferUsed = false;
const gfx::Renderable* stencilStateRenderable = nullptr; const gfx::Renderable* stencilStateRenderable = nullptr;
gfx::RenderingStats stats;
}; };
} // namespace mtl } // namespace mtl

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <mbgl/gfx/index_buffer.hpp>
#include <mbgl/mtl/buffer_resource.hpp> #include <mbgl/mtl/buffer_resource.hpp>
namespace mbgl { namespace mbgl {
@@ -8,10 +9,10 @@ namespace mtl {
class IndexBufferResource : public gfx::IndexBufferResource { class IndexBufferResource : public gfx::IndexBufferResource {
public: public:
IndexBufferResource() = default; IndexBufferResource() = default;
IndexBufferResource(BufferResource&& ptr) IndexBufferResource(BufferResource&&);
: buffer(std::move(ptr)) {}
IndexBufferResource(IndexBufferResource&& other) IndexBufferResource(IndexBufferResource&& other)
: buffer(std::move(other.buffer)) {} : buffer(std::move(other.buffer)) {}
~IndexBufferResource() override;
std::size_t getSizeInBytes() const { return buffer.getSizeInBytes(); } std::size_t getSizeInBytes() const { return buffer.getSizeInBytes(); }
void* contents() const { return buffer.contents(); } void* contents() const { return buffer.contents(); }

View File

@@ -9,12 +9,14 @@ namespace mtl {
class UniformBuffer final : public gfx::UniformBuffer { class UniformBuffer final : public gfx::UniformBuffer {
public: public:
UniformBuffer(BufferResource&&); UniformBuffer(BufferResource&&);
UniformBuffer(const UniformBuffer&) = default; UniformBuffer(const UniformBuffer&) = delete;
UniformBuffer(UniformBuffer&&); UniformBuffer(UniformBuffer&&);
~UniformBuffer() override = default; ~UniformBuffer() override;
const BufferResource& getBufferResource() const { return buffer; } const BufferResource& getBufferResource() const { return buffer; }
UniformBuffer clone() const { return {buffer.clone()}; }
void update(const void* data, std::size_t size_) override; void update(const void* data, std::size_t size_) override;
protected: protected:
@@ -40,7 +42,7 @@ public:
private: private:
gfx::UniqueUniformBuffer copy(const gfx::UniformBuffer& buffer) override { gfx::UniqueUniformBuffer copy(const gfx::UniformBuffer& buffer) override {
return std::make_unique<UniformBuffer>(static_cast<const UniformBuffer&>(buffer)); return std::make_unique<UniformBuffer>(static_cast<const UniformBuffer&>(buffer).clone());
} }
}; };

View File

@@ -8,10 +8,10 @@ namespace mtl {
class VertexBufferResource : public gfx::VertexBufferResource { class VertexBufferResource : public gfx::VertexBufferResource {
public: public:
VertexBufferResource() = default; VertexBufferResource() = default;
VertexBufferResource(BufferResource&& ptr) VertexBufferResource(BufferResource&&);
: buffer(std::move(ptr)) {}
VertexBufferResource(VertexBufferResource&& other) VertexBufferResource(VertexBufferResource&& other)
: buffer(std::move(other.buffer)) {} : buffer(std::move(other.buffer)) {}
~VertexBufferResource() override;
std::size_t getSizeInBytes() const { return buffer.getSizeInBytes(); } std::size_t getSizeInBytes() const { return buffer.getSizeInBytes(); }
void* contents() const { return buffer.contents(); } void* contents() const { return buffer.contents(); }

View File

@@ -103,7 +103,8 @@ protected:
public: public:
virtual std::unique_ptr<CommandEncoder> createCommandEncoder() = 0; virtual std::unique_ptr<CommandEncoder> createCommandEncoder() = 0;
virtual const RenderingStats& renderingStats() const = 0; gfx::RenderingStats& renderingStats() { return stats; }
const gfx::RenderingStats& renderingStats() const { return stats; }
#if !defined(NDEBUG) #if !defined(NDEBUG)
public: public:
@@ -156,6 +157,9 @@ public:
} }
#endif #endif
protected:
gfx::RenderingStats stats;
}; };
} // namespace gfx } // namespace gfx

View File

@@ -1,12 +1,74 @@
#include <mbgl/gfx/rendering_stats.hpp> #include <mbgl/gfx/rendering_stats.hpp>
#include <algorithm>
#include <initializer_list>
#include <sstream>
namespace mbgl { namespace mbgl {
namespace gfx { namespace gfx {
bool RenderingStats::isZero() const { bool RenderingStats::isZero() const {
return numActiveTextures == 0 && numCreatedTextures == 0 && numBuffers == 0 && numFrameBuffers == 0 && const auto expectedZeros = {numActiveTextures,
memTextures == 0 && memIndexBuffers == 0 && memVertexBuffers == 0; numTextureBindings,
numBuffers,
numVertexBuffers,
numIndexBuffers,
numUniformBuffers,
numFrameBuffers,
memTextures,
memBuffers,
memIndexBuffers,
memVertexBuffers,
memUniformBuffers};
return std::all_of(expectedZeros.begin(), expectedZeros.end(), [](auto x) { return x == 0; });
} }
RenderingStats& RenderingStats::operator+=(const RenderingStats& r) {
numFrames += r.numFrames;
numDrawCalls += r.numDrawCalls;
totalDrawCalls += r.totalDrawCalls;
numCreatedTextures += r.numCreatedTextures;
numActiveTextures += r.numActiveTextures;
numTextureBindings += r.numTextureBindings;
numTextureUpdates += r.numTextureUpdates;
textureUpdateBytes += r.textureUpdateBytes;
numBuffers += r.numBuffers;
numFrameBuffers += r.numFrameBuffers;
numIndexBuffers += r.numIndexBuffers;
indexUpdateBytes += r.indexUpdateBytes;
numVertexBuffers += r.numVertexBuffers;
vertexUpdateBytes += r.vertexUpdateBytes;
numUniformBuffers += r.numUniformBuffers;
numUniformUpdates += r.numUniformUpdates;
uniformUpdateBytes += r.uniformUpdateBytes;
memTextures += r.memTextures;
memBuffers += r.memBuffers;
memIndexBuffers += r.memIndexBuffers;
memVertexBuffers += r.memVertexBuffers;
memUniformBuffers += r.memUniformBuffers;
stencilClears += r.stencilClears;
stencilUpdates += r.stencilUpdates;
return *this;
}
#if !defined(NDEBUG)
std::string RenderingStats::toString(std::string_view sep) const {
std::stringstream ss;
ss << "numFrames = " << numFrames << sep << "numDrawCalls = " << numDrawCalls << sep
<< "totalDrawCalls = " << totalDrawCalls << sep << "numCreatedTextures = " << numCreatedTextures << sep
<< "numActiveTextures = " << numActiveTextures << sep << "numTextureBindings = " << numTextureBindings << sep
<< "numTextureUpdates = " << numTextureUpdates << sep << "textureUpdateBytes = " << textureUpdateBytes << sep
<< "numBuffers = " << numBuffers << sep << "numFrameBuffers = " << numFrameBuffers << sep
<< "numIndexBuffers = " << numIndexBuffers << sep << "indexUpdateBytes = " << indexUpdateBytes << sep
<< "numVertexBuffers = " << numVertexBuffers << sep << "vertexUpdateBytes = " << vertexUpdateBytes << sep
<< "numUniformBuffers = " << numUniformBuffers << sep << "numUniformUpdates = " << numUniformUpdates << sep
<< "uniformUpdateBytes = " << uniformUpdateBytes << sep << "memTextures = " << memTextures << sep
<< "memBuffers = " << memBuffers << sep << "memIndexBuffers = " << memIndexBuffers << sep
<< "memVertexBuffers = " << memVertexBuffers << sep << "memUniformBuffers = " << memUniformBuffers << sep
<< "stencilClears = " << stencilClears << sep << "stencilUpdates = " << stencilUpdates << sep;
return ss.str();
}
#endif
} // namespace gfx } // namespace gfx
} // namespace mbgl } // namespace mbgl

View File

@@ -63,14 +63,17 @@ static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "Ope
static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch"); static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch");
static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch"); static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch");
namespace {
GLint getMaxVertexAttribs() {
GLint value = 0;
MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value));
return value;
}
} // namespace
Context::Context(RendererBackend& backend_) Context::Context(RendererBackend& backend_)
: gfx::Context([] { : gfx::Context(/*maximumVertexBindingCount=*/getMaxVertexAttribs()),
GLint value; backend(backend_) {}
MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value));
return value;
}()),
backend(backend_),
stats() {}
Context::~Context() noexcept { Context::~Context() noexcept {
if (cleanupOnDestruction) { if (cleanupOnDestruction) {
@@ -616,14 +619,6 @@ std::unique_ptr<gfx::CommandEncoder> Context::createCommandEncoder() {
return std::make_unique<gl::CommandEncoder>(*this); return std::make_unique<gl::CommandEncoder>(*this);
} }
gfx::RenderingStats& Context::renderingStats() {
return stats;
}
const gfx::RenderingStats& Context::renderingStats() const {
return stats;
}
void Context::finish() { void Context::finish() {
MBGL_CHECK_ERROR(glFinish()); MBGL_CHECK_ERROR(glFinish());
} }

View File

@@ -44,9 +44,6 @@ public:
std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override; std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override;
gfx::RenderingStats& renderingStats();
const gfx::RenderingStats& renderingStats() const override;
void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&); void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&);
void enableDebugging(); void enableDebugging();
@@ -131,7 +128,6 @@ private:
RendererBackend& backend; RendererBackend& backend;
bool cleanupOnDestruction = true; bool cleanupOnDestruction = true;
gfx::RenderingStats stats;
std::unique_ptr<extension::Debugging> debugging; std::unique_ptr<extension::Debugging> debugging;
public: public:

View File

@@ -20,6 +20,16 @@ UniformBufferGL::UniformBufferGL(const void* data_, std::size_t size_)
MBGL_CHECK_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, 0)); MBGL_CHECK_ERROR(glBindBuffer(GL_UNIFORM_BUFFER, 0));
} }
UniformBufferGL::UniformBufferGL(const UniformBufferGL& other)
: UniformBuffer(other),
hash(other.hash) {
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
MBGL_CHECK_ERROR(glCopyBufferSubData(other.id, id, 0, 0, size));
MBGL_CHECK_ERROR(glBindBuffer(GL_COPY_READ_BUFFER, other.id));
MBGL_CHECK_ERROR(glBindBuffer(GL_COPY_WRITE_BUFFER, id));
MBGL_CHECK_ERROR(glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size));
}
UniformBufferGL::~UniformBufferGL() { UniformBufferGL::~UniformBufferGL() {
if (id) { if (id) {
MBGL_CHECK_ERROR(glDeleteBuffers(1, &id)); MBGL_CHECK_ERROR(glDeleteBuffers(1, &id));

View File

@@ -1,37 +1,52 @@
#include <mbgl/mtl/buffer_resource.hpp> #include <mbgl/mtl/buffer_resource.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/mtl/renderer_backend.hpp>
#include <Metal/MTLDevice.hpp> #include <Metal/MTLDevice.hpp>
#include <algorithm> #include <algorithm>
namespace mbgl { namespace mbgl {
namespace mtl { namespace mtl {
BufferResource::BufferResource(MTLDevicePtr device_, const void* data, std::size_t size, MTL::ResourceOptions usage_) BufferResource::BufferResource(Context& context_, const void* data, std::size_t size_, MTL::ResourceOptions usage_)
: device(std::move(device_)), : context(context_),
size(static_cast<NS::UInteger>(size_)),
usage(usage_) { usage(usage_) {
if (data && size) { auto& device = context.getBackend().getDevice();
buffer = NS::TransferPtr(device->newBuffer(data, static_cast<NS::UInteger>(size), usage)); buffer = NS::TransferPtr((data && size) ? device->newBuffer(data, size, usage) : device->newBuffer(size, usage));
} else { if (buffer) {
buffer = NS::TransferPtr(device->newBuffer(static_cast<NS::UInteger>(size), usage)); context.renderingStats().numBuffers++;
} context.renderingStats().memBuffers += size;
}
BufferResource::BufferResource(const BufferResource& other)
: device(other.device),
usage(other.usage) {
if (other.buffer) {
buffer = NS::TransferPtr(device->newBuffer(other.buffer->contents(), other.buffer->length(), other.usage));
} }
} }
BufferResource::BufferResource(BufferResource&& other) BufferResource::BufferResource(BufferResource&& other)
: device(std::move(other.device)), : context(other.context),
buffer(std::move(other.buffer)), buffer(std::move(other.buffer)),
size(other.size),
usage(other.usage) {} usage(other.usage) {}
BufferResource::~BufferResource() {
if (buffer) {
context.renderingStats().numBuffers--;
context.renderingStats().memBuffers -= size;
}
}
BufferResource BufferResource::clone() const {
return {context, buffer->contents(), size, usage};
}
BufferResource& BufferResource::operator=(BufferResource&& other) { BufferResource& BufferResource::operator=(BufferResource&& other) {
device = std::move(other.device); assert(&context == &other.context);
if (buffer) {
context.renderingStats().numBuffers--;
context.renderingStats().memBuffers -= size;
}
buffer = std::move(other.buffer); buffer = std::move(other.buffer);
size = other.size;
usage = other.usage; usage = other.usage;
return *this; return *this;
} }

View File

@@ -12,6 +12,7 @@
#include <mbgl/mtl/render_pass.hpp> #include <mbgl/mtl/render_pass.hpp>
#include <mbgl/mtl/uniform_buffer.hpp> #include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/upload_pass.hpp> #include <mbgl/mtl/upload_pass.hpp>
#include <mbgl/mtl/vertex_buffer_resource.hpp>
#include <mbgl/programs/program_parameters.hpp> #include <mbgl/programs/program_parameters.hpp>
#include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_static_data.hpp> #include <mbgl/renderer/render_static_data.hpp>
@@ -37,12 +38,24 @@ constexpr uint32_t maximumVertexBindingCount = 31;
Context::Context(RendererBackend& backend_) Context::Context(RendererBackend& backend_)
: gfx::Context(mtl::maximumVertexBindingCount), : gfx::Context(mtl::maximumVertexBindingCount),
backend(backend_), backend(backend_) {}
stats() {}
Context::~Context() noexcept { Context::~Context() noexcept {
if (cleanupOnDestruction) { if (cleanupOnDestruction) {
performCleanup(); performCleanup();
emptyVertexBuffer.reset();
tileVertexBuffer.reset();
tileIndexBuffer.reset();
clipMaskShader.reset();
clipMaskDepthStencilState.reset();
clipMaskPipelineState.reset();
clipMaskUniformsBuffer.reset();
stencilStateRenderable = nullptr;
#if !defined(NDEBUG)
Log::Debug(Event::General, "Rendering Stats:\n" + stats.toString("\n"));
#endif
assert(stats.isZero()); assert(stats.isZero());
} }
} }
@@ -52,7 +65,7 @@ std::unique_ptr<gfx::CommandEncoder> Context::createCommandEncoder() {
} }
BufferResource Context::createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const { BufferResource Context::createBuffer(const void* data, std::size_t size, gfx::BufferUsageType) const {
return {backend.getDevice(), data, size, MTL::ResourceStorageModeShared}; return {const_cast<Context&>(*this), data, size, MTL::ResourceStorageModeShared};
} }
UniqueShaderProgram Context::createProgram(std::string name, UniqueShaderProgram Context::createProgram(std::string name,
@@ -144,6 +157,11 @@ MTLSamplerStatePtr Context::createMetalSamplerState(MTLSamplerDescriptorPtr samp
return NS::TransferPtr(backend.getDevice()->newSamplerState(samplerDescriptor.get())); return NS::TransferPtr(backend.getDevice()->newSamplerState(samplerDescriptor.get()));
} }
void Context::clear() {
stats.numDrawCalls = 0;
stats.numFrames++;
}
void Context::performCleanup() { void Context::performCleanup() {
clipMaskUniformsBufferUsed = false; clipMaskUniformsBufferUsed = false;
} }
@@ -207,6 +225,20 @@ const BufferResource& Context::getTileIndexBuffer() {
return *tileIndexBuffer; return *tileIndexBuffer;
} }
const gfx::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.
// This buffer could also hold a single default value applied for all vertices, in which case
// it could not be shared (See `MTL::VertexStepFunctionConstant` in the vertex attribute
// 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));
}
return emptyVertexBuffer;
}
namespace { namespace {
const auto clipMaskStencilMode = gfx::StencilMode{ const auto clipMaskStencilMode = gfx::StencilMode{
/*.test=*/gfx::StencilMode::Always(), /*.test=*/gfx::StencilMode::Always(),
@@ -316,16 +348,16 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
constexpr auto uboSize = sizeof(shaders::ClipUBO); constexpr auto uboSize = sizeof(shaders::ClipUBO);
const auto bufferSize = tileUBOs.size() * uboSize; const auto bufferSize = tileUBOs.size() * uboSize;
BufferResource tempBuffer; std::optional<BufferResource> tempBuffer;
auto& uboBuffer = clipMaskUniformsBufferUsed ? tempBuffer : clipMaskUniformsBuffer; auto& uboBuffer = clipMaskUniformsBufferUsed ? tempBuffer : clipMaskUniformsBuffer;
clipMaskUniformsBufferUsed = true; clipMaskUniformsBufferUsed = true;
if (!uboBuffer || uboBuffer.getSizeInBytes() < bufferSize) { if (!uboBuffer || !*uboBuffer || uboBuffer->getSizeInBytes() < bufferSize) {
uboBuffer = createBuffer(tileUBOs.data(), bufferSize, gfx::BufferUsageType::StaticDraw); uboBuffer = createBuffer(tileUBOs.data(), bufferSize, gfx::BufferUsageType::StaticDraw);
if (!uboBuffer) { if (!uboBuffer) {
return false; return false;
} }
} else { } else {
uboBuffer.update(tileUBOs.data(), bufferSize, /*offset=*/0); uboBuffer->update(tileUBOs.data(), bufferSize, /*offset=*/0);
} }
encoder->setCullMode(MTL::CullModeNone); encoder->setCullMode(MTL::CullModeNone);
@@ -350,7 +382,7 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
for (std::size_t ii = 0; ii < tileUBOs.size(); ++ii) { for (std::size_t ii = 0; ii < tileUBOs.size(); ++ii) {
encoder->setStencilReferenceValue(tileUBOs[ii].stencil_ref); encoder->setStencilReferenceValue(tileUBOs[ii].stencil_ref);
encoder->setVertexBuffer( encoder->setVertexBuffer(
uboBuffer.getMetalBuffer().get(), /*offset=*/ii * uboSize, ShaderClass::uniforms[0].index); uboBuffer->getMetalBuffer().get(), /*offset=*/ii * uboSize, ShaderClass::uniforms[0].index);
encoder->drawIndexedPrimitives(MTL::PrimitiveType::PrimitiveTypeTriangle, encoder->drawIndexedPrimitives(MTL::PrimitiveType::PrimitiveTypeTriangle,
indexCount, indexCount,
MTL::IndexType::IndexTypeUInt16, MTL::IndexType::IndexTypeUInt16,
@@ -362,6 +394,8 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
} }
#endif #endif
stats.numDrawCalls++;
stats.totalDrawCalls++;
return true; return true;
} }

View File

@@ -157,7 +157,7 @@ void Drawable::draw(PaintParameters& parameters) const {
return; return;
} }
const auto& context = static_cast<Context&>(parameters.context); auto& context = static_cast<Context&>(parameters.context);
const auto& renderPass = static_cast<RenderPass&>(*parameters.renderPass); const auto& renderPass = static_cast<RenderPass&>(*parameters.renderPass);
const auto& encoder = renderPass.getMetalEncoder(); const auto& encoder = renderPass.getMetalEncoder();
if (!encoder) { if (!encoder) {
@@ -289,8 +289,8 @@ void Drawable::draw(PaintParameters& parameters) const {
if (binding) { if (binding) {
if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) { if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) {
assert((maxIndex + mlSegment.vertexOffset) * binding->vertexStride <= buffer->length()); assert((maxIndex + mlSegment.vertexOffset) * binding->vertexStride <= buffer->length());
} else if (const auto buffer = getMetalBuffer(impl->noBindingBuffer.get())) { } else if (impl->noBindingBuffer) {
assert(binding->vertexStride <= buffer->length()); assert(binding->vertexStride <= impl->noBindingBuffer->length());
} }
} }
} }
@@ -304,6 +304,7 @@ void Drawable::draw(PaintParameters& parameters) const {
instanceCount, instanceCount,
baseVertex, baseVertex,
baseInstance); baseInstance);
context.renderingStats().numDrawCalls++;
} }
} }
@@ -371,8 +372,8 @@ void Drawable::bindAttributes(const RenderPass& renderPass) const {
if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) { if (const auto buffer = getMetalBuffer(binding ? binding->vertexBufferResource : nullptr)) {
assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource)); assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource));
encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex); encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex);
} else if (const auto buffer = getMetalBuffer(impl->noBindingBuffer.get())) { } else if (impl->noBindingBuffer) {
encoder->setVertexBuffer(buffer, /*offset=*/0, attributeIndex); encoder->setVertexBuffer(impl->noBindingBuffer, /*offset=*/0, attributeIndex);
} }
attributeIndex += 1; attributeIndex += 1;
} }
@@ -593,8 +594,9 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
} }
if (!binding->vertexBufferResource && !impl->noBindingBuffer) { if (!binding->vertexBufferResource && !impl->noBindingBuffer) {
impl->noBindingBuffer = uploadPass.createVertexBufferResource( if (const auto& buf = context.getEmptyVertexBuffer()) {
nullptr, 64, gfx::BufferUsageType::StaticDraw); impl->noBindingBuffer = getMetalBuffer(buf.get());
}
} }
auto attribDesc = NS::TransferPtr(MTL::VertexAttributeDescriptor::alloc()->init()); auto attribDesc = NS::TransferPtr(MTL::VertexAttributeDescriptor::alloc()->init());

View File

@@ -55,7 +55,7 @@ public:
// GLfloat pointSize = 0.0f; // GLfloat pointSize = 0.0f;
StringIdentity idVertexAttrName = stringIndexer().get("a_pos"); StringIdentity idVertexAttrName = stringIndexer().get("a_pos");
gfx::UniqueVertexBufferResource noBindingBuffer; MTL::Buffer* noBindingBuffer = nullptr;
gfx::AttributeBindingArray attributeBindings; gfx::AttributeBindingArray attributeBindings;

View File

@@ -0,0 +1,24 @@
#include <mbgl/mtl/index_buffer_resource.hpp>
#include <mbgl/mtl/context.hpp>
namespace mbgl {
namespace mtl {
IndexBufferResource::IndexBufferResource(BufferResource&& ptr)
: buffer(std::move(ptr)) {
if (buffer) {
buffer.getContext().renderingStats().numIndexBuffers++;
buffer.getContext().renderingStats().memIndexBuffers += buffer.getSizeInBytes();
}
}
IndexBufferResource::~IndexBufferResource() {
if (buffer) {
buffer.getContext().renderingStats().numIndexBuffers--;
buffer.getContext().renderingStats().memIndexBuffers -= buffer.getSizeInBytes();
}
}
} // namespace mtl
} // namespace mbgl

View File

@@ -44,9 +44,10 @@ public:
static_cast<Texture2D*>(stencilTexture.get()) static_cast<Texture2D*>(stencilTexture.get())
->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite | MTL::TextureUsageRenderTarget); ->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite | MTL::TextureUsageRenderTarget);
} }
context.renderingStats().numFrameBuffers++;
} }
~OffscreenTextureResource() noexcept override = default; ~OffscreenTextureResource() noexcept override { context.renderingStats().numFrameBuffers--; }
void bind() override { void bind() override {
assert(context.getBackend().getCommandQueue()); assert(context.getBackend().getCommandQueue());

View File

@@ -47,6 +47,8 @@ RenderPass::RenderPass(CommandEncoder& commandEncoder_, const char* name, const
// Let the encoder pass along any groups pushed to it after this // Let the encoder pass along any groups pushed to it after this
commandEncoder.trackRenderPass(this); commandEncoder.trackRenderPass(this);
commandEncoder.context.clear();
} }
RenderPass::~RenderPass() { RenderPass::~RenderPass() {

View File

@@ -13,7 +13,12 @@ namespace mtl {
Texture2D::Texture2D(Context& context_) Texture2D::Texture2D(Context& context_)
: context(context_) {} : context(context_) {}
Texture2D::~Texture2D() {} Texture2D::~Texture2D() {
if (metalTexture) {
context.renderingStats().numActiveTextures--;
context.renderingStats().memTextures -= getDataSize();
}
}
gfx::Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_) noexcept { gfx::Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_) noexcept {
samplerState = samplerState_; samplerState = samplerState_;
@@ -138,6 +143,8 @@ void Texture2D::createMetalTexture() noexcept {
if (metalTexture) { if (metalTexture) {
textureDirty = false; textureDirty = false;
context.renderingStats().numCreatedTextures++;
context.renderingStats().numActiveTextures++;
context.renderingStats().memTextures += getDataSize(); context.renderingStats().memTextures += getDataSize();
} }
} }
@@ -190,12 +197,16 @@ void Texture2D::bind(const RenderPass& renderPass, int32_t location) noexcept {
encoder->setFragmentTexture(metalTexture.get(), location); encoder->setFragmentTexture(metalTexture.get(), location);
encoder->setFragmentSamplerState(metalSamplerState.get(), location); encoder->setFragmentSamplerState(metalSamplerState.get(), location);
context.renderingStats().numTextureBindings++;
} }
void Texture2D::unbind(const RenderPass& renderPass, int32_t location) noexcept { void Texture2D::unbind(const RenderPass& renderPass, int32_t location) noexcept {
const auto& encoder = renderPass.getMetalEncoder(); const auto& encoder = renderPass.getMetalEncoder();
encoder->setFragmentTexture(nullptr, location); encoder->setFragmentTexture(nullptr, location);
encoder->setFragmentSamplerState(nullptr, location); encoder->setFragmentSamplerState(nullptr, location);
context.renderingStats().numTextureBindings--;
} }
void Texture2D::upload(const void* pixelData, const Size& size_) noexcept { void Texture2D::upload(const void* pixelData, const Size& size_) noexcept {
@@ -215,9 +226,11 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16
assert(metalTexture.get()); assert(metalTexture.get());
assert(!textureDirty); assert(!textureDirty);
MTL::Region region = MTL::Region::Make2D(xOffset, yOffset, size_.width, size_.height); const MTL::Region region = MTL::Region::Make2D(xOffset, yOffset, size_.width, size_.height);
NS::UInteger bytesPerRow = size_.width * getPixelStride(); const NS::UInteger bytesPerRow = size_.width * getPixelStride();
metalTexture->replaceRegion(region, 0, pixelData, bytesPerRow); metalTexture->replaceRegion(region, 0, pixelData, bytesPerRow);
context.renderingStats().numTextureUpdates++;
context.renderingStats().textureUpdateBytes += bytesPerRow * size_.height;
} }
void Texture2D::upload() noexcept { void Texture2D::upload() noexcept {

View File

@@ -1,5 +1,6 @@
#include <mbgl/mtl/uniform_buffer.hpp> #include <mbgl/mtl/uniform_buffer.hpp>
#include <mbgl/mtl/context.hpp>
#include <mbgl/util/logging.hpp> #include <mbgl/util/logging.hpp>
#include <cassert> #include <cassert>
@@ -9,11 +10,20 @@ namespace mtl {
UniformBuffer::UniformBuffer(BufferResource&& buffer_) UniformBuffer::UniformBuffer(BufferResource&& buffer_)
: gfx::UniformBuffer(buffer_.getSizeInBytes()), : gfx::UniformBuffer(buffer_.getSizeInBytes()),
buffer(std::move(buffer_)) {} buffer(std::move(buffer_)) {
buffer.getContext().renderingStats().numUniformBuffers++;
buffer.getContext().renderingStats().memUniformBuffers += size;
}
UniformBuffer::UniformBuffer(UniformBuffer&& other) UniformBuffer::UniformBuffer(UniformBuffer&& other)
: gfx::UniformBuffer(std::move(other)), : gfx::UniformBuffer(std::move(other)),
buffer(std::move(other.buffer)) {} buffer(std::move(other.buffer)) {}
UniformBuffer::~UniformBuffer() {
buffer.getContext().renderingStats().numUniformBuffers--;
buffer.getContext().renderingStats().memUniformBuffers -= size;
}
void UniformBuffer::update(const void* data, std::size_t size_) { void UniformBuffer::update(const void* data, std::size_t size_) {
assert(size == size_); assert(size == size_);
if (size != size_ || size != buffer.getSizeInBytes()) { if (size != size_ || size != buffer.getSizeInBytes()) {
@@ -23,6 +33,8 @@ void UniformBuffer::update(const void* data, std::size_t size_) {
return; return;
} }
buffer.getContext().renderingStats().numUniformUpdates++;
buffer.getContext().renderingStats().uniformUpdateBytes += size_;
buffer.update(data, size, /*offset=*/0); buffer.update(data, size, /*offset=*/0);
} }

View File

@@ -0,0 +1,24 @@
#include <mbgl/mtl/vertex_buffer_resource.hpp>
#include <mbgl/mtl/context.hpp>
namespace mbgl {
namespace mtl {
VertexBufferResource::VertexBufferResource(BufferResource&& ptr)
: buffer(std::move(ptr)) {
if (buffer) {
buffer.getContext().renderingStats().numVertexBuffers++;
buffer.getContext().renderingStats().memVertexBuffers += buffer.getSizeInBytes();
}
}
VertexBufferResource::~VertexBufferResource() {
if (buffer) {
buffer.getContext().renderingStats().numVertexBuffers--;
buffer.getContext().renderingStats().memVertexBuffers -= buffer.getSizeInBytes();
}
}
} // namespace mtl
} // namespace mbgl

View File

@@ -158,6 +158,7 @@ void PaintParameters::clearStencil() {
0, 0,
0}}; 0}};
mtlContext.renderTileClippingMasks(*renderPass, staticData, tileUBO); mtlContext.renderTileClippingMasks(*renderPass, staticData, tileUBO);
context.renderingStats().stencilClears++;
#else // !MLN_RENDER_BACKEND_METAL #else // !MLN_RENDER_BACKEND_METAL
context.clearStencilBuffer(0b00000000); context.clearStencilBuffer(0b00000000);
#endif #endif
@@ -231,6 +232,8 @@ void PaintParameters::renderTileClippingMasks(TIter beg, TIter end, GetTileIDFun
auto& mtlContext = static_cast<mtl::Context&>(context); auto& mtlContext = static_cast<mtl::Context&>(context);
mtlContext.renderTileClippingMasks(*renderPass, staticData, tileUBOs); mtlContext.renderTileClippingMasks(*renderPass, staticData, tileUBOs);
mtlContext.renderingStats().stencilUpdates++;
} }
#else // !MLN_RENDER_BACKEND_METAL #else // !MLN_RENDER_BACKEND_METAL

View File

@@ -136,7 +136,7 @@ RenderOrchestrator::~RenderOrchestrator() {
layer.markContextDestroyed(); layer.markContextDestroyed();
} }
} }
}; }
void RenderOrchestrator::setObserver(RendererObserver* observer_) { void RenderOrchestrator::setObserver(RendererObserver* observer_) {
observer = observer_ ? observer_ : &nullObserver(); observer = observer_ ? observer_ : &nullObserver();

View File

@@ -34,6 +34,7 @@
#include <mbgl/util/color.hpp> #include <mbgl/util/color.hpp>
#include <mbgl/util/image.hpp> #include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp> #include <mbgl/util/io.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/run_loop.hpp> #include <mbgl/util/run_loop.hpp>
#include <atomic> #include <atomic>
@@ -1607,6 +1608,7 @@ TEST(Map, StencilOverflow) {
const auto& backend = test.frontend.getBackend(); const auto& backend = test.frontend.getBackend();
gfx::BackendScope scope{*backend}; gfx::BackendScope scope{*backend};
const auto& context = backend->getContext();
auto& style = test.map.getStyle(); auto& style = test.map.getStyle();
style.loadJSON("{}"); style.loadJSON("{}");
@@ -1628,13 +1630,15 @@ TEST(Map, StencilOverflow) {
test.frontend.render(test.map); test.frontend.render(test.map);
// In drawable builds, no drawables are built because no bucket/tiledata is available. // In drawable builds, no drawables are built because no bucket/tiledata is available.
#if !MLN_DRAWABLE_RENDERER #if MLN_DRAWABLE_RENDERER
// TODO: Collect stats on Metal context ASSERT_LE(0, context.renderingStats().stencilUpdates);
#if MLN_RENDER_BACKEND_OPENGL #else
const auto& context = static_cast<const gl::Context&>(backend->getContext());
ASSERT_LT(0, context.renderingStats().stencilClears); ASSERT_LT(0, context.renderingStats().stencilClears);
#endif // MLN_RENDER_BACKEND_OPENGL #endif // MLN_DRAWABLE_RENDERER
#endif // !MLN_DRAWABLE_RENDERER
#if !defined(NDEBUG)
Log::Info(Event::General, context.renderingStats().toString("\n"));
#endif // !defined(NDEBUG)
// TODO: confirm that the stencil masking actually worked // TODO: confirm that the stencil masking actually worked
} }