4#include <private/qquickshadereffect_p_p.h>
5#include <private/qsgcontextplugin_p.h>
6#include <private/qsgrhisupport_p.h>
7#include <private/qquickwindow_p.h>
12
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
521 static void impl(
int which, QSlotObjectBase *this_, QObject *,
void **a,
bool *ret)
534 case NumOperations: ;
540QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
541 : QQuickItem(*
new QQuickShaderEffectPrivate, parent)
543 setFlag(QQuickItem::ItemHasContents);
546QQuickShaderEffect::~QQuickShaderEffect()
548 Q_D(QQuickShaderEffect);
549 d->inDestructor =
true;
551 for (
int i = 0; i < QQuickShaderEffectPrivate::NShader; ++i) {
552 d->disconnectSignals(QQuickShaderEffectPrivate::Shader(i));
553 d->clearMappers(QQuickShaderEffectPrivate::Shader(i));
561
562
563
564
565
566
567
568
569
570
571
573QUrl QQuickShaderEffect::fragmentShader()
const
575 Q_D(
const QQuickShaderEffect);
576 return d->fragmentShader();
579void QQuickShaderEffect::setFragmentShader(
const QUrl &fileUrl)
581 Q_D(QQuickShaderEffect);
582 d->setFragmentShader(fileUrl);
586
587
588
589
590
591
592
593
594
595
596
598QUrl QQuickShaderEffect::vertexShader()
const
600 Q_D(
const QQuickShaderEffect);
601 return d->vertexShader();
604void QQuickShaderEffect::setVertexShader(
const QUrl &fileUrl)
606 Q_D(QQuickShaderEffect);
607 d->setVertexShader(fileUrl);
611
612
613
614
615
616
617
619bool QQuickShaderEffect::blending()
const
621 Q_D(
const QQuickShaderEffect);
622 return d->blending();
625void QQuickShaderEffect::setBlending(
bool enable)
627 Q_D(QQuickShaderEffect);
628 d->setBlending(enable);
632
633
634
635
636
637
638
639
640
641
642
644QVariant QQuickShaderEffect::mesh()
const
646 Q_D(
const QQuickShaderEffect);
650void QQuickShaderEffect::setMesh(
const QVariant &mesh)
652 Q_D(QQuickShaderEffect);
657
658
659
660
661
662
663
664
665
666
668QQuickShaderEffect::CullMode QQuickShaderEffect::cullMode()
const
670 Q_D(
const QQuickShaderEffect);
671 return d->cullMode();
674void QQuickShaderEffect::setCullMode(CullMode face)
676 Q_D(QQuickShaderEffect);
677 return d->setCullMode(face);
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
701bool QQuickShaderEffect::supportsAtlasTextures()
const
703 Q_D(
const QQuickShaderEffect);
704 return d->supportsAtlasTextures();
707void QQuickShaderEffect::setSupportsAtlasTextures(
bool supports)
709 Q_D(QQuickShaderEffect);
710 d->setSupportsAtlasTextures(supports);
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
754QString QQuickShaderEffect::log()
const
756 Q_D(
const QQuickShaderEffect);
760QQuickShaderEffect::Status QQuickShaderEffect::status()
const
762 Q_D(
const QQuickShaderEffect);
766bool QQuickShaderEffect::event(QEvent *e)
768 Q_D(QQuickShaderEffect);
770 return QQuickItem::event(e);
773void QQuickShaderEffect::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
775 Q_D(QQuickShaderEffect);
776 d->handleGeometryChanged(newGeometry, oldGeometry);
777 QQuickItem::geometryChange(newGeometry, oldGeometry);
780QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
782 Q_D(QQuickShaderEffect);
783 return d->handleUpdatePaintNode(oldNode, updatePaintNodeData);
786void QQuickShaderEffect::componentComplete()
788 Q_D(QQuickShaderEffect);
789 d->maybeUpdateShaders();
790 QQuickItem::componentComplete();
793void QQuickShaderEffect::itemChange(ItemChange change,
const ItemChangeData &value)
795 Q_D(QQuickShaderEffect);
796 d->handleItemChange(change, value);
797 QQuickItem::itemChange(change, value);
800bool QQuickShaderEffect::isComponentComplete()
const
802 return QQuickItem::isComponentComplete();
805bool QQuickShaderEffect::updateUniformValue(
const QByteArray &name,
const QVariant &value)
807 auto node =
static_cast<QSGShaderEffectNode *>(QQuickItemPrivate::get(
this)->paintNode);
811 Q_D(QQuickShaderEffect);
812 return d->updateUniformValue(name, value, node);
815void QQuickShaderEffectPrivate::updatePolish()
817 Q_Q(QQuickShaderEffect);
820 maybeUpdateShaders();
825 return idx | (shaderType << 16);
830 return mappedId & 0xFFFF;
835 return mappedId >> 16;
838QQuickShaderEffectPrivate::QQuickShaderEffectPrivate()
839 : m_meshResolution(1, 1)
841 , m_cullMode(QQuickShaderEffect::NoCulling)
843 , m_supportsAtlasTextures(
false)
845 , m_fragNeedsUpdate(
true)
846 , m_vertNeedsUpdate(
true)
848 qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>(
"ShaderInfo::Type");
849 for (
int i = 0; i < NShader; ++i)
850 m_inProgress[i] =
nullptr;
853QQuickShaderEffectPrivate::~QQuickShaderEffectPrivate()
855 Q_ASSERT(m_mgr ==
nullptr);
858void QQuickShaderEffectPrivate::setFragmentShader(
const QUrl &fileUrl)
860 Q_Q(QQuickShaderEffect);
861 if (m_fragShader == fileUrl)
864 m_fragShader = fileUrl;
866 m_fragNeedsUpdate =
true;
867 if (q->isComponentComplete())
868 maybeUpdateShaders();
870 emit q->fragmentShaderChanged();
873void QQuickShaderEffectPrivate::setVertexShader(
const QUrl &fileUrl)
875 Q_Q(QQuickShaderEffect);
876 if (m_vertShader == fileUrl)
879 m_vertShader = fileUrl;
881 m_vertNeedsUpdate =
true;
882 if (q->isComponentComplete())
883 maybeUpdateShaders();
885 emit q->vertexShaderChanged();
888void QQuickShaderEffectPrivate::setBlending(
bool enable)
890 Q_Q(QQuickShaderEffect);
891 if (m_blending == enable)
896 emit q->blendingChanged();
899QVariant QQuickShaderEffectPrivate::mesh()
const
901 return m_mesh ? QVariant::fromValue(
static_cast<QObject *>(m_mesh))
902 : QVariant::fromValue(m_meshResolution);
905void QQuickShaderEffectPrivate::setMesh(
const QVariant &mesh)
907 Q_Q(QQuickShaderEffect);
908 QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
909 if (newMesh && newMesh == m_mesh)
913 QObject::disconnect(m_meshConnection);
918 m_meshConnection = QObject::connect(m_mesh, &QQuickShaderEffectMesh::geometryChanged, q,
919 [
this] { markGeometryDirtyAndUpdate(); });
921 if (mesh.canConvert<QSize>()) {
922 m_meshResolution = mesh.toSize();
924 QList<QByteArray> res = mesh.toByteArray().split(
'x');
925 bool ok = res.size() == 2;
927 int w = res.at(0).toInt(&ok);
929 int h = res.at(1).toInt(&ok);
931 m_meshResolution = QSize(w, h);
935 qWarning(
"ShaderEffect: mesh property must be a size or an object deriving from QQuickShaderEffectMesh");
937 m_defaultMesh.setResolution(m_meshResolution);
940 m_dirty |= QSGShaderEffectNode::DirtyShaderMesh;
943 emit q->meshChanged();
946void QQuickShaderEffectPrivate::setCullMode(QQuickShaderEffect::CullMode face)
948 Q_Q(QQuickShaderEffect);
949 if (m_cullMode == face)
954 emit q->cullModeChanged();
957void QQuickShaderEffectPrivate::setSupportsAtlasTextures(
bool supports)
959 Q_Q(QQuickShaderEffect);
960 if (m_supportsAtlasTextures == supports)
963 m_supportsAtlasTextures = supports;
964 markGeometryDirtyAndUpdate();
965 emit q->supportsAtlasTexturesChanged();
968QString QQuickShaderEffectPrivate::parseLog()
970 maybeUpdateShaders();
974QString QQuickShaderEffectPrivate::log()
const
976 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
983QQuickShaderEffect::Status QQuickShaderEffectPrivate::status()
const
985 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
987 return QQuickShaderEffect::Uncompiled;
989 return QQuickShaderEffect::Status(mgr->status());
992void QQuickShaderEffectPrivate::handleEvent(QEvent *event)
994 if (event->type() == QEvent::DynamicPropertyChange) {
995 const auto propertyName =
static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
996 for (
int i = 0; i < NShader; ++i) {
997 const auto mappedId = findMappedShaderVariableId(propertyName, Shader(i));
999 propertyChanged(*mappedId);
1004void QQuickShaderEffectPrivate::handleGeometryChanged(
const QRectF &,
const QRectF &)
1006 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1009QSGNode *QQuickShaderEffectPrivate::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
1011 Q_Q(QQuickShaderEffect);
1012 QSGShaderEffectNode *node =
static_cast<QSGShaderEffectNode *>(oldNode);
1014 if (q->width() <= 0 || q->height() <= 0) {
1020 if (m_inProgress[Vertex] || m_inProgress[Fragment])
1024 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1031 QSGRenderContext *rc = QQuickWindowPrivate::get(q->window())->context;
1032 node = rc->sceneGraphContext()->createShaderEffectNode(rc);
1034 qWarning(
"No shader effect node");
1037 m_dirty = QSGShaderEffectNode::DirtyShaderAll;
1038 QObject::connect(node, &QSGShaderEffectNode::textureChanged, q, [
this] { markGeometryDirtyAndUpdateIfSupportsAtlas(); });
1041 QSGShaderEffectNode::SyncData sd;
1043 sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
1044 sd.blending = m_blending;
1045 sd.vertex.shader = &m_shaders[Vertex];
1046 sd.vertex.dirtyConstants = &m_dirtyConstants[Vertex];
1047 sd.vertex.dirtyTextures = &m_dirtyTextures[Vertex];
1048 sd.fragment.shader = &m_shaders[Fragment];
1049 sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
1050 sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
1051 sd.materialTypeCacheKey = q->window();
1052 sd.viewCount = QQuickWindowPrivate::get(q->window())->multiViewCount();
1054 node->syncMaterial(&sd);
1056 if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
1057 node->setGeometry(
nullptr);
1058 m_dirty &= ~QSGShaderEffectNode::DirtyShaderMesh;
1059 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1062 if (m_dirty & QSGShaderEffectNode::DirtyShaderGeometry) {
1063 const QRectF rect(0, 0, q->width(), q->height());
1064 QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
1065 QSGGeometry *geometry = node->geometry();
1067 const QRectF srcRect = node->updateNormalizedTextureSubRect(m_supportsAtlasTextures);
1068 geometry = mesh->updateGeometry(geometry, 2, 0, srcRect, rect);
1070 node->setFlag(QSGNode::OwnsGeometry,
false);
1071 node->setGeometry(geometry);
1072 node->setFlag(QSGNode::OwnsGeometry,
true);
1074 m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
1078 for (
int i = 0; i < NShader; ++i) {
1079 m_dirtyConstants[i].clear();
1080 m_dirtyTextures[i].clear();
1086void QQuickShaderEffectPrivate::maybeUpdateShaders()
1088 Q_Q(QQuickShaderEffect);
1089 if (m_vertNeedsUpdate)
1090 m_vertNeedsUpdate = !updateShader(Vertex, m_vertShader);
1091 if (m_fragNeedsUpdate)
1092 m_fragNeedsUpdate = !updateShader(Fragment, m_fragShader);
1093 if (m_vertNeedsUpdate || m_fragNeedsUpdate) {
1100 if (!q->window() || !q->window()->isSceneGraphInitialized())
1105bool QQuickShaderEffectPrivate::updateUniformValue(
const QByteArray &name,
const QVariant &value,
1106 QSGShaderEffectNode *node)
1108 Q_Q(QQuickShaderEffect);
1109 const auto mappedId = findMappedShaderVariableId(name);
1113 const Shader type = Shader(mappedIdToShaderType(*mappedId));
1114 const int idx = mappedIdToIndex(*mappedId);
1117 m_shaders[type].varData[idx].value = value;
1120 QSet<
int> dirtyConstants[NShader];
1121 dirtyConstants[type].insert(idx);
1124 QSGShaderEffectNode::SyncData sd;
1125 sd.dirty = QSGShaderEffectNode::DirtyShaderConstant;
1126 sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
1127 sd.blending = m_blending;
1128 sd.vertex.shader = &m_shaders[Vertex];
1129 sd.vertex.dirtyConstants = &dirtyConstants[Vertex];
1130 sd.vertex.dirtyTextures = {};
1131 sd.fragment.shader = &m_shaders[Fragment];
1132 sd.fragment.dirtyConstants = &dirtyConstants[Fragment];
1133 sd.fragment.dirtyTextures = {};
1134 sd.materialTypeCacheKey = q->window();
1135 sd.viewCount = QQuickWindowPrivate::get(q->window())->multiViewCount();
1137 node->syncMaterial(&sd);
1142void QQuickShaderEffectPrivate::handleItemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
1148 if (change == QQuickItem::ItemSceneChange) {
1149 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1150 for (
const auto &vd : std::as_const(m_shaders[shaderType].varData)) {
1151 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1152 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1155 QQuickItemPrivate::get(source)->refWindow(value.window);
1157 QQuickItemPrivate::get(source)->derefWindow();
1165QSGGuiThreadShaderEffectManager *QQuickShaderEffectPrivate::shaderEffectManager()
const
1167 Q_Q(
const QQuickShaderEffect);
1170 if (QThread::currentThread() != q->thread())
1172 QQuickWindow *w = q->window();
1174 m_mgr = QQuickWindowPrivate::get(w)->context->sceneGraphContext()->createGuiThreadShaderEffectManager();
1176 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::logAndStatusChanged, q, &QQuickShaderEffect::logChanged);
1177 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::logAndStatusChanged, q, &QQuickShaderEffect::statusChanged);
1178 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::shaderCodePrepared, q,
1179 [
this](
bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
1180 const QUrl &loadUrl, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
1181 {
const_cast<QQuickShaderEffectPrivate *>(
this)->shaderCodePrepared(ok, typeHint, loadUrl, result); });
1188void QQuickShaderEffectPrivate::disconnectSignals(Shader shaderType)
1190 Q_Q(QQuickShaderEffect);
1191 for (
auto *mapper : m_mappers[shaderType]) {
1194 QObjectPrivate::disconnect(q, mapper->signalIndex(), &a);
1196 for (
const auto &vd : std::as_const(m_shaders[shaderType].varData)) {
1197 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1198 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1201 QQuickItemPrivate::get(source)->derefWindow();
1202 auto it = m_destroyedConnections.constFind(source);
1203 if (it != m_destroyedConnections.constEnd()) {
1204 QObject::disconnect(*it);
1205 m_destroyedConnections.erase(it);
1212void QQuickShaderEffectPrivate::clearMappers(QQuickShaderEffectPrivate::Shader shaderType)
1214 for (
auto *mapper : std::as_const(m_mappers[shaderType])) {
1216 mapper->destroyIfLastRef();
1218 m_mappers[shaderType].clear();
1222 const QByteArray &name,
int propertyIndex)
1225 if (propertyIndex == -1) {
1226 value = item->property(name);
1228 value = itemMetaObject->property(propertyIndex).read(item);
1233using QQuickShaderInfoCache = QHash<QUrl, QSGGuiThreadShaderEffectManager::ShaderInfo>;
1238 shaderInfoCache()->clear();
1241bool QQuickShaderEffectPrivate::updateShader(Shader shaderType,
const QUrl &fileUrl)
1243 Q_Q(QQuickShaderEffect);
1244 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1248 const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
1250 disconnectSignals(shaderType);
1252 m_shaders[shaderType].shaderInfo.variables.clear();
1253 m_shaders[shaderType].varData.clear();
1255 if (!fileUrl.isEmpty()) {
1256 const QQmlContext *context = qmlContext(q);
1257 const QUrl loadUrl = context ? context->resolvedUrl(fileUrl) : fileUrl;
1258 auto it = shaderInfoCache()->constFind(loadUrl);
1259 if (it != shaderInfoCache()->cend()) {
1260 m_shaders[shaderType].shaderInfo = *it;
1261 m_shaders[shaderType].hasShaderCode =
true;
1267 m_inProgress[shaderType] =
new QSGGuiThreadShaderEffectManager::ShaderInfo;
1268 const QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint =
1269 shaderType == Vertex ? QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex
1270 : QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
1275 mgr->prepareShaderCode(typeHint, loadUrl, m_inProgress[shaderType]);
1280 m_shaders[shaderType].hasShaderCode =
false;
1281 if (shaderType == Fragment) {
1287 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
1288 v.name = QByteArrayLiteral(
"source");
1290 v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
1291 : QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
1292 m_shaders[shaderType].shaderInfo.variables.append(v);
1296 updateShaderVars(shaderType);
1297 m_dirty |= QSGShaderEffectNode::DirtyShaders;
1302void QQuickShaderEffectPrivate::shaderCodePrepared(
bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
1303 const QUrl &loadUrl, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
1305 Q_Q(QQuickShaderEffect);
1306 const Shader shaderType = typeHint == QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? Vertex : Fragment;
1310 if (result != m_inProgress[shaderType]) {
1315 m_shaders[shaderType].shaderInfo = *result;
1317 m_inProgress[shaderType] =
nullptr;
1320 qWarning(
"ShaderEffect: shader preparation failed for %s\n%s\n",
1321 qPrintable(loadUrl.toString()), qPrintable(log()));
1322 m_shaders[shaderType].hasShaderCode =
false;
1326 m_shaders[shaderType].hasShaderCode =
true;
1327 shaderInfoCache()->insert(loadUrl, m_shaders[shaderType].shaderInfo);
1328 updateShaderVars(shaderType);
1329 m_dirty |= QSGShaderEffectNode::DirtyShaders;
1333void QQuickShaderEffectPrivate::updateShaderVars(Shader shaderType)
1335 Q_Q(QQuickShaderEffect);
1336 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1340 const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
1342 const int varCount = m_shaders[shaderType].shaderInfo.variables.size();
1343 m_shaders[shaderType].varData.resize(varCount);
1346 clearMappers(shaderType);
1348 QQmlPropertyCache::ConstPtr propCache = QQmlData::ensurePropertyCache(q);
1350 if (!m_itemMetaObject)
1351 m_itemMetaObject = q->metaObject();
1355 for (
int i = 0; i < varCount; ++i) {
1356 const auto &v(m_shaders[shaderType].shaderInfo.variables.at(i));
1357 QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
1358 const bool isSpecial = v.name.startsWith(
"qt_");
1360 if (v.name ==
"qt_Opacity")
1361 vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
1362 else if (v.name ==
"qt_Matrix")
1363 vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
1364 else if (v.name.startsWith(
"qt_SubRect_"))
1365 vd.specialType = QSGShaderEffectNode::VariableData::SubRect;
1372 if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
1373 if (texturesSeparate) {
1374 vd.specialType = QSGShaderEffectNode::VariableData::Unused;
1377 vd.specialType = QSGShaderEffectNode::VariableData::Source;
1379 }
else if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
1380 Q_ASSERT(texturesSeparate);
1381 vd.specialType = QSGShaderEffectNode::VariableData::Source;
1383 vd.specialType = QSGShaderEffectNode::VariableData::None;
1388 const QQmlPropertyData *pd =
nullptr;
1390 pd = propCache->property(QLatin1String(v.name),
nullptr,
nullptr);
1392 if (!pd->isFunction())
1393 propIdx = pd->coreIndex();
1397 if (pd && !pd->isFunction()) {
1398 if (pd->notifyIndex() == -1) {
1399 qWarning(
"QQuickShaderEffect: property '%s' does not have notification method!", v.name.constData());
1401 const int mappedId = indexToMappedId(shaderType, i);
1402 auto mapper =
new QtPrivate::EffectSlotMapper([
this, mappedId](){
1403 this->propertyChanged(mappedId);
1405 m_mappers[shaderType].append(mapper);
1406 mapper->setSignalIndex(m_itemMetaObject->property(propIdx).notifySignal().methodIndex());
1407 Q_ASSERT(q->metaObject() == m_itemMetaObject);
1408 bool ok = QObjectPrivate::connectImpl(q, pd->notifyIndex(), q,
nullptr, mapper,
1409 Qt::AutoConnection,
nullptr, m_itemMetaObject);
1411 qWarning() <<
"Failed to connect to property" << m_itemMetaObject->property(propIdx).name()
1412 <<
"(" << propIdx <<
", signal index" << pd->notifyIndex()
1413 <<
") of item" << q;
1418 if (!q->property(v.name.constData()).isValid())
1419 qWarning(
"ShaderEffect: '%s' does not have a matching property", v.name.constData());
1423 vd.propertyIndex = propIdx;
1424 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1425 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1426 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1429 QQuickItemPrivate::get(source)->refWindow(q->window());
1437 if (!m_destroyedConnections.contains(source))
1438 m_destroyedConnections.insert(source, QObject::connect(source, &QObject::destroyed, [
this](QObject *obj) { sourceDestroyed(obj); }));
1444std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name)
const
1446 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1447 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1448 for (
int idx = 0; idx < vars.size(); ++idx) {
1449 if (vars[idx].name == name)
1450 return indexToMappedId(shaderType, idx);
1457std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name, Shader shaderType)
const
1459 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1460 for (
int idx = 0; idx < vars.size(); ++idx) {
1461 if (vars[idx].name == name)
1462 return indexToMappedId(shaderType, idx);
1468bool QQuickShaderEffectPrivate::sourceIsUnique(QQuickItem *source, Shader typeToSkip,
int indexToSkip)
const
1470 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1471 for (
int idx = 0; idx < m_shaders[shaderType].varData.size(); ++idx) {
1472 if (shaderType != typeToSkip || idx != indexToSkip) {
1473 const auto &vd(m_shaders[shaderType].varData[idx]);
1474 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && qvariant_cast<QObject *>(vd.value) == source)
1482void QQuickShaderEffectPrivate::propertyChanged(
int mappedId)
1484 Q_Q(QQuickShaderEffect);
1485 const Shader type = Shader(mappedIdToShaderType(mappedId));
1486 const int idx = mappedIdToIndex(mappedId);
1487 const auto &v(m_shaders[type].shaderInfo.variables[idx]);
1488 auto &vd(m_shaders[type].varData[idx]);
1490 QVariant oldValue = vd.value;
1491 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1493 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1494 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(oldValue));
1497 QQuickItemPrivate::get(source)->derefWindow();
1501 if (sourceIsUnique(source, type, idx)) {
1502 auto it = m_destroyedConnections.constFind(source);
1503 if (it != m_destroyedConnections.constEnd()) {
1504 QObject::disconnect(*it);
1505 m_destroyedConnections.erase(it);
1510 source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1517 QQuickItemPrivate::get(source)->refWindow(q->window());
1518 if (!m_destroyedConnections.contains(source))
1519 m_destroyedConnections.insert(source, QObject::connect(source, &QObject::destroyed, [
this](QObject *obj) { sourceDestroyed(obj); }));
1522 m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
1523 m_dirtyTextures[type].insert(idx);
1526 m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
1527 m_dirtyConstants[type].insert(idx);
1533void QQuickShaderEffectPrivate::sourceDestroyed(QObject *object)
1535 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1536 for (
auto &vd : m_shaders[shaderType].varData) {
1537 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && vd.value.canConvert<QObject *>()) {
1538 if (qvariant_cast<QObject *>(vd.value) == object)
1539 vd.value = QVariant();
1545void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdate()
1547 Q_Q(QQuickShaderEffect);
1548 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1552void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdateIfSupportsAtlas()
1554 if (m_supportsAtlasTextures)
1555 markGeometryDirtyAndUpdate();
1560#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)