QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GstD3DVideoBufferCommon.h
Go to the documentation of this file.
1#pragma once
2
3#include <QtCore/qglobal.h>
4
5#if defined(Q_OS_WIN) && (defined(QGC_HAS_GST_D3D11_GPU_PATH) || defined(QGC_HAS_GST_D3D12_GPU_PATH))
6
7#include <QtCore/QLoggingCategory>
8#include <QtCore/QSize>
9#include <QtMultimedia/QVideoFrame>
10#include <QtMultimedia/QVideoFrameFormat>
11#include <private/qhwvideobuffer_p.h>
12#include <private/qvideotexturehelper_p.h>
13#include <rhi/qrhi.h>
14
15#include <array>
16#include <atomic>
17#include <memory>
18
28namespace GstD3DVideoBufferCommon {
29
30constexpr int kMaxPlanes = 4;
31
34struct MapDiagnostics {
35 std::atomic<quint64> mapFailureCount{0};
36 std::atomic<bool> loggedFirstSuccess{false};
37 // One-shot log flags per failure reason — keeps CI logs informative without
38 // spamming at framerate. Each path warns the first time it trips, then bumps
39 // the counter silently; teardown emits the running total.
40 std::atomic<bool> loggedNullSample{false};
41 std::atomic<bool> loggedBadBackend{false};
42 std::atomic<bool> loggedNullBuffer{false};
43 std::atomic<bool> loggedNonD3DMemory{false};
44 std::atomic<bool> loggedNullResource{false};
45 std::atomic<bool> loggedTextureCreateFail{false};
46 // Tripped when GstD3DXMemory carries a device that doesn't match the bridge's shared
47 // device — sampling from another device's textures corrupts or crashes silently, so the
48 // wrapper rejects the frame instead. Indicates a NEED_CONTEXT race the bridge lost.
49 std::atomic<bool> loggedDeviceMismatch{false};
50};
51
52inline QVideoFrameTexturesUPtr fail(MapDiagnostics &d)
53{
54 d.mapFailureCount.fetch_add(1, std::memory_order_relaxed);
55 return {};
56}
57
58inline quint64 takeMapFailureCount(MapDiagnostics &d)
59{
60 return d.mapFailureCount.exchange(0, std::memory_order_relaxed);
61}
62
63inline quint64 peekMapFailureCount(MapDiagnostics &d)
64{
65 return d.mapFailureCount.load(std::memory_order_relaxed);
66}
67
71template<class HandleT>
72class FrameTextures final : public QVideoFrameTextures
73{
74public:
75 FrameTextures(QRhi *rhi, QSize size, QVideoFrameFormat::PixelFormat pixelFormat,
76 std::array<HandleT *, kMaxPlanes> handles, int count)
77 : _count(count)
78 , _handles(handles)
79 {
80 const auto *desc = QVideoTextureHelper::textureDescription(pixelFormat);
81 if (!desc) return;
82 for (int i = 0; i < _count; ++i) {
83 const QSize planeSize = desc->rhiPlaneSize(size, i, rhi);
84 _textures[i].reset(rhi->newTexture(desc->rhiTextureFormat(i, rhi), planeSize, 1, {}));
85 if (_textures[i] && !_textures[i]->createFrom({reinterpret_cast<quint64>(handles[i]), 0})) {
86 _textures[i].reset();
87 }
88 }
89 }
90
91 ~FrameTextures() override
92 {
93 for (int i = 0; i < _count; ++i) {
94 if (_handles[i]) _handles[i]->Release();
95 }
96 }
97
98 QRhiTexture *texture(uint plane) const override
99 {
100 return (int(plane) < _count) ? _textures[plane].get() : nullptr;
101 }
102
103private:
104 int _count = 0;
105 std::array<HandleT *, kMaxPlanes> _handles;
106 std::unique_ptr<QRhiTexture> _textures[kMaxPlanes];
107};
108
109} // namespace GstD3DVideoBufferCommon
110
113#define QGC_D3D_WARN_ONCE(LOGCAT, FLAG, ...) \
114 do { \
115 if (!(FLAG).exchange(true, std::memory_order_relaxed)) { \
116 qCWarning(LOGCAT) << __VA_ARGS__; \
117 } \
118 } while (0)
119
120#endif // Q_OS_WIN && (QGC_HAS_GST_D3D11_GPU_PATH || QGC_HAS_GST_D3D12_GPU_PATH)