From bf3bd28bfa4c07ca816c5876b7d2c5f4c01e7684 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 24 Jan 2024 12:19:52 +0400 Subject: [PATCH 1/3] wayland: Keep track of entered outputs for scale Wayland kindly informs us which outputs the surface is on, to be used for scale computation (at least on wl_compositor < 6). On mixed DPI setups this fixes Tracy potentially using a higher scale than the output it's displayed on. However, as is, this commit results in Tracy always using scale 1, because at the point of backend creation (which is when the scale is queried) the surface is not yet displayed on any outputs, so a scale of 1 is assumed. --- profiler/src/BackendWayland.cpp | 53 ++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/profiler/src/BackendWayland.cpp b/profiler/src/BackendWayland.cpp index feea6379..c33382e4 100644 --- a/profiler/src/BackendWayland.cpp +++ b/profiler/src/BackendWayland.cpp @@ -194,6 +194,7 @@ struct Output { int32_t scale; wl_output* obj; + bool entered; }; static std::unordered_map> s_output; static int s_maxScale = 1; @@ -207,6 +208,16 @@ static uint64_t s_time; static wl_fixed_t s_wheelAxisX, s_wheelAxisY; static bool s_wheel; +static void RecomputeScale() +{ + int max = 1; + for( auto& out : s_output ) + { + if( out.second->entered && out.second->scale > max ) max = out.second->scale; + } + s_maxScale = max; +} + static void PointerEnter( void*, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surf, wl_fixed_t sx, wl_fixed_t sy ) { wl_pointer_set_cursor( pointer, serial, s_cursorSurf, s_cursorX, s_cursorY ); @@ -471,12 +482,7 @@ static void OutputMode( void*, struct wl_output* output, uint32_t flags, int32_t static void OutputDone( void*, struct wl_output* output ) { - int max = 1; - for( auto& out : s_output ) - { - if( out.second->scale > max ) max = out.second->scale; - } - s_maxScale = max; + RecomputeScale(); } static void OutputScale( void* data, struct wl_output* output, int32_t scale ) @@ -529,7 +535,7 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const else if( strcmp( interface, wl_output_interface.name ) == 0 ) { auto output = (wl_output*)wl_registry_bind( reg, name, &wl_output_interface, 2 ); - auto ptr = std::make_unique( Output { 1, output } ); + auto ptr = std::make_unique( Output { 1, output, false } ); wl_output_add_listener( output, &outputListener, ptr.get() ); s_output.emplace( name, std::move( ptr ) ); } @@ -545,6 +551,7 @@ static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name if( it == s_output.end() ) return; wl_output_destroy( it->second->obj ); s_output.erase( it ); + RecomputeScale(); } constexpr struct wl_registry_listener registryListener = { @@ -603,6 +610,37 @@ constexpr struct xdg_toplevel_listener toplevelListener = { .close = XdgToplevelClose }; +static void SurfaceEnter( void*, struct wl_surface* surface, struct wl_output* output ) +{ + for ( auto& out : s_output ) + { + if ( out.second->obj == output ) + { + out.second->entered = true; + RecomputeScale(); + break; + } + } +} + +static void SurfaceLeave( void*, struct wl_surface* surface, struct wl_output* output ) +{ + for ( auto& out : s_output ) + { + if ( out.second->obj == output ) + { + out.second->entered = false; + RecomputeScale(); + break; + } + } +} + +constexpr struct wl_surface_listener surfaceListener = { + .enter = SurfaceEnter, + .leave = SurfaceLeave, +}; + static void SetupCursor() { auto env_xcursor_theme = getenv( "XCURSOR_THEME" ); @@ -645,6 +683,7 @@ Backend::Backend( const char* title, const std::function& redraw, RunQue if( !s_seat ) { fprintf( stderr, "No wayland seat!\n" ); exit( 1 ); } s_surf = wl_compositor_create_surface( s_comp ); + wl_surface_add_listener( s_surf, &surfaceListener, nullptr ); s_eglWin = wl_egl_window_create( s_surf, m_winPos.w, m_winPos.h ); s_xdgSurf = xdg_wm_base_get_xdg_surface( s_wm, s_surf ); xdg_surface_add_listener( s_xdgSurf, &xdgSurfaceListener, nullptr ); From 16434f116c2a556a93530c995975deec0593fb16 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 24 Jan 2024 12:34:23 +0400 Subject: [PATCH 2/3] Add a way for Backend to signal scale changes On Wayland the scale now changes to the correct value as the Tracy window is moved across monitors. If the scale is overridden from environment, it does not change, just like before. --- profiler/src/Backend.hpp | 2 +- profiler/src/BackendGlfw.cpp | 2 +- profiler/src/BackendWayland.cpp | 5 ++++- profiler/src/main.cpp | 18 ++++++++++++++++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/profiler/src/Backend.hpp b/profiler/src/Backend.hpp index 2f4262a3..f4a031bb 100644 --- a/profiler/src/Backend.hpp +++ b/profiler/src/Backend.hpp @@ -11,7 +11,7 @@ class RunQueue; class Backend { public: - Backend( const char* title, const std::function& redraw, RunQueue* mainThreadTasks ); + Backend( const char* title, const std::function& redraw, const std::function& scaleChanged, RunQueue* mainThreadTasks ); ~Backend(); void Show(); diff --git a/profiler/src/BackendGlfw.cpp b/profiler/src/BackendGlfw.cpp index f3525ee9..51897111 100644 --- a/profiler/src/BackendGlfw.cpp +++ b/profiler/src/BackendGlfw.cpp @@ -60,7 +60,7 @@ static void glfw_window_iconify_callback( GLFWwindow*, int iconified ) } -Backend::Backend( const char* title, const std::function& redraw, RunQueue* mainThreadTasks ) +Backend::Backend( const char* title, const std::function& redraw, const std::function& scaleChanged, RunQueue* mainThreadTasks ) { glfwSetErrorCallback( glfw_error_callback ); if( !glfwInit() ) exit( 1 ); diff --git a/profiler/src/BackendWayland.cpp b/profiler/src/BackendWayland.cpp index c33382e4..04d3d7e5 100644 --- a/profiler/src/BackendWayland.cpp +++ b/profiler/src/BackendWayland.cpp @@ -160,6 +160,7 @@ constexpr ImGuiKey s_keyTable[] = { }; static std::function s_redraw; +static std::function s_scaleChanged; static RunQueue* s_mainThreadTasks; static struct wl_display* s_dpy; @@ -662,9 +663,10 @@ static void SetupCursor() s_cursorY = cursor->images[0]->hotspot_y / s_maxScale; } -Backend::Backend( const char* title, const std::function& redraw, RunQueue* mainThreadTasks ) +Backend::Backend( const char* title, const std::function& redraw, const std::function& scaleChanged, RunQueue* mainThreadTasks ) { s_redraw = redraw; + s_scaleChanged = scaleChanged; s_mainThreadTasks = mainThreadTasks; s_w = m_winPos.w; s_h = m_winPos.h; @@ -820,6 +822,7 @@ void Backend::NewFrame( int& w, int& h ) { if( s_prevScale != s_maxScale ) { + s_scaleChanged( s_maxScale ); SetupCursor(); wl_surface_set_buffer_scale( s_surf, s_maxScale ); s_prevScale = s_maxScale; diff --git a/profiler/src/main.cpp b/profiler/src/main.cpp index 34f7f087..97f798bf 100644 --- a/profiler/src/main.cpp +++ b/profiler/src/main.cpp @@ -95,6 +95,7 @@ static ConnectionHistory* connHist; static std::atomic viewShutdown { ViewShutdown::False }; static double animTime = 0; static float dpiScale = 1.f; +static bool dpiScaleOverriddenFromEnv = false; static Filters* filt; static RunQueue mainThreadTasks; static uint32_t updateVersion = 0; @@ -197,6 +198,15 @@ static bool SaveConfig() return true; } +static void ScaleChanged( float scale ) +{ + if ( dpiScaleOverriddenFromEnv ) return; + if ( dpiScale == scale ) return; + + dpiScale = scale; + SetupDPIScale( dpiScale, s_fixedWidth, s_bigFont, s_smallFont ); +} + int main( int argc, char** argv ) { sprintf( title, "Tracy Profiler %i.%i.%i", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch ); @@ -279,7 +289,7 @@ int main( int argc, char** argv ) LoadConfig(); ImGuiTracyContext imguiContext; - Backend backend( title, DrawContents, &mainThreadTasks ); + Backend backend( title, DrawContents, ScaleChanged, &mainThreadTasks ); tracy::InitTexture(); iconTex = tracy::MakeTexture(); zigzagTex = tracy::MakeTexture( true ); @@ -292,7 +302,11 @@ int main( int argc, char** argv ) if( envDpiScale ) { const auto cnv = atof( envDpiScale ); - if( cnv != 0 ) dpiScale = cnv; + if( cnv != 0 ) + { + dpiScale = cnv; + dpiScaleOverriddenFromEnv = true; + } } SetupDPIScale( dpiScale, s_fixedWidth, s_bigFont, s_smallFont ); From fcdc96748ec854dd00bfaee83d8481c0f1cc46c0 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 24 Jan 2024 12:43:42 +0400 Subject: [PATCH 3/3] wayland: Use preferred_buffer_scale when available On wl_compositor >= 6 we bind v6 and use preferred_buffer_scale. Otherwise we bind 4 and do as before. No other changes are needed for the version bump as Tracy doesn't use wl_surface_attach() with nonzero coordinates. --- profiler/src/BackendWayland.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/profiler/src/BackendWayland.cpp b/profiler/src/BackendWayland.cpp index 04d3d7e5..fa5b55fa 100644 --- a/profiler/src/BackendWayland.cpp +++ b/profiler/src/BackendWayland.cpp @@ -165,6 +165,7 @@ static RunQueue* s_mainThreadTasks; static struct wl_display* s_dpy; static struct wl_compositor* s_comp; +static uint32_t s_comp_version; static struct wl_surface* s_surf; static struct wl_egl_window* s_eglWin; static struct wl_shm* s_shm; @@ -211,6 +212,9 @@ static bool s_wheel; static void RecomputeScale() { + // On wl_compositor >= 6 the scale is sent explicitly via wl_surface.preferred_buffer_scale. + if ( s_comp_version >= 6 ) return; + int max = 1; for( auto& out : s_output ) { @@ -513,7 +517,8 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const { if( strcmp( interface, wl_compositor_interface.name ) == 0 ) { - s_comp = (wl_compositor*)wl_registry_bind( reg, name, &wl_compositor_interface, 4 ); + s_comp_version = version; + s_comp = (wl_compositor*)wl_registry_bind( reg, name, &wl_compositor_interface, version >= 6 ? 6 : 4 ); } else if( strcmp( interface, wl_shm_interface.name ) == 0 ) { @@ -637,9 +642,15 @@ static void SurfaceLeave( void*, struct wl_surface* surface, struct wl_output* o } } +static void SurfacePreferredBufferScale( void*, struct wl_surface* surface, int32_t scale ) +{ + s_maxScale = scale; +} + constexpr struct wl_surface_listener surfaceListener = { .enter = SurfaceEnter, .leave = SurfaceLeave, + .preferred_buffer_scale = SurfacePreferredBufferScale, }; static void SetupCursor()