ProjectPhysX / FluidX3D

The fastest and most memory efficient lattice Boltzmann CFD software, running on all GPUs via OpenCL. Free for non-commercial use.
https://youtube.com/@ProjectPhysX
Other
3.77k stars 300 forks source link

Issue with interactive graphics mode on Linux with multi-monitor setup #140

Closed abcbcafe closed 7 months ago

abcbcafe commented 7 months ago

Hi, and thanks for the cool software.

I ran into an issue using the interactive graphics mode with a multi-monitor setup on Linux/X11. When launching a simulation, the fullscreen window launches on my main monitor, but the actual visualization inside the window is off-center. The same off-centeredness is also apparent for where the cursor gets picked up. This seems to be caused by DisplayWidth() and DisplayHeight() returning the total/combined size of all monitors, instead of only the size of the main monitor, causing the calculation of the center to be off. See attached screenshot.

I noticed that direct PRs are not accepted, but I wanted to share a workaround for anyone else facing this issue. If it suits the project, feel free to incorporate this into the codebase. The patch uses Xrandr to obtain the dimensions of the primary monitor, which ensures correct positioning of the simulation and mouse cursor. Note that this fix adds a dependency to Xrandr and could probably benefit from some better error handling.


===================================================================
diff --git a/src/graphics.cpp b/src/graphics.cpp
--- a/src/graphics.cpp  (revision e974c92e281ff58a19eb8ab986b75673ca44b341)
+++ b/src/graphics.cpp  (date 1705694483737)
@@ -560,6 +560,7 @@
 #elif defined(__linux__)||defined(__APPLE__)

 #include "X11/include/X11/Xlib.h" // source: libx11-dev
+#include <X11/extensions/Xrandr.h>

 Display* x11_display;
 Window x11_window;
@@ -684,12 +685,22 @@

    x11_display = XOpenDisplay(0);
    if(!x11_display) print_error("No X11 display available.");
-
-   const uint height = (uint)DisplayHeight(x11_display, 0);
-   const uint width = (uint)DisplayWidth(x11_display, 0);
+   Window root = DefaultRootWindow(x11_display);
+   XRRScreenResources *screenResources = XRRGetScreenResources(x11_display, root);
+   
+   RROutput primaryOutput = XRRGetOutputPrimary(x11_display, root);
+   XRROutputInfo *info = XRRGetOutputInfo(x11_display, screenResources, primaryOutput);
+   
+   XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo(x11_display, screenResources, info->crtc);
+   const uint width = crtcInfo->width;
+   const uint height = crtcInfo->height;
    camera = Camera(width, height, 60u);

-   x11_window = XCreateWindow(x11_display, DefaultRootWindow(x11_display), 0, 0, width, height, 0, CopyFromParent, CopyFromParent, CopyFromParent, 0, 0);
+   XRRFreeCrtcInfo(crtcInfo);
+   XRRFreeOutputInfo(info);
+   XRRFreeScreenResources(screenResources);
+
+   x11_window = XCreateWindow(x11_display, root, 0, 0, width, height, 0, CopyFromParent, CopyFromParent, CopyFromParent, 0, 0);
    XStoreName(x11_display, x11_window, WINDOW_NAME);
    struct Hints { long flags=2l, functions=0l, decorations=0b0000000l, input_mode=0l, status=0l; } x11_hints; // decorations=maximize|minimize|menu|title|resize|border|all
    Atom x11_property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", 0);

To build, you'll have to add -lXrandr to the linker flags, e.g. g++ src/*.cpp -o bin/FluidX3D -std=c++17 -pthread -I./src/OpenCL/include -L./src/OpenCL/lib -lOpenCL -I./src/X11/include -L./src/X11/lib -lXrandr -lX11

I don't think it should matter, but for reference, I'm using:

Cheers, and have a great weekend.

Screenshot from 2024-01-19 21-50-41

ProjectPhysX commented 7 months ago

Hi @abcbcafe,

thank you so much for reporting this bug AND proposing a fix! I have fixed the multi-monitor issues now:

Find the commit here.

Kind regards, Moritz