Revision control

++ // Copyright (C) 2008-2012 NVIDIA Corporation.
++ // Copyright (C) 2020 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++
++ #include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
++ #include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
++
++ 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<QSSGRhiBuffer>(*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<QSSGRhiBuffer>(*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<QSSGRhiBuffer>(*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<QSSGRhiBuffer>(*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