110QQuick3DRenderPass::AugmentSplitResult QQuick3DRenderPass::splitAugmentShader(
const QByteArray &augment,
111 QByteArray &preamble,
123 QSSGShaderTokenizer tok;
124 tok.initialize(augment.constData());
126 const char *
const begin = augment.constData();
127 const char *
const end = begin + augment.size();
129 const char *funcStart =
nullptr;
130 const char *bodyStart =
nullptr;
131 const char *bodyEnd =
nullptr;
132 const char *afterFunc =
nullptr;
134 const char *prevIdentStart =
nullptr;
135 QByteArrayView prevIdent;
137 for (QSSGShaderTokenizer::Token t = tok.next(); t != QSSGShaderTokenizer::Token_EOF; t = tok.next()) {
138 if (t != QSSGShaderTokenizer::Token_Identifier)
141 const QByteArrayView id(tok.identifier, tok.pos - tok.identifier);
144 if (id == QByteArrayLiteral(
"MAIN_FRAGMENT_AUGMENT") && prevIdent == QByteArrayLiteral(
"void")) {
145 funcStart = prevIdentStart;
148 QSSGShaderTokenizer::Token n = tok.next();
149 while (n != QSSGShaderTokenizer::Token_EOF
150 && n != QSSGShaderTokenizer::Token_OpenBrace
151 && n != QSSGShaderTokenizer::Token_SemiColon) {
154 if (n == QSSGShaderTokenizer::Token_OpenBrace) {
158 for (QSSGShaderTokenizer::Token b = tok.next(); b != QSSGShaderTokenizer::Token_EOF; b = tok.next()) {
159 if (b == QSSGShaderTokenizer::Token_OpenBrace) {
161 }
else if (b == QSSGShaderTokenizer::Token_CloseBrace) {
163 bodyEnd = tok.pos - 1;
173 prevIdentStart = tok.identifier;
178 return AugmentSplitResult::FunctionNotFound;
180 return AugmentSplitResult::OpeningBraceNotFound;
182 return AugmentSplitResult::ClosingBraceNotFound;
184 body = QByteArray(bodyStart, bodyEnd - bodyStart);
185 preamble = QByteArray(begin, funcStart - begin);
186 preamble += QByteArray(afterFunc, end - afterFunc);
187 return AugmentSplitResult::Ok;
190QSSGRenderGraphObject *QQuick3DRenderPass::updateSpatialNode(QSSGRenderGraphObject *node)
192 QSSGRenderUserPass *renderPassNode =
static_cast<QSSGRenderUserPass *>(node);
194 bool newBackendNode =
false;
195 if (!renderPassNode) {
196 renderPassNode =
new QSSGRenderUserPass;
197 newBackendNode =
true;
205 const bool isSubPass = (m_subRenderPassRef > 0);
206 const bool subPassChanged = (renderPassNode->role == QSSGRenderUserPass::Role::SubPass) != isSubPass;
208 renderPassNode->role = isSubPass ? QSSGRenderUserPass::Role::SubPass : QSSGRenderUserPass::Role::TopLevel;
210 const bool fullUpdate = newBackendNode || subPassChanged || (m_dirtyAttributes & Dirty::TextureDirty) || (m_dirtyAttributes & CommandsDirty);
212 auto &shaderAugmentation = renderPassNode->shaderAugmentation;
213 auto &uniformProps = shaderAugmentation.propertyUniforms;
219 uniformProps = extractProperties();
222 renderPassNode->resetCommands();
223 clearDirty(Dirty::CommandsDirty);
224 for (QQuick3DShaderUtilsRenderCommand *command : std::as_const(m_commands)) {
225 if (
auto *cmd = command->cloneCommand())
226 renderPassNode->commands.push_back(cmd);
228 markDirty(CommandsDirty,
true);
234 if (QQuick3DSceneManager *sceneManager = QQuick3DObjectPrivate::get(
this)->sceneManager)
235 sceneManager->userRenderPassesDirty =
true;
239 if (m_dirtyAttributes & Dirty::PropertyDirty) {
240 for (
const auto &prop : std::as_const(uniformProps)) {
241 auto p = metaObject()->property(prop.pid);
242 if (Q_LIKELY(p.isValid())) {
243 QVariant v = p.read(
this);
245 if (v.metaType().id() == qMetaTypeId<QQuick3DTexture *>()) {
246 QQuick3DTexture *tex = v.value<QQuick3DTexture *>();
247 auto *po = QQuick3DObjectPrivate::get(tex);
248 QSSGRenderImage *ri =
static_cast<QSSGRenderImage *>(po->spatialNode);
249 prop.value = QVariant::fromValue(ri);
257 clearDirty(Dirty(Dirty::PropertyDirty | Dirty::TextureDirty));
261 if (m_dirtyAttributes & Dirty::ClearDirty) {
262 renderPassNode->renderTargetFlags = QRhiTextureRenderTarget::Flags(m_renderTargetFlags.toInt());
263 renderPassNode->clearColor = m_clearColor;
264 renderPassNode->depthStencilClearValue = { m_depthClearValue, m_stencilClearValue };
266 clearDirty(Dirty::ClearDirty);
269 if (m_dirtyAttributes & Dirty::PassTypeDirty) {
270 switch (m_passMode) {
272 renderPassNode->passMode = QSSGRenderUserPass::UserPass;
275 renderPassNode->passMode = QSSGRenderUserPass::SkyboxPass;
278 renderPassNode->passMode = QSSGRenderUserPass::Item2DPass;
282 clearDirty(Dirty::PassTypeDirty);
286 if (m_passMode != UserPass)
287 return renderPassNode;
289 renderPassNode->materialMode = QSSGRenderUserPass::MaterialModes(m_materialMode);
290 clearDirty(Dirty::MaterialModeDirty);
292 if (renderPassNode->materialMode == QSSGRenderUserPass::OverrideMaterial) {
293 clearDirty(Dirty::OverrideMaterialDirty);
294 if (m_overrideMaterial) {
296 QSSGRenderGraphObject *graphObject = QQuick3DObjectPrivate::get(m_overrideMaterial)->spatialNode;
298 renderPassNode->overrideMaterial = graphObject;
300 markDirty(OverrideMaterialDirty,
true);
303 renderPassNode->overrideMaterial =
nullptr;
305 }
else if (renderPassNode->materialMode == QSSGRenderUserPass::OriginalMaterial) {
307 }
else if (renderPassNode->materialMode == QSSGRenderUserPass::AugmentMaterial) {
309 if (m_dirtyAttributes & AugmentShaderDirty) {
310 QByteArray augmentSnippet;
311 QByteArray augmentPreamble;
312 if (!m_augmentShader.isEmpty()) {
313 const QQmlContext *context = qmlContext(
this);
314 QByteArray shaderPathKey(
"augment material --");
315 QByteArray augment = QSSGShaderUtils::resolveShader(m_augmentShader, context, shaderPathKey);
317 switch (QQuick3DRenderPass::splitAugmentShader(augment, augmentPreamble, augmentSnippet)) {
318 case AugmentSplitResult::Ok:
320 case AugmentSplitResult::FunctionNotFound:
321 qWarning(
"QQuick3DRenderPass: Could not find MAIN_FRAGMENT_AUGMENT() function in shader %s", qPrintable(m_augmentShader.toString()));
323 case AugmentSplitResult::OpeningBraceNotFound:
324 qWarning(
"QQuick3DRenderPass: Could not find the opening brace of MAIN_FRAGMENT_AUGMENT() in shader %s", qPrintable(m_augmentShader.toString()));
326 case AugmentSplitResult::ClosingBraceNotFound:
327 qWarning(
"QQuick3DRenderPass: Could not find the closing brace of MAIN_FRAGMENT_AUGMENT() in shader %s", qPrintable(m_augmentShader.toString()));
332 renderPassNode->shaderAugmentation.body = augmentSnippet;
333 renderPassNode->shaderAugmentation.preamble = augmentPreamble;
334 renderPassNode->markDirty(QSSGRenderUserPass::DirtyFlag::ShaderDirty);
336 clearDirty(Dirty::AugmentShaderDirty);
339 return renderPassNode;
563void QQuick3DRenderPass::setOverrideMaterial(QQuick3DMaterial *newOverrideMaterial)
565 if (m_overrideMaterial == newOverrideMaterial)
569 if (m_overrideMaterial && m_overrideMaterialRefed) {
570 QQuick3DObjectPrivate::derefSceneManager(m_overrideMaterial);
571 m_overrideMaterialRefed =
false;
574 QQuick3DObjectPrivate::attachWatcher(
this, &QQuick3DRenderPass::setOverrideMaterial, newOverrideMaterial, m_overrideMaterial);
576 m_overrideMaterial = newOverrideMaterial;
579 if (m_overrideMaterial && m_overrideMaterial->parentItem() ==
nullptr) {
582 QQuick3DObject *parentItem = qobject_cast<QQuick3DObject *>(m_overrideMaterial->parent());
584 m_overrideMaterial->setParentItem(parentItem);
587 const auto &sceneManager = QQuick3DObjectPrivate::get(
this)->sceneManager;
589 QQuick3DObjectPrivate::refSceneManager(m_overrideMaterial, *sceneManager);
590 m_overrideMaterialRefed =
true;
596 emit overrideMaterialChanged();
597 markDirty(OverrideMaterialDirty);