From e2d004986d6b66adc6c391794bd602d125c37838 Mon Sep 17 00:00:00 2001 From: Andrew Mickelson Date: Wed, 10 Jul 2024 21:32:46 -0700 Subject: [PATCH] [drm] Implement sf::Cursor functionality for DRM --- src/SFML/Window/DRM/CursorImpl.cpp | 117 +++++++++++++++++++----- src/SFML/Window/DRM/CursorImpl.hpp | 28 ++---- src/SFML/Window/DRM/DRMContext.cpp | 124 ++++++++++++++++++++++++++ src/SFML/Window/DRM/DRMContext.hpp | 14 +-- src/SFML/Window/DRM/InputImplUDev.cpp | 10 ++- src/SFML/Window/DRM/WindowImplDRM.cpp | 14 +-- 6 files changed, 249 insertions(+), 58 deletions(-) diff --git a/src/SFML/Window/DRM/CursorImpl.cpp b/src/SFML/Window/DRM/CursorImpl.cpp index c57cee455..87f63b611 100644 --- a/src/SFML/Window/DRM/CursorImpl.cpp +++ b/src/SFML/Window/DRM/CursorImpl.cpp @@ -26,15 +26,60 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include #include +#include +#include namespace sf { namespace priv { + const char *defaultCursor16x16 = + "\000\000\000\000\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\377\377\377\377\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\210\203\203\377\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\000\000\000\377\210\203\203\377\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\210" + "\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\210\203\203\377\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\000\000\000\377\210\203\203\377\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\000\000\000\377\000\000\000\377" + "\000\000\000\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\377\377\377\377" + "\377\377\377\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\377\377\377\377\000\000\000\377\210" + "\203\203\377\000\000\000\377\377\377\377\377\377\377\377\377\000\000\000\377\210\203" + "\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\377\377\377\377\377\377\377\377" + "\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\377\377" + "\377\377\377\377\377\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\377\000\000\000\377\000\000\000\377\000\000\000\377\210\203\203\377\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000"; + //////////////////////////////////////////////////////////// CursorImpl::CursorImpl() + : m_bo(NULL) { } @@ -42,47 +87,79 @@ CursorImpl::CursorImpl() //////////////////////////////////////////////////////////// CursorImpl::~CursorImpl() { + release(); } //////////////////////////////////////////////////////////// -bool CursorImpl::loadFromPixels(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/) +bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot) { - return false; -} + release(); + Drm &drm = DRMContext::getDRM(); + uint64_t capWidth(0), capHeight(0); + drmGetCap(drm.fileDescriptor, DRM_CAP_CURSOR_WIDTH, &capWidth); + drmGetCap(drm.fileDescriptor, DRM_CAP_CURSOR_HEIGHT, &capHeight); -//////////////////////////////////////////////////////////// -bool CursorImpl::loadFromPixelsARGB(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/) -{ - return false; -} + std::vector curImg(capWidth * capHeight * 4); + std::size_t pitch = std::min(static_cast(size.x), static_cast(capWidth)) * 4; + unsigned int rows = std::min(size.y, static_cast(capHeight)); + uint64_t srcStride = size.x * 4; + uint64_t dstStride = capWidth * 4; + const Uint8* srcPixels = pixels; + Uint8* dstPixels = &curImg[0]; + for (unsigned int i=0; i(capWidth), + static_cast(capHeight), + GBM_BO_FORMAT_ARGB8888, + GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE ); + + if (!m_bo) + { + sf::err() << "Error creating cursor gbm buffer object: " << strerror(errno) << std::endl; + return false; + } + + if (gbm_bo_write( m_bo, &curImg[0], capWidth * capHeight * 4 )) + { + sf::err() << "Error writing cursor gbm buffer object: " << strerror(errno) << std::endl; + return false; + } + + return true; } //////////////////////////////////////////////////////////// bool CursorImpl::loadFromSystem(Cursor::Type /*type*/) { - return false; -} - - -//////////////////////////////////////////////////////////// -bool CursorImpl::isColorCursorSupported() -{ - return false; + return loadFromPixels(reinterpret_cast(defaultCursor16x16), Vector2u(16,16), Vector2u(0,0)); } //////////////////////////////////////////////////////////// void CursorImpl::release() { + if ( m_bo ) + { + gbm_bo_destroy(m_bo); + m_bo = NULL; + } + m_hotspot = Vector2u(); } } // namespace priv diff --git a/src/SFML/Window/DRM/CursorImpl.hpp b/src/SFML/Window/DRM/CursorImpl.hpp index fa736b9ff..bfe7f24de 100644 --- a/src/SFML/Window/DRM/CursorImpl.hpp +++ b/src/SFML/Window/DRM/CursorImpl.hpp @@ -33,6 +33,7 @@ #include #include // Prevent conflict with macro None from Xlib +#include namespace sf { @@ -80,35 +81,16 @@ public: private: - friend class WindowImplDRM; - - //////////////////////////////////////////////////////////// - /// \brief Checks if colored cursors are supported for this display. - /// - //////////////////////////////////////////////////////////// - bool isColorCursorSupported(); - - //////////////////////////////////////////////////////////// - /// \brief Create a cursor with the provided image (ARGB support) - /// - /// Refer to sf::Cursor::loadFromPixels(). - /// - //////////////////////////////////////////////////////////// - bool loadFromPixelsARGB(const Uint8* pixels, Vector2u size, Vector2u hotspot); - - //////////////////////////////////////////////////////////// - /// \brief Create a cursor with the provided image (monochrome) - /// - /// Refer to sf::Cursor::loadFromPixels(). - /// - //////////////////////////////////////////////////////////// - bool loadFromPixelsMonochrome(const Uint8* pixels, Vector2u size, Vector2u hotspot); + friend class DRMContext; //////////////////////////////////////////////////////////// /// \brief Release the cursor, if we have loaded one. /// //////////////////////////////////////////////////////////// void release(); + + gbm_bo *m_bo; + Vector2u m_hotspot; }; } // namespace priv diff --git a/src/SFML/Window/DRM/DRMContext.cpp b/src/SFML/Window/DRM/DRMContext.cpp index a8edee2b3..25d9406a5 100644 --- a/src/SFML/Window/DRM/DRMContext.cpp +++ b/src/SFML/Window/DRM/DRMContext.cpp @@ -28,6 +28,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include #include @@ -62,6 +63,12 @@ namespace int contextCount = 0; EGLDisplay display = EGL_NO_DISPLAY; int waitingForFlip = 0; + sf::Vector2i mousePos; // current mouse position + sf::Vector2u mouseBounds; + bool mouseVisible = false; + int mouseVAdjust = 0; + sf::priv::CursorImpl *mouseDefaultCursor = NULL; + const sf::priv::CursorImpl *mouseUserCursor = NULL; static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data) @@ -102,6 +109,8 @@ namespace if (!initialized) return; + drmModeSetCursor(drmNode.fileDescriptor, drmNode.crtcId, 0, 0, 0 ); + drmModeSetCrtc(drmNode.fileDescriptor, drmNode.originalCrtc->crtc_id, drmNode.originalCrtc->buffer_id, @@ -118,6 +127,12 @@ namespace eglTerminate(display); display = EGL_NO_DISPLAY; + if ( mouseDefaultCursor ) + { + delete mouseDefaultCursor; + mouseDefaultCursor=NULL; + } + gbm_device_destroy(gbmDevice); gbmDevice = NULL; @@ -130,6 +145,9 @@ namespace std::memset(&drmEventCtx, 0, sizeof(drmEventContext)); waitingForFlip = 0; + mouseVisible = false; + mouseUserCursor = NULL; // user is responsible for destruction of this + mouseVAdjust = 0; initialized = false; } @@ -873,6 +891,112 @@ Drm& DRMContext::getDRM() return drmNode; } +gbm_device *DRMContext::getGbmDevice() +{ + initDrm(); + return gbmDevice; +} + +sf::Vector2i DRMContext::getCursorPos() +{ + sf::Vector2i temp=mousePos; + temp.y -= mouseVAdjust; + return temp; +} + +void DRMContext::setCursorPos( const sf::Vector2i &pos ) +{ + sf::Vector2i temp=pos; + + if (temp.x > static_cast(mouseBounds.x)) + temp.x = static_cast(mouseBounds.x); + else if (temp.x < 0) + temp.x=0; + + temp.y += mouseVAdjust; + + if (temp.y > static_cast(mouseBounds.y) + mouseVAdjust) + temp.y = static_cast(mouseBounds.y) + mouseVAdjust; + else if (temp.y < mouseVAdjust) + temp.y=mouseVAdjust; + + mousePos=temp; + drmModeMoveCursor( drmNode.fileDescriptor, drmNode.crtcId, mousePos.x, mousePos.y ); +} + +void DRMContext::setCursorBounds( const sf::Vector2u &bound ) +{ + sf::Vector2u temp=bound; + mouseVAdjust=0; + if (drmNode.mode) + { + if (temp.x > drmNode.mode->hdisplay) + temp.x = drmNode.mode->hdisplay; + if (temp.y > drmNode.mode->vdisplay) + temp.y = drmNode.mode->vdisplay; + + mouseVAdjust=static_cast(drmNode.mode->vdisplay - temp.y); + } + + mouseBounds=temp; + setCursorPos( getCursorPos() ); +} + +void DRMContext::setCursorVisible( bool vis ) +{ + bool update = ( vis != mouseVisible ); + mouseVisible = vis; + + if (update) + updateCursorDisplay(); +} + +void DRMContext::setUserCursor( const CursorImpl &cur ) +{ + bool update = mouseVisible && ( mouseUserCursor != &cur ); + mouseUserCursor = &cur; + + if (update) + updateCursorDisplay(); +} + +void DRMContext::updateCursorDisplay() +{ + const CursorImpl *p = mouseUserCursor; + if (!p || !p->m_bo) + { + if (!mouseDefaultCursor) + { + mouseDefaultCursor = new CursorImpl(); + if (!mouseDefaultCursor->loadFromSystem(sf::Cursor::Type::Arrow)) + { + sf::err() << "Error loading default cursor." << std::endl; + } + } + p=mouseDefaultCursor; + } + + int ret; + + if (!(p->m_bo) || !mouseVisible) + { + ret = drmModeSetCursor(drmNode.fileDescriptor, drmNode.crtcId, 0, 0, 0 ); + } + else + { + setCursorPos(getCursorPos()); + ret = drmModeSetCursor2(drmNode.fileDescriptor, drmNode.crtcId, gbm_bo_get_handle(p->m_bo).u32, + gbm_bo_get_width(p->m_bo), gbm_bo_get_height(p->m_bo), static_cast(p->m_hotspot.x), + static_cast(p->m_hotspot.y)); + } + + if (ret) + { + sf::err() << "drmModeSetCursor failed to set cursor: " << strerror(errno) << std::endl; + } +} + + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/DRM/DRMContext.hpp b/src/SFML/Window/DRM/DRMContext.hpp index 45211240c..e8ae527f7 100644 --- a/src/SFML/Window/DRM/DRMContext.hpp +++ b/src/SFML/Window/DRM/DRMContext.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct Drm }; class WindowImplDRM; +class CursorImpl; class DRMContext : public GlContext { @@ -178,16 +180,17 @@ public: //////////////////////////////////////////////////////////// static GlFunctionPointer getFunction(const char* name); -protected: - - friend class VideoModeImpl; - friend class WindowImplDRM; - //////////////////////////////////////////////////////////// /// \brief Get Direct Rendering Manager pointer /// //////////////////////////////////////////////////////////// static Drm& getDRM(); + static gbm_device *getGbmDevice(); + static sf::Vector2i getCursorPos(); + static void setCursorPos( const sf::Vector2i &pos ); + static void setCursorBounds( const sf::Vector2u &bounds ); + static void setCursorVisible( bool vis ); + static void setUserCursor( const CursorImpl &cur ); private: @@ -196,6 +199,7 @@ private: /// //////////////////////////////////////////////////////////// void updateSettings(); + static void updateCursorDisplay(); //////////////////////////////////////////////////////////// // Member data diff --git a/src/SFML/Window/DRM/InputImplUDev.cpp b/src/SFML/Window/DRM/InputImplUDev.cpp index 2c78cf979..a39c3c390 100644 --- a/src/SFML/Window/DRM/InputImplUDev.cpp +++ b/src/SFML/Window/DRM/InputImplUDev.cpp @@ -26,6 +26,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -60,7 +61,6 @@ namespace }; sf::Mutex inputMutex; // threadsafe? maybe... - sf::Vector2i mousePos; // current mouse position std::vector fileDescriptors; // list of open file descriptors for /dev/input std::vector mouseMap(sf::Mouse::ButtonCount, false); // track whether keys are down @@ -120,7 +120,6 @@ namespace bool is_mouse = (is_abs || is_rel) && TEST_BIT(BTN_MOUSE, bitmask_key); bool is_touch = is_abs && (TEST_BIT(BTN_TOOL_FINGER, bitmask_key) || TEST_BIT(BTN_TOUCH, bitmask_key)); - return is_keyboard || is_mouse || is_touch; } @@ -359,6 +358,7 @@ namespace } ssize_t bytesRead; + sf::Vector2i mousePos = sf::priv::DRMContext::getCursorPos(); // Check all the open file descriptors for the next event for (std::vector::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr) @@ -448,6 +448,8 @@ namespace if (posChange) { event.type = sf::Event::MouseMoved; + sf::priv::DRMContext::setCursorPos( mousePos ); + mousePos = sf::priv::DRMContext::getCursorPos(); event.mouseMove.x = mousePos.x; event.mouseMove.y = mousePos.y; return true; @@ -627,7 +629,7 @@ bool InputImpl::isMouseButtonPressed(Mouse::Button button) Vector2i InputImpl::getMousePosition() { Lock lock(inputMutex); - return mousePos; + return sf::priv::DRMContext::getCursorPos(); } @@ -642,7 +644,7 @@ Vector2i InputImpl::getMousePosition(const WindowBase& /*relativeTo*/) void InputImpl::setMousePosition(const Vector2i& position) { Lock lock(inputMutex); - mousePos = position; + sf::priv::DRMContext::setCursorPos( position ); } diff --git a/src/SFML/Window/DRM/WindowImplDRM.cpp b/src/SFML/Window/DRM/WindowImplDRM.cpp index cc2ae699b..ae698180a 100644 --- a/src/SFML/Window/DRM/WindowImplDRM.cpp +++ b/src/SFML/Window/DRM/WindowImplDRM.cpp @@ -50,6 +50,7 @@ WindowImplDRM::WindowImplDRM(VideoMode mode, const String& /*title*/, unsigned l m_size(mode.width, mode.height) { sf::priv::InputImpl::setTerminalConfig(); + DRMContext::setCursorBounds(Vector2u(mode.width,mode.height)); } @@ -88,8 +89,10 @@ Vector2u WindowImplDRM::getSize() const //////////////////////////////////////////////////////////// -void WindowImplDRM::setSize(const Vector2u& /*size*/) +void WindowImplDRM::setSize(const Vector2u& size) { + m_size=size; + DRMContext::setCursorBounds(m_size); } @@ -111,21 +114,20 @@ void WindowImplDRM::setVisible(bool /*visible*/) } //////////////////////////////////////////////////////////// -void WindowImplDRM::setMouseCursorVisible(bool /*visible*/) +void WindowImplDRM::setMouseCursorVisible(bool visible) { - // TODO: not implemented + DRMContext::setCursorVisible(visible); } //////////////////////////////////////////////////////////// void WindowImplDRM::setMouseCursorGrabbed(bool /*grabbed*/) { - //TODO: not implemented } //////////////////////////////////////////////////////////// -void WindowImplDRM::setMouseCursor(const CursorImpl& /*cursor*/) +void WindowImplDRM::setMouseCursor(const CursorImpl& cursor) { - // TODO: not implemented + DRMContext::setUserCursor(cursor); } ////////////////////////////////////////////////////////////