Compare commits

..

3 Commits

Author SHA1 Message Date
Geoffrey McRae
6ee30b2308 [client] update for the new LGMP interface prototypes 2022-11-07 20:59:36 +11:00
Geoffrey McRae
714b1bce70 [lgmp] update to fix array overflow bug 2022-11-07 20:51:10 +11:00
Geoffrey McRae
3ec632dd3c [host] initial changes to implement frame rate control 2022-11-07 19:48:38 +11:00
10 changed files with 79 additions and 96 deletions

View File

@@ -65,30 +65,15 @@ static const struct xdg_surface_listener xdgSurfaceListener = {
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel, static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
int32_t width, int32_t height, struct wl_array * states) int32_t width, int32_t height, struct wl_array * states)
{ {
wlWm.width = width; wlWm.width = width;
wlWm.height = height; wlWm.height = height;
wlWm.fullscreen = false; wlWm.fullscreen = false;
wlWm.floating = true;
enum xdg_toplevel_state * state; enum xdg_toplevel_state * state;
wl_array_for_each(state, states) wl_array_for_each(state, states)
{ {
switch (*state) if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN)
{
case XDG_TOPLEVEL_STATE_FULLSCREEN:
wlWm.fullscreen = true; wlWm.fullscreen = true;
// fallthrough
case XDG_TOPLEVEL_STATE_MAXIMIZED:
case XDG_TOPLEVEL_STATE_TILED_LEFT:
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
case XDG_TOPLEVEL_STATE_TILED_TOP:
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
wlWm.floating = false;
break;
default:
break;
}
} }
} }
@@ -171,14 +156,5 @@ void waylandMinimize(void)
void waylandShellResize(int w, int h) void waylandShellResize(int w, int h)
{ {
if (!wlWm.floating) //TODO: Implement resize for XDG.
return;
wlWm.width = w;
wlWm.height = h;
xdg_surface_set_window_geometry(wlWm.xdgSurface, 0, 0, w, h);
wlWm.needsResize = true;
app_invalidateWindow(true);
waylandStopWaitFrame();
} }

View File

@@ -112,7 +112,6 @@ struct WaylandDSState
bool fractionalScale; bool fractionalScale;
bool needsResize; bool needsResize;
bool fullscreen; bool fullscreen;
bool floating;
uint32_t resizeSerial; uint32_t resizeSerial;
bool configured; bool configured;
bool warpSupport; bool warpSupport;

View File

@@ -478,10 +478,11 @@ void core_handleMouseNormal(double ex, double ey)
if (!g_state.stopVideo && if (!g_state.stopVideo &&
g_state.kvmfrFeatures & KVMFR_FEATURE_SETCURSORPOS) g_state.kvmfrFeatures & KVMFR_FEATURE_SETCURSORPOS)
{ {
const KVMFRSetCursorPos msg = { const KVMFRMessage_SetCursorPos msg = {
.msg.type = KVMFR_MESSAGE_SETCURSORPOS, .msg.type = KVMFR_MESSAGE_SETCURSORPOS,
.x = round(guest.x), .msg.clientID = g_state.clientID,
.y = round(guest.y) .x = round(guest.x),
.y = round(guest.y)
}; };
uint32_t setPosSerial; uint32_t setPosSerial;

View File

@@ -1434,7 +1434,7 @@ restart:
} }
status = lgmpClientSessionInit(g_state.lgmp, &udataSize, (uint8_t **)&udata, status = lgmpClientSessionInit(g_state.lgmp, &udataSize, (uint8_t **)&udata,
NULL); &g_state.clientID);
switch(status) switch(status)
{ {
case LGMP_OK: case LGMP_OK:

View File

@@ -121,6 +121,7 @@ struct AppState
struct IVSHMEM shm; struct IVSHMEM shm;
PLGMPClient lgmp; PLGMPClient lgmp;
uint32_t clientID;
PLGMPClientQueue pointerQueue; PLGMPClientQueue pointerQueue;
LG_Lock pointerQueueLock; LG_Lock pointerQueueLock;
KVMFRFeatureFlags kvmfrFeatures; KVMFRFeatureFlags kvmfrFeatures;

View File

@@ -28,7 +28,7 @@
#include "types.h" #include "types.h"
#define KVMFR_MAGIC "KVMFR---" #define KVMFR_MAGIC "KVMFR---"
#define KVMFR_VERSION 19 #define KVMFR_VERSION 20
#define KVMFR_MAX_DAMAGE_RECTS 64 #define KVMFR_MAX_DAMAGE_RECTS 64
@@ -56,7 +56,8 @@ typedef uint32_t KVMFRFeatureFlags;
enum enum
{ {
KVMFR_MESSAGE_SETCURSORPOS KVMFR_MESSAGE_SETCURSORPOS,
KVMFR_MESSAGE_FRAME_TIME
}; };
typedef uint32_t KVMFRMessageType; typedef uint32_t KVMFRMessageType;
@@ -137,6 +138,8 @@ typedef struct KVMFRFrame
{ {
uint32_t formatVer; // the frame format version number uint32_t formatVer; // the frame format version number
uint32_t frameSerial; // the unique frame number uint32_t frameSerial; // the unique frame number
uint64_t frameTimeUs; // when the capture was started
uint64_t frameElapsedUs; // total time elapsed to capture the frame
FrameType type; // the frame data type FrameType type; // the frame data type
uint32_t screenWidth; // the client's screen width uint32_t screenWidth; // the client's screen width
uint32_t screenHeight; // the client's screen height uint32_t screenHeight; // the client's screen height
@@ -155,14 +158,28 @@ KVMFRFrame;
typedef struct KVMFRMessage typedef struct KVMFRMessage
{ {
KVMFRMessageType type; KVMFRMessageType type;
uint32_t clientID;
} }
KVMFRMessage; KVMFRMessage;
typedef struct KVMFRSetCursorPos typedef struct KVMFRMessage_SetCursorPos
{ {
KVMFRMessage msg; KVMFRMessage msg;
int32_t x, y; int32_t x, y;
} }
KVMFRSetCursorPos; KVMFRMessage_SetCursorPos;
typedef struct KVMFRMessage_FrameTime
{
KVMFRMessage msg;
/* this is the desired time to start the next capture operation where zero is
* immediate. This is only a hint to the host application and may not be
* honored. The value provided should be offset from the latest frame's
* frameTimeUs. When multiple clients are sending this message, the one with
* the lowest value will be used.
*/
uint64_t frameTimeUs;
}
KVMFRMessage_FrameTime;
#endif #endif

View File

@@ -316,55 +316,43 @@ static bool nvfbc_init(void)
} }
int adapterIndex = option_get_int("nvfbc", "adapterIndex"); int adapterIndex = option_get_int("nvfbc", "adapterIndex");
// NOTE: Calling this on hardware that doesn't support NvFBC such as GeForce
bool created = false; // causes a substantial performance pentalty even if it fails! As such we only
for(int retry = 0; retry < 2; ++retry) // attempt NvFBC as a last resort, or if configured via the app:capture
// option.
if (adapterIndex < 0)
{ {
// NOTE: Calling this on hardware that doesn't support NvFBC such as GeForce IDirect3D9 * d3d = Direct3DCreate9(D3D_SDK_VERSION);
// causes a substantial performance pentalty even if it fails! As such we only int adapterCount = IDirect3D9_GetAdapterCount(d3d);
// attempt NvFBC as a last resort, or if configured via the app:capture for(int i = 0; i < adapterCount; ++i)
// option. {
D3DADAPTER_IDENTIFIER9 ident;
IDirect3D9_GetAdapterIdentifier(d3d, i, 0, &ident);
if (ident.VendorId != 0x10DE)
continue;
if (NvFBCToSysCreate(i, privData, privDataLen, &this->nvfbc,
&this->maxWidth, &this->maxHeight))
{
adapterIndex = i;
break;
}
}
IDirect3D9_Release(d3d);
if (adapterIndex < 0) if (adapterIndex < 0)
{ {
IDirect3D9 * d3d = Direct3DCreate9(D3D_SDK_VERSION); free(privData);
int adapterCount = IDirect3D9_GetAdapterCount(d3d); return false;
for(int i = 0; i < adapterCount; ++i)
{
D3DADAPTER_IDENTIFIER9 ident;
IDirect3D9_GetAdapterIdentifier(d3d, i, 0, &ident);
if (ident.VendorId != 0x10DE)
continue;
if (NvFBCToSysCreate(i, privData, privDataLen, &this->nvfbc,
&this->maxWidth, &this->maxHeight))
{
adapterIndex = i;
created = true;
break;
}
}
IDirect3D9_Release(d3d);
} }
else }
else
if (!NvFBCToSysCreate(adapterIndex, privData, privDataLen, &this->nvfbc, &this->maxWidth, &this->maxHeight))
{ {
if (!NvFBCToSysCreate(adapterIndex, privData, privDataLen, &this->nvfbc, &this->maxWidth, &this->maxHeight)) free(privData);
continue; return false;
created = true;
} }
if (created)
break;
//1000ms delay before retry
nsleep(1000000000);
}
if (!created)
{
free(privData);
return false;
}
int diffRes = option_get_int("nvfbc", "diffRes"); int diffRes = option_get_int("nvfbc", "diffRes");
enum DiffMapBlockSize blockSize; enum DiffMapBlockSize blockSize;
NvFBCGetDiffMapBlockSize(diffRes, &blockSize, &this->diffShift, privData, privDataLen); NvFBCGetDiffMapBlockSize(diffRes, &blockSize, &this->diffShift, privData, privDataLen);

View File

@@ -526,13 +526,7 @@ bool app_init(void)
// redirect stderr to a file // redirect stderr to a file
if (logFile && strcmp(logFile, "stderr") != 0) if (logFile && strcmp(logFile, "stderr") != 0)
{ freopen(logFile, "a", stderr);
DEBUG_INFO("Logs will be written to: %s", logFile);
DEBUG_INFO("Please see there for any further information");
if (!freopen(logFile, "a", stderr))
DEBUG_WARN("Failed to open log file, will log to stderr");
}
// always flush stderr // always flush stderr
setbuf(stderr, NULL); setbuf(stderr, NULL);

View File

@@ -96,6 +96,7 @@ struct app
unsigned int frameIndex; unsigned int frameIndex;
bool frameValid; bool frameValid;
uint32_t frameSerial; uint32_t frameSerial;
uint64_t frameTimeUs;
CaptureInterface * iface; CaptureInterface * iface;
@@ -268,6 +269,7 @@ static bool sendFrame(void)
} }
fi->formatVer = frame.formatVer; fi->formatVer = frame.formatVer;
fi->frameTimeUs = app.frameTimeUs;
fi->frameSerial = app.frameSerial++; fi->frameSerial = app.frameSerial++;
fi->screenWidth = frame.screenWidth; fi->screenWidth = frame.screenWidth;
fi->screenHeight = frame.screenHeight; fi->screenHeight = frame.screenHeight;
@@ -295,6 +297,11 @@ static bool sendFrame(void)
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset); FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset);
framebuffer_prepare(fb); framebuffer_prepare(fb);
// calculate the elapsed time as late as possible, note that this does not
// take into account the memory copy time and the client's that care about
// this value will need to take this into account
fi->frameElapsedUs = microtime() - app.frameTimeUs;
/* we post and then get the frame, this is intentional! */ /* we post and then get the frame, this is intentional! */
if ((status = lgmpHostQueuePost(app.frameQueue, 0, if ((status = lgmpHostQueuePost(app.frameQueue, 0,
app.frameMemory[app.frameIndex])) != LGMP_OK) app.frameMemory[app.frameIndex])) != LGMP_OK)
@@ -748,7 +755,7 @@ int app_main(int argc, char * argv[])
if (option_load(configFile)) if (option_load(configFile))
DEBUG_INFO("Configuration file loaded"); DEBUG_INFO("Configuration file loaded");
else else
DEBUG_INFO("Configuration file not found or invalid, continuing anyway..."); DEBUG_INFO("Configuration file not found or invalid");
// parse the command line arguments // parse the command line arguments
if (!option_parse(argc, argv)) if (!option_parse(argc, argv))
@@ -901,20 +908,20 @@ int app_main(int argc, char * argv[])
LG_UNLOCK(app.pointerLock); LG_UNLOCK(app.pointerLock);
} }
const uint64_t delta = microtime() - previousFrameTime; const uint64_t now = microtime();
const uint64_t delta = now - previousFrameTime;
if (delta < throttleUs) if (delta < throttleUs)
{ {
const uint64_t us = throttleUs - delta; nsleep((throttleUs - delta) * 1000);
// only delay if the time is reasonable previousFrameTime = microtime();
if (us > 1000)
nsleep(us * 1000);
} }
else
previousFrameTime = now;
const uint64_t captureStart = microtime(); app.frameTimeUs = microtime();
switch(iface->capture()) switch(iface->capture())
{ {
case CAPTURE_RESULT_OK: case CAPTURE_RESULT_OK:
previousFrameTime = captureStart;
break; break;
case CAPTURE_RESULT_TIMEOUT: case CAPTURE_RESULT_TIMEOUT:

View File

@@ -421,7 +421,7 @@ static void lgUpdate(void * data, obs_data_t * settings)
usleep(200000); usleep(200000);
if (lgmpClientSessionInit(this->lgmp, &udataSize, (uint8_t **)&udata, NULL) if (lgmpClientSessionInit(this->lgmp, &udataSize, (uint8_t **)&udata)
!= LGMP_OK) != LGMP_OK)
return; return;