QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GstContextBridgeRegistry.cc
Go to the documentation of this file.
3
4#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH) || defined(QGC_HAS_GST_D3D11_GPU_PATH) || defined(QGC_HAS_GST_D3D12_GPU_PATH)
5
6#include <array>
7#include <atomic>
8#include <mutex>
9
10QGC_LOGGING_CATEGORY(GstContextBridgeRegistryLog, "Video.GStreamer.HwBuffers.GstContextBridgeRegistry")
11
12namespace GstContextBridgeRegistry {
13
14namespace {
15
16constexpr int kMaxHandlers = 8;
17// Atomic entries close the write-after-read hazard: dispatch loads each slot with acquire
18// ordering, paired with the release store in registerBridgeHandler.
19std::array<std::atomic<BridgeHandler>, kMaxHandlers> s_handlers{};
20std::atomic<int> s_count{0};
21std::array<std::atomic<ResetCallback>, kMaxHandlers> s_resets{};
22std::atomic<int> s_resetCount{0};
23std::mutex s_registerMutex;
24
25} // namespace
26
27void registerBridgeHandler(BridgeHandler handler)
28{
29 if (!handler) return;
30 std::lock_guard<std::mutex> lock(s_registerMutex);
31 const int slot = s_count.load(std::memory_order_relaxed);
32 if (slot >= kMaxHandlers) {
33 qCWarning(GstContextBridgeRegistryLog)
34 << "Bridge handler limit (" << kMaxHandlers << ") exceeded — dropping registration";
35 return;
36 }
37 // Store handler before publishing the new count so dispatchBridges can't observe a count
38 // that includes a slot whose handler write isn't yet visible.
39 s_handlers[slot].store(handler, std::memory_order_release);
40 s_count.store(slot + 1, std::memory_order_release);
41}
42
43// Handlers run in registration (link) order; first GST_BUS_DROP wins. Bridges must mutually
44// exclude on context-type so order doesn't shadow another bridge's intended handoff.
45GstBusSyncReply dispatchBridges(GstMessage *message)
46{
47 const int count = s_count.load(std::memory_order_acquire);
48 for (int i = 0; i < count && i < kMaxHandlers; ++i) {
49 BridgeHandler h = s_handlers[i].load(std::memory_order_acquire);
50 if (h && h(message) == GST_BUS_DROP) {
51 return GST_BUS_DROP;
52 }
53 }
54 return GST_BUS_PASS;
55}
56
57void registerResetCallback(ResetCallback callback)
58{
59 if (!callback) return;
60 std::lock_guard<std::mutex> lock(s_registerMutex);
61 const int slot = s_resetCount.load(std::memory_order_relaxed);
62 if (slot >= kMaxHandlers) {
63 qCWarning(GstContextBridgeRegistryLog)
64 << "Reset callback limit (" << kMaxHandlers << ") exceeded — dropping registration";
65 return;
66 }
67 s_resets[slot].store(callback, std::memory_order_release);
68 s_resetCount.store(slot + 1, std::memory_order_release);
69}
70
71void resetAllBridges()
72{
73 const int count = s_resetCount.load(std::memory_order_acquire);
74 for (int i = 0; i < count && i < kMaxHandlers; ++i) {
75 ResetCallback cb = s_resets[i].load(std::memory_order_acquire);
76 if (cb) cb();
77 }
78}
79
80#ifdef QT_TESTLIB_LIB
81void clearForTest()
82{
83 // Drop cached device/context state in every bridge first; otherwise a test that primes
84 // a bridge then re-registers via registerBridgeHandler would observe stale s_primed=true.
85 // Done before mutex acquisition because each bridge takes its own lock.
86 resetAllBridges();
87 std::lock_guard<std::mutex> lock(s_registerMutex);
88 // Zero count before the slot stores so a concurrent dispatchBridges can't read a slot
89 // we've already nulled while count is still high. Pairs with the count-after-slot store
90 // ordering in registerBridgeHandler.
91 s_count.store(0, std::memory_order_release);
92 s_resetCount.store(0, std::memory_order_release);
93 for (auto &slot : s_handlers) slot.store(nullptr, std::memory_order_release);
94 for (auto &slot : s_resets) slot.store(nullptr, std::memory_order_release);
95}
96#endif
97
98} // namespace GstContextBridgeRegistry
99
100#endif // QGC_HAS_GST_GLMEMORY_GPU_PATH || QGC_HAS_GST_D3D11_GPU_PATH || QGC_HAS_GST_D3D12_GPU_PATH
#define QGC_LOGGING_CATEGORY(name, categoryStr)