From bccf27f21a2230582cc528b070c0b0adf42ba5a9 Mon Sep 17 00:00:00 2001 From: KingKDot Date: Tue, 4 Aug 2026 00:55:41 -0500 Subject: [PATCH] fix QuickSync final --- .../desktop_encoder_capabilities_windows.go | 12 +++++++ .../agent/capture/qsvbridge/bridge_windows.cc | 36 +++++++++++++++++-- .../public/assets/remotedesktop.js | 2 +- scripts/start-dev.bat | 18 +++++++++- 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/Overlord-Client/cmd/agent/capture/desktop_encoder_capabilities_windows.go b/Overlord-Client/cmd/agent/capture/desktop_encoder_capabilities_windows.go index 4d3d524..f0935ab 100644 --- a/Overlord-Client/cmd/agent/capture/desktop_encoder_capabilities_windows.go +++ b/Overlord-Client/cmd/agent/capture/desktop_encoder_capabilities_windows.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "image" + "log" "sort" "strings" "sync" @@ -129,6 +130,8 @@ func probeDesktopEncoderCapabilities(ctx context.Context, display int, bounds im fpsOptions := []int{240, 165, 144, 120, 90, 60, 30} sizes := desktopProbeSizes(nativeWidth, nativeHeight) providersByProfile := make(map[string][]string) + lastProbeErrors := make(map[string]string) + successfulProbes := make(map[string]bool) probeLoop: for _, size := range sizes { for _, probe := range probes { @@ -150,8 +153,12 @@ probeLoop: frameBudget := time.Second / time.Duration(fps) if err == nil && averageEncode <= frameBudget+frameBudget/5 { maxFPS = fps + successfulProbes[probe.name] = true break } + if err != nil { + lastProbeErrors[probe.name] = err.Error() + } } if maxFPS == 0 { continue @@ -165,6 +172,11 @@ probeLoop: } } hardwareProfilesFound := len(providersByProfile) > 0 + for provider, probeErr := range lastProbeErrors { + if !successfulProbes[provider] { + log.Printf("capture: desktop encoder capability probe provider=%s unavailable: %s", provider, probeErr) + } + } for _, safe := range safeDesktopProfiles(nativeWidth, nativeHeight) { key := desktopProfileKey(safe.Width, safe.Height, safe.FPS) diff --git a/Overlord-Client/cmd/agent/capture/qsvbridge/bridge_windows.cc b/Overlord-Client/cmd/agent/capture/qsvbridge/bridge_windows.cc index 3584c4d..2d6ab7b 100644 --- a/Overlord-Client/cmd/agent/capture/qsvbridge/bridge_windows.cc +++ b/Overlord-Client/cmd/agent/capture/qsvbridge/bridge_windows.cc @@ -2,7 +2,9 @@ #include "bridge_windows.h" #include +#include #include +#include #include #include #include @@ -111,6 +113,34 @@ bool init_session(QSVEncoder* s, std::string& error) { return true; } +bool validate_intel_device(QSVEncoder* s, std::string& error) { + IDXGIDevice* dxgiDevice = nullptr; + HRESULT hr = s->device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); + if (FAILED(hr)) { error = hr_error("IDXGIDevice", hr); return false; } + IDXGIAdapter* adapter = nullptr; + hr = dxgiDevice->GetAdapter(&adapter); + dxgiDevice->Release(); + if (FAILED(hr) || !adapter) { error = hr_error("IDXGIDevice::GetAdapter", hr); return false; } + DXGI_ADAPTER_DESC desc = {}; + hr = adapter->GetDesc(&desc); + adapter->Release(); + if (FAILED(hr)) { error = hr_error("IDXGIAdapter::GetDesc", hr); return false; } + if (desc.VendorId != 0x8086) { + error = "Intel Quick Sync requires the selected display to use an Intel adapter"; + return false; + } + return true; +} + +bool protect_device_context(QSVEncoder* s, std::string& error) { + ID3D10Multithread* multithread = nullptr; + HRESULT hr = s->context->QueryInterface(__uuidof(ID3D10Multithread), reinterpret_cast(&multithread)); + if (FAILED(hr)) { error = hr_error("ID3D10Multithread", hr); return false; } + multithread->SetMultithreadProtected(TRUE); + multithread->Release(); + return true; +} + bool init_video_processor(QSVEncoder* s, std::string& error) { HRESULT hr = s->device->QueryInterface(__uuidof(ID3D11VideoDevice), reinterpret_cast(&s->videoDevice)); if (FAILED(hr)) { error = hr_error("ID3D11VideoDevice", hr); return false; } @@ -174,7 +204,9 @@ extern "C" int overlord_qsv_create(void* device, int input_width, int input_heig *output = nullptr; auto* s = new QSVEncoder(); std::string error; s->device = static_cast(device); s->device->AddRef(); s->device->GetImmediateContext(&s->context); s->inputWidth = input_width; s->inputHeight = input_height; s->width = width; s->height = height; - if (!s->api.open(error) || !init_session(s, error)) goto fail; + if (!s->context) { error = "ID3D11Device::GetImmediateContext returned null"; goto fail; } + if (!validate_intel_device(s, error) || !protect_device_context(s, error) || + !s->api.open(error) || !init_session(s, error)) goto fail; { mfxStatus sts = s->api.SetHandle(s->session, MFX_HANDLE_D3D11_DEVICE, device); if (sts != MFX_ERR_NONE) { error = status_error("MFXVideoCORE_SetHandle", sts); goto fail; } @@ -205,7 +237,7 @@ extern "C" int overlord_qsv_encode(overlord_qsv_encoder opaque, void* texture, i { mfxSurfaceD3D11Tex2D ext = {}; ext.SurfaceInterface.Header.SurfaceType = MFX_SURFACE_TYPE_D3D11_TEX2D; - ext.SurfaceInterface.Header.SurfaceFlags = MFX_SURFACE_FLAG_IMPORT_SHARED; + ext.SurfaceInterface.Header.SurfaceFlags = MFX_SURFACE_FLAG_IMPORT_COPY; ext.SurfaceInterface.Header.StructSize = sizeof(ext); ext.texture2D = s->nv12; mfxFrameSurface1* surface = nullptr; mfxStatus sts = s->memory->ImportFrameSurface(s->memory, MFX_SURFACE_COMPONENT_ENCODE, diff --git a/Overlord-Server/public/assets/remotedesktop.js b/Overlord-Server/public/assets/remotedesktop.js index fb0adc9..9c4b322 100644 --- a/Overlord-Server/public/assets/remotedesktop.js +++ b/Overlord-Server/public/assets/remotedesktop.js @@ -1926,7 +1926,7 @@ import { createSharedUiSettingsSaver, loadSharedUiSettings } from "./generated/s function ensureDuplicationForH264() { if (!duplicationCtrl || duplicationCtrl.disabled) return; const isWindows = clientOs.includes("windows") || clientOs.includes("win"); - if (!isWindows || duplicationCtrl.checked) return; + if (!isWindows) return; duplicationCtrl.checked = true; sendCmd("desktop_set_duplication", { enabled: true }); } diff --git a/scripts/start-dev.bat b/scripts/start-dev.bat index faf3169..29093b1 100644 --- a/scripts/start-dev.bat +++ b/scripts/start-dev.bat @@ -13,6 +13,22 @@ call bun install popd echo === Ensuring client dependencies (Go) === +if not exist "%ROOT%Overlord-Client\third_party\nvcodec\nvEncodeAPI.h" ( + echo [client] NVIDIA NVENC headers are missing; fetching them... + call "%SCRIPT_DIR%vendor-nvcodec-headers.bat" + if errorlevel 1 ( + echo [client] Failed to provision NVIDIA NVENC headers. + exit /b 1 + ) +) +if not exist "%ROOT%Overlord-Client\third_party\amf\include\core\Factory.h" ( + echo [client] AMD AMF headers are missing; fetching them... + call "%SCRIPT_DIR%vendor-amf-headers.bat" + if errorlevel 1 ( + echo [client] Failed to provision AMD AMF headers. + exit /b 1 + ) +) if not exist "%ROOT%Overlord-Client\third_party\onevpl\include\vpl\mfxdispatcher.h" ( echo [client] Intel oneVPL headers are missing; fetching them... call "%SCRIPT_DIR%vendor-onevpl-headers.bat" @@ -39,7 +55,7 @@ set CGO_ENABLED=1 start "Overlord-Server" cmd /k "cd /d ""%ROOT%Overlord-Server"" && set OVERLORD_DISABLE_AGENT_AUTH=true && set OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only && set LOG_LEVEL=debug && set NODE_ENV=development && bun run dev" timeout /t 3 /nobreak >nul -start "Overlord-Client" cmd /k "cd /d ""%ROOT%Overlord-Client"" && set CGO_ENABLED=1 && set OVERLORD_SERVER=wss://localhost:5173 && set OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only && set OVERLORD_TLS_INSECURE_SKIP_VERIFY=true && set OVERLORD_MODE=dev && set OVERLORD_CAPTURE_METRICS=true && set GOINSECURE=* && set GOSUMDB=off && set GOPROXY=https://proxy.golang.org,direct && go mod tidy && go run ./cmd/agent" +start "Overlord-Client" cmd /k "cd /d ""%ROOT%Overlord-Client"" && set CGO_ENABLED=1&& set OVERLORD_SERVER=wss://localhost:5173&& set OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only&& set OVERLORD_TLS_INSECURE_SKIP_VERIFY=true&& set OVERLORD_MODE=dev&& set OVERLORD_CAPTURE_METRICS=true&& set GOINSECURE=*&& set GOSUMDB=off&& set GOPROXY=https://proxy.golang.org,direct&& go mod tidy && go run ./cmd/agent" echo Done. Terminals stay open (/k) for logs. endlocal