From 2c93c071d1142203e1efc6c5ff348c7357d02ce1 Mon Sep 17 00:00:00 2001 From: John Lorentzson Date: Wed, 9 Apr 2025 14:54:13 +0200 Subject: [PATCH] Add use of XShm for faster transfer speeds between game and X server --- CMakeLists.txt | 2 +- .../Rendering/Window/Software/X11.cpp | 76 ++++++++++++++----- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98c27ba6..32d3c5df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -572,7 +572,7 @@ if(BACKEND_PLATFORM MATCHES "GLFW3") endif() if(BACKEND_PLATFORM MATCHES "X11") - target_link_libraries(CSE2 PRIVATE "-lX11") + target_link_libraries(CSE2 PRIVATE "-lXext -lX11") endif() if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2") diff --git a/src/Backends/Rendering/Window/Software/X11.cpp b/src/Backends/Rendering/Window/Software/X11.cpp index 208848e7..e97b887e 100644 --- a/src/Backends/Rendering/Window/Software/X11.cpp +++ b/src/Backends/Rendering/Window/Software/X11.cpp @@ -8,19 +8,55 @@ #include #include +#include +#include +#include static Window window; static XImage* framebufferImage; static unsigned char* framebufferPixels; static int framebufferPitch; -static unsigned char* xfriendlyFB; +static char* xfriendlyFB; static GC gc; static int screenWidth; static int screenHeight; -static Pixmap intermediate; +static bool useShmP = false; +static XShmSegmentInfo seginfo; + extern Display* xDisplay; extern Visual* xVisual; +static bool CheckShm() { + bool exists = XShmQueryExtension(xDisplay); + return exists; +} + +void createFramebuffer() { + gc = DefaultGC(xDisplay, DefaultScreen(xDisplay)); + + int depth = DefaultDepth(xDisplay, DefaultScreen(xDisplay)); + + // Setting up the framebuffer + xfriendlyFB = NULL; + + if(useShmP) { + framebufferImage = XShmCreateImage(xDisplay, xVisual, + depth, ZPixmap, NULL, + &seginfo, screenWidth, screenHeight); + seginfo.shmid = shmget(IPC_PRIVATE, + framebufferImage->bytes_per_line * framebufferImage->height, + IPC_CREAT | 0777); + seginfo.shmaddr = xfriendlyFB = framebufferImage->data = (char*)shmat(seginfo.shmid, NULL, 0); + XShmAttach(xDisplay, &seginfo); + } else { + xfriendlyFB = (char*)malloc(screenWidth * screenHeight * 4); + framebufferImage = XCreateImage(xDisplay, xVisual, + depth, ZPixmap, 0, + (char*)xfriendlyFB, screenWidth, screenHeight, + 32, 0); + } +} + bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen) { screenWidth = screen_width; screenHeight = screen_height; @@ -28,8 +64,14 @@ bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen int screen = DefaultScreen(xDisplay); Window rootWindow = RootWindow(xDisplay, screen); + useShmP = CheckShm(); + if(useShmP) { + Backend_PrintInfo("Using X shared memory extension for higher image transfer speeds.\n"); + } else { + Backend_PrintInfo("Unable to use X shared memory extension. Expect lower performance.\n"); + } + window = XCreateWindow(xDisplay, rootWindow, 0, 0, screen_width, screen_height, 0, 24, InputOutput, xVisual, 0, NULL); - //window = XCreateSimpleWindow(xDisplay, rootWindow, 0, 0, screen_width, screen_height, 1, 0, 0); XSelectInput(xDisplay, window, ExposureMask | KeyPressMask | KeyReleaseMask); XMapRaised(xDisplay, window); XStoreName(xDisplay, window, window_title); @@ -39,20 +81,8 @@ bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen Atom WM_DELETE_WINDOW = XInternAtom(xDisplay, "WM_DELETE_WINDOW", false); XSetWMProtocols(xDisplay, window, &WM_DELETE_WINDOW, 1); - gc = DefaultGC(xDisplay, DefaultScreen(xDisplay)); + createFramebuffer(); - int depth = DefaultDepth(xDisplay, DefaultScreen(xDisplay)); - - intermediate = XCreatePixmap(xDisplay, window, screenWidth, screenHeight, depth); - - // Setting up the framebuffer - framebufferPixels = (unsigned char*)malloc(screen_width * screen_height * 4); - //xfriendlyFB = (unsigned char*)malloc(screen_width * screen_height * 4); - xfriendlyFB = framebufferPixels; - framebufferImage = XCreateImage(xDisplay, xVisual,//DefaultVisual(xDisplay, DefaultScreen(xDisplay)), - depth, ZPixmap, 0, - (char*)xfriendlyFB, screen_width, screen_height, - 32, 0); if(framebufferImage == 0) { return false; } @@ -64,10 +94,16 @@ unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch) { *pitch = framebufferPitch; - return (unsigned char*)framebufferPixels; + return (unsigned char*)xfriendlyFB; } void WindowBackend_Software_DestroyWindow(void) { + if(useShmP) { + XShmDetach(xDisplay, &seginfo); + XDestroyImage(framebufferImage); + shmdt(seginfo.shmaddr); + shmctl(seginfo.shmid, IPC_RMID, 0); + } XDestroyWindow(xDisplay, window); } @@ -92,5 +128,9 @@ void WindowBackend_Software_Display(void) { // srci += 4; // } //memcpy(xfriendlyFB, framebufferPixels, screenWidth * screenHeight * 4); - XPutImage(xDisplay, window, gc, framebufferImage, 0, 0, 0, 0, screenWidth, screenHeight); + if(useShmP) { + XShmPutImage(xDisplay, window, gc, framebufferImage, 0, 0, 0, 0, screenWidth, screenHeight, 0); + } else { + XPutImage(xDisplay, window, gc, framebufferImage, 0, 0, 0, 0, screenWidth, screenHeight); + } }