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 | |
7 | QT_BEGIN_NAMESPACE |
8 | |
9 | static 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 | |
26 | static const QVector2D g_fullScreenRectUVs[] = { |
27 | QVector2D(0, 0), |
28 | QVector2D(0, 1), |
29 | QVector2D(1, 1), |
30 | QVector2D(1, 0) |
31 | }; |
32 | |
33 | static 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 | |
42 | void 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 | |
76 | void 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 | |
83 | void 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 | |
138 | void 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 | |
150 | void 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 |
158 | void 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 | |
201 | void 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 | |
233 | QT_END_NAMESPACE |
234 | |