Fix capture.get_jpg blocking during game load for Companion Mirror (#750)

Add a timeout and skip signalling to the D3D9 capture path so the API
thread no longer waits indefinitely when Present stops during loading.
Return the last successful JPEG frame as a fallback.

## Link to GitHub Issue or related Pull Request, if one exists
#746

## Description of change
* Fix `capture.get_jpg` blocking indefinitely when D3D9 screen capture
cannot
  complete during game loading (e.g. no Present calls).
* Add a 2-second timeout to `graphics_capture_receive_jpeg()` and cancel
  pending capture requests on timeout.
* Signal capture skip from D3D9 failure paths via
`graphics_capture_skip()`.
* Cache the last successful JPEG per screen and return it as a fallback
  when a new capture fails.
Tested with **stock iOS Spice Companion** only. I have not tested
Android or
other Companion clients. The iOS client implementation differs from the
others; this fix is server-side only.
No config file, CLI option, or API schema changes.

## Testing
* Built locally with llvm-mingw cross-compiler (WSL).
* Docker build (`src/spice2x/build_docker.sh`): Pending
* Tested with stock iOS Spice Companion on iPad: Mirror remains
connected
  during game loading instead of returning to KeyPad.
This commit is contained in:
jessemarthin
2026-06-12 11:14:47 +09:00
committed by GitHub
parent 18d6d9783a
commit 3037214932
3 changed files with 126 additions and 25 deletions
@@ -1535,6 +1535,9 @@ void graphics_d3d9_on_present(
log_warning("graphics::d3d9",
"failed to get back buffer, hr={}",
FMT_HRESULT(hr));
if (capture) {
graphics_capture_skip(capture_screen);
}
return;
}
@@ -1545,6 +1548,9 @@ void graphics_d3d9_on_present(
"failed to acquire back buffer descriptor, hr={}",
FMT_HRESULT(hr));
buffer->Release();
if (capture) {
graphics_capture_skip(capture_screen);
}
return;
}
@@ -1558,6 +1564,9 @@ void graphics_d3d9_on_present(
"failed to acquire temporary surface, hr={}",
FMT_HRESULT(hr));
buffer->Release();
if (capture) {
graphics_capture_skip(capture_screen);
}
return;
}
@@ -1568,6 +1577,9 @@ void graphics_d3d9_on_present(
FMT_HRESULT(hr));
temp_surface->Release();
buffer->Release();
if (capture) {
graphics_capture_skip(capture_screen);
}
return;
}