Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qqsbcollection.cpp
Go to the documentation of this file.
1
// Copyright (C) 2020 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
6
#
include
"qqsbcollection_p.h"
7
#
include
<
QtCore
/
QLockFile
>
8
#
include
<
QtCore
/
QSaveFile
>
9
#
include
<
QtCore
/
QCryptographicHash
>
10
#
include
<
QtCore
/
QLoggingCategory
>
11
#
include
<
rhi
/
qrhi
.
h
>
12
13
QT_BEGIN_NAMESPACE
14
15
Q_STATIC_LOGGING_CATEGORY(lcQuick3DCache,
"qt.quick3d.cache"
)
16
17
QQsbCollection::~QQsbCollection()
18
{
19
}
20
21
QDataStream &operator<<(QDataStream &stream,
const
QQsbCollection::Entry &entry)
22
{
23
return
(stream << entry.key << entry.value);
24
}
25
26
QDataStream &
operator
>>(QDataStream &stream, QQsbCollection::Entry &entry)
27
{
28
QByteArray key;
29
qint64 value;
30
stream >> key >> value;
31
entry = QQsbCollection::Entry(key, value);
32
return
stream;
33
}
34
35
size_t
qHash
(
const
QQsbCollection::Entry &entry,
size_t
)
36
{
37
return
entry.hashKey;
38
}
39
40
bool
operator
==(
const
QQsbCollection::Entry &l,
const
QQsbCollection::Entry &r)
41
{
42
return
(l.key == r.key);
43
}
44
45
QDataStream &operator<<(QDataStream &stream,
const
QQsbCollection::EntryDesc &entryDesc)
46
{
47
return
(stream << entryDesc.materialKey
48
<< entryDesc.featureSet
49
<< entryDesc.vertShader.serialized()
50
<< entryDesc.fragShader.serialized());
51
}
52
53
QDataStream &
operator
>>(QDataStream &stream, QQsbCollection::EntryDesc &entryDesc)
54
{
55
QByteArray desc;
56
QQsbCollection::FeatureSet fs;
57
QByteArray vertData;
58
QByteArray fragData;
59
stream >> desc >> fs >> vertData >> fragData;
60
entryDesc.materialKey = desc;
61
entryDesc.featureSet = fs;
62
entryDesc.vertShader = QShader::fromSerialized(vertData);
63
entryDesc.fragShader = QShader::fromSerialized(fragData);
64
return
stream;
65
}
66
67
static
constexpr
quint64
MagicaDS
= 0x3933333335346337;
68
static
constexpr
qint64
HeaderSize
=
sizeof
(qint64
/*startOffs*/
) +
sizeof
(quint8
/*version*/
) +
sizeof
(quint32
/*qtVersion*/
) +
sizeof
(MagicaDS);
69
static
constexpr
quint32
QtVersion
= (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
70
71
bool
QQsbCollection::readEndHeader(QDataStream &ds, qint64 *startPos, quint8 *version)
72
{
73
quint64 fileId = 0;
74
quint32 qtver = 0;
75
ds >> *startPos >> *version >> qtver >> fileId;
76
if
(fileId != MagicaDS) {
77
qCDebug(lcQuick3DCache,
"Corrupt qsbc file"
);
78
return
false
;
79
}
80
if
(*version != Version::Two) {
81
qCDebug(lcQuick3DCache,
"qsbc file has an unsupported version"
);
82
return
false
;
83
}
84
if
(qtver != QtVersion) {
85
qCDebug(lcQuick3DCache,
"qsbc file is for a different Qt version"
);
86
return
false
;
87
}
88
return
true
;
89
}
90
91
bool
QQsbCollection::readEndHeader(QIODevice *device, EntryMap *entries, quint8 *version)
92
{
93
bool
result =
false
;
94
const
qint64 size = device->size();
95
if
(device->seek(size - HeaderSize)) {
96
QDataStream ds(device);
97
ds.setVersion(QDataStream::Qt_6_0);
98
qint64 startPos = 0;
99
if
(readEndHeader(ds, &startPos, version)) {
100
if
(startPos >= 0 && startPos < size && device->seek(startPos)) {
101
ds >> *entries;
102
result =
true
;
103
}
104
}
105
}
106
return
result;
107
}
108
109
void
QQsbCollection::writeEndHeader(QDataStream &ds, qint64 startPos, quint8 version, quint64 magic)
110
{
111
ds << startPos << version << QtVersion << magic;
112
}
113
114
void
QQsbCollection::writeEndHeader(QIODevice *device,
const
EntryMap &entries)
115
{
116
if
(!device->atEnd()) {
117
device->seek(device->size() - 1);
118
Q_ASSERT(device->atEnd());
119
}
120
QDataStream ds(device);
121
ds.setVersion(QDataStream::Qt_6_0);
122
const
qint64 startPos = device->pos();
123
ds << entries;
124
writeEndHeader(ds, startPos, quint8(Version::Two), MagicaDS);
125
}
126
127
QByteArray QQsbCollection::EntryDesc::generateSha(
const
QByteArray &materialKey,
const
FeatureSet &featureSet)
128
{
129
QCryptographicHash h(QCryptographicHash::Algorithm::Sha1);
130
h.addData(materialKey);
131
for
(
auto
it = featureSet.cbegin(), end = featureSet.cend(); it != end; ++it) {
132
if
(it.value())
133
h.addData(it.key());
134
}
135
return
h.result().toHex();
136
}
137
138
QByteArray QQsbCollection::EntryDesc::generateSha()
const
139
{
140
return
generateSha(materialKey, featureSet);
141
}
142
143
QQsbCollection::EntryMap QQsbInMemoryCollection::availableEntries()
const
144
{
145
return
EntryMap(entries.keyBegin(), entries.keyEnd());
146
}
147
148
QQsbCollection::Entry QQsbInMemoryCollection::addEntry(
const
QByteArray &key,
const
EntryDesc &entryDesc)
149
{
150
Entry e(key);
151
if
(!entries.contains(e)) {
152
entries.insert(e, entryDesc);
153
return
e;
154
}
155
return
{};
// can only add with a given key once
156
}
157
158
bool
QQsbInMemoryCollection::extractEntry(Entry entry, EntryDesc &entryDesc)
159
{
160
auto
it = entries.constFind(entry);
161
if
(it != entries.constEnd()) {
162
entryDesc = *it;
163
return
true
;
164
}
165
return
false
;
166
}
167
168
void
QQsbInMemoryCollection::clear()
169
{
170
entries.clear();
171
}
172
173
static
inline
QString
lockFileName
(
const
QString &name)
174
{
175
return
name + QLatin1String(
".lck"
);
176
}
177
178
bool
QQsbInMemoryCollection::load(
const
QString &filename)
179
{
180
QLockFile lock(lockFileName(filename));
181
if
(!lock.lock()) {
182
qCDebug(lcQuick3DCache,
"Could not create shader cache lock file '%s'"
,
183
qPrintable(lock.fileName()));
184
return
false
;
185
}
186
187
QFile f(filename);
188
if
(!f.open(QIODevice::ReadOnly)) {
189
qCDebug(lcQuick3DCache,
"Failed to open qsbc file %s"
, qPrintable(filename));
190
return
false
;
191
}
192
193
EntryMap entryMap;
194
quint8 version = 0;
195
if
(!readEndHeader(&f, &entryMap, &version)) {
196
qCDebug(lcQuick3DCache,
"Ignoring qsbc file %s"
, qPrintable(filename));
197
return
false
;
198
}
199
200
f.seek(0);
201
const
qint64 size = f.size();
202
203
clear();
204
205
const
qsizetype entryCountBefore = entries.size();
206
for
(
const
Entry &e : std::as_const(entryMap)) {
207
const
qint64 offset = e.value;
208
if
(e.isValid() && offset >= 0 && size > offset && f.seek(offset)) {
209
QDataStream ds(&f);
210
ds.setVersion(QDataStream::Qt_6_0);
211
EntryDesc entryDesc;
212
ds >> entryDesc;
213
entries.insert(Entry(e.key), entryDesc);
214
}
215
}
216
qCDebug(lcQuick3DCache,
"Loaded %d material cache entries from %s"
,
217
int
(entries.size() - entryCountBefore),
218
qPrintable(filename));
219
220
return
true
;
221
}
222
223
bool
QQsbInMemoryCollection::save(
const
QString &filename)
224
{
225
QLockFile lock(lockFileName(filename));
226
if
(!lock.lock()) {
227
qCDebug(lcQuick3DCache,
"Could not create shader cache lock file '%s'"
,
228
qPrintable(lock.fileName()));
229
return
false
;
230
}
231
232
#
if
QT_CONFIG
(
temporaryfile
)
233
QSaveFile f(filename);
234
#
else
235
QFile f(filename);
236
#
endif
237
if
(!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
238
qCDebug(lcQuick3DCache,
"Failed to write qsbc file %s"
, qPrintable(filename));
239
return
false
;
240
}
241
242
QDataStream ds(&f);
243
ds.setVersion(QDataStream::Qt_6_0);
244
245
EntryMap entryMap;
246
for
(
auto
it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
247
const
qint64 offset = f.pos();
248
ds << it.value();
249
entryMap.insert(Entry(it.key().key, offset));
250
}
251
252
writeEndHeader(&f, entryMap);
253
254
qCDebug(lcQuick3DCache,
"Writing %d material cache entries to %s"
,
255
int
(entryMap.size()),
256
qPrintable(filename));
257
258
#
if
QT_CONFIG
(
temporaryfile
)
259
return
f.commit();
260
#
else
261
return
true
;
262
#
endif
263
}
264
265
QQsbIODeviceCollection::QQsbIODeviceCollection(
const
QString &filePath)
266
: file(filePath)
267
, device(file)
268
{
269
}
270
271
QQsbIODeviceCollection::QQsbIODeviceCollection(QIODevice &dev)
272
: device(dev)
273
, devOwner(DeviceOwner::Extern)
274
{
275
276
}
277
278
QQsbIODeviceCollection::~QQsbIODeviceCollection()
279
{
280
if
(!entries.isEmpty() || device.isOpen())
281
unmap();
282
}
283
284
bool
QQsbIODeviceCollection::map(MapMode mode)
285
{
286
if
(device.isOpen()) {
287
// Make sure Truncate is set if we're writing.
288
if
((device.openMode() & QIODevice::WriteOnly) != 0) {
289
if
((device.openMode() & QIODevice::Truncate) == 0) {
290
qWarning(
"Open mode needs to have Truncate set for writing!"
);
291
return
false
;
292
}
293
if
((device.openMode() & QIODevice::Text) != 0) {
294
qWarning(
"Open mode can't have Text mode set!"
);
295
return
false
;
296
}
297
}
298
}
else
if
(!device.open(QIODevice::OpenMode(mode))) {
299
qWarning(
"Unable to open device!"
);
300
return
false
;
301
}
302
303
if
(mode == Write)
304
return
true
;
305
306
Q_ASSERT(mode == Read);
307
308
const
bool
ret = readEndHeader(&device, &entries, &version);
309
310
if
(!ret)
311
unmap();
312
313
return
ret;
314
}
315
316
void
QQsbIODeviceCollection::unmap()
317
{
318
if
(device.isOpen() && ((device.openMode() & Write) == Write)) {
319
if
(!entries.isEmpty()) {
320
writeEndHeader(&device, entries);
321
}
else
{
322
if
(devOwner == DeviceOwner::Self)
323
file.remove();
324
}
325
}
326
device.close();
327
entries.clear();
328
}
329
330
QQsbCollection::EntryMap QQsbIODeviceCollection::availableEntries()
const
331
{
332
return
entries;
333
}
334
335
QQsbCollection::Entry QQsbIODeviceCollection::addEntry(
const
QByteArray &key,
const
EntryDesc &entryDesc)
336
{
337
if
(entries.contains(Entry(key)) || !map(MapMode::Write))
338
return
{};
339
340
QDataStream ds(&device);
341
ds.setVersion(QDataStream::Qt_6_0);
342
const
auto
offset = device.pos();
343
ds << entryDesc;
344
Entry e(key, offset);
345
entries.insert(e);
346
return
e;
347
}
348
349
bool
QQsbIODeviceCollection::extractEntry(Entry entry, EntryDesc &entryDesc)
350
{
351
if
(device.isOpen() && device.isReadable()) {
352
const
qint64 offset = entry.value;
353
if
(entry.isValid() && offset >= 0) {
354
const
qint64 size = device.size();
355
if
(size > offset && device.seek(offset)) {
356
QDataStream ds(&device);
357
ds.setVersion(QDataStream::Qt_6_0);
358
ds >> entryDesc;
359
return
true
;
360
}
361
}
else
{
362
qWarning(
"Entry not found id(%s), offset(%lld)"
, entry.key.constData(), entry.value);
363
}
364
}
else
{
365
qWarning(
"Unable to open file for reading"
);
366
}
367
368
return
false
;
369
}
370
371
static
const
char
*
borderText
() {
return
"--------------------------------------------------------------------------------"
; }
372
373
void
QQsbIODeviceCollection::dumpInfo()
374
{
375
if
(map(QQsbIODeviceCollection::Read)) {
376
qDebug(
"Number of entries in collection: %zu\n"
, size_t(entries.size()));
377
int
i = 0;
378
qDebug(
"Qsbc version: %u"
, version);
379
for
(
const
auto
&e : std::as_const(entries)) {
380
qDebug(
"%s\n"
381
"Entry %d\n%s\n"
382
"Key: %s\n"
383
"Offset: %llu"
, borderText(), i++, borderText(), e.key.constData(), e.value);
384
385
QQsbCollection::EntryDesc ed;
386
if
(extractEntry(e, ed)) {
387
qDebug() << ed.materialKey << Qt::endl
388
<< ed.featureSet << Qt::endl
389
<< ed.vertShader << Qt::endl
390
<< ed.fragShader;
391
}
else
{
392
qWarning(
"Extracting Qsb entry failed!"
);
393
}
394
}
395
}
396
unmap();
397
}
398
399
void
QQsbIODeviceCollection::dumpInfo(
const
QString &file)
400
{
401
QQsbIODeviceCollection qsbc(file);
402
qsbc.dumpInfo();
403
}
404
405
void
QQsbIODeviceCollection::dumpInfo(QIODevice &device)
406
{
407
QQsbIODeviceCollection qsbc(device);
408
qsbc.dumpInfo();
409
}
410
411
QT_END_NAMESPACE
QByteArray::FromBase64Result::operator==
friend bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept
Returns true if lhs and rhs are equal, otherwise returns false.
Definition
qbytearray.h:842
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
operator>>
QDataStream & operator>>(QDataStream &s, QKeyCombination &combination)
Definition
qdatastream.h:699
borderText
static const char * borderText()
Definition
qqsbcollection.cpp:371
HeaderSize
static constexpr qint64 HeaderSize
Definition
qqsbcollection.cpp:68
lockFileName
static QString lockFileName(const QString &name)
Definition
qqsbcollection.cpp:173
MagicaDS
static constexpr quint64 MagicaDS
Definition
qqsbcollection.cpp:67
QtVersion
static constexpr quint32 QtVersion
Definition
qqsbcollection.cpp:69
qHash
constexpr size_t qHash(const QSize &s, size_t seed=0) noexcept
Definition
qsize.h:192
qtquick3d
src
utils
qqsbcollection.cpp
Generated on
for Qt by
1.18.0