Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve compatibility with mstsc.exe #5

Merged
merged 4 commits into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 80 additions & 16 deletions XrdpUlalacaPrivate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Created by Gyuhwan Park on 2023/01/28.
//

#include <cmath>

#include "XrdpUlalacaPrivate.hpp"

#include "ProjectorClient.hpp"
Expand Down Expand Up @@ -32,7 +34,7 @@ XrdpUlalacaPrivate::XrdpUlalacaPrivate(XrdpUlalaca *mod):
_socket(),
_projectorClient(),

_fullInvalidate(false),
_fullInvalidate(true),
_commitUpdateLock(),

_dirtyRects(std::make_shared<std::vector<ULIPCRect>>())
Expand Down Expand Up @@ -98,35 +100,97 @@ std::unique_ptr<std::vector<ULIPCRect>> XrdpUlalacaPrivate::createCopyRects(
return std::move(blocks);
}

int mapWidth = ceil((float) _sessionSize.width / (float) rectSize);
int mapHeight = ceil((float) _sessionSize.height / (float) rectSize);
int mapSize = mapWidth * mapHeight;
std::unique_ptr<uint8_t> rectMap(new uint8_t[mapSize]);
memset(rectMap.get(), 0x00, mapSize);

for (auto &dirtyRect : dirtyRects) {
if (_sessionSize.width <= dirtyRect.x ||
_sessionSize.height <= dirtyRect.y) {
continue;
}

auto width = std::min(dirtyRect.width, (short) (_sessionSize.width - dirtyRect.x));
auto height = std::min(dirtyRect.height, (short) (_sessionSize.height - dirtyRect.y));

auto baseX = dirtyRect.x - (dirtyRect.x % rectSize);
auto baseY = dirtyRect.y - (dirtyRect.y % rectSize);

auto blockCountX = ((width + dirtyRect.x % rectSize) + (rectSize - 1)) / rectSize;
auto blockCountY = ((height + dirtyRect.y % rectSize) + (rectSize - 1)) / rectSize;
int mapX1 = dirtyRect.x / rectSize;
int mapY1 = dirtyRect.y / rectSize;
int mapX2 = std::min(
(dirtyRect.x + dirtyRect.width) / rectSize,
mapWidth - 1
);
int mapY2 = std::min(
(dirtyRect.y + dirtyRect.height) / rectSize,
mapHeight - 1
);

for (int y = mapY1; y <= mapY2; y++) {
for (int x = mapX1; x <= mapX2; x++) {
rectMap.get()[(y * mapWidth) + x] = 0x01;
}
}
}

for (int j = 0; j < blockCountY; j++) {
for (int i = 0; i < blockCountX; i++) {
short x = baseX + (rectSize * i);
short y = baseY + (rectSize * j);
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
if (rectMap.get()[(y * mapWidth) + x] == 0x01) {
int rectX = x * rectSize;
int rectY = y * rectSize;

blocks->emplace_back(ULIPCRect {x, y, (short) rectSize, (short) rectSize });
blocks->emplace_back(ULIPCRect{(short) rectX, (short) rectY, (short) rectSize, (short) rectSize});
}
}
}

return std::move(blocks);
}

bool XrdpUlalacaPrivate::isRectOverlaps(const ULIPCRect &a, const ULIPCRect &b) {
int16_t a_x1 = a.x;
int16_t a_x2 = a.x + a.width;
int16_t a_y1 = a.y;
int16_t a_y2 = a.y + a.height;
int16_t b_x1 = b.x;
int16_t b_x2 = b.x + b.width;
int16_t b_y1 = b.y;
int16_t b_y2 = b.y + b.height;

return (
(a_x1 >= b_x1 && a_x1 <= b_x2 && a_y1 >= b_y1 && a_y1 <= b_y2) ||
(a_x2 >= b_x1 && a_x2 <= b_x2 && a_y1 >= b_y1 && a_y1 <= b_y2) ||
(a_x1 >= b_x1 && a_x1 <= b_x2 && a_y2 >= b_y1 && a_y2 <= b_y2) ||
(a_x2 >= b_x1 && a_x2 <= b_x2 && a_y2 >= b_y1 && a_y2 <= b_y2)
);
}

void XrdpUlalacaPrivate::mergeRect(ULIPCRect &a, const ULIPCRect &b) {
int16_t a_x1 = a.x;
int16_t a_x2 = a.x + a.width;
int16_t a_y1 = a.y;
int16_t a_y2 = a.y + a.height;
int16_t b_x1 = b.x;
int16_t b_x2 = b.x + b.width;
int16_t b_y1 = b.y;
int16_t b_y2 = b.y + b.height;

a.x = std::min(a_x1, b_x1);
a.y = std::min(a_y1, b_y1);
a.width = std::max(a_x2, b_x2) - a.x;
a.height = std::max(a_y2, b_y2) - a.y;
}

std::vector<ULIPCRect> XrdpUlalacaPrivate::removeRectOverlap(const ULIPCRect &a, const ULIPCRect &b) {

}

void XrdpUlalacaPrivate::addDirtyRect(ULIPCRect &rect) {
for (auto &x: *_dirtyRects) {
if (isRectOverlaps(x, rect)) {
mergeRect(x, rect);
return;
}
}


_dirtyRects->push_back(rect);
}

Expand Down Expand Up @@ -195,7 +259,7 @@ void XrdpUlalacaPrivate::updateThreadLoop() {
ULIPCRect screenRect {0, 0, (short) width, (short) height};
auto copyRectSize = decideCopyRectSize();

if ((_frameId > 0 && !_fullInvalidate) || isNSCodec()) {
if (!_fullInvalidate) {
auto copyRects = createCopyRects(*dirtyRects, copyRectSize);

_mod->server_paint_rects(
Expand All @@ -218,7 +282,7 @@ void XrdpUlalacaPrivate::updateThreadLoop() {
screenRect.width, screenRect.height,
(char *) image.get(),
screenRect.width, screenRect.height,
0, (_frameId++ % INT32_MAX)
0, 0
);
} else {
_mod->server_paint_rects(
Expand Down
4 changes: 4 additions & 0 deletions XrdpUlalacaPrivate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class XrdpUlalacaPrivate: public ProjectionTarget {

constexpr static const int NO_ERROR = 0;

static bool isRectOverlaps(const ULIPCRect &a, const ULIPCRect &b);
static void mergeRect(ULIPCRect &a, const ULIPCRect &b);
static std::vector<ULIPCRect> removeRectOverlap(const ULIPCRect &a, const ULIPCRect &b);

explicit XrdpUlalacaPrivate(XrdpUlalaca *mod);
XrdpUlalacaPrivate(XrdpUlalacaPrivate &) = delete;
~XrdpUlalacaPrivate();
Expand Down