1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2020 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
6
7QT_BEGIN_NAMESPACE
8
9static const QVector3D g_fullScreenRectFaces[] = {
10 QVector3D(-1, -1, 0),
11 QVector3D(-1, 1, 0),
12 QVector3D(1, 1, 0),
13 QVector3D(1, -1, 0),
14
15 QVector3D(-1, -1, 1),
16 QVector3D(-1, 1, 1),
17 QVector3D(1, 1, 1),
18 QVector3D(1, -1, 1),
19
20 QVector3D(-1, -1, -1),
21 QVector3D(-1, 1, -1),
22 QVector3D(1, 1, -1),
23 QVector3D(1, -1, -1),
24};
25
26static const QVector2D g_fullScreenRectUVs[] = {
27 QVector2D(0, 0),
28 QVector2D(0, 1),
29 QVector2D(1, 1),
30 QVector2D(1, 0)
31};
32
33static const quint16 g_rectIndex[] = {
34 0, 1, 2, 0, 2, 3, // front face - 0, 1, 2, 3
35 0, 4, 5, 0, 5, 1, // left face - 0, 4, 5, 1
36 1, 5, 6, 1, 6, 2, // top face - 1, 5, 6, 2
37 3, 2, 6, 3, 6, 7, // right face - 3, 2, 6, 7
38 0, 3, 7, 0, 7, 4, // bottom face - 0, 3, 7, 4
39 7, 6, 5, 7, 5, 4 // back face - 7, 6, 5, 4
40};
41
42void QSSGRhiQuadRenderer::ensureBuffers(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *rub)
43{
44 if (!m_vbuf) {
45 constexpr int vertexCount = 8;
46 m_vbuf = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
47 args: QRhiBuffer::Immutable,
48 args: QRhiBuffer::VertexBuffer,
49 args: quint32(5 * sizeof(float)),
50 args: 5 * vertexCount * sizeof(float));
51 m_vbuf->buffer()->setName(QByteArrayLiteral("quad vertex buffer"));
52 float buf[5 * vertexCount];
53 float *p = buf;
54 for (int i = 0; i < vertexCount; ++i) {
55 *p++ = g_fullScreenRectFaces[i].x();
56 *p++ = g_fullScreenRectFaces[i].y();
57 *p++ = g_fullScreenRectFaces[i].z();
58 *p++ = g_fullScreenRectUVs[i % 4].x();
59 *p++ = g_fullScreenRectUVs[i % 4].y();
60 }
61 rub->uploadStaticBuffer(buf: m_vbuf->buffer(), data: buf);
62 }
63 if (!m_ibuf) {
64 m_ibuf = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
65 args: QRhiBuffer::Immutable,
66 args: QRhiBuffer::IndexBuffer,
67 args: 0,
68 args: 6 * sizeof(quint16),
69 args: QRhiCommandBuffer::IndexUInt16);
70 m_ibuf->buffer()->setName(QByteArrayLiteral("quad index buffer"));
71 const quint16 buf[] = { 0, 1, 2, 0, 2, 3 };
72 rub->uploadStaticBuffer(buf: m_ibuf->buffer(), data: buf);
73 }
74}
75
76void QSSGRhiQuadRenderer::prepareQuad(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *maybeRub)
77{
78 QRhiResourceUpdateBatch *rub = maybeRub ? maybeRub : rhiCtx->rhi()->nextResourceUpdateBatch();
79 ensureBuffers(rhiCtx, rub);
80 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates: rub);
81}
82
83void QSSGRhiQuadRenderer::recordRenderQuad(QSSGRhiContext *rhiCtx,
84 QSSGRhiGraphicsPipelineState *ps, QRhiShaderResourceBindings *srb,
85 QRhiRenderPassDescriptor *rpDesc, Flags flags)
86{
87 // ps must have viewport and shaderPipeline set already
88 if (flags.testFlag(flag: UvCoords)) {
89 ps->ia.inputLayout.setAttributes({
90 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
91 { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) }
92 });
93 ps->ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic << QSSGRhiInputAssemblerState::TexCoord0Semantic;
94 } else {
95 ps->ia.inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } });
96 ps->ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic;
97 }
98 ps->ia.inputLayout.setBindings({ 5 * sizeof(float) });
99 ps->ia.topology = QRhiGraphicsPipeline::Triangles;
100
101 ps->depthTestEnable = flags.testFlag(flag: DepthTest);
102 ps->depthWriteEnable = flags.testFlag(flag: DepthWrite);
103 ps->cullMode = QRhiGraphicsPipeline::None;
104 if (flags.testFlag(flag: PremulBlend)) {
105 ps->blendEnable = true;
106 ps->targetBlend.srcColor = QRhiGraphicsPipeline::One;
107 ps->targetBlend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
108 ps->targetBlend.srcAlpha = QRhiGraphicsPipeline::One;
109 ps->targetBlend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
110 } else { // set to default, since we may not have had a renderable previously
111 ps->targetBlend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
112 ps->targetBlend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
113 ps->targetBlend.srcAlpha = QRhiGraphicsPipeline::One;
114 ps->targetBlend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
115 }
116
117 QRhiGraphicsPipeline *pipeline = rhiCtx->pipeline(key: QSSGGraphicsPipelineStateKey::create(state: *ps, rpDesc, srb), rpDesc, srb);
118 // Make sure that we were able to create the pipeline before trying to use it
119 // When GraphicsPipeline creation fails it should return nullptr and print a warning
120 if (!pipeline)
121 return;
122
123 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
124 cb->setGraphicsPipeline(pipeline);
125 cb->setShaderResources(srb);
126 cb->setViewport(ps->viewport);
127
128 quint32 vertexOffset = flags.testAnyFlags(flags: RenderBehind) ? 5 * 4 * sizeof(float) : 0;
129
130 QRhiCommandBuffer::VertexInput vb(m_vbuf->buffer(), vertexOffset);
131 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
132 cb->setVertexInput(startBinding: 0, bindingCount: 1, bindings: &vb, indexBuf: m_ibuf->buffer(), indexOffset: m_ibuf->indexFormat());
133 cb->drawIndexed(indexCount: 6);
134 QSSGRHICTX_STAT(rhiCtx, drawIndexed(6, 1));
135 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderCall, 36llu | (1llu << 32), QByteArrayLiteral("render_quad"));
136}
137
138void QSSGRhiQuadRenderer::recordRenderQuadPass(QSSGRhiContext *rhiCtx,
139 QSSGRhiGraphicsPipelineState *ps, QRhiShaderResourceBindings *srb,
140 QRhiTextureRenderTarget *rt, Flags flags)
141{
142 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
143 cb->beginPass(rt, colorClearValue: Qt::black, depthStencilClearValue: { 1.0f, 0 }, resourceUpdates: nullptr, flags: QSSGRhiContext::commonPassFlags());
144 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(rt));
145 recordRenderQuad(rhiCtx, ps, srb, rpDesc: rt->renderPassDescriptor(), flags);
146 cb->endPass();
147 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
148}
149
150void QSSGRhiCubeRenderer::prepareCube(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *maybeRub)
151{
152 QRhiResourceUpdateBatch *rub = maybeRub ? maybeRub : rhiCtx->rhi()->nextResourceUpdateBatch();
153 ensureBuffers(rhiCtx, rub);
154 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates: rub);
155}
156
157//### The flags UvCoords and RenderBehind are ignored
158void QSSGRhiCubeRenderer::recordRenderCube(QSSGRhiContext *rhiCtx, QSSGRhiGraphicsPipelineState *ps, QRhiShaderResourceBindings *srb, QRhiRenderPassDescriptor *rpDesc, QSSGRhiQuadRenderer::Flags flags)
159{
160 // ps must have viewport and shaderPipeline set already
161 ps->ia.inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } });
162 ps->ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic;
163 ps->ia.inputLayout.setBindings({ 3 * sizeof(float) });
164 ps->ia.topology = QRhiGraphicsPipeline::Triangles;
165
166 ps->depthTestEnable = flags.testFlag(flag: QSSGRhiQuadRenderer::DepthTest);
167 ps->depthWriteEnable = flags.testFlag(flag: QSSGRhiQuadRenderer::DepthWrite);
168 ps->cullMode = QRhiGraphicsPipeline::None;
169 if (flags.testFlag(flag: QSSGRhiQuadRenderer::PremulBlend)) {
170 ps->blendEnable = true;
171 ps->targetBlend.srcColor = QRhiGraphicsPipeline::One;
172 ps->targetBlend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
173 ps->targetBlend.srcAlpha = QRhiGraphicsPipeline::One;
174 ps->targetBlend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
175 } else { // set to default, since we may not have had a renderable previously
176 ps->targetBlend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
177 ps->targetBlend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
178 ps->targetBlend.srcAlpha = QRhiGraphicsPipeline::One;
179 ps->targetBlend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
180 }
181
182 QRhiGraphicsPipeline *pipeline = rhiCtx->pipeline(key: QSSGGraphicsPipelineStateKey::create(state: *ps, rpDesc, srb), rpDesc, srb);
183 // Make sure that we were able to create the pipeline before trying to use it
184 // When GraphicsPipeline creation fails it should return nullptr and print a warning
185 if (!pipeline)
186 return;
187
188 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
189 cb->setGraphicsPipeline(pipeline);
190 cb->setShaderResources(srb);
191 cb->setViewport(ps->viewport);
192
193 QRhiCommandBuffer::VertexInput vb(m_vbuf->buffer(), 0);
194 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
195 cb->setVertexInput(startBinding: 0, bindingCount: 1, bindings: &vb, indexBuf: m_ibuf->buffer(), indexOffset: m_ibuf->indexFormat());
196 cb->drawIndexed(indexCount: 36);
197 QSSGRHICTX_STAT(rhiCtx, drawIndexed(36, 1));
198 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderCall, 36, QByteArrayLiteral("render_cube"));
199}
200
201void QSSGRhiCubeRenderer::ensureBuffers(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *rub)
202{
203 if (!m_vbuf) {
204 constexpr int vertexCount = 8;
205 m_vbuf = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
206 args: QRhiBuffer::Immutable,
207 args: QRhiBuffer::VertexBuffer,
208 args: quint32(3 * sizeof(float)),
209 args: 3 * vertexCount * sizeof(float));
210 m_vbuf->buffer()->setName(QByteArrayLiteral("cube vertex buffer"));
211
212 float buf[3 * vertexCount];
213 float *p = buf;
214 for (int i = 0; i < vertexCount; ++i) {
215 *p++ = g_fullScreenRectFaces[4 + i].x();
216 *p++ = g_fullScreenRectFaces[4 + i].y();
217 *p++ = g_fullScreenRectFaces[4 + i].z();
218 }
219 rub->uploadStaticBuffer(buf: m_vbuf->buffer(), data: buf);
220 }
221 if (!m_ibuf) {
222 m_ibuf = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
223 args: QRhiBuffer::Immutable,
224 args: QRhiBuffer::IndexBuffer,
225 args: 0,
226 args: sizeof(g_rectIndex),
227 args: QRhiCommandBuffer::IndexUInt16);
228 m_ibuf->buffer()->setName(QByteArrayLiteral("cube index buffer"));
229 rub->uploadStaticBuffer(buf: m_ibuf->buffer(), data: g_rectIndex);
230 }
231}
232
233QT_END_NAMESPACE
234

source code of qtquick3d/src/runtimerender/qssgrhiquadrenderer.cpp