From 4f0f3bac51c784db26f49a66897b98fc52a42bc8 Mon Sep 17 00:00:00 2001 From: alasram Date: Mon, 17 Jun 2024 10:20:14 -0700 Subject: [PATCH] Add Tracy instrumentation for CPU and GPU in OpenGL mode. (#2417) --- CMakeLists.txt | 8 ++ bazel/core.bzl | 4 + docs/mdbook/src/SUMMARY.md | 3 + docs/mdbook/src/profiling/README.md | 3 + docs/mdbook/src/profiling/tracy-profiling.md | 123 ++++++++++++++++++ include/mbgl/gl/uniform_buffer_gl.hpp | 7 + include/mbgl/util/instrumentation.hpp | 115 ++++++++++++++++ platform/android/DEVELOPING.md | 4 + .../default/src/mbgl/gl/headless_backend.cpp | 21 ++- platform/glfw/BUILD.bazel | 14 ++ platform/glfw/glfw_gl_backend.cpp | 21 ++- platform/glfw/glfw_renderer_frontend.cpp | 3 + platform/glfw/glfw_view.cpp | 104 ++++++++++++++- .../annotation/render_annotation_source.cpp | 3 + src/mbgl/gl/context.cpp | 117 +++++++++++++++++ src/mbgl/gl/debugging_extension.hpp | 1 + src/mbgl/gl/fence.cpp | 7 + src/mbgl/gl/index_buffer_resource.cpp | 8 ++ src/mbgl/gl/index_buffer_resource.hpp | 4 +- src/mbgl/gl/renderbuffer_resource.cpp | 13 ++ src/mbgl/gl/renderbuffer_resource.hpp | 2 +- src/mbgl/gl/renderer_backend.cpp | 23 ++++ src/mbgl/gl/texture_resource.cpp | 8 ++ src/mbgl/gl/texture_resource.hpp | 4 +- src/mbgl/gl/timestamp_query_extension.cpp | 118 +++++++++++++++++ src/mbgl/gl/timestamp_query_extension.hpp | 41 ++++++ src/mbgl/gl/uniform_buffer_gl.cpp | 32 +++++ src/mbgl/gl/vertex_buffer_resource.cpp | 8 ++ src/mbgl/gl/vertex_buffer_resource.hpp | 4 +- src/mbgl/renderer/backend_scope.cpp | 7 + src/mbgl/renderer/render_orchestrator.cpp | 53 ++++++++ src/mbgl/renderer/renderer.cpp | 2 + src/mbgl/renderer/renderer_impl.cpp | 3 + src/mbgl/style/style.cpp | 45 +++++++ src/mbgl/tile/geojson_tile.cpp | 6 + src/mbgl/tile/geometry_tile.cpp | 43 ++++++ src/mbgl/tile/geometry_tile_data.cpp | 17 +++ src/mbgl/tile/geometry_tile_worker.cpp | 27 ++++ src/mbgl/tile/tile_cache.cpp | 7 + src/mbgl/tile/vector_tile_data.cpp | 5 + src/mbgl/util/http_header.cpp | 5 + src/mbgl/util/http_timeout.cpp | 3 + src/mbgl/util/io.cpp | 11 ++ vendor/tracy.cmake | 26 ++++ vendor/tracy/LICENSE | 27 ++++ 45 files changed, 1091 insertions(+), 19 deletions(-) create mode 100644 docs/mdbook/src/profiling/README.md create mode 100644 docs/mdbook/src/profiling/tracy-profiling.md create mode 100644 include/mbgl/util/instrumentation.hpp create mode 100644 src/mbgl/gl/renderbuffer_resource.cpp create mode 100644 src/mbgl/gl/timestamp_query_extension.cpp create mode 100644 src/mbgl/gl/timestamp_query_extension.hpp create mode 100644 vendor/tracy.cmake create mode 100644 vendor/tracy/LICENSE diff --git a/CMakeLists.txt b/CMakeLists.txt index 753152499..2ffa1b9ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ option(MLN_WITH_WERROR "Make all compilation warnings errors" ON) option(MLN_LEGACY_RENDERER "Include the legacy rendering pathway" ON) option(MLN_DRAWABLE_RENDERER "Include the drawable rendering pathway" OFF) option(MLN_USE_UNORDERED_DENSE "Use ankerl dense containers for performance" ON) +option(MLN_USE_TRACY "Enable Tracy instrumentation" OFF) if (MLN_WITH_CLANG_TIDY) find_program(CLANG_TIDY_COMMAND NAMES clang-tidy) @@ -409,6 +410,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/util/image.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/immutable.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/indexed_tuple.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/util/instrumentation.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/interpolate.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/logging.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/util/noncopyable.hpp @@ -1105,6 +1107,7 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_custom_layer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_pass.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_pass.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderbuffer_resource.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderbuffer_resource.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/renderer_backend.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/state.hpp @@ -1112,6 +1115,8 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/src/mbgl/gl/texture.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/texture_resource.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/texture_resource.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gl/timestamp_query_extension.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gl/timestamp_query_extension.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/types.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/uniform.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/uniform.hpp @@ -1337,6 +1342,7 @@ include(${PROJECT_SOURCE_DIR}/vendor/mapbox-base.cmake) include(${PROJECT_SOURCE_DIR}/vendor/parsedate.cmake) include(${PROJECT_SOURCE_DIR}/vendor/polylabel.cmake) include(${PROJECT_SOURCE_DIR}/vendor/protozero.cmake) +include(${PROJECT_SOURCE_DIR}/vendor/tracy.cmake) include(${PROJECT_SOURCE_DIR}/vendor/unique_resource.cmake) include(${PROJECT_SOURCE_DIR}/vendor/vector-tile.cmake) include(${PROJECT_SOURCE_DIR}/vendor/wagyu.cmake) @@ -1377,6 +1383,7 @@ target_link_libraries( Mapbox::Base::geojson.hpp Mapbox::Base::geometry.hpp Mapbox::Base::variant + TracyClient unordered_dense ) @@ -1407,6 +1414,7 @@ export(TARGETS mbgl-vendor-unique_resource mbgl-vendor-vector-tile mbgl-vendor-wagyu + TracyClient unordered_dense FILE MapboxCoreTargets.cmake diff --git a/bazel/core.bzl b/bazel/core.bzl index 48e4fbeb8..9804513a7 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -829,6 +829,7 @@ MLN_CORE_HEADERS = [ "include/mbgl/util/image.hpp", "include/mbgl/util/immutable.hpp", "include/mbgl/util/indexed_tuple.hpp", + "include/mbgl/util/instrumentation.hpp", "include/mbgl/util/interpolate.hpp", "include/mbgl/util/logging.hpp", "include/mbgl/util/monotonic_timer.hpp", @@ -884,6 +885,7 @@ MLN_OPENGL_SOURCE = [ "src/mbgl/gl/program.hpp", "src/mbgl/gl/render_pass.cpp", "src/mbgl/gl/render_pass.hpp", + "src/mbgl/gl/renderbuffer_resource.cpp", "src/mbgl/gl/renderbuffer_resource.hpp", "src/mbgl/gl/renderer_backend.cpp", "src/mbgl/gl/state.hpp", @@ -891,6 +893,8 @@ MLN_OPENGL_SOURCE = [ "src/mbgl/gl/texture.hpp", "src/mbgl/gl/texture_resource.cpp", "src/mbgl/gl/texture_resource.hpp", + "src/mbgl/gl/timestamp_query_extension.cpp", + "src/mbgl/gl/timestamp_query_extension.hpp", "src/mbgl/gl/types.hpp", "src/mbgl/gl/uniform.cpp", "src/mbgl/gl/uniform.hpp", diff --git a/docs/mdbook/src/SUMMARY.md b/docs/mdbook/src/SUMMARY.md index a2ce8b9a0..b868854fd 100644 --- a/docs/mdbook/src/SUMMARY.md +++ b/docs/mdbook/src/SUMMARY.md @@ -14,3 +14,6 @@ - [Quickstart](./android/getting-started-guide.md) - [Annotation: Marker](./android/annotation-guide.md) - [Location Component](./android/location-component-guide.md) + +- [Profiling applications that use MapLibre Native](./profiling/README.md) + - [Tracy profiling](./profiling/tracy-profiling.md) diff --git a/docs/mdbook/src/profiling/README.md b/docs/mdbook/src/profiling/README.md new file mode 100644 index 000000000..969978eed --- /dev/null +++ b/docs/mdbook/src/profiling/README.md @@ -0,0 +1,3 @@ +# MapLibre Native profiling + +MabLibre Native integrates [Tracy profiler](https://github.com/wolfpld/tracy) which offers an easy way to understand and optimize your application's CPU and GPU performance \ No newline at end of file diff --git a/docs/mdbook/src/profiling/tracy-profiling.md b/docs/mdbook/src/profiling/tracy-profiling.md new file mode 100644 index 000000000..3adf54fb8 --- /dev/null +++ b/docs/mdbook/src/profiling/tracy-profiling.md @@ -0,0 +1,123 @@ +# Tracy profiling + +#### Introduction + +MapLibre Native integrates [Tracy profiler](https://github.com/wolfpld/tracy) which offers an easy way to understand and optimize your application's CPU and GPU performance. +Tracy mainly consists in manually adding markup instrumentation in the code to log performance events. These events can then be analyzed and visualized using the [Tracy Profiler tool](https://github.com/wolfpld/tracy/tree/master/profiler). + +Instrumentation is generally the first step in profiling applications that use MapLibre. Once slow inner-loop routines are identified, additional hardware vendor specific tools can be used to collect hardware counters and optimize low level CPU and GPU code. + +#### Tracy client + +Tracy client consists of an API to mark CPU and GPU performance zones. A zone is a code section where the start and end timestamps are recorded. + +#### Tracy server + +The server is the Tracy profiler that allows the analysis and visualization of the client recorded data. +The server can be downloaded from [Tracy release page](https://github.com/wolfpld/tracy/releases) or it can be easily built from [sources](https://github.com/wolfpld/tracy/tree/master/profiler) on Linux, Windows or Mac using CMake + +#### Enabling instrumentation in MapLibre Native + +Instrumentation is enabled by turning `ON` the CMake option `MLN_USE_TRACY`. +Tracy computational overhead is very low but by default it keeps all instrumentation events that are not consumed by the server in system memory. This can have a negative effect on platforms with low memory. To prevent high memory usage, `TRACY_ON_DEMAND` macro should defined. This way instrumentation data is only stored when the server is connected to the application. + +#### Instrumentation in MapLibre + +The file `include/mbgl/util/instrumentation.hpp` defines the following instrumentation macros: + +##### `MLN_TRACE_ZONE(label)` +The macro records the timestamps at the start and end of the code scope. The parameter label is a user defined name for the zone. Example: + +~~~ +// code is not instrumented +{ + MLN_TRACE_ZONE(EmptyZone); // Records from here until the end of the scope + // code here is instrumented +} +// other here not instrumented +~~~ + +##### `MLN_TRACE_FUNC()` +The macro is meant to be placed at the start of a function and expands to: +~~~ +MLN_TRACE_ZONE(__FUNCTION__) +~~~ + +##### GPU instrumentation + +OpenGL is also supported in MapLibre native. Tracy support is currently missing for other APIs such as Metal and need to be added separately. + +##### `MLN_TRACE_GL_ZONE(label)` +This macro is similar to `MLN_TRACE_ZONE` except that [OpenGL timestamp queries](https://www.khronos.org/opengl/wiki/Query_Object) are inserted in the GPU command buffer instead of recording CPU time. + +##### `MLN_TRACE_FUNC_GL(label)` +This macro is similar to `MLN_TRACE_FUNC` except that [OpenGL timestamp queries](https://www.khronos.org/opengl/wiki/Query_Object) are inserted in the GPU command buffer instead of recording CPU time. + +##### Other macros + +The above macros can be added inside MapLibre code and also in the application code that calls MapLibre. + +The following macros should only be used if there are changes to MapLibre internals: + +##### `MLN_END_FRAME()` +Mark the end of a frame. + +##### `MLN_TRACE_GL_CONTEXT()` +Placed after an OpenGL context is created. + +##### `MLN_TRACE_ALLOC_TEXTURE(id, size)` and `MLN_TRACE_FREE_TEXTURE(id)` +Record a read-only texture allocation and deallocation + +##### `MLN_TRACE_ALLOC_RT(id, size)` and `MLN_TRACE_FREE_RT(id)` +Record a render target texture allocation and deallocation + +##### `MLN_TRACE_ALLOC_VERTEX_BUFFER(id, size)` and `MLN_TRACE_FREE_VERTEX_BUFFER(id)` +Record a buffer allocation and deallocation that is intended to be used as a read-only vertex buffer + +##### `MLN_TRACE_ALLOC_INDEX_BUFFER(id, size)` and `MLN_TRACE_FREE_INDEX_BUFFER(id)` +Record a buffer allocation and deallocation that is intended to be used as a read-only index buffer + +##### `MLN_TRACE_ALLOC_CONST_BUFFER(id, size)` and `MLN_TRACE_FREE_CONST_BUFFER(id)` +Record a buffer allocation and deallocation that is intended to be used as a constant buffer + + +#### Usage example on Linux and Windows + +Download or build the Tracy profiler (server) and run it. + +Make sure you generate the MapLibre project with the option `MLN_USE_TRACY` enabled. + +As an example, the glfw sample is used. + +With CMake, in MapLibre repository root do +~~~ +# generate project +cmake -B build -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DMLN_WITH_CLANG_TIDY=OFF -DMLN_WITH_COVERAGE=OFF -DMLN_DRAWABLE_RENDERER=ON -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DMLN_USE_TRACY=ON +# build +cmake --build build --target mbgl-glfw -j 8 +# run +./build/platform/glfw/mbgl-glfw --style https://raw.githubusercontent.com/maplibre/demotiles/gh-pages/style.json --benchmark +~~~ +with Bazel +~~~ +# build and run +bazel run //platform/glfw:glfw_app -- --style https://raw.githubusercontent.com/maplibre/demotiles/gh-pages/style.json --benchmark +~~~ + +In the Tracy Profiler hit the connect button (or select the glfw application from the list of applications that are running Tracy Client). Profile then optimize the code. + +#### Connecting the profiler to a MapLibre Android application +The Android application communicates instrumentation data to the profiler (Tracy server) on the network using port 8086 by default. You can expose the port to the profiler using Android Debug Bridge by running the command: +~~~ +adb forward tcp:8086 tcp:8086 +~~~ + +#### More information and advanced usage in Tracy + +[Tracy Github page](https://github.com/wolfpld/tracy/) + +[Tracy user guide](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) + +[Tracy demo on Youtube](https://www.youtube.com/watch?v=fB5B46lbapc) + +[Tracy CppCon presentation on Youtube](https://www.youtube.com/watch?v=ghXk3Bk5F2U&t=37s) diff --git a/include/mbgl/gl/uniform_buffer_gl.hpp b/include/mbgl/gl/uniform_buffer_gl.hpp index 9775dc9ad..870b2d433 100644 --- a/include/mbgl/gl/uniform_buffer_gl.hpp +++ b/include/mbgl/gl/uniform_buffer_gl.hpp @@ -27,6 +27,13 @@ public: void update(const void* data, std::size_t size_) override; private: + // unique id used for debugging and profiling purposes + // localID should not be used as unique id because a const buffer pool is managed using IBufferAllocator +// Currently unique IDs for constant buffers are only used when Tracy profiling is enabled +#ifdef MLN_TRACY_ENABLE + int64_t uniqueDebugId = -1; +#endif + // If the requested UBO size is too large for the allocator, the UBO will manage its own allocation bool isManagedAllocation = false; BufferID localID; diff --git a/include/mbgl/util/instrumentation.hpp b/include/mbgl/util/instrumentation.hpp new file mode 100644 index 000000000..a9489abf4 --- /dev/null +++ b/include/mbgl/util/instrumentation.hpp @@ -0,0 +1,115 @@ +#pragma once + +#ifdef MLN_TRACY_ENABLE + +#include +#include + +template +const void* castGpuIdToTracyPtr(GpuId id) { + // Tracy functions such as TracyAllocN track resources using `const void*` + // pointers. GPU resources may use a non-pointer handles. These handles may + // be GLsizei, GLuint and Vulkan handles are guaranteed to be 64 bits: + // Check VK_USE_64_BIT_PTR_DEFINES in the spec for instance. + // For simplicity we cast to ptrdiff_t which is guaranteed to work on + // 64bits systems but the cast may drop high bits if the handle is larger + // than the pointer type + // We fail to compile if this happens. A workaround would be to map + // handles to 32 bits values if Tracy is on those systems + static_assert(sizeof(GpuId) <= sizeof(std::ptrdiff_t), "Tracy is currently not supported on 32 bits systems"); + return reinterpret_cast(static_cast(id)); +} + +#ifndef MLN_RENDER_BACKEND_OPENGL +#error \ + "MLN_RENDER_BACKEND_OPENGL is not defined. MLN_RENDER_BACKEND_OPENGL is expected to be defined in CMake and Bazel" +#endif + +#define MLN_TRACE_FUNC() ZoneScoped +#define MLN_TRACE_ZONE(label) ZoneScopedN(#label) + +constexpr const char* tracyTextureMemoryLabel = "Texture Memory"; +#define MLN_TRACE_ALLOC_TEXTURE(id, size) TracyAllocN(castGpuIdToTracyPtr(id), size, tracyTextureMemoryLabel) +#define MLN_TRACE_FREE_TEXTURE(id) TracyFreeN(castGpuIdToTracyPtr(id), tracyTextureMemoryLabel) + +constexpr const char* tracyRenderTargetMemoryLabel = "Render Target Memory"; +#define MLN_TRACE_ALLOC_RT(id, size) TracyAllocN(castGpuIdToTracyPtr(id), size, tracyRenderTargetMemoryLabel) +#define MLN_TRACE_FREE_RT(id) TracyFreeN(castGpuIdToTracyPtr(id), tracyRenderTargetMemoryLabel) + +constexpr const char* tracyVertexMemoryLabel = "Vertex Buffer Memory"; +#define MLN_TRACE_ALLOC_VERTEX_BUFFER(id, size) TracyAllocN(castGpuIdToTracyPtr(id), size, tracyVertexMemoryLabel) +#define MLN_TRACE_FREE_VERTEX_BUFFER(id) TracyFreeN(castGpuIdToTracyPtr(id), tracyVertexMemoryLabel) + +constexpr const char* tracyIndexMemoryLabel = "Index Buffer Memory"; +#define MLN_TRACE_ALLOC_INDEX_BUFFER(id, size) TracyAllocN(castGpuIdToTracyPtr(id), size, tracyIndexMemoryLabel) +#define MLN_TRACE_FREE_INDEX_BUFFER(id) TracyFreeN(castGpuIdToTracyPtr(id), tracyIndexMemoryLabel) + +constexpr const char* tracyConstMemoryLabel = "Constant Buffer Memory"; +#define MLN_TRACE_ALLOC_CONST_BUFFER(id, size) TracyAllocN(castGpuIdToTracyPtr(id), size, tracyConstMemoryLabel) +#define MLN_TRACE_FREE_CONST_BUFFER(id) TracyFreeN(castGpuIdToTracyPtr(id), tracyConstMemoryLabel) + +// Only OpenGL is currently considered for GPU profiling +// Metal and other APIs need to be handled separately +#if MLN_RENDER_BACKEND_OPENGL + +#include + +// TracyOpenGL.hpp assumes OpenGL functions are in the global namespace +// Temporarily expose the functions to TracyOpenGL.hpp then undef +#define glGenQueries mbgl::gl::extension::glGenQueries +#define glGetQueryiv mbgl::gl::extension::glGetQueryiv +#define glGetQueryObjectiv mbgl::gl::extension::glGetQueryObjectiv +#define glGetInteger64v mbgl::gl::extension::glGetInteger64v +#define glQueryCounter mbgl::gl::extension::glQueryCounter +#define glGetQueryObjectui64v mbgl::gl::extension::glGetQueryObjectui64v +#define GLint mbgl::platform::GLint + +#include "tracy/TracyOpenGL.hpp" + +#define MLN_TRACE_GL_CONTEXT() TracyGpuContext +#define MLN_TRACE_GL_ZONE(label) TracyGpuZone(#label) +#define MLN_TRACE_FUNC_GL() TracyGpuZone(__FUNCTION__) + +#define MLN_END_FRAME() \ + do { \ + FrameMark; \ + TracyGpuCollect; \ + } while (0) + +#undef glGenQueries +#undef glGetQueryiv +#undef glGetQueryObjectiv +#undef glGetInteger64v +#undef glQueryCounter +#undef glGetQueryObjectui64v +#undef GLint + +#else // MLN_RENDER_BACKEND_OPENGL + +#define MLN_TRACE_GL_CONTEXT() +#define MLN_TRACE_GL_ZONE(label) +#define MLN_TRACE_FUNC_GL() +#define MLN_END_FRAME() FrameMark + +#endif // MLN_RENDER_BACKEND_OPENGL + +#else // MLN_TRACY_ENABLE + +#define MLN_TRACE_GL_CONTEXT() +#define MLN_TRACE_GL_ZONE(label) +#define MLN_TRACE_FUNC_GL() +#define MLN_END_FRAME() +#define MLN_TRACE_ALLOC_TEXTURE(id, size) +#define MLN_TRACE_FREE_TEXTURE(id) +#define MLN_TRACE_ALLOC_RT(id, size) +#define MLN_TRACE_FREE_RT(id) +#define MLN_TRACE_ALLOC_VERTEX_BUFFER(id, size) +#define MLN_TRACE_FREE_VERTEX_BUFFER(id) +#define MLN_TRACE_ALLOC_INDEX_BUFFER(id, size) +#define MLN_TRACE_FREE_INDEX_BUFFER(id) +#define MLN_TRACE_ALLOC_CONST_BUFFER(id, size) +#define MLN_TRACE_FREE_CONST_BUFFER(id) +#define MLN_TRACE_FUNC() +#define MLN_TRACE_ZONE(label) + +#endif // MLN_TRACY_ENABLE \ No newline at end of file diff --git a/platform/android/DEVELOPING.md b/platform/android/DEVELOPING.md index d5b75adef..99962b6bc 100644 --- a/platform/android/DEVELOPING.md +++ b/platform/android/DEVELOPING.md @@ -80,3 +80,7 @@ To run the benchmarks (for Android) include the following line on a PR comment: ``` !benchmark android ``` + +## Profiling + +[maplibre-native/docs/mdbook](https://maplibre.org/maplibre-native/docs/book/) describes how Tracy can be used for profiling. diff --git a/platform/default/src/mbgl/gl/headless_backend.cpp b/platform/default/src/mbgl/gl/headless_backend.cpp index ccfe6936d..63674eee5 100644 --- a/platform/default/src/mbgl/gl/headless_backend.cpp +++ b/platform/default/src/mbgl/gl/headless_backend.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,11 @@ public: context.viewport = {0, 0, framebuffer.size}; } - void swap() override { backend.swap(); } + void swap() override { + MLN_TRACE_FUNC(); + + backend.swap(); + } HeadlessBackend& backend; gl::Context& context; @@ -44,6 +49,8 @@ HeadlessBackend::HeadlessBackend(const Size size_, swapBehaviour(swapBehaviour_) {} HeadlessBackend::~HeadlessBackend() { + MLN_TRACE_FUNC(); + gfx::BackendScope guard{*this, gfx::BackendScope::ScopeType::Implicit}; // Some implementations require active context for GL functions to work if (impl != nullptr && impl->glNeedsActiveContextOnDestruction()) { @@ -66,6 +73,8 @@ gl::ProcAddress HeadlessBackend::getExtensionFunctionPointer(const char* name) { } void HeadlessBackend::activate() { + MLN_TRACE_FUNC(); + active = true; if (!impl) { @@ -77,12 +86,16 @@ void HeadlessBackend::activate() { } void HeadlessBackend::deactivate() { + MLN_TRACE_FUNC(); + assert(impl); impl->deactivateContext(); active = false; } gfx::Renderable& HeadlessBackend::getDefaultRenderable() { + MLN_TRACE_FUNC(); + if (!resource) { resource = std::make_unique(*this, static_cast(getContext()), size); } @@ -90,6 +103,8 @@ gfx::Renderable& HeadlessBackend::getDefaultRenderable() { } void HeadlessBackend::swap() { + MLN_TRACE_FUNC(); + if (swapBehaviour == SwapBehaviour::Flush) static_cast(getContext()).finish(); } @@ -98,6 +113,8 @@ void HeadlessBackend::updateAssumedState() { } PremultipliedImage HeadlessBackend::readStillImage() { + MLN_TRACE_FUNC(); + return static_cast(getContext()).readFramebuffer(size); } @@ -112,6 +129,8 @@ namespace gfx { template <> std::unique_ptr Backend::Create( const Size size, gfx::Renderable::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode) { + MLN_TRACE_FUNC(); + return std::make_unique(size, swapBehavior, contextMode); } diff --git a/platform/glfw/BUILD.bazel b/platform/glfw/BUILD.bazel index 0f0850722..e7fb784c0 100644 --- a/platform/glfw/BUILD.bazel +++ b/platform/glfw/BUILD.bazel @@ -16,6 +16,13 @@ objc_library( ], ) +filegroup( + name = "mapbox_puck_assets", + srcs = glob([ + "assets/*.png", + ]), +) + cc_binary( name = "glfw_app", srcs = glob( @@ -36,6 +43,12 @@ cc_binary( ], }), copts = CPP_FLAGS + MAPLIBRE_FLAGS, + data = [ + ":mapbox_puck_assets", + ], + defines = [ + r"MAPBOX_PUCK_ASSETS_PATH=\"./platform/glfw/assets/\"", + ], linkopts = [ "-lglfw", ] + select({ @@ -53,6 +66,7 @@ cc_binary( "@glfw", ] + select({ "@platforms//os:macos": ["metal_backend"], + "@platforms//os:linux": ["//platform/linux:impl"], "//conditions:default": [], }), ) diff --git a/platform/glfw/glfw_gl_backend.cpp b/platform/glfw/glfw_gl_backend.cpp index 5a264e1ac..c609d4730 100644 --- a/platform/glfw/glfw_gl_backend.cpp +++ b/platform/glfw/glfw_gl_backend.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -11,11 +12,17 @@ public: : backend(backend_) {} void bind() override { + MLN_TRACE_FUNC(); + backend.setFramebufferBinding(0); backend.setViewport(0, 0, backend.getSize()); } - void swap() override { backend.swap(); } + void swap() override { + MLN_TRACE_FUNC(); + + backend.swap(); + } private: GLFWGLBackend& backend; @@ -32,6 +39,8 @@ GLFWGLBackend::GLFWGLBackend(GLFWwindow* window_, const bool capFrameRate) }(), std::make_unique(*this)), window(window_) { + MLN_TRACE_FUNC(); + glfwMakeContextCurrent(window); if (!capFrameRate) { // Disables vsync on platforms that support it. @@ -44,10 +53,14 @@ GLFWGLBackend::GLFWGLBackend(GLFWwindow* window_, const bool capFrameRate) GLFWGLBackend::~GLFWGLBackend() = default; void GLFWGLBackend::activate() { + MLN_TRACE_FUNC(); + glfwMakeContextCurrent(window); } void GLFWGLBackend::deactivate() { + MLN_TRACE_FUNC(); + glfwMakeContextCurrent(nullptr); } @@ -56,6 +69,8 @@ mbgl::gl::ProcAddress GLFWGLBackend::getExtensionFunctionPointer(const char* nam } void GLFWGLBackend::updateAssumedState() { + MLN_TRACE_FUNC(); + assumeFramebufferBinding(0); setViewport(0, 0, size); } @@ -69,6 +84,8 @@ void GLFWGLBackend::setSize(const mbgl::Size newSize) { } void GLFWGLBackend::swap() { + MLN_TRACE_FUNC(); + glfwSwapBuffers(window); } @@ -77,6 +94,8 @@ namespace gfx { template <> std::unique_ptr Backend::Create(GLFWwindow* window, bool capFrameRate) { + MLN_TRACE_FUNC(); + return std::make_unique(window, capFrameRate); } diff --git a/platform/glfw/glfw_renderer_frontend.cpp b/platform/glfw/glfw_renderer_frontend.cpp index 0daa481e4..0e06a1663 100644 --- a/platform/glfw/glfw_renderer_frontend.cpp +++ b/platform/glfw/glfw_renderer_frontend.cpp @@ -2,6 +2,7 @@ #include #include +#include GLFWRendererFrontend::GLFWRendererFrontend(std::unique_ptr renderer_, GLFWView& glfwView_) : glfwView(glfwView_), @@ -27,6 +28,8 @@ void GLFWRendererFrontend::update(std::shared_ptr params } void GLFWRendererFrontend::render() { + MLN_TRACE_FUNC(); + assert(renderer); if (!updateParameters) return; diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index 5658ba54e..0036abc51 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -78,6 +79,8 @@ class SnapshotObserver final : public mbgl::MapSnapshotterObserver { public: ~SnapshotObserver() override = default; void onDidFinishLoadingStyle() override { + MLN_TRACE_FUNC(); + if (didFinishLoadingStyleCallback) { didFinishLoadingStyleCallback(); } @@ -87,6 +90,8 @@ public: namespace { void addFillExtrusionLayer(mbgl::style::Style &style, bool visible) { + MLN_TRACE_FUNC(); + using namespace mbgl::style; using namespace mbgl::style::expression::dsl; @@ -132,6 +137,8 @@ GLFWView::GLFWView(bool fullscreen_, snapshotterObserver(std::make_unique()), mapResourceOptions(resourceOptions.clone()), mapClientOptions(clientOptions.clone()) { + MLN_TRACE_FUNC(); + glfwSetErrorCallback(glfwError); std::srand(static_cast(std::time(nullptr))); @@ -198,7 +205,8 @@ GLFWView::GLFWView(bool fullscreen_, glfwGetWindowSize(window, &width, &height); - backend = GLFWBackend::Create(window, benchmark); + bool capFrameRate = !benchmark; // disable VSync in benchmark mode + backend = GLFWBackend::Create(window, capFrameRate); #ifdef __APPLE__ int fbW, fbH; @@ -270,24 +278,34 @@ GLFWView::GLFWView(bool fullscreen_, } GLFWView::~GLFWView() { + MLN_TRACE_FUNC(); + glfwDestroyWindow(window); glfwTerminate(); } void GLFWView::setMap(mbgl::Map *map_) { + MLN_TRACE_FUNC(); + map = map_; map->addAnnotationImage(makeImage("default_marker", 22, 22, 1)); } void GLFWView::setRenderFrontend(GLFWRendererFrontend *rendererFrontend_) { + MLN_TRACE_FUNC(); + rendererFrontend = rendererFrontend_; } mbgl::gfx::RendererBackend &GLFWView::getRendererBackend() { + MLN_TRACE_FUNC(); + return backend->getRendererBackend(); } void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { + MLN_TRACE_FUNC(); + auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); if (action == GLFW_RELEASE) { @@ -588,6 +606,8 @@ struct Interpolator { } // namespace mbgl void GLFWView::updateFreeCameraDemo() { + MLN_TRACE_FUNC(); + const mbgl::LatLng trainStartPos = {60.171367, 24.941359}; const mbgl::LatLng trainEndPos = {60.185147, 24.936668}; const mbgl::LatLng cameraStartPos = {60.167443, 24.927176}; @@ -635,6 +655,8 @@ std::unique_ptr GLFWView::makeImage(const std::string &id, int width, int height, float pixelRatio) { + MLN_TRACE_FUNC(); + const int r = static_cast(255 * (static_cast(std::rand()) / RAND_MAX)); const int g = static_cast(255 * (static_cast(std::rand()) / RAND_MAX)); const int b = static_cast(255 * (static_cast(std::rand()) / RAND_MAX)); @@ -680,6 +702,8 @@ void GLFWView::nextOrientation() { } void GLFWView::addRandomCustomPointAnnotations(int count) { + MLN_TRACE_FUNC(); + for (int i = 0; i < count; i++) { static int spriteID = 1; const auto name = std::string{"marker-"} + mbgl::util::toString(spriteID++); @@ -690,12 +714,16 @@ void GLFWView::addRandomCustomPointAnnotations(int count) { } void GLFWView::addRandomPointAnnotations(int count) { + MLN_TRACE_FUNC(); + for (int i = 0; i < count; ++i) { annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation{makeRandomPoint(), "default_marker"})); } } void GLFWView::addRandomLineAnnotations(int count) { + MLN_TRACE_FUNC(); + for (int i = 0; i < count; ++i) { mbgl::LineString lineString; for (int j = 0; j < 3; ++j) { @@ -706,6 +734,8 @@ void GLFWView::addRandomLineAnnotations(int count) { } void GLFWView::addRandomShapeAnnotations(int count) { + MLN_TRACE_FUNC(); + for (int i = 0; i < count; ++i) { mbgl::Polygon triangle; triangle.push_back({makeRandomPoint(), makeRandomPoint(), makeRandomPoint()}); @@ -715,12 +745,16 @@ void GLFWView::addRandomShapeAnnotations(int count) { } void GLFWView::addAnimatedAnnotation() { + MLN_TRACE_FUNC(); + const double started = glfwGetTime(); animatedAnnotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation{{0, 0}, "default_marker"})); animatedAnnotationAddedTimes.push_back(started); } void GLFWView::updateAnimatedAnnotations() { + MLN_TRACE_FUNC(); + const double time = glfwGetTime(); for (size_t i = 0; i < animatedAnnotationIDs.size(); i++) { auto dt = time - animatedAnnotationAddedTimes[i]; @@ -752,6 +786,8 @@ void GLFWView::cycleDebugOptions() { } void GLFWView::clearAnnotations() { + MLN_TRACE_FUNC(); + for (const auto &id : annotationIDs) { map->removeAnnotation(id); } @@ -775,6 +811,8 @@ void GLFWView::popAnnotation() { } void GLFWView::makeSnapshot(bool withOverlay) { + MLN_TRACE_FUNC(); + if (!snapshotter || snapshotter->getStyleURL() != map->getStyle().getURL()) { snapshotter = std::make_unique(map->getMapOptions().size(), map->getMapOptions().pixelRatio(), @@ -815,6 +853,8 @@ void GLFWView::makeSnapshot(bool withOverlay) { } void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) { + MLN_TRACE_FUNC(); + auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); double delta = yOffset * 40; @@ -843,6 +883,8 @@ void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) } void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { + MLN_TRACE_FUNC(); + auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); view->width = width; view->height = height; @@ -856,6 +898,8 @@ void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { } void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { + MLN_TRACE_FUNC(); + auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); view->backend->setSize({static_cast(width), static_cast(height)}); @@ -867,6 +911,8 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { } void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) { + MLN_TRACE_FUNC(); + auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); if (button == GLFW_MOUSE_BUTTON_RIGHT || (button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) { @@ -898,6 +944,8 @@ void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modi } void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) { + MLN_TRACE_FUNC(); + auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); if (view->tracking) { const double dx = x - view->lastX; @@ -958,6 +1006,8 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) { } void GLFWView::onWindowFocus(GLFWwindow *window, int focused) { + MLN_TRACE_FUNC(); + if (focused == GLFW_FALSE) { // Focus lost. auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); view->rendererFrontend->getRenderer()->reduceMemoryUse(); @@ -965,19 +1015,35 @@ void GLFWView::onWindowFocus(GLFWwindow *window, int focused) { } void GLFWView::run() { + MLN_TRACE_FUNC(); + auto callback = [&] { - if (glfwWindowShouldClose(window)) { - runLoop.stop(); - return; + MLN_TRACE_ZONE(GLFWView_runLoop_callback); + + { + MLN_TRACE_ZONE(glfwWindowShouldClose); + if (glfwWindowShouldClose(window)) { + runLoop.stop(); + return; + } } - glfwPollEvents(); + { + MLN_TRACE_ZONE(glfwPollEvents); + glfwPollEvents(); + } if (dirty && rendererFrontend) { + MLN_TRACE_ZONE(ReRender); + dirty = false; const double started = glfwGetTime(); - if (animateRouteCallback) animateRouteCallback(map); + if (animateRouteCallback) { + MLN_TRACE_ZONE(animateRouteCallback); + + animateRouteCallback(map); + } updateAnimatedAnnotations(); @@ -996,7 +1062,15 @@ void GLFWView::run() { } }; - frameTick.start(mbgl::Duration::zero(), mbgl::Milliseconds(1000 / 60), callback); + // Cap frame rate to 60hz if benchmark mode is disabled + auto tickDuration = mbgl::Milliseconds(1000 / 60); + if (benchmark) { + // frameTick.start internally uses libuv which uses milliseconds resolution + // tickDuration is set to 1ms in benchmark mode which limits FPS to 1000 + // 1000 should more than enough for benchmarking purposes + tickDuration = mbgl::Milliseconds(1); + } + frameTick.start(mbgl::Duration::zero(), tickDuration, callback); #if defined(__APPLE__) while (!glfwWindowShouldClose(window)) runLoop.run(); #else @@ -1013,6 +1087,8 @@ mbgl::Size GLFWView::getSize() const { } void GLFWView::invalidate() { + MLN_TRACE_FUNC(); + dirty = true; glfwPostEmptyEvent(); } @@ -1041,15 +1117,21 @@ void GLFWView::setChangeStyleCallback(std::function callback) { } void GLFWView::setShouldClose() { + MLN_TRACE_FUNC(); + glfwSetWindowShouldClose(window, true); glfwPostEmptyEvent(); } void GLFWView::setWindowTitle(const std::string &title) { + MLN_TRACE_FUNC(); + glfwSetWindowTitle(window, (std::string{"MapLibre Native (GLFW): "} + title).c_str()); } void GLFWView::onDidFinishLoadingStyle() { + MLN_TRACE_FUNC(); + #if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) puck = nullptr; #endif @@ -1060,11 +1142,15 @@ void GLFWView::onDidFinishLoadingStyle() { } void GLFWView::toggle3DExtrusions(bool visible) { + MLN_TRACE_FUNC(); + show3DExtrusions = visible; addFillExtrusionLayer(map->getStyle(), show3DExtrusions); } void GLFWView::toggleCustomSource() { + MLN_TRACE_FUNC(); + if (!map->getStyle().getSource("custom")) { mbgl::style::CustomGeometrySource::Options options; options.cancelTileFunction = [](const mbgl::CanonicalTileID &) { @@ -1115,6 +1201,8 @@ void GLFWView::toggleCustomSource() { } void GLFWView::toggleLocationIndicatorLayer() { + MLN_TRACE_FUNC(); + #if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) puck = static_cast(map->getStyle().getLayer("puck")); static const mbgl::LatLng puckLocation{35.683389, 139.76525}; // A location on the crossing of 4 tiles @@ -1178,6 +1266,8 @@ void GLFWView::toggleLocationIndicatorLayer() { using Nanoseconds = std::chrono::nanoseconds; void GLFWView::onWillStartRenderingFrame() { + MLN_TRACE_FUNC(); + #if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) puck = static_cast(map->getStyle().getLayer("puck")); if (puck) { diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index ec60eecbe..622f83862 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -25,6 +26,8 @@ void RenderAnnotationSource::update(Immutable baseImpl_, const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) { + MLN_TRACE_FUNC(); + std::swap(baseImpl, baseImpl_); enabled = needsRendering; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 8632134d2..b53903101 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include #if MLN_DRAWABLE_RENDERER @@ -70,6 +72,24 @@ GLint getMaxVertexAttribs() { MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); return value; } + +// Currently renderBufferByteSize is only used when Tracy profiling is enabled +#ifdef MLN_TRACY_ENABLE +constexpr size_t renderBufferByteSize(const gfx::RenderbufferPixelType type, const Size size) noexcept { + size_t sz = size.width * size.height; + switch (type) { + case gfx::RenderbufferPixelType::RGBA: + [[fallthrough]]; + case gfx::RenderbufferPixelType::DepthStencil: + sz *= 4; + break; + case gfx::RenderbufferPixelType::Depth: + sz *= 2; + break; + } + return sz; +} +#endif } // namespace Context::Context(RendererBackend& backend_) @@ -93,6 +113,8 @@ Context::~Context() noexcept { } void Context::beginFrame() { + MLN_TRACE_FUNC(); + Scheduler::GetBackground()->runRenderJobs(); #if MLN_DRAWABLE_RENDERER @@ -111,6 +133,8 @@ void Context::beginFrame() { } void Context::endFrame() { + MLN_TRACE_FUNC(); + #if MLN_DRAWABLE_RENDERER if (!frameInFlightFence) { return; @@ -121,6 +145,8 @@ void Context::endFrame() { } void Context::initializeExtensions(const std::function& getProcAddress) { + MLN_TRACE_FUNC(); + if (const auto* extensions = reinterpret_cast(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { auto fn = [&](std::initializer_list> probes) -> ProcAddress { for (auto probe : probes) { @@ -143,7 +169,13 @@ void Context::initializeExtensions(const std::function(fn); } + +// Currently GL timestamp queries are only used when Tracy profiling is enabled +#ifdef MLN_TRACY_ENABLE + extension::loadTimeStampQueryExtension(fn); +#endif } + MLN_TRACE_GL_CONTEXT(); } void Context::enableDebugging() { @@ -207,11 +239,15 @@ UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentSha } void Context::linkProgram(ProgramID program_) { + MLN_TRACE_FUNC(); + MBGL_CHECK_ERROR(glLinkProgram(program_)); verifyProgramLinkage(program_); } void Context::verifyProgramLinkage(ProgramID program_) { + MLN_TRACE_FUNC(); + GLint status; MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status)); if (status == GL_TRUE) { @@ -230,6 +266,8 @@ void Context::verifyProgramLinkage(ProgramID program_) { } UniqueTexture Context::createUniqueTexture() { + MLN_TRACE_FUNC(); + if (pooledTextures.empty()) { pooledTextures.resize(TextureMax); MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data())); @@ -244,6 +282,8 @@ UniqueTexture Context::createUniqueTexture() { } VertexArray Context::createVertexArray() { + MLN_TRACE_FUNC(); + VertexArrayID id = 0; MBGL_CHECK_ERROR(glGenVertexArrays(1, &id)); // NOLINTNEXTLINE(performance-move-const-arg) @@ -252,6 +292,8 @@ VertexArray Context::createVertexArray() { } UniqueFramebuffer Context::createFramebuffer() { + MLN_TRACE_FUNC(); + FramebufferID id = 0; MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); stats.numFrameBuffers++; @@ -262,6 +304,8 @@ UniqueFramebuffer Context::createFramebuffer() { std::unique_ptr Context::createTextureResource(const Size size, const gfx::TexturePixelType format, const gfx::TextureChannelDataType type) { + MLN_TRACE_FUNC(); + auto obj = createUniqueTexture(); int textureByteSize = gl::TextureResource::getStorageSize(size, format, type); stats.memTextures += textureByteSize; @@ -296,8 +340,11 @@ std::unique_ptr Context::createTextureResource(const Size std::unique_ptr Context::createRenderbufferResource(const gfx::RenderbufferPixelType type, const Size size) { + MLN_TRACE_FUNC(); + RenderbufferID id = 0; MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id)); + MLN_TRACE_ALLOC_RT(id, renderBufferByteSize(type, size)); // NOLINTNEXTLINE(performance-move-const-arg) UniqueRenderbuffer renderbuffer{std::move(id), {this}}; @@ -305,12 +352,16 @@ std::unique_ptr Context::createRenderbufferResource(c MBGL_CHECK_ERROR( glRenderbufferStorage(GL_RENDERBUFFER, Enum::to(type), size.width, size.height)); bindRenderbuffer = 0; + return std::make_unique(std::move(renderbuffer)); } std::unique_ptr Context::readFramebuffer(const Size size, const gfx::TexturePixelType format, const bool flip) { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + const size_t stride = size.width * (format == gfx::TexturePixelType::RGBA ? 4 : 1); auto data = std::make_unique(stride * size.height); @@ -337,6 +388,8 @@ std::unique_ptr Context::readFramebuffer(const Size size, namespace { void checkFramebuffer() { + MLN_TRACE_FUNC(); + GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER)); if (status != GL_FRAMEBUFFER_COMPLETE) { switch (status) { @@ -368,6 +421,9 @@ void checkFramebuffer() { } void bindDepthStencilRenderbuffer(const gfx::Renderbuffer& depthStencil) { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + auto& depthStencilResource = depthStencil.getResource(); #ifdef GL_DEPTH_STENCIL_ATTACHMENT MBGL_CHECK_ERROR(glFramebufferRenderbuffer( @@ -385,6 +441,8 @@ void bindDepthStencilRenderbuffer(const gfx::Renderbuffer& color, const gfx::Renderbuffer& depthStencil) { + MLN_TRACE_FUNC(); + if (color.getSize() != depthStencil.getSize()) { throw std::runtime_error("Renderbuffer size mismatch"); } @@ -400,6 +458,8 @@ Framebuffer Context::createFramebuffer( } Framebuffer Context::createFramebuffer(const gfx::Renderbuffer& color) { + MLN_TRACE_FUNC(); + auto fbo = createFramebuffer(); bindFramebuffer = fbo; auto& colorResource = color.getResource(); @@ -411,6 +471,8 @@ Framebuffer Context::createFramebuffer(const gfx::Renderbuffer& depthStencil) { + MLN_TRACE_FUNC(); + if (color.size != depthStencil.getSize()) { throw std::runtime_error("Renderbuffer size mismatch"); } @@ -424,6 +486,8 @@ Framebuffer Context::createFramebuffer( } Framebuffer Context::createFramebuffer(const gfx::Texture& color) { + MLN_TRACE_FUNC(); + auto fbo = createFramebuffer(); bindFramebuffer = fbo; MBGL_CHECK_ERROR(glFramebufferTexture2D( @@ -434,6 +498,7 @@ Framebuffer Context::createFramebuffer(const gfx::Texture& color) { Framebuffer Context::createFramebuffer(const gfx::Texture& color, const gfx::Renderbuffer& depth) { + MLN_TRACE_FUNC(); if (color.size != depth.getSize()) { throw std::runtime_error("Renderbuffer size mismatch"); } @@ -451,14 +516,20 @@ Framebuffer Context::createFramebuffer(const gfx::Texture& color, std::unique_ptr Context::createOffscreenTexture(const Size size, const gfx::TextureChannelDataType type) { + MLN_TRACE_FUNC(); + return std::make_unique(*this, size, type); } std::unique_ptr Context::createDrawScopeResource() { + MLN_TRACE_FUNC(); + return std::make_unique(createVertexArray()); } void Context::reset() { + MLN_TRACE_FUNC(); + std::copy(pooledTextures.begin(), pooledTextures.end(), std::back_inserter(abandonedTextures)); pooledTextures.resize(0); performCleanup(); @@ -466,6 +537,9 @@ void Context::reset() { #if MLN_DRAWABLE_RENDERER void Context::resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + // Reset GL state to a known state so the CustomLayer always has a clean slate. bindVertexArray = value::BindVertexArray::Default; setDepthMode(depthMode); @@ -478,6 +552,8 @@ bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, const void* data, std::size_t size, bool persistent) { + MLN_TRACE_FUNC(); + if (buffer) { buffer->update(data, size); return false; @@ -488,6 +564,8 @@ bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, } void Context::bindGlobalUniformBuffers(gfx::RenderPass&) const noexcept { + MLN_TRACE_FUNC(); + for (size_t id = 0; id < globalUniformBuffers.allocatedSize(); id++) { const auto& globalUniformBuffer = globalUniformBuffers.get(id); if (!globalUniformBuffer) continue; @@ -502,6 +580,8 @@ void Context::bindGlobalUniformBuffers(gfx::RenderPass&) const noexcept { } void Context::unbindGlobalUniformBuffers(gfx::RenderPass&) const noexcept { + MLN_TRACE_FUNC(); + for (size_t id = 0; id < globalUniformBuffers.allocatedSize(); id++) { const auto& globalUniformBuffer = globalUniformBuffers.get(id); if (!globalUniformBuffer) continue; @@ -512,6 +592,8 @@ void Context::unbindGlobalUniformBuffers(gfx::RenderPass&) const noexcept { #endif void Context::setDirtyState() { + MLN_TRACE_FUNC(); + // Note: does not set viewport/scissorTest/bindFramebuffer to dirty // since they are handled separately in the view object. stencilFunc.setDirty(); @@ -550,14 +632,20 @@ void Context::setDirtyState() { #if MLN_DRAWABLE_RENDERER gfx::UniqueDrawableBuilder Context::createDrawableBuilder(std::string name) { + MLN_TRACE_FUNC(); + return std::make_unique(std::move(name)); } gfx::UniformBufferPtr Context::createUniformBuffer(const void* data, std::size_t size, bool /*persistent*/) { + MLN_TRACE_FUNC(); + return std::make_shared(data, size, *uboAllocator); } gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders, const std::string& name) { + MLN_TRACE_FUNC(); + auto shaderGroup = shaders.getShaderGroup(name); if (!shaderGroup) { return nullptr; @@ -566,22 +654,32 @@ gfx::ShaderProgramBasePtr Context::getGenericShader(gfx::ShaderRegistry& shaders } TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) { + MLN_TRACE_FUNC(); + return std::make_shared(layerIndex, initialCapacity, std::move(name)); } LayerGroupPtr Context::createLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) { + MLN_TRACE_FUNC(); + return std::make_shared(layerIndex, initialCapacity, std::move(name)); } gfx::Texture2DPtr Context::createTexture2D() { + MLN_TRACE_FUNC(); + return std::make_shared(*this); } RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { + MLN_TRACE_FUNC(); + return std::make_shared(*this, size, type); } Framebuffer Context::createFramebuffer(const gfx::Texture2D& color) { + MLN_TRACE_FUNC(); + auto fbo = createFramebuffer(); bindFramebuffer = fbo; MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, @@ -600,6 +698,9 @@ gfx::VertexAttributeArrayPtr Context::createVertexAttributeArray() const { #endif void Context::clear(std::optional color, std::optional depth, std::optional stencil) { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + GLbitfield mask = 0; if (color) { @@ -687,6 +788,8 @@ void Context::setColorMode(const gfx::ColorMode& color) { } std::unique_ptr Context::createCommandEncoder() { + MLN_TRACE_FUNC(); + backend.updateAssumedState(); if (backend.contextIsShared()) { setDirtyState(); @@ -695,6 +798,9 @@ std::unique_ptr Context::createCommandEncoder() { } void Context::finish() { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + MBGL_CHECK_ERROR(glFinish()); } @@ -705,6 +811,9 @@ std::shared_ptr Context::getCurrentFrameFence() const { #endif void Context::draw(const gfx::DrawMode& drawMode, std::size_t indexOffset, std::size_t indexLength) { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + switch (drawMode.type) { case gfx::DrawModeType::Points: break; @@ -726,6 +835,8 @@ void Context::draw(const gfx::DrawMode& drawMode, std::size_t indexOffset, std:: } void Context::performCleanup() { + MLN_TRACE_FUNC(); + // TODO: Find a better way to unbind VAOs after we're done with them without // introducing unnecessary bind(0)/bind(N) sequences. { @@ -806,6 +917,9 @@ void Context::performCleanup() { } void Context::reduceMemoryUsage() { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + performCleanup(); // Ensure that all pending actions are executed to ensure that they happen @@ -824,6 +938,9 @@ void Context::visualizeDepthBuffer([[maybe_unused]] const float depthRangeSize) #endif void Context::clearStencilBuffer(const int32_t bits) { + MLN_TRACE_FUNC(); + MLN_TRACE_FUNC_GL(); + MBGL_CHECK_ERROR(glClearStencil(bits)); MBGL_CHECK_ERROR(glClear(GL_STENCIL_BUFFER_BIT)); diff --git a/src/mbgl/gl/debugging_extension.hpp b/src/mbgl/gl/debugging_extension.hpp index 89b23a45a..f7295a51b 100644 --- a/src/mbgl/gl/debugging_extension.hpp +++ b/src/mbgl/gl/debugging_extension.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 diff --git a/src/mbgl/gl/fence.cpp b/src/mbgl/gl/fence.cpp index dc8324549..350939e6c 100644 --- a/src/mbgl/gl/fence.cpp +++ b/src/mbgl/gl/fence.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -25,17 +26,23 @@ std::string glErrors() { Fence::Fence() {} Fence::~Fence() { + MLN_TRACE_FUNC(); + if (fence) { glDeleteSync(fence); } } void Fence::insert() noexcept { + MLN_TRACE_FUNC(); + assert(!fence); fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); } bool Fence::isSignaled() const { + MLN_TRACE_FUNC(); + if (!fence) { return false; } diff --git a/src/mbgl/gl/index_buffer_resource.cpp b/src/mbgl/gl/index_buffer_resource.cpp index 616fbf5e6..c5b558ecd 100644 --- a/src/mbgl/gl/index_buffer_resource.cpp +++ b/src/mbgl/gl/index_buffer_resource.cpp @@ -1,10 +1,18 @@ #include #include +#include namespace mbgl { namespace gl { +IndexBufferResource::IndexBufferResource(UniqueBuffer&& buffer_, int byteSize_) + : buffer(std::move(buffer_)), + byteSize(byteSize_) { + MLN_TRACE_ALLOC_INDEX_BUFFER(buffer.get(), byteSize); +} + IndexBufferResource::~IndexBufferResource() noexcept { + MLN_TRACE_FREE_INDEX_BUFFER(buffer.get()); auto& stats = buffer.get_deleter().context.renderingStats(); stats.memIndexBuffers -= byteSize; assert(stats.memIndexBuffers >= 0); diff --git a/src/mbgl/gl/index_buffer_resource.hpp b/src/mbgl/gl/index_buffer_resource.hpp index f3f42d3ef..5cbb20239 100644 --- a/src/mbgl/gl/index_buffer_resource.hpp +++ b/src/mbgl/gl/index_buffer_resource.hpp @@ -8,9 +8,7 @@ namespace gl { class IndexBufferResource : public gfx::IndexBufferResource { public: - IndexBufferResource(UniqueBuffer&& buffer_, int byteSize_) - : buffer(std::move(buffer_)), - byteSize(byteSize_) {} + IndexBufferResource(UniqueBuffer&& buffer_, int byteSize_); ~IndexBufferResource() noexcept override; UniqueBuffer buffer; diff --git a/src/mbgl/gl/renderbuffer_resource.cpp b/src/mbgl/gl/renderbuffer_resource.cpp new file mode 100644 index 000000000..372aadb58 --- /dev/null +++ b/src/mbgl/gl/renderbuffer_resource.cpp @@ -0,0 +1,13 @@ + +#include +#include + +namespace mbgl { +namespace gl { + +RenderbufferResource::~RenderbufferResource() noexcept { + MLN_TRACE_FREE_RT(renderbuffer.get()); +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/renderbuffer_resource.hpp b/src/mbgl/gl/renderbuffer_resource.hpp index dc701a480..396ec138a 100644 --- a/src/mbgl/gl/renderbuffer_resource.hpp +++ b/src/mbgl/gl/renderbuffer_resource.hpp @@ -11,7 +11,7 @@ public: explicit RenderbufferResource(UniqueRenderbuffer renderbuffer_) : renderbuffer(std::move(renderbuffer_)) {} - ~RenderbufferResource() noexcept override = default; + ~RenderbufferResource() noexcept override; UniqueRenderbuffer renderbuffer; }; diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index c1b61afc1..f3aefb132 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #if MLN_DRAWABLE_RENDERER @@ -19,6 +20,8 @@ RendererBackend::RendererBackend(const gfx::ContextMode contextMode_) : gfx::RendererBackend(contextMode_) {} std::unique_ptr RendererBackend::createContext() { + MLN_TRACE_FUNC(); + auto result = std::make_unique(*this); result->enableDebugging(); result->initializeExtensions(std::bind(&RendererBackend::getExtensionFunctionPointer, this, std::placeholders::_1)); @@ -26,10 +29,14 @@ std::unique_ptr RendererBackend::createContext() { } PremultipliedImage RendererBackend::readFramebuffer(const Size& size) { + MLN_TRACE_FUNC(); + return getContext().readFramebuffer(size); } void RendererBackend::assumeFramebufferBinding(const gl::FramebufferID fbo) { + MLN_TRACE_FUNC(); + getContext().bindFramebuffer.setCurrentValue(fbo); if (fbo != ImplicitFramebufferBinding) { assert(gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); @@ -37,20 +44,28 @@ void RendererBackend::assumeFramebufferBinding(const gl::FramebufferID fbo) { } void RendererBackend::assumeViewport(int32_t x, int32_t y, const Size& size) { + MLN_TRACE_FUNC(); + getContext().viewport.setCurrentValue({x, y, size}); assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); } void RendererBackend::assumeScissorTest(bool enabled) { + MLN_TRACE_FUNC(); + getContext().scissorTest.setCurrentValue(enabled); assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue()); } bool RendererBackend::implicitFramebufferBound() { + MLN_TRACE_FUNC(); + return getContext().bindFramebuffer.getCurrentValue() == ImplicitFramebufferBinding; } void RendererBackend::setFramebufferBinding(const gl::FramebufferID fbo) { + MLN_TRACE_FUNC(); + getContext().bindFramebuffer = fbo; if (fbo != ImplicitFramebufferBinding) { assert(gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); @@ -58,11 +73,15 @@ void RendererBackend::setFramebufferBinding(const gl::FramebufferID fbo) { } void RendererBackend::setViewport(int32_t x, int32_t y, const Size& size) { + MLN_TRACE_FUNC(); + getContext().viewport = {x, y, size}; assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); } void RendererBackend::setScissorTest(bool enabled) { + MLN_TRACE_FUNC(); + getContext().scissorTest = enabled; assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue()); } @@ -76,6 +95,8 @@ RendererBackend::~RendererBackend() = default; /// @param programParameters ProgramParameters used to initialize each instance template void registerTypes(gfx::ShaderRegistry& registry, const ProgramParameters& programParameters) { + MLN_TRACE_FUNC(); + /// The following fold expression will create a shader for every type /// in the parameter pack and register it with the shader registry. @@ -93,6 +114,8 @@ void registerTypes(gfx::ShaderRegistry& registry, const ProgramParameters& progr } void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramParameters& programParameters) { + MLN_TRACE_FUNC(); + registerTypes #include +#include namespace mbgl { namespace gl { @@ -31,8 +32,15 @@ static int channelStorageSize(gfx::TextureChannelDataType type) { } } +TextureResource::TextureResource(UniqueTexture&& texture_, int byteSize_) + : texture(std::move(texture_)), + byteSize(byteSize_) { + MLN_TRACE_ALLOC_TEXTURE(texture.get(), byteSize); +} + TextureResource::~TextureResource() noexcept { auto& stats = texture.get_deleter().context->renderingStats(); + MLN_TRACE_FREE_TEXTURE(texture.get()); stats.memTextures -= byteSize; assert(stats.memTextures >= 0); } diff --git a/src/mbgl/gl/texture_resource.hpp b/src/mbgl/gl/texture_resource.hpp index 100beadb6..65d6e2dcf 100644 --- a/src/mbgl/gl/texture_resource.hpp +++ b/src/mbgl/gl/texture_resource.hpp @@ -8,9 +8,7 @@ namespace gl { class TextureResource : public gfx::TextureResource { public: - TextureResource(UniqueTexture&& texture_, int byteSize_) - : texture(std::move(texture_)), - byteSize(byteSize_) {} + TextureResource(UniqueTexture&& texture_, int byteSize_); ~TextureResource() noexcept override; static int getStorageSize(const Size& size, gfx::TexturePixelType format, gfx::TextureChannelDataType type); diff --git a/src/mbgl/gl/timestamp_query_extension.cpp b/src/mbgl/gl/timestamp_query_extension.cpp new file mode 100644 index 000000000..fba993d72 --- /dev/null +++ b/src/mbgl/gl/timestamp_query_extension.cpp @@ -0,0 +1,118 @@ + +#include + +#include +#include + +namespace mbgl { +namespace gl { +namespace extension { + +using namespace platform; + +namespace { + +struct TimestampQueryLoader { + TimestampQueryLoader(const GlContexsLoader &loadExtension) + : glGenQueries(loadExtension({{"GL_EXT_disjoint_timer_query", "glGenQueries"}})), + glDeleteQueries(loadExtension({{"GL_EXT_disjoint_timer_query", "glDeleteQueries"}})), + glIsQuery(loadExtension({{"GL_EXT_disjoint_timer_query", "glIsQuery"}})), + glBeginQuery(loadExtension({{"GL_EXT_disjoint_timer_query", "glBeginQuery"}})), + glEndQuery(loadExtension({{"GL_EXT_disjoint_timer_query", "glEndQuery"}})), + glQueryCounter(loadExtension({{"GL_EXT_disjoint_timer_query", "glQueryCounter"}})), + glGetQueryiv(loadExtension({{"GL_EXT_disjoint_timer_query", "glGetQueryiv"}})), + glGetQueryObjectiv(loadExtension({{"GL_EXT_disjoint_timer_query", "glGetQueryObjectiv"}})), + glGetQueryObjectuiv(loadExtension({{"GL_EXT_disjoint_timer_query", "glGetQueryObjectuiv"}})), + glGetQueryObjecti64v(loadExtension({{"GL_EXT_disjoint_timer_query", "glGetQueryObjecti64v"}})), + glGetQueryObjectui64v(loadExtension({{"GL_EXT_disjoint_timer_query", "glGetQueryObjectui64v"}})), + glGetInteger64v(loadExtension({{"GL_EXT_disjoint_timer_query", "glGetInteger64v"}})) {} + + ExtensionFunction glGenQueries; + ExtensionFunction glDeleteQueries; + ExtensionFunction glIsQuery; + ExtensionFunction glBeginQuery; + ExtensionFunction glEndQuery; + ExtensionFunction glQueryCounter; + ExtensionFunction glGetQueryiv; + ExtensionFunction glGetQueryObjectiv; + ExtensionFunction glGetQueryObjectuiv; + ExtensionFunction glGetQueryObjecti64v; + ExtensionFunction glGetQueryObjectui64v; + ExtensionFunction glGetInteger64v; +}; + +std::unique_ptr &singleton() { + static std::unique_ptr loader; + return loader; +} + +} // namespace + +void glGenQueries(GLsizei n, GLuint *ids) { + assert(singleton() && singleton()->glGenQueries); + return singleton()->glGenQueries(n, ids); +} + +void glDeleteQueries(GLsizei n, const GLuint *ids) { + assert(singleton() && singleton()->glDeleteQueries); + return singleton()->glDeleteQueries(n, ids); +} + +GLboolean glIsQuery(GLuint id) { + assert(singleton() && singleton()->glIsQuery); + return singleton()->glIsQuery(id); +} + +void glBeginQuery(GLenum target, GLuint id) { + assert(singleton() && singleton()->glBeginQuery); + return singleton()->glBeginQuery(target, id); +} + +void glEndQuery(GLenum target) { + assert(singleton() && singleton()->glEndQuery); + return singleton()->glEndQuery(target); +} + +void glQueryCounter(GLuint id, GLenum target) { + assert(singleton() && singleton()->glQueryCounter); + return singleton()->glQueryCounter(id, target); +} + +void glGetQueryiv(GLenum target, GLenum pname, GLint *params) { + assert(singleton() && singleton()->glGetQueryiv); + return singleton()->glGetQueryiv(target, pname, params); +} + +void glGetQueryObjectiv(GLuint id, GLenum pname, GLint *params) { + assert(singleton() && singleton()->glGetQueryObjectiv); + return singleton()->glGetQueryObjectiv(id, pname, params); +} + +void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) { + assert(singleton() && singleton()->glGetQueryObjectuiv); + return singleton()->glGetQueryObjectuiv(id, pname, params); +} + +void glGetQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) { + assert(singleton() && singleton()->glGetQueryObjecti64v); + return singleton()->glGetQueryObjecti64v(id, pname, params); +} + +void glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) { + assert(singleton() && singleton()->glGetQueryObjectui64v); + return singleton()->glGetQueryObjectui64v(id, pname, params); +} + +void glGetInteger64v(GLenum pname, GLint64 *data) { + assert(singleton() && singleton()->glGetInteger64v); + return singleton()->glGetInteger64v(pname, data); +} + +void loadTimeStampQueryExtension(const GlContexsLoader &loadExtension) { + auto &loader = singleton(); + loader = std::make_unique(loadExtension); +} + +} // namespace extension +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/timestamp_query_extension.hpp b/src/mbgl/gl/timestamp_query_extension.hpp new file mode 100644 index 000000000..411187bc4 --- /dev/null +++ b/src/mbgl/gl/timestamp_query_extension.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#include + +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_GPU_DISJOINT 0x8FBB + +namespace mbgl { +namespace gl { +namespace extension { + +using namespace platform; + +void glGenQueries(GLsizei n, GLuint *ids); +void glDeleteQueries(GLsizei n, const GLuint *ids); +GLboolean glIsQuery(GLuint id); +void glBeginQuery(GLenum target, GLuint id); +void glEndQuery(GLenum target); +void glQueryCounter(GLuint id, GLenum target); +void glGetQueryiv(GLenum target, GLenum pname, GLint *params); +void glGetQueryObjectiv(GLuint id, GLenum pname, GLint *params); +void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params); +void glGetQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params); +void glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params); +void glGetInteger64v(GLenum pname, GLint64 *data); + +using GlContexsLoader = std::function>)>; + +void loadTimeStampQueryExtension(const GlContexsLoader &loadExtension); + +} // namespace extension +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/uniform_buffer_gl.cpp b/src/mbgl/gl/uniform_buffer_gl.cpp index 6c6ab4adc..e678976d3 100644 --- a/src/mbgl/gl/uniform_buffer_gl.cpp +++ b/src/mbgl/gl/uniform_buffer_gl.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include +#include #include #include @@ -12,9 +14,25 @@ namespace gl { using namespace platform; +namespace { + +// Currently unique IDs for constant buffers are only used when Tracy profiling is enabled +#ifdef MLN_TRACY_ENABLE +int64_t generateDebugId() noexcept { + static std::atomic_int64_t counter(0); + return ++counter; +} +#endif + +} // namespace + UniformBufferGL::UniformBufferGL(const void* data_, std::size_t size_, IBufferAllocator& allocator_) : UniformBuffer(size_), +#ifdef MLN_TRACY_ENABLE + uniqueDebugId(generateDebugId()), +#endif managedBuffer(allocator_, this) { + MLN_TRACE_ALLOC_CONST_BUFFER(uniqueDebugId, size_); if (size_ > managedBuffer.allocator.pageSize()) { // Buffer is very large, won't fit in the provided allocator MBGL_CHECK_ERROR(glGenBuffers(1, &localID)); @@ -30,15 +48,25 @@ UniformBufferGL::UniformBufferGL(const void* data_, std::size_t size_, IBufferAl UniformBufferGL::UniformBufferGL(UniformBufferGL&& rhs) noexcept : UniformBuffer(rhs.size), +#ifdef MLN_TRACY_ENABLE + uniqueDebugId(rhs.uniqueDebugId), +#endif isManagedAllocation(rhs.isManagedAllocation), localID(rhs.localID), managedBuffer(std::move(rhs.managedBuffer)) { managedBuffer.setOwner(this); +#ifdef MLN_TRACY_ENABLE + rhs.uniqueDebugId = -1; +#endif } UniformBufferGL::UniformBufferGL(const UniformBufferGL& other) : UniformBuffer(other), +#ifdef MLN_TRACY_ENABLE + uniqueDebugId(generateDebugId()), +#endif managedBuffer(other.managedBuffer.allocator, this) { + MLN_TRACE_ALLOC_CONST_BUFFER(uniqueDebugId, other.size); managedBuffer.setOwner(this); if (other.isManagedAllocation) { managedBuffer.allocate(other.managedBuffer.getContents().data(), other.size); @@ -52,6 +80,10 @@ UniformBufferGL::UniformBufferGL(const UniformBufferGL& other) } UniformBufferGL::~UniformBufferGL() { +#ifdef MLN_TRACY_ENABLE + assert(uniqueDebugId > 0); +#endif + MLN_TRACE_FREE_CONST_BUFFER(uniqueDebugId); if (isManagedAllocation) { return; } diff --git a/src/mbgl/gl/vertex_buffer_resource.cpp b/src/mbgl/gl/vertex_buffer_resource.cpp index f44464fdb..d1d71bb74 100644 --- a/src/mbgl/gl/vertex_buffer_resource.cpp +++ b/src/mbgl/gl/vertex_buffer_resource.cpp @@ -1,10 +1,18 @@ #include #include +#include namespace mbgl { namespace gl { +VertexBufferResource::VertexBufferResource(UniqueBuffer&& buffer_, int byteSize_) + : buffer(std::move(buffer_)), + byteSize(byteSize_) { + MLN_TRACE_ALLOC_VERTEX_BUFFER(buffer.get(), byteSize); +} + VertexBufferResource::~VertexBufferResource() noexcept { + MLN_TRACE_FREE_VERTEX_BUFFER(buffer.get()); auto& stats = buffer.get_deleter().context.renderingStats(); stats.memVertexBuffers -= byteSize; assert(stats.memVertexBuffers >= 0); diff --git a/src/mbgl/gl/vertex_buffer_resource.hpp b/src/mbgl/gl/vertex_buffer_resource.hpp index efa373e5e..1bd48ed94 100644 --- a/src/mbgl/gl/vertex_buffer_resource.hpp +++ b/src/mbgl/gl/vertex_buffer_resource.hpp @@ -8,9 +8,7 @@ namespace gl { class VertexBufferResource : public gfx::VertexBufferResource { public: - VertexBufferResource(UniqueBuffer&& buffer_, int byteSize_) - : buffer(std::move(buffer_)), - byteSize(byteSize_) {} + VertexBufferResource(UniqueBuffer&& buffer_, int byteSize_); ~VertexBufferResource() noexcept override; UniqueBuffer buffer; diff --git a/src/mbgl/renderer/backend_scope.cpp b/src/mbgl/renderer/backend_scope.cpp index b34fde222..0ce476604 100644 --- a/src/mbgl/renderer/backend_scope.cpp +++ b/src/mbgl/renderer/backend_scope.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -22,6 +23,8 @@ BackendScope::BackendScope(RendererBackend& backend_, ScopeType scopeType_) nextScope(nullptr), backend(backend_), scopeType(scopeType_) { + MLN_TRACE_FUNC(); + if (priorScope) { assert(priorScope->nextScope == nullptr); priorScope->nextScope = this; @@ -34,6 +37,8 @@ BackendScope::BackendScope(RendererBackend& backend_, ScopeType scopeType_) } BackendScope::~BackendScope() { + MLN_TRACE_FUNC(); + assert(nextScope == nullptr); deactivate(); @@ -48,6 +53,8 @@ BackendScope::~BackendScope() { } void BackendScope::activate() { + MLN_TRACE_FUNC(); + if (scopeType == ScopeType::Explicit && !(priorScope && this->backend == priorScope->backend) && !(nextScope && this->backend == nextScope->backend)) { // Only activate when set to Explicit and diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 376bc8f62..431e7301d 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,8 @@ public: updateSymbolOpacities(updateSymbolOpacities_) {} void prepare() override { + MLN_TRACE_FUNC(); + for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) { placement->updateLayerBuckets(*it, parameters->transformParams.state, updateSymbolOpacities); } @@ -128,6 +131,8 @@ RenderOrchestrator::RenderOrchestrator(bool backgroundLayerAsColor_, const std:: } RenderOrchestrator::~RenderOrchestrator() { + MLN_TRACE_FUNC(); + if (contextLost) { // Signal all RenderLayers that the context was lost // before cleaning up. At the moment, only CustomLayer is @@ -158,6 +163,8 @@ void RenderOrchestrator::setObserver(RendererObserver* observer_) { std::unique_ptr RenderOrchestrator::createRenderTree( const std::shared_ptr& updateParameters) { + MLN_TRACE_FUNC(); + const auto startTime = util::MonotonicTimer::now().count(); const bool isMapModeContinuous = updateParameters->mode == MapMode::Continuous; @@ -534,6 +541,8 @@ std::unique_ptr RenderOrchestrator::createRenderTree( std::vector RenderOrchestrator::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const { + MLN_TRACE_FUNC(); + std::unordered_map layers; if (options.layerIDs) { for (const auto& layerID : *options.layerIDs) { @@ -554,6 +563,8 @@ void RenderOrchestrator::queryRenderedSymbols(std::unordered_map& layers, const RenderedQueryOptions& options) const { + MLN_TRACE_FUNC(); + const auto hasCrossTileIndex = [](const auto& pair) { return pair.second->baseImpl->getTypeInfo()->crossTileIndex == style::LayerTypeInfo::CrossTileIndex::Required; }; @@ -602,6 +613,8 @@ std::vector RenderOrchestrator::queryRenderedFeatures( const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::unordered_map& layers) const { + MLN_TRACE_FUNC(); + std::unordered_set sourceIDs; std::unordered_map filteredLayers; for (const auto& pair : layers) { @@ -651,6 +664,8 @@ std::vector RenderOrchestrator::queryRenderedFeatures( } std::vector RenderOrchestrator::queryShapeAnnotations(const ScreenLineString& geometry) const { + MLN_TRACE_FUNC(); + assert(LayerManager::annotationsEnabled); std::unordered_map shapeAnnotationLayers; RenderedQueryOptions options; @@ -671,6 +686,8 @@ std::vector RenderOrchestrator::queryShapeAnnotations(const ScreenLineS std::vector RenderOrchestrator::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const { + MLN_TRACE_FUNC(); + const RenderSource* source = getRenderSource(sourceID); if (!source) return {}; @@ -683,6 +700,8 @@ FeatureExtensionValue RenderOrchestrator::queryFeatureExtensions( const std::string& extension, const std::string& extensionField, const std::optional>& args) const { + MLN_TRACE_FUNC(); + if (RenderSource* renderSource = getRenderSource(sourceID)) { return renderSource->queryFeatureExtensions(feature, extension, extensionField, args); } @@ -693,6 +712,8 @@ void RenderOrchestrator::setFeatureState(const std::string& sourceID, const std::optional& sourceLayerID, const std::string& featureID, const FeatureState& state) { + MLN_TRACE_FUNC(); + if (RenderSource* renderSource = getRenderSource(sourceID)) { renderSource->setFeatureState(sourceLayerID, featureID, state); } @@ -702,6 +723,8 @@ void RenderOrchestrator::getFeatureState(FeatureState& state, const std::string& sourceID, const std::optional& sourceLayerID, const std::string& featureID) const { + MLN_TRACE_FUNC(); + if (RenderSource* renderSource = getRenderSource(sourceID)) { renderSource->getFeatureState(state, sourceLayerID, featureID); } @@ -711,12 +734,16 @@ void RenderOrchestrator::removeFeatureState(const std::string& sourceID, const std::optional& sourceLayerID, const std::optional& featureID, const std::optional& stateKey) { + MLN_TRACE_FUNC(); + if (RenderSource* renderSource = getRenderSource(sourceID)) { renderSource->removeFeatureState(sourceLayerID, featureID, stateKey); } } void RenderOrchestrator::reduceMemoryUse() { + MLN_TRACE_FUNC(); + filteredLayersForSource.shrink_to_fit(); for (const auto& entry : renderSources) { entry.second->reduceMemoryUse(); @@ -726,6 +753,8 @@ void RenderOrchestrator::reduceMemoryUse() { } void RenderOrchestrator::dumpDebugLogs() { + MLN_TRACE_FUNC(); + for (const auto& entry : renderSources) { entry.second->dumpDebugLogs(); } @@ -781,6 +810,8 @@ bool RenderOrchestrator::hasTransitions(TimePoint timePoint) const { } bool RenderOrchestrator::isLoaded() const { + MLN_TRACE_FUNC(); + // do the simple boolean check before iterating over all the tiles in all the sources if (!imageManager->isLoaded()) { return false; @@ -796,6 +827,8 @@ bool RenderOrchestrator::isLoaded() const { } void RenderOrchestrator::clearData() { + MLN_TRACE_FUNC(); + if (!sourceImpls->empty()) sourceImpls = makeMutable>>(); if (!layerImpls->empty()) layerImpls = makeMutable>>(); if (!imageImpls->empty()) imageImpls = makeMutable>>(); @@ -830,6 +863,8 @@ void RenderOrchestrator::addChanges(UniqueChangeRequestVec& changes) { } void RenderOrchestrator::updateLayerIndex(LayerGroupBasePtr layerGroup, const int32_t newIndex) { + MLN_TRACE_FUNC(); + if (!layerGroup || layerGroup->getLayerIndex() == newIndex) { return; } @@ -847,6 +882,8 @@ void RenderOrchestrator::updateLayerIndex(LayerGroupBasePtr layerGroup, const in } bool RenderOrchestrator::addLayerGroup(LayerGroupBasePtr layerGroup) { + MLN_TRACE_FUNC(); + const auto index = layerGroup->getLayerIndex(); const auto range = layerGroupsByLayerIndex.equal_range(index); bool found = false; @@ -867,6 +904,8 @@ bool RenderOrchestrator::addLayerGroup(LayerGroupBasePtr layerGroup) { } bool RenderOrchestrator::removeLayerGroup(const LayerGroupBasePtr& layerGroup) { + MLN_TRACE_FUNC(); + if (!layerGroup) { return false; } @@ -885,6 +924,8 @@ size_t RenderOrchestrator::numLayerGroups() const noexcept { } int32_t RenderOrchestrator::maxLayerIndex() const { + MLN_TRACE_FUNC(); + if (!layerGroupsByLayerIndex.empty()) { assert(layerGroupsByLayerIndex.crbegin()->first == layerGroupsByLayerIndex.crbegin()->second->getLayerIndex()); return layerGroupsByLayerIndex.crbegin()->first; @@ -897,6 +938,8 @@ void RenderOrchestrator::updateLayers(gfx::ShaderRegistry& shaders, const TransformState& state, const std::shared_ptr& updateParameters, const RenderTree& renderTree) { + MLN_TRACE_FUNC(); + const bool isMapModeContinuous = updateParameters->mode == MapMode::Continuous; const auto transitionOptions = isMapModeContinuous ? updateParameters->transitionOptions : style::TransitionOptions(); @@ -957,6 +1000,8 @@ void RenderOrchestrator::updateDebugLayerGroups(const RenderTree& renderTree, Pa void RenderOrchestrator::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) { + MLN_TRACE_FUNC(); + Log::Error(Event::Style, "Failed to load glyph range " + std::to_string(glyphRange.first) + "-" + std::to_string(glyphRange.second) + " for font stack " + fontStackToString(fontStack) + ": " + @@ -965,6 +1010,8 @@ void RenderOrchestrator::onGlyphsError(const FontStack& fontStack, } void RenderOrchestrator::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) { + MLN_TRACE_FUNC(); + Log::Error(Event::Style, "Failed to load tile " + util::toString(tileID) + " for source " + source.baseImpl->id + ": " + util::toString(error)); @@ -972,14 +1019,20 @@ void RenderOrchestrator::onTileError(RenderSource& source, const OverscaledTileI } void RenderOrchestrator::onTileChanged(RenderSource&, const OverscaledTileID&) { + MLN_TRACE_FUNC(); + observer->onInvalidate(); } void RenderOrchestrator::onStyleImageMissing(const std::string& id, const std::function& done) { + MLN_TRACE_FUNC(); + observer->onStyleImageMissing(id, done); } void RenderOrchestrator::onRemoveUnusedStyleImages(const std::vector& unusedImageIDs) { + MLN_TRACE_FUNC(); + observer->onRemoveUnusedStyleImages(unusedImageIDs); } diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp index 8fb96a85a..53a6072f1 100644 --- a/src/mbgl/renderer/renderer.cpp +++ b/src/mbgl/renderer/renderer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace mbgl { @@ -29,6 +30,7 @@ void Renderer::setObserver(RendererObserver* observer) { } void Renderer::render(const std::shared_ptr& updateParameters) { + MLN_TRACE_FUNC(); assert(updateParameters); if (auto renderTree = impl->orchestrator.createRenderTree(updateParameters)) { renderTree->prepare(); diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 2477b1d63..7673b5268 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #if MLN_DRAWABLE_RENDERER #include @@ -73,6 +74,7 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) { void Renderer::Impl::render(const RenderTree& renderTree, [[maybe_unused]] const std::shared_ptr& updateParameters) { + MLN_TRACE_FUNC(); auto& context = backend.getContext(); #if MLN_RENDER_BACKEND_METAL if constexpr (EnableMetalCapture) { @@ -539,6 +541,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, } frameCount += 1; + MLN_END_FRAME(); } void Renderer::Impl::reduceMemoryUse() { diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 880a9b1ba..afbc95812 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -15,18 +16,26 @@ Style::Style(std::shared_ptr fileSource, float pixelRatio) Style::~Style() = default; void Style::loadJSON(const std::string& json) { + MLN_TRACE_FUNC(); + impl->loadJSON(json); } void Style::loadURL(const std::string& url) { + MLN_TRACE_FUNC(); + impl->loadURL(url); } std::string Style::getJSON() const { + MLN_TRACE_FUNC(); + return impl->getJSON(); } std::string Style::getURL() const { + MLN_TRACE_FUNC(); + return impl->getURL(); } @@ -35,14 +44,20 @@ std::string Style::getName() const { } CameraOptions Style::getDefaultCamera() const { + MLN_TRACE_FUNC(); + return impl->getDefaultCamera(); } TransitionOptions Style::getTransitionOptions() const { + MLN_TRACE_FUNC(); + return impl->getTransitionOptions(); } void Style::setTransitionOptions(const TransitionOptions& options) { + MLN_TRACE_FUNC(); + impl->mutated = true; impl->setTransitionOptions(options); } @@ -61,73 +76,103 @@ const Light* Style::getLight() const { } std::optional Style::getImage(const std::string& name) const { + MLN_TRACE_FUNC(); + auto image = impl->getImage(name); if (!image) return std::nullopt; return style::Image(std::move(*image)); } void Style::addImage(std::unique_ptr image) { + MLN_TRACE_FUNC(); + impl->mutated = true; impl->addImage(std::move(image)); } void Style::removeImage(const std::string& name) { + MLN_TRACE_FUNC(); + impl->mutated = true; impl->removeImage(name); } std::vector Style::getSources() { + MLN_TRACE_FUNC(); + impl->mutated = true; return impl->getSources(); } std::vector Style::getSources() const { + MLN_TRACE_FUNC(); + return const_cast(*impl).getSources(); } Source* Style::getSource(const std::string& id) { + MLN_TRACE_FUNC(); + impl->mutated = true; return impl->getSource(id); } const Source* Style::getSource(const std::string& id) const { + MLN_TRACE_FUNC(); + return impl->getSource(id); } void Style::addSource(std::unique_ptr source) { + MLN_TRACE_FUNC(); + impl->mutated = true; impl->addSource(std::move(source)); } std::unique_ptr Style::removeSource(const std::string& sourceID) { + MLN_TRACE_FUNC(); + impl->mutated = true; return impl->removeSource(sourceID); } std::vector Style::getLayers() { + MLN_TRACE_FUNC(); + impl->mutated = true; return impl->getLayers(); } std::vector Style::getLayers() const { + MLN_TRACE_FUNC(); + return const_cast(*impl).getLayers(); } Layer* Style::getLayer(const std::string& layerID) { + MLN_TRACE_FUNC(); + impl->mutated = true; return impl->getLayer(layerID); } const Layer* Style::getLayer(const std::string& layerID) const { + MLN_TRACE_FUNC(); + return impl->getLayer(layerID); } void Style::addLayer(std::unique_ptr layer, const std::optional& before) { + MLN_TRACE_FUNC(); + impl->mutated = true; impl->addLayer(std::move(layer), before); } std::unique_ptr Style::removeLayer(const std::string& id) { + MLN_TRACE_FUNC(); + impl->mutated = true; return impl->removeLayer(id); } diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 7af90adc5..803d12651 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -3,7 +3,9 @@ #include #include #include +#include #include + namespace mbgl { GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID, @@ -15,6 +17,8 @@ GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID, } void GeoJSONTile::updateData(std::shared_ptr data_, bool needsRelayout) { + MLN_TRACE_FUNC(); + assert(data_); data = std::move(data_); if (needsRelayout) reset(); @@ -29,6 +33,8 @@ void GeoJSONTile::updateData(std::shared_ptr data_, bool nee } void GeoJSONTile::querySourceFeatures(std::vector& result, const SourceQueryOptions& options) { + MLN_TRACE_FUNC(); + // Ignore the sourceLayer, there is only one if (auto tileData = getData()) { if (auto layer = tileData->getLayer({})) { diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 1649b69f9..086cd862f 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,8 @@ namespace mbgl { LayerRenderData* GeometryTile::LayoutResult::getLayerRenderData(const style::Layer::Impl& layerImpl) { + MLN_TRACE_FUNC(); + auto it = layerRenderData.find(layerImpl.id); if (it == layerRenderData.end()) { return nullptr; @@ -62,6 +65,8 @@ private: using namespace style; std::optional GeometryTileRenderData::getPattern(const std::string& pattern) const { + MLN_TRACE_FUNC(); + if (layoutResult) { const auto& iconAtlas = layoutResult->iconAtlas; auto it = iconAtlas.patternPositions.find(pattern); @@ -73,6 +78,8 @@ std::optional GeometryTileRenderData::getPattern(const std::strin } void GeometryTileRenderData::upload(gfx::UploadPass& uploadPass) { + MLN_TRACE_FUNC(); + if (!layoutResult) return; auto uploadFn = [&](Bucket& bucket) { @@ -127,6 +134,8 @@ void GeometryTileRenderData::upload(gfx::UploadPass& uploadPass) { } void GeometryTileRenderData::prepare(const SourcePrepareParameters& parameters) { + MLN_TRACE_FUNC(); + if (!layoutResult) return; imagePatches = layoutResult->iconAtlas.getImagePatchesAndUpdateVersions(parameters.imageManager); } @@ -177,6 +186,8 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_, std::string sourceID_, c showCollisionBoxes(parameters.debugOptions & MapDebugOptions::Collision) {} GeometryTile::~GeometryTile() { + MLN_TRACE_FUNC(); + markObsolete(); glyphManager->removeRequestor(*this); @@ -203,6 +214,8 @@ void GeometryTile::setError(std::exception_ptr err) { } void GeometryTile::setData(std::unique_ptr data_) { + MLN_TRACE_FUNC(); + if (obsolete) { return; } @@ -217,6 +230,8 @@ void GeometryTile::setData(std::unique_ptr data_) { } void GeometryTile::reset() { + MLN_TRACE_FUNC(); + // Mark the tile as pending again if it was complete before to prevent // signaling a complete state despite pending parse operations. pending = true; @@ -226,10 +241,14 @@ void GeometryTile::reset() { } std::unique_ptr GeometryTile::createRenderData() { + MLN_TRACE_FUNC(); + return std::make_unique(layoutResult, atlasTextures); } void GeometryTile::setLayers(const std::vector>& layers) { + MLN_TRACE_FUNC(); + // Mark the tile as pending again if it was complete before to prevent // signaling a complete state despite pending parse operations. pending = true; @@ -256,6 +275,8 @@ void GeometryTile::setLayers(const std::vector>& laye } void GeometryTile::setShowCollisionBoxes(const bool showCollisionBoxes_) { + MLN_TRACE_FUNC(); + if (showCollisionBoxes != showCollisionBoxes_) { showCollisionBoxes = showCollisionBoxes_; ++correlationID; @@ -264,6 +285,8 @@ void GeometryTile::setShowCollisionBoxes(const bool showCollisionBoxes_) { } void GeometryTile::onLayout(std::shared_ptr result, const uint64_t resultCorrelationID) { + MLN_TRACE_FUNC(); + loaded = true; renderable = true; if (resultCorrelationID == correlationID) { @@ -287,10 +310,14 @@ void GeometryTile::onError(std::exception_ptr err, const uint64_t resultCorrelat } void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) { + MLN_TRACE_FUNC(); + worker.self().invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs)); } void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { + MLN_TRACE_FUNC(); + if (fileSource) { glyphManager->getGlyphs(*this, std::move(glyphDependencies), *fileSource); } @@ -300,6 +327,8 @@ void GeometryTile::onImagesAvailable(ImageMap images, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) { + MLN_TRACE_FUNC(); + worker.self().invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), std::move(patterns), @@ -308,6 +337,8 @@ void GeometryTile::onImagesAvailable(ImageMap images, } void GeometryTile::getImages(ImageRequestPair pair) { + MLN_TRACE_FUNC(); + imageManager->getImages(*this, std::move(pair)); } @@ -316,6 +347,8 @@ std::shared_ptr GeometryTile::getFeatureIndex() const { } bool GeometryTile::layerPropertiesUpdated(const Immutable& layerProperties) { + MLN_TRACE_FUNC(); + LayerRenderData* renderData = getLayerRenderData(*layerProperties->baseImpl); if (!renderData) { return false; @@ -337,10 +370,14 @@ const GeometryTileData* GeometryTile::getData() const { } LayerRenderData* GeometryTile::getLayerRenderData(const style::Layer::Impl& layerImpl) { + MLN_TRACE_FUNC(); + return layoutResult ? layoutResult->getLayerRenderData(layerImpl) : nullptr; } float GeometryTile::getQueryPadding(const std::unordered_map& layers) { + MLN_TRACE_FUNC(); + float queryPadding = 0; for (const auto& pair : layers) { const LayerRenderData* data = getLayerRenderData(*pair.second->baseImpl); @@ -358,6 +395,8 @@ void GeometryTile::queryRenderedFeatures(std::unordered_map& result, const SourceQueryOptions& options) { + MLN_TRACE_FUNC(); + // Data not yet available, or tile is empty if (!getData()) { return; @@ -435,6 +476,8 @@ void GeometryTile::performedFadePlacement() { } void GeometryTile::setFeatureState(const LayerFeatureStates& states) { + MLN_TRACE_FUNC(); + auto layers = getData(); if ((layers == nullptr) || states.empty() || !layoutResult) { return; diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp index d3df36215..81a82efdb 100644 --- a/src/mbgl/tile/geometry_tile_data.cpp +++ b/src/mbgl/tile/geometry_tile_data.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma warning(push) @@ -28,6 +29,8 @@ static double signedArea(const GeometryCoordinates& ring) { } static LinearRing toWagyuPath(const GeometryCoordinates& ring) { + MLN_TRACE_FUNC(); + LinearRing result; result.reserve(ring.size()); for (const auto& p : ring) { @@ -37,6 +40,8 @@ static LinearRing toWagyuPath(const GeometryCoordinates& ring) { } static GeometryCollection toGeometryCollection(MultiPolygon&& multipolygon) { + MLN_TRACE_FUNC(); + GeometryCollection result; for (auto& polygon : multipolygon) { for (auto& ring : polygon) { @@ -47,6 +52,8 @@ static GeometryCollection toGeometryCollection(MultiPolygon&& multipoly } GeometryCollection fixupPolygons(const GeometryCollection& rings) { + MLN_TRACE_FUNC(); + using namespace mapbox::geometry::wagyu; wagyu clipper; @@ -62,6 +69,8 @@ GeometryCollection fixupPolygons(const GeometryCollection& rings) { } std::vector classifyRings(const GeometryCollection& rings) { + MLN_TRACE_FUNC(); + std::vector polygons; std::size_t len = rings.size(); @@ -98,6 +107,8 @@ std::vector classifyRings(const GeometryCollection& rings) { } void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) { + MLN_TRACE_FUNC(); + if (polygon.size() > 1 + maxHoles) { std::nth_element( polygon.begin() + 1, polygon.begin() + 1 + maxHoles, polygon.end(), [](const auto& a, const auto& b) { @@ -108,6 +119,8 @@ void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) { } Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) { + MLN_TRACE_FUNC(); + const double size = util::EXTENT * std::pow(2, tileID.z); const double x0 = util::EXTENT * static_cast(tileID.x); const double y0 = util::EXTENT * static_cast(tileID.y); @@ -179,6 +192,8 @@ Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFe } GeometryCollection convertGeometry(const Feature::geometry_type& geometryTileFeature, const CanonicalTileID& tileID) { + MLN_TRACE_FUNC(); + const double size = util::EXTENT * std::pow(2, tileID.z); const double x0 = util::EXTENT * static_cast(tileID.x); const double y0 = util::EXTENT * static_cast(tileID.y); @@ -260,6 +275,8 @@ GeometryCollection convertGeometry(const Feature::geometry_type& geometryTileFea } Feature convertFeature(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) { + MLN_TRACE_FUNC(); + Feature feature{convertGeometry(geometryTileFeature, tileID)}; feature.properties = geometryTileFeature.getProperties(); feature.id = geometryTileFeature.getID(); diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index ec1c444f5..adf1b603b 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ GeometryTileWorker::GeometryTileWorker(ActorRef self_, showCollisionBoxes(showCollisionBoxes_) {} GeometryTileWorker::~GeometryTileWorker() { + MLN_TRACE_FUNC(); + Scheduler::GetBackground()->runOnRenderThread([renderData_{std::move(renderData)}]() {}); } @@ -123,6 +126,8 @@ GeometryTileWorker::~GeometryTileWorker() { void GeometryTileWorker::setData(std::unique_ptr data_, std::set availableImages_, uint64_t correlationID_) { + MLN_TRACE_FUNC(); + try { data = std::move(data_); correlationID = correlationID_; @@ -148,6 +153,8 @@ void GeometryTileWorker::setData(std::unique_ptr data_, void GeometryTileWorker::setLayers(std::vector> layers_, std::set availableImages_, uint64_t correlationID_) { + MLN_TRACE_FUNC(); + try { layers = std::move(layers_); correlationID = correlationID_; @@ -189,6 +196,8 @@ void GeometryTileWorker::reset(uint64_t correlationID_) { } void GeometryTileWorker::setShowCollisionBoxes(bool showCollisionBoxes_, uint64_t correlationID_) { + MLN_TRACE_FUNC(); + try { showCollisionBoxes = showCollisionBoxes_; correlationID = correlationID_; @@ -217,6 +226,8 @@ void GeometryTileWorker::setShowCollisionBoxes(bool showCollisionBoxes_, uint64_ } void GeometryTileWorker::symbolDependenciesChanged() { + MLN_TRACE_FUNC(); + try { switch (state) { case Idle: @@ -245,6 +256,8 @@ void GeometryTileWorker::symbolDependenciesChanged() { } void GeometryTileWorker::coalesced() { + MLN_TRACE_FUNC(); + try { switch (state) { case Idle: @@ -274,11 +287,15 @@ void GeometryTileWorker::coalesced() { } void GeometryTileWorker::coalesce() { + MLN_TRACE_FUNC(); + state = Coalescing; self.invoke(&GeometryTileWorker::coalesced); } void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) { + MLN_TRACE_FUNC(); + for (auto& newFontGlyphs : newGlyphMap) { FontStackHash fontStack = newFontGlyphs.first; Glyphs& newGlyphs = newFontGlyphs.second; @@ -308,6 +325,8 @@ void GeometryTileWorker::onImagesAvailable(ImageMap newIconMap, ImageMap newPatternMap, ImageVersionMap newVersionMap, uint64_t imageCorrelationID_) { + MLN_TRACE_FUNC(); + if (imageCorrelationID != imageCorrelationID_) { return; // Ignore outdated image request replies. } @@ -319,6 +338,8 @@ void GeometryTileWorker::onImagesAvailable(ImageMap newIconMap, } void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependencies) { + MLN_TRACE_FUNC(); + for (auto& fontDependencies : glyphDependencies) { auto fontGlyphs = glyphMap.find(FontStackHasher()(fontDependencies.first)); for (auto glyphID : fontDependencies.second) { @@ -333,6 +354,8 @@ void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependen } void GeometryTileWorker::requestNewImages(const ImageDependencies& imageDependencies) { + MLN_TRACE_FUNC(); + pendingImageDependencies = imageDependencies; if (!pendingImageDependencies.empty()) { @@ -341,6 +364,8 @@ void GeometryTileWorker::requestNewImages(const ImageDependencies& imageDependen } void GeometryTileWorker::parse() { + MLN_TRACE_FUNC(); + if (!data || !layers) { return; } @@ -462,6 +487,8 @@ bool GeometryTileWorker::hasPendingParseResult() const { } void GeometryTileWorker::finalizeLayout() { + MLN_TRACE_FUNC(); + if (!data || !layers || !hasPendingParseResult() || hasPendingDependencies()) { return; } diff --git a/src/mbgl/tile/tile_cache.cpp b/src/mbgl/tile/tile_cache.cpp index b4d65990f..2d7c98206 100644 --- a/src/mbgl/tile/tile_cache.cpp +++ b/src/mbgl/tile/tile_cache.cpp @@ -1,10 +1,13 @@ #include #include +#include #include namespace mbgl { void TileCache::setSize(size_t size_) { + MLN_TRACE_FUNC(); + size = size_; while (orderedKeys.size() > size) { @@ -37,6 +40,8 @@ struct CaptureWrapper { } // namespace void TileCache::deferredRelease(std::unique_ptr&& tile) { + MLN_TRACE_FUNC(); + tile->cancel(); // The `std::function` must be created in a separate statement from the `schedule` call. @@ -53,6 +58,8 @@ void TileCache::deferredRelease(std::unique_ptr&& tile) { } void TileCache::add(const OverscaledTileID& key, std::unique_ptr&& tile) { + MLN_TRACE_FUNC(); + if (!tile->isRenderable() || !size) { deferredRelease(std::move(tile)); return; diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp index 8df24eec7..644225a92 100644 --- a/src/mbgl/tile/vector_tile_data.cpp +++ b/src/mbgl/tile/vector_tile_data.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace mbgl { @@ -37,6 +38,8 @@ FeatureIdentifier VectorTileFeature::getID() const { } const GeometryCollection& VectorTileFeature::getGeometries() const { + MLN_TRACE_FUNC(); + if (!lines) { const auto scale = static_cast(util::EXTENT) / feature.getExtent(); @@ -78,6 +81,8 @@ std::unique_ptr VectorTileData::clone() const { } std::unique_ptr VectorTileData::getLayer(const std::string& name) const { + MLN_TRACE_FUNC(); + if (!parsed) { // We're parsing this lazily so that we can construct VectorTileData // objects on the main thread without incurring the overhead of parsing diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp index ceb4bcf08..cf66fc6c6 100644 --- a/src/mbgl/util/http_header.cpp +++ b/src/mbgl/util/http_header.cpp @@ -2,6 +2,7 @@ #include #include +#include #ifdef _MSC_VER #pragma warning(push) @@ -20,6 +21,8 @@ namespace mbgl { namespace http { CacheControl CacheControl::parse(const std::string& value) { + MLN_TRACE_FUNC(); + namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; @@ -40,6 +43,8 @@ std::optional CacheControl::toTimePoint() const { std::optional parseRetryHeaders(const std::optional& retryAfter, const std::optional& xRateLimitReset) { + MLN_TRACE_FUNC(); + if (retryAfter) { try { auto secs = std::chrono::seconds(std::stoi(*retryAfter)); diff --git a/src/mbgl/util/http_timeout.cpp b/src/mbgl/util/http_timeout.cpp index 647c65a4d..1eeef972b 100644 --- a/src/mbgl/util/http_timeout.cpp +++ b/src/mbgl/util/http_timeout.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -10,6 +11,8 @@ namespace http { Duration errorRetryTimeout(Response::Error::Reason failedRequestReason, uint32_t failedRequests, std::optional retryAfter) { + MLN_TRACE_FUNC(); + if (failedRequestReason == Response::Error::Reason::Server) { // Retry after one second three times, then start exponential backoff. return Seconds(failedRequests <= 3 ? 1 : 1u << std::min(failedRequests - 3, 31u)); diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp index 68b7dfa64..e66389e33 100644 --- a/src/mbgl/util/io.cpp +++ b/src/mbgl/util/io.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -21,6 +22,8 @@ IOException::IOException(int err, const std::string &msg) code(err) {} void write_file(const std::string &filename, const std::string &data) { + MLN_TRACE_FUNC(); + FILE *fd = fopen(filename.c_str(), MBGL_FOPEN_MODE_WBE); if (fd) { fwrite(data.data(), sizeof(std::string::value_type), data.size(), fd); @@ -31,6 +34,8 @@ void write_file(const std::string &filename, const std::string &data) { } std::string read_file(const std::string &filename) { + MLN_TRACE_FUNC(); + std::ifstream file(filename, std::ios::binary); if (file.good()) { std::stringstream data; @@ -42,6 +47,8 @@ std::string read_file(const std::string &filename) { } std::optional readFile(const std::string &filename) { + MLN_TRACE_FUNC(); + std::ifstream file(filename, std::ios::binary); if (file.good()) { std::stringstream data; @@ -52,6 +59,8 @@ std::optional readFile(const std::string &filename) { } void deleteFile(const std::string &filename) { + MLN_TRACE_FUNC(); + const int ret = std::remove(filename.c_str()); if (ret != 0 && errno != ENOENT) { throw IOException(errno, "Could not delete file " + filename); @@ -59,6 +68,8 @@ void deleteFile(const std::string &filename) { } void copyFile(const std::string &destination, const std::string &source) { + MLN_TRACE_FUNC(); + std::ifstream src(source, std::ios::binary); if (!src.good()) { throw IOException(errno, "Cannot read file " + source); diff --git a/vendor/tracy.cmake b/vendor/tracy.cmake new file mode 100644 index 000000000..1a033802d --- /dev/null +++ b/vendor/tracy.cmake @@ -0,0 +1,26 @@ +if (MLN_USE_TRACY) + add_definitions(-DTRACY_ENABLE) + add_definitions(-DMLN_TRACY_ENABLE) +endif() + +include(FetchContent) + +FetchContent_Declare( + tracy + GIT_REPOSITORY "https://github.com/wolfpld/tracy.git" + GIT_TAG master + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE +) + +FetchContent_MakeAvailable(tracy) + +set_target_properties( + TracyClient + PROPERTIES + INTERFACE_MAPBOX_NAME "Tracy profiler" + INTERFACE_MAPBOX_URL "https://github.com/wolfpld/tracy.git" + INTERFACE_MAPBOX_AUTHOR "Bartosz Taudul" + INTERFACE_MAPBOX_LICENSE ${CMAKE_CURRENT_LIST_DIR}/tracy/LICENSE +) + diff --git a/vendor/tracy/LICENSE b/vendor/tracy/LICENSE new file mode 100644 index 000000000..84f56c347 --- /dev/null +++ b/vendor/tracy/LICENSE @@ -0,0 +1,27 @@ +Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the +3-clause BSD license. + +Copyright (c) 2017-2024, Bartosz Taudul +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file