mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-10-27 14:29:58 +00:00
Pack NV_UNICODE_PACKET densely for Sunshine
This reduces overhead up to 32x for large text blocks and avoids flooding the ENet connection with packets all at once.
This commit is contained in:
1 parent
4a95eb35b2
commit
04053843c9
1 file changed
+83
-38
+83
-38
@@ -319,6 +319,36 @@ static void floatToNetfloat(float in, netfloat out) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the length in bytes of the UTF-8 code point at the given offset in the text,
|
||||||
|
// or 0 if the byte at that offset does not start a valid UTF-8 code point.
|
||||||
|
static uint32_t getUtf8CodePointLength(const char* utf8Text, uint32_t offset) {
|
||||||
|
uint8_t firstByte = (uint8_t)utf8Text[offset];
|
||||||
|
uint32_t codePointLength;
|
||||||
|
|
||||||
|
if ((firstByte & 0x80) == 0x00) {
|
||||||
|
// 1 byte code point
|
||||||
|
codePointLength = 1;
|
||||||
|
}
|
||||||
|
else if ((firstByte & 0xE0) == 0xC0) {
|
||||||
|
// 2 byte code point
|
||||||
|
codePointLength = 2;
|
||||||
|
}
|
||||||
|
else if ((firstByte & 0xF0) == 0xE0) {
|
||||||
|
// 3 byte code point
|
||||||
|
codePointLength = 3;
|
||||||
|
}
|
||||||
|
else if ((firstByte & 0xF8) == 0xF0) {
|
||||||
|
// 4 byte code point
|
||||||
|
codePointLength = 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Limelog("Invalid unicode code point starting byte: %02x\n", firstByte);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return codePointLength;
|
||||||
|
}
|
||||||
|
|
||||||
// Input thread proc
|
// Input thread proc
|
||||||
static void inputSendThreadProc(void* context) {
|
static void inputSendThreadProc(void* context) {
|
||||||
SOCK_RET err;
|
SOCK_RET err;
|
||||||
@@ -549,56 +579,71 @@ static void inputSendThreadProc(void* context) {
|
|||||||
uint32_t totalLength = PAYLOAD_SIZE(holder) - sizeof(uint32_t);
|
uint32_t totalLength = PAYLOAD_SIZE(holder) - sizeof(uint32_t);
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
// HACK: This is a workaround for the fact that GFE doesn't appear to synchronize keyboard
|
if (!IS_SUNSHINE()) {
|
||||||
// and UTF-8 text events with each other. We need to make sure any previous keyboard events
|
// HACK: This is a workaround for the fact that GFE doesn't appear to synchronize keyboard
|
||||||
// have been processed prior to sending these UTF-8 events to avoid interference between
|
// and UTF-8 text events with each other. We need to make sure any previous keyboard events
|
||||||
// the two (especially with modifier keys).
|
// have been processed prior to sending these UTF-8 events to avoid interference between
|
||||||
flushInputOnControlStream();
|
// the two (especially with modifier keys).
|
||||||
while (!PltIsThreadInterrupted(&inputSendThread) && isControlDataInTransit()) {
|
flushInputOnControlStream();
|
||||||
PltSleepMs(10);
|
while (!PltIsThreadInterrupted(&inputSendThread) && isControlDataInTransit()) {
|
||||||
|
PltSleepMs(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, sleep an additional 50 ms to allow the events to be processed by Windows
|
||||||
|
PltSleepMs(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, sleep an additional 50 ms to allow the events to be processed by Windows
|
|
||||||
PltSleepMs(50);
|
|
||||||
|
|
||||||
// We send each Unicode code point individually. This way we can always ensure they will
|
|
||||||
// never straddle a packet boundary (which will cause a parsing error on the host).
|
|
||||||
while (i < totalLength && !PltIsThreadInterrupted(&inputSendThread)) {
|
while (i < totalLength && !PltIsThreadInterrupted(&inputSendThread)) {
|
||||||
uint32_t codePointLength;
|
uint32_t chunkLength = 0;
|
||||||
uint8_t firstByte = (uint8_t)holder->packet.unicode.text[i];
|
uint32_t remaining = totalLength - i;
|
||||||
if ((firstByte & 0x80) == 0x00) {
|
|
||||||
// 1 byte code point
|
if (IS_SUNSHINE()) {
|
||||||
codePointLength = 1;
|
// Sunshine accepts multiple code points per packet, so we pack as many as
|
||||||
}
|
// fit within the NV_UNICODE_PACKET to send fewer packets overall. Code points
|
||||||
else if ((firstByte & 0xE0) == 0xC0) {
|
// are never split across packet boundaries.
|
||||||
// 2 byte code point
|
while (chunkLength < remaining) {
|
||||||
codePointLength = 2;
|
uint32_t codePointLength = getUtf8CodePointLength(holder->packet.unicode.text, i + chunkLength);
|
||||||
}
|
if (codePointLength == 0) {
|
||||||
else if ((firstByte & 0xF0) == 0xE0) {
|
break;
|
||||||
// 3 byte code point
|
}
|
||||||
codePointLength = 3;
|
if (chunkLength + codePointLength > UTF8_TEXT_EVENT_MAX_COUNT) {
|
||||||
}
|
break;
|
||||||
else if ((firstByte & 0xF8) == 0xF0) {
|
}
|
||||||
// 4 byte code point
|
chunkLength += codePointLength;
|
||||||
codePointLength = 4;
|
}
|
||||||
|
|
||||||
|
// No code point fit, so stop sending
|
||||||
|
if (chunkLength == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Limelog("Invalid unicode code point starting byte: %02x\n", firstByte);
|
// We send each Unicode code point individually. This way we can always ensure they will
|
||||||
break;
|
// never straddle a packet boundary (which will cause a parsing error on the host).
|
||||||
|
uint32_t codePointLength = getUtf8CodePointLength(holder->packet.unicode.text, i);
|
||||||
|
if (codePointLength == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chunkLength = codePointLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the original packet as a template and fixup to send one code point at a time
|
// Clamp the chunk if the final code point is truncated
|
||||||
splitPacket = *holder;
|
if (chunkLength > remaining) {
|
||||||
splitPacket.packet.unicode.header.size = BE32(sizeof(uint32_t) + codePointLength);
|
chunkLength = remaining;
|
||||||
memcpy(splitPacket.packet.unicode.text, &holder->packet.unicode.text[i], codePointLength);
|
}
|
||||||
|
|
||||||
// Encrypt and send the split packet
|
// Use the original packet as a template and fixup to send the chunk
|
||||||
if (!sendInputPacket(&splitPacket, i + 1 < totalLength)) {
|
splitPacket = *holder;
|
||||||
|
splitPacket.packet.unicode.header.size = BE32(sizeof(uint32_t) + chunkLength);
|
||||||
|
memcpy(splitPacket.packet.unicode.text, &holder->packet.unicode.text[i], chunkLength);
|
||||||
|
|
||||||
|
// Encrypt and send the chunk
|
||||||
|
if (!sendInputPacket(&splitPacket, i + chunkLength < totalLength)) {
|
||||||
freePacketHolder(holder);
|
freePacketHolder(holder);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
i += codePointLength;
|
i += chunkLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
freePacketHolder(holder);
|
freePacketHolder(holder);
|
||||||
|
|||||||
Reference in new issue
Block a user