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

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