581void NormalPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
583 using namespace RenderHelpers;
585 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
586 QSSGRenderCamera *camera = data.renderedCameras[0];
588 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
589 QRhi *rhi = rhiCtx->rhi();
591 const auto &layerPrepResult = data.layerPrepResult;
598 ps = data.getPipelineState();
602 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
606 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
607 shaderFeatures.set(QSSGShaderFeatures::Feature::NormalPass,
true);
609 normalTexture = data.getRenderResult(QSSGRenderResult::Key::NormalTexture);
611 const QSize size = layerPrepResult.textureDimensions();
612 bool needsBuild =
false;
614 if (!normalTexture->texture) {
615 QRhiTexture::Format format = QRhiTexture::RGBA16F;
616 if (!rhi->isTextureFormatSupported(format)) {
617 qWarning(
"No float formats, not great");
618 format = QRhiTexture::RGBA8;
620 normalTexture->texture = rhiCtx->rhi()->newTexture(format, size, 1, QRhiTexture::RenderTarget);
622 normalTexture->texture->setName(QByteArrayLiteral(
"Normal texture"));
623 }
else if (normalTexture->texture->pixelSize() != size) {
624 normalTexture->texture->setPixelSize(size);
628 if (!normalTexture->depthStencil) {
629 normalTexture->depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size);
631 }
else if (normalTexture->depthStencil->pixelSize() != size) {
632 normalTexture->depthStencil->setPixelSize(size);
637 if (!normalTexture->texture->create()) {
638 qWarning(
"Failed to build normal texture (size %dx%d, format %d)",
639 size.width(), size.height(),
int(normalTexture->texture->format()));
640 normalTexture->reset();
644 if (!normalTexture->depthStencil->create()) {
645 qWarning(
"Failed to build depth-stencil buffer for normal texture (size %dx%d)",
646 size.width(), size.height());
647 normalTexture->reset();
651 normalTexture->resetRenderTarget();
653 QRhiTextureRenderTargetDescription rtDesc;
654 QRhiColorAttachment colorAttachment(normalTexture->texture);
655 rtDesc.setColorAttachments({ colorAttachment });
656 rtDesc.setDepthStencilBuffer(normalTexture->depthStencil);
658 normalTexture->rt = rhi->newTextureRenderTarget(rtDesc);
659 normalTexture->rt->setName(QByteArrayLiteral(
"Normal texture RT"));
660 normalTexture->rpDesc = normalTexture->rt->newCompatibleRenderPassDescriptor();
661 normalTexture->rt->setRenderPassDescriptor(normalTexture->rpDesc);
662 if (!normalTexture->rt->create()) {
663 qWarning(
"Failed to build render target for normal texture");
664 normalTexture->reset();
669 rhiPrepareNormalPass(rhiCtx.get(),
this, ps, normalTexture->rpDesc, data, sortedOpaqueObjects);
1432 auto *ctx = renderer.contextInterface();
1433 const auto &rhiCtx = ctx->rhiContext();
1434 auto *rhi = rhiCtx->rhi();
1436 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
1437 QSSGRenderCamera *camera = data.renderedCameras[0];
1439 ps = data.getPipelineState();
1440 ps.samples = rhiCtx->mainPassSampleCount();
1441 ps.viewCount = rhiCtx->mainPassViewCount();
1443 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1444 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1446 shaderFeatures = data.getShaderFeatures();
1447 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1449 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1450 ps.colorAttachmentCount = 2;
1452 rhiAccumTexture = data.getRenderResult(QSSGRenderResult::Key::AccumTexture);
1453 rhiRevealageTexture = data.getRenderResult(QSSGRenderResult::Key::RevealageTexture);
1455 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTextureMS);
1457 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTexture);
1458 if (!rhiDepthTexture->isValid())
1460 auto &oitrt = data.getOitRenderContext();
1461 if (!oitrt.oitRenderTarget || oitrt.oitRenderTarget->pixelSize() != data.layerPrepResult.textureDimensions()
1462 || rhiDepthTexture->texture != oitrt.oitRenderTarget->description().depthTexture()
1463 || ps.samples != oitrt.oitRenderTarget->sampleCount()) {
1464 if (oitrt.oitRenderTarget) {
1465 rhiAccumTexture->texture->destroy();
1466 rhiRevealageTexture->texture->destroy();
1467 oitrt.oitRenderTarget->destroy();
1468 oitrt.renderPassDescriptor->destroy();
1469 oitrt.oitRenderTarget =
nullptr;
1471 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget;
1472 if (ps.viewCount >= 2) {
1473 rhiAccumTexture->texture = rhi->newTextureArray(QRhiTexture::RGBA16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1474 rhiRevealageTexture->texture = rhi->newTextureArray(QRhiTexture::R16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1476 rhiAccumTexture->texture = rhi->newTexture(QRhiTexture::RGBA16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1477 rhiRevealageTexture->texture = rhi->newTexture(QRhiTexture::R16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1479 rhiAccumTexture->texture->create();
1480 rhiRevealageTexture->texture->create();
1482 QRhiTextureRenderTargetDescription desc;
1483 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1484 desc.setDepthTexture(rhiDepthTexture->texture);
1486 if (oitrt.oitRenderTarget ==
nullptr) {
1487 oitrt.oitRenderTarget = rhi->newTextureRenderTarget(desc, QRhiTextureRenderTarget::PreserveDepthStencilContents);
1488 oitrt.renderPassDescriptor = oitrt.oitRenderTarget->newCompatibleRenderPassDescriptor();
1489 oitrt.oitRenderTarget->setRenderPassDescriptor(oitrt.renderPassDescriptor);
1490 oitrt.oitRenderTarget->create();
1492 renderTarget = oitrt.oitRenderTarget;
1495 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1496 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1497 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1499 QSSGRhiShaderResourceBindingList bindings;
1500 QVector4D clearData[2];
1501 clearData[0] = QVector4D(0.0, 0.0, 0.0, 0.0);
1502 clearData[1] = QVector4D(1.0, 1.0, 1.0, 1.0);
1504 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1505 QRhiBuffer *&ubuf = dcd.ubuf;
1506 const int ubufSize =
sizeof(clearData);
1508 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1512 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1513 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1514 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1516 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1518 clearSrb = rhiCtxD->srb(bindings);
1520 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1521 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::One;
1522 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::One;
1523 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::One;
1524 ps.targetBlend[1].srcAlpha = QRhiGraphicsPipeline::Zero;
1525 ps.targetBlend[1].srcColor = QRhiGraphicsPipeline::Zero;
1526 ps.targetBlend[1].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1527 ps.targetBlend[1].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1529 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects,
true);
1530 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1532 rhiCtx->commandBuffer()->resourceUpdate(
this->rub);
1533 this->rub =
nullptr;
1537 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1538 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1539 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1540 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha;
1541 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1542 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1544 shaderFeatures = data.getShaderFeatures();
1545 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1547#ifdef QSSG_OIT_USE_BUFFERS
1548 auto &oitCtx = data.getOitRenderContext();
1549 rhiABuffer = oitCtx.aBuffer;
1550 rhiAuxBuffer = oitCtx.auxBuffer;
1551 rhiCounterBuffer = oitCtx.counterBuffer;
1553 rhiABufferImage = data.getRenderResult(QSSGRenderResult::Key::ABufferImage);
1554 rhiAuxiliaryImage = data.getRenderResult(QSSGRenderResult::Key::AuxiliaryImage);
1555 rhiCounterImage = data.getRenderResult(QSSGRenderResult::Key::CounterImage);
1557 QSize dim = data.layerPrepResult.textureDimensions();
1558 dim.setWidth(dim.width() * ps.samples);
1559 dim.setHeight(dim.height() * ps.viewCount);
1560#ifdef QSSG_OIT_USE_BUFFERS
1561 if (!rhiAuxBuffer || rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u) || currentNodeCount == 0 || currentNodeCount != reportedNodeCount)
1563 if (!rhiAuxiliaryImage->texture || rhiAuxiliaryImage->texture->pixelSize() != dim || currentNodeCount == 0 || currentNodeCount != reportedNodeCount)
1566 quint32 extraNodeCount = 0;
1567#ifdef QSSG_OIT_USE_BUFFERS
1568 if (rhiAuxBuffer && rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u)) {
1569 if (rhiAuxBuffer->size() < (dim.width() * dim.height() * 4u))
1570 extraNodeCount = ensureFreeNodes((dim.width() * dim.height() * 4u) - rhiAuxBuffer->size(), 32u * 1024u);
1571 rhiAuxBuffer->destroy();
1572 rhiAuxBuffer =
nullptr;
1575 if (rhiABufferImage->texture) {
1576 const auto s = rhiAuxiliaryImage->texture->pixelSize();
1577 if (s.width() * s.height() < dim.width() * dim.height())
1578 extraNodeCount = ensureFreeNodes(s.width() * s.height() - dim.width() * dim.height(), 32u * 1024u);
1579 rhiABufferImage->texture->destroy();
1580 rhiAuxiliaryImage->texture->destroy();
1584 if (reportedNodeCount) {
1585 currentNodeCount = reportedNodeCount + extraNodeCount;
1587 quint32 size = RenderHelpers::rhiCalculateABufferSize(data.layerPrepResult.textureDimensions(), 4 * ps.samples * ps.viewCount);
1588 currentNodeCount = ensureFreeNodes(size * size, 32u * 1024u);
1590 data.layer.oitNodeCount = currentNodeCount;
1592#ifdef QSSG_OIT_USE_BUFFERS
1593 if (rhiABuffer && currentNodeCount * 16 != rhiABuffer->size()) {
1594 rhiABuffer->destroy();
1595 rhiABuffer =
nullptr;
1598 rhiABuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, currentNodeCount * 16);
1599 rhiABuffer->create();
1601 if (!rhiAuxBuffer) {
1602 rhiAuxBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, dim.width() * dim.height() * 4);
1603 rhiAuxBuffer->create();
1605 if (!rhiCounterBuffer) {
1606 rhiCounterBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, 4);
1607 rhiCounterBuffer->create();
1608 oitCtx.counterBuffer = rhiCounterBuffer;
1610 oitCtx.aBuffer = rhiABuffer;
1611 oitCtx.auxBuffer = rhiAuxBuffer;
1613 quint32 sizeWithLayers = RenderHelpers::rhiCalculateABufferSize(currentNodeCount);
1614 const QRhiTexture::Flags textureFlags = QRhiTexture::UsedWithLoadStore;
1615 rhiABufferImage->texture = rhi->newTexture(QRhiTexture::RGBA32UI, QSize(sizeWithLayers, sizeWithLayers), 1, textureFlags);
1616 rhiABufferImage->texture->create();
1617 rhiAuxiliaryImage->texture = rhi->newTexture(QRhiTexture::R32UI, dim, 1, textureFlags);
1618 rhiAuxiliaryImage->texture->create();
1619 if (!rhiCounterImage->texture) {
1620 rhiCounterImage->texture = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, textureFlags | QRhiTexture::UsedAsTransferSource);
1621 rhiCounterImage->texture->create();
1623 auto &oitrt = data.getOitRenderContext();
1624 readbackImage = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, QRhiTexture::UsedAsTransferSource);
1630 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1632 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1633 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1634#ifdef QSSG_OIT_USE_BUFFERS
1635 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearBufferShader();
1637 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearImageShader();
1639 QSSGRhiShaderResourceBindingList bindings;
1640 quint32 clearImageData[8] = {0};
1642 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1643 QRhiBuffer *&ubuf = dcd.ubuf;
1644 const int ubufSize =
sizeof(clearImageData);
1646 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1650 clearImageData[4] = data.layerPrepResult.textureDimensions().width();
1651 clearImageData[5] = data.layerPrepResult.textureDimensions().height();
1652 clearImageData[6] = ps.samples;
1653 clearImageData[7] = ps.viewCount;
1655 rub->updateDynamicBuffer(ubuf, 0, ubufSize, clearImageData);
1657#ifdef QSSG_OIT_USE_BUFFERS
1658 rub->uploadStaticBuffer(rhiCounterBuffer, 0, 4, &zero);
1660 rub->uploadTexture(rhiCounterImage->texture, {{0, 0, {&zero, 4}}});
1663 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1664#ifdef QSSG_OIT_USE_BUFFERS
1665 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1667 bindings.addImageStore(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1670 clearSrb = rhiCtxD->srb(bindings);
1672 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1674 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, rhiCtx->mainRenderPassDescriptor(), sortedTransparentObjects,
true);
1680 auto *ctx = renderer.contextInterface();
1681 const auto &rhiCtx = ctx->rhiContext();
1682 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1683 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1685 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1686 if (Q_LIKELY(renderTarget)) {
1687 cb->beginPass(renderTarget, Qt::black, {});
1689 QRhiShaderResourceBindings *srb = clearSrb;
1691 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
1692 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1693 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, renderTarget->renderPassDescriptor(), {});
1694 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1696 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render order-independent alpha"));
1697 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1698 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render order-independent alpha"));
1699 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
true);
1700 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1701 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1703 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1704 Q_TRACE(QSSG_renderPass_exit);
1708 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1709 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render alpha"));
1710 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1711 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render alpha"));
1713 QRhiShaderResourceBindings *srb = clearSrb;
1715 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1716 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1717 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(), {});
1719 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1720#ifdef QSSG_OIT_USE_BUFFERS
1721 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1722 QRhiReadbackResult *result =
nullptr;
1723 if (results.size() > 1) {
1724 result = results.takeLast();
1725 result->pixelSize = {};
1727 result->format = QRhiTexture::UnknownFormat;
1729 result =
new QRhiReadbackResult();
1731 const auto completedFunc = [
this, result](){
1733 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1734 quint32 nodeCount = *d;
1736 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1737 this->results.append(result);
1740 result->completed = completedFunc;
1741 rub->readBackBuffer(rhiCounterBuffer, 0, 4, result);
1744 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1746 QRhiReadbackDescription rbdesc;
1748 QRhiReadbackResult *result =
nullptr;
1749 if (results.size() > 1) {
1750 result = results.takeLast();
1751 result->pixelSize = {};
1753 result->format = QRhiTexture::UnknownFormat;
1755 result =
new QRhiReadbackResult();
1757 const auto completedFunc = [
this, result](){
1759 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1760 quint32 nodeCount = *d;
1762 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1763 this->results.append(result);
1766 result->completed = completedFunc;
1767 rub->readBackTexture(rbdesc, result);
1771 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1772 Q_TRACE(QSSG_renderPass_exit);
1860 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1861 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1862 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1864 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1866 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
1869 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1870 QSSGRhiShaderResourceBindingList bindings;
1872 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1873 QRhiSampler::Nearest,
1875 QRhiSampler::ClampToEdge,
1876 QRhiSampler::ClampToEdge,
1877 QRhiSampler::ClampToEdge });
1878 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiAccumTexture->texture, sampler);
1879 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, rhiRevealageTexture->texture, sampler);
1881 compositeSrb = rhiCtxD->srb(bindings);
1883 QRhiShaderResourceBindings *srb = compositeSrb;
1886 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D revealage"));
1887 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1888 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1889 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1890 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1891 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"revealage"));
1893 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1894 QSSGRhiShaderResourceBindingList bindings;
1896 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1897 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 }));
1898 QRhiBuffer *&ubuf = dcd.ubuf;
1900 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1901#ifdef QSSG_OIT_USE_BUFFERS
1902 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiABuffer);
1903 bindings.addStorageBuffer(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1905 bindings.addImageLoad(1, QRhiShaderResourceBinding::FragmentStage, rhiABufferImage->texture, 0);
1906 bindings.addImageLoad(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1909 compositeSrb = rhiCtxD->srb(bindings);
1911 QRhiShaderResourceBindings *srb = compositeSrb;
1914 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D oit-composite"));
1915 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1916 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1917 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1918 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1919 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"oit-composite"));
2017 QSSGRenderUserPass *passNode,
2018 std::vector<UserPassData> &outData,
2019 QSSGRhiRenderableTextureV2Ptr renderableTexture)
2023 const bool isTopLevelPass = (renderableTexture ==
nullptr);
2025 QSSGRenderCamera *camera = data.renderedCameras[0];
2026 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2028 const QSize targetSize = data.layerPrepResult.textureDimensions();
2030 static const auto needsRebuild = [](QRhiTexture *texture,
const QSize &size, QRhiTexture::Format format) {
2031 return !texture || texture->pixelSize() != size || texture->format() != format;
2034 qCDebug(lcUserRenderPass,
"renderPrep in UserRenderPass");
2036 const QSSGResourceId currentPassId = QSSGRenderGraphObjectUtils::getResourceId(*passNode);
2037 if (visitedPasses.find(currentPassId) != visitedPasses.end()) {
2038 qWarning(
"UserRenderPass: Circular dependency detected in SubRenderPass chain. Ignoring pass.");
2043 if (visitedPasses.size() >= MAX_SUBPASS_DEPTH) {
2044 qWarning(
"UserRenderPass: Maximum SubRenderPass nesting depth (%zu) exceeded. Ignoring pass.", MAX_SUBPASS_DEPTH);
2048 visitedPasses.insert(currentPassId);
2051 currentPassData.clearColor = passNode->clearColor;
2052 currentPassData.depthStencilClearValue = passNode->depthStencilClearValue;
2054 renderableTexture = currentPassData.renderableTexture = data.requestUserRenderPassManager()->getOrCreateRenderableTexture(*passNode);
2056 currentPassData.renderableTexture = renderableTexture;
2058 QSSGRenderableObjectList &renderables = currentPassData.renderables;
2059 QSSGRhiGraphicsPipelineState &ps = currentPassData.ps;
2060 const auto &renderTarget = currentPassData.renderableTexture;
2063 ps = data.getPipelineState();
2065 bool renderablesFiltered =
false;
2067 bool needsDepthStencilRenderBuffer =
false;
2068 QSSGAllocateTexturePtr depthTextureAllocCommand;
2070 QVarLengthArray<QSSGColorAttachment *, 16> colorAttachments;
2071 QVarLengthArray<QSSGResourceId, 4> subPassIds;
2074 for (
const QSSGCommand *theCommand : std::as_const(passNode->commands)) {
2077 qCDebug(lcUserRenderPass) <<
"Exec. command: >" << theCommand->typeAsString() <<
"--" << theCommand->debugString();
2079 switch (theCommand->m_type) {
2080 case CommandType::ColorAttachment:
2082 const QSSGColorAttachment *colorAttachCmd =
static_cast<
const QSSGColorAttachment *>(theCommand);
2083 colorAttachments.push_back(
const_cast<QSSGColorAttachment *>(colorAttachCmd));
2086 case CommandType::DepthTextureAttachment:
2088 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2089 const QSSGDepthTextureAttachment *depthAttachCmd =
static_cast<
const QSSGDepthTextureAttachment *>(theCommand);
2090 needsDepthStencilRenderBuffer =
false;
2091 depthTextureAllocCommand = depthAttachCmd->m_textureCmd;
2094 case CommandType::AddShaderDefine:
2096 const auto *defineCmd =
static_cast<
const QSSGAddShaderDefine *>(theCommand);
2097 const auto &defineName = defineCmd->m_name;
2098 if (defineName.size() > 0) {
2099 QByteArray value = QByteArray::number(defineCmd->m_value);
2100 currentPassData.shaderDefines.push_back({ defineName, value });
2104 case CommandType::RenderablesFilter:
2106 auto filterCommand =
static_cast<
const QSSGRenderablesFilterCommand *>(theCommand);
2110 enum RenderableType : quint8 {
2116 if (filterCommand->renderableTypes & RenderableType::Opaque)
2117 renderables = data.getSortedOpaqueRenderableObjects(*camera, 0, filterCommand->layerMask);
2118 if (filterCommand->renderableTypes & RenderableType::Transparent)
2119 renderables += data.getSortedTransparentRenderableObjects(*camera, 0, filterCommand->layerMask);
2123 renderablesFiltered =
true;
2127 case CommandType::PipelineStateOverride:
2129 auto pipelineCommand =
static_cast<
const QSSGPipelineStateOverrideCommand *>(theCommand);
2130 if (pipelineCommand->m_depthTestEnabled)
2131 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, *pipelineCommand->m_depthTestEnabled);
2132 if (pipelineCommand->m_depthWriteEnabled)
2133 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, *pipelineCommand->m_depthWriteEnabled);
2134 if (pipelineCommand->m_blendEnabled)
2135 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, *pipelineCommand->m_blendEnabled);
2136 if (pipelineCommand->m_usesStencilReference)
2137 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef, *pipelineCommand->m_usesStencilReference);
2138 if (pipelineCommand->m_usesScissor)
2139 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor, *pipelineCommand->m_usesScissor);
2140 if (pipelineCommand->m_depthFunction)
2141 ps.depthFunc = *pipelineCommand->m_depthFunction;
2142 if (pipelineCommand->m_cullMode)
2143 ps.cullMode = *pipelineCommand->m_cullMode;
2144 if (pipelineCommand->m_polygonMode)
2145 ps.polygonMode = *pipelineCommand->m_polygonMode;
2146 if (pipelineCommand->m_stencilOpFrontState)
2147 ps.stencilOpFrontState = *pipelineCommand->m_stencilOpFrontState;
2148 if (pipelineCommand->m_stencilWriteMask)
2149 ps.stencilWriteMask = *pipelineCommand->m_stencilWriteMask;
2150 if (pipelineCommand->m_stencilReference)
2151 ps.stencilRef = *pipelineCommand->m_stencilReference;
2152 if (pipelineCommand->m_viewport)
2153 ps.viewport = *pipelineCommand->m_viewport;
2154 if (pipelineCommand->m_scissor)
2155 ps.scissor = *pipelineCommand->m_scissor;
2156 if (pipelineCommand->m_targetBlend0)
2157 ps.targetBlend[0] = *pipelineCommand->m_targetBlend0;
2158 if (pipelineCommand->m_targetBlend1)
2159 ps.targetBlend[1] = *pipelineCommand->m_targetBlend1;
2160 if (pipelineCommand->m_targetBlend2)
2161 ps.targetBlend[2] = *pipelineCommand->m_targetBlend2;
2162 if (pipelineCommand->m_targetBlend3)
2163 ps.targetBlend[3] = *pipelineCommand->m_targetBlend3;
2164 if (pipelineCommand->m_targetBlend4)
2165 ps.targetBlend[4] = *pipelineCommand->m_targetBlend4;
2166 if (pipelineCommand->m_targetBlend5)
2167 ps.targetBlend[5] = *pipelineCommand->m_targetBlend5;
2168 if (pipelineCommand->m_targetBlend6)
2169 ps.targetBlend[6] = *pipelineCommand->m_targetBlend6;
2170 if (pipelineCommand->m_targetBlend7)
2171 ps.targetBlend[7] = *pipelineCommand->m_targetBlend7;
2174 case CommandType::DepthStencilAttachment:
2176 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2177 needsDepthStencilRenderBuffer =
true;
2179 case CommandType::SubRenderPass:
2181 auto subPassCommand =
static_cast<
const QSSGSubRenderPass *>(theCommand);
2182 if (subPassCommand && subPassCommand->m_userPassId != QSSGResourceId::Invalid)
2183 subPassIds.append(subPassCommand->m_userPassId);
2187 qWarning() <<
"Effect command" << theCommand->typeAsString() <<
"not implemented";
2192 if (colorAttachments.size() > 4) {
2193 colorAttachments.resize(4);
2194 qWarning() <<
"UserRenderPass supports up to 4 color attachments only.";
2199 if (isTopLevelPass) {
2201 bool needsBuild = !renderTarget->isValid();
2203 const qsizetype oldAttachmentCount = renderTarget->colorAttachmentCount();
2205 if (oldAttachmentCount != colorAttachments.size())
2211 for (
int i = 0; i != oldAttachmentCount; ++i) {
2212 const auto &colorAttachment = colorAttachments.at(i);
2213 QSSG_ASSERT(colorAttachment !=
nullptr,
continue);
2214 const auto expectedFormat = QSSGBufferManager::toRhiFormat(colorAttachment->format());
2215 const auto &texture = renderTarget->getColorTexture(i);
2216 needsBuild = needsBuild || needsRebuild(&(*texture->texture()), targetSize, expectedFormat);
2220 if (needsDepthStencilRenderBuffer != (renderTarget->getDepthStencil() !=
nullptr))
2224 if (depthTextureAllocCommand) {
2225 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2226 const auto &depthTextureWrapper = renderTarget->getDepthTexture();
2227 needsBuild = depthTextureWrapper ==
nullptr;
2228 needsBuild = needsBuild || needsRebuild(&(*depthTextureWrapper->texture()), targetSize, format);
2230 if (renderTarget->getDepthTexture() !=
nullptr)
2236 renderTarget->reset();
2238 QRhiTextureRenderTargetDescription rtDesc;
2241 const qsizetype colorAttachmentCount = qMax<qsizetype>(colorAttachments.size(), 1);
2243 bool createSucceeded =
true;
2244 bool colorAllocatorsNeedsUpdate =
false;
2248 QVarLengthArray<QRhiTexture *, 4> textures;
2249 for (qsizetype i = 0; i < colorAttachmentCount && createSucceeded ; ++i) {
2250 const auto &colorAttCmd = colorAttachments.at(i);
2251 const auto &name = colorAttCmd->m_name;
2252 const auto format = QSSGBufferManager::toRhiFormat(colorAttCmd->format());
2253 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2254 if (allocateTexCmd->texture() && !needsRebuild(&(*allocateTexCmd->texture()->texture()), targetSize, format)) {
2257 textures.push_back(allocateTexCmd->texture()->texture().get());
2259 auto *tex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2261 createSucceeded = createSucceeded && tex->create();
2262 textures.push_back(tex);
2266 colorAllocatorsNeedsUpdate =
true;
2270 rtDesc.setColorAttachments(textures.cbegin(), textures.cend());
2273 if (needsDepthStencilRenderBuffer) {
2274 auto renderBuffer = rhiCtx->rhi()->newRenderBuffer(QRhiRenderBuffer::DepthStencil, targetSize, ps.samples);
2275 if (renderBuffer->create())
2276 rtDesc.setDepthStencilBuffer(renderBuffer);
2277 }
else if (depthTextureAllocCommand) {
2278 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2279 if (depthTextureAllocCommand->texture() && !needsRebuild(&(*depthTextureAllocCommand->texture()->texture()), targetSize, format)) {
2280 rtDesc.setDepthTexture(depthTextureAllocCommand->texture()->texture().get());
2283 QRhiTexture *depthTex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2284 if (depthTex->create())
2285 rtDesc.setDepthTexture(depthTex);
2289 if (createSucceeded) {
2291 renderTarget->setDescription(rhiCtx->rhi(),
std::move(rtDesc), passNode->renderTargetFlags);
2294 if (colorAllocatorsNeedsUpdate) {
2295 for (qsizetype i = 0; i < colorAttachmentCount; ++i) {
2296 const auto &colorAttCmd = colorAttachments.at(i);
2297 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2298 allocateTexCmd->setTexture(renderTarget->getColorTexture(i));
2302 if (depthTextureAllocCommand)
2303 depthTextureAllocCommand->setTexture(renderTarget->getDepthTexture());
2306 renderTarget->resetRenderTarget();
2307 qWarning() <<
"Failed to create textures for UserRenderPass";
2313 Q_ASSERT(renderTarget->isValid());
2315 ps.colorAttachmentCount =
int(renderTarget->colorAttachmentCount());
2318 for (
const auto &subPassId : std::as_const(subPassIds)) {
2319 QSSGRenderUserPass *userPassNode = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subPassId);
2320 QSSG_ASSERT(userPassNode && userPassNode->type == QSSGRenderGraphObject::Type::RenderPass,
continue);
2321 prepareSubPass(renderer, data, userPassNode, currentPassData.subPassData, currentPassData.renderableTexture);
2324 if (passNode->passMode == QSSGRenderUserPass::PassModes::UserPass) {
2326 if (!renderablesFiltered && renderables.isEmpty())
2327 renderables = data.getSortedOpaqueRenderableObjects(*camera);
2329 if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::AugmentMaterial) {
2333 QSSG_ASSERT(shaderAugmentation.outputs.size() == 0, shaderAugmentation.outputs.clear());
2334 shaderAugmentation.defines =
std::move(currentPassData.shaderDefines);
2336 for (
int i = 0, end = colorAttachments.size(); i < end; ++i) {
2337 const auto &colorAttCmd = colorAttachments.at(i);
2338 const auto &name = colorAttCmd->m_name;
2339 if (name.size() > 0)
2340 shaderAugmentation.outputs.push_back(name);
2342 shaderAugmentation.outputs.push_back(getDefaultOutputName(size_t(i)));
2345 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2346 shaderFeatures.disableTonemapping();
2348 currentPassData.index = RenderHelpers::rhiPrepareAugmentedUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), shaderAugmentation, data, renderables, shaderFeatures);
2349 }
else if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::OverrideMaterial) {
2351 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2352 shaderFeatures.disableTonemapping();
2354 currentPassData.index = RenderHelpers::rhiPrepareOverrideMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), passNode->overrideMaterial, data, renderables, shaderFeatures);
2358 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2359 shaderFeatures.disableTonemapping();
2360 currentPassData.index = RenderHelpers::rhiPrepareOriginalMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), data, renderables, shaderFeatures);
2362 outData.push_back(currentPassData);
2365 if (passNode->passMode == QSSGRenderUserPass::PassModes::SkyboxPass) {
2366 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2367 if (data.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && data.layer.skyBoxCubeMap) {
2368 if (!currentPassData.skyboxCubeMapPass)
2371 currentPassData.skyboxCubeMapPass->skipTonemapping =
true;
2372 currentPassData.skyboxCubeMapPass->renderPrep(renderer, data);
2373 currentPassData.skyboxCubeMapPass->ps.samples = ps.samples;
2374 currentPassData.skyboxCubeMapPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2376 currentPassData.skyboxPass =
std::nullopt;
2377 }
else if (data.layer.background == QSSGRenderLayer::Background::SkyBox && data.layer.lightProbe) {
2378 if (!currentPassData.skyboxPass)
2381 currentPassData.skyboxPass->skipTonemapping =
true;
2382 currentPassData.skyboxPass->renderPrep(renderer, data);
2383 currentPassData.skyboxPass->ps.samples = ps.samples;
2384 currentPassData.skyboxPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2386 currentPassData.skyboxCubeMapPass =
std::nullopt;
2388 outData.push_back(currentPassData);
2390 }
else if (passNode->passMode == QSSGRenderUserPass::PassModes::Item2DPass) {
2391 if (!currentPassData.item2DPass)
2393 const bool hasItem2Ds = (data.item2DsView.size() > 0);
2396 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(renderer.contextInterface()->rhiContext().get());
2397 QRhiRenderTarget *prevRenderTarget = rhiCtx->renderTarget();
2398 rhiCtxD->setRenderTarget(renderTarget->getRenderTarget().get());
2399 currentPassData.item2DPass->renderPrep(renderer, data);
2401 rhiCtxD->setRenderTarget(prevRenderTarget);
2402 outData.push_back(currentPassData);