1190 const auto &ctx = *renderer.contextInterface();
1191 const auto &rhiCtx = ctx.rhiContext();
1192 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1193 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
1194 QSSG_ASSERT(data.renderedCameras.count() == data.layer.viewCount,
return);
1195 layer = &data.layer;
1200 rpDesc = rhiCtx->mainRenderPassDescriptor();
1201 ps = data.getPipelineState();
1202 ps.samples = rhiCtx->mainPassSampleCount();
1203 ps.viewCount = data.layer.viewCount;
1204 ps.polygonMode = QRhiGraphicsPipeline::Fill;
1207 skipTonemapping = layer->firstEffect !=
nullptr;
1209 QRhi *rhi = rhiCtx->rhi();
1210 QSSGRenderSkyMaterial &skyMaterial = *layer->skyMaterial;
1211 const int viewCount = data.layer.viewCount;
1213 const QSSGRenderLayer::TonemapMode tonemapMode =
1214 skipTonemapping && (layer->tonemapMode != QSSGRenderLayer::TonemapMode::Custom)
1215 ? QSSGRenderLayer::TonemapMode::None
1216 : layer->tonemapMode;
1217 QSSGShaderFeatures tonemapFeatures;
1218 quint32 tonemapKey = 0;
1219 skyMaterialTonemapFeatures(tonemapMode, tonemapFeatures, tonemapKey);
1221 pipeline = skyMaterial.ensureBackgroundPipeline(ctx, tonemapFeatures, tonemapKey, viewCount);
1229 const QMatrix3x3 o = layer->lightProbeSettings.probeOrientation;
1230 const QMatrix4x4 orientation(o(0, 0), o(0, 1), o(0, 2), 0.0f,
1231 o(1, 0), o(1, 1), o(1, 2), 0.0f,
1232 o(2, 0), o(2, 1), o(2, 2), 0.0f,
1233 0.0f, 0.0f, 0.0f, 1.0f);
1234 QVarLengthArray<QMatrix4x4, 2> inverseProjections;
1235 QVarLengthArray<QMatrix4x4, 2> viewRotations;
1236 for (
int v = 0; v < viewCount; ++v) {
1237 const QSSGRenderCamera &camera = *data.renderedCameras[v];
1238 inverseProjections.append(camera.projection.inverted());
1239 QMatrix4x4 cameraRotation = data.getGlobalTransform(camera);
1240 cameraRotation.setColumn(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
1241 viewRotations.append(orientation * cameraRotation);
1243 const float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
1244 const float exposure = layer->lightProbeSettings.probeExposure;
1246 skyMaterial.updateBackgroundUniforms(ctx,
this, inverseProjections, viewRotations, adjustY, exposure);
1248 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1249 backgroundSrb = rhiCtxD->srb(skyMaterial.backgroundBindings);
1251 switch (skyMaterial.skyboxMode) {
1252 case QSSGRenderSkyMaterial::SkyboxMode::ScreenSpaceHalf:
1255 case QSSGRenderSkyMaterial::SkyboxMode::ScreenSpaceQuarter:
1258 case QSSGRenderSkyMaterial::SkyboxMode::ScreenSpaceFull:
1259 case QSSGRenderSkyMaterial::SkyboxMode::Cubemap:
1264 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(),
nullptr);
1269 const std::array<
float, 4> vp = ps.viewport.viewport();
1270 const QSize fullSize(
int(vp.at(2)),
int(vp.at(3)));
1271 const QSize targetSize = (fullSize / qreal(
scaleDivisor)).expandedTo(QSize(1, 1));
1272 const bool multiView = viewCount >= 2;
1273 const int wantArraySize = multiView ? viewCount : 0;
1275 offscreenTexture = data.getRenderResult(QSSGRenderResult::Key::SkyMaterialBackgroundTexture);
1276 QSSGRhiRenderableTexture *tex = offscreenTexture;
1277 if (!tex->texture || tex->texture->pixelSize() != targetSize || tex->texture->arraySize() != wantArraySize) {
1279 tex->texture = multiView ? rhi->newTextureArray(QRhiTexture::RGBA16F, viewCount, targetSize, 1, QRhiTexture::RenderTarget)
1280 : rhi->newTexture(QRhiTexture::RGBA16F, targetSize, 1, QRhiTexture::RenderTarget);
1281 if (!tex->texture->create()) {
1282 qWarning(
"Failed to build SkyMaterial screen-space background texture");
1284 offscreenTexture =
nullptr;
1287 QRhiColorAttachment att(tex->texture);
1288 att.setMultiViewCount(viewCount);
1289 QRhiTextureRenderTargetDescription desc;
1290 desc.setColorAttachments({ att });
1291 tex->rt = rhi->newTextureRenderTarget(desc);
1292 tex->rt->setName(QByteArrayLiteral(
"SkyMaterial screen-space background"));
1293 tex->rpDesc = tex->rt->newCompatibleRenderPassDescriptor();
1294 tex->rt->setRenderPassDescriptor(tex->rpDesc);
1295 if (!tex->rt->create()) {
1296 qWarning(
"Failed to build SkyMaterial screen-space background render target");
1298 offscreenTexture =
nullptr;
1303 QSSGRhiGraphicsPipelineState offscreenPs;
1304 offscreenPs.viewport = QRhiViewport(0, 0,
float(targetSize.width()),
float(targetSize.height()));
1305 offscreenPs.samples = 1;
1306 offscreenPs.viewCount = viewCount;
1307 offscreenPs.polygonMode = QRhiGraphicsPipeline::Fill;
1308 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(offscreenPs, pipeline.get());
1309 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx.get(), &offscreenPs, backgroundSrb,
1310 offscreenTexture->rt, QSSGRhiQuadRenderer::RenderBehind);
1679 auto *ctx = renderer.contextInterface();
1680 const auto &rhiCtx = ctx->rhiContext();
1681 auto *rhi = rhiCtx->rhi();
1683 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
1684 QSSGRenderCamera *camera = data.renderedCameras[0];
1686 ps = data.getPipelineState();
1687 ps.samples = rhiCtx->mainPassSampleCount();
1688 ps.viewCount = rhiCtx->mainPassViewCount();
1690 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1691 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1693 shaderFeatures = data.getShaderFeatures();
1694 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1696 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1697 ps.colorAttachmentCount = 2;
1699 rhiAccumTexture = data.getRenderResult(QSSGRenderResult::Key::AccumTexture);
1700 rhiRevealageTexture = data.getRenderResult(QSSGRenderResult::Key::RevealageTexture);
1702 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTextureMS);
1704 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTexture);
1705 if (!rhiDepthTexture->isValid())
1707 auto &oitrt = data.getOitRenderContext();
1708 if (!oitrt.oitRenderTarget || oitrt.oitRenderTarget->pixelSize() != data.layerPrepResult.textureDimensions()
1709 || rhiDepthTexture->texture != oitrt.oitRenderTarget->description().depthTexture()
1710 || ps.samples != oitrt.oitRenderTarget->sampleCount()) {
1711 if (oitrt.oitRenderTarget) {
1712 delete oitrt.oitRenderTarget;
1713 delete oitrt.renderPassDescriptor;
1714 delete rhiAccumTexture->texture;
1715 delete rhiRevealageTexture->texture;
1716 oitrt.oitRenderTarget =
nullptr;
1717 oitrt.renderPassDescriptor =
nullptr;
1718 rhiAccumTexture->texture =
nullptr;
1719 rhiRevealageTexture->texture =
nullptr;
1721 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget;
1722 if (ps.viewCount >= 2) {
1723 rhiAccumTexture->texture = rhi->newTextureArray(QRhiTexture::RGBA16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1724 rhiRevealageTexture->texture = rhi->newTextureArray(QRhiTexture::R16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1726 rhiAccumTexture->texture = rhi->newTexture(QRhiTexture::RGBA16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1727 rhiRevealageTexture->texture = rhi->newTexture(QRhiTexture::R16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1729 rhiAccumTexture->texture->create();
1730 rhiRevealageTexture->texture->create();
1732 QRhiTextureRenderTargetDescription desc;
1733 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1734 desc.setDepthTexture(rhiDepthTexture->texture);
1736 if (oitrt.oitRenderTarget ==
nullptr) {
1737 oitrt.oitRenderTarget = rhi->newTextureRenderTarget(desc, QRhiTextureRenderTarget::PreserveDepthStencilContents);
1738 oitrt.renderPassDescriptor = oitrt.oitRenderTarget->newCompatibleRenderPassDescriptor();
1739 oitrt.oitRenderTarget->setRenderPassDescriptor(oitrt.renderPassDescriptor);
1740 oitrt.oitRenderTarget->create();
1742 renderTarget = oitrt.oitRenderTarget;
1745 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1746 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1747 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1749 QSSGRhiShaderResourceBindingList bindings;
1750 QVector4D clearData[2];
1751 clearData[0] = QVector4D(0.0, 0.0, 0.0, 0.0);
1752 clearData[1] = QVector4D(1.0, 1.0, 1.0, 1.0);
1754 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr,
nullptr, 0 }));
1755 QRhiBuffer *&ubuf = dcd.ubuf;
1756 const int ubufSize =
sizeof(clearData);
1758 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1762 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1763 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1764 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1766 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1768 clearSrb = rhiCtxD->srb(bindings);
1770 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1771 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::One;
1772 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::One;
1773 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::One;
1774 ps.targetBlend[1].srcAlpha = QRhiGraphicsPipeline::Zero;
1775 ps.targetBlend[1].srcColor = QRhiGraphicsPipeline::Zero;
1776 ps.targetBlend[1].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1777 ps.targetBlend[1].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1779 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects,
true);
1780 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1789 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1790 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1791 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1792 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha;
1793 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1794 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1796 shaderFeatures = data.getShaderFeatures();
1797 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1799#ifdef QSSG_OIT_USE_BUFFERS
1800 auto &oitCtx = data.getOitRenderContext();
1801 rhiABuffer = oitCtx.aBuffer;
1802 rhiAuxBuffer = oitCtx.auxBuffer;
1803 rhiCounterBuffer = oitCtx.counterBuffer;
1805 rhiABufferImage = data.getRenderResult(QSSGRenderResult::Key::ABufferImage);
1806 rhiAuxiliaryImage = data.getRenderResult(QSSGRenderResult::Key::AuxiliaryImage);
1807 rhiCounterImage = data.getRenderResult(QSSGRenderResult::Key::CounterImage);
1809 QSize dim = data.layerPrepResult.textureDimensions();
1810 dim.setWidth(dim.width() * ps.samples);
1811 dim.setHeight(dim.height() * ps.viewCount);
1812#ifdef QSSG_OIT_USE_BUFFERS
1813 if (!rhiAuxBuffer || rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u) || currentNodeCount == 0 || linkedListRequiresResize(dim))
1815 if (!rhiAuxiliaryImage->texture || rhiAuxiliaryImage->texture->pixelSize() != dim || currentNodeCount == 0 || linkedListRequiresResize(dim))
1818 quint32 extraNodeCount = 0;
1819#ifdef QSSG_OIT_USE_BUFFERS
1820 if (rhiAuxBuffer && rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u)) {
1821 if (rhiAuxBuffer->size() < (dim.width() * dim.height() * 4u))
1822 extraNodeCount = ensureFreeNodes((dim.width() * dim.height() * 4u) - rhiAuxBuffer->size(), 32u * 1024u);
1823 rhiAuxBuffer->destroy();
1824 rhiAuxBuffer =
nullptr;
1827 if (rhiABufferImage->texture) {
1828 const auto s = rhiAuxiliaryImage->texture->pixelSize();
1829 if (s.width() * s.height() < dim.width() * dim.height())
1830 extraNodeCount = ensureFreeNodes(dim.width() * dim.height() - s.width() * s.height(), 32u * 1024u);
1831 rhiABufferImage->texture->destroy();
1832 rhiAuxiliaryImage->texture->destroy();
1836 if (reportedNodeCount) {
1838 currentNodeCount = ensureFreeNodes(reportedNodeCount + extraNodeCount, dim.width() * dim.height() / 2);
1840 quint32 size = RenderHelpers::rhiCalculateABufferSize(data.layerPrepResult.textureDimensions(), 4 * ps.samples * ps.viewCount);
1841 currentNodeCount = ensureFreeNodes(size * size, 32u * 1024u);
1843 data.layer.oitNodeCount = currentNodeCount;
1845#ifdef QSSG_OIT_USE_BUFFERS
1846 if (rhiABuffer && currentNodeCount * 16 != rhiABuffer->size()) {
1847 rhiABuffer->destroy();
1848 rhiABuffer =
nullptr;
1851 rhiABuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, currentNodeCount * 16);
1852 rhiABuffer->create();
1854 if (!rhiAuxBuffer) {
1855 rhiAuxBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, dim.width() * dim.height() * 4);
1856 rhiAuxBuffer->create();
1858 if (!rhiCounterBuffer) {
1859 rhiCounterBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, 4);
1860 rhiCounterBuffer->create();
1861 oitCtx.counterBuffer = rhiCounterBuffer;
1863 oitCtx.aBuffer = rhiABuffer;
1864 oitCtx.auxBuffer = rhiAuxBuffer;
1866 quint32 sizeWithLayers = RenderHelpers::rhiCalculateABufferSize(currentNodeCount);
1867 const QRhiTexture::Flags textureFlags = QRhiTexture::UsedWithLoadStore;
1868 rhiABufferImage->texture = rhi->newTexture(QRhiTexture::RGBA32UI, QSize(sizeWithLayers, sizeWithLayers), 1, textureFlags);
1869 rhiABufferImage->texture->create();
1870 rhiAuxiliaryImage->texture = rhi->newTexture(QRhiTexture::R32UI, dim, 1, textureFlags);
1871 rhiAuxiliaryImage->texture->create();
1872 if (!rhiCounterImage->texture) {
1873 rhiCounterImage->texture = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, textureFlags | QRhiTexture::UsedAsTransferSource);
1874 rhiCounterImage->texture->create();
1876 auto &oitrt = data.getOitRenderContext();
1877 readbackImage = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, QRhiTexture::UsedAsTransferSource);
1883 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1885 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1886 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1887#ifdef QSSG_OIT_USE_BUFFERS
1888 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearBufferShader();
1890 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearImageShader();
1892 QSSGRhiShaderResourceBindingList bindings;
1893 quint32 clearImageData[8] = {0};
1895 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr,
nullptr, 0 }));
1896 QRhiBuffer *&ubuf = dcd.ubuf;
1897 const int ubufSize =
sizeof(clearImageData);
1899 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1903 clearImageData[4] = data.layerPrepResult.textureDimensions().width();
1904 clearImageData[5] = data.layerPrepResult.textureDimensions().height();
1905 clearImageData[6] = ps.samples;
1906 clearImageData[7] = ps.viewCount;
1908 rub->updateDynamicBuffer(ubuf, 0, ubufSize, clearImageData);
1910#ifdef QSSG_OIT_USE_BUFFERS
1911 rub->uploadStaticBuffer(rhiCounterBuffer, 0, 4, &zero);
1913 rub->uploadTexture(rhiCounterImage->texture, {{0, 0, {&zero, 4}}});
1916 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1917#ifdef QSSG_OIT_USE_BUFFERS
1918 bindings.addStorageBufferStore(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1920 bindings.addImageStore(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1923 clearSrb = rhiCtxD->srb(bindings);
1925 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1927 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, rhiCtx->mainRenderPassDescriptor(), sortedTransparentObjects,
true);
1933 auto *ctx = renderer.contextInterface();
1934 const auto &rhiCtx = ctx->rhiContext();
1935 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1936 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1938 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1939 if (Q_LIKELY(renderTarget)) {
1940 cb->beginPass(renderTarget, Qt::black, {});
1942 QRhiShaderResourceBindings *srb = clearSrb;
1944 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
1945 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1946 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, renderTarget->renderPassDescriptor(), {});
1947 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1949 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render order-independent alpha"));
1950 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1951 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render order-independent alpha"));
1952 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
true);
1953 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1954 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1956 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1957 Q_TRACE(QSSG_renderPass_exit);
1961 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1962 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render alpha"));
1963 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1964 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render alpha"));
1966 QRhiShaderResourceBindings *srb = clearSrb;
1968 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1969 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1970 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(), {});
1972 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1975 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1976 QRhiReadbackResult *result =
nullptr;
1979 result->pixelSize = {};
1981 result->format = QRhiTexture::UnknownFormat;
1983 result =
new QRhiReadbackResult();
1986 const auto completedFunc = [
this, oitrt, result](){
1988 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1989 quint32 nodeCount = *d;
1991 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1992 oitrt->completedResults.append(result);
1993 QSSG_ASSERT(oitrt->pendingResult == result,
return;);
1994 oitrt->pendingResult =
nullptr;
1997 result->completed = completedFunc;
1998#ifdef QSSG_OIT_USE_BUFFERS
1999 rub->readBackBuffer(rhiCounterBuffer, 0, 4, result);
2002 QRhiReadbackDescription rbdesc;
2004 rub->readBackTexture(rbdesc, result);
2010 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
2011 Q_TRACE(QSSG_renderPass_exit);
2100 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2101 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
2102 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
2104 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
2106 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
2109 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
2110 QSSGRhiShaderResourceBindingList bindings;
2112 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2113 QRhiSampler::Nearest,
2115 QRhiSampler::ClampToEdge,
2116 QRhiSampler::ClampToEdge,
2117 QRhiSampler::ClampToEdge });
2118 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiAccumTexture->texture, sampler);
2119 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, rhiRevealageTexture->texture, sampler);
2121 compositeSrb = rhiCtxD->srb(bindings);
2123 QRhiShaderResourceBindings *srb = compositeSrb;
2126 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D revealage"));
2127 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
2128 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
2129 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
2130 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
2131 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"revealage"));
2133 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
2134 QSSGRhiShaderResourceBindingList bindings;
2136 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
2137 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this,
nullptr,
nullptr,
nullptr, 0 }));
2138 QRhiBuffer *&ubuf = dcd.ubuf;
2140 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
2141#ifdef QSSG_OIT_USE_BUFFERS
2142 bindings.addStorageBufferLoad(1, QRhiShaderResourceBinding::FragmentStage, rhiABuffer);
2143 bindings.addStorageBufferLoad(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
2145 bindings.addImageLoad(1, QRhiShaderResourceBinding::FragmentStage, rhiABufferImage->texture, 0);
2146 bindings.addImageLoad(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
2149 compositeSrb = rhiCtxD->srb(bindings);
2151 QRhiShaderResourceBindings *srb = compositeSrb;
2154 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D oit-composite"));
2155 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
2156 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
2157 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
2158 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
2159 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"oit-composite"));
2257 QSSGRenderUserPass *passNode,
2258 std::vector<UserPassData> &outData,
2259 QSSGRhiRenderableTextureV2Ptr renderableTexture)
2263 const bool isTopLevelPass = (renderableTexture ==
nullptr);
2265 QSSGRenderCamera *camera = data.renderedCameras[0];
2266 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2268 const QSize targetSize = data.layerPrepResult.textureDimensions();
2270 static const auto needsRebuild = [](QRhiTexture *texture,
const QSize &size, QRhiTexture::Format format) {
2271 return !texture || texture->pixelSize() != size || texture->format() != format;
2274 qCDebug(lcUserRenderPass,
"renderPrep in UserRenderPass");
2276 const QSSGResourceId currentPassId = QSSGRenderGraphObjectUtils::getResourceId(*passNode);
2277 if (visitedPasses.find(currentPassId) != visitedPasses.end()) {
2278 qWarning(
"UserRenderPass: Circular dependency detected in SubRenderPass chain. Ignoring pass.");
2283 if (visitedPasses.size() >= MAX_SUBPASS_DEPTH) {
2284 qWarning(
"UserRenderPass: Maximum SubRenderPass nesting depth (%zu) exceeded. Ignoring pass.", MAX_SUBPASS_DEPTH);
2288 visitedPasses.insert(currentPassId);
2291 currentPassData.clearColor = passNode->clearColor;
2292 currentPassData.depthStencilClearValue = passNode->depthStencilClearValue;
2294 renderableTexture = currentPassData.renderableTexture = data.requestUserRenderPassManager()->getOrCreateRenderableTexture(*passNode);
2296 currentPassData.renderableTexture = renderableTexture;
2298 QSSGRenderableObjectList &renderables = currentPassData.renderables;
2299 QSSGRhiGraphicsPipelineState &ps = currentPassData.ps;
2300 const auto &renderTarget = currentPassData.renderableTexture;
2303 ps = data.getPipelineState();
2305 bool renderablesFiltered =
false;
2307 bool needsDepthStencilRenderBuffer =
false;
2308 QSSGAllocateTexturePtr depthTextureAllocCommand;
2310 QVarLengthArray<QSSGColorAttachment *, 16> colorAttachments;
2311 QVarLengthArray<QSSGResourceId, 4> subPassIds;
2314 for (
const QSSGCommand *theCommand : std::as_const(passNode->commands)) {
2317 qCDebug(lcUserRenderPass) <<
"Exec. command: >" << theCommand->typeAsString() <<
"--" << theCommand->debugString();
2319 switch (theCommand->m_type) {
2320 case CommandType::ColorAttachment:
2322 const QSSGColorAttachment *colorAttachCmd =
static_cast<
const QSSGColorAttachment *>(theCommand);
2323 colorAttachments.push_back(
const_cast<QSSGColorAttachment *>(colorAttachCmd));
2326 case CommandType::DepthTextureAttachment:
2328 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2329 const QSSGDepthTextureAttachment *depthAttachCmd =
static_cast<
const QSSGDepthTextureAttachment *>(theCommand);
2330 needsDepthStencilRenderBuffer =
false;
2331 depthTextureAllocCommand = depthAttachCmd->m_textureCmd;
2334 case CommandType::AddShaderDefine:
2336 const auto *defineCmd =
static_cast<
const QSSGAddShaderDefine *>(theCommand);
2337 const auto &defineName = defineCmd->m_name;
2338 if (defineName.size() > 0) {
2339 QByteArray value = QByteArray::number(defineCmd->m_value);
2340 currentPassData.shaderDefines.push_back({ defineName, value });
2344 case CommandType::RenderablesFilter:
2346 auto filterCommand =
static_cast<
const QSSGRenderablesFilterCommand *>(theCommand);
2350 enum RenderableType : quint8 {
2356 if (filterCommand->renderableTypes & RenderableType::Opaque)
2357 renderables = data.getSortedOpaqueRenderableObjects(*camera, 0, filterCommand->layerMask);
2358 if (filterCommand->renderableTypes & RenderableType::Transparent)
2359 renderables += data.getSortedTransparentRenderableObjects(*camera, 0, filterCommand->layerMask);
2363 renderablesFiltered =
true;
2367 case CommandType::PipelineStateOverride:
2369 auto pipelineCommand =
static_cast<
const QSSGPipelineStateOverrideCommand *>(theCommand);
2370 if (pipelineCommand->m_depthTestEnabled)
2371 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, *pipelineCommand->m_depthTestEnabled);
2372 if (pipelineCommand->m_depthWriteEnabled)
2373 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, *pipelineCommand->m_depthWriteEnabled);
2374 if (pipelineCommand->m_blendEnabled)
2375 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, *pipelineCommand->m_blendEnabled);
2376 if (pipelineCommand->m_usesStencilReference)
2377 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef, *pipelineCommand->m_usesStencilReference);
2378 if (pipelineCommand->m_usesScissor)
2379 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor, *pipelineCommand->m_usesScissor);
2380 if (pipelineCommand->m_depthFunction)
2381 ps.depthFunc = *pipelineCommand->m_depthFunction;
2382 if (pipelineCommand->m_cullMode) {
2383 ps.cullMode = *pipelineCommand->m_cullMode;
2384 ps.userSetCullMode =
true;
2386 if (pipelineCommand->m_polygonMode)
2387 ps.polygonMode = *pipelineCommand->m_polygonMode;
2388 if (pipelineCommand->m_stencilOpFrontState)
2389 ps.stencilOpFrontState = *pipelineCommand->m_stencilOpFrontState;
2390 if (pipelineCommand->m_stencilWriteMask)
2391 ps.stencilWriteMask = *pipelineCommand->m_stencilWriteMask;
2392 if (pipelineCommand->m_stencilReference)
2393 ps.stencilRef = *pipelineCommand->m_stencilReference;
2394 if (pipelineCommand->m_viewport)
2395 ps.viewport = *pipelineCommand->m_viewport;
2396 if (pipelineCommand->m_scissor)
2397 ps.scissor = *pipelineCommand->m_scissor;
2398 if (pipelineCommand->m_targetBlend0)
2399 ps.targetBlend[0] = *pipelineCommand->m_targetBlend0;
2400 if (pipelineCommand->m_targetBlend1)
2401 ps.targetBlend[1] = *pipelineCommand->m_targetBlend1;
2402 if (pipelineCommand->m_targetBlend2)
2403 ps.targetBlend[2] = *pipelineCommand->m_targetBlend2;
2404 if (pipelineCommand->m_targetBlend3)
2405 ps.targetBlend[3] = *pipelineCommand->m_targetBlend3;
2406 if (pipelineCommand->m_targetBlend4)
2407 ps.targetBlend[4] = *pipelineCommand->m_targetBlend4;
2408 if (pipelineCommand->m_targetBlend5)
2409 ps.targetBlend[5] = *pipelineCommand->m_targetBlend5;
2410 if (pipelineCommand->m_targetBlend6)
2411 ps.targetBlend[6] = *pipelineCommand->m_targetBlend6;
2412 if (pipelineCommand->m_targetBlend7)
2413 ps.targetBlend[7] = *pipelineCommand->m_targetBlend7;
2416 case CommandType::DepthStencilAttachment:
2418 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2419 needsDepthStencilRenderBuffer =
true;
2421 case CommandType::SubRenderPass:
2423 auto subPassCommand =
static_cast<
const QSSGSubRenderPass *>(theCommand);
2424 if (subPassCommand && subPassCommand->m_userPassId != QSSGResourceId::Invalid)
2425 subPassIds.append(subPassCommand->m_userPassId);
2429 qWarning() <<
"Effect command" << theCommand->typeAsString() <<
"not implemented";
2434 if (colorAttachments.size() > 4) {
2435 colorAttachments.resize(4);
2436 qWarning() <<
"UserRenderPass supports up to 4 color attachments only.";
2441 if (isTopLevelPass) {
2443 bool needsBuild = !renderTarget->isValid();
2445 const qsizetype oldAttachmentCount = renderTarget->colorAttachmentCount();
2448 const qsizetype wantedAttachmentCount = qMax<qsizetype>(colorAttachments.size(), 1);
2450 if (oldAttachmentCount != wantedAttachmentCount)
2457 if (renderTarget->getRenderTarget() && renderTarget->getRenderTarget()->flags() != passNode->renderTargetFlags)
2464 for (
int i = 0; i != oldAttachmentCount; ++i) {
2465 QRhiTexture::Format expectedFormat = QRhiTexture::RGBA8;
2466 if (i < colorAttachments.size()) {
2467 const auto &colorAttachment = colorAttachments.at(i);
2468 QSSG_ASSERT(colorAttachment !=
nullptr,
continue);
2469 expectedFormat = QSSGBufferManager::toRhiFormat(colorAttachment->format());
2471 const auto &texture = renderTarget->getColorTexture(i);
2472 needsBuild = needsBuild || needsRebuild(&(*texture->texture()), targetSize, expectedFormat);
2476 if (needsDepthStencilRenderBuffer != (renderTarget->getDepthStencil() !=
nullptr))
2480 if (depthTextureAllocCommand) {
2481 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2482 const auto &depthTextureWrapper = renderTarget->getDepthTexture();
2483 needsBuild = depthTextureWrapper ==
nullptr;
2484 needsBuild = needsBuild || needsRebuild(&(*depthTextureWrapper->texture()), targetSize, format);
2486 if (renderTarget->getDepthTexture() !=
nullptr)
2492 const auto &rt = renderTarget->getRenderTarget();
2493 if (rt && rt->flags() != passNode->renderTargetFlags)
2499 renderTarget->reset();
2501 QRhiTextureRenderTargetDescription rtDesc;
2504 const qsizetype colorAttachmentCount = wantedAttachmentCount;
2506 bool createSucceeded =
true;
2507 bool colorAllocatorsNeedsUpdate =
false;
2511 QVarLengthArray<QRhiTexture *, 4> textures;
2512 for (qsizetype i = 0; i < colorAttachmentCount && createSucceeded ; ++i) {
2513 if (i >= colorAttachments.size()) {
2515 auto *tex = rhiCtx->rhi()->newTexture(QRhiTexture::RGBA8, targetSize, ps.samples, QRhiTexture::RenderTarget);
2516 tex->setName(QByteArrayLiteral(
"Default color attachment"));
2517 createSucceeded = createSucceeded && tex->create();
2518 textures.push_back(tex);
2521 const auto &colorAttCmd = colorAttachments.at(i);
2522 const auto &name = colorAttCmd->m_name;
2523 const auto format = QSSGBufferManager::toRhiFormat(colorAttCmd->format());
2524 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2525 if (allocateTexCmd->texture() && !needsRebuild(&(*allocateTexCmd->texture()->texture()), targetSize, format)) {
2528 textures.push_back(allocateTexCmd->texture()->texture().get());
2530 auto *tex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2532 createSucceeded = createSucceeded && tex->create();
2533 textures.push_back(tex);
2537 colorAllocatorsNeedsUpdate =
true;
2541 rtDesc.setColorAttachments(textures.cbegin(), textures.cend());
2544 if (needsDepthStencilRenderBuffer) {
2545 auto renderBuffer = rhiCtx->rhi()->newRenderBuffer(QRhiRenderBuffer::DepthStencil, targetSize, ps.samples);
2546 if (renderBuffer->create())
2547 rtDesc.setDepthStencilBuffer(renderBuffer);
2548 }
else if (depthTextureAllocCommand) {
2549 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2550 if (depthTextureAllocCommand->texture() && !needsRebuild(&(*depthTextureAllocCommand->texture()->texture()), targetSize, format)) {
2551 rtDesc.setDepthTexture(depthTextureAllocCommand->texture()->texture().get());
2554 QRhiTexture *depthTex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2555 if (depthTex->create())
2556 rtDesc.setDepthTexture(depthTex);
2560 if (createSucceeded) {
2562 renderTarget->setDescription(rhiCtx->rhi(),
std::move(rtDesc), passNode->renderTargetFlags);
2567 if (colorAllocatorsNeedsUpdate) {
2568 for (qsizetype i = 0; i < colorAttachments.size(); ++i) {
2569 const auto &colorAttCmd = colorAttachments.at(i);
2570 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2571 allocateTexCmd->setTexture(renderTarget->getColorTexture(i));
2575 if (depthTextureAllocCommand)
2576 depthTextureAllocCommand->setTexture(renderTarget->getDepthTexture());
2579 renderTarget->resetRenderTarget();
2580 qWarning() <<
"Failed to create textures for UserRenderPass";
2586 Q_ASSERT(renderTarget->isValid());
2588 ps.colorAttachmentCount =
int(renderTarget->colorAttachmentCount());
2591 for (
const auto &subPassId : std::as_const(subPassIds)) {
2592 QSSGRenderUserPass *userPassNode = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subPassId);
2593 QSSG_ASSERT(userPassNode && userPassNode->type == QSSGRenderGraphObject::Type::RenderPass,
continue);
2594 prepareSubPass(renderer, data, userPassNode, currentPassData.subPassData, currentPassData.renderableTexture);
2597 if (passNode->passMode == QSSGRenderUserPass::PassModes::UserPass) {
2599 if (!renderablesFiltered && renderables.isEmpty())
2600 renderables = data.getSortedOpaqueRenderableObjects(*camera);
2602 if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::AugmentMaterial) {
2606 QSSG_ASSERT(shaderAugmentation.outputs.size() == 0, shaderAugmentation.outputs.clear());
2607 shaderAugmentation.defines =
std::move(currentPassData.shaderDefines);
2609 for (
int i = 0, end = colorAttachments.size(); i < end; ++i) {
2610 const auto &colorAttCmd = colorAttachments.at(i);
2611 const auto &name = colorAttCmd->m_name;
2612 if (name.size() > 0)
2613 shaderAugmentation.outputs.push_back(name);
2615 shaderAugmentation.outputs.push_back(getDefaultOutputName(size_t(i)));
2618 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2619 shaderFeatures.disableTonemapping();
2621 currentPassData.index = RenderHelpers::rhiPrepareAugmentedUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), shaderAugmentation, data, renderables, shaderFeatures);
2622 }
else if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::OverrideMaterial) {
2624 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2625 shaderFeatures.disableTonemapping();
2627 currentPassData.index = RenderHelpers::rhiPrepareOverrideMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), passNode->overrideMaterial, data, renderables, shaderFeatures);
2631 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2632 shaderFeatures.disableTonemapping();
2633 currentPassData.index = RenderHelpers::rhiPrepareOriginalMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), data, renderables, shaderFeatures);
2635 outData.push_back(currentPassData);
2638 if (passNode->passMode == QSSGRenderUserPass::PassModes::SkyboxPass) {
2639 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2640 if (data.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && data.layer.skyBoxCubeMap) {
2641 if (!currentPassData.skyboxCubeMapPass)
2644 currentPassData.skyboxCubeMapPass->skipTonemapping =
true;
2645 currentPassData.skyboxCubeMapPass->renderPrep(renderer, data);
2646 currentPassData.skyboxCubeMapPass->ps.samples = ps.samples;
2647 currentPassData.skyboxCubeMapPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2649 currentPassData.skyboxPass =
std::nullopt;
2650 }
else if ((data.layer.background == QSSGRenderLayer::Background::SkyBox && data.layer.lightProbe)
2651 || (data.layer.background == QSSGRenderLayer::Background::SkyMaterial && data.layer.skyMaterial)) {
2652 if (!currentPassData.skyboxPass)
2655 currentPassData.skyboxPass->skipTonemapping =
true;
2656 currentPassData.skyboxPass->renderPrep(renderer, data);
2657 currentPassData.skyboxPass->ps.samples = ps.samples;
2658 currentPassData.skyboxPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2660 currentPassData.skyboxCubeMapPass =
std::nullopt;
2662 outData.push_back(currentPassData);
2664 }
else if (passNode->passMode == QSSGRenderUserPass::PassModes::Item2DPass) {
2665 if (!currentPassData.item2DPass)
2667 const bool hasItem2Ds = (data.item2DsView.size() > 0);
2670 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(renderer.contextInterface()->rhiContext().get());
2671 QRhiRenderTarget *prevRenderTarget = rhiCtx->renderTarget();
2672 rhiCtxD->setRenderTarget(renderTarget->getRenderTarget().get());
2673 currentPassData.item2DPass->renderPrep(renderer, data);
2675 rhiCtxD->setRenderTarget(prevRenderTarget);
2676 outData.push_back(currentPassData);