28#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
29#include <vulkan/vulkan.h>
30#include <vulkan/vulkan_xlib.h>
43int32_t GPUDisplayFrontendX11::GetKey(int32_t
key)
51 if (
key == 65505 ||
key == 65506) {
54 if (
key == 65513 ||
key == 65511) {
144void GPUDisplayFrontendX11::GetKey(XEvent&
event, int32_t& keyOut, int32_t& keyPressOut)
148 if (XLookupString(&
event.xkey, tmpString, 8, &sym,
nullptr) == 0) {
151 int32_t specialKey = GetKey(sym);
152 int32_t localeKey = (
uint8_t)tmpString[0];
156 keyOut = keyPressOut = specialKey;
158 keyOut = keyPressOut = localeKey;
159 if (keyPressOut >=
'a' && keyPressOut <=
'z') {
160 keyPressOut +=
'A' -
'a';
167#ifndef GPUCA_DISPLAY_OPENGL_CORE
172 glColor4f(
r,
g,
b,
a);
174 if (!glIsList(mFontBase)) {
175 GPUError(
"print string: Bad display list.");
177 }
else if (s && strlen(s)) {
178 glPushAttrib(GL_LIST_BIT);
179 glListBase(mFontBase);
187int32_t GPUDisplayFrontendX11::FrontendMain()
189 XSetWindowAttributes windowAttributes;
190 XVisualInfo* visualInfo =
nullptr;
193 GLXContext glxContext =
nullptr;
198 mDisplay = XOpenDisplay(
nullptr);
200 if (mDisplay ==
nullptr) {
201 GPUError(
"could not open display");
206 if (!glXQueryExtension(mDisplay, &errorBase, &eventBase)) {
207 GPUError(
"X server has no OpenGL GLX extension");
211 const char* glxExt = glXQueryExtensionsString(mDisplay, DefaultScreen(mDisplay));
212 if (strstr(glxExt,
"GLX_EXT_swap_control") ==
nullptr) {
213 GPUError(
"No vsync support!");
214 vsync_supported =
false;
216 vsync_supported =
true;
220 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,
225 GLXFBConfig fbconfig =
nullptr;
227 GLXFBConfig* fbc = glXChooseFBConfig(mDisplay, DefaultScreen(mDisplay), attribs, &fbcount);
228 if (fbc ==
nullptr || fbcount == 0) {
229 GPUError(
"Failed to get MSAA GLXFBConfig");
234 visualInfo = glXGetVisualFromFBConfig(mDisplay, fbconfig);
236 if (visualInfo ==
nullptr) {
237 GPUError(
"no RGB visual with depth buffer");
244 if (glXCreateContextAttribsARB) {
245 int32_t context_attribs[] = {
248 GLX_CONTEXT_PROFILE_MASK_ARB,
mBackend->
CoreProfile() ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB : GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
250 glxContext = glXCreateContextAttribsARB(mDisplay, fbconfig,
nullptr,
GL_TRUE, context_attribs);
252 glxContext = glXCreateContext(mDisplay, visualInfo,
nullptr,
GL_TRUE);
254 if (glxContext ==
nullptr) {
255 GPUError(
"could not create rendering context");
260 Window win = RootWindow(mDisplay, visualInfo->screen);
261 colorMap = XCreateColormap(mDisplay, win, visualInfo->visual, AllocNone);
262 windowAttributes.colormap = colorMap;
263 windowAttributes.border_pixel = 0;
264 windowAttributes.event_mask = ExposureMask | VisibilityChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask;
268 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBorderPixel | CWColormap | CWEventMask, &windowAttributes);
271 glXMakeCurrent(mDisplay, mWindow, glxContext);
273 XMapWindow(mDisplay, mWindow);
279 Atom WM_DELETE_WINDOW = XInternAtom(mDisplay,
"WM_DELETE_WINDOW", False);
280 XSetWMProtocols(mDisplay, mWindow, &WM_DELETE_WINDOW, 1);
281#ifndef GPUCA_DISPLAY_OPENGL_CORE
282 XFontStruct* font_info =
nullptr;
285 mFontBase = glGenLists(256);
286 if (!glIsList(mFontBase)) {
287 GPUError(
"Out of display lists.");
290 const char*
f =
"fixed";
291 font_info = XLoadQueryFont(mDisplay,
f);
293 GPUError(
"XLoadQueryFont failed.");
296 int32_t
first = font_info->min_char_or_byte2;
297 int32_t
last = font_info->max_char_or_byte2;
298 glXUseXFont(font_info->fid,
first, last -
first + 1, mFontBase +
first);
308 fprintf(stderr,
"Error initializing backend\n");
312 XMapWindow(mDisplay, mWindow);
314 int32_t x11_fd = ConnectionNumber(mDisplay);
318 mGlXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((
const GLubyte*)
"glXSwapIntervalEXT");
319 if (mGlXSwapIntervalEXT ==
nullptr) {
320 GPUError(
"Cannot enable vsync");
323 mGlXSwapIntervalEXT(mDisplay, glXGetCurrentDrawable(), 1);
330 pthread_mutex_lock(&mSemLockExit);
331 mDisplayRunning =
true;
332 pthread_mutex_unlock(&mSemLockExit);
334 std::chrono::high_resolution_clock::time_point
t1 = std::chrono::high_resolution_clock::now();
336 int32_t num_ready_fds;
339 int32_t waitCount = 0;
342 FD_SET(x11_fd, &in_fds);
345 std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
346 bool allowMax =
mMaxFPSRate && std::chrono::duration_cast<std::chrono::duration<double>>(t2 -
t1).
count() < 0.01;
348 num_ready_fds = allowMax || XPending(mDisplay) ||
select(x11_fd + 1, &in_fds,
nullptr,
nullptr, &tv);
349 if (num_ready_fds < 0) {
350 GPUError(
"Error (num_ready_fds)");
358 if (waitCount++ != 100) {
369 if (!XPending(mDisplay)) {
372 XNextEvent(mDisplay, &
event);
374 switch (
event.type) {
376 if (
event.xbutton.button == 4) {
378 }
else if (
event.xbutton.button == 5) {
381 if (
event.xbutton.button == 1) {
392 case ButtonRelease: {
393 if (
event.xbutton.button != 4 &&
event.xbutton.button != 5) {
394 if (
event.xbutton.button == 1) {
404 int32_t handleKey = 0, keyPress = 0;
407 mKeys[keyPress] =
true;
413 int32_t handleKey = 0, keyPress = 0;
415 mKeys[keyPress] =
false;
430 case ConfigureNotify: {
435 case ClientMessage: {
436 if (
event.xclient.message_type == XInternAtom(mDisplay,
"_NET_WM_STATE", False)) {
444 }
while (XPending(mDisplay));
451 glXSwapBuffers(mDisplay, mWindow);
455#ifndef GPUCA_DISPLAY_OPENGL_CORE
457 glDeleteLists(mFontBase, 256);
458 XUnloadFont(mDisplay, font_info->fid);
463 glXDestroyContext(mDisplay, glxContext);
466 XDestroyWindow(mDisplay, mWindow);
467 XCloseDisplay(mDisplay);
469 pthread_mutex_lock(&mSemLockExit);
470 mDisplayRunning =
false;
471 pthread_mutex_unlock(&mSemLockExit);
478 pthread_mutex_lock(&mSemLockExit);
479 if (mDisplayRunning) {
482 pthread_mutex_unlock(&mSemLockExit);
483 while (mDisplayRunning) {
491 memset(&xev, 0,
sizeof(xev));
492 xev.type = ClientMessage;
493 xev.xclient.window = mWindow;
494 xev.xclient.message_type = XInternAtom(mDisplay,
"_NET_WM_STATE", False);
495 xev.xclient.format = 32;
496 xev.xclient.data.l[0] = 2;
497 xev.xclient.data.l[1] = XInternAtom(mDisplay,
"_NET_WM_STATE_FULLSCREEN", True);
498 xev.xclient.data.l[2] = 0;
499 XSendEvent(mDisplay, DefaultRootWindow(mDisplay), False, SubstructureNotifyMask, &xev);
505 memset(&xev, 0,
sizeof(xev));
506 xev.type = ClientMessage;
507 xev.xclient.window = mWindow;
508 xev.xclient.message_type = XInternAtom(mDisplay,
"_NET_WM_STATE", False);
509 xev.xclient.format = 32;
510 xev.xclient.data.l[0] = set ? 1 : 2;
511 xev.xclient.data.l[1] = XInternAtom(mDisplay,
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
512 xev.xclient.data.l[2] = XInternAtom(mDisplay,
"_NET_WM_STATE_MAXIMIZED_VERT", False);
513 XSendEvent(mDisplay, DefaultRootWindow(mDisplay), False, SubstructureNotifyMask, &xev);
519 mGlXSwapIntervalEXT(mDisplay, glXGetCurrentDrawable(), (int32_t)
enable);
526 int32_t x_return, y_return;
527 uint32_t width_return, height_return, border_width_return, depth_return;
528 if (XGetGeometry(mDisplay, mWindow, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return) == 0) {
529 throw std::runtime_error(
"Cannot query X11 window geometry");
531 width = width_return;
537#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
538 VkXlibSurfaceCreateInfoKHR info{};
539 info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
542 info.window = mWindow;
543 return vkCreateXlibSurfaceKHR(*(VkInstance*)instance, &info,
nullptr, (VkSurfaceKHR*)surface) != VK_SUCCESS;
551 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
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 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.