5#include <private/qquickshadereffect_p_p.h>
6#include <private/qsgcontextplugin_p.h>
7#include <private/qsgrhisupport_p.h>
8#include <private/qquickwindow_p.h>
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
522 static void impl(
int which, QSlotObjectBase *this_, QObject *,
void **a,
bool *ret)
535 case NumOperations: ;
541QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
542 : QQuickItem(*
new QQuickShaderEffectPrivate, parent)
544 setFlag(QQuickItem::ItemHasContents);
547QQuickShaderEffect::~QQuickShaderEffect()
549 Q_D(QQuickShaderEffect);
550 d->inDestructor =
true;
552 for (
int i = 0; i < QQuickShaderEffectPrivate::NShader; ++i) {
553 d->disconnectSignals(QQuickShaderEffectPrivate::Shader(i));
554 d->clearMappers(QQuickShaderEffectPrivate::Shader(i));
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
579QUrl QQuickShaderEffect::fragmentShader()
const
581 Q_D(
const QQuickShaderEffect);
582 return d->fragmentShader();
585void QQuickShaderEffect::setFragmentShader(
const QUrl &fileUrl)
587 Q_D(QQuickShaderEffect);
588 d->setFragmentShader(fileUrl);
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
609QUrl QQuickShaderEffect::vertexShader()
const
611 Q_D(
const QQuickShaderEffect);
612 return d->vertexShader();
615void QQuickShaderEffect::setVertexShader(
const QUrl &fileUrl)
617 Q_D(QQuickShaderEffect);
618 d->setVertexShader(fileUrl);
622
623
624
625
626
627
628
630bool QQuickShaderEffect::blending()
const
632 Q_D(
const QQuickShaderEffect);
633 return d->blending();
636void QQuickShaderEffect::setBlending(
bool enable)
638 Q_D(QQuickShaderEffect);
639 d->setBlending(enable);
643
644
645
646
647
648
649
650
651
652
653
655QVariant QQuickShaderEffect::mesh()
const
657 Q_D(
const QQuickShaderEffect);
661void QQuickShaderEffect::setMesh(
const QVariant &mesh)
663 Q_D(QQuickShaderEffect);
668
669
670
671
672
673
674
675
676
677
679QQuickShaderEffect::CullMode QQuickShaderEffect::cullMode()
const
681 Q_D(
const QQuickShaderEffect);
682 return d->cullMode();
685void QQuickShaderEffect::setCullMode(CullMode face)
687 Q_D(QQuickShaderEffect);
688 return d->setCullMode(face);
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
712bool QQuickShaderEffect::supportsAtlasTextures()
const
714 Q_D(
const QQuickShaderEffect);
715 return d->supportsAtlasTextures();
718void QQuickShaderEffect::setSupportsAtlasTextures(
bool supports)
720 Q_D(QQuickShaderEffect);
721 d->setSupportsAtlasTextures(supports);
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
765QString QQuickShaderEffect::log()
const
767 Q_D(
const QQuickShaderEffect);
771QQuickShaderEffect::Status QQuickShaderEffect::status()
const
773 Q_D(
const QQuickShaderEffect);
777bool QQuickShaderEffect::event(QEvent *e)
779 Q_D(QQuickShaderEffect);
781 return QQuickItem::event(e);
784void QQuickShaderEffect::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
786 Q_D(QQuickShaderEffect);
787 d->handleGeometryChanged(newGeometry, oldGeometry);
788 QQuickItem::geometryChange(newGeometry, oldGeometry);
791QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
793 Q_D(QQuickShaderEffect);
794 return d->handleUpdatePaintNode(oldNode, updatePaintNodeData);
797void QQuickShaderEffect::componentComplete()
799 Q_D(QQuickShaderEffect);
800 d->maybeUpdateShaders();
801 QQuickItem::componentComplete();
804void QQuickShaderEffect::itemChange(ItemChange change,
const ItemChangeData &value)
806 Q_D(QQuickShaderEffect);
807 d->handleItemChange(change, value);
808 QQuickItem::itemChange(change, value);
811bool QQuickShaderEffect::isComponentComplete()
const
813 return QQuickItem::isComponentComplete();
816bool QQuickShaderEffect::updateUniformValue(
const QByteArray &name,
const QVariant &value)
818 auto node =
static_cast<QSGShaderEffectNode *>(QQuickItemPrivate::get(
this)->paintNode);
822 Q_D(QQuickShaderEffect);
823 return d->updateUniformValue(name, value, node);
826void QQuickShaderEffectPrivate::updatePolish()
828 Q_Q(QQuickShaderEffect);
831 maybeUpdateShaders();
836 return idx | (shaderType << 16);
841 return mappedId & 0xFFFF;
846 return mappedId >> 16;
849QQuickShaderEffectPrivate::QQuickShaderEffectPrivate()
850 : m_meshResolution(1, 1)
852 , m_cullMode(QQuickShaderEffect::NoCulling)
854 , m_supportsAtlasTextures(
false)
856 , m_fragNeedsUpdate(
true)
857 , m_vertNeedsUpdate(
true)
859 qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>(
"ShaderInfo::Type");
860 for (
int i = 0; i < NShader; ++i)
861 m_inProgress[i] =
nullptr;
864QQuickShaderEffectPrivate::~QQuickShaderEffectPrivate()
866 Q_ASSERT(m_mgr ==
nullptr);
869void QQuickShaderEffectPrivate::setFragmentShader(
const QUrl &fileUrl)
871 Q_Q(QQuickShaderEffect);
872 if (m_fragShader == fileUrl)
875 m_fragShader = fileUrl;
877 m_fragNeedsUpdate =
true;
878 if (q->isComponentComplete())
879 maybeUpdateShaders();
881 emit q->fragmentShaderChanged();
884void QQuickShaderEffectPrivate::setVertexShader(
const QUrl &fileUrl)
886 Q_Q(QQuickShaderEffect);
887 if (m_vertShader == fileUrl)
890 m_vertShader = fileUrl;
892 m_vertNeedsUpdate =
true;
893 if (q->isComponentComplete())
894 maybeUpdateShaders();
896 emit q->vertexShaderChanged();
899void QQuickShaderEffectPrivate::setBlending(
bool enable)
901 Q_Q(QQuickShaderEffect);
902 if (m_blending == enable)
907 emit q->blendingChanged();
910QVariant QQuickShaderEffectPrivate::mesh()
const
912 return m_mesh ? QVariant::fromValue(
static_cast<QObject *>(m_mesh))
913 : QVariant::fromValue(m_meshResolution);
916void QQuickShaderEffectPrivate::setMesh(
const QVariant &mesh)
918 Q_Q(QQuickShaderEffect);
919 QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
920 if (newMesh && newMesh == m_mesh)
924 QObject::disconnect(m_meshConnection);
929 m_meshConnection = QObject::connect(m_mesh, &QQuickShaderEffectMesh::geometryChanged, q,
930 [
this] { markGeometryDirtyAndUpdate(); });
932 if (mesh.canConvert<QSize>()) {
933 m_meshResolution = mesh.toSize();
935 QList<QByteArray> res = mesh.toByteArray().split(
'x');
936 bool ok = res.size() == 2;
938 int w = res.at(0).toInt(&ok);
940 int h = res.at(1).toInt(&ok);
942 m_meshResolution = QSize(w, h);
946 qWarning(
"ShaderEffect: mesh property must be a size or an object deriving from QQuickShaderEffectMesh");
948 m_defaultMesh.setResolution(m_meshResolution);
951 m_dirty |= QSGShaderEffectNode::DirtyShaderMesh;
954 emit q->meshChanged();
957void QQuickShaderEffectPrivate::setCullMode(QQuickShaderEffect::CullMode face)
959 Q_Q(QQuickShaderEffect);
960 if (m_cullMode == face)
965 emit q->cullModeChanged();
968void QQuickShaderEffectPrivate::setSupportsAtlasTextures(
bool supports)
970 Q_Q(QQuickShaderEffect);
971 if (m_supportsAtlasTextures == supports)
974 m_supportsAtlasTextures = supports;
975 markGeometryDirtyAndUpdate();
976 emit q->supportsAtlasTexturesChanged();
979QString QQuickShaderEffectPrivate::parseLog()
981 maybeUpdateShaders();
985QString QQuickShaderEffectPrivate::log()
const
987 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
994QQuickShaderEffect::Status QQuickShaderEffectPrivate::status()
const
996 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
998 return QQuickShaderEffect::Uncompiled;
1000 return QQuickShaderEffect::Status(mgr->status());
1003void QQuickShaderEffectPrivate::handleEvent(QEvent *event)
1005 if (event->type() == QEvent::DynamicPropertyChange) {
1006 const auto propertyName =
static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
1007 for (
int i = 0; i < NShader; ++i) {
1008 const auto mappedId = findMappedShaderVariableId(propertyName, Shader(i));
1010 propertyChanged(*mappedId);
1015void QQuickShaderEffectPrivate::handleGeometryChanged(
const QRectF &,
const QRectF &)
1017 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1020QSGNode *QQuickShaderEffectPrivate::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
1022 Q_Q(QQuickShaderEffect);
1023 QSGShaderEffectNode *node =
static_cast<QSGShaderEffectNode *>(oldNode);
1025 if (q->width() <= 0 || q->height() <= 0) {
1031 if (m_inProgress[Vertex] || m_inProgress[Fragment])
1035 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1042 QSGRenderContext *rc = QQuickWindowPrivate::get(q->window())->context;
1043 node = rc->sceneGraphContext()->createShaderEffectNode(rc);
1045 qWarning(
"No shader effect node");
1048 m_dirty = QSGShaderEffectNode::DirtyShaderAll;
1049 QObject::connect(node, &QSGShaderEffectNode::textureChanged, q, [
this] { markGeometryDirtyAndUpdateIfSupportsAtlas(); });
1052 QSGShaderEffectNode::SyncData sd;
1054 sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
1055 sd.blending = m_blending;
1056 sd.vertex.shader = &m_shaders[Vertex];
1057 sd.vertex.dirtyConstants = &m_dirtyConstants[Vertex];
1058 sd.vertex.dirtyTextures = &m_dirtyTextures[Vertex];
1059 sd.fragment.shader = &m_shaders[Fragment];
1060 sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
1061 sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
1062 sd.materialTypeCacheKey = q->window();
1063 sd.viewCount = QQuickWindowPrivate::get(q->window())->multiViewCount();
1065 node->syncMaterial(&sd);
1067 if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
1068 node->setGeometry(
nullptr);
1069 m_dirty &= ~QSGShaderEffectNode::DirtyShaderMesh;
1070 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1073 if (m_dirty & QSGShaderEffectNode::DirtyShaderGeometry) {
1074 const QRectF rect(0, 0, q->width(), q->height());
1075 QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
1076 QSGGeometry *geometry = node->geometry();
1078 const QRectF srcRect = node->updateNormalizedTextureSubRect(m_supportsAtlasTextures);
1079 geometry = mesh->updateGeometry(geometry, 2, 0, srcRect, rect);
1081 node->setFlag(QSGNode::OwnsGeometry,
false);
1082 node->setGeometry(geometry);
1083 node->setFlag(QSGNode::OwnsGeometry,
true);
1085 m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
1089 for (
int i = 0; i < NShader; ++i) {
1090 m_dirtyConstants[i].clear();
1091 m_dirtyTextures[i].clear();
1097void QQuickShaderEffectPrivate::maybeUpdateShaders()
1099 Q_Q(QQuickShaderEffect);
1100 if (m_vertNeedsUpdate)
1101 m_vertNeedsUpdate = !updateShader(Vertex, m_vertShader);
1102 if (m_fragNeedsUpdate)
1103 m_fragNeedsUpdate = !updateShader(Fragment, m_fragShader);
1104 if (m_vertNeedsUpdate || m_fragNeedsUpdate) {
1111 if (!q->window() || !q->window()->isSceneGraphInitialized())
1116bool QQuickShaderEffectPrivate::updateUniformValue(
const QByteArray &name,
const QVariant &value,
1117 QSGShaderEffectNode *node)
1119 Q_Q(QQuickShaderEffect);
1120 const auto mappedId = findMappedShaderVariableId(name);
1124 const Shader type = Shader(mappedIdToShaderType(*mappedId));
1125 const int idx = mappedIdToIndex(*mappedId);
1128 m_shaders[type].varData[idx].value = value;
1131 QSet<
int> dirtyConstants[NShader];
1132 dirtyConstants[type].insert(idx);
1135 QSGShaderEffectNode::SyncData sd;
1136 sd.dirty = QSGShaderEffectNode::DirtyShaderConstant;
1137 sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
1138 sd.blending = m_blending;
1139 sd.vertex.shader = &m_shaders[Vertex];
1140 sd.vertex.dirtyConstants = &dirtyConstants[Vertex];
1141 sd.vertex.dirtyTextures = {};
1142 sd.fragment.shader = &m_shaders[Fragment];
1143 sd.fragment.dirtyConstants = &dirtyConstants[Fragment];
1144 sd.fragment.dirtyTextures = {};
1145 sd.materialTypeCacheKey = q->window();
1146 sd.viewCount = QQuickWindowPrivate::get(q->window())->multiViewCount();
1148 node->syncMaterial(&sd);
1153void QQuickShaderEffectPrivate::handleItemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
1159 if (change == QQuickItem::ItemSceneChange) {
1160 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1161 for (
const auto &vd : std::as_const(m_shaders[shaderType].varData)) {
1162 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1163 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1166 QQuickItemPrivate::get(source)->refWindow(value.window);
1168 QQuickItemPrivate::get(source)->derefWindow();
1176QSGGuiThreadShaderEffectManager *QQuickShaderEffectPrivate::shaderEffectManager()
const
1178 Q_Q(
const QQuickShaderEffect);
1181 if (QThread::currentThread() != q->thread())
1183 QQuickWindow *w = q->window();
1185 QSGRenderContext *renderContext = QQuickWindowPrivate::get(w)->context;
1186 if (QSGContext *sgContext = renderContext->sceneGraphContext())
1187 m_mgr = sgContext->createGuiThreadShaderEffectManager();
1189 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::logAndStatusChanged, q, &QQuickShaderEffect::logChanged);
1190 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::logAndStatusChanged, q, &QQuickShaderEffect::statusChanged);
1191 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::shaderCodePrepared, q,
1192 [
this](
bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
1193 const QUrl &loadUrl, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
1194 {
const_cast<QQuickShaderEffectPrivate *>(
this)->shaderCodePrepared(ok, typeHint, loadUrl, result); });
1201void QQuickShaderEffectPrivate::disconnectSignals(Shader shaderType)
1203 Q_Q(QQuickShaderEffect);
1204 for (
auto *mapper : m_mappers[shaderType]) {
1207 QObjectPrivate::disconnect(q, mapper->signalIndex(), &a);
1209 for (
const auto &vd : std::as_const(m_shaders[shaderType].varData)) {
1210 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1211 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1214 QQuickItemPrivate::get(source)->derefWindow();
1215 auto it = m_destroyedConnections.constFind(source);
1216 if (it != m_destroyedConnections.constEnd()) {
1217 QObject::disconnect(*it);
1218 m_destroyedConnections.erase(it);
1225void QQuickShaderEffectPrivate::clearMappers(QQuickShaderEffectPrivate::Shader shaderType)
1227 for (
auto *mapper : std::as_const(m_mappers[shaderType])) {
1229 mapper->destroyIfLastRef();
1231 m_mappers[shaderType].clear();
1235 const QByteArray &name,
int propertyIndex)
1238 if (propertyIndex == -1) {
1239 value = item->property(name);
1241 value = itemMetaObject->property(propertyIndex).read(item);
1246using QQuickShaderInfoCache = QHash<QUrl, QSGGuiThreadShaderEffectManager::ShaderInfo>;
1251 shaderInfoCache()->clear();
1254bool QQuickShaderEffectPrivate::updateShader(Shader shaderType,
const QUrl &fileUrl)
1256 Q_Q(QQuickShaderEffect);
1257 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1261 const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
1263 disconnectSignals(shaderType);
1265 m_shaders[shaderType].shaderInfo.variables.clear();
1266 m_shaders[shaderType].varData.clear();
1268 if (!fileUrl.isEmpty()) {
1269 const QQmlContext *context = qmlContext(q);
1270 const QUrl loadUrl = context ? context->resolvedUrl(fileUrl) : fileUrl;
1271 auto it = shaderInfoCache()->constFind(loadUrl);
1272 if (it != shaderInfoCache()->cend()) {
1273 m_shaders[shaderType].shaderInfo = *it;
1274 m_shaders[shaderType].hasShaderCode =
true;
1280 m_inProgress[shaderType] =
new QSGGuiThreadShaderEffectManager::ShaderInfo;
1281 const QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint =
1282 shaderType == Vertex ? QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex
1283 : QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
1288 mgr->prepareShaderCode(typeHint, loadUrl, m_inProgress[shaderType]);
1293 m_shaders[shaderType].hasShaderCode =
false;
1294 if (shaderType == Fragment) {
1300 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
1301 v.name = QByteArrayLiteral(
"source");
1303 v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
1304 : QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
1305 m_shaders[shaderType].shaderInfo.variables.append(v);
1309 updateShaderVars(shaderType);
1310 m_dirty |= QSGShaderEffectNode::DirtyShaders;
1315void QQuickShaderEffectPrivate::shaderCodePrepared(
bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
1316 const QUrl &loadUrl, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
1318 Q_Q(QQuickShaderEffect);
1319 const Shader shaderType = typeHint == QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? Vertex : Fragment;
1323 if (result != m_inProgress[shaderType]) {
1328 m_shaders[shaderType].shaderInfo = *result;
1330 m_inProgress[shaderType] =
nullptr;
1333 qWarning(
"ShaderEffect: shader preparation failed for %s\n%s\n",
1334 qPrintable(loadUrl.toString()), qPrintable(log()));
1335 m_shaders[shaderType].hasShaderCode =
false;
1339 m_shaders[shaderType].hasShaderCode =
true;
1340 shaderInfoCache()->insert(loadUrl, m_shaders[shaderType].shaderInfo);
1341 updateShaderVars(shaderType);
1342 m_dirty |= QSGShaderEffectNode::DirtyShaders;
1346void QQuickShaderEffectPrivate::updateShaderVars(Shader shaderType)
1348 Q_Q(QQuickShaderEffect);
1349 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1353 const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
1355 const int varCount = m_shaders[shaderType].shaderInfo.variables.size();
1356 m_shaders[shaderType].varData.resize(varCount);
1359 clearMappers(shaderType);
1361 QQmlPropertyCache::ConstPtr propCache = QQmlData::ensurePropertyCache(q);
1363 if (!m_itemMetaObject)
1364 m_itemMetaObject = q->metaObject();
1368 for (
int i = 0; i < varCount; ++i) {
1369 const auto &v(m_shaders[shaderType].shaderInfo.variables.at(i));
1370 QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
1371 const bool isSpecial = v.name.startsWith(
"qt_");
1373 if (v.name ==
"qt_Opacity")
1374 vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
1375 else if (v.name ==
"qt_Matrix")
1376 vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
1377 else if (v.name.startsWith(
"qt_SubRect_"))
1378 vd.specialType = QSGShaderEffectNode::VariableData::SubRect;
1385 if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
1386 if (texturesSeparate) {
1387 vd.specialType = QSGShaderEffectNode::VariableData::Unused;
1390 vd.specialType = QSGShaderEffectNode::VariableData::Source;
1392 }
else if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
1393 Q_ASSERT(texturesSeparate);
1394 vd.specialType = QSGShaderEffectNode::VariableData::Source;
1396 vd.specialType = QSGShaderEffectNode::VariableData::None;
1401 const QQmlPropertyData *pd =
nullptr;
1403 pd = propCache->property(QLatin1String(v.name),
nullptr,
nullptr);
1405 if (!pd->isFunction())
1406 propIdx = pd->coreIndex();
1410 if (pd && !pd->isFunction()) {
1411 if (pd->notifyIndex() == -1) {
1412 qWarning(
"QQuickShaderEffect: property '%s' does not have notification method!", v.name.constData());
1414 const int mappedId = indexToMappedId(shaderType, i);
1415 auto mapper =
new QtPrivate::EffectSlotMapper([
this, mappedId](){
1416 this->propertyChanged(mappedId);
1418 m_mappers[shaderType].append(mapper);
1419 mapper->setSignalIndex(m_itemMetaObject->property(propIdx).notifySignal().methodIndex());
1420 Q_ASSERT(q->metaObject() == m_itemMetaObject);
1421 bool ok = QObjectPrivate::connectImpl(q, pd->notifyIndex(), q,
nullptr, mapper,
1422 Qt::AutoConnection,
nullptr, m_itemMetaObject);
1424 qWarning() <<
"Failed to connect to property" << m_itemMetaObject->property(propIdx).name()
1425 <<
"(" << propIdx <<
", signal index" << pd->notifyIndex()
1426 <<
") of item" << q;
1431 if (!q->property(v.name.constData()).isValid())
1432 qWarning(
"ShaderEffect: '%s' does not have a matching property", v.name.constData());
1436 vd.propertyIndex = propIdx;
1437 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1438 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1439 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1442 QQuickItemPrivate::get(source)->refWindow(q->window());
1450 if (!m_destroyedConnections.contains(source))
1451 m_destroyedConnections.insert(source, QObject::connect(source, &QObject::destroyed, [
this](QObject *obj) { sourceDestroyed(obj); }));
1457std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name)
const
1459 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1460 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1461 for (
int idx = 0; idx < vars.size(); ++idx) {
1462 if (vars[idx].name == name)
1463 return indexToMappedId(shaderType, idx);
1470std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name, Shader shaderType)
const
1472 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1473 for (
int idx = 0; idx < vars.size(); ++idx) {
1474 if (vars[idx].name == name)
1475 return indexToMappedId(shaderType, idx);
1481bool QQuickShaderEffectPrivate::sourceIsUnique(QQuickItem *source, Shader typeToSkip,
int indexToSkip)
const
1483 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1484 for (
int idx = 0; idx < m_shaders[shaderType].varData.size(); ++idx) {
1485 if (shaderType != typeToSkip || idx != indexToSkip) {
1486 const auto &vd(m_shaders[shaderType].varData[idx]);
1487 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && qvariant_cast<QObject *>(vd.value) == source)
1495void QQuickShaderEffectPrivate::propertyChanged(
int mappedId)
1497 Q_Q(QQuickShaderEffect);
1498 const Shader type = Shader(mappedIdToShaderType(mappedId));
1499 const int idx = mappedIdToIndex(mappedId);
1500 const auto &v(m_shaders[type].shaderInfo.variables[idx]);
1501 auto &vd(m_shaders[type].varData[idx]);
1503 QVariant oldValue = vd.value;
1504 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1506 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1507 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(oldValue));
1510 QQuickItemPrivate::get(source)->derefWindow();
1514 if (sourceIsUnique(source, type, idx)) {
1515 auto it = m_destroyedConnections.constFind(source);
1516 if (it != m_destroyedConnections.constEnd()) {
1517 QObject::disconnect(*it);
1518 m_destroyedConnections.erase(it);
1523 source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1530 QQuickItemPrivate::get(source)->refWindow(q->window());
1531 if (!m_destroyedConnections.contains(source))
1532 m_destroyedConnections.insert(source, QObject::connect(source, &QObject::destroyed, [
this](QObject *obj) { sourceDestroyed(obj); }));
1535 m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
1536 m_dirtyTextures[type].insert(idx);
1539 m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
1540 m_dirtyConstants[type].insert(idx);
1546void QQuickShaderEffectPrivate::sourceDestroyed(QObject *object)
1548 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1549 for (
auto &vd : m_shaders[shaderType].varData) {
1550 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && vd.value.canConvert<QObject *>()) {
1551 if (qvariant_cast<QObject *>(vd.value) == object)
1552 vd.value = QVariant();
1558void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdate()
1560 Q_Q(QQuickShaderEffect);
1561 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1565void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdateIfSupportsAtlas()
1567 if (m_supportsAtlasTextures)
1568 markGeometryDirtyAndUpdate();
1573#include "moc_qquickshadereffect_p.cpp"
std::function< void()> PropChangedFunc
void setSignalIndex(int idx)
EffectSlotMapper(PropChangedFunc func)
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
constexpr int mappedIdToShaderType(const int mappedId)
constexpr int mappedIdToIndex(const int mappedId)
static QVariant getValueFromProperty(QObject *item, const QMetaObject *itemMetaObject, const QByteArray &name, int propertyIndex)
void qtquick_shadereffect_purge_gui_thread_shader_cache()
constexpr int indexToMappedId(const int shaderType, const int idx)