Rendering statistics view (#3322)

Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
Adrian Cojocaru
2025-06-03 18:59:51 +03:00
committed by GitHub
parent 3c07cacc4d
commit 2a7249a3b0
81 changed files with 1271 additions and 128 deletions

View File

@@ -122,6 +122,8 @@ add_library(maplibre SHARED
${PROJECT_SOURCE_DIR}/offline/offline_region_error.hpp
${PROJECT_SOURCE_DIR}/offline/offline_region_status.cpp
${PROJECT_SOURCE_DIR}/offline/offline_region_status.hpp
${PROJECT_SOURCE_DIR}/rendering_stats.cpp
${PROJECT_SOURCE_DIR}/rendering_stats.hpp
${PROJECT_SOURCE_DIR}/snapshotter/map_snapshot.cpp
${PROJECT_SOURCE_DIR}/snapshotter/map_snapshot.hpp
${PROJECT_SOURCE_DIR}/snapshotter/map_snapshotter.cpp

View File

@@ -36,11 +36,10 @@ public:
void onDidFinishRenderingFrame(RenderMode mode,
bool repaintNeeded,
bool placementChanged,
double frameEncodingTime,
double frameRenderingTime) override {
const gfx::RenderingStats& stats) override {
void (RendererObserver::*f)(
RenderMode, bool, bool, double, double) = &RendererObserver::onDidFinishRenderingFrame;
delegate.invoke(f, mode, repaintNeeded, placementChanged, frameEncodingTime, frameRenderingTime);
RenderMode, bool, bool, const gfx::RenderingStats&) = &RendererObserver::onDidFinishRenderingFrame;
delegate.invoke(f, mode, repaintNeeded, placementChanged, stats);
}
void onDidFinishRenderingMap() override { delegate.invoke(&RendererObserver::onDidFinishRenderingMap); }

View File

@@ -35,6 +35,7 @@
#include "maplibre.hpp"
#include "native_map_view.hpp"
#include "native_map_options.hpp"
#include "rendering_stats.hpp"
#include "util/tile_server_options.hpp"
#ifndef MBGL_MODULE_OFFLINE_DISABLE
#include "offline/offline_manager.hpp"
@@ -111,6 +112,7 @@ void registerNatives(JavaVM* vm) {
MapRendererRunnable::registerNative(env);
NativeMapView::registerNative(env);
NativeMapOptions::registerNative(env);
RenderingStats::registerNative(env);
// Http
RegisterNativeHTTPRequest(env);

View File

@@ -40,6 +40,7 @@
#include "conversion/collection.hpp"
#include "style/conversion/filter.hpp"
#include "geojson/feature.hpp"
#include "rendering_stats.hpp"
#include "android_renderer_frontend.hpp"
#include "attach_env.hpp"
@@ -187,20 +188,25 @@ void NativeMapView::onWillStartRenderingFrame() {
}
}
void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderFrameStatus status) {
void NativeMapView::onDidFinishRenderingFrame(const MapObserver::RenderFrameStatus& status) {
assert(vm != nullptr);
android::UniqueEnv _env = android::AttachEnv();
static auto& javaClass = jni::Class<NativeMapView>::Singleton(*_env);
static auto onDidFinishRenderingFrame = javaClass.GetMethod<void(jboolean, jdouble, jdouble)>(
static auto onDidFinishRenderingFrame = javaClass.GetMethod<void(jboolean, jni::Object<RenderingStats>)>(
*_env, "onDidFinishRenderingFrame");
auto weakReference = javaPeer.get(*_env);
if (weakReference) {
if (!renderingStats) {
renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env));
}
RenderingStats::Update(*_env, renderingStats, status.renderingStats);
weakReference.Call(*_env,
onDidFinishRenderingFrame,
(jboolean)(status.mode != MapObserver::RenderMode::Partial),
(jdouble)status.frameEncodingTime,
(jdouble)status.frameRenderingTime);
renderingStats);
}
}
@@ -1272,6 +1278,16 @@ void NativeMapView::triggerRepaint(JNIEnv&) {
map->triggerRepaint();
}
jni::jboolean NativeMapView::isRenderingStatsViewEnabled(JNIEnv&) {
assert(map);
return jni::jboolean(map->isRenderingStatsViewEnabled());
}
void NativeMapView::enableRenderingStatsView(JNIEnv&, jni::jboolean value) {
assert(map);
map->enableRenderingStatsView(value);
}
// Static methods //
void NativeMapView::registerNative(jni::JNIEnv& env) {
@@ -1384,7 +1400,9 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta"),
METHOD(&NativeMapView::setTileCacheEnabled, "nativeSetTileCacheEnabled"),
METHOD(&NativeMapView::getTileCacheEnabled, "nativeGetTileCacheEnabled"),
METHOD(&NativeMapView::triggerRepaint, "nativeTriggerRepaint"));
METHOD(&NativeMapView::triggerRepaint, "nativeTriggerRepaint"),
METHOD(&NativeMapView::isRenderingStatsViewEnabled, "nativeIsRenderingStatsViewEnabled"),
METHOD(&NativeMapView::enableRenderingStatsView, "nativeEnableRenderingStatsView"));
}
void NativeMapView::onRegisterShaders(gfx::ShaderRegistry&) {};

View File

@@ -39,6 +39,7 @@ namespace android {
class AndroidRendererFrontend;
class FileSource;
class MapRenderer;
class RenderingStats;
class NativeMapView : public MapObserver {
public:
@@ -62,7 +63,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(MapLoadError, const std::string&) override;
void onWillStartRenderingFrame() override;
void onDidFinishRenderingFrame(MapObserver::RenderFrameStatus) override;
void onDidFinishRenderingFrame(const MapObserver::RenderFrameStatus&) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(MapObserver::RenderMode) override;
void onDidBecomeIdle() override;
@@ -305,6 +306,9 @@ public:
void triggerRepaint(JNIEnv&);
jni::jboolean isRenderingStatsViewEnabled(JNIEnv&);
void enableRenderingStatsView(JNIEnv&, jni::jboolean);
// Shader compilation
void onRegisterShaders(mbgl::gfx::ShaderRegistry&) override;
void onPreCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override;
@@ -336,6 +340,8 @@ private:
float pixelRatio;
jni::Global<jni::Object<RenderingStats>> renderingStats;
// Minimum texture size according to OpenGL ES 2.0 specification.
int width = 64;
int height = 64;

View File

@@ -0,0 +1,61 @@
#include "rendering_stats.hpp"
namespace mbgl {
namespace android {
void RenderingStats::registerNative(jni::JNIEnv& env) {
jni::Class<RenderingStats>::Singleton(env);
}
jni::Local<jni::Object<RenderingStats>> RenderingStats::Create(jni::JNIEnv& env) {
auto& javaClass = jni::Class<RenderingStats>::Singleton(env);
auto constructor = javaClass.GetConstructor(env);
return javaClass.New(env, constructor);
}
void RenderingStats::Update(jni::JNIEnv& env,
jni::Object<RenderingStats>& javaObject,
const gfx::RenderingStats& stats) {
static auto& javaClass = jni::Class<RenderingStats>::Singleton(env);
#define SetField(name, type) \
static auto name##Field = javaClass.GetField<type>(env, #name); \
javaObject.Set(env, name##Field, static_cast<type>(stats.name));
SetField(encodingTime, jni::jdouble);
SetField(renderingTime, jni::jdouble);
SetField(numFrames, jni::jint);
SetField(numDrawCalls, jni::jint);
SetField(totalDrawCalls, jni::jint);
SetField(numCreatedTextures, jni::jint);
SetField(numActiveTextures, jni::jint);
SetField(numTextureBindings, jni::jint);
SetField(numTextureUpdates, jni::jint);
SetField(textureUpdateBytes, jni::jlong);
SetField(totalBuffers, jni::jlong);
SetField(totalBufferObjs, jni::jlong);
SetField(bufferUpdates, jni::jlong);
SetField(bufferObjUpdates, jni::jlong);
SetField(bufferUpdateBytes, jni::jlong);
SetField(numBuffers, jni::jint);
SetField(numFrameBuffers, jni::jint);
SetField(numIndexBuffers, jni::jint);
SetField(indexUpdateBytes, jni::jlong);
SetField(numVertexBuffers, jni::jint);
SetField(vertexUpdateBytes, jni::jlong);
SetField(numUniformBuffers, jni::jint);
SetField(numUniformUpdates, jni::jint);
SetField(uniformUpdateBytes, jni::jlong);
SetField(memTextures, jni::jint);
SetField(memBuffers, jni::jint);
SetField(memIndexBuffers, jni::jint);
SetField(memVertexBuffers, jni::jint);
SetField(memUniformBuffers, jni::jint);
SetField(stencilClears, jni::jint);
SetField(stencilUpdates, jni::jint);
#undef SetField
}
} // namespace android
} // namespace mbgl

View File

@@ -0,0 +1,22 @@
#pragma once
#include <mbgl/gfx/rendering_stats.hpp>
#include <string>
#include <jni.h>
#include <jni/jni.hpp>
namespace mbgl {
namespace android {
class RenderingStats {
public:
static constexpr auto Name() { return "org/maplibre/android/maps/RenderingStats"; };
static void registerNative(jni::JNIEnv& env);
static jni::Local<jni::Object<RenderingStats>> Create(jni::JNIEnv&);
static void Update(jni::JNIEnv&, jni::Object<RenderingStats>&, const gfx::RenderingStats&);
};
} // namespace android
} // namespace mbgl

View File

@@ -249,6 +249,11 @@ jni::Local<jni::Object<>> SymbolLayer::getTextOptional(jni::JNIEnv& env) {
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextOptional()));
}
jni::Local<jni::Object<>> SymbolLayer::getSymbolScreenSpace(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getSymbolScreenSpace()));
}
jni::Local<jni::Object<>> SymbolLayer::getIconOpacity(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getIconOpacity()));
@@ -557,6 +562,7 @@ void SymbolJavaLayerPeerFactory::registerNative(jni::JNIEnv& env) {
METHOD(&SymbolLayer::getTextAllowOverlap, "nativeGetTextAllowOverlap"),
METHOD(&SymbolLayer::getTextIgnorePlacement, "nativeGetTextIgnorePlacement"),
METHOD(&SymbolLayer::getTextOptional, "nativeGetTextOptional"),
METHOD(&SymbolLayer::getSymbolScreenSpace, "nativeGetSymbolScreenSpace"),
METHOD(&SymbolLayer::getIconOpacityTransition, "nativeGetIconOpacityTransition"),
METHOD(&SymbolLayer::setIconOpacityTransition, "nativeSetIconOpacityTransition"),
METHOD(&SymbolLayer::getIconOpacity, "nativeGetIconOpacity"),

View File

@@ -110,6 +110,8 @@ public:
jni::Local<jni::Object<jni::ObjectTag>> getTextOptional(jni::JNIEnv&);
jni::Local<jni::Object<jni::ObjectTag>> getSymbolScreenSpace(jni::JNIEnv&);
jni::Local<jni::Object<jni::ObjectTag>> getIconOpacity(jni::JNIEnv&);
void setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
jni::Local<jni::Object<TransitionOptions>> getIconOpacityTransition(jni::JNIEnv&);