// Mirrors a target window into a D3D11 texture using Windows.Graphics.Capture // (no injection). Frames arrive on a WGC thread; the newest is handed to the // render thread, which copies and draws it -- so all D3D11 context use stays on // one thread. #pragma once #include #include #include #include #include #include #include namespace coop { class FrameRenderer; class WindowCapture { public: ~WindowCapture(); // Begins capturing `target`. Returns false if WGC is unavailable or the // window can't be captured. bool start(HWND target, ID3D11Device* device); void stop(); [[nodiscard]] bool running() const { return session_ != nullptr; } [[nodiscard]] HWND target() const { return target_; } [[nodiscard]] std::uint32_t frame_width() const { return width_; } [[nodiscard]] std::uint32_t frame_height() const { return height_; } // Cumulative frames WGC has delivered (for the capture-rate metric). [[nodiscard]] std::uint64_t frames_arrived() const { return frames_arrived_; } // Render thread: consume the newest frame (if any) and draw it letterboxed // into a dst_w x dst_h target via `renderer`. void draw_latest(FrameRenderer& renderer, ID3D11DeviceContext* ctx, std::uint32_t dst_w, std::uint32_t dst_h); private: void on_frame_arrived(winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& pool, winrt::Windows::Foundation::IInspectable const&); HWND target_ = nullptr; Microsoft::WRL::ComPtr device_; Microsoft::WRL::ComPtr latest_; Microsoft::WRL::ComPtr latest_srv_; std::uint32_t width_ = 0; std::uint32_t height_ = 0; std::uint64_t frames_arrived_ = 0; // incremented in on_frame_arrived std::mutex mutex_; // guards pending_ handoff only (no context work under it) winrt::Windows::Graphics::Capture::Direct3D11CaptureFrame pending_{nullptr}; winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice winrt_device_{nullptr}; winrt::Windows::Graphics::Capture::GraphicsCaptureItem item_{nullptr}; winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool frame_pool_{nullptr}; winrt::Windows::Graphics::Capture::GraphicsCaptureSession session_{nullptr}; winrt::event_token frame_token_{}; winrt::Windows::Graphics::SizeInt32 pool_size_{0, 0}; }; } // namespace coop