// Copyright (C) 2008-2012 NVIDIA Corporation. // Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include QT_BEGIN_NAMESPACE static const QVector3D g_fullScreenRectFaces[] = { QVector3D(-1, -1, 0), QVector3D(-1, 1, 0), QVector3D(1, 1, 0), QVector3D(1, -1, 0), QVector3D(-1, -1, 1), QVector3D(-1, 1, 1), QVector3D(1, 1, 1), QVector3D(1, -1, 1), QVector3D(-1, -1, -1), QVector3D(-1, 1, -1), QVector3D(1, 1, -1), QVector3D(1, -1, -1), }; static const QVector2D g_fullScreenRectUVs[] = { QVector2D(0, 0), QVector2D(0, 1), QVector2D(1, 1), QVector2D(1, 0) }; static const quint16 g_rectIndex[] = { 0, 1, 2, 0, 2, 3, // front face - 0, 1, 2, 3 0, 4, 5, 0, 5, 1, // left face - 0, 4, 5, 1 1, 5, 6, 1, 6, 2, // top face - 1, 5, 6, 2 3, 2, 6, 3, 6, 7, // right face - 3, 2, 6, 7 0, 3, 7, 0, 7, 4, // bottom face - 0, 3, 7, 4 7, 6, 5, 7, 5, 4 // back face - 7, 6, 5, 4 }; void QSSGRhiQuadRenderer::ensureBuffers(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *rub) { if (!m_vbuf) { constexpr int vertexCount = 8; m_vbuf = std::make_shared(*rhiCtx, QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, quint32(5 * sizeof(float)), 5 * vertexCount * sizeof(float)); m_vbuf->buffer()->setName(QByteArrayLiteral("quad vertex buffer")); float buf[5 * vertexCount]; float *p = buf; for (int i = 0; i < vertexCount; ++i) { *p++ = g_fullScreenRectFaces[i].x(); *p++ = g_fullScreenRectFaces[i].y(); *p++ = g_fullScreenRectFaces[i].z(); *p++ = g_fullScreenRectUVs[i % 4].x(); *p++ = g_fullScreenRectUVs[i % 4].y(); } rub->uploadStaticBuffer(m_vbuf->buffer(), buf); } if (!m_ibuf) { m_ibuf = std::make_shared(*rhiCtx, QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, 0, 6 * sizeof(quint16), QRhiCommandBuffer::IndexUInt16); m_ibuf->buffer()->setName(QByteArrayLiteral("quad index buffer")); const quint16 buf[] = { 0, 1, 2, 0, 2, 3 }; rub->uploadStaticBuffer(m_ibuf->buffer(), buf); } } void QSSGRhiQuadRenderer::prepareQuad(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *maybeRub) { QRhiResourceUpdateBatch *rub = maybeRub ? maybeRub : rhiCtx->rhi()->nextResourceUpdateBatch(); ensureBuffers(rhiCtx, rub); rhiCtx->commandBuffer()->resourceUpdate(rub); } void QSSGRhiQuadRenderer::recordRenderQuad(QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiShaderResourceBindings *srb, QRhiRenderPassDescriptor *rpDesc, Flags flags) { // ps must have viewport and shaderPipeline set already auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps); if (flags.testFlag(UvCoords)) { ia.inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } }); ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic << QSSGRhiInputAssemblerState::TexCoord0Semantic; } else { ia.inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } }); ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic; } ia.inputLayout.setBindings({ 5 * sizeof(float) }); ia.topology = QRhiGraphicsPipeline::Triangles; ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, flags.testFlag(DepthTest)); ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, flags.testFlag(DepthWrite)); ps->cullMode = QRhiGraphicsPipeline::None; if (flags.testFlag(PremulBlend)) { ps->flags |= QSSGRhiGraphicsPipelineState::Flag::BlendEnabled; ps->targetBlend[0].srcColor = QRhiGraphicsPipeline::One; ps->targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha; ps->targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One; ps->targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha; } else { // set to default, since we may not have had a renderable previously ps->targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha; ps->targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha; ps->targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One; ps->targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha; } QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx); QRhiGraphicsPipeline *pipeline = rhiCtxD->pipeline(*ps, rpDesc, srb); // Make sure that we were able to create the pipeline before trying to use it // When GraphicsPipeline creation fails it should return nullptr and print a warning if (!pipeline) return; QRhiCommandBuffer *cb = rhiCtx->commandBuffer(); cb->setGraphicsPipeline(pipeline); cb->setShaderResources(srb); cb->setViewport(ps->viewport); quint32 vertexOffset = flags.testAnyFlags(RenderBehind) ? 5 * 4 * sizeof(float) : 0; QRhiCommandBuffer::VertexInput vb(m_vbuf->buffer(), vertexOffset); Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall); cb->setVertexInput(0, 1, &vb, m_ibuf->buffer(), m_ibuf->indexFormat()); cb->drawIndexed(6); QSSGRHICTX_STAT(rhiCtx, drawIndexed(6, 1)); Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderCall, 36llu | (1llu << 32), QByteArrayLiteral("render_quad")); } void QSSGRhiQuadRenderer::recordRenderQuadPass(QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiShaderResourceBindings *srb, QRhiTextureRenderTarget *rt, Flags flags) { QRhiCommandBuffer *cb = rhiCtx->commandBuffer(); cb->beginPass(rt, Qt::black, { 1.0f, 0 }, nullptr, rhiCtx->commonPassFlags()); QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt)); recordRenderQuad(rhiCtx, ps, srb, rt->renderPassDescriptor(), flags); cb->endPass(); QSSGRHICTX_STAT(rhiCtx, endRenderPass()); } void QSSGRhiCubeRenderer::prepareCube(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *maybeRub) { QRhiResourceUpdateBatch *rub = maybeRub ? maybeRub : rhiCtx->rhi()->nextResourceUpdateBatch(); ensureBuffers(rhiCtx, rub); rhiCtx->commandBuffer()->resourceUpdate(rub); } //### The flags UvCoords and RenderBehind are ignored void QSSGRhiCubeRenderer::recordRenderCube(QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiShaderResourceBindings *srb, QRhiRenderPassDescriptor *rpDesc, QSSGRhiQuadRenderer::Flags flags) { auto &ia = QSSGRhiInputAssemblerStatePrivate::get(*ps); // ps must have viewport and shaderPipeline set already ia.inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } }); ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic; ia.inputLayout.setBindings({ 3 * sizeof(float) }); ia.topology = QRhiGraphicsPipeline::Triangles; ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled, flags.testFlag(QSSGRhiQuadRenderer::DepthTest)); ps->flags.setFlag(QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled, flags.testFlag(QSSGRhiQuadRenderer::DepthWrite)); ps->cullMode = QRhiGraphicsPipeline::None; if (flags.testFlag(QSSGRhiQuadRenderer::PremulBlend)) { ps->flags |= QSSGRhiGraphicsPipelineState::Flag::BlendEnabled; ps->targetBlend[0].srcColor = QRhiGraphicsPipeline::One; ps->targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha; ps->targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One; ps->targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha; } else { // set to default, since we may not have had a renderable previously ps->targetBlend[0].srcColor = QRhiGraphicsPipeline::SrcAlpha; ps->targetBlend[0].dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha; ps->targetBlend[0].srcAlpha = QRhiGraphicsPipeline::One; ps->targetBlend[0].dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha; } QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx); QRhiGraphicsPipeline *pipeline = rhiCtxD->pipeline(*ps, rpDesc, srb); // Make sure that we were able to create the pipeline before trying to use it // When GraphicsPipeline creation fails it should return nullptr and print a warning if (!pipeline) return; QRhiCommandBuffer *cb = rhiCtx->commandBuffer(); cb->setGraphicsPipeline(pipeline); cb->setShaderResources(srb); cb->setViewport(ps->viewport); QRhiCommandBuffer::VertexInput vb(m_vbuf->buffer(), 0); Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall); cb->setVertexInput(0, 1, &vb, m_ibuf->buffer(), m_ibuf->indexFormat()); cb->drawIndexed(36); QSSGRHICTX_STAT(rhiCtx, drawIndexed(36, 1)); Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderCall, 36, QByteArrayLiteral("render_cube")); } void QSSGRhiCubeRenderer::ensureBuffers(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *rub) { if (!m_vbuf) { constexpr int vertexCount = 8; m_vbuf = std::make_shared(*rhiCtx, QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, quint32(3 * sizeof(float)), 3 * vertexCount * sizeof(float)); m_vbuf->buffer()->setName(QByteArrayLiteral("cube vertex buffer")); float buf[3 * vertexCount]; float *p = buf; for (int i = 0; i < vertexCount; ++i) { *p++ = g_fullScreenRectFaces[4 + i].x(); *p++ = g_fullScreenRectFaces[4 + i].y(); *p++ = g_fullScreenRectFaces[4 + i].z(); } rub->uploadStaticBuffer(m_vbuf->buffer(), buf); } if (!m_ibuf) { m_ibuf = std::make_shared(*rhiCtx, QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, 0, sizeof(g_rectIndex), QRhiCommandBuffer::IndexUInt16); m_ibuf->buffer()->setName(QByteArrayLiteral("cube index buffer")); rub->uploadStaticBuffer(m_ibuf->buffer(), g_rectIndex); } } QT_END_NAMESPACE