Compare commits

...

23 Commits
B6-rc1 ... B6

Author SHA1 Message Date
Geoffrey McRae
188f25c6bf [host] nvfbc: increase retry timeout to 1 second 2022-12-09 08:00:03 +11:00
Geoffrey McRae
8619f787b9 [host] nvfbc: retry on failure to init
@quantum has observed nvfbc under rare circumstances fail to initialize,
this adds a retry to the init with a short delay to hopefully recover
from this situation.
2022-12-08 21:24:11 +11:00
Quantum
60ac03ebaf [client] wayland: implement window size setting for xdg-shell
This should allow win:autoResize to work on Wayland when the compositor
supports such an operation.
2022-12-08 21:08:33 +11:00
Quantum
e1ebde3cd2 [host] windows: log to stderr that logs will continue in file
This prevents users from posting the stderr as if it's the only output.
2022-12-08 21:08:07 +11:00
Quantum
f519904c38 [host] app: clarify that config file not found is not fatal
This prevents users from thinking this is the problem they are facing.
2022-12-08 21:08:07 +11:00
Geoffrey McRae
fa6f1abaac [obs] fix compatibility with updated LGMP build 2022-11-08 00:00:39 +11:00
Geoffrey McRae
875242fe15 [host] app: improve throttleFPS logic 2022-11-07 22:56:20 +11:00
Geoffrey McRae
20b5957999 [client] update LGMP to fix buffer overflow bug 2022-11-07 21:57:10 +11:00
Geoffrey McRae
f0cb9d1167 [client] main: fix spice display fallback when waiting for LGMP upgrade 2022-11-07 19:16:52 +11:00
Geoffrey McRae
6cd88a70ad [host/client] lgmp: update to fix possible race issue 2022-11-07 14:44:26 +11:00
Geoffrey McRae
697bbcd6d4 [host] app: correct timer restart on lgmp corruption recovery 2022-11-07 13:36:57 +11:00
Geoffrey McRae
ecca5720a9 [host] app: ensure that rand will be random 2022-11-07 13:26:52 +11:00
Geoffrey McRae
50e856f823 [host] lgmp: update LGMP again to fix bug in last update 2022-11-07 13:20:24 +11:00
Geoffrey McRae
6359bb9acd [host] lgmp: update to fix failure to randomize the session ID 2022-11-07 13:12:51 +11:00
Geoffrey McRae
938011fce6 [module] swap offset & size in printk output for consistency 2022-11-07 13:12:51 +11:00
Geoffrey McRae
d09a10299e [module] cosmetics 2022-11-07 13:12:51 +11:00
Geoffrey McRae
8e706636d3 [host] app: don't stop the lgmpTimer on session recovery 2022-11-07 12:20:25 +11:00
Ali Abdel-Qader
352cd2fafe [client] remove non-prototype function declarations
With -Wstrict-prototypes on non-protyped functions are deprecated and
functions must include a void parameter if they do not take parameters.
2022-11-01 08:03:15 +11:00
Chris Spencer
081a0a419d [client] audio: use actual device period if larger than expected maximum
This is rare and I'm not sure what causes it, but PipeWire sometimes uses a
larger period size than requested for no obvious reason (e.g., we could
request a period size of 512, but PipeWire uses 2048 anyway). This causes
us to stay in a permanent state of underrunning because the target latency
is too low.

With this change, we use the actual device period in the target latency
calculation if it is larger than the expected maximum. We may still get
some glitches at the beginning of playback (because the startup latency is
based upon the expected maximum period size), but it will recover after a
few seconds as it adjusts to the new target latency.
2022-11-01 08:02:37 +11:00
esi
7e42e6cdce [obs] Fix function call causing crash on lgUpdate 2022-11-01 08:01:54 +11:00
Quantum
d857b2a36e [cmake] CheckSubmodule: check for nanosvg 2022-11-01 08:01:08 +11:00
Quantum
ba64a2d400 [repos] nanosvg: convert to submodule
This is fine now that nanosvg can be compiled with -Wstrict-prototypes
without warning.
2022-11-01 08:01:08 +11:00
Geoffrey McRae
9d8bc46812 [client] keybind: fix typo 2022-11-01 08:00:37 +11:00
21 changed files with 145 additions and 4596 deletions

3
.gitmodules vendored
View File

@@ -10,3 +10,6 @@
[submodule "repos/wayland-protocols"]
path = repos/wayland-protocols
url = https://gitlab.freedesktop.org/wayland/wayland-protocols.git
[submodule "repos/nanosvg"]
path = repos/nanosvg
url = https://github.com/memononen/nanosvg.git

View File

@@ -9,7 +9,7 @@ arcnmx <arcnmx@users.noreply.github.com> (arcnmx)
TheCakeIsNaOH <TheCakeIsNaOH@gmail.com> (TheCakeIsNaOH)
NamoDev <namodev@users.noreply.github.com> (NamoDev)
feltcat <58396817+feltcat@users.noreply.github.com> (feltcat)
Ali Abdel-Qader <abdelqaderali@protonmail.com>
Ali Abdel-Qader <abdelqaderali@protonmail.com> (thrifty-txt)
Jack Karamanian <karamanian.jack@gmail.com>
Mikko Rasa <tdb@tdb.fi> (DataBeaver)
Omar Pakker <Omar007@users.noreply.github.com> (Omar007)

View File

@@ -65,15 +65,30 @@ static const struct xdg_surface_listener xdgSurfaceListener = {
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
int32_t width, int32_t height, struct wl_array * states)
{
wlWm.width = width;
wlWm.height = height;
wlWm.width = width;
wlWm.height = height;
wlWm.fullscreen = false;
wlWm.floating = true;
enum xdg_toplevel_state * state;
wl_array_for_each(state, states)
{
if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN)
switch (*state)
{
case XDG_TOPLEVEL_STATE_FULLSCREEN:
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;
}
}
}
@@ -156,5 +171,14 @@ void waylandMinimize(void)
void waylandShellResize(int w, int h)
{
//TODO: Implement resize for XDG.
if (!wlWm.floating)
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,6 +112,7 @@ struct WaylandDSState
bool fractionalScale;
bool needsResize;
bool fullscreen;
bool floating;
uint32_t resizeSerial;
bool configured;
bool warpSupport;

View File

@@ -103,7 +103,7 @@ bool x11CBEventThread(const XEvent xe)
return false;
}
bool x11CBInit()
bool x11CBInit(void)
{
x11cb.aCurSelection = BadValue;
for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)

View File

@@ -458,7 +458,7 @@ void app_handleMouseRelative(double normx, double normy,
// cursor warp support. Instead, we attempt a best-effort emulation which works
// with a 1:1 mouse movement patch applied in the guest. For anything fancy, use
// capture mode.
void app_handleMouseBasic()
void app_handleMouseBasic(void)
{
/* do not pass mouse events to the guest if we do not have focus */
if (!g_cursor.guest.valid || !g_state.haveSrcSize || !g_state.focused ||
@@ -495,7 +495,7 @@ void app_handleMouseBasic()
DEBUG_ERROR("failed to send mouse motion message");
}
void app_resyncMouseBasic()
void app_resyncMouseBasic(void)
{
if (!g_cursor.guest.valid)
return;

View File

@@ -525,12 +525,15 @@ void audio_playbackData(uint8_t * data, size_t size)
}
/* Determine the target latency. This is made up of the maximum audio device
* period (plus a little extra to absorb timing jitter) and a configurable
* period (or the current actual period, if larger than the expected maximum),
* plus a little extra to absorb timing jitter, and a configurable
* additional buffer period. The default is set high enough to absorb typical
* timing jitter from qemu. */
int configLatencyMs = max(g_params.audioBufferLatency, 0);
int maxPeriodFrames =
max(audio.playback.deviceMaxPeriodFrames, spiceData->devPeriodFrames);
double targetLatencyFrames =
audio.playback.deviceMaxPeriodFrames * 1.1 +
maxPeriodFrames * 1.1 +
configLatencyMs * audio.playback.sampleRate / 1000.0;
/* If the device is currently at a lower period size than its maximum (which

View File

@@ -170,7 +170,7 @@ void keybind_spiceRegister(void)
"Spice keyboard & mouse toggle");
app_registerKeybind(KEY_INSERT, 0, bind_mouseSens, (void *) true ,
"Increase mouse sensitivity 0, in capture mode");
"Increase mouse sensitivity in capture mode");
app_registerKeybind(KEY_DELETE, 0, bind_mouseSens, (void *) false,
"Descrease mouse sensitivity in capture mode");

View File

@@ -1433,7 +1433,8 @@ restart:
initialSpiceEnable = 0;
}
status = lgmpClientSessionInit(g_state.lgmp, &udataSize, (uint8_t **)&udata);
status = lgmpClientSessionInit(g_state.lgmp, &udataSize, (uint8_t **)&udata,
NULL);
switch(status)
{
case LGMP_OK:
@@ -1442,21 +1443,19 @@ restart:
case LGMP_ERR_INVALID_VERSION:
{
reportBadVersion();
msgs[msgsCount++] = app_msgBox(
"Incompatible LGMP Version",
"The host application is not compatible with this client.\n"
"Please download and install the matching version."
);
if (waitCount++ == 0)
{
reportBadVersion();
msgs[msgsCount++] = app_msgBox(
"Incompatible LGMP Version",
"The host application is not compatible with this client.\n"
"Please download and install the matching version."
);
DEBUG_INFO("Waiting for you to upgrade the host application");
while (g_state.state == APP_STATE_RUNNING &&
lgmpClientSessionInit(g_state.lgmp, &udataSize, (uint8_t **)&udata) != LGMP_OK)
g_state.ds->wait(1000);
if (g_state.state != APP_STATE_RUNNING)
return -1;
DEBUG_INFO("Waiting for you to upgrade the host application");
}
g_state.ds->wait(1000);
continue;
}

View File

@@ -3,7 +3,8 @@ if (EXISTS "${PROJECT_TOP}/.git" AND (
(NOT EXISTS "${PROJECT_TOP}/repos/LGMP/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/PureSpice/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/cimgui/imgui/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/wayland-protocols/.git")
(NOT EXISTS "${PROJECT_TOP}/repos/wayland-protocols/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/nanosvg/.git")
))
message(FATAL_ERROR "Submodules are not initialized. Run\n\tgit submodule update --init --recursive")
endif()

View File

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

View File

@@ -526,7 +526,13 @@ bool app_init(void)
// redirect stderr to a file
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
setbuf(stderr, NULL);

View File

@@ -719,6 +719,9 @@ int app_main(int argc, char * argv[])
if (!installCrashHandler(os_getExecutable()))
DEBUG_WARN("Failed to install the crash handler");
// make sure rng is actually seeded for LGMP
srand((unsigned)time(NULL));
app.state = APP_STATE_RUNNING;
ivshmemOptionsInit();
@@ -745,7 +748,7 @@ int app_main(int argc, char * argv[])
if (option_load(configFile))
DEBUG_INFO("Configuration file loaded");
else
DEBUG_INFO("Configuration file not found or invalid");
DEBUG_INFO("Configuration file not found or invalid, continuing anyway...");
// parse the command line arguments
if (!option_parse(argc, argv))
@@ -855,9 +858,9 @@ int app_main(int argc, char * argv[])
{
DEBUG_INFO("Performing LGMP reinitialization");
lgmpShutdown();
app.state = APP_STATE_RUNNING;
if (!lgmpSetup(&shmDev))
goto fail_lgmp;
app.state = APP_STATE_RUNNING;
}
if (app.state == APP_STATE_IDLE)
@@ -898,19 +901,20 @@ int app_main(int argc, char * argv[])
LG_UNLOCK(app.pointerLock);
}
const uint64_t now = microtime();
const uint64_t delta = now - previousFrameTime;
const uint64_t delta = microtime() - previousFrameTime;
if (delta < throttleUs)
{
nsleep((throttleUs - delta) * 1000);
previousFrameTime = microtime();
const uint64_t us = throttleUs - delta;
// only delay if the time is reasonable
if (us > 1000)
nsleep(us * 1000);
}
else
previousFrameTime = now;
const uint64_t captureStart = microtime();
switch(iface->capture())
{
case CAPTURE_RESULT_OK:
previousFrameTime = captureStart;
break;
case CAPTURE_RESULT_TIMEOUT:

View File

@@ -124,7 +124,8 @@ err:
return ERR_PTR(ret);
}
static void unmap_kvmfrbuf(struct dma_buf_attachment * at, struct sg_table * sg, enum dma_data_direction direction)
static void unmap_kvmfrbuf(struct dma_buf_attachment * at, struct sg_table * sg,
enum dma_data_direction direction)
{
dma_unmap_sg(at->dev, sg->sgl, sg->nents, direction);
sg_free_table(sg);
@@ -144,7 +145,8 @@ static int mmap_kvmfrbuf(struct dma_buf * buf, struct vm_area_struct * vma)
unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
if ((offset + size > (kbuf->pagecount << PAGE_SHIFT)) || (offset + size < offset))
if ((offset + size > (kbuf->pagecount << PAGE_SHIFT))
|| (offset + size < offset))
return -EINVAL;
if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
@@ -158,7 +160,8 @@ static int mmap_kvmfrbuf(struct dma_buf * buf, struct vm_area_struct * vma)
return 0;
case KVMFR_TYPE_STATIC:
return remap_vmalloc_range(vma, kbuf->kdev->addr + kbuf->offset, vma->vm_pgoff);
return remap_vmalloc_range(vma, kbuf->kdev->addr + kbuf->offset,
vma->vm_pgoff);
default:
return -EINVAL;
@@ -173,7 +176,8 @@ static const struct dma_buf_ops kvmfrbuf_ops =
.mmap = mmap_kvmfrbuf
};
static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp, unsigned long arg)
static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp,
unsigned long arg)
{
struct kvmfr_dmabuf_create create;
DEFINE_DMA_BUF_EXPORT_INFO(exp_kdev);
@@ -194,7 +198,8 @@ static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp, uns
return -EINVAL;
}
if ((create.offset + create.size > kdev->size) || (create.offset + create.size < create.offset))
if ((create.offset + create.size > kdev->size) ||
(create.offset + create.size < create.offset))
return -EINVAL;
kbuf = kzalloc(sizeof(struct kvmfrbuf), GFP_KERNEL);
@@ -204,7 +209,8 @@ static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp, uns
kbuf->kdev = kdev;
kbuf->pagecount = create.size >> PAGE_SHIFT;
kbuf->offset = create.offset;
kbuf->pages = kmalloc_array(kbuf->pagecount, sizeof(*kbuf->pages), GFP_KERNEL);
kbuf->pages = kmalloc_array(kbuf->pagecount, sizeof(*kbuf->pages),
GFP_KERNEL);
if (!kbuf->pages)
{
ret = -ENOMEM;
@@ -244,7 +250,8 @@ static long kvmfr_dmabuf_create(struct kvmfr_dev * kdev, struct file * filp, uns
goto err;
}
printk("kvmfr_dmabuf_create: offset: %llu, size: %llu\n", create.offset, create.size);
printk("kvmfr_dmabuf_create with size %llu offset: %llu",
create.size, create.offset);
return dma_buf_fd(buf, create.flags & KVMFR_DMABUF_FLAG_CLOEXEC ? O_CLOEXEC : 0);
err:
@@ -253,7 +260,8 @@ err:
return ret;
}
static long device_ioctl(struct file * filp, unsigned int ioctl, unsigned long arg)
static long device_ioctl(struct file * filp, unsigned int ioctl,
unsigned long arg)
{
struct kvmfr_dev * kdev;
long ret;
@@ -359,7 +367,8 @@ static int kvmfr_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
mutex_unlock(&minor_lock);
kdev->devNo = MKDEV(kvmfr->major, kdev->minor);
kdev->pDev = device_create(kvmfr->pClass, NULL, kdev->devNo, NULL, KVMFR_DEV_NAME "%d", kdev->minor);
kdev->pDev = device_create(kvmfr->pClass, NULL, kdev->devNo, NULL,
KVMFR_DEV_NAME "%d", kdev->minor);
if (IS_ERR(kdev->pDev))
goto out_unminor;
@@ -451,7 +460,9 @@ static int create_static_device_unlocked(int size_mb)
kdev->addr = vmalloc_user(kdev->size);
if (!kdev->addr)
{
printk(KERN_ERR "kvmfr: failed to allocate memory for static device: %d MiB\n", size_mb);
printk(
KERN_ERR "kvmfr: failed to allocate memory for static device: %d MiB\n",
size_mb);
ret = -ENOMEM;
goto out_free;
}
@@ -461,7 +472,8 @@ static int create_static_device_unlocked(int size_mb)
goto out_release;
kdev->devNo = MKDEV(kvmfr->major, kdev->minor);
kdev->pDev = device_create(kvmfr->pClass, NULL, kdev->devNo, NULL, KVMFR_DEV_NAME "%d", kdev->minor);
kdev->pDev = device_create(kvmfr->pClass, NULL, kdev->devNo, NULL,
KVMFR_DEV_NAME "%d", kdev->minor);
if (IS_ERR(kdev->pDev))
goto out_unminor;

View File

@@ -156,7 +156,7 @@ static void deinit(LGPlugin * this)
case STATE_STOPPING:
case STATE_RESTARTING:
this->state = STATE_STOPPING;
createThreads(this);
waitThreads(this);
this->state = STATE_STOPPED;
/* fallthrough */
@@ -421,7 +421,7 @@ static void lgUpdate(void * data, obs_data_t * settings)
usleep(200000);
if (lgmpClientSessionInit(this->lgmp, &udataSize, (uint8_t **)&udata)
if (lgmpClientSessionInit(this->lgmp, &udataSize, (uint8_t **)&udata, NULL)
!= LGMP_OK)
return;

1
repos/nanosvg Submodule

Submodule repos/nanosvg added at 64d59e4d53

View File

@@ -1,31 +0,0 @@
## Compiled source #
*.com
*.class
*.dll
*.exe
*.o
*.so
test
## Logs and databases #
*.log
*.sql
*.sqlite
## OS generated files #
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
## Build dir
build/*
## Stuff in example
example/_*
## xcode specific
*xcuserdata*

View File

@@ -1,18 +0,0 @@
Copyright (c) 2013-14 Mikko Mononen memon@inside.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff