-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wayland support on Linux #853
Comments
This seems like an odd angle to approach from. The in-application API just falls out of what I can actually hook and capture - the DevicePointer / WindowHandle are cast to I don't know much about wayland but Can you give more details about what you're actually trying to do and what goes wrong? That would help to give context. Once you're able to capture your program properly then either the in-application API will already work, or it might need a minor bugfix. I don't think I can test wayland directly here, I think it became available on ubuntu 17.10 on one of my linux installs but I immediately disabled it since it proved buggy and kind of limited. In theory I don't have any problem supporting wayland but it's probably not an immediate priority until it becomes more stable and widespread. |
Thanks for the quick response! I already know that both types are typedefs to I was actually unaware that EGL was already working in RenderDoc since the in-application API docs do not mention it as a supported option. The game code in question doesn't pass in an EDIT: To my knowledge, the correct window handle type for Wayland is |
It's not in the docs yet since GLES support in general is not officially shipped 😄. It will be soon™ at which point I'll update the docs. |
Great to hear! I'll get back to you if it works for me. EDIT: @baldurk So, I've amended my code, built
In this case, I'm passing in an |
Interestingly enough, when I launch the application through X11, RenderDoc correctly identifies the API as OpenGL, but still produces the same Couldn't find frame capturer for device error as in Wayland above.
|
Oops, apparently ctrl-enter posts a comment. The device handle looks quite weird, RDCLOG("Created context %p", ctxdata.ctx); (Note v1.x may be unstable/broken at the moment which might contribute to this). |
It's possible, yes. But I'm still happy to have RenderDoc working great on X11, at least! Back on topic, though, I found this informative blog post describing how EGL contexts and surfaces fit into the greater Wayland protocol stack, though as a disclaimer, it is from 2012 and might be very out of date by now. |
@baldurk I added the line you requested to
Looks like that value is indeed what it received, somehow. EDIT: I checked |
Fair enough, I'd normally seen context handles as more.. 'handley' but this is perfectly fine I just wanted to check. I ran a test myself, I patched one of ogl-samples to call into renderdoc's API, and it worked OK when I tested it. This was on latest v1.x as of now (there was one fix that went in today, but I think only for something that broke since the commit you were working from). The diff is here if you want to try it: diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index 2ade0992..b019b246 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -11,7 +11,7 @@ function(glCreateSampleGTC NAME)
add_executable(${SAMPLE_NAME} ${GL_PROFILE_GTC}-${GL_VERSION_GTC}-${NAME}.cpp ${SHADER_PATH})
add_test(NAME ${SAMPLE_NAME} COMMAND $<TARGET_FILE:${SAMPLE_NAME}>)
- target_link_libraries(${SAMPLE_NAME} ${FRAMEWORK_NAME} ${BINARY_FILES})
+ target_link_libraries(${SAMPLE_NAME} ${FRAMEWORK_NAME} ${BINARY_FILES} -ldl)
add_dependencies(${SAMPLE_NAME} glfw ${FRAMEWORK_NAME} ${COPY_BINARY})
install(TARGETS ${SAMPLE_NAME} DESTINATION .)
diff --git a/samples/gl-320-fbo-layered.cpp b/samples/gl-320-fbo-layered.cpp
index 6ade827a..8e240f9e 100644
--- a/samples/gl-320-fbo-layered.cpp
+++ b/samples/gl-320-fbo-layered.cpp
@@ -1,5 +1,13 @@
#include "test.hpp"
+#define GLFW_EXPOSE_NATIVE_X11
+#define GLFW_EXPOSE_NATIVE_GLX
+#include <GLFW/glfw3native.h>
+
+#include <dlfcn.h>
+
+#include "/home/baldurk/renderdoc/renderdoc/api/app/renderdoc_app.h"
+
namespace
{
char const* VERT_SHADER_SOURCE1("gl-320/fbo-layered.vert");
@@ -262,6 +270,37 @@ private:
{
glm::ivec2 WindowSize(this->getWindowSize());
+ GLXContext ctx = glfwGetGLXContext(glfwGetCurrentContext());
+
+ static int frame = 0;
+ frame++;
+
+ fprintf(stderr, "%d: current context %p\n", frame, ctx);
+
+ RENDERDOC_API_1_1_1 *api = NULL;
+
+ {
+ void *rdoc = dlopen("librenderdoc.so", RTLD_NOW | RTLD_GLOBAL | RTLD_NOLOAD);
+
+ if(rdoc)
+ {
+ pRENDERDOC_GetAPI getapi = (pRENDERDOC_GetAPI)dlsym(rdoc, "RENDERDOC_GetAPI");
+
+ if(getapi)
+ {
+ getapi(eRENDERDOC_API_Version_1_1_1, (void **)&api);
+
+ if(frame == 100)
+ api->StartFrameCapture(ctx, NULL);
+ }
+ }
+ }
+
+ if(api)
+ fprintf(stderr, "%d: got api!\n", frame);
+ else
+ fprintf(stderr, "%d: no api\n", frame);
+
glm::mat4 Projection = glm::ortho(-1.0f, 1.0f, 1.0f,-1.0f, 1.0f, -1.0f);
glm::mat4 View = glm::mat4(1.0f);
glm::mat4 Model = glm::mat4(1.0f);
@@ -301,6 +340,9 @@ private:
}
}
+ if(api && frame == 100)
+ api->EndFrameCapture(ctx, NULL);
+
return true;
}
}; As a further test for your case, can you add a print in
Just to check that the window is getting registered as well, although it shouldn't be needed. It would also be nice to debug through I synced your sample code from renderdoc-rs but it doesn't seem like the one on github is set up to provide a context to start a capture. If you could push that code to a new branch or give me a patch, I could test it locally and see how I get on. |
Thanks for the diff! Unfortunately, v1.x doesn't build on my machine anymore after The latest version that has this capability is in the |
What problem do you hit building latest v1.x? I'm not seeing it locally or on travis, but with the number of compiler versions around on linux it's easy for some new warning to be generated somewhere. If it's just a warning you can build in release mode, and then there's no warnings as errors, but I would like to fix it. I switched to the |
Well, the specific error I'm hitting is at the 90% mark from linking
This is from me invoking As for the Rust code, I'm sorry for not having explained the build process or given further detail. If you need any help from me in getting the code built or understood, please feel free to ask! In the EDIT: D'oh! I fixed the build error by invoking |
That's a strange error, I did add that project recently to isolate off the module entry point, but unless there are some other errors I don't know why it would fail to link. Can you remove your As to the rust code it's OK - once someone had pointed me at The So instead I only consider windows to be really present once you are presenting to them with Note that |
I already did try with a fresh Oh, that's interesting! I didn't know that was how |
I wonder if I'm missing a dependency then, to ensure renderdoc_libentry builds before renderdoc. I'll check that out. For what it's worth, the SetActiveWindow in your code was redundant anyway, since the first window that becomes available becomes active by default - I was able to capture anyway with |
Whatever changes you made to the CMake scripts fixed the I was calling |
Good news! Compiling RenderDoc with Unfortunately, RenderDoc fails to pick up any input for the window (e.g. pressing With that said, from examining this Wayland input tutorial I found, implementing this support in RenderDoc should be doable. If the user provides the RenderDoc API with a Once I familiarize myself with the RenderDoc code base, I might be willing to take a stab at it, if you'd like. EDIT: Another caveat; it appears that launching the |
That's promising, that suggests that it's most of the way there. I believe vulkan will need explicit wayland support as EGL just overloads the same function used for xlib/xcb/whatever, but vulkan has separate entry points. There'll need to be a default-off As for keyboard input, this mostly happens in There are a couple of important functions - on the 'setup' side there's a Then the meat of the code is when If you require the window handle you'll need to hook I don't mind getting to all this myself at some stage, but as I say since it's a niche/experimental platform on linux and I'm not able to test it directly then it's not high priority, so any pull requests would be welcome. Check the |
Thank you so much for all the information! As you requested, I've created all the CMake and First issue: Wayland is a heavily callback-based API for reasons of thread safety, so there is no polling version available at all AFAICT. I don't think it would interfere with RenderDoc's main loop since the client application is the one updating it and pumping messages; we're just listening to events. To implement support for Wayland, I think we could do the following:
Second issue: as a security measure, Wayland is very reluctant to give arbitrary clients access to other clients' keyboards. Since we are literally handing over a |
Sounds good, you can of course PR the support in multiple parts, especially if it's behind a feature flag that defaults to off then there's no harm in bringing it in piecemeal. Regarding the callbacks, if that's the only way to implement it then fair enough, but I remain a little skeptical that it will work without problems. I'd expect the library to work great when within the application doing its own main loop, but RenderDoc injected doing its own thing often breaks the assumptions of libraries that only expect a single application to be using them. While injected RenderDoc has no main loop of its own - it will be checking for keypresses inside eglSwapBuffers whenever that happens. Either way any work you do on this is welcome, let me know when you have a PR to look at and we can take it from there. |
So, it turns out that the most common way to detect a Wayland session over an X11 session is to simply check for the existence of a EDIT: For context, I'm currently trying to adapt |
That seems really sketchy and unreliable 😞. I worry that there will be cases where you'll have both variables set and be unable to decide. You shouldn't modify the |
Usually, Wayland applications use the According to this blog post by Martin Graesslin of KDE fame, currently working on porting applications from X11 to Wayland, a common solution with Qt-based applications is something like: #if HAVE_X11
if (QX11Info::isPlatformX11()) {
callX11SpecificImplementation();
}
#endif
#if HAVE_WAYLAND
if (QGuiApplication::platformName().startsWith(
QLatin1String("wayland"), Qt::CaseInsensitive)) {
callWaylandSpecificImplementation();
}
#endif While this should work well for |
Handling |
I've been looking further into how applications detect X11 and Wayland sessions at run-time, and I can't find any other way except for checking for |
Also, it looks like Additionally, I noticed that there are two separate arrays for Any insight on how to solve these issues would be very helpful! |
You should not call any of the keyboard functions from inside Also FYI the keyboard input window functions should only be called during capture, they're unused during replay (although maybe some common code still calls them it's not used for anything). If there's an issue getting GL to call the functions consistently then it should be fixed at the source in the GL driver. I suspect the issue is because GL's context handle is a complete mess and is very difficult to actually untangle after the fact. At the moment So the question is - when do you want the information about window use and what's it going to feed into ultimately? That will determine what we can do, considering awkward edge cases. The current code on the PR doesn't use the window at all and seems to get the input from the display directly - is this only to implement filtering so that only input when the window is focussed gets considered? |
Okay, I'll remove those If you check the current state of the PR, it does make use of both the Ultimately, during capture mode, I want the currently active window to get registered with |
Yeh this is unfortunately a consequence of how OpenGL's design is a problem rather than intentional. We can look at vulkan for a better example of how the flow should be:
D3D11 and D3D12 work the same way - the input windows are tied to swapchain creation/destruction. On GL this flow is complicated by steps 1 and 2 being not direct. Windows are attached and detached from contexts arbitrarily and there's no evident lifetime - it's all implicit. Currently the frame capturers work by adding for a window when we first present with it with a given context, and then just kind of.... timing out after 5 seconds 😞. We can't call
OK fair enough, as mentioned on the comments there I hadn't checked the PR's most recent changes until I understood how you wanted to use it and if it was in a state to review yet. It looks like you're doing essentially the same as the windows path - fetching global input and then simply filtering the results by a window whitelist, so that should be fine.
It makes sense but it can't work like this. The active window has a particular meaning in RenderDoc - hitting the capture shortcut will begin a capture at the next present of the active window, and end the capture at the present after that. This is done specifically for the case where you have many windows presenting at different frequencies with different workloads and you want to be sure you capture the one you're interested in. There's a shortcut to cycle between all windows choosing which one is active. For that reason, we can't limit keyboard input only to the active window. If the active window isn't visible currently or isn't presenting we need to be able to cycle away from it with keyboard input to one of the other windows. So we do need to register a set of windows and whitelist input from any of them. So I think what needs more investigation is why Let me know if you need any more info about any of that. I can talk your ear off about reasoning but I don't want to side-track and ramble about something unimportant for ages. |
* This is only lightly tested and may break heavily. It is disabled by default and must be explicitly enabled. * In particular this is only known to work for Wayland use at capture time. Wayland on replay is still unsupported. Known issues include: EGL pbuffer surfaces are not implemented on Wayland, Wayland cannot get window dimensions, and there are hangs/failures with GL and vulkan presentation with Wayland.
I've added experimental support in that commit. I was barely able to get Wayland working as it still seems like it's quite immature, but in a simple test I could capture from GL, GLES and Vulkan on Wayland with that commit. The cmake option is off by default so you need to build with it enabled explicitly. Replaying on Wayland is still not working as I think there are a bunch of problems to solve there, but since it seems like xcb works fine on Wayland this doesn't seem important. Any further testing or improvements are still welcome but note that this should still be considered unsupported for the time being, hence I'm leaving this issue open. |
Hi, I quickly read through the this issue and I'd like clarify or confirm a few things. It's not so much that Wayland uses EGL, but EGL is the only glue API for any OpenGL flavour that supports Wayland. Hence all Wayland applications use EGL for getting at OpenGL. The flavour of OpenGL is not limited in any way. You can use whatever you want: desktop OpenGL both compat and core profiles, any version; OpenGL ES 1, 2, 3 whatever. EGL implementations might vary, but Mesa supports everything. What does EGL do in the Wayland stack is still a good reference. The major difference today is that Detecting the underlying native window system object type from Knowing whether to connect to a Wayland or X11 display is actually a hard problem, see https://gitlab.gnome.org/GNOME/gtk/issues/1741 . Wayland is just a set of protocol specifications and a pair of small IPC libraries really. When people complain that Wayland doesn't work, the reason in almost all cases is in the implementations: app toolkits, each Wayland server/compositor, EGL implementation, etc. Libwayland IPC API was first decided to be callback function based. Thread-safety was demanded for the client side later, which explains some not-so-straightforward API design. Libwayland-client does not run a hidden event loop internally, it still depends on the caller to On Wayland, all objects you can access are restricted to those that you created on that very Wayland connection. Wayland IPC simply has no way to reference an object on a different connection. (People can and have written specific Wayland extensions to export global handles and then refer to them, but that is in no way generic, and requires explicit use from all parties.) Therefore it is very important to do everything on the same Wayland connection ( A Wayland connection cannot be shared between processes, so everything touching the connection must always be in-process. OTOH, a process can use as many Wayland connections as it wants, that will work fine. They will just be all isolated from each other. Passing a Wayland object from a wrong connection will probably result in an abort or a fatal protocol error, sooner or later. Input handling on a connection shared between multiple components/libraries/parties has a catch. When you subscribe to e.g. keyboard events, you do so without specifying a window. The keyboard protocol interface has "focus" events that tell you which window the key events are targeting. On a shared connection, multiple components can listen for input events on the same window, they both see the same events. The catch is, the focus change handling code must be prepared to deal with "unknown" windows - a component must be able to detect that input focus is shifting into a window it did not create. If the code blindly assumes that all windows are its own, it will dereference the user data pointer expecting it to point to something it is not. More information is in Add API to tag proxy objects. This may not be a new problem you to you since you are already looking at windows created by other components, but I thought to mention it. To recap from above, subscribing to input events will deliver you only events for your own windows (those that were created on this Wayland connection). I hope this gives a little more insight. I'm happy to answer further questions about Wayland, but I might not have time to review patches. |
I think what you're talked about has already been addressed in the commit above. I set up something for keyboard input which at least works in my extremely limited testing, and capturing via normal methods and the in-application API works. As mentioned above, using wayland at replay time currently doesn't work at all. There may be other bugs I don't know about since I was barely able to get wayland working so the testing I did was very rudimentary. It will remain disabled by default and I have no plans to come back to this support, so this issue will stay open in case someone wants to fix the remaining bugs, test it, and support it. |
…urk#1463 * The original fix leads to infinite recursion in GLX, EGL hooks. Due to `dlopen` function override in `librenderdoc.so` library the `Process::LoadModule` function always returns a handle of `librenderdoc.so` instead of requested library. So instead of `real function` we receive an address of the `hook` that leads to the infinite recursion in this `hook`. Fixes: 6d40bbb ('Add experimental wayland support. Refs baldurk#853') Tested-by: Andrii Simiklit <[email protected]>
* The original fix leads to infinite recursion in GLX, EGL hooks. Due to `dlopen` function override in `librenderdoc.so` library the `Process::LoadModule` function always returns a handle of `librenderdoc.so` instead of requested library. So instead of `real function` we receive an address of the `hook` that leads to the infinite recursion in this `hook`. Fixes: 6d40bbb ('Add experimental wayland support. Refs #853') Tested-by: Andrii Simiklit <[email protected]>
@baldurk few years passed, Fedora using Wayland by default for some time, Ubuntu 22.04 default to Wayland too. Is there chance you can re-try with Wayland and reconsider? |
As a prerequisite I think it would make sense to first port to Qt6, which includes some important Wayland fixes. |
isn't very convenient. |
"Debugging wayland applcations" and "running qrenderdoc on wayland" seem to be orthogonal issues but are both gated behind the same feature. Running qrenderdoc with QT_QPA_PLATFORM=xcb and debugging a wayland application seems to work fine, while running qrenderdoc itself on wayland is indeed a buggy mess. Could these features be separated, so we have ENABLE_WAYLAND as a separate feature to ENABLE_UNSUPPORTED_EXPERIMENTAL_POSSIBLY_BROKEN_QT_WAYLAND_PLATFORM? |
Debugging does not work on wayland when using GLFW 3.4 and glad 2.0.6. Renderdoc says "Unknown window" in the overlay. |
@DistortedDragon1o4 I had the same issue - you can try to use |
Debugging does not work on wayland when using bare wayland for windowing. My application doesn't have any X11 support whatsoever at the moment so I cannot fallback to X11 for debugging. I think I must request VK_KHR_wayland_surface extension in my case but it is not available when booting app from the renderdoc. Is there a way to debug a wayland application with renderdoc at the time? |
@ahryshan How I do it is build renderdoc myself with the experimental-possibly-broken-wayland-support flag, then run that build with QT_QPA_PLATFORM=xcb set in your environment so renderdoc itself still uses X but will debug Wayland. |
By the way. To anyone running in this issue, at moment of writing this comment the exact name of the flag is |
Many Unix-like platforms are in the process of adopting the more modern Wayland protocol in place of X11, so it would be great to have native Wayland support in the RenderDoc in-application API. Currently, both RenderDoc and the games need to be launched using the XWayland compatibility layer to work properly, which is a bit irritating.
Introducing support for Wayland would require the following changes:
DevicePointer
should support anEGLSurface
(seems like issue Add OpenGL ES support #253 is relevant here).WindowHandle
should support awl_surface
.The text was updated successfully, but these errors were encountered: