1188 const auto &ctx = *renderer.contextInterface();
1189 const auto &rhiCtx = ctx.rhiContext();
1190 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1191 QSSG_ASSERT(!data.renderedCameras.isEmpty(),
return);
1192 QSSG_ASSERT(data.renderedCameras.count() == data.layer.viewCount,
return);
1193 layer = &data.layer;
1198 rpDesc = rhiCtx->mainRenderPassDescriptor();
1199 ps = data.getPipelineState();
1200 ps.samples = rhiCtx->mainPassSampleCount();
1201 ps.viewCount = data.layer.viewCount;
1202 ps.polygonMode = QRhiGraphicsPipeline::Fill;
1205 skipTonemapping = layer->firstEffect !=
nullptr;
1207 QRhi *rhi = rhiCtx->rhi();
1208 QSSGRenderSkyMaterial &skyMaterial = *layer->skyMaterial;
1209 const int viewCount = data.layer.viewCount;
1211 const QSSGRenderLayer::TonemapMode tonemapMode =
1212 skipTonemapping && (layer->tonemapMode != QSSGRenderLayer::TonemapMode::Custom)
1213 ? QSSGRenderLayer::TonemapMode::None
1214 : layer->tonemapMode;
1215 QSSGShaderFeatures tonemapFeatures;
1216 quint32 tonemapKey = 0;
1217 skyMaterialTonemapFeatures(tonemapMode, tonemapFeatures, tonemapKey);
1219 pipeline = skyMaterial.ensureBackgroundPipeline(ctx, tonemapFeatures, tonemapKey, viewCount);
1227 const QMatrix3x3 o = layer->lightProbeSettings.probeOrientation;
1228 const QMatrix4x4 orientation(o(0, 0), o(0, 1), o(0, 2), 0.0f,
1229 o(1, 0), o(1, 1), o(1, 2), 0.0f,
1230 o(2, 0), o(2, 1), o(2, 2), 0.0f,
1231 0.0f, 0.0f, 0.0f, 1.0f);
1232 QVarLengthArray<QMatrix4x4, 2> inverseProjections;
1233 QVarLengthArray<QMatrix4x4, 2> viewRotations;
1234 for (
int v = 0; v < viewCount; ++v) {
1235 const QSSGRenderCamera &camera = *data.renderedCameras[v];
1236 inverseProjections.append(camera.projection.inverted());
1237 QMatrix4x4 cameraRotation = data.getGlobalTransform(camera);
1238 cameraRotation.setColumn(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
1239 viewRotations.append(orientation * cameraRotation);
1241 const float adjustY = rhi->isYUpInNDC() ? 1.0f : -1.0f;
1242 const float exposure = layer->lightProbeSettings.probeExposure;
1244 skyMaterial.updateBackgroundUniforms(ctx, inverseProjections, viewRotations, adjustY, exposure);
1246 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1247 backgroundSrb = rhiCtxD->srb(skyMaterial.backgroundBindings);
1249 switch (skyMaterial.skyboxMode) {
1250 case QSSGRenderSkyMaterial::SkyboxMode::ScreenSpaceHalf:
1253 case QSSGRenderSkyMaterial::SkyboxMode::ScreenSpaceQuarter:
1256 case QSSGRenderSkyMaterial::SkyboxMode::ScreenSpaceFull:
1257 case QSSGRenderSkyMaterial::SkyboxMode::Cubemap:
1262 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(),
nullptr);
1267 const std::array<
float, 4> vp = ps.viewport.viewport();
1268 const QSize fullSize(
int(vp.at(2)),
int(vp.at(3)));
1269 const QSize targetSize = (fullSize / qreal(
scaleDivisor)).expandedTo(QSize(1, 1));
1270 const bool multiView = viewCount >= 2;
1271 const int wantArraySize = multiView ? viewCount : 0;
1273 offscreenTexture = data.getRenderResult(QSSGRenderResult::Key::SkyMaterialBackgroundTexture);
1274 QSSGRhiRenderableTexture *tex = offscreenTexture;
1275 if (!tex->texture || tex->texture->pixelSize() != targetSize || tex->texture->arraySize() != wantArraySize) {
1277 tex->texture = multiView ? rhi->newTextureArray(QRhiTexture::RGBA16F, viewCount, targetSize, 1, QRhiTexture::RenderTarget)
1278 : rhi->newTexture(QRhiTexture::RGBA16F, targetSize, 1, QRhiTexture::RenderTarget);
1279 if (!tex->texture->create()) {
1280 qWarning(
"Failed to build SkyMaterial screen-space background texture");
1282 offscreenTexture =
nullptr;
1285 QRhiColorAttachment att(tex->texture);
1286 att.setMultiViewCount(viewCount);
1287 QRhiTextureRenderTargetDescription desc;
1288 desc.setColorAttachments({ att });
1289 tex->rt = rhi->newTextureRenderTarget(desc);
1290 tex->rt->setName(QByteArrayLiteral(
"SkyMaterial screen-space background"));
1291 tex->rpDesc = tex->rt->newCompatibleRenderPassDescriptor();
1292 tex->rt->setRenderPassDescriptor(tex->rpDesc);
1293 if (!tex->rt->create()) {
1294 qWarning(
"Failed to build SkyMaterial screen-space background render target");
1296 offscreenTexture =
nullptr;
1301 QSSGRhiGraphicsPipelineState offscreenPs;
1302 offscreenPs.viewport = QRhiViewport(0, 0,
float(targetSize.width()),
float(targetSize.height()));
1303 offscreenPs.samples = 1;
1304 offscreenPs.viewCount = viewCount;
1305 offscreenPs.polygonMode = QRhiGraphicsPipeline::Fill;
1306 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(offscreenPs, pipeline.get());
1307 renderer.rhiQuadRenderer()->recordRenderQuadPass(rhiCtx.get(), &offscreenPs, backgroundSrb,
1308 offscreenTexture->rt, QSSGRhiQuadRenderer::RenderBehind);
1677 auto *ctx = renderer.contextInterface();
1678 const auto &rhiCtx = ctx->rhiContext();
1679 auto *rhi = rhiCtx->rhi();
1681 QSSG_ASSERT(!data.renderedCameras.isEmpty() && data.renderedCameraData.has_value() ,
return);
1682 QSSGRenderCamera *camera = data.renderedCameras[0];
1684 ps = data.getPipelineState();
1685 ps.samples = rhiCtx->mainPassSampleCount();
1686 ps.viewCount = rhiCtx->mainPassViewCount();
1688 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1689 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1691 shaderFeatures = data.getShaderFeatures();
1692 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1694 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1695 ps.colorAttachmentCount = 2;
1697 rhiAccumTexture = data.getRenderResult(QSSGRenderResult::Key::AccumTexture);
1698 rhiRevealageTexture = data.getRenderResult(QSSGRenderResult::Key::RevealageTexture);
1700 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTextureMS);
1702 rhiDepthTexture = data.getRenderResult(QSSGRenderResult::Key::DepthTexture);
1703 if (!rhiDepthTexture->isValid())
1705 auto &oitrt = data.getOitRenderContext();
1706 if (!oitrt.oitRenderTarget || oitrt.oitRenderTarget->pixelSize() != data.layerPrepResult.textureDimensions()
1707 || rhiDepthTexture->texture != oitrt.oitRenderTarget->description().depthTexture()
1708 || ps.samples != oitrt.oitRenderTarget->sampleCount()) {
1709 if (oitrt.oitRenderTarget) {
1710 rhiAccumTexture->texture->destroy();
1711 rhiRevealageTexture->texture->destroy();
1712 oitrt.oitRenderTarget->destroy();
1713 oitrt.renderPassDescriptor->destroy();
1714 oitrt.oitRenderTarget =
nullptr;
1716 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget;
1717 if (ps.viewCount >= 2) {
1718 rhiAccumTexture->texture = rhi->newTextureArray(QRhiTexture::RGBA16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1719 rhiRevealageTexture->texture = rhi->newTextureArray(QRhiTexture::R16F, ps.viewCount, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1721 rhiAccumTexture->texture = rhi->newTexture(QRhiTexture::RGBA16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1722 rhiRevealageTexture->texture = rhi->newTexture(QRhiTexture::R16F, data.layerPrepResult.textureDimensions(), ps.samples, textureFlags);
1724 rhiAccumTexture->texture->create();
1725 rhiRevealageTexture->texture->create();
1727 QRhiTextureRenderTargetDescription desc;
1728 desc.setColorAttachments({{rhiAccumTexture->texture}, {rhiRevealageTexture->texture}});
1729 desc.setDepthTexture(rhiDepthTexture->texture);
1731 if (oitrt.oitRenderTarget ==
nullptr) {
1732 oitrt.oitRenderTarget = rhi->newTextureRenderTarget(desc, QRhiTextureRenderTarget::PreserveDepthStencilContents);
1733 oitrt.renderPassDescriptor = oitrt.oitRenderTarget->newCompatibleRenderPassDescriptor();
1734 oitrt.oitRenderTarget->setRenderPassDescriptor(oitrt.renderPassDescriptor);
1735 oitrt.oitRenderTarget->create();
1737 renderTarget = oitrt.oitRenderTarget;
1740 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1741 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1742 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearMRTShader();
1744 QSSGRhiShaderResourceBindingList bindings;
1745 QVector4D clearData[2];
1746 clearData[0] = QVector4D(0.0, 0.0, 0.0, 0.0);
1747 clearData[1] = QVector4D(1.0, 1.0, 1.0, 1.0);
1749 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1750 QRhiBuffer *&ubuf = dcd.ubuf;
1751 const int ubufSize =
sizeof(clearData);
1753 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1757 QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
1758 rub->updateDynamicBuffer(ubuf, 0, ubufSize, &clearData);
1759 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1761 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1763 clearSrb = rhiCtxD->srb(bindings);
1765 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1766 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::One;
1767 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::One;
1768 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::One;
1769 ps.targetBlend[1].srcAlpha = QRhiGraphicsPipeline::Zero;
1770 ps.targetBlend[1].srcColor = QRhiGraphicsPipeline::Zero;
1771 ps.targetBlend[1].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1772 ps.targetBlend[1].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1774 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, oitrt.renderPassDescriptor, sortedTransparentObjects,
true);
1775 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1777 rhiCtx->commandBuffer()->resourceUpdate(
this->rub);
1778 this->rub =
nullptr;
1782 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1783 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1784 ps.targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One;
1785 ps.targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha;
1786 ps.targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1787 ps.targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
1789 shaderFeatures = data.getShaderFeatures();
1790 sortedTransparentObjects = data.getSortedTransparentRenderableObjects(*camera);
1792#ifdef QSSG_OIT_USE_BUFFERS
1793 auto &oitCtx = data.getOitRenderContext();
1794 rhiABuffer = oitCtx.aBuffer;
1795 rhiAuxBuffer = oitCtx.auxBuffer;
1796 rhiCounterBuffer = oitCtx.counterBuffer;
1798 rhiABufferImage = data.getRenderResult(QSSGRenderResult::Key::ABufferImage);
1799 rhiAuxiliaryImage = data.getRenderResult(QSSGRenderResult::Key::AuxiliaryImage);
1800 rhiCounterImage = data.getRenderResult(QSSGRenderResult::Key::CounterImage);
1802 QSize dim = data.layerPrepResult.textureDimensions();
1803 dim.setWidth(dim.width() * ps.samples);
1804 dim.setHeight(dim.height() * ps.viewCount);
1805#ifdef QSSG_OIT_USE_BUFFERS
1806 if (!rhiAuxBuffer || rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u) || currentNodeCount == 0 || linkedListRequiresResize(dim))
1808 if (!rhiAuxiliaryImage->texture || rhiAuxiliaryImage->texture->pixelSize() != dim || currentNodeCount == 0 || linkedListRequiresResize(dim))
1811 quint32 extraNodeCount = 0;
1812#ifdef QSSG_OIT_USE_BUFFERS
1813 if (rhiAuxBuffer && rhiAuxBuffer->size() != (dim.width() * dim.height() * 4u)) {
1814 if (rhiAuxBuffer->size() < (dim.width() * dim.height() * 4u))
1815 extraNodeCount = ensureFreeNodes((dim.width() * dim.height() * 4u) - rhiAuxBuffer->size(), 32u * 1024u);
1816 rhiAuxBuffer->destroy();
1817 rhiAuxBuffer =
nullptr;
1820 if (rhiABufferImage->texture) {
1821 const auto s = rhiAuxiliaryImage->texture->pixelSize();
1822 if (s.width() * s.height() < dim.width() * dim.height())
1823 extraNodeCount = ensureFreeNodes(dim.width() * dim.height() - s.width() * s.height(), 32u * 1024u);
1824 rhiABufferImage->texture->destroy();
1825 rhiAuxiliaryImage->texture->destroy();
1829 if (reportedNodeCount) {
1831 currentNodeCount = ensureFreeNodes(reportedNodeCount + extraNodeCount, dim.width() * dim.height() / 2);
1833 quint32 size = RenderHelpers::rhiCalculateABufferSize(data.layerPrepResult.textureDimensions(), 4 * ps.samples * ps.viewCount);
1834 currentNodeCount = ensureFreeNodes(size * size, 32u * 1024u);
1836 data.layer.oitNodeCount = currentNodeCount;
1838#ifdef QSSG_OIT_USE_BUFFERS
1839 if (rhiABuffer && currentNodeCount * 16 != rhiABuffer->size()) {
1840 rhiABuffer->destroy();
1841 rhiABuffer =
nullptr;
1844 rhiABuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, currentNodeCount * 16);
1845 rhiABuffer->create();
1847 if (!rhiAuxBuffer) {
1848 rhiAuxBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, dim.width() * dim.height() * 4);
1849 rhiAuxBuffer->create();
1851 if (!rhiCounterBuffer) {
1852 rhiCounterBuffer = rhi->newBuffer(QRhiBuffer::Static, QRhiBuffer::StorageBuffer, 4);
1853 rhiCounterBuffer->create();
1854 oitCtx.counterBuffer = rhiCounterBuffer;
1856 oitCtx.aBuffer = rhiABuffer;
1857 oitCtx.auxBuffer = rhiAuxBuffer;
1859 quint32 sizeWithLayers = RenderHelpers::rhiCalculateABufferSize(currentNodeCount);
1860 const QRhiTexture::Flags textureFlags = QRhiTexture::UsedWithLoadStore;
1861 rhiABufferImage->texture = rhi->newTexture(QRhiTexture::RGBA32UI, QSize(sizeWithLayers, sizeWithLayers), 1, textureFlags);
1862 rhiABufferImage->texture->create();
1863 rhiAuxiliaryImage->texture = rhi->newTexture(QRhiTexture::R32UI, dim, 1, textureFlags);
1864 rhiAuxiliaryImage->texture->create();
1865 if (!rhiCounterImage->texture) {
1866 rhiCounterImage->texture = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, textureFlags | QRhiTexture::UsedAsTransferSource);
1867 rhiCounterImage->texture->create();
1869 auto &oitrt = data.getOitRenderContext();
1870 readbackImage = rhi->newTexture(QRhiTexture::R32UI, QSize(1, 1), 1, QRhiTexture::UsedAsTransferSource);
1876 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1878 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
1879 const auto &shaderCache = renderer.contextInterface()->shaderCache();
1880#ifdef QSSG_OIT_USE_BUFFERS
1881 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearBufferShader();
1883 clearPipeline = shaderCache->getBuiltInRhiShaders().getRhiClearImageShader();
1885 QSSGRhiShaderResourceBindingList bindings;
1886 quint32 clearImageData[8] = {0};
1888 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this, clearPipeline.get(),
nullptr, 0 }));
1889 QRhiBuffer *&ubuf = dcd.ubuf;
1890 const int ubufSize =
sizeof(clearImageData);
1892 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, ubufSize);
1896 clearImageData[4] = data.layerPrepResult.textureDimensions().width();
1897 clearImageData[5] = data.layerPrepResult.textureDimensions().height();
1898 clearImageData[6] = ps.samples;
1899 clearImageData[7] = ps.viewCount;
1901 rub->updateDynamicBuffer(ubuf, 0, ubufSize, clearImageData);
1903#ifdef QSSG_OIT_USE_BUFFERS
1904 rub->uploadStaticBuffer(rhiCounterBuffer, 0, 4, &zero);
1906 rub->uploadTexture(rhiCounterImage->texture, {{0, 0, {&zero, 4}}});
1909 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
1910#ifdef QSSG_OIT_USE_BUFFERS
1911 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
1913 bindings.addImageStore(1, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
1916 clearSrb = rhiCtxD->srb(bindings);
1918 renderer.rhiQuadRenderer()->prepareQuad(rhiCtx.get(), rub);
1920 TransparentPass::prep(*ctx, data,
this, ps, shaderFeatures, rhiCtx->mainRenderPassDescriptor(), sortedTransparentObjects,
true);
1926 auto *ctx = renderer.contextInterface();
1927 const auto &rhiCtx = ctx->rhiContext();
1928 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
1929 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
1931 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
1932 if (Q_LIKELY(renderTarget)) {
1933 cb->beginPass(renderTarget, Qt::black, {});
1935 QRhiShaderResourceBindings *srb = clearSrb;
1937 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
false);
1938 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1939 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, renderTarget->renderPassDescriptor(), {});
1940 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1942 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render order-independent alpha"));
1943 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1944 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render order-independent alpha"));
1945 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled,
true);
1946 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled,
false);
1947 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1949 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
1950 Q_TRACE(QSSG_renderPass_exit);
1954 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
1955 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D render alpha"));
1956 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
1957 Q_TRACE(QSSG_renderPass_entry, QStringLiteral(
"Quick3D render alpha"));
1959 QRhiShaderResourceBindings *srb = clearSrb;
1961 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
1962 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, clearPipeline.get());
1963 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(), {});
1965 TransparentPass::render(*ctx, ps, sortedTransparentObjects);
1966#ifdef QSSG_OIT_USE_BUFFERS
1967 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1968 QRhiReadbackResult *result =
nullptr;
1969 if (results.size() > 1) {
1970 result = results.takeLast();
1971 result->pixelSize = {};
1973 result->format = QRhiTexture::UnknownFormat;
1975 result =
new QRhiReadbackResult();
1977 const auto completedFunc = [
this, result](){
1979 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
1980 quint32 nodeCount = *d;
1982 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
1983 this->results.append(result);
1986 result->completed = completedFunc;
1987 rub->readBackBuffer(rhiCounterBuffer, 0, 4, result);
1990 QRhiResourceUpdateBatch *rub = rhiCtx->rhi()->nextResourceUpdateBatch();
1992 QRhiReadbackDescription rbdesc;
1994 QRhiReadbackResult *result =
nullptr;
1995 if (results.size() > 1) {
1996 result = results.takeLast();
1997 result->pixelSize = {};
1999 result->format = QRhiTexture::UnknownFormat;
2001 result =
new QRhiReadbackResult();
2003 const auto completedFunc = [
this, result](){
2005 const quint32 *d =
reinterpret_cast<
const quint32 *>(result->data.constData());
2006 quint32 nodeCount = *d;
2008 this->reportedNodeCount = ensureFreeNodes(nodeCount, 32u * 1024u);
2009 this->results.append(result);
2012 result->completed = completedFunc;
2013 rub->readBackTexture(rbdesc, result);
2017 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"transparent_order_independent_pass"));
2018 Q_TRACE(QSSG_renderPass_exit);
2106 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2107 QSSG_ASSERT(rhiCtx->rhi()->isRecordingFrame(),
return);
2108 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
2110 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
2112 if (!rhiAccumTexture->texture || !rhiRevealageTexture->texture)
2115 if (method == QSSGRenderLayer::OITMethod::WeightedBlended) {
2116 QSSGRhiShaderResourceBindingList bindings;
2118 QRhiSampler *sampler = rhiCtx->sampler({ QRhiSampler::Nearest,
2119 QRhiSampler::Nearest,
2121 QRhiSampler::ClampToEdge,
2122 QRhiSampler::ClampToEdge,
2123 QRhiSampler::ClampToEdge });
2124 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, rhiAccumTexture->texture, sampler);
2125 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, rhiRevealageTexture->texture, sampler);
2127 compositeSrb = rhiCtxD->srb(bindings);
2129 QRhiShaderResourceBindings *srb = compositeSrb;
2132 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D revealage"));
2133 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
2134 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
2135 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
2136 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
2137 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"revealage"));
2139 }
else if (method == QSSGRenderLayer::OITMethod::LinkedList) {
2140 QSSGRhiShaderResourceBindingList bindings;
2142 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
2143 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({
this,
nullptr,
nullptr, 0 }));
2144 QRhiBuffer *&ubuf = dcd.ubuf;
2146 bindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf);
2147#ifdef QSSG_OIT_USE_BUFFERS
2148 bindings.addStorageBuffer(1, QRhiShaderResourceBinding::FragmentStage, rhiABuffer);
2149 bindings.addStorageBuffer(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxBuffer);
2151 bindings.addImageLoad(1, QRhiShaderResourceBinding::FragmentStage, rhiABufferImage->texture, 0);
2152 bindings.addImageLoad(2, QRhiShaderResourceBinding::FragmentStage, rhiAuxiliaryImage->texture, 0);
2155 compositeSrb = rhiCtxD->srb(bindings);
2157 QRhiShaderResourceBindings *srb = compositeSrb;
2160 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D oit-composite"));
2161 QSSGRhiGraphicsPipelineStatePrivate::setShaderPipeline(ps, compositeShaderPipeline.get());
2162 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled,
true);
2163 renderer.rhiQuadRenderer()->recordRenderQuad(rhiCtx.get(), &ps, srb, rhiCtx->mainRenderPassDescriptor(),
2164 { QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::DepthTest | QSSGRhiQuadRenderer::PremulBlend});
2165 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral(
"oit-composite"));
2263 QSSGRenderUserPass *passNode,
2264 std::vector<UserPassData> &outData,
2265 QSSGRhiRenderableTextureV2Ptr renderableTexture)
2269 const bool isTopLevelPass = (renderableTexture ==
nullptr);
2271 QSSGRenderCamera *camera = data.renderedCameras[0];
2272 const auto &rhiCtx = renderer.contextInterface()->rhiContext();
2274 const QSize targetSize = data.layerPrepResult.textureDimensions();
2276 static const auto needsRebuild = [](QRhiTexture *texture,
const QSize &size, QRhiTexture::Format format) {
2277 return !texture || texture->pixelSize() != size || texture->format() != format;
2280 qCDebug(lcUserRenderPass,
"renderPrep in UserRenderPass");
2282 const QSSGResourceId currentPassId = QSSGRenderGraphObjectUtils::getResourceId(*passNode);
2283 if (visitedPasses.find(currentPassId) != visitedPasses.end()) {
2284 qWarning(
"UserRenderPass: Circular dependency detected in SubRenderPass chain. Ignoring pass.");
2289 if (visitedPasses.size() >= MAX_SUBPASS_DEPTH) {
2290 qWarning(
"UserRenderPass: Maximum SubRenderPass nesting depth (%zu) exceeded. Ignoring pass.", MAX_SUBPASS_DEPTH);
2294 visitedPasses.insert(currentPassId);
2297 currentPassData.clearColor = passNode->clearColor;
2298 currentPassData.depthStencilClearValue = passNode->depthStencilClearValue;
2300 renderableTexture = currentPassData.renderableTexture = data.requestUserRenderPassManager()->getOrCreateRenderableTexture(*passNode);
2302 currentPassData.renderableTexture = renderableTexture;
2304 QSSGRenderableObjectList &renderables = currentPassData.renderables;
2305 QSSGRhiGraphicsPipelineState &ps = currentPassData.ps;
2306 const auto &renderTarget = currentPassData.renderableTexture;
2309 ps = data.getPipelineState();
2311 bool renderablesFiltered =
false;
2313 bool needsDepthStencilRenderBuffer =
false;
2314 QSSGAllocateTexturePtr depthTextureAllocCommand;
2316 QVarLengthArray<QSSGColorAttachment *, 16> colorAttachments;
2317 QVarLengthArray<QSSGResourceId, 4> subPassIds;
2320 for (
const QSSGCommand *theCommand : std::as_const(passNode->commands)) {
2323 qCDebug(lcUserRenderPass) <<
"Exec. command: >" << theCommand->typeAsString() <<
"--" << theCommand->debugString();
2325 switch (theCommand->m_type) {
2326 case CommandType::ColorAttachment:
2328 const QSSGColorAttachment *colorAttachCmd =
static_cast<
const QSSGColorAttachment *>(theCommand);
2329 colorAttachments.push_back(
const_cast<QSSGColorAttachment *>(colorAttachCmd));
2332 case CommandType::DepthTextureAttachment:
2334 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2335 const QSSGDepthTextureAttachment *depthAttachCmd =
static_cast<
const QSSGDepthTextureAttachment *>(theCommand);
2336 needsDepthStencilRenderBuffer =
false;
2337 depthTextureAllocCommand = depthAttachCmd->m_textureCmd;
2340 case CommandType::AddShaderDefine:
2342 const auto *defineCmd =
static_cast<
const QSSGAddShaderDefine *>(theCommand);
2343 const auto &defineName = defineCmd->m_name;
2344 if (defineName.size() > 0) {
2345 QByteArray value = QByteArray::number(defineCmd->m_value);
2346 currentPassData.shaderDefines.push_back({ defineName, value });
2350 case CommandType::RenderablesFilter:
2352 auto filterCommand =
static_cast<
const QSSGRenderablesFilterCommand *>(theCommand);
2356 enum RenderableType : quint8 {
2362 if (filterCommand->renderableTypes & RenderableType::Opaque)
2363 renderables = data.getSortedOpaqueRenderableObjects(*camera, 0, filterCommand->layerMask);
2364 if (filterCommand->renderableTypes & RenderableType::Transparent)
2365 renderables += data.getSortedTransparentRenderableObjects(*camera, 0, filterCommand->layerMask);
2369 renderablesFiltered =
true;
2373 case CommandType::PipelineStateOverride:
2375 auto pipelineCommand =
static_cast<
const QSSGPipelineStateOverrideCommand *>(theCommand);
2376 if (pipelineCommand->m_depthTestEnabled)
2377 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, *pipelineCommand->m_depthTestEnabled);
2378 if (pipelineCommand->m_depthWriteEnabled)
2379 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, *pipelineCommand->m_depthWriteEnabled);
2380 if (pipelineCommand->m_blendEnabled)
2381 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::BlendEnabled, *pipelineCommand->m_blendEnabled);
2382 if (pipelineCommand->m_usesStencilReference)
2383 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesStencilRef, *pipelineCommand->m_usesStencilReference);
2384 if (pipelineCommand->m_usesScissor)
2385 ps.flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::UsesScissor, *pipelineCommand->m_usesScissor);
2386 if (pipelineCommand->m_depthFunction)
2387 ps.depthFunc = *pipelineCommand->m_depthFunction;
2388 if (pipelineCommand->m_cullMode) {
2389 ps.cullMode = *pipelineCommand->m_cullMode;
2390 ps.userSetCullMode =
true;
2392 if (pipelineCommand->m_polygonMode)
2393 ps.polygonMode = *pipelineCommand->m_polygonMode;
2394 if (pipelineCommand->m_stencilOpFrontState)
2395 ps.stencilOpFrontState = *pipelineCommand->m_stencilOpFrontState;
2396 if (pipelineCommand->m_stencilWriteMask)
2397 ps.stencilWriteMask = *pipelineCommand->m_stencilWriteMask;
2398 if (pipelineCommand->m_stencilReference)
2399 ps.stencilRef = *pipelineCommand->m_stencilReference;
2400 if (pipelineCommand->m_viewport)
2401 ps.viewport = *pipelineCommand->m_viewport;
2402 if (pipelineCommand->m_scissor)
2403 ps.scissor = *pipelineCommand->m_scissor;
2404 if (pipelineCommand->m_targetBlend0)
2405 ps.targetBlend[0] = *pipelineCommand->m_targetBlend0;
2406 if (pipelineCommand->m_targetBlend1)
2407 ps.targetBlend[1] = *pipelineCommand->m_targetBlend1;
2408 if (pipelineCommand->m_targetBlend2)
2409 ps.targetBlend[2] = *pipelineCommand->m_targetBlend2;
2410 if (pipelineCommand->m_targetBlend3)
2411 ps.targetBlend[3] = *pipelineCommand->m_targetBlend3;
2412 if (pipelineCommand->m_targetBlend4)
2413 ps.targetBlend[4] = *pipelineCommand->m_targetBlend4;
2414 if (pipelineCommand->m_targetBlend5)
2415 ps.targetBlend[5] = *pipelineCommand->m_targetBlend5;
2416 if (pipelineCommand->m_targetBlend6)
2417 ps.targetBlend[6] = *pipelineCommand->m_targetBlend6;
2418 if (pipelineCommand->m_targetBlend7)
2419 ps.targetBlend[7] = *pipelineCommand->m_targetBlend7;
2422 case CommandType::DepthStencilAttachment:
2424 QSSG_ASSERT(depthTextureAllocCommand ==
nullptr,
break);
2425 needsDepthStencilRenderBuffer =
true;
2427 case CommandType::SubRenderPass:
2429 auto subPassCommand =
static_cast<
const QSSGSubRenderPass *>(theCommand);
2430 if (subPassCommand && subPassCommand->m_userPassId != QSSGResourceId::Invalid)
2431 subPassIds.append(subPassCommand->m_userPassId);
2435 qWarning() <<
"Effect command" << theCommand->typeAsString() <<
"not implemented";
2440 if (colorAttachments.size() > 4) {
2441 colorAttachments.resize(4);
2442 qWarning() <<
"UserRenderPass supports up to 4 color attachments only.";
2447 if (isTopLevelPass) {
2449 bool needsBuild = !renderTarget->isValid();
2451 const qsizetype oldAttachmentCount = renderTarget->colorAttachmentCount();
2454 const qsizetype wantedAttachmentCount = qMax<qsizetype>(colorAttachments.size(), 1);
2456 if (oldAttachmentCount != wantedAttachmentCount)
2463 if (renderTarget->getRenderTarget() && renderTarget->getRenderTarget()->flags() != passNode->renderTargetFlags)
2470 for (
int i = 0; i != oldAttachmentCount; ++i) {
2471 QRhiTexture::Format expectedFormat = QRhiTexture::RGBA8;
2472 if (i < colorAttachments.size()) {
2473 const auto &colorAttachment = colorAttachments.at(i);
2474 QSSG_ASSERT(colorAttachment !=
nullptr,
continue);
2475 expectedFormat = QSSGBufferManager::toRhiFormat(colorAttachment->format());
2477 const auto &texture = renderTarget->getColorTexture(i);
2478 needsBuild = needsBuild || needsRebuild(&(*texture->texture()), targetSize, expectedFormat);
2482 if (needsDepthStencilRenderBuffer != (renderTarget->getDepthStencil() !=
nullptr))
2486 if (depthTextureAllocCommand) {
2487 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2488 const auto &depthTextureWrapper = renderTarget->getDepthTexture();
2489 needsBuild = depthTextureWrapper ==
nullptr;
2490 needsBuild = needsBuild || needsRebuild(&(*depthTextureWrapper->texture()), targetSize, format);
2492 if (renderTarget->getDepthTexture() !=
nullptr)
2498 const auto &rt = renderTarget->getRenderTarget();
2499 if (rt && rt->flags() != passNode->renderTargetFlags)
2505 renderTarget->reset();
2507 QRhiTextureRenderTargetDescription rtDesc;
2510 const qsizetype colorAttachmentCount = wantedAttachmentCount;
2512 bool createSucceeded =
true;
2513 bool colorAllocatorsNeedsUpdate =
false;
2517 QVarLengthArray<QRhiTexture *, 4> textures;
2518 for (qsizetype i = 0; i < colorAttachmentCount && createSucceeded ; ++i) {
2519 if (i >= colorAttachments.size()) {
2521 auto *tex = rhiCtx->rhi()->newTexture(QRhiTexture::RGBA8, targetSize, ps.samples, QRhiTexture::RenderTarget);
2522 tex->setName(QByteArrayLiteral(
"Default color attachment"));
2523 createSucceeded = createSucceeded && tex->create();
2524 textures.push_back(tex);
2527 const auto &colorAttCmd = colorAttachments.at(i);
2528 const auto &name = colorAttCmd->m_name;
2529 const auto format = QSSGBufferManager::toRhiFormat(colorAttCmd->format());
2530 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2531 if (allocateTexCmd->texture() && !needsRebuild(&(*allocateTexCmd->texture()->texture()), targetSize, format)) {
2534 textures.push_back(allocateTexCmd->texture()->texture().get());
2536 auto *tex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2538 createSucceeded = createSucceeded && tex->create();
2539 textures.push_back(tex);
2543 colorAllocatorsNeedsUpdate =
true;
2547 rtDesc.setColorAttachments(textures.cbegin(), textures.cend());
2550 if (needsDepthStencilRenderBuffer) {
2551 auto renderBuffer = rhiCtx->rhi()->newRenderBuffer(QRhiRenderBuffer::DepthStencil, targetSize, ps.samples);
2552 if (renderBuffer->create())
2553 rtDesc.setDepthStencilBuffer(renderBuffer);
2554 }
else if (depthTextureAllocCommand) {
2555 const auto format = QSSGBufferManager::toRhiFormat(depthTextureAllocCommand->format());
2556 if (depthTextureAllocCommand->texture() && !needsRebuild(&(*depthTextureAllocCommand->texture()->texture()), targetSize, format)) {
2557 rtDesc.setDepthTexture(depthTextureAllocCommand->texture()->texture().get());
2560 QRhiTexture *depthTex = rhiCtx->rhi()->newTexture(format, targetSize, ps.samples, QRhiTexture::RenderTarget);
2561 if (depthTex->create())
2562 rtDesc.setDepthTexture(depthTex);
2566 if (createSucceeded) {
2568 renderTarget->setDescription(rhiCtx->rhi(),
std::move(rtDesc), passNode->renderTargetFlags);
2573 if (colorAllocatorsNeedsUpdate) {
2574 for (qsizetype i = 0; i < colorAttachments.size(); ++i) {
2575 const auto &colorAttCmd = colorAttachments.at(i);
2576 const auto &allocateTexCmd = colorAttCmd->m_textureCmd;
2577 allocateTexCmd->setTexture(renderTarget->getColorTexture(i));
2581 if (depthTextureAllocCommand)
2582 depthTextureAllocCommand->setTexture(renderTarget->getDepthTexture());
2585 renderTarget->resetRenderTarget();
2586 qWarning() <<
"Failed to create textures for UserRenderPass";
2592 Q_ASSERT(renderTarget->isValid());
2594 ps.colorAttachmentCount =
int(renderTarget->colorAttachmentCount());
2597 for (
const auto &subPassId : std::as_const(subPassIds)) {
2598 QSSGRenderUserPass *userPassNode = QSSGRenderGraphObjectUtils::getResource<QSSGRenderUserPass>(subPassId);
2599 QSSG_ASSERT(userPassNode && userPassNode->type == QSSGRenderGraphObject::Type::RenderPass,
continue);
2600 prepareSubPass(renderer, data, userPassNode, currentPassData.subPassData, currentPassData.renderableTexture);
2603 if (passNode->passMode == QSSGRenderUserPass::PassModes::UserPass) {
2605 if (!renderablesFiltered && renderables.isEmpty())
2606 renderables = data.getSortedOpaqueRenderableObjects(*camera);
2608 if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::AugmentMaterial) {
2612 QSSG_ASSERT(shaderAugmentation.outputs.size() == 0, shaderAugmentation.outputs.clear());
2613 shaderAugmentation.defines =
std::move(currentPassData.shaderDefines);
2615 for (
int i = 0, end = colorAttachments.size(); i < end; ++i) {
2616 const auto &colorAttCmd = colorAttachments.at(i);
2617 const auto &name = colorAttCmd->m_name;
2618 if (name.size() > 0)
2619 shaderAugmentation.outputs.push_back(name);
2621 shaderAugmentation.outputs.push_back(getDefaultOutputName(size_t(i)));
2624 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2625 shaderFeatures.disableTonemapping();
2627 currentPassData.index = RenderHelpers::rhiPrepareAugmentedUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), shaderAugmentation, data, renderables, shaderFeatures);
2628 }
else if (passNode->materialMode == QSSGRenderUserPass::MaterialModes::OverrideMaterial) {
2630 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2631 shaderFeatures.disableTonemapping();
2633 currentPassData.index = RenderHelpers::rhiPrepareOverrideMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), passNode->overrideMaterial, data, renderables, shaderFeatures);
2637 QSSGShaderFeatures shaderFeatures = data.getShaderFeatures();
2638 shaderFeatures.disableTonemapping();
2639 currentPassData.index = RenderHelpers::rhiPrepareOriginalMaterialUserPass(&(*rhiCtx),
this, ps, renderTarget->getRenderPassDescriptor().get(), data, renderables, shaderFeatures);
2641 outData.push_back(currentPassData);
2644 if (passNode->passMode == QSSGRenderUserPass::PassModes::SkyboxPass) {
2645 if (rhiCtx->rhi()->isFeatureSupported(QRhi::TexelFetch)) {
2646 if (data.layer.background == QSSGRenderLayer::Background::SkyBoxCubeMap && data.layer.skyBoxCubeMap) {
2647 if (!currentPassData.skyboxCubeMapPass)
2650 currentPassData.skyboxCubeMapPass->skipTonemapping =
true;
2651 currentPassData.skyboxCubeMapPass->renderPrep(renderer, data);
2652 currentPassData.skyboxCubeMapPass->ps.samples = ps.samples;
2653 currentPassData.skyboxCubeMapPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2655 currentPassData.skyboxPass =
std::nullopt;
2656 }
else if ((data.layer.background == QSSGRenderLayer::Background::SkyBox && data.layer.lightProbe)
2657 || (data.layer.background == QSSGRenderLayer::Background::SkyMaterial && data.layer.skyMaterial)) {
2658 if (!currentPassData.skyboxPass)
2661 currentPassData.skyboxPass->skipTonemapping =
true;
2662 currentPassData.skyboxPass->renderPrep(renderer, data);
2663 currentPassData.skyboxPass->ps.samples = ps.samples;
2664 currentPassData.skyboxPass->rpDesc = renderTarget->getRenderPassDescriptor().get();
2666 currentPassData.skyboxCubeMapPass =
std::nullopt;
2668 outData.push_back(currentPassData);
2670 }
else if (passNode->passMode == QSSGRenderUserPass::PassModes::Item2DPass) {
2671 if (!currentPassData.item2DPass)
2673 const bool hasItem2Ds = (data.item2DsView.size() > 0);
2676 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(renderer.contextInterface()->rhiContext().get());
2677 QRhiRenderTarget *prevRenderTarget = rhiCtx->renderTarget();
2678 rhiCtxD->setRenderTarget(renderTarget->getRenderTarget().get());
2679 currentPassData.item2DPass->renderPrep(renderer, data);
2681 rhiCtxD->setRenderTarget(prevRenderTarget);
2682 outData.push_back(currentPassData);