596void NormalPass::renderPrep(QSSGRenderer &renderer, QSSGLayerRenderData &data)
598 using namespace RenderHelpers;
600 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
601 QSSGRenderCamera *camera = data.renderedCameras[0];
603 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
604 QRhi *rhi = rhiCtx->rhi();
606 const auto &layerPrepResult = data.layerPrepResult;
613 ps = data.getPipelineState();
617 sortedOpaqueObjects = data.getSortedOpaqueRenderableObjects(*camera);
621 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
622 shaderFeatures.set(QSSGShaderFeatures::Feature::NormalPass,
true);
624 normalTexture = data.getRenderResult(QSSGRenderResult::Key::NormalTexture);
626 const QSize size = layerPrepResult.textureDimensions();
627 bool needsBuild =
false;
629 if (!normalTexture->texture) {
630 QRhiTexture::Format format = QRhiTexture::RGBA16F;
631 if (!rhi->isTextureFormatSupported(format)) {
632 qWarning(
"No float formats, not great");
633 format = QRhiTexture::RGBA8;
635 normalTexture->texture = rhiCtx->rhi()->newTexture(format, size, 1, QRhiTexture::RenderTarget);
637 normalTexture->texture->setName(QByteArrayLiteral(
"Normal texture"));
638 }
else if (normalTexture->texture->pixelSize() != size) {
639 normalTexture->texture->setPixelSize(size);
643 if (!normalTexture->depthStencil) {
644 normalTexture->depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size);
646 }
else if (normalTexture->depthStencil->pixelSize() != size) {
647 normalTexture->depthStencil->setPixelSize(size);
652 if (!normalTexture->texture->create()) {
653 qWarning(
"Failed to build normal texture (size %dx%d, format %d)",
654 size.width(), size.height(),
int(normalTexture->texture->format()));
655 normalTexture->reset();
659 if (!normalTexture->depthStencil->create()) {
660 qWarning(
"Failed to build depth-stencil buffer for normal texture (size %dx%d)",
661 size.width(), size.height());
662 normalTexture->reset();
666 normalTexture->resetRenderTarget();
668 QRhiTextureRenderTargetDescription rtDesc;
669 QRhiColorAttachment colorAttachment(normalTexture->texture);
670 rtDesc.setColorAttachments({ colorAttachment });
671 rtDesc.setDepthStencilBuffer(normalTexture->depthStencil);
673 normalTexture->rt = rhi->newTextureRenderTarget(rtDesc);
674 normalTexture->rt->setName(QByteArrayLiteral(
"Normal texture RT"));
675 normalTexture->rpDesc = normalTexture->rt->newCompatibleRenderPassDescriptor();
676 normalTexture->rt->setRenderPassDescriptor(normalTexture->rpDesc);
677 if (!normalTexture->rt->create()) {
678 qWarning(
"Failed to build render target for normal texture");
679 normalTexture->reset();
684 rhiPrepareNormalPass(rhiCtx.get(),
this, ps, normalTexture->rpDesc, data, sortedOpaqueObjects);
1449 auto *ctx = renderer.contextInterface();
1450 const auto &rhiCtx = ctx->rhiContext();
1451 auto *rhi = rhiCtx->rhi();
1453 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
1454 QSSGRenderCamera *camera = data.renderedCameras[0];
1456 ps = data.getPipelineState();
1457 ps.samples = rhiCtx->mainPassSampleCount();
1458 ps.viewCount = rhiCtx->mainPassViewCount();
1460 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1461 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1463 shaderFeatures = data.getShaderFeatures();
1464 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1466 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1467 ps.colorAttachmentCount = 2;
1469 rhiAccumTexture = data.getRenderResult(QSSGRenderResult::Key::AccumTexture);
1470 rhiRevealageTexture = data.getRenderResult(QSSGRenderResult::Key::RevealageTexture);
1472 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTextureMS);
1474 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTexture);
1475 if (!rhiDepthTexture->isValid())
1477 auto &oitrt = data.getOitRenderContext();
1478 if (!oitrt.oitRenderTarget || oitrt.oitRenderTarget->pixelSize() != data.layerPrepResult.textureDimensions()
1479 || rhiDepthTexture->texture != oitrt.oitRenderTarget->description().depthTexture()
1480 || ps.samples != oitrt.oitRenderTarget->sampleCount()) {
1481 if (oitrt.oitRenderTarget) {
1482 rhiAccumTexture->texture->destroy();
1483 rhiRevealageTexture->texture->destroy();
1484 oitrt.oitRenderTarget->destroy();
1485 oitrt.renderPassDescriptor->destroy();
1486 oitrt.oitRenderTarget =
nullptr;
1488 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget;
1489 if (ps.viewCount >= 2) {
1490 rhiAccumTexture->texture = rhi->newTextureArray(QRhiTexture::RGBA16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1491 rhiRevealageTexture->texture = rhi->newTextureArray(QRhiTexture::R16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1493 rhiAccumTexture->texture = rhi->newTexture(QRhiTexture::RGBA16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1494 rhiRevealageTexture->texture = rhi->newTexture(QRhiTexture::R16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1496 rhiAccumTexture->texture->create();
1497 rhiRevealageTexture->texture->create();
1499 QRhiTextureRenderTargetDescription desc;
1500 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1501 desc.setDepthTexture(rhiDepthTexture->texture);
1503 if (oitrt.oitRenderTarget ==
nullptr) {
1504 oitrt.oitRenderTarget = rhi->newTextureRenderTarget(desc, QRhiTextureRenderTarget::PreserveDepthStencilContents);
1505 oitrt.renderPassDescriptor = oitrt.oitRenderTarget->newCompatibleRenderPassDescriptor();
1506 oitrt.oitRenderTarget->setRenderPassDescriptor(oitrt.renderPassDescriptor);
1507 oitrt.oitRenderTarget->create();
1509 renderTarget = oitrt.oitRenderTarget;
1512 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1513 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1514 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1516 QSSGRhiShaderResourceBindingList bindings;
1517 QVector4D clearData[2];
1518 clearData[0] = QVector4D(0.0, 0.0, 0.0, 0.0);
1519 clearData[1] = QVector4D(1.0, 1.0, 1.0, 1.0);
1521 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1522 QRhiBuffer *&ubuf = dcd.ubuf;
1523 const int ubufSize =
sizeof(clearData);
1525 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1529 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1530 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1531 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1533 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1535 clearSrb = rhiCtxD->srb(bindings);
1537 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1538 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::One;
1539 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::One;
1540 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::One;
1541 ps.targetBlend[1].srcAlpha = QRhiGraphicsPipeline::Zero;
1542 ps.targetBlend[1].srcColor = QRhiGraphicsPipeline::Zero;
1543 ps.targetBlend[1].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1544 ps.targetBlend[1].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1546 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects,
true);
1547 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1549 rhiCtx->commandBuffer()->resourceUpdate(
this->rub);
1550 this->rub =
nullptr;
1554 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1555 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1556 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1557 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha;
1558 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1559 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1561 shaderFeatures = data.getShaderFeatures();
1562 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1564#ifdef QSSG_OIT_USE_BUFFERS
1565 auto &oitCtx = data.getOitRenderContext();
1566 rhiABuffer = oitCtx.aBuffer;
1567 rhiAuxBuffer = oitCtx.auxBuffer;
1568 rhiCounterBuffer = oitCtx.counterBuffer;
1570 rhiABufferImage = data.getRenderResult(QSSGRenderResult::Key::ABufferImage);
1571 rhiAuxiliaryImage = data.getRenderResult(QSSGRenderResult::Key::AuxiliaryImage);
1572 rhiCounterImage = data.getRenderResult(QSSGRenderResult::Key::CounterImage);
1574 QSize dim = data.layerPrepResult.textureDimensions();
1575 dim.setWidth(dim.width() * ps.samples);
1576 dim.setHeight(dim.height() * ps.viewCount);
1577#ifdef QSSG_OIT_USE_BUFFERS
1578 if (!rhiAuxBuffer || rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u) || currentNodeCount == 0 || currentNodeCount != reportedNodeCount)
1580 if (!rhiAuxiliaryImage->texture || rhiAuxiliaryImage->texture->pixelSize() != dim || currentNodeCount == 0 || currentNodeCount != reportedNodeCount)
1583 quint32 extraNodeCount = 0;
1584#ifdef QSSG_OIT_USE_BUFFERS
1585 if (rhiAuxBuffer && rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u)) {
1586 if (rhiAuxBuffer->size() < (dim.width() * dim.height() * 4u))
1587 extraNodeCount = ensureFreeNodes((dim.width() * dim.height() * 4u) - rhiAuxBuffer->size(), 32u * 1024u);
1588 rhiAuxBuffer->destroy();
1589 rhiAuxBuffer =
nullptr;
1592 if (rhiABufferImage->texture) {
1593 const auto s = rhiAuxiliaryImage->texture->pixelSize();
1594 if (s.width() * s.height() < dim.width() * dim.height())
1595 extraNodeCount = ensureFreeNodes(s.width() * s.height() - dim.width() * dim.height(), 32u * 1024u);
1596 rhiABufferImage->texture->destroy();
1597 rhiAuxiliaryImage->texture->destroy();
1601 if (reportedNodeCount) {
1602 currentNodeCount = reportedNodeCount + extraNodeCount;
1604 quint32 size = RenderHelpers::rhiCalculateABufferSize(data.layerPrepResult.textureDimensions(), 4 * ps.samples * ps.viewCount);
1605 currentNodeCount = ensureFreeNodes(size * size, 32u * 1024u);
1607 data.layer.oitNodeCount = currentNodeCount;
1609#ifdef QSSG_OIT_USE_BUFFERS
1610 if (rhiABuffer && currentNodeCount * 16 != rhiABuffer->size()) {
1611 rhiABuffer->destroy();
1612 rhiABuffer =
nullptr;
1615 rhiABuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, currentNodeCount * 16);
1616 rhiABuffer->create();
1618 if (!rhiAuxBuffer) {
1619 rhiAuxBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, dim.width() * dim.height() * 4);
1620 rhiAuxBuffer->create();
1622 if (!rhiCounterBuffer) {
1623 rhiCounterBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, 4);
1624 rhiCounterBuffer->create();
1625 oitCtx.counterBuffer = rhiCounterBuffer;
1627 oitCtx.aBuffer = rhiABuffer;
1628 oitCtx.auxBuffer = rhiAuxBuffer;
1630 quint32 sizeWithLayers = RenderHelpers::rhiCalculateABufferSize(currentNodeCount);
1631 const QRhiTexture::Flags textureFlags = QRhiTexture::UsedWithLoadStore;
1632 rhiABufferImage->texture = rhi->newTexture(QRhiTexture::RGBA32UI, QSize(sizeWithLayers, sizeWithLayers), 1, textureFlags);
1633 rhiABufferImage->texture->create();
1634 rhiAuxiliaryImage->texture = rhi->newTexture(QRhiTexture::R32UI, dim, 1, textureFlags);
1635 rhiAuxiliaryImage->texture->create();
1636 if (!rhiCounterImage->texture) {
1637 rhiCounterImage->texture = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, textureFlags | QRhiTexture::UsedAsTransferSource);
1638 rhiCounterImage->texture->create();
1640 auto &oitrt = data.getOitRenderContext();
1641 readbackImage = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, QRhiTexture::UsedAsTransferSource);
1647 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1649 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1650 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1651#ifdef QSSG_OIT_USE_BUFFERS
1652 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearBufferShader();
1654 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearImageShader();
1656 QSSGRhiShaderResourceBindingList bindings;
1657 quint32 clearImageData[8] = {0};
1659 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1660 QRhiBuffer *&ubuf = dcd.ubuf;
1661 const int ubufSize =
sizeof(clearImageData);
1663 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1667 clearImageData[4] = data.layerPrepResult.textureDimensions().width();
1668 clearImageData[5] = data.layerPrepResult.textureDimensions().height();
1669 clearImageData[6] = ps.samples;
1670 clearImageData[7] = ps.viewCount;
1672 rub->updateDynamicBuffer(ubuf, 0, ubufSize, clearImageData);
1674#ifdef QSSG_OIT_USE_BUFFERS
1675 rub->uploadStaticBuffer(rhiCounterBuffer, 0, 4, &zero);
1677 rub->uploadTexture(rhiCounterImage->texture, {{0, 0, {&zero, 4}}});
1680 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1681#ifdef QSSG_OIT_USE_BUFFERS
1682 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1684 bindings.addImageStore(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1687 clearSrb = rhiCtxD->srb(bindings);
1689 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1691 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, rhiCtx->mainRenderPassDescriptor(), sortedTransparentObjects,
true);
1697 auto *ctx = renderer.contextInterface();
1698 const auto &rhiCtx = ctx->rhiContext();
1699 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1700 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1702 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1703 if (Q_LIKELY(renderTarget)) {
1704 cb->beginPass(renderTarget, Qt::black, {});
1706 QRhiShaderResourceBindings *srb = clearSrb;
1708 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
1709 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1710 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, renderTarget->renderPassDescriptor(), {});
1711 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1713 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render order-independent alpha"));
1714 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1715 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render order-independent alpha"));
1716 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
true);
1717 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1718 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1720 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1721 Q_TRACE(QSSG_renderPass_exit);
1725 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1726 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render alpha"));
1727 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1728 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render alpha"));
1730 QRhiShaderResourceBindings *srb = clearSrb;
1732 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1733 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1734 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(), {});
1736 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1737#ifdef QSSG_OIT_USE_BUFFERS
1738 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1739 QRhiReadbackResult *result =
nullptr;
1740 if (results.size() > 1) {
1741 result = results.takeLast();
1742 result->pixelSize = {};
1744 result->format = QRhiTexture::UnknownFormat;
1746 result =
new QRhiReadbackResult();
1748 const auto completedFunc = [
this, result](){
1750 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1751 quint32 nodeCount = *d;
1753 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1754 this->results.append(result);
1757 result->completed = completedFunc;
1758 rub->readBackBuffer(rhiCounterBuffer, 0, 4, result);
1761 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1763 QRhiReadbackDescription rbdesc;
1765 QRhiReadbackResult *result =
nullptr;
1766 if (results.size() > 1) {
1767 result = results.takeLast();
1768 result->pixelSize = {};
1770 result->format = QRhiTexture::UnknownFormat;
1772 result =
new QRhiReadbackResult();
1774 const auto completedFunc = [
this, result](){
1776 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1777 quint32 nodeCount = *d;
1779 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1780 this->results.append(result);
1783 result->completed = completedFunc;
1784 rub->readBackTexture(rbdesc, result);
1788 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1789 Q_TRACE(QSSG_renderPass_exit);
1877 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
1878 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1879 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1881 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1883 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
1886 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1887 QSSGRhiShaderResourceBindingList bindings;
1889 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
1890 QRhiSampler::Nearest,
1892 QRhiSampler::ClampToEdge,
1893 QRhiSampler::ClampToEdge,
1894 QRhiSampler::ClampToEdge });
1895 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiAccumTexture->texture, sampler);
1896 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, rhiRevealageTexture->texture, sampler);
1898 compositeSrb = rhiCtxD->srb(bindings);
1900 QRhiShaderResourceBindings *srb = compositeSrb;
1903 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D revealage"));
1904 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1905 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1906 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1907 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1908 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"revealage"));
1910 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1911 QSSGRhiShaderResourceBindingList bindings;
1913 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1914 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 }));
1915 QRhiBuffer *&ubuf = dcd.ubuf;
1917 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1918#ifdef QSSG_OIT_USE_BUFFERS
1919 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiABuffer);
1920 bindings.addStorageBuffer(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1922 bindings.addImageLoad(1, QRhiShaderResourceBinding::FragmentStage, rhiABufferImage->texture, 0);
1923 bindings.addImageLoad(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1926 compositeSrb = rhiCtxD->srb(bindings);
1928 QRhiShaderResourceBindings *srb = compositeSrb;
1931 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D oit-composite"));
1932 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
1933 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1934 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
1935 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
1936 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"oit-composite"));
2034 QSSGRenderUserPass *passNode,
2035 std::vector<UserPassData> &outData,
2036 QSSGRhiRenderableTextureV2Ptr renderableTexture)
2040 const bool isTopLevelPass = (renderableTexture ==
nullptr);
2042 QSSGRenderCamera *camera = data.renderedCameras[0];
2043 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2045 const QSize targetSize = data.layerPrepResult.textureDimensions();
2047 static const auto needsRebuild = [](QRhiTexture *texture,
const QSize &size, QRhiTexture::Format format) {
2048 return !texture || texture->pixelSize() != size || texture->format() != format;
2051 qCDebug(lcUserRenderPass,
"renderPrep in UserRenderPass");
2053 const QSSGResourceId currentPassId = QSSGRenderGraphObjectUtils::getResourceId(*passNode);
2054 if (visitedPasses.find(currentPassId) != visitedPasses.end()) {
2055 qWarning(
"UserRenderPass: Circular dependency detected in SubRenderPass chain. Ignoring pass.");
2060 if (visitedPasses.size() >= MAX_SUBPASS_DEPTH) {
2061 qWarning(
"UserRenderPass: Maximum SubRenderPass nesting depth (%zu) exceeded. Ignoring pass.", MAX_SUBPASS_DEPTH);
2065 visitedPasses.insert(currentPassId);
2068 currentPassData.clearColor = passNode->clearColor;
2069 currentPassData.depthStencilClearValue = passNode->depthStencilClearValue;
2071 renderableTexture = currentPassData.renderableTexture = data.requestUserRenderPassManager()->getOrCreateRenderableTexture(*passNode);
2073 currentPassData.renderableTexture = renderableTexture;
2075 QSSGRenderableObjectList &renderables = currentPassData.renderables;
2076 QSSGRhiGraphicsPipelineState &ps = currentPassData.ps;
2077 const auto &renderTarget = currentPassData.renderableTexture;
2080 ps = data.getPipelineState();
2082 bool renderablesFiltered =
false;
2084 bool needsDepthStencilRenderBuffer =
false;
2085 QSSGAllocateTexturePtr depthTextureAllocCommand;
2087 QVarLengthArray<QSSGColorAttachment *, 16> colorAttachments;
2088 QVarLengthArray<QSSGResourceId, 4> subPassIds;
2091 for (
const QSSGCommand *theCommand : std::as_const(passNode->commands)) {
2094 qCDebug(lcUserRenderPass) <<
"Exec. command: >" << theCommand->typeAsString() <<
"--" << theCommand->debugString();
2096 switch (theCommand->m_type) {
2097 case CommandType::ColorAttachment:
2099 const QSSGColorAttachment *colorAttachCmd =
static_cast<
const QSSGColorAttachment *>(theCommand);
2100 colorAttachments.push_back(
const_cast<QSSGColorAttachment *>(colorAttachCmd));
2103 case CommandType::DepthTextureAttachment:
2105 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2106 const QSSGDepthTextureAttachment *depthAttachCmd =
static_cast<
const QSSGDepthTextureAttachment *>(theCommand);
2107 needsDepthStencilRenderBuffer =
false;
2108 depthTextureAllocCommand = depthAttachCmd->m_textureCmd;
2111 case CommandType::AddShaderDefine:
2113 const auto *defineCmd =
static_cast<
const QSSGAddShaderDefine *>(theCommand);
2114 const auto &defineName = defineCmd->m_name;
2115 if (defineName.size() > 0) {
2116 QByteArray value = QByteArray::number(defineCmd->m_value);
2117 currentPassData.shaderDefines.push_back({ defineName, value });
2121 case CommandType::RenderablesFilter:
2123 auto filterCommand =
static_cast<
const QSSGRenderablesFilterCommand *>(theCommand);
2127 enum RenderableType : quint8 {
2133 if (filterCommand->renderableTypes & RenderableType::Opaque)
2134 renderables = data.getSortedOpaqueRenderableObjects(*camera, 0, filterCommand->layerMask);
2135 if (filterCommand->renderableTypes & RenderableType::Transparent)
2136 renderables += data.getSortedTransparentRenderableObjects(*camera, 0, filterCommand->layerMask);
2140 renderablesFiltered =
true;
2144 case CommandType::PipelineStateOverride:
2146 auto pipelineCommand =
static_cast<
const QSSGPipelineStateOverrideCommand *>(theCommand);
2147 if (pipelineCommand->m_depthTestEnabled)
2148 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, *pipelineCommand->m_depthTestEnabled);
2149 if (pipelineCommand->m_depthWriteEnabled)
2150 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, *pipelineCommand->m_depthWriteEnabled);
2151 if (pipelineCommand->m_blendEnabled)
2152 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, *pipelineCommand->m_blendEnabled);
2153 if (pipelineCommand->m_usesStencilReference)
2154 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef, *pipelineCommand->m_usesStencilReference);
2155 if (pipelineCommand->m_usesScissor)
2156 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor, *pipelineCommand->m_usesScissor);
2157 if (pipelineCommand->m_depthFunction)
2158 ps.depthFunc = *pipelineCommand->m_depthFunction;
2159 if (pipelineCommand->m_cullMode) {
2160 ps.cullMode = *pipelineCommand->m_cullMode;
2161 ps.userSetCullMode =
true;
2163 if (pipelineCommand->m_polygonMode)
2164 ps.polygonMode = *pipelineCommand->m_polygonMode;
2165 if (pipelineCommand->m_stencilOpFrontState)
2166 ps.stencilOpFrontState = *pipelineCommand->m_stencilOpFrontState;
2167 if (pipelineCommand->m_stencilWriteMask)
2168 ps.stencilWriteMask = *pipelineCommand->m_stencilWriteMask;
2169 if (pipelineCommand->m_stencilReference)
2170 ps.stencilRef = *pipelineCommand->m_stencilReference;
2171 if (pipelineCommand->m_viewport)
2172 ps.viewport = *pipelineCommand->m_viewport;
2173 if (pipelineCommand->m_scissor)
2174 ps.scissor = *pipelineCommand->m_scissor;
2175 if (pipelineCommand->m_targetBlend0)
2176 ps.targetBlend[0] = *pipelineCommand->m_targetBlend0;
2177 if (pipelineCommand->m_targetBlend1)
2178 ps.targetBlend[1] = *pipelineCommand->m_targetBlend1;
2179 if (pipelineCommand->m_targetBlend2)
2180 ps.targetBlend[2] = *pipelineCommand->m_targetBlend2;
2181 if (pipelineCommand->m_targetBlend3)
2182 ps.targetBlend[3] = *pipelineCommand->m_targetBlend3;
2183 if (pipelineCommand->m_targetBlend4)
2184 ps.targetBlend[4] = *pipelineCommand->m_targetBlend4;
2185 if (pipelineCommand->m_targetBlend5)
2186 ps.targetBlend[5] = *pipelineCommand->m_targetBlend5;
2187 if (pipelineCommand->m_targetBlend6)
2188 ps.targetBlend[6] = *pipelineCommand->m_targetBlend6;
2189 if (pipelineCommand->m_targetBlend7)
2190 ps.targetBlend[7] = *pipelineCommand->m_targetBlend7;
2193 case CommandType::DepthStencilAttachment:
2195 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2196 needsDepthStencilRenderBuffer =
true;
2198 case CommandType::SubRenderPass:
2200 auto subPassCommand =
static_cast<
const QSSGSubRenderPass *>(theCommand);
2201 if (subPassCommand && subPassCommand->m_userPassId != QSSGResourceId::Invalid)
2202 subPassIds.append(subPassCommand->m_userPassId);
2206 qWarning() <<
"Effect command" << theCommand->typeAsString() <<
"not implemented";
2211 if (colorAttachments.size() > 4) {
2212 colorAttachments.resize(4);
2213 qWarning() <<
"UserRenderPass supports up to 4 color attachments only.";
2218 if (isTopLevelPass) {
2220 bool needsBuild = !renderTarget->isValid();
2222 const qsizetype oldAttachmentCount = renderTarget->colorAttachmentCount();
2224 if (oldAttachmentCount != colorAttachments.size())
2231 if (renderTarget->getRenderTarget() && renderTarget->getRenderTarget()->flags() != passNode->renderTargetFlags)
2237 for (
int i = 0; i != oldAttachmentCount; ++i) {
2238 const auto &colorAttachment = colorAttachments.at(i);
2239 QSSG_ASSERT(colorAttachment !=
nullptr,
continue);
2240 const auto expectedFormat = QSSGBufferManager::toRhiFormat(colorAttachment->format());
2241 const auto &texture = renderTarget->getColorTexture(i);
2242 needsBuild = needsBuild || needsRebuild(&(*texture->texture()), targetSize, expectedFormat);
2246 if (needsDepthStencilRenderBuffer != (renderTarget->getDepthStencil() !=
nullptr))
2250 if (depthTextureAllocCommand) {
2251 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2252 const auto &depthTextureWrapper = renderTarget->getDepthTexture();
2253 needsBuild = depthTextureWrapper ==
nullptr;
2254 needsBuild = needsBuild || needsRebuild(&(*depthTextureWrapper->texture()), targetSize, format);
2256 if (renderTarget->getDepthTexture() !=
nullptr)
2262 const auto &rt = renderTarget->getRenderTarget();
2263 if (rt && rt->flags() != passNode->renderTargetFlags)
2269 renderTarget->reset();
2271 QRhiTextureRenderTargetDescription rtDesc;
2274 const qsizetype colorAttachmentCount = qMax<qsizetype>(colorAttachments.size(), 1);
2276 bool createSucceeded =
true;
2277 bool colorAllocatorsNeedsUpdate =
false;
2281 QVarLengthArray<QRhiTexture *, 4> textures;
2282 for (qsizetype i = 0; i < colorAttachmentCount && createSucceeded ; ++i) {
2283 const auto &colorAttCmd = colorAttachments.at(i);
2284 const auto &name = colorAttCmd->m_name;
2285 const auto format = QSSGBufferManager::toRhiFormat(colorAttCmd->format());
2286 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2287 if (allocateTexCmd->texture() && !needsRebuild(&(*allocateTexCmd->texture()->texture()), targetSize, format)) {
2290 textures.push_back(allocateTexCmd->texture()->texture().get());
2292 auto *tex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2294 createSucceeded = createSucceeded && tex->create();
2295 textures.push_back(tex);
2299 colorAllocatorsNeedsUpdate =
true;
2303 rtDesc.setColorAttachments(textures.cbegin(), textures.cend());
2306 if (needsDepthStencilRenderBuffer) {
2307 auto renderBuffer = rhiCtx->rhi()->newRenderBuffer(QRhiRenderBuffer::DepthStencil, targetSize, ps.samples);
2308 if (renderBuffer->create())
2309 rtDesc.setDepthStencilBuffer(renderBuffer);
2310 }
else if (depthTextureAllocCommand) {
2311 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2312 if (depthTextureAllocCommand->texture() && !needsRebuild(&(*depthTextureAllocCommand->texture()->texture()), targetSize, format)) {
2313 rtDesc.setDepthTexture(depthTextureAllocCommand->texture()->texture().get());
2316 QRhiTexture *depthTex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2317 if (depthTex->create())
2318 rtDesc.setDepthTexture(depthTex);
2322 if (createSucceeded) {
2324 renderTarget->setDescription(rhiCtx->rhi(),
std::move(rtDesc), passNode->renderTargetFlags);
2327 if (colorAllocatorsNeedsUpdate) {
2328 for (qsizetype i = 0; i < colorAttachmentCount; ++i) {
2329 const auto &colorAttCmd = colorAttachments.at(i);
2330 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2331 allocateTexCmd->setTexture(renderTarget->getColorTexture(i));
2335 if (depthTextureAllocCommand)
2336 depthTextureAllocCommand->setTexture(renderTarget->getDepthTexture());
2339 renderTarget->resetRenderTarget();
2340 qWarning() <<
"Failed to create textures for UserRenderPass";
2346 Q_ASSERT(renderTarget->isValid());
2348 ps.colorAttachmentCount =
int(renderTarget->colorAttachmentCount());
2351 for (
const auto &subPassId : std::as_const(subPassIds)) {
2352 QSSGRenderUserPass *userPassNode = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subPassId);
2353 QSSG_ASSERT(userPassNode && userPassNode->type == QSSGRenderGraphObject::Type::RenderPass,
continue);
2354 prepareSubPass(renderer, data, userPassNode, currentPassData.subPassData, currentPassData.renderableTexture);
2357 if (passNode->passMode == QSSGRenderUserPass::PassModes::UserPass) {
2359 if (!renderablesFiltered && renderables.isEmpty())
2360 renderables = data.getSortedOpaqueRenderableObjects(*camera);
2362 if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::AugmentMaterial) {
2366 QSSG_ASSERT(shaderAugmentation.outputs.size() == 0, shaderAugmentation.outputs.clear());
2367 shaderAugmentation.defines =
std::move(currentPassData.shaderDefines);
2369 for (
int i = 0, end = colorAttachments.size(); i < end; ++i) {
2370 const auto &colorAttCmd = colorAttachments.at(i);
2371 const auto &name = colorAttCmd->m_name;
2372 if (name.size() > 0)
2373 shaderAugmentation.outputs.push_back(name);
2375 shaderAugmentation.outputs.push_back(getDefaultOutputName(size_t(i)));
2378 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2379 shaderFeatures.disableTonemapping();
2381 currentPassData.index = RenderHelpers::rhiPrepareAugmentedUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), shaderAugmentation, data, renderables, shaderFeatures);
2382 }
else if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::OverrideMaterial) {
2384 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2385 shaderFeatures.disableTonemapping();
2387 currentPassData.index = RenderHelpers::rhiPrepareOverrideMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), passNode->overrideMaterial, data, renderables, shaderFeatures);
2391 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2392 shaderFeatures.disableTonemapping();
2393 currentPassData.index = RenderHelpers::rhiPrepareOriginalMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), data, renderables, shaderFeatures);
2395 outData.push_back(currentPassData);
2398 if (passNode->passMode == QSSGRenderUserPass::PassModes::SkyboxPass) {
2399 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2400 if (data.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && data.layer.skyBoxCubeMap) {
2401 if (!currentPassData.skyboxCubeMapPass)
2404 currentPassData.skyboxCubeMapPass->skipTonemapping =
true;
2405 currentPassData.skyboxCubeMapPass->renderPrep(renderer, data);
2406 currentPassData.skyboxCubeMapPass->ps.samples = ps.samples;
2407 currentPassData.skyboxCubeMapPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2409 currentPassData.skyboxPass =
std::nullopt;
2410 }
else if ((data.layer.background == QSSGRenderLayer::Background::SkyBox && data.layer.lightProbe)
2411 || (data.layer.background == QSSGRenderLayer::Background::SkyMaterial && data.layer.skyMaterial)) {
2412 if (!currentPassData.skyboxPass)
2415 currentPassData.skyboxPass->skipTonemapping =
true;
2416 currentPassData.skyboxPass->renderPrep(renderer, data);
2417 currentPassData.skyboxPass->ps.samples = ps.samples;
2418 currentPassData.skyboxPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2420 currentPassData.skyboxCubeMapPass =
std::nullopt;
2422 outData.push_back(currentPassData);
2424 }
else if (passNode->passMode == QSSGRenderUserPass::PassModes::Item2DPass) {
2425 if (!currentPassData.item2DPass)
2427 const bool hasItem2Ds = (data.item2DsView.size() > 0);
2430 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(renderer.contextInterface()->rhiContext().get());
2431 QRhiRenderTarget *prevRenderTarget = rhiCtx->renderTarget();
2432 rhiCtxD->setRenderTarget(renderTarget->getRenderTarget().get());
2433 currentPassData.item2DPass->renderPrep(renderer, data);
2435 rhiCtxD->setRenderTarget(prevRenderTarget);
2436 outData.push_back(currentPassData);