// DX11 backend for the mock game. Renders the animated pattern entirely with region // clears (ID3D11DeviceContext1::ClearView) so it needs no shaders: an animated full-screen // background, a moving vertical bar, and the top-left frame-counter block. #include "render_backend.hpp" #include #include #include using Microsoft::WRL::ComPtr; namespace coop::mock { namespace { class Dx11Backend : public RenderBackend { public: bool init(HWND hwnd, std::uint32_t width, std::uint32_t height) override { width_ = width; height_ = height; const D3D_FEATURE_LEVEL levels[] = {D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0}; ComPtr ctx0; if (FAILED(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, levels, static_cast(std::size(levels)), D3D11_SDK_VERSION, device_.GetAddressOf(), nullptr, ctx0.GetAddressOf()))) { return false; } if (FAILED(ctx0.As(&ctx_))) // ClearView needs ID3D11DeviceContext1 { return false; } ComPtr dxgi_device; ComPtr adapter; ComPtr factory; if (FAILED(device_.As(&dxgi_device)) || FAILED(dxgi_device->GetAdapter(adapter.GetAddressOf())) || FAILED(adapter->GetParent(IID_PPV_ARGS(factory.GetAddressOf())))) { return false; } // The mock does trivial work, so it must render UNCAPPED (it's a perf fixture, not a real // game) -- a flip-model swapchain only tears free of vsync with ALLOW_TEARING, so require it. ComPtr factory5; BOOL tearing = FALSE; if (SUCCEEDED(factory.As(&factory5))) { factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &tearing, sizeof(tearing)); } tearing_ = tearing != 0; DXGI_SWAP_CHAIN_DESC1 desc = {}; desc.Width = width; desc.Height = height; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // UNORM (not sRGB) so the frame code is exact desc.SampleDesc.Count = 1; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 2; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; desc.Flags = tearing_ ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u; if (FAILED(factory->CreateSwapChainForHwnd(device_.Get(), hwnd, &desc, nullptr, nullptr, swap_.GetAddressOf()))) { return false; } factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); // D3D11 flip-model: GetBuffer(0) stays the live back buffer, so one RTV is reused. ComPtr back; if (FAILED(swap_->GetBuffer(0, IID_PPV_ARGS(back.GetAddressOf()))) || FAILED(device_->CreateRenderTargetView(back.Get(), nullptr, rtv_.GetAddressOf()))) { return false; } return true; } void render_and_present(std::uint32_t frame) override { // Animated background: each channel sweeps at a different rate -> constant motion. const float bg[4] = {static_cast((frame * 2) % 256) / 255.0f, static_cast((frame * 3) % 256) / 255.0f, static_cast((frame * 5) % 256) / 255.0f, 1.0f}; ctx_->ClearRenderTargetView(rtv_.Get(), bg); // Moving vertical bar (obvious motion; a dropped frame makes it jump). const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; const LONG span = width_ > 24 ? static_cast(width_ - 24) : 1; const LONG bx = static_cast((frame * 4) % static_cast(span)); const D3D11_RECT bar = {bx, 0, bx + 24, static_cast(height_)}; ctx_->ClearView(rtv_.Get(), white, &bar, 1); // Frame-counter block (top-left): RGB encodes the exact frame number for the test. std::uint8_t r = 0, g = 0, b = 0; frame_to_rgb(frame, r, g, b); const float code[4] = {r / 255.0f, g / 255.0f, b / 255.0f, 1.0f}; const D3D11_RECT block = {0, 0, static_cast(kFrameBlock), static_cast(kFrameBlock)}; ctx_->ClearView(rtv_.Get(), code, &block, 1); swap_->Present(0, tearing_ ? DXGI_PRESENT_ALLOW_TEARING : 0u); // uncapped: the mock must be fast } [[nodiscard]] const char* name() const override { return "dx11"; } private: std::uint32_t width_ = 0; std::uint32_t height_ = 0; bool tearing_ = false; ComPtr device_; ComPtr ctx_; ComPtr swap_; ComPtr rtv_; }; } // namespace std::unique_ptr create_dx11_backend() { return std::make_unique(); } } // namespace coop::mock