1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qrhivaluemapper_p.h"
5
6#include <qmutex.h>
7#include <rhi/qrhi.h>
8#include <q20vector.h>
9
10#include <vector>
11
12QT_BEGIN_NAMESPACE
13
14// ensures thread-safe access to rhi cleanup handlers
15class QRhiCallback::Manager : public std::enable_shared_from_this<Manager>
16{
17 using CallbackList = std::vector<std::weak_ptr<QRhiCallback>>;
18 struct CallbacksItem
19 {
20 CallbackList callbacks;
21 size_t lastValidCallbackCount = 1u;
22
23 void addCallback(const std::weak_ptr<QRhiCallback> &cb)
24 {
25 Q_ASSERT(!cb.expired());
26
27 // check periodically to ensure avg O(1)
28 if (callbacks.size() > lastValidCallbackCount * 2) {
29 q20::erase_if(c&: callbacks, pred: [](const auto &cb) {
30 return cb.expired();
31 });
32 lastValidCallbackCount = callbacks.size() + 1;
33 }
34
35 callbacks.push_back(x: cb);
36 }
37 };
38
39public:
40 void registerCallback(QRhi &rhi, const std::weak_ptr<QRhiCallback> &cb)
41 {
42 QMutexLocker locker(&m_mutex);
43 auto [rhiIt, added] = m_rhiToCallbackItems.try_emplace(k: &rhi, args: CallbacksItem{});
44 if (added)
45 rhi.addCleanupCallback(callback: [instance = shared_from_this()](QRhi *rhi) {
46 for (auto &weakCb : instance->extractCallbacks(rhi))
47 if (auto cb = weakCb.lock())
48 cb->onRhiCleanup(rhi&: *rhi); // run outside the global mutex
49 });
50
51 rhiIt->second.addCallback(cb);
52 }
53
54private:
55 CallbackList extractCallbacks(QRhi *rhi)
56 {
57 QMutexLocker locker(&m_mutex);
58 auto it = m_rhiToCallbackItems.find(x: rhi);
59 Q_ASSERT(it != m_rhiToCallbackItems.end());
60
61 CallbackList result = std::move(it->second.callbacks);
62 m_rhiToCallbackItems.erase(position: it);
63 return result;
64 }
65
66private:
67 std::unordered_map<QRhi *, CallbacksItem> m_rhiToCallbackItems;
68 QBasicMutex m_mutex;
69};
70
71Q_GLOBAL_STATIC(std::shared_ptr<QRhiCallback::Manager>, rhiCallbacksStorage,
72 std::make_shared<QRhiCallback::Manager>());
73
74QRhiCallback::QRhiCallback() : m_manager(*rhiCallbacksStorage) { }
75
76QRhiCallback::~QRhiCallback() = default; // must be out-of-line
77
78void QRhiCallback::registerCallback(QRhi &rhi)
79{
80 m_manager->registerCallback(rhi, cb: weak_from_this());
81}
82
83QT_END_NAMESPACE
84

source code of qtmultimedia/src/multimedia/qrhivaluemapper.cpp