574void NormalPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
576 using namespace RenderHelpers;
578 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
579 QSSGRenderCamera *camera = data.renderedCameras[0];
581 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
582 QRhi *rhi = rhiCtx->rhi();
584 const auto &layerPrepResult = data.layerPrepResult;
591 ps = data.getPipelineState();
595 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
599 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
600 shaderFeatures.set(QSSGShaderFeatures::Feature::NormalPass,
true);
602 normalTexture = data.getRenderResult(QSSGRenderResult::Key::NormalTexture);
604 const QSize size = layerPrepResult.textureDimensions();
605 bool needsBuild =
false;
607 if (!normalTexture->texture) {
608 QRhiTexture::Format format = QRhiTexture::RGBA16F;
609 if (!rhi->isTextureFormatSupported(format)) {
610 qWarning(
"No float formats, not great");
611 format = QRhiTexture::RGBA8;
613 normalTexture->texture = rhiCtx->rhi()->newTexture(format, size, 1, QRhiTexture::RenderTarget);
615 normalTexture->texture->setName(QByteArrayLiteral(
"Normal texture"));
616 }
else if (normalTexture->texture->pixelSize() != size) {
617 normalTexture->texture->setPixelSize(size);
621 if (!normalTexture->depthStencil) {
622 normalTexture->depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size);
624 }
else if (normalTexture->depthStencil->pixelSize() != size) {
625 normalTexture->depthStencil->setPixelSize(size);
630 if (!normalTexture->texture->create()) {
631 qWarning(
"Failed to build normal texture (size %dx%d, format %d)",
632 size.width(), size.height(),
int(normalTexture->texture->format()));
633 normalTexture->reset();
637 if (!normalTexture->depthStencil->create()) {
638 qWarning(
"Failed to build depth-stencil buffer for normal texture (size %dx%d)",
639 size.width(), size.height());
640 normalTexture->reset();
644 normalTexture->resetRenderTarget();
646 QRhiTextureRenderTargetDescription rtDesc;
647 QRhiColorAttachment colorAttachment(normalTexture->texture);
648 rtDesc.setColorAttachments({ colorAttachment });
649 rtDesc.setDepthStencilBuffer(normalTexture->depthStencil);
651 normalTexture->rt = rhi->newTextureRenderTarget(rtDesc);
652 normalTexture->rt->setName(QByteArrayLiteral(
"Normal texture RT"));
653 normalTexture->rpDesc = normalTexture->rt->newCompatibleRenderPassDescriptor();
654 normalTexture->rt->setRenderPassDescriptor(normalTexture->rpDesc);
655 if (!normalTexture->rt->create()) {
656 qWarning(
"Failed to build render target for normal texture");
657 normalTexture->reset();
662 rhiPrepareNormalPass(rhiCtx.get(),
this, ps, normalTexture->rpDesc, data, sortedOpaqueObjects);
1425 auto *ctx = renderer.contextInterface();
1426 const auto &rhiCtx = ctx->rhiContext();
1427 auto *rhi = rhiCtx->rhi();
1429 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
1430 QSSGRenderCamera *camera = data.renderedCameras[0];
1432 ps = data.getPipelineState();
1433 ps.samples = rhiCtx->mainPassSampleCount();
1434 ps.viewCount = rhiCtx->mainPassViewCount();
1436 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1437 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1439 shaderFeatures = data.getShaderFeatures();
1440 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1442 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1443 ps.colorAttachmentCount = 2;
1445 rhiAccumTexture = data.getRenderResult(QSSGRenderResult::Key::AccumTexture);
1446 rhiRevealageTexture = data.getRenderResult(QSSGRenderResult::Key::RevealageTexture);
1448 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTextureMS);
1450 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTexture);
1451 if (!rhiDepthTexture->isValid())
1453 auto &oitrt = data.getOitRenderContext();
1454 if (!oitrt.oitRenderTarget || oitrt.oitRenderTarget->pixelSize() != data.layerPrepResult.textureDimensions()
1455 || rhiDepthTexture->texture != oitrt.oitRenderTarget->description().depthTexture()
1456 || ps.samples != oitrt.oitRenderTarget->sampleCount()) {
1457 if (oitrt.oitRenderTarget) {
1458 rhiAccumTexture->texture->destroy();
1459 rhiRevealageTexture->texture->destroy();
1460 oitrt.oitRenderTarget->destroy();
1461 oitrt.renderPassDescriptor->destroy();
1462 oitrt.oitRenderTarget =
nullptr;
1464 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget;
1465 if (ps.viewCount >= 2) {
1466 rhiAccumTexture->texture = rhi->newTextureArray(QRhiTexture::RGBA16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1467 rhiRevealageTexture->texture = rhi->newTextureArray(QRhiTexture::R16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1469 rhiAccumTexture->texture = rhi->newTexture(QRhiTexture::RGBA16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1470 rhiRevealageTexture->texture = rhi->newTexture(QRhiTexture::R16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1472 rhiAccumTexture->texture->create();
1473 rhiRevealageTexture->texture->create();
1475 QRhiTextureRenderTargetDescription desc;
1476 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1477 desc.setDepthTexture(rhiDepthTexture->texture);
1479 if (oitrt.oitRenderTarget ==
nullptr) {
1480 oitrt.oitRenderTarget = rhi->newTextureRenderTarget(desc, QRhiTextureRenderTarget::PreserveDepthStencilContents);
1481 oitrt.renderPassDescriptor = oitrt.oitRenderTarget->newCompatibleRenderPassDescriptor();
1482 oitrt.oitRenderTarget->setRenderPassDescriptor(oitrt.renderPassDescriptor);
1483 oitrt.oitRenderTarget->create();
1485 renderTarget = oitrt.oitRenderTarget;
1488 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1489 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1490 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1492 QSSGRhiShaderResourceBindingList bindings;
1493 QVector4D clearData[2];
1494 clearData[0] = QVector4D(0.0, 0.0, 0.0, 0.0);
1495 clearData[1] = QVector4D(1.0, 1.0, 1.0, 1.0);
1497 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1498 QRhiBuffer *&ubuf = dcd.ubuf;
1499 const int ubufSize =
sizeof(clearData);
1501 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1505 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1506 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1507 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1509 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1511 clearSrb = rhiCtxD->srb(bindings);
1513 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1514 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::One;
1515 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::One;
1516 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::One;
1517 ps.targetBlend[1].srcAlpha = QRhiGraphicsPipeline::Zero;
1518 ps.targetBlend[1].srcColor = QRhiGraphicsPipeline::Zero;
1519 ps.targetBlend[1].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1520 ps.targetBlend[1].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1522 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects,
true);
1523 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1525 rhiCtx->commandBuffer()->resourceUpdate(
this->rub);
1526 this->rub =
nullptr;
1530 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1531 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1532 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1533 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha;
1534 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1535 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1537 shaderFeatures = data.getShaderFeatures();
1538 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1540#ifdef QSSG_OIT_USE_BUFFERS
1541 auto &oitCtx = data.getOitRenderContext();
1542 rhiABuffer = oitCtx.aBuffer;
1543 rhiAuxBuffer = oitCtx.auxBuffer;
1544 rhiCounterBuffer = oitCtx.counterBuffer;
1546 rhiABufferImage = data.getRenderResult(QSSGRenderResult::Key::ABufferImage);
1547 rhiAuxiliaryImage = data.getRenderResult(QSSGRenderResult::Key::AuxiliaryImage);
1548 rhiCounterImage = data.getRenderResult(QSSGRenderResult::Key::CounterImage);
1550 QSize dim = data.layerPrepResult.textureDimensions();
1551 dim.setWidth(dim.width() * ps.samples);
1552 dim.setHeight(dim.height() * ps.viewCount);
1553#ifdef QSSG_OIT_USE_BUFFERS
1554 if (!rhiAuxBuffer || rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u) || currentNodeCount == 0 || currentNodeCount != reportedNodeCount)
1556 if (!rhiAuxiliaryImage->texture || rhiAuxiliaryImage->texture->pixelSize() != dim || currentNodeCount == 0 || currentNodeCount != reportedNodeCount)
1559 quint32 extraNodeCount = 0;
1560#ifdef QSSG_OIT_USE_BUFFERS
1561 if (rhiAuxBuffer && rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u)) {
1562 if (rhiAuxBuffer->size() < (dim.width() * dim.height() * 4u))
1563 extraNodeCount = ensureFreeNodes((dim.width() * dim.height() * 4u) - rhiAuxBuffer->size(), 32u * 1024u);
1564 rhiAuxBuffer->destroy();
1565 rhiAuxBuffer =
nullptr;
1568 if (rhiABufferImage->texture) {
1569 const auto s = rhiAuxiliaryImage->texture->pixelSize();
1570 if (s.width() * s.height() < dim.width() * dim.height())
1571 extraNodeCount = ensureFreeNodes(s.width() * s.height() - dim.width() * dim.height(), 32u * 1024u);
1572 rhiABufferImage->texture->destroy();
1573 rhiAuxiliaryImage->texture->destroy();
1577 if (reportedNodeCount) {
1578 currentNodeCount = reportedNodeCount + extraNodeCount;
1580 quint32 size = RenderHelpers::rhiCalculateABufferSize(data.layerPrepResult.textureDimensions(), 4 * ps.samples * ps.viewCount);
1581 currentNodeCount = ensureFreeNodes(size * size, 32u * 1024u);
1583 data.layer.oitNodeCount = currentNodeCount;
1585#ifdef QSSG_OIT_USE_BUFFERS
1586 if (rhiABuffer && currentNodeCount * 16 != rhiABuffer->size()) {
1587 rhiABuffer->destroy();
1588 rhiABuffer =
nullptr;
1591 rhiABuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, currentNodeCount * 16);
1592 rhiABuffer->create();
1594 if (!rhiAuxBuffer) {
1595 rhiAuxBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, dim.width() * dim.height() * 4);
1596 rhiAuxBuffer->create();
1598 if (!rhiCounterBuffer) {
1599 rhiCounterBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, 4);
1600 rhiCounterBuffer->create();
1601 oitCtx.counterBuffer = rhiCounterBuffer;
1603 oitCtx.aBuffer = rhiABuffer;
1604 oitCtx.auxBuffer = rhiAuxBuffer;
1606 quint32 sizeWithLayers = RenderHelpers::rhiCalculateABufferSize(currentNodeCount);
1607 const QRhiTexture::Flags textureFlags = QRhiTexture::UsedWithLoadStore;
1608 rhiABufferImage->texture = rhi->newTexture(QRhiTexture::RGBA32UI, QSize(sizeWithLayers, sizeWithLayers), 1, textureFlags);
1609 rhiABufferImage->texture->create();
1610 rhiAuxiliaryImage->texture = rhi->newTexture(QRhiTexture::R32UI, dim, 1, textureFlags);
1611 rhiAuxiliaryImage->texture->create();
1612 if (!rhiCounterImage->texture) {
1613 rhiCounterImage->texture = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, textureFlags | QRhiTexture::UsedAsTransferSource);
1614 rhiCounterImage->texture->create();
1616 auto &oitrt = data.getOitRenderContext();
1617 readbackImage = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, QRhiTexture::UsedAsTransferSource);
1623 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1625 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1626 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1627#ifdef QSSG_OIT_USE_BUFFERS
1628 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearBufferShader();
1630 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearImageShader();
1632 QSSGRhiShaderResourceBindingList bindings;
1633 quint32 clearImageData[8] = {0};
1635 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1636 QRhiBuffer *&ubuf = dcd.ubuf;
1637 const int ubufSize =
sizeof(clearImageData);
1639 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1643 clearImageData[4] = data.layerPrepResult.textureDimensions().width();
1644 clearImageData[5] = data.layerPrepResult.textureDimensions().height();
1645 clearImageData[6] = ps.samples;
1646 clearImageData[7] = ps.viewCount;
1648 rub->updateDynamicBuffer(ubuf, 0, ubufSize, clearImageData);
1650#ifdef QSSG_OIT_USE_BUFFERS
1651 rub->uploadStaticBuffer(rhiCounterBuffer, 0, 4, &zero);
1653 rub->uploadTexture(rhiCounterImage->texture, {{0, 0, {&zero, 4}}});
1656 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1657#ifdef QSSG_OIT_USE_BUFFERS
1658 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1660 bindings.addImageStore(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1663 clearSrb = rhiCtxD->srb(bindings);
1665 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1667 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, rhiCtx->mainRenderPassDescriptor(), sortedTransparentObjects,
true);
1673 auto *ctx = renderer.contextInterface();
1674 const auto &rhiCtx = ctx->rhiContext();
1675 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1676 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1678 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1679 if (Q_LIKELY(renderTarget)) {
1680 cb->beginPass(renderTarget, Qt::black, {});
1682 QRhiShaderResourceBindings *srb = clearSrb;
1684 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
1685 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1686 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, renderTarget->renderPassDescriptor(), {});
1687 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1689 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render order-independent alpha"));
1690 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1691 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render order-independent alpha"));
1692 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
true);
1693 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1694 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1696 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1697 Q_TRACE(QSSG_renderPass_exit);
1701 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1702 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render alpha"));
1703 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1704 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render alpha"));
1706 QRhiShaderResourceBindings *srb = clearSrb;
1708 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1709 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1710 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(), {});
1712 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1713#ifdef QSSG_OIT_USE_BUFFERS
1714 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1715 QRhiReadbackResult *result =
nullptr;
1716 if (results.size() > 1) {
1717 result = results.takeLast();
1718 result->pixelSize = {};
1720 result->format = QRhiTexture::UnknownFormat;
1722 result =
new QRhiReadbackResult();
1724 const auto completedFunc = [
this, result](){
1726 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1727 quint32 nodeCount = *d;
1729 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1730 this->results.append(result);
1733 result->completed = completedFunc;
1734 rub->readBackBuffer(rhiCounterBuffer, 0, 4, result);
1737 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1739 QRhiReadbackDescription rbdesc;
1741 QRhiReadbackResult *result =
nullptr;
1742 if (results.size() > 1) {
1743 result = results.takeLast();
1744 result->pixelSize = {};
1746 result->format = QRhiTexture::UnknownFormat;
1748 result =
new QRhiReadbackResult();
1750 const auto completedFunc = [
this, result](){
1752 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1753 quint32 nodeCount = *d;
1755 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1756 this->results.append(result);
1759 result->completed = completedFunc;
1760 rub->readBackTexture(rbdesc, result);
1764 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1765 Q_TRACE(QSSG_renderPass_exit);
1853 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1854 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1855 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1857 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1859 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
1862 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1863 QSSGRhiShaderResourceBindingList bindings;
1865 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1866 QRhiSampler::Nearest,
1868 QRhiSampler::ClampToEdge,
1869 QRhiSampler::ClampToEdge,
1870 QRhiSampler::ClampToEdge });
1871 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiAccumTexture->texture, sampler);
1872 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, rhiRevealageTexture->texture, sampler);
1874 compositeSrb = rhiCtxD->srb(bindings);
1876 QRhiShaderResourceBindings *srb = compositeSrb;
1879 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D revealage"));
1880 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1881 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1882 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1883 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1884 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"revealage"));
1886 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1887 QSSGRhiShaderResourceBindingList bindings;
1889 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1890 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 }));
1891 QRhiBuffer *&ubuf = dcd.ubuf;
1893 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1894#ifdef QSSG_OIT_USE_BUFFERS
1895 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiABuffer);
1896 bindings.addStorageBuffer(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1898 bindings.addImageLoad(1, QRhiShaderResourceBinding::FragmentStage, rhiABufferImage->texture, 0);
1899 bindings.addImageLoad(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1902 compositeSrb = rhiCtxD->srb(bindings);
1904 QRhiShaderResourceBindings *srb = compositeSrb;
1907 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D oit-composite"));
1908 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1909 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1910 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1911 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1912 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"oit-composite"));
2010 QSSGRenderUserPass *passNode,
2011 std::vector<UserPassData> &outData,
2012 QSSGRhiRenderableTextureV2Ptr renderableTexture)
2016 const bool isTopLevelPass = (renderableTexture ==
nullptr);
2018 QSSGRenderCamera *camera = data.renderedCameras[0];
2019 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2021 const QSize targetSize = data.layerPrepResult.textureDimensions();
2023 static const auto needsRebuild = [](QRhiTexture *texture,
const QSize &size, QRhiTexture::Format format) {
2024 return !texture || texture->pixelSize() != size || texture->format() != format;
2027 qCDebug(lcUserRenderPass,
"renderPrep in UserRenderPass");
2029 const QSSGResourceId currentPassId = QSSGRenderGraphObjectUtils::getResourceId(*passNode);
2030 if (visitedPasses.find(currentPassId) != visitedPasses.end()) {
2031 qWarning(
"UserRenderPass: Circular dependency detected in SubRenderPass chain. Ignoring pass.");
2036 if (visitedPasses.size() >= MAX_SUBPASS_DEPTH) {
2037 qWarning(
"UserRenderPass: Maximum SubRenderPass nesting depth (%zu) exceeded. Ignoring pass.", MAX_SUBPASS_DEPTH);
2041 visitedPasses.insert(currentPassId);
2044 currentPassData.clearColor = passNode->clearColor;
2045 currentPassData.depthStencilClearValue = passNode->depthStencilClearValue;
2047 renderableTexture = currentPassData.renderableTexture = data.requestUserRenderPassManager()->getOrCreateRenderableTexture(*passNode);
2049 currentPassData.renderableTexture = renderableTexture;
2051 QSSGRenderableObjectList &renderables = currentPassData.renderables;
2052 QSSGRhiGraphicsPipelineState &ps = currentPassData.ps;
2053 const auto &renderTarget = currentPassData.renderableTexture;
2056 ps = data.getPipelineState();
2058 bool renderablesFiltered =
false;
2060 bool needsDepthStencilRenderBuffer =
false;
2061 QSSGAllocateTexturePtr depthTextureAllocCommand;
2063 QVarLengthArray<QSSGColorAttachment *, 16> colorAttachments;
2064 QVarLengthArray<QSSGResourceId, 4> subPassIds;
2067 for (
const QSSGCommand *theCommand : std::as_const(passNode->commands)) {
2070 qCDebug(lcUserRenderPass) <<
"Exec. command: >" << theCommand->typeAsString() <<
"--" << theCommand->debugString();
2072 switch (theCommand->m_type) {
2073 case CommandType::ColorAttachment:
2075 const QSSGColorAttachment *colorAttachCmd =
static_cast<
const QSSGColorAttachment *>(theCommand);
2076 colorAttachments.push_back(
const_cast<QSSGColorAttachment *>(colorAttachCmd));
2079 case CommandType::DepthTextureAttachment:
2081 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2082 const QSSGDepthTextureAttachment *depthAttachCmd =
static_cast<
const QSSGDepthTextureAttachment *>(theCommand);
2083 needsDepthStencilRenderBuffer =
false;
2084 depthTextureAllocCommand = depthAttachCmd->m_textureCmd;
2087 case CommandType::AddShaderDefine:
2089 const auto *defineCmd =
static_cast<
const QSSGAddShaderDefine *>(theCommand);
2090 const auto &defineName = defineCmd->m_name;
2091 if (defineName.size() > 0) {
2092 QByteArray value = QByteArray::number(defineCmd->m_value);
2093 currentPassData.shaderDefines.push_back({ defineName, value });
2097 case CommandType::RenderablesFilter:
2099 auto filterCommand =
static_cast<
const QSSGRenderablesFilterCommand *>(theCommand);
2103 enum RenderableType : quint8 {
2109 if (filterCommand->renderableTypes & RenderableType::Opaque)
2110 renderables = data.getSortedOpaqueRenderableObjects(*camera, 0, filterCommand->layerMask);
2111 if (filterCommand->renderableTypes & RenderableType::Transparent)
2112 renderables += data.getSortedTransparentRenderableObjects(*camera, 0, filterCommand->layerMask);
2116 renderablesFiltered =
true;
2120 case CommandType::PipelineStateOverride:
2122 auto pipelineCommand =
static_cast<
const QSSGPipelineStateOverrideCommand *>(theCommand);
2123 if (pipelineCommand->m_depthTestEnabled)
2124 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, *pipelineCommand->m_depthTestEnabled);
2125 if (pipelineCommand->m_depthWriteEnabled)
2126 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, *pipelineCommand->m_depthWriteEnabled);
2127 if (pipelineCommand->m_blendEnabled)
2128 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, *pipelineCommand->m_blendEnabled);
2129 if (pipelineCommand->m_usesStencilReference)
2130 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef, *pipelineCommand->m_usesStencilReference);
2131 if (pipelineCommand->m_usesScissor)
2132 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor, *pipelineCommand->m_usesScissor);
2133 if (pipelineCommand->m_depthFunction)
2134 ps.depthFunc = *pipelineCommand->m_depthFunction;
2135 if (pipelineCommand->m_cullMode)
2136 ps.cullMode = *pipelineCommand->m_cullMode;
2137 if (pipelineCommand->m_polygonMode)
2138 ps.polygonMode = *pipelineCommand->m_polygonMode;
2139 if (pipelineCommand->m_stencilOpFrontState)
2140 ps.stencilOpFrontState = *pipelineCommand->m_stencilOpFrontState;
2141 if (pipelineCommand->m_stencilWriteMask)
2142 ps.stencilWriteMask = *pipelineCommand->m_stencilWriteMask;
2143 if (pipelineCommand->m_stencilReference)
2144 ps.stencilRef = *pipelineCommand->m_stencilReference;
2145 if (pipelineCommand->m_viewport)
2146 ps.viewport = *pipelineCommand->m_viewport;
2147 if (pipelineCommand->m_scissor)
2148 ps.scissor = *pipelineCommand->m_scissor;
2149 if (pipelineCommand->m_targetBlend0)
2150 ps.targetBlend[0] = *pipelineCommand->m_targetBlend0;
2151 if (pipelineCommand->m_targetBlend1)
2152 ps.targetBlend[1] = *pipelineCommand->m_targetBlend1;
2153 if (pipelineCommand->m_targetBlend2)
2154 ps.targetBlend[2] = *pipelineCommand->m_targetBlend2;
2155 if (pipelineCommand->m_targetBlend3)
2156 ps.targetBlend[3] = *pipelineCommand->m_targetBlend3;
2157 if (pipelineCommand->m_targetBlend4)
2158 ps.targetBlend[4] = *pipelineCommand->m_targetBlend4;
2159 if (pipelineCommand->m_targetBlend5)
2160 ps.targetBlend[5] = *pipelineCommand->m_targetBlend5;
2161 if (pipelineCommand->m_targetBlend6)
2162 ps.targetBlend[6] = *pipelineCommand->m_targetBlend6;
2163 if (pipelineCommand->m_targetBlend7)
2164 ps.targetBlend[7] = *pipelineCommand->m_targetBlend7;
2167 case CommandType::DepthStencilAttachment:
2169 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2170 needsDepthStencilRenderBuffer =
true;
2172 case CommandType::SubRenderPass:
2174 auto subPassCommand =
static_cast<
const QSSGSubRenderPass *>(theCommand);
2175 if (subPassCommand && subPassCommand->m_userPassId != QSSGResourceId::Invalid)
2176 subPassIds.append(subPassCommand->m_userPassId);
2180 qWarning() <<
"Effect command" << theCommand->typeAsString() <<
"not implemented";
2185 if (colorAttachments.size() > 4) {
2186 colorAttachments.resize(4);
2187 qWarning() <<
"UserRenderPass supports up to 4 color attachments only.";
2192 if (isTopLevelPass) {
2194 bool needsBuild = !renderTarget->isValid();
2196 const qsizetype oldAttachmentCount = renderTarget->colorAttachmentCount();
2198 if (oldAttachmentCount != colorAttachments.size())
2204 for (
int i = 0; i != oldAttachmentCount; ++i) {
2205 const auto &colorAttachment = colorAttachments.at(i);
2206 QSSG_ASSERT(colorAttachment !=
nullptr,
continue);
2207 const auto expectedFormat = QSSGBufferManager::toRhiFormat(colorAttachment->format());
2208 const auto &texture = renderTarget->getColorTexture(i);
2209 needsBuild = needsBuild || needsRebuild(&(*texture->texture()), targetSize, expectedFormat);
2213 if (needsDepthStencilRenderBuffer != (renderTarget->getDepthStencil() !=
nullptr))
2217 if (depthTextureAllocCommand) {
2218 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2219 const auto &depthTextureWrapper = renderTarget->getDepthTexture();
2220 needsBuild = depthTextureWrapper ==
nullptr;
2221 needsBuild = needsBuild || needsRebuild(&(*depthTextureWrapper->texture()), targetSize, format);
2223 if (renderTarget->getDepthTexture() !=
nullptr)
2229 renderTarget->reset();
2231 QRhiTextureRenderTargetDescription rtDesc;
2234 const qsizetype colorAttachmentCount = qMax<qsizetype>(colorAttachments.size(), 1);
2236 bool createSucceeded =
true;
2237 bool colorAllocatorsNeedsUpdate =
false;
2241 QVarLengthArray<QRhiTexture *, 4> textures;
2242 for (qsizetype i = 0; i < colorAttachmentCount && createSucceeded ; ++i) {
2243 const auto &colorAttCmd = colorAttachments.at(i);
2244 const auto &name = colorAttCmd->m_name;
2245 const auto format = QSSGBufferManager::toRhiFormat(colorAttCmd->format());
2246 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2247 if (allocateTexCmd->texture() && !needsRebuild(&(*allocateTexCmd->texture()->texture()), targetSize, format)) {
2250 textures.push_back(allocateTexCmd->texture()->texture().get());
2252 auto *tex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2254 createSucceeded = createSucceeded && tex->create();
2255 textures.push_back(tex);
2259 colorAllocatorsNeedsUpdate =
true;
2263 rtDesc.setColorAttachments(textures.cbegin(), textures.cend());
2266 if (needsDepthStencilRenderBuffer) {
2267 auto renderBuffer = rhiCtx->rhi()->newRenderBuffer(QRhiRenderBuffer::DepthStencil, targetSize, ps.samples);
2268 if (renderBuffer->create())
2269 rtDesc.setDepthStencilBuffer(renderBuffer);
2270 }
else if (depthTextureAllocCommand) {
2271 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2272 if (depthTextureAllocCommand->texture() && !needsRebuild(&(*depthTextureAllocCommand->texture()->texture()), targetSize, format)) {
2273 rtDesc.setDepthTexture(depthTextureAllocCommand->texture()->texture().get());
2276 QRhiTexture *depthTex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2277 if (depthTex->create())
2278 rtDesc.setDepthTexture(depthTex);
2282 if (createSucceeded) {
2284 renderTarget->setDescription(rhiCtx->rhi(),
std::move(rtDesc), passNode->renderTargetFlags);
2287 if (colorAllocatorsNeedsUpdate) {
2288 for (qsizetype i = 0; i < colorAttachmentCount; ++i) {
2289 const auto &colorAttCmd = colorAttachments.at(i);
2290 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2291 allocateTexCmd->setTexture(renderTarget->getColorTexture(i));
2295 if (depthTextureAllocCommand)
2296 depthTextureAllocCommand->setTexture(renderTarget->getDepthTexture());
2299 renderTarget->resetRenderTarget();
2300 qWarning() <<
"Failed to create textures for UserRenderPass";
2306 Q_ASSERT(renderTarget->isValid());
2308 ps.colorAttachmentCount =
int(renderTarget->colorAttachmentCount());
2311 for (
const auto &subPassId : std::as_const(subPassIds)) {
2312 QSSGRenderUserPass *userPassNode = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subPassId);
2313 QSSG_ASSERT(userPassNode && userPassNode->type == QSSGRenderGraphObject::Type::RenderPass,
continue);
2314 prepareSubPass(renderer, data, userPassNode, currentPassData.subPassData, currentPassData.renderableTexture);
2317 if (passNode->passMode == QSSGRenderUserPass::PassModes::UserPass) {
2319 if (!renderablesFiltered && renderables.isEmpty())
2320 renderables = data.getSortedOpaqueRenderableObjects(*camera);
2322 if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::AugmentMaterial) {
2326 QSSG_ASSERT(shaderAugmentation.outputs.size() == 0, shaderAugmentation.outputs.clear());
2327 shaderAugmentation.defines =
std::move(currentPassData.shaderDefines);
2329 for (
int i = 0, end = colorAttachments.size(); i < end; ++i) {
2330 const auto &colorAttCmd = colorAttachments.at(i);
2331 const auto &name = colorAttCmd->m_name;
2332 if (name.size() > 0)
2333 shaderAugmentation.outputs.push_back(name);
2335 shaderAugmentation.outputs.push_back(getDefaultOutputName(size_t(i)));
2338 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2339 shaderFeatures.disableTonemapping();
2341 currentPassData.index = RenderHelpers::rhiPrepareAugmentedUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), shaderAugmentation, data, renderables, shaderFeatures);
2342 }
else if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::OverrideMaterial) {
2344 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2345 shaderFeatures.disableTonemapping();
2347 currentPassData.index = RenderHelpers::rhiPrepareOverrideMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), passNode->overrideMaterial, data, renderables, shaderFeatures);
2351 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2352 shaderFeatures.disableTonemapping();
2353 currentPassData.index = RenderHelpers::rhiPrepareOriginalMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), data, renderables, shaderFeatures);
2355 outData.push_back(currentPassData);
2358 if (passNode->passMode == QSSGRenderUserPass::PassModes::SkyboxPass) {
2359 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2360 if (data.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && data.layer.skyBoxCubeMap) {
2361 if (!currentPassData.skyboxCubeMapPass)
2364 currentPassData.skyboxCubeMapPass->skipTonemapping =
true;
2365 currentPassData.skyboxCubeMapPass->renderPrep(renderer, data);
2366 currentPassData.skyboxCubeMapPass->ps.samples = ps.samples;
2367 currentPassData.skyboxCubeMapPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2369 currentPassData.skyboxPass =
std::nullopt;
2370 }
else if (data.layer.background == QSSGRenderLayer::Background::SkyBox && data.layer.lightProbe) {
2371 if (!currentPassData.skyboxPass)
2374 currentPassData.skyboxPass->skipTonemapping =
true;
2375 currentPassData.skyboxPass->renderPrep(renderer, data);
2376 currentPassData.skyboxPass->ps.samples = ps.samples;
2377 currentPassData.skyboxPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2379 currentPassData.skyboxCubeMapPass =
std::nullopt;
2381 outData.push_back(currentPassData);
2383 }
else if (passNode->passMode == QSSGRenderUserPass::PassModes::Item2DPass) {
2384 if (!currentPassData.item2DPass)
2386 const bool hasItem2Ds = (data.item2DsView.size() > 0);
2389 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(renderer.contextInterface()->rhiContext().get());
2390 QRhiRenderTarget *prevRenderTarget = rhiCtx->renderTarget();
2391 rhiCtxD->setRenderTarget(renderTarget->getRenderTarget().get());
2392 currentPassData.item2DPass->renderPrep(renderer, data);
2394 rhiCtxD->setRenderTarget(prevRenderTarget);
2395 outData.push_back(currentPassData);