Repository navigation
gtk,opengl: free us from the clutches of GtkGLArea - #14052
Conversation
7233110 to
fe52129
Compare
|
My first high-level pass: this looks great. I want to dig in a bit more but I did pass through every line of code manually here and looking WAY simpler overall. One thing that felt a bit weird was the message-based displayRealized/Unrealized. Why do that versus just locking the renderer and keeping that synchronous? I feel like you may not want to depend on queues before you allocate/remove GPU resources. |
|
Good point. I figure if you're unrealizing a surface anyway there's not much of a point trying to send stuff into a mailbox that's going to be destroyed very soon... Lemme change that |
261265f to
3e7bf04
Compare
031ecfa to
cf0f7af
Compare
|
I've been running these patches on my daily driver for the past couple of days and no problems so far! |
mitchellh
left a comment
There was a problem hiding this comment.
Mostly ready to accept this as-is now but curious on this.
|
Also I found a bug with background images so I'm not gonna hit merge just yet till I fix it |
|
I tried to test this on my system with a Nvidia card, but ran into some trouble. I use Arch + Hyprland + Nvidia Driver 580.178.04-1 with a GTX1060, the card is kind of old, but generally things work out of the box for various GPU-accelerated apps, including Ghostty. Setting up the display with With those changes Ghostty works and uses the Nvidia GPU, but there is a lot of lag. See the following video. The input is delayed sometimes up to 1s and when running new.mp4If you don't have access to a Nvidia system, this might be tough to work on, so I will investigate more myself and can of course test any ideas you might have. Disclaimer: The code above was developed in collaboration with AI, while I kind of understand what's going on high-level, I don't know a lot about graphics programming. |
|
Ugh why is Nvidia like this One side benefit is maybe we can do a bit of device selection here like with Metal, so in hybrid (dual-GPU) setups we can use the one that's more appropriate for this use case. We have to do this unconditionally on Vulkan anyways so having this for OpenGL is probably also a good idea |
Oh, that does suck. |
|
I tried this with a 3080 with drivers 610.57.04, I see OpenGL 4.6 being used by default Opening the Inspector reliably causes a crash with stack trace ghostty.mp4
|
|
Here's a patch fix, move the gl.finish() till after we blit for presenting to the app surface. This is a latent bug in the OpenGL renderer. No more latency issues from trying it out |
We need this for exporting DMABUFs and creating our own GL context independent of GTK.
GtkGLArea had numerous downsides that forced us to invent unsightly hacks in our renderer to work around them, most chiefly the fact that it holds its own GdkGLContext on the main thread (GL contexts are not at all thread-safe), forcing us to keep our GL calls on the main thread. It also does not interact well with triple-buffering and initialization is forced to be this sort of deferred song-and-dance since we need to wait for the GLArea to initialize its GL context before we can initialize the renderer, the core surface, and then most things in the GTK surface. We instead invent our own custom widget named RenderSurface that takes simple DMABUFs and displays them. The task of obtaining a GL context falls to manual EGL bindings, since we also need EGL to export OpenGL textures into DMABUFs. We keep the EGL context solely on the render thread meaning that the main thread never concerns itself with rendering except when being notified that the renderer has pushed a new frame. What makes this extra significant is that now the entire GTK apprt no longer depends on OpenGL in any way, shape or form. As long as it is being fed DMABUFs, it can render from whichever graphics API you want. This means we can add more backends based on OpenGL ES or more likely Vulkan rather painlessly in the future. **AI disclosure**: I came up with the idea and let Pi implement most of the nitty-gritty details around EGL, as well as replumbing the renderer and cleaning up all the GTK-specific workarounds there. I then carefully vetted every line of code and spent roughly as much time reviewing as coding. Most of the documentation and all commit messages are in my own words.
libghostty-internal isn't really supposed to be used in Windows anyway, so why bother testing it?
Now that our core surface does not depend on any GTK-sided OpenGL initialization, we can initialize it a lot earlier than before, during the first resize event right after GTK allocates the size for the widget.
General Zig 0.16+ futureproofing
Apparently either OpenGL ES or Vulkan is required to present our DMABUFs for jcollie
25baa19 to
202fa8e
Compare
f63a133 to
d00a498
Compare
|
We're going to send this. Ghostty 1.4 is soon but if we can get some weeks for this to bake that'd be fantastic. Thanks @pluiedev |
|
I should add, if we get a ton of reports of Linux breaking I will revert it and we can fix up and go again another time. |
I'm just one data point, but this PR breaks startup for me: 49b95d8 throws errors like "MESA-EGL: warning: egl: failed to create dri2 screen" and ultimately crashes when Running with Lavapipe (software rendering) OR with This is running an Nvidia GPU (GB10, DGX Spark) on COSMIC (Wayland) with the proprietary GPU driver. |
|
Please open a new discussion instead of adding details here. Filling in the template is necessary for informed debugging. |
## Fix This PR aims to use gdk_surface_get_scale() over gtk_widget_get_scale_factor() so device sizes and DPI follow the real fractional scale instead of the ceiled integer. Fall back to get_scale_factor when there is no GdkSurface. in short: Keep textures 1:1 with device pixels and listen to GdkSurface notify::scale for resize/redraw. - Related to #1938 (The issue was closed, but eventually it regressed; fractional scaling still blurry). - Because the original issue was closed I created this discussion: #13911 (Let me know if that is enough for this PR otherwise I guess we would need to create a new issue although I see it as unnecessary). - I was waiting on #14052 to be merged. ## Considerations Ok the blurry font is in a way subtle and hard to perceive. But a very "easy" way to test this is by looking at box characters. Box chars are supposed to be rendered pixel perfect with sharp edges because they're just boxes I suppose (correct me if I am wrong). You can compare to other terminal emulators, but if you see blurry edges on them, then we're not rendering on fractional scaling properly. Like this image in the discussion (the box char is much sharper on kitty previous to the fix): <img width="444" height="338" alt="image" src="https://github.com/user-attachments/assets/ec60dae0-2c33-4d52-adb5-92ea41775bf8" /> I mention this because I have only tested on 1440p and ultrawide 4k (5120x2160). on Niri Wayland at 1.3x 1.5x and 1.666x. I have NOT tested yet on X11. I would love is someone could help with that otherwise I will do it, it's just going to take me abit of time. Same for other resolutions. > [!IMPORTANT] > of course just let me know if I can improve or change anything here in the code. Thanks! ## AI Disclosure I used GPT 5.6 Terra and Grok 4.6 here & there.
The GtkGLArea to EGL/DMA-BUF rewrite (ghostty-org/ghostty#14052) renders garbled output on tomservo (RX 7900, mesa 26.2.3). The pre-rewrite build works fine against the same mesa, so pin to it until upstream fixes the regression. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stops just before upstream replaced GtkGLArea with a surfaceless EGL OpenGL backend (ghostty-org#14052), which the win32 WGL renderer does not fit yet. Conflict notes: - renderer/Thread: upstream dropped the always-on draw timer for an on-demand animation timer. Keep a win32-only draw poll timer for content_dirty; other runtimes use upstream's scheduling. - kitty graphics: upstream now removes all placements when an image ID is retransmitted, so drop our equivalent removeAllPlacementsForImage. - config: take upstream's copy-on-select / middle-click-action redesign; keep the wsl-mode compat handler. - cli/edit_config: keep opening the config with ShellExecuteW on Windows. - termio/Thread: keep visual-only redraw grouping; add kitty clipboard grant messages to the non-visual group.




GtkGLArea had numerous downsides that forced us to invent unsightly hacks in our renderer to work around them, most chiefly the fact that it holds its own GdkGLContext on the main thread (GL contexts are not at all thread-safe), forcing us to keep our GL calls on the main thread. It also does not interact well with triple-buffering and initialization is forced to be this sort of deferred song-and-dance since we need to wait for the GLArea to initialize its GL context before we can initialize the renderer, the core surface, and then most things in the GTK surface.
We instead invent our own custom widget named RenderSurface that takes simple DMABUFs and displays them. The task of obtaining a GL context falls to manual EGL bindings, since we also need EGL to export OpenGL textures into DMABUFs. We keep the EGL context solely on the render thread meaning that the main thread never concerns itself with rendering except when being notified that the renderer has pushed a new frame.
What makes this extra significant is that now the entire GTK apprt no longer depends on OpenGL in any way, shape or form. As long as it is being fed DMABUFs, it can render from whichever graphics API you want. This means we can add more backends based on OpenGL ES or more likely Vulkan rather painlessly in the future.
AI disclosure: I came up with the idea and let Pi implement most of the nitty-gritty details around EGL, as well as replumbing the renderer and cleaning up all the GTK-specific workarounds there. I then carefully vetted every line of code and spent roughly as much time reviewing as coding. Most of the documentation and all commit messages are in my own words.