mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-02 05:12:02 +00:00
[client] transport: introduce pluggable frame transports
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Move shared-memory ownership, LGMP session handling, queue access, and DMA setup behind a transport interface. The LGMP backend preserves the existing zero-copy frame and DMA paths while owning its lgmp:* options. Expose the initialized EGL context through a versioned renderer interop record for future accelerated decode backends. Add an LGMP-independent, deterministic test transport for graphics-pipeline validation.
This commit is contained in:
@@ -1174,27 +1174,27 @@ void app_invalidateOverlay(bool renderTwice)
|
||||
|
||||
bool app_guestIsLinux(void)
|
||||
{
|
||||
return g_state.guestOS == KVMFR_OS_LINUX;
|
||||
return g_state.guestOS == LG_TRANSPORT_OS_LINUX;
|
||||
}
|
||||
|
||||
bool app_guestIsWindows(void)
|
||||
{
|
||||
return g_state.guestOS == KVMFR_OS_WINDOWS;
|
||||
return g_state.guestOS == LG_TRANSPORT_OS_WINDOWS;
|
||||
}
|
||||
|
||||
bool app_guestIsOSX(void)
|
||||
{
|
||||
return g_state.guestOS == KVMFR_OS_OSX;
|
||||
return g_state.guestOS == LG_TRANSPORT_OS_OSX;
|
||||
}
|
||||
|
||||
bool app_guestIsBSD(void)
|
||||
{
|
||||
return g_state.guestOS == KVMFR_OS_BSD;
|
||||
return g_state.guestOS == LG_TRANSPORT_OS_BSD;
|
||||
}
|
||||
|
||||
bool app_guestIsOther(void)
|
||||
{
|
||||
return g_state.guestOS == KVMFR_OS_OTHER;
|
||||
return g_state.guestOS == LG_TRANSPORT_OS_OTHER;
|
||||
}
|
||||
|
||||
void app_stopVideo(bool stop)
|
||||
|
||||
@@ -47,6 +47,7 @@ static StringList optScancodeValues (struct Option * opt);
|
||||
static bool optScancodeValidate (struct Option * opt, const char ** error);
|
||||
static char * optScancodeToString (struct Option * opt);
|
||||
static bool optRotateValidate (struct Option * opt, const char ** error);
|
||||
static bool optTransportValidate (struct Option * opt, const char ** error);
|
||||
static bool optMicDefaultParse (struct Option * opt, const char * str);
|
||||
static StringList optMicDefaultValues (struct Option * opt);
|
||||
static char * optMicDefaultToString(struct Option * opt);
|
||||
@@ -87,25 +88,12 @@ static struct Option options[] =
|
||||
.value.x_bool = false,
|
||||
},
|
||||
{
|
||||
.module = "app",
|
||||
.name = "cursorPollInterval",
|
||||
.description = "How often to check for a cursor update in microseconds",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 1000
|
||||
},
|
||||
{
|
||||
.module = "app",
|
||||
.name = "framePollInterval",
|
||||
.description = "How often to check for a frame update in microseconds",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = 1000
|
||||
},
|
||||
{
|
||||
.module = "app",
|
||||
.name = "allowDMA",
|
||||
.description = "Allow direct DMA transfers if supported (see `README.md` in the `module` dir)",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = true
|
||||
.module = "app",
|
||||
.name = "transport",
|
||||
.description = "Transport backend to use",
|
||||
.type = OPTION_TYPE_STRING,
|
||||
.value.x_string = "lgmp",
|
||||
.validator = optTransportValidate,
|
||||
},
|
||||
|
||||
// window options
|
||||
@@ -686,9 +674,7 @@ bool config_load(int argc, char * argv[])
|
||||
}
|
||||
|
||||
// setup the application params for the basic types
|
||||
g_params.cursorPollInterval = option_get_int ("app" , "cursorPollInterval");
|
||||
g_params.framePollInterval = option_get_int ("app" , "framePollInterval" );
|
||||
g_params.allowDMA = option_get_bool ("app" , "allowDMA" );
|
||||
g_params.transport = option_get_string("app", "transport" );
|
||||
|
||||
g_params.windowTitle = option_get_string("win", "title" );
|
||||
g_params.appId = option_get_string("win", "appId" );
|
||||
@@ -1025,6 +1011,15 @@ static bool optRotateValidate(struct Option * opt, const char ** error)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool optTransportValidate(struct Option * opt, const char ** error)
|
||||
{
|
||||
if (lgTransport_isValid(opt->value.x_string))
|
||||
return true;
|
||||
|
||||
*error = "Unknown transport (expected lgmp or test)";
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool optMicDefaultParse(struct Option * opt, const char * str)
|
||||
{
|
||||
if (!str)
|
||||
|
||||
@@ -192,29 +192,30 @@ bool core_warpPointer(int x, int y, bool exiting)
|
||||
|
||||
void core_onWindowSizeChanged(unsigned width, unsigned height)
|
||||
{
|
||||
if (!g_state.pointerQueue)
|
||||
if (!g_state.transport ||
|
||||
!(g_state.transportFeatures & LG_TRANSPORT_FEATURE_WINDOW_SIZE))
|
||||
return;
|
||||
|
||||
if (g_state.srcSize.x == width && g_state.srcSize.y == height)
|
||||
return;
|
||||
|
||||
const KVMFRWindowSize msg =
|
||||
const LG_TransportControl control =
|
||||
{
|
||||
.msg.type = KVMFR_MESSAGE_WINDOWSIZE,
|
||||
.w = width,
|
||||
.h = height
|
||||
.type = LG_TRANSPORT_CONTROL_WINDOW_SIZE,
|
||||
.windowSize = { .width = width, .height = height },
|
||||
};
|
||||
|
||||
uint32_t serial;
|
||||
LGMP_STATUS status;
|
||||
if ((status = lgmpClientSendData(g_state.pointerQueue,
|
||||
&msg, sizeof(msg), &serial)) != LGMP_OK)
|
||||
DEBUG_WARN("Message send failed: %s", lgmpStatusString(status));
|
||||
LG_TransportControlToken token;
|
||||
const LG_TransportStatus status = g_state.transportOps->sendControl(
|
||||
g_state.transport, &control, &token);
|
||||
if (status != LG_TRANSPORT_OK && status != LG_TRANSPORT_UNAVAILABLE)
|
||||
DEBUG_WARN("Window-size control failed with status %d", status);
|
||||
}
|
||||
|
||||
void core_updatePositionInfo(void)
|
||||
{
|
||||
if (g_params.setGuestRes && g_state.kvmfrFeatures & KVMFR_FEATURE_WINDOWSIZE)
|
||||
if (g_params.setGuestRes &&
|
||||
g_state.transportFeatures & LG_TRANSPORT_FEATURE_WINDOW_SIZE)
|
||||
{
|
||||
LGMsg msg =
|
||||
{
|
||||
@@ -535,20 +536,19 @@ void core_handleMouseNormal(double ex, double ey)
|
||||
util_localCurToGuest(&guest);
|
||||
|
||||
if (!g_state.stopVideo &&
|
||||
g_state.kvmfrFeatures & KVMFR_FEATURE_SETCURSORPOS)
|
||||
g_state.transportFeatures & LG_TRANSPORT_FEATURE_SET_CURSOR_POS)
|
||||
{
|
||||
const KVMFRSetCursorPos msg = {
|
||||
.msg.type = KVMFR_MESSAGE_SETCURSORPOS,
|
||||
.x = round(guest.x),
|
||||
.y = round(guest.y)
|
||||
const LG_TransportControl control = {
|
||||
.type = LG_TRANSPORT_CONTROL_SET_CURSOR_POS,
|
||||
.cursorPos = { .x = round(guest.x), .y = round(guest.y) },
|
||||
};
|
||||
|
||||
uint32_t setPosSerial;
|
||||
LGMP_STATUS status;
|
||||
if ((status = lgmpClientSendData(g_state.pointerQueue,
|
||||
&msg, sizeof(msg), &setPosSerial)) != LGMP_OK)
|
||||
LG_TransportControlToken token;
|
||||
LG_TransportStatus status = g_state.transportOps->sendControl(
|
||||
g_state.transport, &control, &token);
|
||||
if (status != LG_TRANSPORT_OK)
|
||||
{
|
||||
DEBUG_WARN("Message send failed: %s", lgmpStatusString(status));
|
||||
DEBUG_WARN("Cursor-position control failed with status %d", status);
|
||||
goto fallback;
|
||||
}
|
||||
else
|
||||
@@ -558,32 +558,24 @@ void core_handleMouseNormal(double ex, double ey)
|
||||
unsigned timeout = 200;
|
||||
do
|
||||
{
|
||||
LG_LOCK(g_state.pointerQueueLock);
|
||||
if (!g_state.pointerQueue)
|
||||
status = g_state.transportOps->controlStatus(g_state.transport,
|
||||
token);
|
||||
if (status == LG_TRANSPORT_DISCONNECTED)
|
||||
{
|
||||
/* the queue is nolonger valid, assume complete */
|
||||
g_cursor.realigning = false;
|
||||
LG_UNLOCK(g_state.pointerQueueLock);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t hostSerial;
|
||||
if (lgmpClientGetSerial(g_state.pointerQueue, &hostSerial) != LGMP_OK)
|
||||
if (status == LG_TRANSPORT_OK)
|
||||
break;
|
||||
if (status != LG_TRANSPORT_UNAVAILABLE)
|
||||
{
|
||||
g_cursor.realigning = false;
|
||||
LG_UNLOCK(g_state.pointerQueueLock);
|
||||
return;
|
||||
}
|
||||
LG_UNLOCK(g_state.pointerQueueLock);
|
||||
|
||||
if (hostSerial >= setPosSerial)
|
||||
break;
|
||||
|
||||
if (--timeout == 0)
|
||||
{
|
||||
DEBUG_ERROR(
|
||||
"pointerQueue serial not updating, expected %u but stuck at %u",
|
||||
setPosSerial, hostSerial);
|
||||
DEBUG_ERROR("Cursor-position control was not acknowledged");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -591,8 +583,8 @@ void core_handleMouseNormal(double ex, double ey)
|
||||
}
|
||||
while(app_isRunning());
|
||||
|
||||
g_cursor.guest.x = msg.x;
|
||||
g_cursor.guest.y = msg.y;
|
||||
g_cursor.guest.x = control.cursorPos.x;
|
||||
g_cursor.guest.y = control.cursorPos.y;
|
||||
g_cursor.realign = false;
|
||||
g_cursor.realigning = false;
|
||||
g_cursor.redraw = true;
|
||||
|
||||
@@ -128,7 +128,7 @@ static void bind_toggleKey(int sc, void * opaque)
|
||||
|
||||
static void bind_setGuestRes(int sc, void * opaque)
|
||||
{
|
||||
if (!(g_state.kvmfrFeatures & KVMFR_FEATURE_WINDOWSIZE))
|
||||
if (!(g_state.transportFeatures & LG_TRANSPORT_FEATURE_WINDOW_SIZE))
|
||||
{
|
||||
app_alert(LG_ALERT_INFO, "The guest doesn't support this feature");
|
||||
return;
|
||||
|
||||
1001
client/src/main.c
1001
client/src/main.c
File diff suppressed because it is too large
Load Diff
@@ -28,16 +28,14 @@
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "common/types.h"
|
||||
#include "common/ivshmem.h"
|
||||
#include "common/locking.h"
|
||||
#include "common/ringbuffer.h"
|
||||
#include "common/event.h"
|
||||
#include "common/ll.h"
|
||||
|
||||
#include <purespice.h>
|
||||
#include <lgmp/client.h>
|
||||
|
||||
#include "cimgui.h"
|
||||
#include "interface/transport.h"
|
||||
|
||||
enum RunState
|
||||
{
|
||||
@@ -91,7 +89,7 @@ struct AppState
|
||||
|
||||
uint8_t guestUUID[16];
|
||||
bool guestUUIDValid;
|
||||
KVMFROS guestOS;
|
||||
LG_TransportGuestOS guestOS;
|
||||
|
||||
atomic_bool lgHostConnected;
|
||||
|
||||
@@ -133,11 +131,9 @@ struct AppState
|
||||
size_t cbXfer;
|
||||
struct ll * cbRequestList;
|
||||
|
||||
struct IVSHMEM shm;
|
||||
PLGMPClient lgmp;
|
||||
PLGMPClientQueue pointerQueue;
|
||||
LG_Lock pointerQueueLock;
|
||||
KVMFRFeatureFlags kvmfrFeatures;
|
||||
LG_Transport * transport;
|
||||
const LG_TransportOps * transportOps;
|
||||
LG_TransportFeatureFlags transportFeatures;
|
||||
|
||||
LGThread * cursorThread;
|
||||
LGThread * frameThread;
|
||||
@@ -223,9 +219,7 @@ struct AppParams
|
||||
bool requestActivation;
|
||||
bool disableWaitingMessage;
|
||||
|
||||
unsigned int cursorPollInterval;
|
||||
unsigned int framePollInterval;
|
||||
bool allowDMA;
|
||||
const char * transport;
|
||||
|
||||
bool forceRenderer;
|
||||
unsigned int forceRendererIndex;
|
||||
|
||||
59
client/src/transport.c
Normal file
59
client/src/transport.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "interface/transport.h"
|
||||
#include "dynamic/transports.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void lgTransport_setup(void)
|
||||
{
|
||||
for (unsigned i = 0; i < LG_TRANSPORT_COUNT; ++i)
|
||||
if (LG_Transports[i]->setup)
|
||||
LG_Transports[i]->setup();
|
||||
}
|
||||
|
||||
bool lgTransport_isValid(const char * name)
|
||||
{
|
||||
if (!name)
|
||||
return false;
|
||||
for (unsigned i = 0; i < LG_TRANSPORT_COUNT; ++i)
|
||||
if (strcmp(LG_Transports[i]->name, name) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lgTransport_create(const char * name, LG_Transport ** transport,
|
||||
const LG_TransportOps ** ops)
|
||||
{
|
||||
for (unsigned i = 0; i < LG_TRANSPORT_COUNT; ++i)
|
||||
{
|
||||
if (strcmp(LG_Transports[i]->name, name) != 0)
|
||||
continue;
|
||||
|
||||
if (!LG_Transports[i]->create(transport))
|
||||
return false;
|
||||
|
||||
*ops = LG_Transports[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user