Add coop_mock_game: animated, frame-numbered A/V test game (DX11 + DX12)
A tiny test "game" for exercising the capture/audio/hook paths. Opens a normal window and renders an animated pattern -- moving bar + per-frame background so motion (and dropped frames) are obvious -- with a top-left block whose RGB encodes the exact frame number, so a capture test can decode it and detect dropped / duplicated / stale frames. Selectable backend (dx11 / dx12 today), behind a RenderBackend interface so OpenGL/Vulkan can be added. With audio args it also plays a configurable WASAPI tone (shared ToneSource), so it's a full A/V source with a window (unlike coop_tone). coop_mock_game.exe [dx11|dx12] [seconds] [rate] [channels] [bits] [pcm|float] Milestone 1 of the mock-game roadmap item (the stress-test suite follows). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
64
tools/mock_game/render_backend.hpp
Normal file
64
tools/mock_game/render_backend.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Pluggable render backend for the mock game (a test fixture, not a shipped component).
|
||||
//
|
||||
// The mock game renders an *animated* (never static) pattern so dropped / duplicated /
|
||||
// torn / stale frames are obvious both to the eye and to an automated capture test: a
|
||||
// moving bar + a per-frame background colour give visible motion, and a small top-left
|
||||
// "frame-counter" block encodes the exact frame number in its RGB so a test can decode it
|
||||
// from a captured pixel and assert the sequence advances (the DX12 rotating-backbuffer bug
|
||||
// showed up as a stuck/repeating counter). The backend is selectable (DX11 / DX12 today)
|
||||
// and structured so OpenGL / Vulkan can be added by implementing this interface.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace coop::mock
|
||||
{
|
||||
|
||||
// Encode a frame counter into an RGB triple (and back). R/G/B are the low 24 bits, so it
|
||||
// is unambiguous for ~16M frames. The swap chain is UNORM (not sRGB), so the bytes survive
|
||||
// a capture copy exactly. The capture test samples the frame-counter block and decodes it.
|
||||
inline void frame_to_rgb(std::uint32_t frame, std::uint8_t& r, std::uint8_t& g, std::uint8_t& b)
|
||||
{
|
||||
r = static_cast<std::uint8_t>(frame & 0xFF);
|
||||
g = static_cast<std::uint8_t>((frame >> 8) & 0xFF);
|
||||
b = static_cast<std::uint8_t>((frame >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
inline std::uint32_t rgb_to_frame(std::uint8_t r, std::uint8_t g, std::uint8_t b)
|
||||
{
|
||||
return static_cast<std::uint32_t>(r) | (static_cast<std::uint32_t>(g) << 8) |
|
||||
(static_cast<std::uint32_t>(b) << 16);
|
||||
}
|
||||
|
||||
// Size (px) of the top-left frame-counter block the test samples.
|
||||
inline constexpr std::uint32_t kFrameBlock = 64;
|
||||
|
||||
class RenderBackend
|
||||
{
|
||||
public:
|
||||
virtual ~RenderBackend() = default;
|
||||
|
||||
// Bring up the device + swap chain on `hwnd` at the given client size. False on failure.
|
||||
virtual bool init(HWND hwnd, std::uint32_t width, std::uint32_t height) = 0;
|
||||
|
||||
// Draw frame `frame` (animated background + moving bar + the frame-counter block) and
|
||||
// present it. One call per displayed frame.
|
||||
virtual void render_and_present(std::uint32_t frame) = 0;
|
||||
|
||||
// Human-readable backend name (e.g. "dx11"), for logging.
|
||||
[[nodiscard]] virtual const char* name() const = 0;
|
||||
|
||||
// Factory: returns a backend for `name` ("dx11" / "dx12"), or nullptr if unknown /
|
||||
// unavailable on this machine.
|
||||
static std::unique_ptr<RenderBackend> create(const std::string& name);
|
||||
};
|
||||
|
||||
// Per-backend factories (defined in their own TUs; create() dispatches to them).
|
||||
std::unique_ptr<RenderBackend> create_dx11_backend();
|
||||
std::unique_ptr<RenderBackend> create_dx12_backend();
|
||||
|
||||
} // namespace coop::mock
|
||||
Reference in New Issue
Block a user