1 | // Copyright (C) 2008-2012 NVIDIA Corporation. |
2 | // Copyright (C) 2022 The Qt Company Ltd. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
4 | |
5 | #ifndef QSSG_LAYER_RENDER_DATA_H |
6 | #define QSSG_LAYER_RENDER_DATA_H |
7 | |
8 | |
9 | // |
10 | // W A R N I N G |
11 | // ------------- |
12 | // |
13 | // This file is not part of the Qt API. It exists purely as an |
14 | // implementation detail. This header file may change from version to |
15 | // version without notice, or even be removed. |
16 | // |
17 | // We mean it. |
18 | // |
19 | |
20 | #include <QtQuick3DRuntimeRender/private/qssgrenderitem2d_p.h> |
21 | #include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h> |
22 | #include <QtQuick3DRuntimeRender/private/qssgrendershadercache_p.h> |
23 | #include <QtQuick3DRuntimeRender/private/qssgrenderableobjects_p.h> |
24 | #include <QtQuick3DRuntimeRender/private/qssgrenderclippingfrustum_p.h> |
25 | #include <QtQuick3DRuntimeRender/private/qssgrendershadowmap_p.h> |
26 | #include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h> |
27 | #include <QtQuick3DRuntimeRender/private/qssgrenderresourceloader_p.h> |
28 | #include <QtQuick3DRuntimeRender/private/qssgrenderreflectionmap_p.h> |
29 | #include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h> |
30 | #include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h> |
31 | #include <QtQuick3DRuntimeRender/private/qssgrenderextensions_p.h> |
32 | |
33 | #include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h> |
34 | |
35 | #include <optional> |
36 | |
37 | #include "qssgrenderpass_p.h" |
38 | |
39 | #define QSSG_RENDER_MINIMUM_RENDER_OPACITY .01f |
40 | |
41 | QT_BEGIN_NAMESPACE |
42 | |
43 | struct QSSGRenderableObject; |
44 | |
45 | enum class QSSGLayerRenderPreparationResultFlag |
46 | { |
47 | // Was the data in this layer dirty (meaning re-render to texture, possibly) |
48 | WasLayerDataDirty = 1 << 0, |
49 | |
50 | // Was the data in this layer dirty *or* this layer *or* any effect dirty. |
51 | WasDirty = 1 << 1, |
52 | |
53 | RequiresDepthTexture = 1 << 2, |
54 | |
55 | // SSAO should be done in a separate pass |
56 | // Note that having an AO pass necessitates a DepthTexture so this flag should |
57 | // never be set without the RequiresDepthTexture flag as well. |
58 | RequiresSsaoPass = 1 << 3, |
59 | |
60 | // if some light cause shadow |
61 | // we need a separate per light shadow map pass |
62 | RequiresShadowMapPass = 1 << 4, |
63 | |
64 | RequiresScreenTexture = 1 << 5, |
65 | |
66 | // set together with RequiresScreenTexture when SCREEN_MIP_TEXTURE is used |
67 | RequiresMipmapsForScreenTexture = 1 << 6 |
68 | }; |
69 | |
70 | struct QSSGLayerRenderPreparationResultFlags : public QFlags<QSSGLayerRenderPreparationResultFlag> |
71 | { |
72 | bool wasLayerDataDirty() const |
73 | { |
74 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::WasLayerDataDirty); |
75 | } |
76 | void setLayerDataDirty(bool inValue) |
77 | { |
78 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::WasLayerDataDirty, on: inValue); |
79 | } |
80 | |
81 | bool wasDirty() const { return this->operator&(other: QSSGLayerRenderPreparationResultFlag::WasDirty); } |
82 | void setWasDirty(bool inValue) { setFlag(flag: QSSGLayerRenderPreparationResultFlag::WasDirty, on: inValue); } |
83 | |
84 | bool requiresDepthTexture() const |
85 | { |
86 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresDepthTexture); |
87 | } |
88 | void setRequiresDepthTexture(bool inValue) |
89 | { |
90 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresDepthTexture, on: inValue); |
91 | } |
92 | |
93 | bool requiresSsaoPass() const { return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresSsaoPass); } |
94 | void setRequiresSsaoPass(bool inValue) |
95 | { |
96 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresSsaoPass, on: inValue); |
97 | } |
98 | |
99 | bool requiresShadowMapPass() const |
100 | { |
101 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresShadowMapPass); |
102 | } |
103 | void setRequiresShadowMapPass(bool inValue) |
104 | { |
105 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresShadowMapPass, on: inValue); |
106 | } |
107 | |
108 | bool requiresScreenTexture() const |
109 | { |
110 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresScreenTexture); |
111 | } |
112 | void setRequiresScreenTexture(bool inValue) |
113 | { |
114 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresScreenTexture, on: inValue); |
115 | } |
116 | |
117 | bool requiresMipmapsForScreenTexture() const |
118 | { |
119 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresMipmapsForScreenTexture); |
120 | } |
121 | void setRequiresMipmapsForScreenTexture(bool inValue) |
122 | { |
123 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresMipmapsForScreenTexture, on: inValue); |
124 | } |
125 | }; |
126 | |
127 | struct QSSGCameraRenderData |
128 | { |
129 | QMatrix4x4 viewProjection; |
130 | std::optional<QSSGClippingFrustum> clippingFrustum; |
131 | QVector3D direction { 0.0f, 0.0f, -1.0f }; |
132 | QVector3D position; |
133 | }; |
134 | |
135 | struct QSSGLayerRenderPreparationResult |
136 | { |
137 | QSSGLayerRenderPreparationResultFlags flags; |
138 | QRectF viewport; |
139 | QSSGRenderLayer *layer = nullptr; |
140 | |
141 | QSSGLayerRenderPreparationResult() = default; |
142 | QSSGLayerRenderPreparationResult(const QRectF &inViewport, QSSGRenderLayer &inLayer); |
143 | |
144 | bool isLayerVisible() const; |
145 | QSize textureDimensions() const; |
146 | QSSGCameraGlobalCalculationResult setupCameraForRender(QSSGRenderCamera &inCamera); |
147 | }; |
148 | |
149 | struct QSSGDefaultMaterialPreparationResult |
150 | { |
151 | QSSGRenderableImage *firstImage; |
152 | float opacity; |
153 | QSSGRenderableObjectFlags renderableFlags; |
154 | QSSGShaderDefaultMaterialKey materialKey; |
155 | bool dirty; |
156 | |
157 | explicit QSSGDefaultMaterialPreparationResult(QSSGShaderDefaultMaterialKey inMaterialKey); |
158 | }; |
159 | |
160 | struct QSSGBakedLightingModel |
161 | { |
162 | QSSGBakedLightingModel(const QSSGRenderModel *model, const QVector<QSSGRenderableObjectHandle> &renderables) |
163 | : model(model), |
164 | renderables(renderables) |
165 | { } |
166 | |
167 | const QSSGRenderModel *model; |
168 | QVector<QSSGRenderableObjectHandle> renderables; |
169 | }; |
170 | |
171 | class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGLayerRenderData |
172 | { |
173 | public: |
174 | enum Enum { |
175 | MAX_AA_LEVELS = 8, |
176 | MAX_TEMPORAL_AA_LEVELS = 2, |
177 | }; |
178 | |
179 | using RenderableFilter = std::function<bool(QSSGModelContext *)>; |
180 | |
181 | QSSGLayerRenderData(QSSGRenderLayer &inLayer, QSSGRenderer &inRenderer); |
182 | ~QSSGLayerRenderData(); |
183 | |
184 | typedef QVector<QSSGModelContext *> TModelContextPtrList; |
185 | using RenderableNodeEntries = QVector<QSSGRenderableNodeEntry>; |
186 | using RenderableItem2DEntries = QVector<QSSGRenderItem2D *>; |
187 | |
188 | QSSGShaderDefaultMaterialKey generateLightingKey(QSSGRenderDefaultMaterial::MaterialLighting inLightingType, |
189 | const QSSGShaderLightListView &lights, bool receivesShadows = true); |
190 | |
191 | void prepareImageForRender(QSSGRenderImage &inImage, |
192 | QSSGRenderableImage::Type inMapType, |
193 | QSSGRenderableImage *&ioFirstImage, |
194 | QSSGRenderableImage *&ioNextImage, |
195 | QSSGRenderableObjectFlags &ioFlags, |
196 | QSSGShaderDefaultMaterialKey &ioGeneratedShaderKey, |
197 | quint32 inImageIndex, QSSGRenderDefaultMaterial *inMaterial = nullptr); |
198 | |
199 | void setVertexInputPresence(const QSSGRenderableObjectFlags &renderableFlags, |
200 | QSSGShaderDefaultMaterialKey &key, |
201 | QSSGRenderer *renderer); |
202 | |
203 | // Load meshes as needed |
204 | static void prepareModelMeshes(const QSSGRenderContextInterface &contextInterface, |
205 | RenderableNodeEntries &renderableModels); |
206 | |
207 | static void prepareModelBoneTextures(const QSSGRenderContextInterface &contextInterface, |
208 | const RenderableNodeEntries &renderableModels); |
209 | |
210 | // Helper functions used during PrepareForRender and PrepareAndRender |
211 | // Updates lights with model receivesShadows. Do not pass globalLights. |
212 | bool prepareModelsForRender(const RenderableNodeEntries &renderableModels, |
213 | QSSGLayerRenderPreparationResultFlags &ioFlags, |
214 | const QSSGCameraRenderData &cameraData, |
215 | RenderableFilter filter, |
216 | float lodThreshold = 0.0f); |
217 | bool prepareParticlesForRender(const RenderableNodeEntries &renderableParticles, const QSSGCameraRenderData &cameraData); |
218 | bool prepareItem2DsForRender(const QSSGRenderContextInterface &ctxIfc, |
219 | const RenderableItem2DEntries &renderableItem2Ds); |
220 | |
221 | void prepareResourceLoaders(); |
222 | |
223 | void prepareForRender(); |
224 | // Helper function used during prepareForRender |
225 | void prepareReflectionProbesForRender(); |
226 | |
227 | static qsizetype frustumCulling(const QSSGClippingFrustum &clipFrustum, const QSSGRenderableObjectList &renderables, QSSGRenderableObjectList &visibleRenderables); |
228 | [[nodiscard]] static qsizetype frustumCullingInline(const QSSGClippingFrustum &clipFrustum, QSSGRenderableObjectList &renderables); |
229 | |
230 | |
231 | // Per-frame cache of renderable objects post-sort (for the MAIN rendering camera, i.e., don't use these lists for rendering from a different camera). |
232 | const QSSGRenderableObjectList &getSortedOpaqueRenderableObjects(); |
233 | // If layer depth test is false, this may also contain opaque objects. |
234 | const QSSGRenderableObjectList &getSortedTransparentRenderableObjects(); |
235 | const QSSGRenderableObjectList &getSortedScreenTextureRenderableObjects(); |
236 | const QVector<QSSGBakedLightingModel> &getSortedBakedLightingModels(); |
237 | const RenderableItem2DEntries &getRenderableItem2Ds(); |
238 | const QSSGRenderableObjectList &getSortedRenderedDepthWriteObjects(); |
239 | const QSSGRenderableObjectList &getSortedrenderedOpaqueDepthPrepassObjects(); |
240 | |
241 | void resetForFrame(); |
242 | |
243 | void maybeBakeLightmap(); |
244 | |
245 | QSSGFrameData &getFrameData(); |
246 | |
247 | ShadowMapPass shadowMapPass; |
248 | ReflectionMapPass reflectionMapPass; |
249 | ZPrePassPass zPrePassPass; |
250 | SSAOMapPass ssaoMapPass; |
251 | DepthMapPass depthMapPass; |
252 | ScreenMapPass screenMapPass; |
253 | ScreenReflectionPass reflectionPass; |
254 | Item2DPass item2DPass; |
255 | SkyboxPass skyboxPass; |
256 | SkyboxCubeMapPass skyboxCubeMapPass; |
257 | static constexpr size_t USERPASSES = 2; // See QSSGRenderLayer::RenderExtensionMode::Count |
258 | UserPass userPasses[USERPASSES]; |
259 | OpaquePass opaquePass; |
260 | TransparentPass transparentPass; |
261 | InfiniteGridPass infiniteGridPass; |
262 | DebugDrawPass debugDrawPass; |
263 | |
264 | // Built-in passes |
265 | QVarLengthArray<QSSGRenderPass *, 16> activePasses; |
266 | |
267 | QSSGRenderLayer &layer; |
268 | QSSGRenderer *renderer = nullptr; |
269 | // List of nodes we can render, not all may be active. Found by doing a depth-first |
270 | // search through m_FirstChild if length is zero. |
271 | |
272 | // renderableNodes have all lights, but properties configured for specific node |
273 | RenderableNodeEntries renderableModels; |
274 | RenderableNodeEntries renderableParticles; |
275 | QVector<QSSGRenderItem2D *> renderableItem2Ds; |
276 | QVector<QSSGRenderCamera *> cameras; |
277 | QVector<QSSGRenderLight *> lights; |
278 | QVector<QSSGRenderReflectionProbe *> reflectionProbes; |
279 | |
280 | // Results of prepare for render. |
281 | QSSGRenderCamera *camera = nullptr; |
282 | QSSGShaderLightList globalLights; // All non-scoped lights |
283 | QSSGRenderableObjectList opaqueObjects; |
284 | QSSGRenderableObjectList transparentObjects; |
285 | QSSGRenderableObjectList screenTextureObjects; |
286 | QVector<QSSGBakedLightingModel> bakedLightingModels; |
287 | // Sorted lists of the rendered objects. There may be other transforms applied so |
288 | // it is simplest to duplicate the lists. |
289 | QSSGRenderableObjectList renderedOpaqueObjects; |
290 | QSSGRenderableObjectList renderedTransparentObjects; |
291 | QSSGRenderableObjectList renderedScreenTextureObjects; |
292 | QSSGRenderableObjectList renderedOpaqueDepthPrepassObjects; |
293 | QSSGRenderableObjectList renderedDepthWriteObjects; |
294 | QVector<QSSGBakedLightingModel> renderedBakedLightingModels; |
295 | RenderableItem2DEntries renderedItem2Ds; |
296 | |
297 | std::optional<QSSGClippingFrustum> clippingFrustum; |
298 | std::optional<QSSGLayerRenderPreparationResult> layerPrepResult; |
299 | std::optional<QSSGCameraRenderData> cameraData; |
300 | |
301 | TModelContextPtrList modelContexts; |
302 | |
303 | |
304 | bool tooManyLightsWarningShown = false; |
305 | bool tooManyShadowLightsWarningShown = false; |
306 | |
307 | QSSGLightmapper *m_lightmapper = nullptr; |
308 | |
309 | QSSGShaderFeatures getShaderFeatures() const { return features; } |
310 | QSSGRhiGraphicsPipelineState getPipelineState() const { return ps; } |
311 | |
312 | bool interactiveLightmapBakingRequested = false; |
313 | QSSGLightmapper::Callback lightmapBakingOutputCallback; |
314 | |
315 | [[nodiscard]] QSSGRenderableNodeEntry getNode(QSSGNodeId id) const; |
316 | [[nodiscard]] QSSGRenderableNodeEntry takeNode(QSSGNodeId id); |
317 | |
318 | [[nodiscard]] QSSGRenderGraphObject *getResource(QSSGResourceId id) const; |
319 | |
320 | [[nodiscard]] QSSGRenderCamera *activeCamera() const { return camera; } |
321 | |
322 | [[nodiscard]] QSSGCameraRenderData getCameraRenderData(const QSSGRenderCamera *camera); |
323 | [[nodiscard]] QSSGCameraRenderData getCameraRenderData(const QSSGRenderCamera *camera) const; |
324 | |
325 | void setLightmapTexture(const QSSGModelContext &modelContext, QRhiTexture *lightmapTexture); |
326 | [[nodiscard]] QRhiTexture *getLightmapTexture(const QSSGModelContext &modelContext) const; |
327 | |
328 | void setBonemapTexture(const QSSGModelContext &modelContext, QRhiTexture *bonemapTexture); |
329 | [[nodiscard]] QRhiTexture *getBonemapTexture(const QSSGModelContext &modelContext) const; |
330 | |
331 | [[nodiscard]] QSSGRenderContextInterface *contextInterface() const; |
332 | // Note: temp. API to report the state of the z-prepass step |
333 | [[nodiscard]] bool isZPrePassActive() const { return zPrePassActive; } |
334 | void setZPrePassPrepResult(bool res) { zPrePassActive = res; } |
335 | |
336 | |
337 | // Temp. API. Ideally there shouldn't be a reason for anyone to hold onto these, |
338 | // but we follow the existing pattern for now. |
339 | const QSSGRenderShadowMapPtr &requestShadowMapManager(); |
340 | const QSSGRenderReflectionMapPtr &requestReflectionMapManager(); |
341 | const QSSGRenderShadowMapPtr &getShadowMapManager() const { return shadowMapManager; } |
342 | const QSSGRenderReflectionMapPtr &getReflectionMapManager() const { return reflectionMapManager; } |
343 | |
344 | static bool prepareInstancing(QSSGRhiContext *rhiCtx, |
345 | QSSGSubsetRenderable *renderable, |
346 | const QVector3D &cameraDirection, |
347 | const QVector3D &cameraPosition, |
348 | float minThreshold, |
349 | float maxThreshold); |
350 | |
351 | [[nodiscard]] QSSGRhiRenderableTexture *getRenderResult(QSSGFrameData::RenderResult id) { return &renderResults[size_t(id)]; } |
352 | [[nodiscard]] const QSSGRhiRenderableTexture *getRenderResult(QSSGFrameData::RenderResult id) const { return &renderResults[size_t(id)]; } |
353 | |
354 | private: |
355 | friend class QSSGRenderer; |
356 | friend class QSSGFrameData; |
357 | friend class QSSGModelHelpers; |
358 | friend class QSSGRenderHelpers; |
359 | |
360 | [[nodiscard]] QSSGCameraRenderData getCachedCameraData(); |
361 | void updateSortedDepthObjectsListImp(); |
362 | |
363 | [[nodiscard]] static QSSGLayerRenderData *getCurrent(const QSSGRenderer &renderer) { return renderer.m_currentLayer; } |
364 | |
365 | QSSGDefaultMaterialPreparationResult prepareDefaultMaterialForRender(QSSGRenderDefaultMaterial &inMaterial, |
366 | QSSGRenderableObjectFlags &inExistingFlags, |
367 | float inOpacity, |
368 | const QSSGShaderLightListView &lights, |
369 | QSSGLayerRenderPreparationResultFlags &ioFlags); |
370 | |
371 | QSSGDefaultMaterialPreparationResult prepareCustomMaterialForRender(QSSGRenderCustomMaterial &inMaterial, |
372 | QSSGRenderableObjectFlags &inExistingFlags, |
373 | float inOpacity, bool alreadyDirty, |
374 | const QSSGShaderLightListView &lights, |
375 | QSSGLayerRenderPreparationResultFlags &ioFlags); |
376 | |
377 | |
378 | static void prepareModelMeshesForRenderInternal(const QSSGRenderContextInterface &contextInterface, |
379 | RenderableNodeEntries &renderableModels, |
380 | bool globalPickingEnabled); |
381 | |
382 | QSSGFrameData frameData; |
383 | QSSGRhiGraphicsPipelineState ps; // Base pipleline state |
384 | QSSGShaderFeatures features; // Base feature set |
385 | bool particlesEnabled = true; |
386 | bool hasDepthWriteObjects = false; |
387 | bool zPrePassActive = false; |
388 | enum class DepthPrepassObject : quint8 |
389 | { |
390 | None = 0x0, |
391 | ScreenTexture = 0x1, |
392 | Transparent = 0x2, |
393 | Opaque = 0x4 |
394 | }; |
395 | using DepthPrepassObjectStateT = std::underlying_type_t<DepthPrepassObject>; |
396 | DepthPrepassObjectStateT depthPrepassObjectsState { DepthPrepassObjectStateT(DepthPrepassObject::None) }; |
397 | QSSGRenderShadowMapPtr shadowMapManager; |
398 | QSSGRenderReflectionMapPtr reflectionMapManager; |
399 | QHash<const QSSGModelContext *, QRhiTexture *> lightmapTextures; |
400 | QHash<const QSSGModelContext *, QRhiTexture *> bonemapTextures; |
401 | QSSGRhiRenderableTexture renderResults[3] {}; |
402 | }; |
403 | |
404 | QT_END_NAMESPACE |
405 | |
406 | #endif // QSSG_LAYER_RENDER_DATA_H |
407 | |
408 | |