3#include <QtGui/qtguiglobal.h>
8#if defined(QGC_HAS_GST_VULKAN_GPU_PATH) && QT_CONFIG(vulkan)
10#include <QtCore/QLoggingCategory>
11#include <QtCore/QMutex>
12#include <QtCore/QMutexLocker>
14#include <vulkan/vulkan.h>
17#pragma push_macro("slots")
23#include <gst/vulkan/gstvkdevice.h>
24#include <gst/vulkan/gstvkimagememory.h>
25#include <gst/vulkan/gstvkinstance.h>
26#include <gst/vulkan/gstvkphysicaldevice.h>
27#include <gst/vulkan/gstvkqueue.h>
29#pragma pop_macro("slots")
36namespace GstVulkanContextBridge {
41GstVulkanDevice* s_device =
nullptr;
42GstVulkanQueue* s_queue =
nullptr;
43GstBridgePrimeRetry::PrimeRetryState s_retry;
50 VkPhysicalDevice physDev = VK_NULL_HANDLE;
51 quint32 queueFamilyIdx = 0;
55bool readSnapshotHandles(SnapshotHandles& out)
59 if (snap.backend.load(std::memory_order_acquire) !=
static_cast<int>(QRhi::Vulkan)) {
62 out.physDev =
static_cast<VkPhysicalDevice
>(snap.vkPhysicalDevice.load(std::memory_order_acquire));
63 out.queueFamilyIdx = snap.vkQueueFamilyIdx.load(std::memory_order_acquire);
64 out.queueIdx = snap.vkQueueIdx.load(std::memory_order_acquire);
65 return out.physDev != VK_NULL_HANDLE;
72GstVulkanPhysicalDevice* matchPhysicalDevice(GstVulkanInstance* instance, VkPhysicalDevice want)
74 const guint n = instance->n_physical_devices;
75 for (guint i = 0; i < n; ++i) {
76 GstVulkanPhysicalDevice* phys = gst_vulkan_physical_device_new(instance, i);
80 if (phys->device == want) {
83 gst_object_unref(phys);
90 switch (GstBridgePrimeRetry::primeRetryGuard(s_retry)) {
91 case GstBridgePrimeRetry::Decision::AlreadyPrimed:
93 case GstBridgePrimeRetry::Decision::GiveUp:
95 case GstBridgePrimeRetry::Decision::ShouldRetry:
100 if (!readSnapshotHandles(nh)) {
102 if (!GstBridgePrimeRetry::rearmRetry(s_retry) && GstBridgePrimeRetry::justGaveUp(s_retry)) {
103 qCInfo(GstVulkanBridgeLog) <<
"active RHI is not Vulkan after" << s_retry.maxRetries
104 <<
"retries; Vulkan bridge inactive";
109 auto bail = [](
const char* what) ->
bool {
110 qCWarning(GstVulkanBridgeLog) <<
"Vulkan bridge prime failed:" << what;
111 gst_clear_object(&s_queue);
112 gst_clear_object(&s_device);
114 s_retry.primeAttempted =
false;
120 return bail(
"gst_vulkan_instance_open");
123 GstVulkanPhysicalDevice* phys = matchPhysicalDevice(
s_instance, nh.physDev);
125 return bail(
"no GstVulkanPhysicalDevice matches QRhi physDev");
127 s_device = gst_vulkan_device_new(phys);
128 gst_object_unref(phys);
129 if (!s_device || !gst_vulkan_device_open(s_device,
nullptr)) {
130 return bail(
"gst_vulkan_device_open");
132 s_queue = gst_vulkan_device_get_queue(s_device, nh.queueFamilyIdx, nh.queueIdx);
134 return bail(
"gst_vulkan_device_get_queue");
137 s_retry.primed =
true;
140 qCInfo(GstVulkanBridgeLog) <<
"Vulkan bridge primed on QRhi physical device — note: gst VkDevice differs from "
141 "QRhi VkDevice, so import falls back to CPU until same-device wrapping is available";
145GstVulkanInstance* refInstance()
150GstVulkanDevice* refDevice()
152 return s_device ? GST_VULKAN_DEVICE(gst_object_ref(s_device)) : nullptr;
155GstVulkanQueue* refQueue()
157 return s_queue ? GST_VULKAN_QUEUE(gst_object_ref(s_queue)) : nullptr;
164const char*
const kContextTypes[] = {
165 GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR,
166 GST_VULKAN_DEVICE_CONTEXT_TYPE_STR,
167 GST_VULKAN_QUEUE_CONTEXT_TYPE_STR,
170const QLoggingCategory& vtCat(
void*)
172 return GstVulkanBridgeLog();
175QMutex& vtMutex(
void*)
182 return primeLocked();
185GstObject* vtRefObject(
void*,
const char* contextType)
187 if (g_strcmp0(contextType, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) {
188 return GST_OBJECT(refInstance());
190 if (g_strcmp0(contextType, GST_VULKAN_DEVICE_CONTEXT_TYPE_STR) == 0) {
191 return GST_OBJECT(refDevice());
193 return GST_OBJECT(refQueue());
196GstContext* vtBuildContext(
void*,
const char* contextType, GstObject*
object)
198 if (g_strcmp0(contextType, GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR) == 0) {
199 GstContext* ctx = gst_context_new(GST_VULKAN_INSTANCE_CONTEXT_TYPE_STR, TRUE);
200 gst_context_set_vulkan_instance(ctx, GST_VULKAN_INSTANCE(
object));
203 if (g_strcmp0(contextType, GST_VULKAN_DEVICE_CONTEXT_TYPE_STR) == 0) {
204 GstContext* ctx = gst_context_new(GST_VULKAN_DEVICE_CONTEXT_TYPE_STR, TRUE);
205 gst_context_set_vulkan_device(ctx, GST_VULKAN_DEVICE(
object));
208 GstContext* ctx = gst_context_new(GST_VULKAN_QUEUE_CONTEXT_TYPE_STR, TRUE);
209 gst_context_set_vulkan_queue(ctx, GST_VULKAN_QUEUE(
object));
213const GstContextBridge::BridgeVTable s_vtable = {
214 "Vulkan", kContextTypes, 3, &vtCat, &vtMutex, &vtPrime, &vtRefObject, &vtBuildContext,
nullptr,
221 QMutexLocker lock(&s_mutex);
222 return primeLocked();
225GstBusSyncReply handleSyncMessage(GstMessage* message)
227 return GstContextBridge::handleSyncMessage(s_vtable,
nullptr, message);
230bool answerContextQuery(GstQuery* query)
232 return GstContextBridge::answerContextQuery(s_vtable,
nullptr, query);
237 QMutexLocker lock(&s_mutex);
238 gst_clear_object(&s_queue);
239 gst_clear_object(&s_device);
241 GstBridgePrimeRetry::resetRetry(s_retry);
242 qCDebug(GstVulkanBridgeLog) <<
"Vulkan bridge reset";
247 QMutexLocker lock(&s_mutex);
248 GstBridgePrimeRetry::rearmAfterExhaustion(s_retry);
252struct VulkanBridgeRegistrar
254 VulkanBridgeRegistrar()
256 GstContextBridge::registerBridge(GstVulkanBridgeLog(),
"Vulkan", &GstVulkanContextBridge::handleSyncMessage,
257 &GstVulkanContextBridge::reset);
261static VulkanBridgeRegistrar s_vulkanBridgeRegistrar;
static std::atomic< LogManager * > s_instance
#define QGC_LOGGING_CATEGORY(name, categoryStr)
DeviceSnapshot & deviceSnapshot() noexcept
Returns the global snapshot. Atomic fields make individual reads thread-safe.