// 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 #include #include #include 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(frame & 0xFF); g = static_cast((frame >> 8) & 0xFF); b = static_cast((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(r) | (static_cast(g) << 8) | (static_cast(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 create(const std::string& name); }; // Per-backend factories (defined in their own TUs; create() dispatches to them). std::unique_ptr create_dx11_backend(); std::unique_ptr create_dx12_backend(); std::unique_ptr create_dx10_backend(); std::unique_ptr create_dx9_backend(bool ex); // ex: D3D9Ex vs plain D3D9 std::unique_ptr create_gl_backend(); } // namespace coop::mock