Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/neutrinolabs/ulalaca-xrdp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGyuhwan Park★ <unstabler@unstabler.pl>2023-01-28 23:10:08 +0300
committerGyuhwan Park★ <unstabler@unstabler.pl>2023-01-28 23:10:08 +0300
commit47d6b37bbfc7f05d8d5a07c4f065b9c0f64817fc (patch)
tree8ee6789c71bb1e00fc4f8e67f74c618911acd7f6
parent676c9b085f9422f874c3dd5be24b6b2013fbf3c5 (diff)
refactor: move render-related code into thread loop
-rw-r--r--ProjectionTarget.hpp1
-rw-r--r--ProjectorClient.cpp1
-rw-r--r--XrdpUlalacaPrivate.cpp206
-rw-r--r--XrdpUlalacaPrivate.hpp32
-rw-r--r--XrdpUlalacaPrivate.xrdpmodule.cpp8
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;