Add use of XShm for faster transfer speeds between game and X server

This commit is contained in:
John Lorentzson 2025-04-09 14:54:13 +02:00
parent e14d3f59f2
commit 2c93c071d1
2 changed files with 59 additions and 19 deletions

View file

@ -572,7 +572,7 @@ if(BACKEND_PLATFORM MATCHES "GLFW3")
endif() endif()
if(BACKEND_PLATFORM MATCHES "X11") if(BACKEND_PLATFORM MATCHES "X11")
target_link_libraries(CSE2 PRIVATE "-lX11") target_link_libraries(CSE2 PRIVATE "-lXext -lX11")
endif() endif()
if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2") if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2")

View file

@ -8,19 +8,55 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
static Window window; static Window window;
static XImage* framebufferImage; static XImage* framebufferImage;
static unsigned char* framebufferPixels; static unsigned char* framebufferPixels;
static int framebufferPitch; static int framebufferPitch;
static unsigned char* xfriendlyFB; static char* xfriendlyFB;
static GC gc; static GC gc;
static int screenWidth; static int screenWidth;
static int screenHeight; static int screenHeight;
static Pixmap intermediate; static bool useShmP = false;
static XShmSegmentInfo seginfo;
extern Display* xDisplay; extern Display* xDisplay;
extern Visual* xVisual; 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) { bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen) {
screenWidth = screen_width; screenWidth = screen_width;
screenHeight = screen_height; screenHeight = screen_height;
@ -28,8 +64,14 @@ bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen
int screen = DefaultScreen(xDisplay); int screen = DefaultScreen(xDisplay);
Window rootWindow = RootWindow(xDisplay, screen); 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 = 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); XSelectInput(xDisplay, window, ExposureMask | KeyPressMask | KeyReleaseMask);
XMapRaised(xDisplay, window); XMapRaised(xDisplay, window);
XStoreName(xDisplay, window, window_title); 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); Atom WM_DELETE_WINDOW = XInternAtom(xDisplay, "WM_DELETE_WINDOW", false);
XSetWMProtocols(xDisplay, window, &WM_DELETE_WINDOW, 1); 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) { if(framebufferImage == 0) {
return false; return false;
} }
@ -64,10 +94,16 @@ unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch)
{ {
*pitch = framebufferPitch; *pitch = framebufferPitch;
return (unsigned char*)framebufferPixels; return (unsigned char*)xfriendlyFB;
} }
void WindowBackend_Software_DestroyWindow(void) { void WindowBackend_Software_DestroyWindow(void) {
if(useShmP) {
XShmDetach(xDisplay, &seginfo);
XDestroyImage(framebufferImage);
shmdt(seginfo.shmaddr);
shmctl(seginfo.shmid, IPC_RMID, 0);
}
XDestroyWindow(xDisplay, window); XDestroyWindow(xDisplay, window);
} }
@ -92,5 +128,9 @@ void WindowBackend_Software_Display(void) {
// srci += 4; // srci += 4;
// } // }
//memcpy(xfriendlyFB, framebufferPixels, screenWidth * screenHeight * 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);
}
} }