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 QObject::disconnect(m_destroyedConnections.take(source));
1221void QQuickShaderEffectPrivate::clearMappers(QQuickShaderEffectPrivate::Shader shaderType)
1223 for (
auto *mapper : std::as_const(m_mappers[shaderType])) {
1225 mapper->destroyIfLastRef();
1227 m_mappers[shaderType].clear();
1231 const QByteArray &name,
int propertyIndex)
1234 if (propertyIndex == -1) {
1235 value = item->property(name);
1237 value = itemMetaObject->property(propertyIndex).read(item);
1242using QQuickShaderInfoCache = QHash<QUrl, QSGGuiThreadShaderEffectManager::ShaderInfo>;
1247 shaderInfoCache()->clear();
1250bool QQuickShaderEffectPrivate::updateShader(Shader shaderType,
const QUrl &fileUrl)
1252 Q_Q(QQuickShaderEffect);
1253 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1257 const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
1259 disconnectSignals(shaderType);
1261 m_shaders[shaderType].shaderInfo.variables.clear();
1262 m_shaders[shaderType].varData.clear();
1264 if (!fileUrl.isEmpty()) {
1265 const QQmlContext *context = qmlContext(q);
1266 const QUrl loadUrl = context ? context->resolvedUrl(fileUrl) : fileUrl;
1267 auto it = shaderInfoCache()->constFind(loadUrl);
1268 if (it != shaderInfoCache()->cend()) {
1269 m_shaders[shaderType].shaderInfo = *it;
1270 m_shaders[shaderType].hasShaderCode =
true;
1276 m_inProgress[shaderType] =
new QSGGuiThreadShaderEffectManager::ShaderInfo;
1277 const QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint =
1278 shaderType == Vertex ? QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex
1279 : QSGGuiThreadShaderEffectManager::ShaderInfo::TypeFragment;
1284 mgr->prepareShaderCode(typeHint, loadUrl, m_inProgress[shaderType]);
1289 m_shaders[shaderType].hasShaderCode =
false;
1290 if (shaderType == Fragment) {
1296 QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
1297 v.name = QByteArrayLiteral(
"source");
1299 v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
1300 : QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
1301 m_shaders[shaderType].shaderInfo.variables.append(v);
1305 updateShaderVars(shaderType);
1306 m_dirty |= QSGShaderEffectNode::DirtyShaders;
1311void QQuickShaderEffectPrivate::shaderCodePrepared(
bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
1312 const QUrl &loadUrl, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
1314 Q_Q(QQuickShaderEffect);
1315 const Shader shaderType = typeHint == QSGGuiThreadShaderEffectManager::ShaderInfo::TypeVertex ? Vertex : Fragment;
1319 if (result != m_inProgress[shaderType]) {
1324 m_shaders[shaderType].shaderInfo = *result;
1326 m_inProgress[shaderType] =
nullptr;
1329 qWarning(
"ShaderEffect: shader preparation failed for %s\n%s\n",
1330 qPrintable(loadUrl.toString()), qPrintable(log()));
1331 m_shaders[shaderType].hasShaderCode =
false;
1335 m_shaders[shaderType].hasShaderCode =
true;
1336 shaderInfoCache()->insert(loadUrl, m_shaders[shaderType].shaderInfo);
1337 updateShaderVars(shaderType);
1338 m_dirty |= QSGShaderEffectNode::DirtyShaders;
1342void QQuickShaderEffectPrivate::updateShaderVars(Shader shaderType)
1344 Q_Q(QQuickShaderEffect);
1345 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1349 const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
1351 const int varCount = m_shaders[shaderType].shaderInfo.variables.size();
1352 m_shaders[shaderType].varData.resize(varCount);
1355 clearMappers(shaderType);
1357 QQmlPropertyCache::ConstPtr propCache = QQmlData::ensurePropertyCache(q);
1359 if (!m_itemMetaObject)
1360 m_itemMetaObject = q->metaObject();
1364 for (
int i = 0; i < varCount; ++i) {
1365 const auto &v(m_shaders[shaderType].shaderInfo.variables.at(i));
1366 QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
1367 const bool isSpecial = v.name.startsWith(
"qt_");
1369 if (v.name ==
"qt_Opacity")
1370 vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
1371 else if (v.name ==
"qt_Matrix")
1372 vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
1373 else if (v.name.startsWith(
"qt_SubRect_"))
1374 vd.specialType = QSGShaderEffectNode::VariableData::SubRect;
1381 if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
1382 if (texturesSeparate) {
1383 vd.specialType = QSGShaderEffectNode::VariableData::Unused;
1386 vd.specialType = QSGShaderEffectNode::VariableData::Source;
1388 }
else if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
1389 Q_ASSERT(texturesSeparate);
1390 vd.specialType = QSGShaderEffectNode::VariableData::Source;
1392 vd.specialType = QSGShaderEffectNode::VariableData::None;
1397 const QQmlPropertyData *pd =
nullptr;
1399 pd = propCache->property(QLatin1String(v.name),
nullptr,
nullptr);
1401 if (!pd->isFunction())
1402 propIdx = pd->coreIndex();
1406 if (pd && !pd->isFunction()) {
1407 if (pd->notifyIndex() == -1) {
1408 qWarning(
"QQuickShaderEffect: property '%s' does not have notification method!", v.name.constData());
1410 const int mappedId = indexToMappedId(shaderType, i);
1411 auto mapper =
new QtPrivate::EffectSlotMapper([
this, mappedId](){
1412 this->propertyChanged(mappedId);
1414 m_mappers[shaderType].append(mapper);
1415 mapper->setSignalIndex(m_itemMetaObject->property(propIdx).notifySignal().methodIndex());
1416 Q_ASSERT(q->metaObject() == m_itemMetaObject);
1417 bool ok = QObjectPrivate::connectImpl(q, pd->notifyIndex(), q,
nullptr, mapper,
1418 Qt::AutoConnection,
nullptr, m_itemMetaObject);
1420 qWarning() <<
"Failed to connect to property" << m_itemMetaObject->property(propIdx).name()
1421 <<
"(" << propIdx <<
", signal index" << pd->notifyIndex()
1422 <<
") of item" << q;
1427 if (!q->property(v.name.constData()).isValid())
1428 qWarning(
"ShaderEffect: '%s' does not have a matching property", v.name.constData());
1432 vd.propertyIndex = propIdx;
1433 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1434 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1435 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1438 QQuickItemPrivate::get(source)->refWindow(q->window());
1446 if (!m_destroyedConnections.contains(source))
1447 m_destroyedConnections.insert(source,
1448 connect(source, &QObject::destroyed,
1449 this, &QQuickShaderEffectPrivate::sourceDestroyed));
1455std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name)
const
1457 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1458 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1459 for (
int idx = 0; idx < vars.size(); ++idx) {
1460 if (vars[idx].name == name)
1461 return indexToMappedId(shaderType, idx);
1468std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name, Shader shaderType)
const
1470 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1471 for (
int idx = 0; idx < vars.size(); ++idx) {
1472 if (vars[idx].name == name)
1473 return indexToMappedId(shaderType, idx);
1479bool QQuickShaderEffectPrivate::sourceIsUnique(QQuickItem *source, Shader typeToSkip,
int indexToSkip)
const
1481 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1482 for (
int idx = 0; idx < m_shaders[shaderType].varData.size(); ++idx) {
1483 if (shaderType != typeToSkip || idx != indexToSkip) {
1484 const auto &vd(m_shaders[shaderType].varData[idx]);
1485 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && qvariant_cast<QObject *>(vd.value) == source)
1493void QQuickShaderEffectPrivate::propertyChanged(
int mappedId)
1495 Q_Q(QQuickShaderEffect);
1496 const Shader type = Shader(mappedIdToShaderType(mappedId));
1497 const int idx = mappedIdToIndex(mappedId);
1498 const auto &v(m_shaders[type].shaderInfo.variables[idx]);
1499 auto &vd(m_shaders[type].varData[idx]);
1501 QVariant oldValue = vd.value;
1502 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1504 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1505 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(oldValue));
1508 QQuickItemPrivate::get(source)->derefWindow();
1512 if (sourceIsUnique(source, type, idx))
1513 QObject::disconnect(m_destroyedConnections.take(source));
1516 source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1523 QQuickItemPrivate::get(source)->refWindow(q->window());
1524 if (!m_destroyedConnections.contains(source))
1525 m_destroyedConnections.insert(source,
1526 connect(source, &QObject::destroyed,
1527 this, &QQuickShaderEffectPrivate::sourceDestroyed));
1530 m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
1531 m_dirtyTextures[type].insert(idx);
1534 m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
1535 m_dirtyConstants[type].insert(idx);
1541void QQuickShaderEffectPrivate::sourceDestroyed(QObject *object)
1543 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1544 for (
auto &vd : m_shaders[shaderType].varData) {
1545 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && vd.value.canConvert<QObject *>()) {
1546 if (qvariant_cast<QObject *>(vd.value) == object)
1547 vd.value = QVariant();
1553void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdate()
1555 Q_Q(QQuickShaderEffect);
1556 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1560void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdateIfSupportsAtlas()
1562 if (m_supportsAtlasTextures)
1563 markGeometryDirtyAndUpdate();
1568#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)