Files
FrameAssistant/src/render/VulkanRenderBackend.h
T
matzmanandClaude Opus 5.5 4a5b09053e Initial FrameAssistant baseline from the vrdashboard template
Template stripped to the overlay platform (examples, demo UI and Frame
test package removed), renamed to FrameAssistant, and working rules for
the project recorded in CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:06:58 +02:00

93 lines
3.5 KiB
C++

#pragma once
#include <QVulkanInstance>
#include "RenderBackend.h"
// Vulkan implementation. Qt Quick creates the VkDevice (on the physical device
// SteamVR reports for the HMD, with the device extensions SteamVR requires);
// this backend owns the color image Qt renders into and handles the layout
// dance SteamVR needs:
//
// Qt renders -> image in COLOR_ATTACHMENT_OPTIMAL
// finishFrame() -> transition to TRANSFER_SRC_OPTIMAL (required by
// OpenVR);
// the CPU waits for it, the texture is handed over
// right after
// SetOverlayTexture -> SteamVR copies from the image using our queue
// beginFrame() (next) -> transition back to COLOR_ATTACHMENT_OPTIMAL, the
// layout Qt's
// resource tracking expects; no CPU wait: queue order
// puts it before Qt's frame
//
// Everything runs on the GUI thread; QQuickRenderControl::endFrame() waits for
// the GPU (offscreen frames are synchronous).
class VulkanRenderBackend final : public RenderBackend {
public:
VulkanRenderBackend() = default;
~VulkanRenderBackend() override;
QString name() const override { return QStringLiteral("Vulkan"); }
QSGRendererInterface::GraphicsApi graphicsApi() const override {
return QSGRendererInterface::Vulkan;
}
bool initialize(const RenderInterop& interop, QString* error) override;
void configureWindow(QQuickWindow* window) override;
bool attachWindow(QQuickWindow* window, QString* error) override;
void detachWindow() override;
QString deviceName() const override { return m_deviceName; }
bool makeCurrent() override { return true; }
void doneCurrent() override {}
QQuickRenderTarget createRenderTarget(QSize size) override;
void releaseRenderTarget() override;
void beginFrame() override;
void finishFrame() override;
void waitForGpu() override;
vr::Texture_t vrTexture() override;
vr::VRTextureBounds_t vrTextureBounds() const override;
QImage readback() override;
private:
bool findMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties,
uint32_t* index) const;
// A command buffer with its fence, for small submissions of our own.
struct Submission {
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VkFence fence = VK_NULL_HANDLE;
bool pending = false;
};
// Records `record` into the submission's command buffer (after its
// previous use has finished) and submits it; with `wait`, blocks until
// the GPU has executed it.
bool submit(Submission& submission,
const std::function<void(VkCommandBuffer)>& record, bool wait);
bool waitFor(Submission& submission);
void transitionImage(Submission& submission, VkImageLayout from,
VkImageLayout to, bool wait);
QVulkanInstance m_instance;
QByteArrayList m_deviceExtensions;
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE;
VkQueue m_queue = VK_NULL_HANDLE;
uint32_t m_queueFamilyIndex = 0;
QVulkanDeviceFunctions* m_df = nullptr;
VkCommandPool m_commandPool = VK_NULL_HANDLE;
Submission m_restore; // beginFrame(): async
Submission m_handoff; // finishFrame() and readback(): synchronous
VkImage m_image = VK_NULL_HANDLE;
VkDeviceMemory m_imageMemory = VK_NULL_HANDLE;
// Actual layout outside of Qt's frame
VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
QSize m_size;
vr::VRVulkanTextureData_t m_vrTextureData{};
QString m_deviceName;
};