26#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
27#include <vulkan/vulkan.h>
28#include <vulkan/vulkan_xlib.h>
41int32_t GPUDisplayFrontendX11::GetKey(int32_t
key)
49 if (
key == 65505 ||
key == 65506) {
52 if (
key == 65513 ||
key == 65511) {
142void GPUDisplayFrontendX11::GetKey(XEvent&
event, int32_t& keyOut, int32_t& keyPressOut)
146 if (XLookupString(&
event.xkey, tmpString, 8, &sym,
nullptr) == 0) {
149 int32_t specialKey = GetKey(sym);
150 int32_t localeKey = (
uint8_t)tmpString[0];
154 keyOut = keyPressOut = specialKey;
156 keyOut = keyPressOut = localeKey;
157 if (keyPressOut >=
'a' && keyPressOut <=
'z') {
158 keyPressOut +=
'A' -
'a';
165#ifndef GPUCA_DISPLAY_OPENGL_CORE
170 glColor4f(
r,
g,
b,
a);
172 if (!glIsList(mFontBase)) {
173 GPUError(
"print string: Bad display list.");
175 }
else if (s && strlen(s)) {
176 glPushAttrib(GL_LIST_BIT);
177 glListBase(mFontBase);
185int32_t GPUDisplayFrontendX11::FrontendMain()
187 XSetWindowAttributes windowAttributes;
188 XVisualInfo* visualInfo =
nullptr;
191 GLXContext glxContext =
nullptr;
196 mDisplay = XOpenDisplay(
nullptr);
198 if (mDisplay ==
nullptr) {
199 GPUError(
"could not open display");
204 if (!glXQueryExtension(mDisplay, &errorBase, &eventBase)) {
205 GPUError(
"X server has no OpenGL GLX extension");
209 const char* glxExt = glXQueryExtensionsString(mDisplay, DefaultScreen(mDisplay));
210 if (strstr(glxExt,
"GLX_EXT_swap_control") ==
nullptr) {
211 GPUError(
"No vsync support!");
212 vsync_supported =
false;
214 vsync_supported =
true;
218 int32_t attribs[] = {GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_DOUBLEBUFFER, True,
223 GLXFBConfig fbconfig =
nullptr;
225 GLXFBConfig* fbc = glXChooseFBConfig(mDisplay, DefaultScreen(mDisplay), attribs, &fbcount);
226 if (fbc ==
nullptr || fbcount == 0) {
227 GPUError(
"Failed to get MSAA GLXFBConfig");
232 visualInfo = glXGetVisualFromFBConfig(mDisplay, fbconfig);
234 if (visualInfo ==
nullptr) {
235 GPUError(
"no RGB visual with depth buffer");
242 if (glXCreateContextAttribsARB) {
243 int32_t context_attribs[] = {
246 GLX_CONTEXT_PROFILE_MASK_ARB,
mBackend->
CoreProfile() ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB : GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
248 glxContext = glXCreateContextAttribsARB(mDisplay, fbconfig,
nullptr,
GL_TRUE, context_attribs);
250 glxContext = glXCreateContext(mDisplay, visualInfo,
nullptr,
GL_TRUE);
252 if (glxContext ==
nullptr) {
253 GPUError(
"could not create rendering context");
258 Window win = RootWindow(mDisplay, visualInfo->screen);
259 colorMap = XCreateColormap(mDisplay, win, visualInfo->visual, AllocNone);
260 windowAttributes.colormap = colorMap;
261 windowAttributes.border_pixel = 0;
262 windowAttributes.event_mask = ExposureMask | VisibilityChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask;
266 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBorderPixel | CWColormap | CWEventMask, &windowAttributes);
269 glXMakeCurrent(mDisplay, mWindow, glxContext);
271 XMapWindow(mDisplay, mWindow);
277 Atom WM_DELETE_WINDOW = XInternAtom(mDisplay,
"WM_DELETE_WINDOW", False);
278 XSetWMProtocols(mDisplay, mWindow, &WM_DELETE_WINDOW, 1);
279#ifndef GPUCA_DISPLAY_OPENGL_CORE
280 XFontStruct* font_info =
nullptr;
283 mFontBase = glGenLists(256);
284 if (!glIsList(mFontBase)) {
285 GPUError(
"Out of display lists.");
288 const char*
f =
"fixed";
289 font_info = XLoadQueryFont(mDisplay,
f);
291 GPUError(
"XLoadQueryFont failed.");
294 int32_t
first = font_info->min_char_or_byte2;
295 int32_t
last = font_info->max_char_or_byte2;
296 glXUseXFont(font_info->fid,
first, last -
first + 1, mFontBase +
first);
306 fprintf(stderr,
"Error initializing backend\n");
310 XMapWindow(mDisplay, mWindow);
312 int32_t x11_fd = ConnectionNumber(mDisplay);
316 mGlXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((
const GLubyte*)
"glXSwapIntervalEXT");
317 if (mGlXSwapIntervalEXT ==
nullptr) {
318 GPUError(
"Cannot enable vsync");
321 mGlXSwapIntervalEXT(mDisplay, glXGetCurrentDrawable(), 1);
328 pthread_mutex_lock(&mSemLockExit);
329 mDisplayRunning =
true;
330 pthread_mutex_unlock(&mSemLockExit);
332 std::chrono::high_resolution_clock::time_point
t1 = std::chrono::high_resolution_clock::now();
334 int32_t num_ready_fds;
337 int32_t waitCount = 0;
340 FD_SET(x11_fd, &in_fds);
343 std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
344 bool allowMax =
mMaxFPSRate && std::chrono::duration_cast<std::chrono::duration<double>>(t2 -
t1).
count() < 0.01;
346 num_ready_fds = allowMax || XPending(mDisplay) ||
select(x11_fd + 1, &in_fds,
nullptr,
nullptr, &tv);
347 if (num_ready_fds < 0) {
348 GPUError(
"Error (num_ready_fds)");
356 if (waitCount++ != 100) {
367 if (!XPending(mDisplay)) {
370 XNextEvent(mDisplay, &
event);
372 switch (
event.type) {
374 if (
event.xbutton.button == 4) {
376 }
else if (
event.xbutton.button == 5) {
379 if (
event.xbutton.button == 1) {
390 case ButtonRelease: {
391 if (
event.xbutton.button != 4 &&
event.xbutton.button != 5) {
392 if (
event.xbutton.button == 1) {
402 int32_t handleKey = 0, keyPress = 0;
405 mKeys[keyPress] =
true;
411 int32_t handleKey = 0, keyPress = 0;
413 mKeys[keyPress] =
false;
428 case ConfigureNotify: {
433 case ClientMessage: {
434 if (
event.xclient.message_type == XInternAtom(mDisplay,
"_NET_WM_STATE", False)) {
442 }
while (XPending(mDisplay));
449 glXSwapBuffers(mDisplay, mWindow);
453#ifndef GPUCA_DISPLAY_OPENGL_CORE
455 glDeleteLists(mFontBase, 256);
456 XUnloadFont(mDisplay, font_info->fid);
461 glXDestroyContext(mDisplay, glxContext);
464 XDestroyWindow(mDisplay, mWindow);
465 XCloseDisplay(mDisplay);
467 pthread_mutex_lock(&mSemLockExit);
468 mDisplayRunning =
false;
469 pthread_mutex_unlock(&mSemLockExit);
476 pthread_mutex_lock(&mSemLockExit);
477 if (mDisplayRunning) {
480 pthread_mutex_unlock(&mSemLockExit);
481 while (mDisplayRunning) {
489 memset(&xev, 0,
sizeof(xev));
490 xev.type = ClientMessage;
491 xev.xclient.window = mWindow;
492 xev.xclient.message_type = XInternAtom(mDisplay,
"_NET_WM_STATE", False);
493 xev.xclient.format = 32;
494 xev.xclient.data.l[0] = 2;
495 xev.xclient.data.l[1] = XInternAtom(mDisplay,
"_NET_WM_STATE_FULLSCREEN", True);
496 xev.xclient.data.l[2] = 0;
497 XSendEvent(mDisplay, DefaultRootWindow(mDisplay), False, SubstructureNotifyMask, &xev);
503 memset(&xev, 0,
sizeof(xev));
504 xev.type = ClientMessage;
505 xev.xclient.window = mWindow;
506 xev.xclient.message_type = XInternAtom(mDisplay,
"_NET_WM_STATE", False);
507 xev.xclient.format = 32;
508 xev.xclient.data.l[0] = set ? 1 : 2;
509 xev.xclient.data.l[1] = XInternAtom(mDisplay,
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
510 xev.xclient.data.l[2] = XInternAtom(mDisplay,
"_NET_WM_STATE_MAXIMIZED_VERT", False);
511 XSendEvent(mDisplay, DefaultRootWindow(mDisplay), False, SubstructureNotifyMask, &xev);
517 mGlXSwapIntervalEXT(mDisplay, glXGetCurrentDrawable(), (int32_t)
enable);
525 GPUError(
"Coult not Create frontend Thread...");
534 int32_t x_return, y_return;
535 uint32_t width_return, height_return, border_width_return, depth_return;
536 if (XGetGeometry(mDisplay, mWindow, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return) == 0) {
537 throw std::runtime_error(
"Cannot query X11 window geometry");
539 width = width_return;
545#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
546 VkXlibSurfaceCreateInfoKHR info{};
547 info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
550 info.window = mWindow;
551 return vkCreateXlibSurfaceKHR(*(VkInstance*)instance, &info,
nullptr, (VkSurfaceKHR*)surface) != VK_SUCCESS;
559 static const char* exts[] = {
"VK_KHR_surface",
"VK_KHR_xlib_surface"};
int32_t GetKey(int32_t key)
GLXContext(* glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int32_t *)
virtual bool CoreProfile()
virtual int32_t ExtInit()
void getSize(int32_t &width, int32_t &height) override
void DisplayExit() override
int32_t getVulkanSurface(void *instance, void *surface) override
void ToggleMaximized(bool set) override
void OpenGLPrint(const char *s, float x, float y, float r, float g, float b, float a, bool fromBotton=true) override
uint32_t getReqVulkanExtensions(const char **&p) override
int32_t StartDisplay() override
void SwitchFullscreen(bool set) override
void SetVSync(bool enable) override
int32_t & drawTextFontSize()
static constexpr int32_t KEY_F9
const char * mFrontendName
static constexpr int32_t KEY_F2
static void * FrontendThreadWrapper(void *)
static constexpr int32_t KEY_ALT
void HandleKey(uint8_t key)
static constexpr int32_t KEY_F12
static constexpr int32_t KEY_F7
static constexpr int32_t KEY_END
static constexpr int32_t KEY_PAGEDOWN
static constexpr int32_t KEY_RALT
volatile int32_t mDisplayControl
static constexpr int32_t KEY_F10
static constexpr int32_t KEY_F4
static constexpr int32_t KEY_LEFT
static constexpr int32_t KEY_ENTER
static constexpr int32_t KEY_F6
volatile int32_t mNeedUpdate
static constexpr int32_t KEY_CTRL
static constexpr int32_t KEY_F1
void ResizeScene(int32_t width, int32_t height)
static constexpr const char * DISPLAY_WINDOW_NAME
static constexpr int32_t INIT_WIDTH
static constexpr int32_t GL_MIN_VERSION_MAJOR
frontendTypes mFrontendType
static constexpr int32_t KEY_SHIFT
static constexpr int32_t KEY_F3
static constexpr int32_t KEY_INSERT
static constexpr int32_t KEY_F11
static constexpr int32_t KEY_SPACE
static constexpr int32_t KEY_F5
static constexpr int32_t KEY_PAGEUP
static constexpr int32_t KEY_HOME
GPUDisplayBackend * mBackend
static constexpr int32_t GL_MIN_VERSION_MINOR
int32_t InitDisplay(bool initFailure=false)
GPUDisplayBackend * backend()
static constexpr int32_t KEY_UP
static constexpr int32_t KEY_DOWN
static constexpr int32_t KEY_F8
static constexpr int32_t INIT_HEIGHT
static constexpr int32_t KEY_RIGHT
volatile int32_t mSendKey
static constexpr int32_t KEY_RCTRL
static constexpr int32_t KEY_ESCAPE
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
uint8_t itsSharedClusterMap uint8_t
std::vector< InputSpec > select(char const *matcher="")
Marks an empty item in the context.