Revision control

Copy as Markdown

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhivaluemapper_p.h"
#include <qmutex.h>
#include <rhi/qrhi.h>
#include <q20vector.h>
#include <vector>
QT_BEGIN_NAMESPACE
// ensures thread-safe access to rhi cleanup handlers
class QRhiCallback::Manager : public std::enable_shared_from_this<Manager>
{
using CallbackList = std::vector<std::weak_ptr<QRhiCallback>>;
struct CallbacksItem
{
CallbackList callbacks;
size_t lastValidCallbackCount = 1u;
void addCallback(const std::weak_ptr<QRhiCallback> &cb)
{
Q_ASSERT(!cb.expired());
// check periodically to ensure avg O(1)
if (callbacks.size() > lastValidCallbackCount * 2) {
q20::erase_if(callbacks, [](const auto &cb) {
return cb.expired();
});
lastValidCallbackCount = callbacks.size() + 1;
}
callbacks.push_back(cb);
}
};
public:
void registerCallback(QRhi &rhi, const std::weak_ptr<QRhiCallback> &cb)
{
QMutexLocker locker(&m_mutex);
auto [rhiIt, added] = m_rhiToCallbackItems.try_emplace(&rhi, CallbacksItem{});
if (added)
rhi.addCleanupCallback([instance = shared_from_this()](QRhi *rhi) {
for (auto &weakCb : instance->extractCallbacks(rhi))
if (auto cb = weakCb.lock())
cb->onRhiCleanup(*rhi); // run outside the global mutex
});
rhiIt->second.addCallback(cb);
}
private:
CallbackList extractCallbacks(QRhi *rhi)
{
QMutexLocker locker(&m_mutex);
auto it = m_rhiToCallbackItems.find(rhi);
Q_ASSERT(it != m_rhiToCallbackItems.end());
CallbackList result = std::move(it->second.callbacks);
m_rhiToCallbackItems.erase(it);
return result;
}
private:
std::unordered_map<QRhi *, CallbacksItem> m_rhiToCallbackItems;
QBasicMutex m_mutex;
};
Q_GLOBAL_STATIC(std::shared_ptr<QRhiCallback::Manager>, rhiCallbacksStorage,
std::make_shared<QRhiCallback::Manager>());
QRhiCallback::QRhiCallback() : m_manager(*rhiCallbacksStorage) { }
QRhiCallback::~QRhiCallback() = default; // must be out-of-line
void QRhiCallback::registerCallback(QRhi &rhi)
{
m_manager->registerCallback(rhi, weak_from_this());
}
QT_END_NAMESPACE