// Adapted from the vrdashboard template (FrameAssistant commit 4a5b090), // verified on the Steam Frame. See docs/steamframe/DESIGN.md, section 3. #pragma once #include #include #include #include #include #include #include #include #include class QQuickWindow; // Requirements the VR runtime imposes on the graphics device. All optional: // without them (snapshot mode, tests) backends pick defaults. struct RenderInterop { std::function vulkanInstanceExtensions; std::function vulkanDeviceExtensions; // The physical device driving the HMD, for a given VkInstance. std::function vulkanOutputDevice; }; // Abstraction over the graphics API used to render the Qt Quick scene into a // texture that SteamVR can consume. Everything API-specific (context/device // setup, texture allocation, layout transitions, handing the texture to OpenVR, // CPU readback) lives behind this interface; OverlayController and the // VR/input code stay API-agnostic. // // Call order (driven by OverlayController): // initialize → configureWindow → [QQuickRenderControl::initialize] → // attachWindow → createRenderTarget → per frame: beginFrame … [Qt renders] … // finishFrame → vrTexture → releaseRenderTarget → detachWindow → [Qt destroys // its device/context] class RenderBackend { public: virtual ~RenderBackend() = default; virtual QString name() const = 0; // Must be applied via QQuickWindow::setGraphicsApi() before any // QQuickWindow exists. virtual QSGRendererInterface::GraphicsApi graphicsApi() const = 0; // Creates API-level objects (context / instance). Requires a // QGuiApplication. virtual bool initialize( const RenderInterop& interop, QString* error ) = 0; // Tells Qt Quick which device/context/instance to use. Before // QQuickRenderControl::initialize(). virtual void configureWindow( QQuickWindow* window ) = 0; // Picks up objects Qt created during QQuickRenderControl::initialize() // (e.g. VkDevice). virtual bool attachWindow( QQuickWindow* window, QString* error ) = 0; // Releases everything created on Qt's device; called before Qt destroys // it. virtual void detachWindow() = 0; // Human-readable GPU/driver description (valid after attachWindow). virtual QString deviceName() const = 0; // Bind the API context to the current thread (no-op for APIs without // one). virtual bool makeCurrent() = 0; virtual void doneCurrent() = 0; // (Re)allocates the shared color texture; returns the target for // QQuickWindow::setRenderTarget. virtual QQuickRenderTarget createRenderTarget( QSize size ) = 0; // Frees the texture. Called before Qt's device/context goes away. virtual void releaseRenderTarget() = 0; // Before Qt renders a frame / after QQuickRenderControl::endFrame(). // Backends put the texture into the state Qt resp. SteamVR expects // (layouts, flushes). virtual void beginFrame() = 0; virtual void finishFrame() = 0; // Blocks until the GPU has finished all submitted work (benchmarks: // makes the asynchronous OpenGL path comparable to the synchronous // Vulkan one). virtual void waitForGpu() = 0; // Texture description for IVROverlay::SetOverlayTexture. Only valid // while the render target exists; must be submitted with the context // current (see makeCurrent()). virtual vr::Texture_t vrTexture() = 0; // UV bounds for IVROverlay::SetOverlayTextureBounds (compensates // API-specific origin). virtual vr::VRTextureBounds_t vrTextureBounds() const = 0; // Reads the last finished frame back to the CPU (snapshots, tests). // Slow. virtual QImage readback() = 0; }; enum class GraphicsApi { OpenGL, Vulkan }; // Returns nullptr if the API was not compiled in (Vulkan is optional, see // OVRAS_HAS_VULKAN). std::unique_ptr createRenderBackend( GraphicsApi api ); // "opengl" / "vulkan" (case-insensitive). Returns false for unknown names. bool parseGraphicsApi( const QString& name, GraphicsApi* api );