mock_game_test launches coop_mock_game (DX11/DX12, frame-numbered A/V), injects coop_hook.dll, opens the hook's shared video texture, and decodes the frame number from the captured pixels to assert a monotonic, advancing mirror for both backends (catches dropped/stale/out-of-order frames). Then it runs an A/V + hook/unhook stress pass and confirms no crash + capture resumes. Adds a read_pixel() readback to the shipping SharedTextureSource for the decode. Robust to repeated/CI runs (kills stray games, retries inject). Trim the roadmap (the mock-game item is done) and document the test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
2.7 KiB
C++
83 lines
2.7 KiB
C++
// Host-side consumer of the injected Present-hook's shared backbuffer texture.
|
|
// Opens the keyed-mutex texture the hook publishes (coop_video_<pid>) by name,
|
|
// copies the latest frame into a private texture under the keyed mutex, and
|
|
// exposes an SRV the FrameRenderer can draw -- the lower-latency alternative to
|
|
// Windows Graphics Capture. See hook/src/present_hook.cpp and coop/protocol.hpp.
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
#include <d3d11_1.h>
|
|
#include <wrl/client.h>
|
|
|
|
#include "ipc/ipc_server.hpp"
|
|
|
|
namespace coop
|
|
{
|
|
|
|
class SharedTextureSource
|
|
{
|
|
public:
|
|
// Binds to the host's device (must support ID3D11Device1). Returns false if not.
|
|
bool init(ID3D11Device* device);
|
|
|
|
// Polls the hook's video channel for `pid`. (Re)opens the shared texture when
|
|
// the pid/dimensions/format change, and copies the newest frame into the
|
|
// private texture under the keyed mutex. Returns true if a frame is available
|
|
// to draw (sticky: keeps the last copy until a new one or a reset).
|
|
bool update(const VideoShareView& share, unsigned long pid);
|
|
|
|
// Drop the opened resources (target changed / mirror turned off).
|
|
void reset();
|
|
|
|
// Read the RGBA8 pixel at (x,y) of the last copied frame into out[4]. For verification
|
|
// (e.g. decoding the mock game's frame-number block in a capture test). Copies the
|
|
// private texture to a CPU-readable staging texture and maps it -- not a hot path.
|
|
// Returns false if no frame has been copied yet or the readback failed.
|
|
bool read_pixel(std::uint32_t x, std::uint32_t y, std::uint8_t out[4]);
|
|
|
|
[[nodiscard]] ID3D11ShaderResourceView* srv() const
|
|
{
|
|
return srv_.Get();
|
|
}
|
|
[[nodiscard]] std::uint32_t width() const
|
|
{
|
|
return width_;
|
|
}
|
|
[[nodiscard]] std::uint32_t height() const
|
|
{
|
|
return height_;
|
|
}
|
|
[[nodiscard]] std::uint64_t frames_copied() const
|
|
{
|
|
return frames_copied_;
|
|
}
|
|
// Cumulative published frames the host never displayed because the generation
|
|
// advanced by more than one between copies (host render rate < hook publish rate).
|
|
[[nodiscard]] std::uint64_t frames_missed() const
|
|
{
|
|
return frames_missed_;
|
|
}
|
|
|
|
private:
|
|
bool reopen(unsigned long pid, const VideoShareView& share);
|
|
|
|
Microsoft::WRL::ComPtr<ID3D11Device1> device_;
|
|
Microsoft::WRL::ComPtr<ID3D11DeviceContext> ctx_;
|
|
Microsoft::WRL::ComPtr<ID3D11Texture2D> shared_; // opened from the hook, by name
|
|
Microsoft::WRL::ComPtr<IDXGIKeyedMutex> mutex_;
|
|
Microsoft::WRL::ComPtr<ID3D11Texture2D> private_; // our sampled copy
|
|
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> srv_;
|
|
|
|
unsigned long pid_ = 0;
|
|
std::uint32_t width_ = 0;
|
|
std::uint32_t height_ = 0;
|
|
std::uint32_t format_ = 0;
|
|
std::uint32_t last_generation_ = 0;
|
|
std::uint64_t frames_copied_ = 0;
|
|
std::uint64_t frames_missed_ = 0;
|
|
};
|
|
|
|
} // namespace coop
|