Phase 0: donor-launch spike foundation

Scaffold CoopAllTheThings: Remote Play Together for any XInput game via a
mirror app under a donor appid (real game keeps its own appid, so DRM,
achievements, and playtime stay intact).

- Build: CMake skeleton, ImGui + SafetyHook submodules (no vcpkg)
- common/: host<->hook IPC contract (seqlock pad state, shared-memory RAII)
- host/: borderless D3D11 window + ImGui overlay listing visible XInput pads,
  behind an InputSource interface (Steam Input slots in later)
- README documents the Phase 0 donor-launch validation procedure, anti-cheat
  limitation, and XInput/bitness constraints

Phase 0 validates the riskiest assumption (Steam RPT streams an arbitrary
window under a donor appid and routes guest input to it) before capture and
injection are built.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 22:48:31 +02:00
commit cf058aecfa
23 changed files with 1129 additions and 0 deletions

68
host/src/d3d11_window.hpp Normal file
View File

@@ -0,0 +1,68 @@
// Borderless full-screen D3D11 window. This is the surface Steam Remote Play
// Together captures, so it must be a normal (non-exclusive) top-level window
// that owns a flip-model swap chain.
#pragma once
#include <d3d11.h>
#include <dxgi1_2.h>
#include <wrl/client.h>
#include <functional>
namespace coop
{
class D3D11Window
{
public:
using RenderCallback = std::function<void()>;
D3D11Window() = default;
~D3D11Window();
D3D11Window(const D3D11Window&) = delete;
D3D11Window& operator=(const D3D11Window&) = delete;
// Creates the borderless window sized to the primary monitor and brings up
// the D3D11 device + swap chain. Returns false on any failure.
bool create(const wchar_t* title);
// Pumps the message queue once. Returns false when the window is closing.
bool pump_messages();
// Clears the back buffer, invokes render (where ImGui draws), and presents.
void render_frame(const RenderCallback& render);
[[nodiscard]] HWND hwnd() const
{
return hwnd_;
}
[[nodiscard]] ID3D11Device* device() const
{
return device_.Get();
}
[[nodiscard]] ID3D11DeviceContext* context() const
{
return context_.Get();
}
private:
static LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
bool create_device();
void create_render_target();
void release_render_target();
void handle_resize(UINT width, UINT height);
HWND hwnd_ = nullptr;
bool resize_pending_ = false;
UINT resize_width_ = 0;
UINT resize_height_ = 0;
Microsoft::WRL::ComPtr<ID3D11Device> device_;
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context_;
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain_;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv_;
};
} // namespace coop