Make rendering stats thread safe [Core feature] (#4059)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Adrian Cojocaru <adrian.cojocaru92@yahoo.com>
Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
Alex Cristici
2026-01-21 02:49:45 +02:00
committed by GitHub
parent 4fab83669a
commit a8622a3a4f
5 changed files with 65 additions and 34 deletions

View File

@@ -13,6 +13,8 @@
#include <memory>
#include <string>
#include <mutex>
#include <shared_mutex>
namespace mbgl {
@@ -93,6 +95,16 @@ public:
gfx::RenderingStats& renderingStats() { return stats; }
const gfx::RenderingStats& renderingStats() const { return stats; }
void threadSafeAccessRenderingStats(const std::function<void(RenderingStats&)>& function) {
std::scoped_lock lock(renderingStatsMutex);
function(stats);
}
RenderingStats threadSafeCopyRenderingStats() {
std::shared_lock lock(renderingStatsMutex);
return stats;
}
#ifndef NDEBUG
virtual void visualizeStencilBuffer() = 0;
virtual void visualizeDepthBuffer(float depthRangeSize) = 0;
@@ -174,6 +186,7 @@ protected:
virtual std::unique_ptr<RenderbufferResource> createRenderbufferResource(RenderbufferPixelType, Size) = 0;
virtual std::unique_ptr<DrawScopeResource> createDrawScopeResource() = 0;
std::shared_mutex renderingStatsMutex;
gfx::RenderingStats stats;
ContextObserver* observer;
};

View File

@@ -184,9 +184,11 @@ void Texture2D::createMetalTexture() noexcept {
if (metalTexture) {
textureDirty = false;
context.renderingStats().numCreatedTextures++;
context.renderingStats().numActiveTextures++;
context.renderingStats().memTextures += getDataSize();
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numCreatedTextures++;
stats.numActiveTextures++;
stats.memTextures += getDataSize();
});
}
}
@@ -205,8 +207,10 @@ void Texture2D::destroyMetalTexture() noexcept {
}
metalTexture.reset();
context.renderingStats().numActiveTextures--;
context.renderingStats().memTextures -= getDataSize();
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numActiveTextures--;
stats.memTextures -= getDataSize();
});
}
gfx::Texture2D& Texture2D::setUsage(MTL::TextureUsage usage_) noexcept {
@@ -250,11 +254,11 @@ void Texture2D::bind(RenderPass& renderPass, int32_t location) noexcept {
renderPass.setFragmentTexture(metalTexture, location);
renderPass.setFragmentSamplerState(metalSamplerState, location);
context.renderingStats().numTextureBindings++;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) { stats.numTextureBindings++; });
}
void Texture2D::unbind(RenderPass&, int32_t /*location*/) noexcept {
context.renderingStats().numTextureBindings--;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) { stats.numTextureBindings--; });
}
void Texture2D::upload(const void* pixelData, const Size& size_) noexcept {
@@ -277,8 +281,10 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16
const MTL::Region region = MTL::Region::Make2D(xOffset, yOffset, size_.width, size_.height);
const NS::UInteger bytesPerRow = size_.width * getPixelStride();
metalTexture->replaceRegion(region, 0, pixelData, bytesPerRow);
context.renderingStats().numTextureUpdates++;
context.renderingStats().textureUpdateBytes += bytesPerRow * size_.height;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numTextureUpdates++;
stats.textureUpdateBytes += bytesPerRow * size_.height;
});
}
void Texture2D::upload() noexcept {

View File

@@ -468,7 +468,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr<
renderTreeParameters.loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
renderTreeParameters.needsRepaint,
renderTreeParameters.placementChanged,
context.renderingStats());
context.threadSafeCopyRenderingStats());
if (!renderTreeParameters.loaded) {
renderState = RenderState::Partial;

View File

@@ -105,12 +105,13 @@ BufferResource::BufferResource(
}
if (isValid()) {
auto& stats = context.renderingStats();
stats.numBuffers++;
stats.memBuffers += totalSize;
stats.totalBuffers++;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numBuffers++;
stats.memBuffers += totalSize;
stats.totalBuffers++;
stats.totalBufferObjs++;
stats.totalBufferObjs++;
});
}
}
@@ -128,13 +129,15 @@ BufferResource::BufferResource(BufferResource&& other) noexcept
BufferResource::~BufferResource() noexcept {
if (isValid()) {
context.renderingStats().numBuffers--;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numBuffers--;
if (bufferWindowSize > 0) {
context.renderingStats().memBuffers -= bufferWindowSize * context.getBackend().getMaxFrames();
} else {
context.renderingStats().memBuffers -= size;
}
if (bufferWindowSize > 0) {
stats.memBuffers -= bufferWindowSize * context.getBackend().getMaxFrames();
} else {
stats.memBuffers -= size;
}
});
}
if (!bufferAllocation) return;
@@ -149,8 +152,10 @@ BufferResource BufferResource::clone() const {
BufferResource& BufferResource::operator=(BufferResource&& other) noexcept {
assert(&context == &other.context);
if (isValid()) {
context.renderingStats().numBuffers--;
context.renderingStats().memBuffers -= size;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numBuffers--;
stats.memBuffers -= size;
});
}
size = other.size;
@@ -178,10 +183,11 @@ void BufferResource::update(const void* newData, std::size_t updateSize, std::si
std::memcpy(data, newData, updateSize);
auto& stats = context.renderingStats();
stats.bufferUpdateBytes += updateSize;
stats.bufferUpdates++;
stats.bufferObjUpdates++;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.bufferUpdateBytes += updateSize;
stats.bufferUpdates++;
stats.bufferObjUpdates++;
});
version++;
if (version == std::numeric_limits<VersionType>::max()) {

View File

@@ -224,8 +224,10 @@ void Texture2D::uploadSubRegion(const void* pixelData,
context.enqueueDeletion(std::move(function));
}
context.renderingStats().numTextureUpdates++;
context.renderingStats().textureUpdateBytes += bufferInfo.size;
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numTextureUpdates++;
stats.textureUpdateBytes += bufferInfo.size;
});
}
vk::Format Texture2D::vulkanFormat(const gfx::TexturePixelType pixel, gfx::TextureChannelDataType channel) {
@@ -385,9 +387,11 @@ void Texture2D::createTexture() {
imageLayout = imageCreateInfo.initialLayout;
}
context.renderingStats().numCreatedTextures++;
context.renderingStats().numActiveTextures++;
context.renderingStats().memTextures += getDataSize();
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numCreatedTextures++;
stats.numActiveTextures++;
stats.memTextures += getDataSize();
});
textureDirty = false;
lastModified = util::MonotonicTimer::now();
@@ -431,8 +435,10 @@ void Texture2D::destroyTexture() {
imageLayout = vk::ImageLayout::eUndefined;
context.renderingStats().numActiveTextures--;
context.renderingStats().memTextures -= Texture2D::getDataSize();
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
stats.numActiveTextures--;
stats.memTextures -= Texture2D::getDataSize();
});
}
}