Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/platform/windows/capture_backend.zig
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,16 @@ pub const CaptureBackend = struct {
}

pub fn acquireFrame(self: *CaptureBackend, timeout_ms: u32, pts_nanos: u64) !?types.VideoFrame {
switch (self.backend_type) {
.dxgi => return self.dxgi_cap.?.acquireFrame(timeout_ms, pts_nanos),
.wgc => return self.wgc_cap.?.acquireFrame(timeout_ms, pts_nanos),
.game => return self.game_cap.?.acquireFrame(timeout_ms, pts_nanos),
const frame = switch (self.backend_type) {
.dxgi => try self.dxgi_cap.?.acquireFrame(timeout_ms, pts_nanos),
.wgc => try self.wgc_cap.?.acquireFrame(timeout_ms, pts_nanos),
.game => try self.game_cap.?.acquireFrame(timeout_ms, pts_nanos),
};
if (frame) |f| {
self.width = f.width;
self.height = f.height;
}
return frame;
}

pub fn getD3DDevice(self: *CaptureBackend) *d3d11.ID3D11Device {
Expand Down
23 changes: 19 additions & 4 deletions src/platform/windows/game_capture.zig
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,31 @@ pub const GameCapture = struct {
return null; // Timeout / skipped frame
}

const ipc = self.ipc_ptr.?;
if (!ipc.active or ipc.shared_handle == 0) return null;

// Check if game resized swapchain or recreated shared texture
if (self.ipc_ptr.?.shared_handle != self.current_shared_handle) {
if (ipc.shared_handle != self.current_shared_handle) {
log.info("Game texture resized to {d}x{d}, reopening shared handle...", .{
self.ipc_ptr.?.width,
self.ipc_ptr.?.height,
ipc.width,
ipc.height,
});
try self.reopenSharedTexture();
}

const tex = self.shared_texture orelse return null;
var tex = self.shared_texture orelse return null;
if (ipc.width > 0 and ipc.height > 0 and (ipc.width != self.width or ipc.height != self.height)) {
const tex_desc = tex.getDesc();
if (tex_desc.Width != ipc.width or tex_desc.Height != ipc.height) {
log.info("Game frame size changed to {d}x{d} with same shared handle, reopening texture...", .{ ipc.width, ipc.height });
try self.reopenSharedTexture();
tex = self.shared_texture orelse return null;
} else {
self.width = ipc.width;
self.height = ipc.height;
}
}

self.frame_index += 1;

return types.VideoFrame{
Expand Down
28 changes: 26 additions & 2 deletions src/platform/windows/wgc_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,32 @@ bool wgc_capture_acquire_frame(WgcCapture* cap, void* dest_texture, uint32_t tim
SizeInt32 contentSize = { 0, 0 };
frame->lpVtbl->get_ContentSize(frame, &contentSize);
if (contentSize.Width > 0 && contentSize.Height > 0) {
cap->width = (uint32_t)contentSize.Width;
cap->height = (uint32_t)contentSize.Height;
const uint32_t new_width = (uint32_t)contentSize.Width;
const uint32_t new_height = (uint32_t)contentSize.Height;
if (new_width != cap->width || new_height != cap->height) {
SizeInt32 new_size = { (int32_t)new_width, (int32_t)new_height };
HRESULT recreate_hr = cap->frame_pool->lpVtbl->Recreate(
cap->frame_pool,
cap->winrt_device,
87, // DirectXPixelFormat_B8G8R8A8UIntNormalized
2,
new_size
);
if (FAILED(recreate_hr)) {
fprintf(stderr, "[WGC] FramePool Recreate failed: 0x%08X (new size: %ux%u)\n", (unsigned int)recreate_hr, new_width, new_height);
}

cap->width = new_width;
cap->height = new_height;
if (out_width) *out_width = cap->width;
if (out_height) *out_height = cap->height;

frame->lpVtbl->base.Release((IInspectable_Local*)frame);
return false;
}

cap->width = new_width;
cap->height = new_height;
}
if (out_width) *out_width = cap->width;
if (out_height) *out_height = cap->height;
Expand Down
20 changes: 20 additions & 0 deletions src/platform/windows/wgc_capture.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ pub const WgcCapture = struct {
height: u32,
frame_count: u64 = 0,

fn recreateDestTexture(self: *WgcCapture, new_w: u32, new_h: u32) !void {
const tex_desc = d3d11.D3D11_TEXTURE2D_DESC{
.Width = new_w,
.Height = new_h,
.Format = d3d11.DXGI_FORMAT_B8G8R8A8_UNORM,
.Usage = d3d11.D3D11_USAGE_DEFAULT,
.BindFlags = d3d11.D3D11_BIND_RENDER_TARGET | d3d11.D3D11_BIND_SHADER_RESOURCE,
.MiscFlags = 0x2, // D3D11_RESOURCE_MISC_SHARED
};

const new_tex = try self.d3d.device.createTexture2D(&tex_desc);
_ = self.dest_texture.release();
self.dest_texture = new_tex;
self.width = new_w;
self.height = new_h;
}

pub fn isSupported() bool {
return wgc_is_supported();
}
Expand Down Expand Up @@ -117,6 +134,9 @@ pub const WgcCapture = struct {
var h: u32 = self.height;

const ok = wgc_capture_acquire_frame(self.handle, @ptrCast(self.dest_texture), timeout_ms, &w, &h);
if ((w != self.width or h != self.height) and w > 0 and h > 0) {
try self.recreateDestTexture(w, h);
}
if (!ok) return null;

self.width = w;
Expand Down
31 changes: 27 additions & 4 deletions src/ui/imgui_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ static int g_currentHotkeyPreset = -1;
// Live Screen Preview Engine State
static ID3D11Texture2D* g_pPreviewTexture = NULL;
static ID3D11ShaderResourceView* g_pPreviewSRV = NULL;
static ID3D11Texture2D* g_pPreviewSharedOpenedTexture = NULL;
static HANDLE g_previewSharedHandle = NULL;
static int g_previewWidth = 0;
static int g_previewHeight = 0;
static bool g_previewEnabled = false;
Expand All @@ -89,6 +91,14 @@ static uint64_t g_previewFrameCount = 0;
static CRITICAL_SECTION g_previewCs;
static bool g_previewCsInit = false;

static void reset_preview_shared_cache(void) {
if (g_pPreviewSharedOpenedTexture) {
g_pPreviewSharedOpenedTexture->Release();
g_pPreviewSharedOpenedTexture = NULL;
}
g_previewSharedHandle = NULL;
}

extern "C" {
void imgui_set_preview_enabled(bool enabled) {
g_previewEnabled = enabled;
Expand Down Expand Up @@ -125,6 +135,7 @@ void imgui_update_preview_d3d11(void* d3d11_texture, int width, int height) {
if (!g_pPreviewTexture || g_previewWidth != req_w || g_previewHeight != req_h) {
if (g_pPreviewSRV) { g_pPreviewSRV->Release(); g_pPreviewSRV = NULL; }
if (g_pPreviewTexture) { g_pPreviewTexture->Release(); g_pPreviewTexture = NULL; }
reset_preview_shared_cache();

D3D11_TEXTURE2D_DESC desc = {};
desc.Width = (UINT)req_w;
Expand Down Expand Up @@ -160,13 +171,23 @@ void imgui_update_preview_d3d11(void* d3d11_texture, int width, int height) {
if (SUCCEEDED(srcTex->QueryInterface(__uuidof(IDXGIResource), (void**)&dxgiRes)) && dxgiRes) {
HANDLE sharedHandle = NULL;
if (SUCCEEDED(dxgiRes->GetSharedHandle(&sharedHandle)) && sharedHandle) {
ID3D11Texture2D* openedTex = NULL;
if (SUCCEEDED(g_pd3dDevice->OpenSharedResource(sharedHandle, __uuidof(ID3D11Texture2D), (void**)&openedTex)) && openedTex) {
g_pd3dDeviceContext->CopyResource((ID3D11Resource*)g_pPreviewTexture, (ID3D11Resource*)openedTex);
openedTex->Release();
if (g_previewSharedHandle != sharedHandle || !g_pPreviewSharedOpenedTexture) {
reset_preview_shared_cache();
if (FAILED(g_pd3dDevice->OpenSharedResource(sharedHandle, __uuidof(ID3D11Texture2D), (void**)&g_pPreviewSharedOpenedTexture)) || !g_pPreviewSharedOpenedTexture) {
g_previewSharedHandle = NULL;
} else {
g_previewSharedHandle = sharedHandle;
}
}
if (g_pPreviewSharedOpenedTexture) {
g_pd3dDeviceContext->CopyResource((ID3D11Resource*)g_pPreviewTexture, (ID3D11Resource*)g_pPreviewSharedOpenedTexture);
}
} else {
reset_preview_shared_cache();
}
dxgiRes->Release();
} else {
reset_preview_shared_cache();
}
}
g_previewFrameCount++;
Expand Down Expand Up @@ -1906,6 +1927,7 @@ void imgui_window_render_ui(UiState* state) {
if (g_previewCsInit) EnterCriticalSection(&g_previewCs);
if (g_pPreviewSRV) { g_pPreviewSRV->Release(); g_pPreviewSRV = NULL; }
if (g_pPreviewTexture) { g_pPreviewTexture->Release(); g_pPreviewTexture = NULL; }
reset_preview_shared_cache();
g_previewWidth = 0;
g_previewHeight = 0;
if (g_previewCsInit) LeaveCriticalSection(&g_previewCs);
Expand Down Expand Up @@ -1959,6 +1981,7 @@ void imgui_window_destroy(void) {
ImGui::DestroyContext();

cleanup_render_target();
reset_preview_shared_cache();
if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = NULL; }
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
Expand Down
2 changes: 2 additions & 0 deletions src/ui/ui_controller.zig
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,8 @@ pub fn runUi(allocator: std.mem.Allocator, cfg: config.Config, headless_test_ms:
const now_ns = clock.MonotonicClock.nowNanos();
if (pb.acquireFrame(2, now_ns)) |maybe_frame| {
if (maybe_frame) |frame| {
ui_state.preview_width = @intCast(frame.width);
ui_state.preview_height = @intCast(frame.height);
app_window.imgui_update_preview_d3d11(frame.gpu_texture_ptr, @intCast(frame.width), @intCast(frame.height));
}
} else |_| {}
Expand Down
Loading