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>
93 lines
3.5 KiB
C++
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;
|
|
};
|