diff --git a/CMakeLists.txt b/CMakeLists.txt index 235c097..16322d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,6 @@ else() lib/x11/ApplicationWayland.hpp lib/x11/WindowXCB.cpp lib/x11/WindowWayland.cpp - lib/x11/GraphicsContextXCB.cpp lib/x11/GraphicsContextWayland.cpp lib/inputdev/HIDListenerUdev.cpp lib/inputdev/HIDDeviceUdev.cpp) @@ -73,7 +72,7 @@ else() endif() include_directories(${DBUS_INCLUDE_DIR} ${DBUS_ARCH_INCLUDE_DIR}) - list(APPEND _BOO_SYS_LIBS xcb xcb-glx xcb-xinput xcb-xkb xcb-keysyms xkbcommon xkbcommon-x11 ${DBUS_LIBRARY} udev pthread) + list(APPEND _BOO_SYS_LIBS xcb xcb-glx xcb-xinput xcb-xkb xcb-keysyms xkbcommon xkbcommon-x11 GL ${DBUS_LIBRARY} udev pthread) endif() diff --git a/include/boo/IApplication.hpp b/include/boo/IApplication.hpp index fc88800..27f4096 100644 --- a/include/boo/IApplication.hpp +++ b/include/boo/IApplication.hpp @@ -14,9 +14,8 @@ class IApplication; struct IApplicationCallback { - virtual void appLaunched(IApplication* app) {(void)app;} - virtual void appQuitting(IApplication* app) {(void)app;} - virtual void appFilesOpen(IApplication* app, const std::vector& paths) {(void)app;(void)paths;} + virtual void appQuitting(IApplication*) {} + virtual void appFilesOpen(IApplication*, const std::vector&) {} }; class IApplication @@ -44,8 +43,7 @@ public: }; virtual EPlatformType getPlatformType() const=0; - virtual void run()=0; - virtual void quit()=0; + virtual void pump()=0; virtual const std::string& getUniqueName() const=0; virtual const std::string& getFriendlyName() const=0; virtual const std::string& getProcessName() const=0; diff --git a/include/boo/IWindow.hpp b/include/boo/IWindow.hpp index 6418f87..d63c9d3 100644 --- a/include/boo/IWindow.hpp +++ b/include/boo/IWindow.hpp @@ -127,6 +127,8 @@ public: virtual bool isFullscreen() const=0; virtual void setFullscreen(bool fs)=0; + + virtual void waitForRetrace()=0; virtual uintptr_t getPlatformHandle() const=0; virtual void _incomingEvent(void* event) {(void)event;} diff --git a/lib/x11/ApplicationWayland.hpp b/lib/x11/ApplicationWayland.hpp index c157bf2..59b4c1c 100644 --- a/lib/x11/ApplicationWayland.hpp +++ b/lib/x11/ApplicationWayland.hpp @@ -46,16 +46,11 @@ public: return PLAT_WAYLAND; } - void run() + void pump() { } - void quit() - { - - } - const std::string& getUniqueName() const { return m_uniqueName; diff --git a/lib/x11/ApplicationXCB.hpp b/lib/x11/ApplicationXCB.hpp index 626a8f9..26aca1e 100644 --- a/lib/x11/ApplicationXCB.hpp +++ b/lib/x11/ApplicationXCB.hpp @@ -10,8 +10,13 @@ #include #include #include +#include #undef explicit +#include +#include +#include + #include DBusConnection* registerDBus(const char* appName, bool& isFirst); @@ -20,6 +25,10 @@ DBusConnection* registerDBus(const char* appName, bool& isFirst); namespace boo { +PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI = nullptr; +PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI = nullptr; + +int XCB_GLX_EVENT_BASE = 0; int XINPUT_OPCODE = 0; static xcb_window_t getWindowOfEvent(xcb_generic_event_t* event, bool& windowEvent) @@ -131,7 +140,7 @@ class ApplicationXCB final : public IApplication std::unordered_map m_windows; xcb_connection_t* m_xcbConn = NULL; - bool m_running; + int m_xcbFd, m_dbusFd, m_maxFd; void _deletedWindow(IWindow* window) { @@ -198,6 +207,13 @@ public: /* Open X connection */ m_xcbConn = xcb_connect(NULL, NULL); + /* GLX extension data */ + const xcb_query_extension_reply_t* glxExtData = + xcb_get_extension_data(m_xcbConn, &xcb_glx_id); + XCB_GLX_EVENT_BASE = glxExtData->first_event; + FglXGetVideoSyncSGI = PFNGLXGETVIDEOSYNCSGIPROC(glXGetProcAddress((GLubyte*)"glXGetVideoSyncSGI")); + FglXWaitVideoSyncSGI = PFNGLXWAITVIDEOSYNCSGIPROC(glXGetProcAddress((GLubyte*)"glXWaitVideoSyncSGI")); + /* The xkb extension requests that the X server does not * send repeated keydown events when a key is held */ xkb_x11_setup_xkb_extension(m_xcbConn, @@ -212,9 +228,14 @@ public: /* Xinput major opcode */ const xcb_query_extension_reply_t* xiReply = xcb_get_extension_data(m_xcbConn, &xcb_input_id); - if (xiReply) - XINPUT_OPCODE = xiReply->major_opcode; + XINPUT_OPCODE = xiReply->major_opcode; + /* Get file descriptors of xcb and dbus interfaces */ + m_xcbFd = xcb_get_file_descriptor(m_xcbConn); + dbus_connection_get_unix_fd(m_dbus, &m_dbusFd); + m_maxFd = MAX(m_xcbFd, m_dbusFd); + + xcb_flush(m_xcbConn); } ~ApplicationXCB() @@ -227,35 +248,23 @@ public: return PLAT_XCB; } - void run() + void pump() { if (!m_xcbConn) return; xcb_generic_event_t* event; - m_running = true; - m_callback.appLaunched(this); - xcb_flush(m_xcbConn); + fd_set fds; + FD_ZERO(&fds); + FD_SET(m_xcbFd, &fds); + FD_SET(m_dbusFd, &fds); + select(m_maxFd+1, &fds, NULL, NULL, NULL); - int xcbFd = xcb_get_file_descriptor(m_xcbConn); - int dbusFd; - dbus_connection_get_unix_fd(m_dbus, &dbusFd); - int maxFd = MAX(xcbFd, dbusFd); - - while (m_running) + if (FD_ISSET(m_xcbFd, &fds)) { - fd_set fds; - FD_ZERO(&fds); - FD_SET(xcbFd, &fds); - FD_SET(dbusFd, &fds); - select(maxFd+1, &fds, NULL, NULL, NULL); - - if (FD_ISSET(xcbFd, &fds)) + event = xcb_poll_for_event(m_xcbConn); + if (event) { - event = xcb_poll_for_event(m_xcbConn); - if (!event) - break; - bool windowEvent; xcb_window_t evWindow = getWindowOfEvent(event, windowEvent); //fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event)); @@ -267,40 +276,33 @@ public: } free(event); } - - if (FD_ISSET(dbusFd, &fds)) - { - DBusMessage* msg; - dbus_connection_read_write(m_dbus, 0); - while ((msg = dbus_connection_pop_message(m_dbus))) - { - /* check if the message is a signal from the correct interface and with the correct name */ - if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open")) - { - /* read the parameters */ - std::vector paths; - DBusMessageIter iter; - dbus_message_iter_init(msg, &iter); - while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) - { - const char* argVal; - dbus_message_iter_get_basic(&iter, &argVal); - paths.push_back(argVal); - dbus_message_iter_next(&iter); - } - m_callback.appFilesOpen(this, paths); - } - dbus_message_unref(msg); - } - } } - m_callback.appQuitting(this); - } - - void quit() - { - m_running = false; + if (FD_ISSET(m_dbusFd, &fds)) + { + DBusMessage* msg; + dbus_connection_read_write(m_dbus, 0); + while ((msg = dbus_connection_pop_message(m_dbus))) + { + /* check if the message is a signal from the correct interface and with the correct name */ + if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open")) + { + /* read the parameters */ + std::vector paths; + DBusMessageIter iter; + dbus_message_iter_init(msg, &iter); + while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID) + { + const char* argVal; + dbus_message_iter_get_basic(&iter, &argVal); + paths.push_back(argVal); + dbus_message_iter_next(&iter); + } + m_callback.appFilesOpen(this, paths); + } + dbus_message_unref(msg); + } + } } const std::string& getUniqueName() const diff --git a/lib/x11/GraphicsContextXCB.cpp b/lib/x11/GraphicsContextXCB.cpp deleted file mode 100644 index 8544e14..0000000 --- a/lib/x11/GraphicsContextXCB.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "boo/IGraphicsContext.hpp" -#include "boo/IWindow.hpp" - -#include -#include -#include -#include -#include -#include -#include - -namespace boo -{ - -struct GraphicsContextXCB : IGraphicsContext -{ - - EGraphicsAPI m_api; - EPixelFormat m_pf; - IWindow* m_parentWindow; - xcb_connection_t* m_xcbConn; - - xcb_glx_fbconfig_t m_fbconfig = 0; - xcb_visualid_t m_visualid = 0; - xcb_glx_window_t m_glxWindow = 0; - xcb_glx_context_t m_glxCtx = 0; - xcb_glx_context_tag_t m_glxCtxTag = 0; - - std::thread* m_commandThread = NULL; - -public: - IWindowCallback* m_callback; - - GraphicsContextXCB(EGraphicsAPI api, IWindow* parentWindow, xcb_connection_t* conn, uint32_t& visualIdOut) - : m_api(api), - m_pf(PF_RGBA8), - m_parentWindow(parentWindow), - m_xcbConn(conn) - { - - /* WTF freedesktop?? Fix this awful API and your nonexistant docs */ - xcb_glx_get_fb_configs_reply_t* fbconfigs = - xcb_glx_get_fb_configs_reply(m_xcbConn, xcb_glx_get_fb_configs(m_xcbConn, 0), NULL); - struct conf_prop - { - uint32_t key; - uint32_t val; - }* props = (struct conf_prop*)xcb_glx_get_fb_configs_property_list(fbconfigs); - - for (uint32_t i=0 ; inum_FB_configs ; ++i) - { - struct conf_prop* configProps = &props[fbconfigs->num_properties * i]; - uint32_t fbconfId, visualId, depthSize, colorSize, doubleBuffer; - for (uint32_t j=0 ; jnum_properties ; ++j) - { - struct conf_prop* prop = &configProps[j]; - if (prop->key == GLX_FBCONFIG_ID) - fbconfId = prop->val; - if (prop->key == GLX_VISUAL_ID) - visualId = prop->val; - else if (prop->key == GLX_DEPTH_SIZE) - depthSize = prop->val; - else if (prop->key == GLX_BUFFER_SIZE) - colorSize = prop->val; - else if (prop->key == GLX_DOUBLEBUFFER) - doubleBuffer = prop->val; - } - - /* Double-buffer only */ - if (!doubleBuffer) - continue; - - if (m_pf == PF_RGBA8 && colorSize >= 32) - { - m_fbconfig = fbconfId; - m_visualid = visualId; - break; - } - else if (m_pf == PF_RGBA8_Z24 && colorSize >= 32 && depthSize >= 24) - { - m_fbconfig = fbconfId; - m_visualid = visualId; - break; - } - else if (m_pf == PF_RGBAF32 && colorSize >= 128) - { - m_fbconfig = fbconfId; - m_visualid = visualId; - break; - } - else if (m_pf == PF_RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24) - { - m_fbconfig = fbconfId; - m_visualid = visualId; - break; - } - } - free(fbconfigs); - - if (!m_fbconfig) - { - fprintf(stderr, "unable to find suitable pixel format"); - return; - } - - visualIdOut = m_visualid; - } - - ~GraphicsContextXCB() - { - - } - - void _setCallback(IWindowCallback* cb) - { - m_callback = cb; - } - - EGraphicsAPI getAPI() const - { - return m_api; - } - - EPixelFormat getPixelFormat() const - { - return m_pf; - } - - void setPixelFormat(EPixelFormat pf) - { - if (pf > PF_RGBAF32_Z24) - return; - m_pf = pf; - } - - void initializeContext() - { - m_glxWindow = xcb_generate_id(m_xcbConn); - xcb_glx_create_window(m_xcbConn, 0, m_fbconfig, - m_parentWindow->getPlatformHandle(), - m_glxWindow, 0, NULL); - } - -}; - -IGraphicsContext* _GraphicsContextXCBNew(IGraphicsContext::EGraphicsAPI api, - IWindow* parentWindow, xcb_connection_t* conn, - uint32_t& visualIdOut) -{ - return new GraphicsContextXCB(api, parentWindow, conn, visualIdOut); -} - -} diff --git a/lib/x11/WindowWayland.cpp b/lib/x11/WindowWayland.cpp index 442836d..026d8fe 100644 --- a/lib/x11/WindowWayland.cpp +++ b/lib/x11/WindowWayland.cpp @@ -1,8 +1,15 @@ #include "boo/IWindow.hpp" #include "boo/IGraphicsContext.hpp" +#include +#include +#include + namespace boo { + +extern PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI; +extern PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI; IGraphicsContext* _CGraphicsContextWaylandNew(IGraphicsContext::EGraphicsAPI api, IWindow* parentWindow); @@ -74,6 +81,12 @@ struct WindowWayland : IWindow } + void waitForRetrace() + { + unsigned int sync; + FglXWaitVideoSyncSGI(1, 0, &sync); + } + uintptr_t getPlatformHandle() const { diff --git a/lib/x11/WindowXCB.cpp b/lib/x11/WindowXCB.cpp index b2200ec..3b078a3 100644 --- a/lib/x11/WindowXCB.cpp +++ b/lib/x11/WindowXCB.cpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -25,6 +28,10 @@ namespace boo { +extern PFNGLXGETVIDEOSYNCSGIPROC FglXGetVideoSyncSGI; +extern PFNGLXWAITVIDEOSYNCSGIPROC FglXWaitVideoSyncSGI; + +extern int XCB_GLX_EVENT_BASE; extern int XINPUT_OPCODE; static inline double fp3232val(xcb_input_fp3232_t* val) @@ -146,16 +153,141 @@ static void genFrameDefault(xcb_screen_t* screen, int* xOut, int* yOut, int* wOu *hOut = height; } -IGraphicsContext* _GraphicsContextXCBNew(IGraphicsContext::EGraphicsAPI api, - IWindow* parentWindow, xcb_connection_t* conn, - uint32_t& visualIdOut); +struct GraphicsContextXCB : IGraphicsContext +{ + EGraphicsAPI m_api; + EPixelFormat m_pf; + IWindow* m_parentWindow; + xcb_connection_t* m_xcbConn; + + xcb_glx_fbconfig_t m_fbconfig = 0; + xcb_visualid_t m_visualid = 0; + xcb_glx_window_t m_glxWindow = 0; + xcb_glx_context_t m_glxCtx = 0; + xcb_glx_context_tag_t m_glxCtxTag = 0; + +public: + IWindowCallback* m_callback; + + GraphicsContextXCB(EGraphicsAPI api, IWindow* parentWindow, xcb_connection_t* conn, uint32_t& visualIdOut) + : m_api(api), + m_pf(PF_RGBA8), + m_parentWindow(parentWindow), + m_xcbConn(conn) + { + + /* WTF freedesktop?? Fix this awful API and your nonexistant docs */ + xcb_glx_get_fb_configs_reply_t* fbconfigs = + xcb_glx_get_fb_configs_reply(m_xcbConn, xcb_glx_get_fb_configs(m_xcbConn, 0), NULL); + struct conf_prop + { + uint32_t key; + uint32_t val; + }* props = (struct conf_prop*)xcb_glx_get_fb_configs_property_list(fbconfigs); + + for (uint32_t i=0 ; inum_FB_configs ; ++i) + { + struct conf_prop* configProps = &props[fbconfigs->num_properties * i]; + uint32_t fbconfId, visualId, depthSize, colorSize, doubleBuffer; + for (uint32_t j=0 ; jnum_properties ; ++j) + { + struct conf_prop* prop = &configProps[j]; + if (prop->key == GLX_FBCONFIG_ID) + fbconfId = prop->val; + if (prop->key == GLX_VISUAL_ID) + visualId = prop->val; + else if (prop->key == GLX_DEPTH_SIZE) + depthSize = prop->val; + else if (prop->key == GLX_BUFFER_SIZE) + colorSize = prop->val; + else if (prop->key == GLX_DOUBLEBUFFER) + doubleBuffer = prop->val; + } + + /* Double-buffer only */ + if (!doubleBuffer) + continue; + + if (m_pf == PF_RGBA8 && colorSize >= 32) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + else if (m_pf == PF_RGBA8_Z24 && colorSize >= 32 && depthSize >= 24) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + else if (m_pf == PF_RGBAF32 && colorSize >= 128) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + else if (m_pf == PF_RGBAF32_Z24 && colorSize >= 128 && depthSize >= 24) + { + m_fbconfig = fbconfId; + m_visualid = visualId; + break; + } + } + free(fbconfigs); + + if (!m_fbconfig) + { + fprintf(stderr, "unable to find suitable pixel format"); + return; + } + + visualIdOut = m_visualid; + } + + ~GraphicsContextXCB() + { + + } + + void _setCallback(IWindowCallback* cb) + { + m_callback = cb; + } + + EGraphicsAPI getAPI() const + { + return m_api; + } + + EPixelFormat getPixelFormat() const + { + return m_pf; + } + + void setPixelFormat(EPixelFormat pf) + { + if (pf > PF_RGBAF32_Z24) + return; + m_pf = pf; + } + + void initializeContext() + { + m_glxWindow = xcb_generate_id(m_xcbConn); + xcb_glx_create_window(m_xcbConn, 0, m_fbconfig, + m_parentWindow->getPlatformHandle(), + m_glxWindow, 0, NULL); + } + +}; struct WindowXCB : IWindow { xcb_connection_t* m_xcbConn; - xcb_window_t m_windowId; - IGraphicsContext* m_gfxCtx; IWindowCallback* m_callback; + xcb_window_t m_windowId; + GraphicsContextXCB m_gfxCtx; + uint32_t m_visualId; /* Last known input device id (0xffff if not yet set) */ xcb_input_device_id_t m_lastInputID = 0xffff; @@ -174,7 +306,7 @@ struct WindowXCB : IWindow public: WindowXCB(const std::string& title, xcb_connection_t* conn) - : m_xcbConn(conn), m_callback(NULL) + : m_xcbConn(conn), m_callback(NULL), m_gfxCtx(IGraphicsContext::API_OPENGL_3_3, this, m_xcbConn, m_visualId) { if (!S_ATOMS) S_ATOMS = new XCBAtoms(conn); @@ -183,14 +315,10 @@ public: xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(m_xcbConn)).data; m_pixelFactor = screen->width_in_pixels / (float)screen->width_in_millimeters / REF_DPMM; - /* Construct graphics context */ - uint32_t visualId; - m_gfxCtx = _GraphicsContextXCBNew(IGraphicsContext::API_OPENGL_3_3, this, m_xcbConn, visualId); - /* Create colormap */ xcb_colormap_t colormap = xcb_generate_id(m_xcbConn); xcb_create_colormap(m_xcbConn, XCB_COLORMAP_ALLOC_NONE, - colormap, screen->root, visualId); + colormap, screen->root, m_visualId); /* Create window */ int x, y, w, h; @@ -208,9 +336,10 @@ public: m_windowId = xcb_generate_id(conn); xcb_create_window(m_xcbConn, XCB_COPY_FROM_PARENT, m_windowId, screen->root, x, y, w, h, 10, - XCB_WINDOW_CLASS_INPUT_OUTPUT, visualId, + XCB_WINDOW_CLASS_INPUT_OUTPUT, m_visualId, XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP, valueMasks); + /* The XInput 2.1 extension enables per-pixel smooth scrolling trackpads */ xcb_generic_error_t* xiErr = NULL; @@ -233,7 +362,7 @@ public: }; xcb_input_xi_select_events(m_xcbConn, m_windowId, 1, &masks.mask); } - free(xiReply); + free(xiReply); /* Register netwm extension atom for window closing */ #if 0 @@ -262,7 +391,7 @@ public: xcb_map_window(m_xcbConn, m_windowId); xcb_flush(m_xcbConn); - m_gfxCtx->initializeContext(); + m_gfxCtx.initializeContext(); } ~WindowXCB() @@ -383,6 +512,12 @@ public: (const char*)&fsEvent); } + void waitForRetrace() + { + unsigned int sync; + FglXWaitVideoSyncSGI(1, 0, &sync); + } + uintptr_t getPlatformHandle() const { return (uintptr_t)m_windowId; diff --git a/test/main.cpp b/test/main.cpp index a8a3d23..edd32c7 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -200,7 +200,6 @@ int main(int argc, const char** argv) std::unique_ptr app = ApplicationBootstrap(boo::IApplication::PLAT_AUTO, appCb, "rwk", "RWK", argc, argv); - app->run(); printf("IM DYING!!\n"); return 0; }