diff options
author | Gyuhwan Park★ <unstabler@unstabler.pl> | 2023-01-28 23:10:08 +0300 |
---|---|---|
committer | Gyuhwan Park★ <unstabler@unstabler.pl> | 2023-01-28 23:10:08 +0300 |
commit | 47d6b37bbfc7f05d8d5a07c4f065b9c0f64817fc (patch) | |
tree | 8ee6789c71bb1e00fc4f8e67f74c618911acd7f6 | |
parent | 676c9b085f9422f874c3dd5be24b6b2013fbf3c5 (diff) |
refactor: move render-related code into thread loop
-rw-r--r-- | ProjectionTarget.hpp | 1 | ||||
-rw-r--r-- | ProjectorClient.cpp | 1 | ||||
-rw-r--r-- | XrdpUlalacaPrivate.cpp | 206 | ||||
-rw-r--r-- | XrdpUlalacaPrivate.hpp | 32 | ||||
-rw-r--r-- | XrdpUlalacaPrivate.xrdpmodule.cpp | 8 |
5 files changed, 155 insertions, 93 deletions
diff --git a/ProjectionTarget.hpp b/ProjectionTarget.hpp index 89c6da2..ef2d3ef 100644 --- a/ProjectionTarget.hpp +++ b/ProjectionTarget.hpp @@ -16,6 +16,7 @@ public: virtual void commitUpdate( const uint8_t *image, + size_t size, int32_t width, int32_t height ) = 0; }; diff --git a/ProjectorClient.cpp b/ProjectorClient.cpp index b8f72c4..adf31d8 100644 --- a/ProjectorClient.cpp +++ b/ProjectorClient.cpp @@ -190,6 +190,7 @@ void ProjectorClient::mainLoop() { LOG(LOG_LEVEL_DEBUG, "mainLoop(): commiting update"); _target.commitUpdate( bitmap.get(), + commit->bitmapLength, commit->screenRect.width, commit->screenRect.height ); diff --git a/XrdpUlalacaPrivate.cpp b/XrdpUlalacaPrivate.cpp index 80e29de..cd3c54b 100644 --- a/XrdpUlalacaPrivate.cpp +++ b/XrdpUlalacaPrivate.cpp @@ -7,37 +7,43 @@ #include "ProjectorClient.hpp" XrdpUlalacaPrivate::XrdpUlalacaPrivate(XrdpUlalaca *mod): - _mod(mod), - _error(0), + _mod(mod), + _error(0), - _sessionSize(), - _screenLayouts(), + _sessionSize(), + _screenLayouts(), - _bpp(0), + _bpp(0), - _frameId(0), - _ackFrameId(0), + _frameId(0), + _ackFrameId(0), - _username(), - _password(), - _ip(), - _port(), + _username(), + _password(), + _ip(), + _port(), - _keyLayout(0), - _delayMs(0), - _guid(), - _encodingsMask(0), - _clientInfo(), + _keyLayout(0), + _delayMs(0), + _guid(), + _encodingsMask(0), + _clientInfo(), - _socket(), - _projectionThread(), + _socket(), + _projectorClient(), - _fullInvalidate(false), - _commitUpdateLock(), + _fullInvalidate(false), + _commitUpdateLock(), - _dirtyRects() + _dirtyRects(std::make_shared<std::vector<ULIPCRect>>()) { +} +XrdpUlalacaPrivate::~XrdpUlalacaPrivate() { + _isUpdateThreadRunning = false; + if (_updateThread->joinable()) { + _updateThread->join(); + } } void XrdpUlalacaPrivate::serverMessage(const char *message, int code) { @@ -46,21 +52,25 @@ void XrdpUlalacaPrivate::serverMessage(const char *message, int code) { } void XrdpUlalacaPrivate::attachToSession(std::string sessionPath) { - if (_projectionThread != nullptr) { + if (_projectorClient != nullptr) { LOG(LOG_LEVEL_ERROR, "already attached to session"); // TODO: throw runtime_error return; } - _projectionThread = std::make_unique<ProjectorClient>( + _projectorClient = std::make_unique<ProjectorClient>( *this, sessionPath ); - _projectionThread->start(); + _projectorClient->start(); + _isUpdateThreadRunning = true; + _updateThread = std::make_unique<std::thread>( + &XrdpUlalacaPrivate::updateThreadLoop, this + ); LOG(LOG_LEVEL_TRACE, "sessionSize: %d, %d", _sessionSize.width, _sessionSize.height); - _projectionThread->setViewport(_sessionSize); - _projectionThread->setOutputSuppression(false); + _projectorClient->setViewport(_sessionSize); + _projectorClient->setOutputSuppression(false); } int XrdpUlalacaPrivate::decideCopyRectSize() const { @@ -81,7 +91,7 @@ std::unique_ptr<std::vector<ULIPCRect>> XrdpUlalacaPrivate::createCopyRects( int rectSize ) const { auto blocks = std::make_unique<std::vector<ULIPCRect>>(); - blocks->reserve(128); + blocks->reserve((_sessionSize.width * _sessionSize.height) / (rectSize * rectSize)); if (rectSize == RECT_SIZE_BYPASS_CREATE) { std::copy(dirtyRects.begin(), dirtyRects.end(), std::back_insert_iterator(*blocks)); @@ -108,7 +118,7 @@ std::unique_ptr<std::vector<ULIPCRect>> XrdpUlalacaPrivate::createCopyRects( short x = baseX + (rectSize * i); short y = baseY + (rectSize * j); - blocks->push_back(ULIPCRect {x, y, (short) rectSize, (short) rectSize }); + blocks->emplace_back(ULIPCRect {x, y, (short) rectSize, (short) rectSize }); } } } @@ -117,74 +127,110 @@ std::unique_ptr<std::vector<ULIPCRect>> XrdpUlalacaPrivate::createCopyRects( } void XrdpUlalacaPrivate::addDirtyRect(ULIPCRect &rect) { - std::scoped_lock<std::mutex> scopedCommitLock(_commitUpdateLock); - _dirtyRects.push_back(rect); + _dirtyRects->push_back(rect); } -void XrdpUlalacaPrivate::commitUpdate(const uint8_t *image, int32_t width, int32_t height) { - LOG(LOG_LEVEL_DEBUG, "updating screen: %d, %d", width, height); +void XrdpUlalacaPrivate::commitUpdate(const uint8_t *image, size_t size, int32_t width, int32_t height) { + std::shared_ptr<uint8_t> tmp((uint8_t *) g_malloc(size, 0), g_free); + memmove(tmp.get(), image, size); - if (!_commitUpdateLock.try_lock()) { - _dirtyRects.clear(); - return; - } + auto dirtyRects = _dirtyRects; + _dirtyRects = std::make_shared<std::vector<ULIPCRect>>(); - if (_sessionSize.width != width || _sessionSize.height != height) { - // server_reset(this, width, height, _bpp); - } + auto now = std::chrono::steady_clock::now(); + _updateQueue.emplace(ScreenUpdate { + std::chrono::duration<double>(now.time_since_epoch()).count(), + tmp, size, width, height, dirtyRects + }); +} - if (_frameId > 0 && _dirtyRects.empty()) { - return; - } +void XrdpUlalacaPrivate::updateThreadLoop() { + while (_isUpdateThreadRunning) { + while (_updateQueue.empty()) { + using namespace std::chrono_literals; + std::this_thread::sleep_for(4ms); + } + + if (!_isUpdateThreadRunning) { + break; + } + + _commitUpdateLock.lock(); + auto update = std::move(_updateQueue.front()); + _updateQueue.pop(); + _commitUpdateLock.unlock(); + + + auto now = std::chrono::steady_clock::now(); + auto tdelta = std::chrono::duration<double>(now.time_since_epoch()).count() - update.timestamp; + + if (tdelta > 1.0 / 15.0 || _updateQueue.size() > 4) { + LOG(LOG_LEVEL_INFO, "skipping frame (tdelta = %.4f)", tdelta); + continue; + } + + auto width = update.width; + auto height = update.height; + auto dirtyRects = update.dirtyRects; + auto image = update.image; + + // LOG(LOG_LEVEL_TRACE, "updating screen: [%.4f] %d, %d", update.timestamp, update.width, update.height); + + if (_sessionSize.width != update.width || _sessionSize.height != update.height) { + // server_reset(this, width, height, _bpp); + } + + if (_frameId > 0 && dirtyRects->empty()) { + continue; + } + + _mod->server_begin_update(_mod); + + ULIPCRect screenRect {0, 0, (short) width, (short) height}; + auto copyRectSize = decideCopyRectSize(); + + if (_frameId > 0 || !_fullInvalidate) { + auto copyRects = createCopyRects(*dirtyRects, copyRectSize); - _mod->server_begin_update(_mod); - - ULIPCRect screenRect {0, 0, (short) width, (short) height}; - auto copyRectSize = decideCopyRectSize(); - - if (_frameId > 0 || !_fullInvalidate) { - auto copyRects = createCopyRects(_dirtyRects, copyRectSize); - - _mod->server_paint_rects( - _mod, - _dirtyRects.size(), reinterpret_cast<short *>(_dirtyRects.data()), - copyRects->size(), reinterpret_cast<short *>(copyRects->data()), - (char *) image, - width, height, - 0, (_frameId++ % INT32_MAX) - ); - } else { - // paint entire screen - auto dirtyRects = std::vector<ULIPCRect> { screenRect } ; - auto copyRects = createCopyRects(dirtyRects, copyRectSize); - - if (isRawBitmap()) { - _mod->server_paint_rect( - _mod, - screenRect.x, screenRect.y, - screenRect.width, screenRect.height, - (char *) image, - screenRect.width, screenRect.height, - 0, 0 - ); - } else { _mod->server_paint_rects( _mod, - dirtyRects.size(), reinterpret_cast<short *>(dirtyRects.data()), + dirtyRects->size(), reinterpret_cast<short *>(dirtyRects->data()), copyRects->size(), reinterpret_cast<short *>(copyRects->data()), - (char *) image, + (char *) image.get(), width, height, 0, (_frameId++ % INT32_MAX) ); + } else { + // paint entire screen + auto dirtyRects = std::vector<ULIPCRect> { screenRect } ; + auto copyRects = createCopyRects(dirtyRects, copyRectSize); + + if (isRawBitmap()) { + _mod->server_paint_rect( + _mod, + screenRect.x, screenRect.y, + screenRect.width, screenRect.height, + (char *) image.get(), + screenRect.width, screenRect.height, + 0, (_frameId++ % INT32_MAX) + ); + } else { + _mod->server_paint_rects( + _mod, + dirtyRects.size(), reinterpret_cast<short *>(dirtyRects.data()), + copyRects->size(), reinterpret_cast<short *>(copyRects->data()), + (char *) image.get(), + width, height, + 0, (_frameId++ % INT32_MAX) + ); + } + + _fullInvalidate = false; } - _fullInvalidate = false; + _mod->server_end_update(_mod); } - _dirtyRects.clear(); - _mod->server_end_update(_mod); - - _commitUpdateLock.unlock(); } void XrdpUlalacaPrivate::calculateSessionSize() { diff --git a/XrdpUlalacaPrivate.hpp b/XrdpUlalacaPrivate.hpp index 22c61a7..98f9866 100644 --- a/XrdpUlalacaPrivate.hpp +++ b/XrdpUlalacaPrivate.hpp @@ -14,6 +14,7 @@ extern "C" { #include "xrdp_client_info.h" }; +#include <queue> #include <mutex> #include "XrdpEvent.hpp" @@ -27,6 +28,17 @@ extern "C" { struct XrdpUlalaca; class ProjectorClient; +struct ScreenUpdate { + double timestamp; + + std::shared_ptr<uint8_t> image; + size_t size; + int32_t width; + int32_t height; + + std::shared_ptr<std::vector<ULIPCRect>> dirtyRects; +}; + class XrdpUlalacaPrivate: public ProjectionTarget { public: constexpr static const int RECT_SIZE_BYPASS_CREATE = 0; @@ -35,6 +47,7 @@ public: explicit XrdpUlalacaPrivate(XrdpUlalaca *mod); XrdpUlalacaPrivate(XrdpUlalacaPrivate &) = delete; + ~XrdpUlalacaPrivate(); /* lib_mod_* */ int libModStart(int width, int height, int bpp); @@ -57,12 +70,6 @@ public: /* utility methods / lib_server_* wrappers */ void serverMessage(const char *message, int code); - /* session-broker related */ - inline std::string getSessionSocketPathUsingCredential( - const std::string &username, - const std::string &password - ); - /** * attach to projector session */ @@ -73,7 +80,9 @@ public: inline std::unique_ptr<std::vector<ULIPCRect>> createCopyRects(std::vector<ULIPCRect> &dirtyRects, int rectSize) const; void addDirtyRect(ULIPCRect &rect); - void commitUpdate(const uint8_t *image, int32_t width, int32_t height); + void commitUpdate(const uint8_t *image, size_t size, int32_t width, int32_t height); + + void updateThreadLoop(); void calculateSessionSize(); @@ -86,6 +95,7 @@ public: private: XrdpUlalaca *_mod; int _error = 0; + bool _isUpdateThreadRunning; ULIPCRect _sessionSize; std::vector<ULIPCRect> _screenLayouts; @@ -106,12 +116,16 @@ private: xrdp_client_info _clientInfo; std::unique_ptr<UnixSocket> _socket; - std::unique_ptr<ProjectorClient> _projectionThread; + std::unique_ptr<ProjectorClient> _projectorClient; + std::unique_ptr<std::thread> _updateThread; std::atomic_bool _fullInvalidate; std::mutex _commitUpdateLock; - std::vector<ULIPCRect> _dirtyRects; + std::shared_ptr<std::vector<ULIPCRect>> _dirtyRects; + + std::queue<ScreenUpdate> _updateQueue; + }; #endif
\ No newline at end of file diff --git a/XrdpUlalacaPrivate.xrdpmodule.cpp b/XrdpUlalacaPrivate.xrdpmodule.cpp index aa9117c..556142a 100644 --- a/XrdpUlalacaPrivate.xrdpmodule.cpp +++ b/XrdpUlalacaPrivate.xrdpmodule.cpp @@ -57,8 +57,8 @@ int XrdpUlalacaPrivate::libModEvent(int type, long arg1, long arg2, long arg3, l arg1, arg2, arg3, arg4 }; - if (_projectionThread != nullptr) { - _projectionThread->handleEvent(event); + if (_projectorClient != nullptr) { + _projectorClient->handleEvent(event); } return 0; @@ -72,8 +72,8 @@ int XrdpUlalacaPrivate::libModSignal() { int XrdpUlalacaPrivate::libModEnd() { LOG(LOG_LEVEL_INFO, "lib_mod_end() called"); - if (_projectionThread != nullptr) { - _projectionThread->stop(); + if (_projectorClient != nullptr) { + _projectorClient->stop(); } return 0; |