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"));
2013 QSSGRenderUserPass *passNode,
2014 std::vector<UserPassData> &outData,
2015 QSSGRhiRenderableTextureV2Ptr renderableTexture)
2019 const bool isTopLevelPass = (renderableTexture ==
nullptr);
2021 QSSGRenderCamera *camera = data.renderedCameras[0];
2022 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2024 const QSize targetSize = data.layerPrepResult.textureDimensions();
2026 static const auto needsRebuild = [](QRhiTexture *texture,
const QSize &size, QRhiTexture::Format format) {
2027 return !texture || texture->pixelSize() != size || texture->format() != format;
2030 qCDebug(lcUserRenderPass,
"renderPrep in UserRenderPass");
2032 const QSSGResourceId currentPassId = QSSGRenderGraphObjectUtils::getResourceId(*passNode);
2033 if (visitedPasses.find(currentPassId) != visitedPasses.end()) {
2034 qWarning(
"UserRenderPass: Circular dependency detected in SubRenderPass chain. Ignoring pass.");
2039 if (visitedPasses.size() >= MAX_SUBPASS_DEPTH) {
2040 qWarning(
"UserRenderPass: Maximum SubRenderPass nesting depth (%zu) exceeded. Ignoring pass.", MAX_SUBPASS_DEPTH);
2044 visitedPasses.insert(currentPassId);
2047 currentPassData.clearColor = passNode->clearColor;
2048 currentPassData.depthStencilClearValue = passNode->depthStencilClearValue;
2049 const size_t userPassIndex = outData.size();
2050 currentPassData.index = userPassIndex;
2052 renderableTexture = currentPassData.renderableTexture = data.requestUserRenderPassManager()->getOrCreateRenderableTexture(*passNode);
2054 currentPassData.renderableTexture = renderableTexture;
2056 QSSGRenderableObjectList &renderables = currentPassData.renderables;
2057 QSSGRhiGraphicsPipelineState &ps = currentPassData.ps;
2058 const auto &renderTarget = currentPassData.renderableTexture;
2061 ps = data.getPipelineState();
2063 bool renderablesFiltered =
false;
2065 bool needsDepthStencilRenderBuffer =
false;
2066 QSSGAllocateTexturePtr depthTextureAllocCommand;
2068 QVarLengthArray<QSSGColorAttachment *, 16> colorAttachments;
2069 QVarLengthArray<QSSGResourceId, 4> subPassIds;
2072 for (
const QSSGCommand *theCommand : std::as_const(passNode->commands)) {
2075 qCDebug(lcUserRenderPass) <<
"Exec. command: >" << theCommand->typeAsString() <<
"--" << theCommand->debugString();
2077 switch (theCommand->m_type) {
2078 case CommandType::ColorAttachment:
2080 const QSSGColorAttachment *colorAttachCmd =
static_cast<
const QSSGColorAttachment *>(theCommand);
2081 colorAttachments.push_back(
const_cast<QSSGColorAttachment *>(colorAttachCmd));
2084 case CommandType::DepthTextureAttachment:
2086 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2087 const QSSGDepthTextureAttachment *depthAttachCmd =
static_cast<
const QSSGDepthTextureAttachment *>(theCommand);
2088 needsDepthStencilRenderBuffer =
false;
2089 depthTextureAllocCommand = depthAttachCmd->m_textureCmd;
2092 case CommandType::AddShaderDefine:
2094 const auto *defineCmd =
static_cast<
const QSSGAddShaderDefine *>(theCommand);
2095 const auto &defineName = defineCmd->m_name;
2096 if (defineName.size() > 0) {
2097 QByteArray value = QByteArray::number(defineCmd->m_value);
2098 currentPassData.shaderDefines.push_back({ defineName, value });
2102 case CommandType::RenderablesFilter:
2104 auto filterCommand =
static_cast<
const QSSGRenderablesFilterCommand *>(theCommand);
2108 enum RenderableType : quint8 {
2114 if (filterCommand->renderableTypes & RenderableType::Opaque)
2115 renderables = data.getSortedOpaqueRenderableObjects(*camera, 0, filterCommand->layerMask);
2116 if (filterCommand->renderableTypes & RenderableType::Transparent)
2117 renderables += data.getSortedTransparentRenderableObjects(*camera, 0, filterCommand->layerMask);
2121 renderablesFiltered =
true;
2125 case CommandType::PipelineStateOverride:
2127 auto pipelineCommand =
static_cast<
const QSSGPipelineStateOverrideCommand *>(theCommand);
2128 if (pipelineCommand->m_depthTestEnabled)
2129 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, *pipelineCommand->m_depthTestEnabled);
2130 if (pipelineCommand->m_depthWriteEnabled)
2131 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, *pipelineCommand->m_depthWriteEnabled);
2132 if (pipelineCommand->m_blendEnabled)
2133 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, *pipelineCommand->m_blendEnabled);
2134 if (pipelineCommand->m_usesStencilReference)
2135 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef, *pipelineCommand->m_usesStencilReference);
2136 if (pipelineCommand->m_usesScissor)
2137 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor, *pipelineCommand->m_usesScissor);
2138 if (pipelineCommand->m_depthFunction)
2139 ps.depthFunc = *pipelineCommand->m_depthFunction;
2140 if (pipelineCommand->m_cullMode)
2141 ps.cullMode = *pipelineCommand->m_cullMode;
2142 if (pipelineCommand->m_polygonMode)
2143 ps.polygonMode = *pipelineCommand->m_polygonMode;
2144 if (pipelineCommand->m_stencilOpFrontState)
2145 ps.stencilOpFrontState = *pipelineCommand->m_stencilOpFrontState;
2146 if (pipelineCommand->m_stencilWriteMask)
2147 ps.stencilWriteMask = *pipelineCommand->m_stencilWriteMask;
2148 if (pipelineCommand->m_stencilReference)
2149 ps.stencilRef = *pipelineCommand->m_stencilReference;
2150 if (pipelineCommand->m_viewport)
2151 ps.viewport = *pipelineCommand->m_viewport;
2152 if (pipelineCommand->m_scissor)
2153 ps.scissor = *pipelineCommand->m_scissor;
2154 if (pipelineCommand->m_targetBlend0)
2155 ps.targetBlend[0] = *pipelineCommand->m_targetBlend0;
2156 if (pipelineCommand->m_targetBlend1)
2157 ps.targetBlend[1] = *pipelineCommand->m_targetBlend1;
2158 if (pipelineCommand->m_targetBlend2)
2159 ps.targetBlend[2] = *pipelineCommand->m_targetBlend2;
2160 if (pipelineCommand->m_targetBlend3)
2161 ps.targetBlend[3] = *pipelineCommand->m_targetBlend3;
2162 if (pipelineCommand->m_targetBlend4)
2163 ps.targetBlend[4] = *pipelineCommand->m_targetBlend4;
2164 if (pipelineCommand->m_targetBlend5)
2165 ps.targetBlend[5] = *pipelineCommand->m_targetBlend5;
2166 if (pipelineCommand->m_targetBlend6)
2167 ps.targetBlend[6] = *pipelineCommand->m_targetBlend6;
2168 if (pipelineCommand->m_targetBlend7)
2169 ps.targetBlend[7] = *pipelineCommand->m_targetBlend7;
2172 case CommandType::DepthStencilAttachment:
2174 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2175 needsDepthStencilRenderBuffer =
true;
2177 case CommandType::SubRenderPass:
2179 auto subPassCommand =
static_cast<
const QSSGSubRenderPass *>(theCommand);
2180 if (subPassCommand && subPassCommand->m_userPassId != QSSGResourceId::Invalid)
2181 subPassIds.append(subPassCommand->m_userPassId);
2185 qWarning() <<
"Effect command" << theCommand->typeAsString() <<
"not implemented";
2190 if (colorAttachments.size() > 4) {
2191 colorAttachments.resize(4);
2192 qWarning() <<
"UserRenderPass supports up to 4 color attachments only.";
2197 if (isTopLevelPass) {
2199 bool needsBuild = !renderTarget->isValid();
2201 const qsizetype oldAttachmentCount = renderTarget->colorAttachmentCount();
2203 if (oldAttachmentCount != colorAttachments.size())
2209 for (
int i = 0; i != oldAttachmentCount; ++i) {
2210 const auto &colorAttachment = colorAttachments.at(i);
2211 QSSG_ASSERT(colorAttachment !=
nullptr,
continue);
2212 const auto expectedFormat = QSSGBufferManager::toRhiFormat(colorAttachment->format());
2213 const auto &texture = renderTarget->getColorTexture(i);
2214 needsBuild = needsBuild || needsRebuild(&(*texture->texture()), targetSize, expectedFormat);
2218 if (needsDepthStencilRenderBuffer != (renderTarget->getDepthStencil() !=
nullptr))
2222 if (depthTextureAllocCommand) {
2223 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2224 const auto &depthTextureWrapper = renderTarget->getDepthTexture();
2225 needsBuild = depthTextureWrapper ==
nullptr;
2226 needsBuild = needsBuild || needsRebuild(&(*depthTextureWrapper->texture()), targetSize, format);
2228 if (renderTarget->getDepthTexture() !=
nullptr)
2234 renderTarget->reset();
2236 QRhiTextureRenderTargetDescription rtDesc;
2239 const qsizetype colorAttachmentCount = qMax<qsizetype>(colorAttachments.size(), 1);
2241 bool createSucceeded =
true;
2242 bool colorAllocatorsNeedsUpdate =
false;
2246 QVarLengthArray<QRhiTexture *, 4> textures;
2247 for (qsizetype i = 0; i < colorAttachmentCount && createSucceeded ; ++i) {
2248 const auto &colorAttCmd = colorAttachments.at(i);
2249 const auto &name = colorAttCmd->m_name;
2250 const auto format = QSSGBufferManager::toRhiFormat(colorAttCmd->format());
2251 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2252 if (allocateTexCmd->texture() && !needsRebuild(&(*allocateTexCmd->texture()->texture()), targetSize, format)) {
2255 textures.push_back(allocateTexCmd->texture()->texture().get());
2257 auto *tex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2259 createSucceeded = createSucceeded && tex->create();
2260 textures.push_back(tex);
2264 colorAllocatorsNeedsUpdate =
true;
2268 rtDesc.setColorAttachments(textures.cbegin(), textures.cend());
2271 if (needsDepthStencilRenderBuffer) {
2272 auto renderBuffer = rhiCtx->rhi()->newRenderBuffer(QRhiRenderBuffer::DepthStencil, targetSize, ps.samples);
2273 if (renderBuffer->create())
2274 rtDesc.setDepthStencilBuffer(renderBuffer);
2275 }
else if (depthTextureAllocCommand) {
2276 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2277 if (depthTextureAllocCommand->texture() && !needsRebuild(&(*depthTextureAllocCommand->texture()->texture()), targetSize, format)) {
2278 rtDesc.setDepthTexture(depthTextureAllocCommand->texture()->texture().get());
2281 QRhiTexture *depthTex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2282 if (depthTex->create())
2283 rtDesc.setDepthTexture(depthTex);
2287 if (createSucceeded) {
2289 renderTarget->setDescription(rhiCtx->rhi(),
std::move(rtDesc), passNode->renderTargetFlags);
2292 if (colorAllocatorsNeedsUpdate) {
2293 for (qsizetype i = 0; i < colorAttachmentCount; ++i) {
2294 const auto &colorAttCmd = colorAttachments.at(i);
2295 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2296 allocateTexCmd->setTexture(renderTarget->getColorTexture(i));
2300 if (depthTextureAllocCommand)
2301 depthTextureAllocCommand->setTexture(renderTarget->getDepthTexture());
2304 renderTarget->resetRenderTarget();
2305 qWarning() <<
"Failed to create textures for UserRenderPass";
2311 Q_ASSERT(renderTarget->isValid());
2313 ps.colorAttachmentCount =
int(renderTarget->colorAttachmentCount());
2316 for (
const auto &subPassId : std::as_const(subPassIds)) {
2317 QSSGRenderUserPass *userPassNode = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subPassId);
2318 QSSG_ASSERT(userPassNode && userPassNode->type == QSSGRenderGraphObject::Type::RenderPass,
continue);
2319 prepareSubPass(renderer, data, userPassNode, currentPassData.subPassData, currentPassData.renderableTexture);
2322 if (passNode->passMode == QSSGRenderUserPass::PassModes::UserPass) {
2324 if (!renderablesFiltered && renderables.isEmpty())
2325 renderables = data.getSortedOpaqueRenderableObjects(*camera);
2327 if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::AugmentMaterial) {
2331 QSSG_ASSERT(shaderAugmentation.outputs.size() == 0, shaderAugmentation.outputs.clear());
2332 shaderAugmentation.defines =
std::move(currentPassData.shaderDefines);
2334 for (
int i = 0, end = colorAttachments.size(); i < end; ++i) {
2335 const auto &colorAttCmd = colorAttachments.at(i);
2336 const auto &name = colorAttCmd->m_name;
2337 if (name.size() > 0)
2338 shaderAugmentation.outputs.push_back(name);
2340 shaderAugmentation.outputs.push_back(getDefaultOutputName(size_t(i)));
2343 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2344 shaderFeatures.disableTonemapping();
2347 }
else if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::OverrideMaterial) {
2349 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2350 shaderFeatures.disableTonemapping();
2356 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2357 shaderFeatures.disableTonemapping();
2360 outData.push_back(currentPassData);
2363 if (passNode->passMode == QSSGRenderUserPass::PassModes::SkyboxPass) {
2364 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2365 if (data.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && data.layer.skyBoxCubeMap) {
2366 if (!currentPassData.skyboxCubeMapPass)
2369 currentPassData.skyboxCubeMapPass->skipTonemapping =
true;
2370 currentPassData.skyboxCubeMapPass->renderPrep(renderer, data);
2371 currentPassData.skyboxCubeMapPass->ps.samples = ps.samples;
2372 currentPassData.skyboxCubeMapPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2374 currentPassData.skyboxPass =
std::nullopt;
2375 }
else if (data.layer.background == QSSGRenderLayer::Background::SkyBox && data.layer.lightProbe) {
2376 if (!currentPassData.skyboxPass)
2379 currentPassData.skyboxPass->skipTonemapping =
true;
2380 currentPassData.skyboxPass->renderPrep(renderer, data);
2381 currentPassData.skyboxPass->ps.samples = ps.samples;
2382 currentPassData.skyboxPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2384 currentPassData.skyboxCubeMapPass =
std::nullopt;
2386 outData.push_back(currentPassData);
2388 }
else if (passNode->passMode == QSSGRenderUserPass::PassModes::Item2DPass) {
2389 if (!currentPassData.item2DPass)
2391 const bool hasItem2Ds = (data.item2DsView.size() > 0);
2394 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(renderer.contextInterface()->rhiContext().get());
2395 QRhiRenderTarget *prevRenderTarget = rhiCtx->renderTarget();
2396 rhiCtxD->setRenderTarget(renderTarget->getRenderTarget().get());
2397 currentPassData.item2DPass->renderPrep(renderer, data);
2399 rhiCtxD->setRenderTarget(prevRenderTarget);
2400 outData.push_back(currentPassData);