3#include <QtCore/qglobal.h>
5#if defined(Q_OS_WIN) && (defined(QGC_HAS_GST_D3D11_GPU_PATH) || defined(QGC_HAS_GST_D3D12_GPU_PATH))
7#include <QtCore/QLoggingCategory>
9#include <QtMultimedia/QVideoFrame>
10#include <QtMultimedia/QVideoFrameFormat>
17#include <private/qhwvideobuffer_p.h>
18#include <private/qvideotexturehelper_p.h>
28namespace GstD3DVideoBufferCommon {
32inline bool canAliasSingleResourceAcrossPlanes(QVideoFrameFormat::PixelFormat pixelFormat)
noexcept
34 switch (pixelFormat) {
35 case QVideoFrameFormat::Format_NV12:
36 case QVideoFrameFormat::Format_NV21:
37 case QVideoFrameFormat::Format_P010:
38 case QVideoFrameFormat::Format_P016:
49 std::atomic<bool> loggedNonD3DMemory{
false};
50 std::atomic<bool> loggedNullResource{
false};
53 std::atomic<bool> loggedDeviceMismatch{
false};
58 loggedFirstSuccess.store(
false, std::memory_order_release);
59 loggedNullSample.store(
false, std::memory_order_release);
60 loggedBadBackend.store(
false, std::memory_order_release);
61 loggedNullBuffer.store(
false, std::memory_order_release);
62 loggedTextureCreateFail.store(
false, std::memory_order_release);
63 loggedNonD3DMemory.store(
false, std::memory_order_release);
64 loggedNullResource.store(
false, std::memory_order_release);
65 loggedDeviceMismatch.store(
false, std::memory_order_release);
78 bool operator<(
const StagingKey& o)
const
80 return std::tie(width, height, format, plane) < std::tie(o.width, o.height, o.format, o.plane);
83 bool operator==(
const StagingKey& o)
const noexcept =
default;
88 std::size_t operator()(
const StagingKey& key)
const noexcept
90 std::size_t seed = std::hash<quint64>{}(key.width);
91 seed ^= std::hash<quint32>{}(key.height) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
92 seed ^= std::hash<quint32>{}(key.format) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
93 seed ^= std::hash<int>{}(key.plane) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
100template <
class HandleT>
101struct PlaneResourceGuard
103 std::array<HandleT*, kMaxPlanes> handles{};
106 ~PlaneResourceGuard()
108 for (
int j = 0; j < owned; ++j) {
110 handles[j]->Release();
116 void commit() noexcept { owned = 0; }
121template <
class HandleT>
125 FrameTextures(
HwVideoBufferPath path, QRhi* rhi, QSize size, QVideoFrameFormat::PixelFormat pixelFormat,
126 std::array<HandleT*, kMaxPlanes> handles,
int count)
127 : _handles(handles), _path(path), _rhi(rhi), _size(size), _pixelFormat(pixelFormat)
130 const auto* desc = QVideoTextureHelper::textureDescription(pixelFormat);
133 for (
int i = 0; i < _count; ++i) {
134 const QSize planeSize = desc->rhiPlaneSize(size, i, rhi);
135 _textures[i].reset(rhi->newTexture(desc->rhiTextureFormat(i, rhi), planeSize, 1, {}));
136 if (_textures[i] && !_textures[i]->createFrom({
reinterpret_cast<quint64
>(handles[i]), 0})) {
137 _textures[i].reset();
142 ~FrameTextures()
override
144 for (
int i = 0; i < _count; ++i) {
146 _handles[i]->Release();
154 bool matches(QRhi* rhi, QSize size, QVideoFrameFormat::PixelFormat pixelFormat,
155 const std::array<HandleT*, kMaxPlanes>& handles,
int count)
const
157 if (_rhi != rhi || _size != size || _pixelFormat != pixelFormat || _count != count) {
160 for (
int i = 0; i < _count; ++i) {
161 if (!_handles[i] || _handles[i] != handles[i] || !_textures[i]) {
169 std::array<HandleT*, kMaxPlanes> _handles;
171 QRhi* _rhi =
nullptr;
173 QVideoFrameFormat::PixelFormat _pixelFormat = QVideoFrameFormat::Format_Invalid;
181template <
class HandleT,
class CatFn>
182QVideoFrameTexturesUPtr mapResolvedTextures(
GstHwVideoBuffer& self, QRhi& rhi, QVideoFrameTexturesUPtr& old,
184 const std::array<HandleT*, kMaxPlanes>& resolvedHandles,
int resolvedCount,
185 QSize frameSize, QVideoFrameFormat::PixelFormat pixelFormat,
186 std::atomic<bool>& loggedFirstSuccess,
187 std::atomic<bool>& loggedTextureCreateFail, CatFn catFn,
const char* tag)
189 using BundleT = FrameTextures<HandleT>;
191 const auto* desc = QVideoTextureHelper::textureDescription(pixelFormat);
192 if (!desc || desc->nplanes <= 0) {
193 return GstHwPathTelemetry::fail(path);
196 const int textureCount = (std::min)(desc->nplanes, kMaxPlanes);
197 if (resolvedCount <= 0 || resolvedCount > kMaxPlanes) {
198 return GstHwPathTelemetry::fail(path);
201 std::array<HandleT*, kMaxPlanes> handles{};
202 for (
int i = 0; i < (std::min)(resolvedCount, textureCount); ++i) {
203 handles[i] = resolvedHandles[i];
206 if (resolvedCount < textureCount) {
207 if (resolvedCount != 1 || !handles[0] || !canAliasSingleResourceAcrossPlanes(pixelFormat)) {
208 return GstHwPathTelemetry::fail(path);
211 for (
int i = resolvedCount; i < textureCount; ++i) {
212 handles[i] = handles[0];
216 if (
auto* prev = GstHwFrameTexturesBase::reusableBundle<BundleT>(old, path)) {
217 if (prev->matches(&rhi, frameSize, pixelFormat, handles, textureCount)) {
220 QVideoFrameTexturesUPtr reused = std::move(old);
226 if (!GstHwImportPreflight::preflightOrRecord(&rhi, path, pixelFormat, frameSize)) {
227 return GstHwPathTelemetry::fail(path);
231 for (
int i = 0; i < textureCount; ++i) {
233 handles[i]->AddRef();
236 auto textures = std::make_unique<BundleT>(path, &rhi, frameSize, pixelFormat, handles, textureCount);
238 for (
int i = 0; i < textureCount; ++i) {
239 if (!textures->texture(
static_cast<uint
>(i))) {
241 "mapTextures: QRhiTexture::createFrom failed plane="
242 << i <<
" (size=" << frameSize <<
" format=" <<
int(pixelFormat)
243 <<
" planes=" << textureCount <<
")");
244 return GstHwPathTelemetry::fail(path);
HwVideoBufferPath
Identifies which GPU path was chosen; used by the adapter to increment the right counter.
#define QGC_HW_WARN_ONCE(LOGCAT, FLAG,...)
Logs once via qCWarning(LOGCAT) the first time FLAG flips true; subsequent trips are silent.
Common base for per-platform FrameTextures : QVideoFrameTextures from *VideoBuffer::mapTextures().
Common base for GStreamer-backed QHwVideoBuffer subclasses.
GstSample * takeSample() noexcept
Transfers GstSample ownership out for early pool-slot release in mapTextures.
static void logFirstSuccess(std::atomic< bool > &flag, const QLoggingCategory &cat, const char *tag, QSize frameSize, QVideoFrameFormat::PixelFormat pixelFormat, int planes)
One-shot "first zero-copy success" info line; silent after flag first flips.
void recordTextureReuse(HwVideoBufferPath path) noexcept
Prior frame's QRhiTexture wrappers reused (decoder pool returned same native handle).
constexpr int kMaxPlanes
Matches GST_VIDEO_MAX_PLANES (gst-video pins it at 4); single source of truth for every per-platform ...
One-shot warning flags per failure cause; paths with extra causes (D3D, IOSurface) derive and add mem...