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
503
504
505
506
526 static void impl(
int which, QSlotObjectBase *this_, QObject *,
void **a,
bool *ret)
539 case NumOperations: ;
545QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
546 : QQuickItem(*
new QQuickShaderEffectPrivate, parent)
548 setFlag(QQuickItem::ItemHasContents);
551QQuickShaderEffect::~QQuickShaderEffect()
553 Q_D(QQuickShaderEffect);
554 d->inDestructor =
true;
556 for (
int i = 0; i < QQuickShaderEffectPrivate::NShader; ++i) {
557 d->disconnectSignals(QQuickShaderEffectPrivate::Shader(i));
558 d->clearMappers(QQuickShaderEffectPrivate::Shader(i));
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
583QUrl QQuickShaderEffect::fragmentShader()
const
585 Q_D(
const QQuickShaderEffect);
586 return d->fragmentShader();
589void QQuickShaderEffect::setFragmentShader(
const QUrl &fileUrl)
591 Q_D(QQuickShaderEffect);
592 d->setFragmentShader(fileUrl);
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
613QUrl QQuickShaderEffect::vertexShader()
const
615 Q_D(
const QQuickShaderEffect);
616 return d->vertexShader();
619void QQuickShaderEffect::setVertexShader(
const QUrl &fileUrl)
621 Q_D(QQuickShaderEffect);
622 d->setVertexShader(fileUrl);
626
627
628
629
630
631
632
634bool QQuickShaderEffect::blending()
const
636 Q_D(
const QQuickShaderEffect);
637 return d->blending();
640void QQuickShaderEffect::setBlending(
bool enable)
642 Q_D(QQuickShaderEffect);
643 d->setBlending(enable);
647
648
649
650
651
652
653
654
655
656
657
659QVariant QQuickShaderEffect::mesh()
const
661 Q_D(
const QQuickShaderEffect);
665void QQuickShaderEffect::setMesh(
const QVariant &mesh)
667 Q_D(QQuickShaderEffect);
672
673
674
675
676
677
678
679
680
681
683QQuickShaderEffect::CullMode QQuickShaderEffect::cullMode()
const
685 Q_D(
const QQuickShaderEffect);
686 return d->cullMode();
689void QQuickShaderEffect::setCullMode(CullMode face)
691 Q_D(QQuickShaderEffect);
692 return d->setCullMode(face);
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
716bool QQuickShaderEffect::supportsAtlasTextures()
const
718 Q_D(
const QQuickShaderEffect);
719 return d->supportsAtlasTextures();
722void QQuickShaderEffect::setSupportsAtlasTextures(
bool supports)
724 Q_D(QQuickShaderEffect);
725 d->setSupportsAtlasTextures(supports);
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
769QString QQuickShaderEffect::log()
const
771 Q_D(
const QQuickShaderEffect);
775QQuickShaderEffect::Status QQuickShaderEffect::status()
const
777 Q_D(
const QQuickShaderEffect);
781bool QQuickShaderEffect::event(QEvent *e)
783 Q_D(QQuickShaderEffect);
785 return QQuickItem::event(e);
788void QQuickShaderEffect::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
790 Q_D(QQuickShaderEffect);
791 d->handleGeometryChanged(newGeometry, oldGeometry);
792 QQuickItem::geometryChange(newGeometry, oldGeometry);
795QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
797 Q_D(QQuickShaderEffect);
798 return d->handleUpdatePaintNode(oldNode, updatePaintNodeData);
801void QQuickShaderEffect::componentComplete()
803 Q_D(QQuickShaderEffect);
804 d->maybeUpdateShaders();
805 QQuickItem::componentComplete();
808void QQuickShaderEffect::itemChange(ItemChange change,
const ItemChangeData &value)
810 Q_D(QQuickShaderEffect);
811 d->handleItemChange(change, value);
812 QQuickItem::itemChange(change, value);
815bool QQuickShaderEffect::isComponentComplete()
const
817 return QQuickItem::isComponentComplete();
820bool QQuickShaderEffect::updateUniformValue(
const QByteArray &name,
const QVariant &value)
822 auto node =
static_cast<QSGShaderEffectNode *>(QQuickItemPrivate::get(
this)->paintNode);
826 Q_D(QQuickShaderEffect);
827 return d->updateUniformValue(name, value, node);
830void QQuickShaderEffectPrivate::updatePolish()
832 Q_Q(QQuickShaderEffect);
835 maybeUpdateShaders();
840 return idx | (shaderType << 16);
845 return mappedId & 0xFFFF;
850 return mappedId >> 16;
853QQuickShaderEffectPrivate::QQuickShaderEffectPrivate()
854 : m_meshResolution(1, 1)
856 , m_cullMode(QQuickShaderEffect::NoCulling)
858 , m_supportsAtlasTextures(
false)
860 , m_fragNeedsUpdate(
true)
861 , m_vertNeedsUpdate(
true)
863 qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>(
"ShaderInfo::Type");
864 for (
int i = 0; i < NShader; ++i)
865 m_inProgress[i] =
nullptr;
868QQuickShaderEffectPrivate::~QQuickShaderEffectPrivate()
870 Q_ASSERT(m_mgr ==
nullptr);
873void QQuickShaderEffectPrivate::setFragmentShader(
const QUrl &fileUrl)
875 Q_Q(QQuickShaderEffect);
876 if (m_fragShader == fileUrl)
879 m_fragShader = fileUrl;
881 m_fragNeedsUpdate =
true;
882 if (q->isComponentComplete())
883 maybeUpdateShaders();
885 emit q->fragmentShaderChanged();
888void QQuickShaderEffectPrivate::setVertexShader(
const QUrl &fileUrl)
890 Q_Q(QQuickShaderEffect);
891 if (m_vertShader == fileUrl)
894 m_vertShader = fileUrl;
896 m_vertNeedsUpdate =
true;
897 if (q->isComponentComplete())
898 maybeUpdateShaders();
900 emit q->vertexShaderChanged();
903void QQuickShaderEffectPrivate::setBlending(
bool enable)
905 Q_Q(QQuickShaderEffect);
906 if (m_blending == enable)
911 emit q->blendingChanged();
914QVariant QQuickShaderEffectPrivate::mesh()
const
916 return m_mesh ? QVariant::fromValue(
static_cast<QObject *>(m_mesh))
917 : QVariant::fromValue(m_meshResolution);
920void QQuickShaderEffectPrivate::setMesh(
const QVariant &mesh)
922 Q_Q(QQuickShaderEffect);
923 QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
924 if (newMesh && newMesh == m_mesh)
928 QObject::disconnect(m_meshConnection);
933 m_meshConnection = QObject::connect(m_mesh, &QQuickShaderEffectMesh::geometryChanged, q,
934 [
this] { markGeometryDirtyAndUpdate(); });
936 if (mesh.canConvert<QSize>()) {
937 m_meshResolution = mesh.toSize();
939 QList<QByteArray> res = mesh.toByteArray().split(
'x');
940 bool ok = res.size() == 2;
942 int w = res.at(0).toInt(&ok);
944 int h = res.at(1).toInt(&ok);
946 m_meshResolution = QSize(w, h);
950 qWarning(
"ShaderEffect: mesh property must be a size or an object deriving from QQuickShaderEffectMesh");
952 m_defaultMesh.setResolution(m_meshResolution);
955 m_dirty |= QSGShaderEffectNode::DirtyShaderMesh;
958 emit q->meshChanged();
961void QQuickShaderEffectPrivate::setCullMode(QQuickShaderEffect::CullMode face)
963 Q_Q(QQuickShaderEffect);
964 if (m_cullMode == face)
969 emit q->cullModeChanged();
972void QQuickShaderEffectPrivate::setSupportsAtlasTextures(
bool supports)
974 Q_Q(QQuickShaderEffect);
975 if (m_supportsAtlasTextures == supports)
978 m_supportsAtlasTextures = supports;
979 markGeometryDirtyAndUpdate();
980 emit q->supportsAtlasTexturesChanged();
983QString QQuickShaderEffectPrivate::parseLog()
985 maybeUpdateShaders();
989QString QQuickShaderEffectPrivate::log()
const
991 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
998QQuickShaderEffect::Status QQuickShaderEffectPrivate::status()
const
1000 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1002 return QQuickShaderEffect::Uncompiled;
1004 return QQuickShaderEffect::Status(mgr->status());
1007void QQuickShaderEffectPrivate::handleEvent(QEvent *event)
1009 if (event->type() == QEvent::DynamicPropertyChange) {
1010 const auto propertyName =
static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
1011 for (
int i = 0; i < NShader; ++i) {
1012 const auto mappedId = findMappedShaderVariableId(propertyName, Shader(i));
1014 propertyChanged(*mappedId);
1019void QQuickShaderEffectPrivate::handleGeometryChanged(
const QRectF &,
const QRectF &)
1021 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1024QSGNode *QQuickShaderEffectPrivate::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
1026 Q_Q(QQuickShaderEffect);
1027 QSGShaderEffectNode *node =
static_cast<QSGShaderEffectNode *>(oldNode);
1029 if (q->width() <= 0 || q->height() <= 0) {
1035 if (m_inProgress[Vertex] || m_inProgress[Fragment])
1039 QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
1046 QSGRenderContext *rc = QQuickWindowPrivate::get(q->window())->context;
1047 node = rc->sceneGraphContext()->createShaderEffectNode(rc);
1049 qWarning(
"No shader effect node");
1052 m_dirty = QSGShaderEffectNode::DirtyShaderAll;
1053 QObject::connect(node, &QSGShaderEffectNode::textureChanged, q, [
this] { markGeometryDirtyAndUpdateIfSupportsAtlas(); });
1056 QSGShaderEffectNode::SyncData sd;
1058 sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
1059 sd.blending = m_blending;
1060 sd.vertex.shader = &m_shaders[Vertex];
1061 sd.vertex.dirtyConstants = &m_dirtyConstants[Vertex];
1062 sd.vertex.dirtyTextures = &m_dirtyTextures[Vertex];
1063 sd.fragment.shader = &m_shaders[Fragment];
1064 sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
1065 sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
1066 sd.materialTypeCacheKey = q->window();
1067 sd.viewCount = QQuickWindowPrivate::get(q->window())->multiViewCount();
1069 node->syncMaterial(&sd);
1071 if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
1072 node->setGeometry(
nullptr);
1073 m_dirty &= ~QSGShaderEffectNode::DirtyShaderMesh;
1074 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1077 if (m_dirty & QSGShaderEffectNode::DirtyShaderGeometry) {
1078 const QRectF rect(0, 0, q->width(), q->height());
1079 QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
1080 QSGGeometry *geometry = node->geometry();
1082 const QRectF srcRect = node->updateNormalizedTextureSubRect(m_supportsAtlasTextures);
1083 geometry = mesh->updateGeometry(geometry, 2, 0, srcRect, rect);
1085 node->setFlag(QSGNode::OwnsGeometry,
false);
1086 node->setGeometry(geometry);
1087 node->setFlag(QSGNode::OwnsGeometry,
true);
1089 m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
1093 for (
int i = 0; i < NShader; ++i) {
1094 m_dirtyConstants[i].clear();
1095 m_dirtyTextures[i].clear();
1101void QQuickShaderEffectPrivate::maybeUpdateShaders()
1103 Q_Q(QQuickShaderEffect);
1104 if (m_vertNeedsUpdate)
1105 m_vertNeedsUpdate = !updateShader(Vertex, m_vertShader);
1106 if (m_fragNeedsUpdate)
1107 m_fragNeedsUpdate = !updateShader(Fragment, m_fragShader);
1108 if (m_vertNeedsUpdate || m_fragNeedsUpdate) {
1115 if (!q->window() || !q->window()->isSceneGraphInitialized())
1120bool QQuickShaderEffectPrivate::updateUniformValue(
const QByteArray &name,
const QVariant &value,
1121 QSGShaderEffectNode *node)
1123 Q_Q(QQuickShaderEffect);
1124 const auto mappedId = findMappedShaderVariableId(name);
1128 const Shader type = Shader(mappedIdToShaderType(*mappedId));
1129 const int idx = mappedIdToIndex(*mappedId);
1132 m_shaders[type].varData[idx].value = value;
1135 QSet<
int> dirtyConstants[NShader];
1136 dirtyConstants[type].insert(idx);
1139 QSGShaderEffectNode::SyncData sd;
1140 sd.dirty = QSGShaderEffectNode::DirtyShaderConstant;
1141 sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
1142 sd.blending = m_blending;
1143 sd.vertex.shader = &m_shaders[Vertex];
1144 sd.vertex.dirtyConstants = &dirtyConstants[Vertex];
1145 sd.vertex.dirtyTextures = {};
1146 sd.fragment.shader = &m_shaders[Fragment];
1147 sd.fragment.dirtyConstants = &dirtyConstants[Fragment];
1148 sd.fragment.dirtyTextures = {};
1149 sd.materialTypeCacheKey = q->window();
1150 sd.viewCount = QQuickWindowPrivate::get(q->window())->multiViewCount();
1152 node->syncMaterial(&sd);
1157void QQuickShaderEffectPrivate::handleItemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
1163 if (change == QQuickItem::ItemSceneChange) {
1164 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1165 for (
const auto &vd : std::as_const(m_shaders[shaderType].varData)) {
1166 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1167 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1170 QQuickItemPrivate::get(source)->refWindow(value.window);
1172 QQuickItemPrivate::get(source)->derefWindow();
1180QSGGuiThreadShaderEffectManager *QQuickShaderEffectPrivate::shaderEffectManager()
const
1182 Q_Q(
const QQuickShaderEffect);
1185 if (QThread::currentThread() != q->thread())
1187 QQuickWindow *w = q->window();
1189 QSGRenderContext *renderContext = QQuickWindowPrivate::get(w)->context;
1190 if (QSGContext *sgContext = renderContext->sceneGraphContext())
1191 m_mgr = sgContext->createGuiThreadShaderEffectManager();
1193 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::logAndStatusChanged, q, &QQuickShaderEffect::logChanged);
1194 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::logAndStatusChanged, q, &QQuickShaderEffect::statusChanged);
1195 QObject::connect(m_mgr, &QSGGuiThreadShaderEffectManager::shaderCodePrepared, q,
1196 [
this](
bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
1197 const QUrl &loadUrl, QSGGuiThreadShaderEffectManager::ShaderInfo *result)
1198 {
const_cast<QQuickShaderEffectPrivate *>(
this)->shaderCodePrepared(ok, typeHint, loadUrl, result); });
1205void QQuickShaderEffectPrivate::disconnectSignals(Shader shaderType)
1207 Q_Q(QQuickShaderEffect);
1208 for (
auto *mapper : m_mappers[shaderType]) {
1211 QObjectPrivate::disconnect(q, mapper->signalIndex(), &a);
1213 for (
const auto &vd : std::as_const(m_shaders[shaderType].varData)) {
1214 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1215 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1218 QQuickItemPrivate::get(source)->derefWindow();
1219 QObject::disconnect(m_destroyedConnections.take(source));
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,
1452 connect(source, &QObject::destroyed,
1453 this, &QQuickShaderEffectPrivate::sourceDestroyed));
1459std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name)
const
1461 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1462 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1463 for (
int idx = 0; idx < vars.size(); ++idx) {
1464 if (vars[idx].name == name)
1465 return indexToMappedId(shaderType, idx);
1472std::optional<
int> QQuickShaderEffectPrivate::findMappedShaderVariableId(
const QByteArray &name, Shader shaderType)
const
1474 const auto &vars = m_shaders[shaderType].shaderInfo.variables;
1475 for (
int idx = 0; idx < vars.size(); ++idx) {
1476 if (vars[idx].name == name)
1477 return indexToMappedId(shaderType, idx);
1483bool QQuickShaderEffectPrivate::sourceIsUnique(QQuickItem *source, Shader typeToSkip,
int indexToSkip)
const
1485 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1486 for (
int idx = 0; idx < m_shaders[shaderType].varData.size(); ++idx) {
1487 if (shaderType != typeToSkip || idx != indexToSkip) {
1488 const auto &vd(m_shaders[shaderType].varData[idx]);
1489 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && qvariant_cast<QObject *>(vd.value) == source)
1497void QQuickShaderEffectPrivate::propertyChanged(
int mappedId)
1499 Q_Q(QQuickShaderEffect);
1500 const Shader type = Shader(mappedIdToShaderType(mappedId));
1501 const int idx = mappedIdToIndex(mappedId);
1502 const auto &v(m_shaders[type].shaderInfo.variables[idx]);
1503 auto &vd(m_shaders[type].varData[idx]);
1505 QVariant oldValue = vd.value;
1506 vd.value = getValueFromProperty(q, m_itemMetaObject, v.name, vd.propertyIndex);
1508 if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
1509 QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(oldValue));
1512 QQuickItemPrivate::get(source)->derefWindow();
1516 if (sourceIsUnique(source, type, idx))
1517 QObject::disconnect(m_destroyedConnections.take(source));
1520 source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
1527 QQuickItemPrivate::get(source)->refWindow(q->window());
1528 if (!m_destroyedConnections.contains(source))
1529 m_destroyedConnections.insert(source,
1530 connect(source, &QObject::destroyed,
1531 this, &QQuickShaderEffectPrivate::sourceDestroyed));
1534 m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
1535 m_dirtyTextures[type].insert(idx);
1538 m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
1539 m_dirtyConstants[type].insert(idx);
1545void QQuickShaderEffectPrivate::sourceDestroyed(QObject *object)
1547 for (
int shaderType = 0; shaderType < NShader; ++shaderType) {
1548 for (
auto &vd : m_shaders[shaderType].varData) {
1549 if (vd.specialType == QSGShaderEffectNode::VariableData::Source && vd.value.canConvert<QObject *>()) {
1550 if (qvariant_cast<QObject *>(vd.value) == object)
1551 vd.value = QVariant();
1557void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdate()
1559 Q_Q(QQuickShaderEffect);
1560 m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
1564void QQuickShaderEffectPrivate::markGeometryDirtyAndUpdateIfSupportsAtlas()
1566 if (m_supportsAtlasTextures)
1567 markGeometryDirtyAndUpdate();
1572#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)