7#include <QtCore/QLockFile>
8#include <QtCore/QSaveFile>
9#include <QtCore/QCryptographicHash>
14QQsbCollection::~QQsbCollection()
18QDataStream &operator<<(QDataStream &stream,
const QQsbCollection::Entry &entry)
20 return (stream << entry.key << entry.value);
23QDataStream &
operator>>(QDataStream &stream, QQsbCollection::Entry &entry)
27 stream >> key >> value;
28 entry = QQsbCollection::Entry(key, value);
37bool operator==(
const QQsbCollection::Entry &l,
const QQsbCollection::Entry &r)
39 return (l.key == r.key);
42QDataStream &operator<<(QDataStream &stream,
const QQsbCollection::EntryDesc &entryDesc)
44 return (stream << entryDesc.materialKey
45 << entryDesc.featureSet
46 << entryDesc.vertShader.serialized()
47 << entryDesc.fragShader.serialized());
50QDataStream &
operator>>(QDataStream &stream, QQsbCollection::EntryDesc &entryDesc)
53 QQsbCollection::FeatureSet fs;
56 stream >> desc >> fs >> vertData >> fragData;
57 entryDesc.materialKey = desc;
58 entryDesc.featureSet = fs;
59 entryDesc.vertShader = QShader::fromSerialized(vertData);
60 entryDesc.fragShader = QShader::fromSerialized(fragData);
65static constexpr qint64 HeaderSize =
sizeof(qint64 ) +
sizeof(quint8 ) +
sizeof(quint32 ) +
sizeof(MagicaDS);
66static constexpr quint32 QtVersion = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
68bool QQsbCollection::readEndHeader(QDataStream &ds, qint64 *startPos, quint8 *version)
72 ds >> *startPos >> *version >> qtver >> fileId;
73 if (fileId != MagicaDS) {
74 qWarning(
"Corrupt qsbc file");
77 if (*version != Version::Two) {
78 qWarning(
"qsbc file has an unsupported version");
81 if (qtver != QtVersion) {
82 qWarning(
"qsbc file is for a different Qt version");
88bool QQsbCollection::readEndHeader(QIODevice *device, EntryMap *entries, quint8 *version)
91 const qint64 size = device->size();
92 if (device->seek(size - HeaderSize)) {
93 QDataStream ds(device);
94 ds.setVersion(QDataStream::Qt_6_0);
96 if (readEndHeader(ds, &startPos, version)) {
97 if (startPos >= 0 && startPos < size && device->seek(startPos)) {
106void QQsbCollection::writeEndHeader(QDataStream &ds, qint64 startPos, quint8 version, quint64 magic)
108 ds << startPos << version << QtVersion << magic;
111void QQsbCollection::writeEndHeader(QIODevice *device,
const EntryMap &entries)
113 if (!device->atEnd()) {
114 device->seek(device->size() - 1);
115 Q_ASSERT(device->atEnd());
117 QDataStream ds(device);
118 ds.setVersion(QDataStream::Qt_6_0);
119 const qint64 startPos = device->pos();
121 writeEndHeader(ds, startPos, quint8(Version::Two), MagicaDS);
124QByteArray QQsbCollection::EntryDesc::generateSha(
const QByteArray &materialKey,
const FeatureSet &featureSet)
126 QCryptographicHash h(QCryptographicHash::Algorithm::Sha1);
127 h.addData(materialKey);
128 for (
auto it = featureSet.cbegin(), end = featureSet.cend(); it != end; ++it) {
132 return h.result().toHex();
135QByteArray QQsbCollection::EntryDesc::generateSha()
const
137 return generateSha(materialKey, featureSet);
140QQsbCollection::EntryMap QQsbInMemoryCollection::availableEntries()
const
142 return EntryMap(entries.keyBegin(), entries.keyEnd());
145QQsbCollection::Entry QQsbInMemoryCollection::addEntry(
const QByteArray &key,
const EntryDesc &entryDesc)
148 if (!entries.contains(e)) {
149 entries.insert(e, entryDesc);
155bool QQsbInMemoryCollection::extractEntry(Entry entry, EntryDesc &entryDesc)
157 auto it = entries.constFind(entry);
158 if (it != entries.constEnd()) {
165void QQsbInMemoryCollection::clear()
172 return name + QLatin1String(
".lck");
175bool QQsbInMemoryCollection::load(
const QString &filename)
177 QLockFile lock(lockFileName(filename));
179 qWarning(
"Could not create shader cache lock file '%s'",
180 qPrintable(lock.fileName()));
185 if (!f.open(QIODevice::ReadOnly)) {
186 qWarning(
"Failed to open qsbc file %s", qPrintable(filename));
192 if (!readEndHeader(&f, &entryMap, &version)) {
193 qWarning(
"Ignoring qsbc file %s", qPrintable(filename));
198 const qint64 size = f.size();
202 for (
const Entry &e : entryMap) {
203 const qint64 offset = e.value;
204 if (e.isValid() && offset >= 0 && size > offset && f.seek(offset)) {
206 ds.setVersion(QDataStream::Qt_6_0);
209 entries.insert(Entry(e.key), entryDesc);
216bool QQsbInMemoryCollection::save(
const QString &filename)
218 QLockFile lock(lockFileName(filename));
220 qWarning(
"Could not create shader cache lock file '%s'",
221 qPrintable(lock.fileName()));
225#if QT_CONFIG(temporaryfile)
226 QSaveFile f(filename);
230 if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
231 qWarning(
"Failed to write qsbc file %s", qPrintable(filename));
236 ds.setVersion(QDataStream::Qt_6_0);
239 for (
auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
240 const qint64 offset = f.pos();
242 entryMap.insert(Entry(it.key().key, offset));
245 writeEndHeader(&f, entryMap);
247#if QT_CONFIG(temporaryfile)
254QQsbIODeviceCollection::QQsbIODeviceCollection(
const QString &filePath)
260QQsbIODeviceCollection::QQsbIODeviceCollection(QIODevice &dev)
262 , devOwner(DeviceOwner::Extern)
267QQsbIODeviceCollection::~QQsbIODeviceCollection()
269 if (!entries.isEmpty() || device.isOpen())
273bool QQsbIODeviceCollection::map(MapMode mode)
275 if (device.isOpen()) {
277 if ((device.openMode() & QIODevice::WriteOnly) != 0) {
278 if ((device.openMode() & QIODevice::Truncate) == 0) {
279 qWarning(
"Open mode needs to have Truncate set for writing!");
282 if ((device.openMode() & QIODevice::Text) != 0) {
283 qWarning(
"Open mode can't have Text mode set!");
287 }
else if (!device.open(QIODevice::OpenMode(mode))) {
288 qWarning(
"Unable to open device!");
295 Q_ASSERT(mode == Read);
297 const bool ret = readEndHeader(&device, &entries, &version);
305void QQsbIODeviceCollection::unmap()
307 if (device.isOpen() && ((device.openMode() & Write) == Write)) {
308 if (!entries.isEmpty()) {
309 writeEndHeader(&device, entries);
311 if (devOwner == DeviceOwner::Self)
319QQsbCollection::EntryMap QQsbIODeviceCollection::availableEntries()
const
324QQsbCollection::Entry QQsbIODeviceCollection::addEntry(
const QByteArray &key,
const EntryDesc &entryDesc)
326 if (entries.contains(Entry(key)) || !map(MapMode::Write))
329 QDataStream ds(&device);
330 ds.setVersion(QDataStream::Qt_6_0);
331 const auto offset = device.pos();
333 Entry e(key, offset);
338bool QQsbIODeviceCollection::extractEntry(Entry entry, EntryDesc &entryDesc)
340 if (device.isOpen() && device.isReadable()) {
341 const qint64 offset = entry.value;
342 if (entry.isValid() && offset >= 0) {
343 const qint64 size = device.size();
344 if (size > offset && device.seek(offset)) {
345 QDataStream ds(&device);
346 ds.setVersion(QDataStream::Qt_6_0);
351 qWarning(
"Entry not found id(%s), offset(%lld)", entry.key.constData(), entry.value);
354 qWarning(
"Unable to open file for reading");
360static const char *
borderText() {
return "--------------------------------------------------------------------------------"; }
362void QQsbIODeviceCollection::dumpInfo()
364 if (map(QQsbIODeviceCollection::Read)) {
365 qDebug(
"Number of entries in collection: %zu\n", size_t(entries.size()));
367 qDebug(
"Qsbc version: %u", version);
368 for (
const auto &e : std::as_const(entries)) {
372 "Offset: %llu", borderText(), i++, borderText(), e.key.constData(), e.value);
374 QQsbCollection::EntryDesc ed;
375 if (extractEntry(e, ed)) {
376 qDebug() << ed.materialKey << Qt::endl
377 << ed.featureSet << Qt::endl
378 << ed.vertShader << Qt::endl
381 qWarning(
"Extracting Qsb entry failed!");
388void QQsbIODeviceCollection::dumpInfo(
const QString &file)
390 QQsbIODeviceCollection qsbc(file);
394void QQsbIODeviceCollection::dumpInfo(QIODevice &device)
396 QQsbIODeviceCollection qsbc(device);
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
Combined button and popup list for selecting options.
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
static const char * borderText()
static constexpr qint64 HeaderSize
static QString lockFileName(const QString &name)
static constexpr quint64 MagicaDS
static constexpr quint32 QtVersion
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept