| 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/qssgrendershadowmap_p.h> |
| 25 | #include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h> |
| 26 | #include <QtQuick3DRuntimeRender/private/qssgrenderresourceloader_p.h> |
| 27 | #include <QtQuick3DRuntimeRender/private/qssgrenderreflectionmap_p.h> |
| 28 | #include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h> |
| 29 | #include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h> |
| 30 | #include <QtQuick3DRuntimeRender/private/qssgperframeallocator_p.h> |
| 31 | #include <QtQuick3DRuntimeRender/private/qssgshadermapkey_p.h> |
| 32 | #include <QtQuick3DRuntimeRender/private/qssglightmapbaker_p.h> |
| 33 | #include <ssg/qssgrenderextensions.h> |
| 34 | |
| 35 | #include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h> |
| 36 | |
| 37 | #include <optional> |
| 38 | #include <unordered_map> |
| 39 | |
| 40 | #include "qssgrenderpass_p.h" |
| 41 | #include "qssgrenderdata_p.h" |
| 42 | |
| 43 | QT_BEGIN_NAMESPACE |
| 44 | |
| 45 | class QSSGRenderableObject; |
| 46 | |
| 47 | class QSGRenderer; |
| 48 | |
| 49 | enum class QSSGLayerRenderPreparationResultFlag |
| 50 | { |
| 51 | // Was the data in this layer dirty (meaning re-render to texture, possibly) |
| 52 | WasLayerDataDirty = 1 << 0, |
| 53 | |
| 54 | // Was the data in this layer dirty *or* this layer *or* any effect dirty. |
| 55 | WasDirty = 1 << 1, |
| 56 | |
| 57 | RequiresDepthTexture = 1 << 2, |
| 58 | |
| 59 | // SSAO should be done in a separate pass |
| 60 | // Note that having an AO pass necessitates a DepthTexture so this flag should |
| 61 | // never be set without the RequiresDepthTexture flag as well. |
| 62 | RequiresSsaoPass = 1 << 3, |
| 63 | |
| 64 | // if some light cause shadow |
| 65 | // we need a separate per light shadow map pass |
| 66 | RequiresShadowMapPass = 1 << 4, |
| 67 | |
| 68 | RequiresScreenTexture = 1 << 5, |
| 69 | |
| 70 | // set together with RequiresScreenTexture when SCREEN_MIP_TEXTURE is used |
| 71 | RequiresMipmapsForScreenTexture = 1 << 6, |
| 72 | |
| 73 | // Set when material has custom blend mode(not SourceOver) |
| 74 | MaterialHasCustomBlendMode = 1 << 7, |
| 75 | |
| 76 | // Set when multisampled depth texture is required |
| 77 | RequiresDepthTextureMS = 1 << 8 |
| 78 | }; |
| 79 | |
| 80 | struct QSSGLayerRenderPreparationResultFlags : public QFlags<QSSGLayerRenderPreparationResultFlag> |
| 81 | { |
| 82 | bool wasLayerDataDirty() const |
| 83 | { |
| 84 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::WasLayerDataDirty); |
| 85 | } |
| 86 | void setLayerDataDirty(bool inValue) |
| 87 | { |
| 88 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::WasLayerDataDirty, on: inValue); |
| 89 | } |
| 90 | |
| 91 | bool wasDirty() const { return this->operator&(other: QSSGLayerRenderPreparationResultFlag::WasDirty); } |
| 92 | void setWasDirty(bool inValue) { setFlag(flag: QSSGLayerRenderPreparationResultFlag::WasDirty, on: inValue); } |
| 93 | |
| 94 | bool requiresDepthTexture() const |
| 95 | { |
| 96 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresDepthTexture); |
| 97 | } |
| 98 | void setRequiresDepthTexture(bool inValue) |
| 99 | { |
| 100 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresDepthTexture, on: inValue); |
| 101 | } |
| 102 | |
| 103 | bool requiresDepthTextureMS() const |
| 104 | { |
| 105 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresDepthTextureMS); |
| 106 | } |
| 107 | void setRequiresDepthTextureMS(bool inValue) |
| 108 | { |
| 109 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresDepthTextureMS, on: inValue); |
| 110 | } |
| 111 | |
| 112 | bool requiresSsaoPass() const { return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresSsaoPass); } |
| 113 | void setRequiresSsaoPass(bool inValue) |
| 114 | { |
| 115 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresSsaoPass, on: inValue); |
| 116 | } |
| 117 | |
| 118 | bool requiresShadowMapPass() const |
| 119 | { |
| 120 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresShadowMapPass); |
| 121 | } |
| 122 | void setRequiresShadowMapPass(bool inValue) |
| 123 | { |
| 124 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresShadowMapPass, on: inValue); |
| 125 | } |
| 126 | |
| 127 | bool requiresScreenTexture() const |
| 128 | { |
| 129 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresScreenTexture); |
| 130 | } |
| 131 | void setRequiresScreenTexture(bool inValue) |
| 132 | { |
| 133 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresScreenTexture, on: inValue); |
| 134 | } |
| 135 | |
| 136 | bool requiresMipmapsForScreenTexture() const |
| 137 | { |
| 138 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::RequiresMipmapsForScreenTexture); |
| 139 | } |
| 140 | void setRequiresMipmapsForScreenTexture(bool inValue) |
| 141 | { |
| 142 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::RequiresMipmapsForScreenTexture, on: inValue); |
| 143 | } |
| 144 | |
| 145 | bool hasCustomBlendMode() const |
| 146 | { |
| 147 | return this->operator&(other: QSSGLayerRenderPreparationResultFlag::MaterialHasCustomBlendMode); |
| 148 | } |
| 149 | void setHasCustomBlendMode(bool inValue) |
| 150 | { |
| 151 | setFlag(flag: QSSGLayerRenderPreparationResultFlag::MaterialHasCustomBlendMode, on: inValue); |
| 152 | } |
| 153 | }; |
| 154 | |
| 155 | struct QSSGLayerRenderPreparationResult |
| 156 | { |
| 157 | QSSGLayerRenderPreparationResultFlags flags; |
| 158 | QRectF viewport; |
| 159 | QSSGRenderLayer *layer = nullptr; |
| 160 | |
| 161 | QSSGLayerRenderPreparationResult() = default; |
| 162 | QSSGLayerRenderPreparationResult(const QRectF &inViewport, QSSGRenderLayer &inLayer); |
| 163 | |
| 164 | bool isNull() const { return !layer; } |
| 165 | bool isLayerVisible() const; |
| 166 | QSize textureDimensions() const; |
| 167 | }; |
| 168 | |
| 169 | struct QSSGDefaultMaterialPreparationResult |
| 170 | { |
| 171 | QSSGRenderableImage *firstImage; |
| 172 | float opacity; |
| 173 | QSSGRenderableObjectFlags renderableFlags; |
| 174 | QSSGShaderDefaultMaterialKey materialKey; |
| 175 | bool dirty; |
| 176 | |
| 177 | explicit QSSGDefaultMaterialPreparationResult(QSSGShaderDefaultMaterialKey inMaterialKey); |
| 178 | }; |
| 179 | |
| 180 | struct QSSGBakedLightingModel |
| 181 | { |
| 182 | QSSGBakedLightingModel(const QSSGRenderModel *model, const QVector<QSSGRenderableObjectHandle> &renderables) |
| 183 | : model(model), |
| 184 | renderables(renderables) |
| 185 | { } |
| 186 | |
| 187 | const QSSGRenderModel *model; |
| 188 | QVector<QSSGRenderableObjectHandle> renderables; |
| 189 | }; |
| 190 | |
| 191 | struct QSSGOITRenderContext |
| 192 | { |
| 193 | QRhiTextureRenderTarget *oitRenderTarget = nullptr; |
| 194 | QRhiRenderPassDescriptor *renderPassDescriptor = nullptr; |
| 195 | void reset() |
| 196 | { |
| 197 | delete oitRenderTarget; |
| 198 | delete renderPassDescriptor; |
| 199 | oitRenderTarget = nullptr; |
| 200 | renderPassDescriptor = nullptr; |
| 201 | } |
| 202 | }; |
| 203 | |
| 204 | class Q_QUICK3DRUNTIMERENDER_EXPORT QSSGLayerRenderData |
| 205 | { |
| 206 | public: |
| 207 | enum Enum { |
| 208 | MAX_AA_LEVELS = 8, |
| 209 | MAX_TEMPORAL_AA_LEVELS = 2, |
| 210 | }; |
| 211 | |
| 212 | using InstanceTransforms = QSSGGlobalRenderNodeData::InstanceTransforms; |
| 213 | using ModelViewProjections = QSSGRenderModelData::ModelViewProjections; |
| 214 | |
| 215 | using QSSGModelsView = QSSGDataView<QSSGRenderModel *>; |
| 216 | using QSSGParticlesView = QSSGDataView<QSSGRenderParticles *>; |
| 217 | using QSSGItem2DsView = QSSGDataView<QSSGRenderItem2D *>; |
| 218 | using QSSGCamerasView = QSSGDataView<QSSGRenderCamera *>; |
| 219 | using QSSGLightsView = QSSGDataView<QSSGRenderLight *>; |
| 220 | using QSSGReflectionProbesView = QSSGDataView<QSSGRenderReflectionProbe *>; |
| 221 | using QSSGNonCategorizedView = QSSGDataView<QSSGRenderNode *>; |
| 222 | |
| 223 | using RenderableFilter = std::function<bool(QSSGModelContext *)>; |
| 224 | |
| 225 | QSSGLayerRenderData(QSSGRenderLayer &inLayer, QSSGRenderer &inRenderer); |
| 226 | ~QSSGLayerRenderData(); |
| 227 | |
| 228 | typedef QVector<QSSGModelContext *> TModelContextPtrList; |
| 229 | using RenderableNodeEntries = QVector<QSSGRenderableNodeEntry>; |
| 230 | using RenderableItem2DEntries = QVector<QSSGRenderItem2D *>; |
| 231 | |
| 232 | QSSGShaderDefaultMaterialKey generateLightingKey(QSSGRenderDefaultMaterial::MaterialLighting inLightingType, |
| 233 | const QSSGShaderLightListView &lights, bool receivesShadows = true); |
| 234 | |
| 235 | void prepareImageForRender(QSSGRenderImage &inImage, |
| 236 | QSSGRenderableImage::Type inMapType, |
| 237 | QSSGRenderableImage *&ioFirstImage, |
| 238 | QSSGRenderableImage *&ioNextImage, |
| 239 | QSSGRenderableObjectFlags &ioFlags, |
| 240 | QSSGShaderDefaultMaterialKey &ioGeneratedShaderKey, |
| 241 | quint32 inImageIndex, QSSGRenderDefaultMaterial *inMaterial = nullptr); |
| 242 | |
| 243 | void setVertexInputPresence(const QSSGRenderableObjectFlags &renderableFlags, |
| 244 | QSSGShaderDefaultMaterialKey &key); |
| 245 | |
| 246 | static void prepareModelBoneTextures(const QSSGRenderContextInterface &contextInterface, |
| 247 | const RenderableNodeEntries &renderableModels); |
| 248 | |
| 249 | // Helper functions used during PrepareForRender and PrepareAndRender |
| 250 | // Updates lights with model receivesShadows. Do not pass globalLights. |
| 251 | bool prepareModelsForRender(QSSGRenderContextInterface &ctx, |
| 252 | const RenderableNodeEntries &renderableModels, |
| 253 | QSSGLayerRenderPreparationResultFlags &ioFlags, |
| 254 | const QSSGRenderCameraList &allCameras, |
| 255 | const QSSGRenderCameraDataList &allCameraData, |
| 256 | TModelContextPtrList &modelContexts, |
| 257 | QSSGRenderableObjectList &opaqueObjects, |
| 258 | QSSGRenderableObjectList &transparentObjects, |
| 259 | QSSGRenderableObjectList &screenTextureObjects, |
| 260 | float lodThreshold = 0.0f); |
| 261 | bool prepareParticlesForRender(const RenderableNodeEntries &renderableParticles, const QSSGRenderCameraData &cameraData, QSSGLayerRenderPreparationResultFlags &ioFlags); |
| 262 | bool prepareItem2DsForRender(const QSSGRenderContextInterface &ctxIfc, |
| 263 | const QSSGItem2DsView &renderableItem2Ds); |
| 264 | |
| 265 | void prepareResourceLoaders(); |
| 266 | |
| 267 | void prepareForRender(); |
| 268 | // Helper function used during prepareForRender |
| 269 | void prepareReflectionProbesForRender(); |
| 270 | |
| 271 | static qsizetype frustumCulling(const QSSGClippingFrustum &clipFrustum, const QSSGRenderableObjectList &renderables, QSSGRenderableObjectList &visibleRenderables); |
| 272 | [[nodiscard]] static qsizetype frustumCullingInline(const QSSGClippingFrustum &clipFrustum, QSSGRenderableObjectList &renderables); |
| 273 | |
| 274 | |
| 275 | // 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). |
| 276 | const QSSGRenderableObjectList &getSortedOpaqueRenderableObjects(const QSSGRenderCamera &camera, size_t index = 0); |
| 277 | // If layer depth test is false, this may also contain opaque objects. |
| 278 | const QSSGRenderableObjectList &getSortedTransparentRenderableObjects(const QSSGRenderCamera &camera, size_t index = 0); |
| 279 | const QSSGRenderableObjectList &getSortedScreenTextureRenderableObjects(const QSSGRenderCamera &camera, size_t index = 0); |
| 280 | const QVector<QSSGBakedLightingModel> &getSortedBakedLightingModels(); |
| 281 | const RenderableItem2DEntries &getRenderableItem2Ds(); |
| 282 | const QSSGRenderableObjectList &getSortedRenderedDepthWriteObjects(const QSSGRenderCamera &camera, size_t index = 0); |
| 283 | const QSSGRenderableObjectList &getSortedrenderedOpaqueDepthPrepassObjects(const QSSGRenderCamera &camera, size_t index = 0); |
| 284 | |
| 285 | void resetForFrame(); |
| 286 | |
| 287 | QSSGFrameData &getFrameData(); |
| 288 | |
| 289 | ShadowMapPass shadowMapPass; |
| 290 | ReflectionMapPass reflectionMapPass; |
| 291 | ZPrePassPass zPrePassPass; |
| 292 | SSAOMapPass ssaoMapPass; |
| 293 | DepthMapPass depthMapPass; |
| 294 | DepthMapPass depthMapPassMS; |
| 295 | ScreenMapPass screenMapPass; |
| 296 | ScreenReflectionPass reflectionPass; |
| 297 | Item2DPass item2DPass; |
| 298 | SkyboxPass skyboxPass; |
| 299 | SkyboxCubeMapPass skyboxCubeMapPass; |
| 300 | static constexpr size_t USERPASSES = 2; // See QSSGRenderLayer::RenderExtensionMode::Count |
| 301 | UserPass userPasses[USERPASSES]; |
| 302 | OpaquePass opaquePass; |
| 303 | TransparentPass transparentPass; |
| 304 | OITRenderPass oitRenderPass; |
| 305 | OITCompositePass oitCompositePass; |
| 306 | InfiniteGridPass infiniteGridPass; |
| 307 | DebugDrawPass debugDrawPass; |
| 308 | |
| 309 | // Built-in passes |
| 310 | QVarLengthArray<QSSGRenderPass *, 16> activePasses; |
| 311 | |
| 312 | QSSGRenderLayer &layer; |
| 313 | QSSGRenderer *renderer = nullptr; |
| 314 | // List of nodes we can render, not all may be active. Found by doing a depth-first |
| 315 | // search through m_FirstChild if length is zero. |
| 316 | |
| 317 | using LayerNodes = std::vector<QSSGRenderNode *>; |
| 318 | QSSGGlobalRenderNodeData::LayerNodeView layerNodes; |
| 319 | LayerNodes layerNodesCategorized; |
| 320 | |
| 321 | // renderableNodes have all lights, but properties configured for specific node |
| 322 | RenderableNodeEntries renderableModels; |
| 323 | RenderableNodeEntries renderableParticles; |
| 324 | |
| 325 | // Views into the collected nodes (unsorted) |
| 326 | QSSGModelsView modelsView; |
| 327 | QSSGParticlesView particlesView; |
| 328 | QSSGItem2DsView item2DsView; |
| 329 | QSSGCamerasView camerasView; |
| 330 | QSSGLightsView lightsView; |
| 331 | QSSGReflectionProbesView reflectionProbesView; |
| 332 | QSSGNonCategorizedView nonCategorizedView; |
| 333 | |
| 334 | // Results of prepare for render. |
| 335 | QSSGRenderCameraList renderedCameras; // multiple items with multiview, one otherwise (or zero if no cameras at all) |
| 336 | QSSGShaderLightList globalLights; // All non-scoped lights |
| 337 | |
| 338 | QVector<QSSGBakedLightingModel> bakedLightingModels; |
| 339 | // Sorted lists of the rendered objects. There may be other transforms applied so |
| 340 | // it is simplest to duplicate the lists. |
| 341 | QVector<QSSGBakedLightingModel> renderedBakedLightingModels; |
| 342 | RenderableItem2DEntries renderedItem2Ds; |
| 343 | // Temporary look-up map for Item2D data (for use in prepareItem2DsForRender()). |
| 344 | QSSGRenderer::Item2DDataMap item2DDataMap; |
| 345 | QPointer<QSGRenderContext> item2DRenderContext; |
| 346 | |
| 347 | QSSGLayerRenderPreparationResult layerPrepResult; |
| 348 | std::optional<QSSGRenderCameraDataList> renderedCameraData; |
| 349 | |
| 350 | TModelContextPtrList modelContexts; |
| 351 | |
| 352 | |
| 353 | bool tooManyLightsWarningShown = false; |
| 354 | bool tooManyShadowLightsWarningShown = false; |
| 355 | bool oitWarningUnsupportedShown = false; |
| 356 | bool oitWarningInvalidBlendModeShown = false; |
| 357 | bool orderIndependentTransparencyEnabled = false; |
| 358 | |
| 359 | std::unique_ptr<QSSGLightmapBaker> lightmapBaker = nullptr; |
| 360 | |
| 361 | QSSGShaderFeatures getShaderFeatures() const { return features; } |
| 362 | QSSGRhiGraphicsPipelineState getPipelineState() const { return ps; } |
| 363 | |
| 364 | void initializeLightmapBaking(QSSGLightmapBaker::Context &ctx); |
| 365 | void maybeProcessLightmapBaking(); |
| 366 | |
| 367 | [[nodiscard]] QSSGRenderGraphObject *getCamera(QSSGCameraId id) const; |
| 368 | [[nodiscard]] QSSGRenderCamera *activeCamera() const { return !renderedCameras.isEmpty() ? renderedCameras[0] : nullptr; } |
| 369 | |
| 370 | [[nodiscard]] QSSGRenderCameraData getCameraRenderData(const QSSGRenderCamera *camera); |
| 371 | [[nodiscard]] QSSGRenderCameraData getCameraRenderData(const QSSGRenderCamera *camera) const; |
| 372 | |
| 373 | void setLightmapTexture(const QSSGModelContext &modelContext, QRhiTexture *lightmapTexture); |
| 374 | [[nodiscard]] QRhiTexture *getLightmapTexture(const QSSGModelContext &modelContext) const; |
| 375 | |
| 376 | void setBonemapTexture(const QSSGModelContext &modelContext, QRhiTexture *bonemapTexture); |
| 377 | [[nodiscard]] QRhiTexture *getBonemapTexture(const QSSGModelContext &modelContext) const; |
| 378 | |
| 379 | [[nodiscard]] QSSGRenderContextInterface *contextInterface() const; |
| 380 | // Note: temp. API to report the state of the z-prepass step |
| 381 | [[nodiscard]] bool isZPrePassActive() const { return zPrePassActive; } |
| 382 | void setZPrePassPrepResult(bool res) { zPrePassActive = res; } |
| 383 | |
| 384 | // Exposed as const, as we often need to use this to look-up values from a specific key. |
| 385 | [[nodiscard]] const QSSGShaderDefaultMaterialKeyProperties &getDefaultMaterialPropertyTable() const |
| 386 | { |
| 387 | return defaultMaterialShaderKeyProperties; |
| 388 | } |
| 389 | |
| 390 | struct GlobalRenderProperties |
| 391 | { |
| 392 | bool isYUpInFramebuffer = true; |
| 393 | bool isYUpInNDC = true; |
| 394 | bool isClipDepthZeroToOne = true; |
| 395 | }; |
| 396 | |
| 397 | [[nodiscard]] static GlobalRenderProperties globalRenderProperties(const QSSGRenderContextInterface &ctx); |
| 398 | |
| 399 | // Temp. API. Ideally there shouldn't be a reason for anyone to hold onto these, |
| 400 | // but we follow the existing pattern for now. |
| 401 | const QSSGRenderShadowMapPtr &requestShadowMapManager(); |
| 402 | const QSSGRenderReflectionMapPtr &requestReflectionMapManager(); |
| 403 | const QSSGRenderShadowMapPtr &getShadowMapManager() const { return shadowMapManager; } |
| 404 | const QSSGRenderReflectionMapPtr &getReflectionMapManager() const { return reflectionMapManager; } |
| 405 | |
| 406 | QSSGOITRenderContext &getOitRenderContext() { return oitRenderContext; } |
| 407 | |
| 408 | static bool prepareInstancing(QSSGRhiContext *rhiCtx, |
| 409 | QSSGSubsetRenderable *renderable, |
| 410 | const QVector3D &cameraDirection, |
| 411 | const QVector3D &cameraPosition, |
| 412 | float minThreshold, |
| 413 | float maxThreshold); |
| 414 | |
| 415 | [[nodiscard]] QSSGRhiRenderableTexture *getRenderResult(QSSGFrameData::RenderResult id) { return &renderResults[size_t(id)]; } |
| 416 | [[nodiscard]] const QSSGRhiRenderableTexture *getRenderResult(QSSGFrameData::RenderResult id) const { return &renderResults[size_t(id)]; } |
| 417 | [[nodiscard]] static inline const std::unique_ptr<QSSGPerFrameAllocator> &perFrameAllocator(QSSGRenderContextInterface &ctx); |
| 418 | [[nodiscard]] static inline QSSGLayerRenderData *getCurrent(const QSSGRenderer &renderer) { return renderer.m_currentLayer; } |
| 419 | void saveRenderState(const QSSGRenderer &renderer); |
| 420 | void restoreRenderState(QSSGRenderer &renderer); |
| 421 | |
| 422 | static void setTonemapFeatures(QSSGShaderFeatures &features, QSSGRenderLayer::TonemapMode tonemapMode) |
| 423 | { |
| 424 | features.set(feature: QSSGShaderFeatures::Feature::LinearTonemapping, |
| 425 | val: tonemapMode == QSSGRenderLayer::TonemapMode::Linear); |
| 426 | features.set(feature: QSSGShaderFeatures::Feature::AcesTonemapping, |
| 427 | val: tonemapMode == QSSGRenderLayer::TonemapMode::Aces); |
| 428 | features.set(feature: QSSGShaderFeatures::Feature::HejlDawsonTonemapping, |
| 429 | val: tonemapMode == QSSGRenderLayer::TonemapMode::HejlDawson); |
| 430 | features.set(feature: QSSGShaderFeatures::Feature::FilmicTonemapping, |
| 431 | val: tonemapMode == QSSGRenderLayer::TonemapMode::Filmic); |
| 432 | features.set(feature: QSSGShaderFeatures::Feature::ForceIblExposure, |
| 433 | val: tonemapMode == QSSGRenderLayer::TonemapMode::Custom); |
| 434 | } |
| 435 | |
| 436 | QSSGPrepContextId getOrCreateExtensionContext(const QSSGRenderExtension &ext, |
| 437 | QSSGRenderCamera *camera = nullptr, |
| 438 | quint32 slot = 0); |
| 439 | |
| 440 | // Model API |
| 441 | QSSGRenderablesId createRenderables(QSSGPrepContextId prepId, const QList<QSSGNodeId> &nodes, QSSGRenderHelpers::CreateFlags createFlags); |
| 442 | void setGlobalTransform(QSSGRenderablesId renderablesId, const QSSGRenderModel &model, const QMatrix4x4 &mvp); |
| 443 | QMatrix4x4 getGlobalTransform(QSSGPrepContextId prepId, const QSSGRenderModel &model); |
| 444 | void setGlobalOpacity(QSSGRenderablesId renderablesId, const QSSGRenderModel &model, float opacity); |
| 445 | float getGlobalOpacity(QSSGPrepContextId prepId, const QSSGRenderModel &model); |
| 446 | [[nodiscard]] QMatrix4x4 getModelMvps(QSSGPrepContextId prepId, const QSSGRenderModel &model) const; |
| 447 | void setModelMaterials(QSSGRenderablesId renderablesId, const QSSGRenderModel &model, const QList<QSSGResourceId> &materials); |
| 448 | void setModelMaterials(const QSSGRenderablesId renderablesId, const QList<QSSGResourceId> &materials); |
| 449 | [[nodiscard]] QSSGPrepResultId prepareModelsForRender(QSSGRenderContextInterface &contextInterface, |
| 450 | QSSGPrepContextId prepId, |
| 451 | QSSGRenderablesId renderablesId, |
| 452 | float lodThreshold); |
| 453 | |
| 454 | // Convenience wrappers for getting values from the node, model store. |
| 455 | [[nodiscard]] QMatrix4x4 getGlobalTransform(QSSGRenderNodeHandle h, QMatrix4x4 defaultValue) const; |
| 456 | [[nodiscard]] QMatrix4x4 getGlobalTransform(QSSGRenderNodeHandle h) const; |
| 457 | [[nodiscard]] QMatrix4x4 getGlobalTransform(const QSSGRenderNode &node) const; |
| 458 | |
| 459 | [[nodiscard]] QMatrix3x3 getNormalMatrix(QSSGRenderModelHandle h) const; |
| 460 | [[nodiscard]] QMatrix3x3 getNormalMatrix(const QSSGRenderModel &model) const; |
| 461 | |
| 462 | [[nodiscard]] ModelViewProjections getModelMvps(QSSGRenderModelHandle h) const; |
| 463 | [[nodiscard]] ModelViewProjections getModelMvps(const QSSGRenderModel &model) const; |
| 464 | |
| 465 | [[nodiscard]] InstanceTransforms getInstanceTransforms(QSSGRenderNodeHandle h) const; |
| 466 | [[nodiscard]] InstanceTransforms getInstanceTransforms(const QSSGRenderNode &node) const; |
| 467 | |
| 468 | [[nodiscard]] float getGlobalOpacity(QSSGRenderNodeHandle h, float defaultValue = 1.0f) const; |
| 469 | [[nodiscard]] float getGlobalOpacity(const QSSGRenderNode &node) const; |
| 470 | |
| 471 | // |
| 472 | void prepareRenderables(QSSGRenderContextInterface &ctx, |
| 473 | QSSGPrepResultId prepId, |
| 474 | QRhiRenderPassDescriptor *renderPassDescriptor, |
| 475 | const QSSGRhiGraphicsPipelineState &ps, |
| 476 | QSSGRenderablesFilters filter); |
| 477 | void renderRenderables(QSSGRenderContextInterface &ctx, |
| 478 | QSSGPrepResultId prepId); |
| 479 | |
| 480 | static bool calculateGlobalVariables(QSSGRenderNode &node, |
| 481 | std::vector<QMatrix4x4> &globalTransforms, |
| 482 | std::vector<float> &globalOpacities); |
| 483 | |
| 484 | QSSGRenderCameraData getCameraDataImpl(const QSSGRenderCamera *camera) const; |
| 485 | |
| 486 | private: |
| 487 | friend class QSSGRenderer; |
| 488 | friend class QSSGRendererPrivate; |
| 489 | friend class QSSGFrameData; |
| 490 | friend class QSSGModelHelpers; |
| 491 | friend class QSSGRenderHelpers; |
| 492 | |
| 493 | class ExtensionContext |
| 494 | { |
| 495 | public: |
| 496 | explicit ExtensionContext() = default; |
| 497 | explicit ExtensionContext(const QSSGRenderExtension &ownerExt, QSSGRenderCamera *cam, size_t idx, quint32 slot) |
| 498 | : owner(&ownerExt), camera(cam), ps{}, filter{0}, index(idx), slot(slot) |
| 499 | { } |
| 500 | const QSSGRenderExtension *owner = nullptr; |
| 501 | QSSGRenderCamera *camera = nullptr; |
| 502 | QSSGRhiGraphicsPipelineState ps[3] {}; |
| 503 | QSSGRenderablesFilters filter { 0 }; |
| 504 | size_t index = 0; // index into the model store |
| 505 | quint32 slot = 0; |
| 506 | }; |
| 507 | |
| 508 | std::vector<ExtensionContext> extContexts { ExtensionContext{ /* 0 - Always available */ } }; |
| 509 | std::vector<RenderableNodeEntries> renderableModelStore { RenderableNodeEntries{ /* 0 - Always available */ } }; |
| 510 | std::vector<TModelContextPtrList> modelContextStore { TModelContextPtrList{ /* 0 - Always available */ }}; |
| 511 | std::vector<QSSGRenderableObjectList> renderableObjectStore { QSSGRenderableObjectList{ /* 0 - Always available */ }}; |
| 512 | std::vector<QSSGRenderableObjectList> opaqueObjectStore { QSSGRenderableObjectList{ /* 0 - Always available */ }}; |
| 513 | std::vector<QSSGRenderableObjectList> transparentObjectStore { QSSGRenderableObjectList{ /* 0 - Always available */ }}; |
| 514 | std::vector<QSSGRenderableObjectList> screenTextureObjectStore { QSSGRenderableObjectList{ /* 0 - Always available */ }}; |
| 515 | |
| 516 | std::shared_ptr<QSSGGlobalRenderNodeData> nodeData; |
| 517 | std::unique_ptr<QSSGRenderModelData> modelData; |
| 518 | |
| 519 | // Soreted cache (per camera and extension) |
| 520 | using PerCameraCache = std::unordered_map<const QSSGRenderCamera *, QSSGRenderableObjectList>; |
| 521 | std::vector<PerCameraCache> sortedOpaqueObjectCache { PerCameraCache{ /* 0 - Always available */ } }; |
| 522 | std::vector<PerCameraCache> sortedTransparentObjectCache { PerCameraCache{ /* 0 - Always available */ } }; |
| 523 | std::vector<PerCameraCache> sortedScreenTextureObjectCache { PerCameraCache{ /* 0 - Always available */ } }; |
| 524 | std::vector<PerCameraCache> sortedOpaqueDepthPrepassCache { PerCameraCache{ /* 0 - Always available */ } }; |
| 525 | std::vector<PerCameraCache> sortedDepthWriteCache { PerCameraCache{ /* 0 - Always available */ } }; |
| 526 | |
| 527 | [[nodiscard]] const QSSGRenderCameraDataList &getCachedCameraDatas(); |
| 528 | void ensureCachedCameraDatas(); |
| 529 | void updateSortedDepthObjectsListImp(const QSSGRenderCamera &camera, size_t index); |
| 530 | |
| 531 | |
| 532 | QSSGDefaultMaterialPreparationResult prepareDefaultMaterialForRender(QSSGRenderDefaultMaterial &inMaterial, |
| 533 | QSSGRenderableObjectFlags &inExistingFlags, |
| 534 | float inOpacity, |
| 535 | const QSSGShaderLightListView &lights, |
| 536 | QSSGLayerRenderPreparationResultFlags &ioFlags); |
| 537 | |
| 538 | QSSGDefaultMaterialPreparationResult prepareCustomMaterialForRender(QSSGRenderCustomMaterial &inMaterial, |
| 539 | QSSGRenderableObjectFlags &inExistingFlags, |
| 540 | float inOpacity, bool alreadyDirty, |
| 541 | const QSSGShaderLightListView &lights, |
| 542 | QSSGLayerRenderPreparationResultFlags &ioFlags); |
| 543 | |
| 544 | static void prepareModelMaterials(RenderableNodeEntries &renderableModels, bool cullUnrenderables); |
| 545 | static void prepareModelMaterials(const RenderableNodeEntries::ConstIterator &begin, |
| 546 | const RenderableNodeEntries::ConstIterator &end); |
| 547 | |
| 548 | // Persistent data |
| 549 | QHash<QSSGShaderMapKey, QSSGRhiShaderPipelinePtr> shaderMap; |
| 550 | |
| 551 | // Cached buffer. |
| 552 | QByteArray generatedShaderString; |
| 553 | |
| 554 | // Saved render state (for sublayers) |
| 555 | struct SavedRenderState |
| 556 | { |
| 557 | QRect viewport; |
| 558 | QRect scissorRect; |
| 559 | float dpr = 1.0; |
| 560 | }; |
| 561 | |
| 562 | std::optional<SavedRenderState> savedRenderState; |
| 563 | |
| 564 | // Note: Re-used to avoid expensive initialization. |
| 565 | // - Should be revisit, as we can do better. |
| 566 | QSSGShaderDefaultMaterialKeyProperties defaultMaterialShaderKeyProperties; |
| 567 | QSSGFrameData frameData; |
| 568 | QSSGRhiGraphicsPipelineState ps; // Base pipleline state |
| 569 | QSSGShaderFeatures features; // Base feature set |
| 570 | quint32 version = 0; |
| 571 | bool particlesEnabled = true; |
| 572 | bool hasDepthWriteObjects = false; |
| 573 | bool zPrePassActive = false; |
| 574 | // NOTE: For the time being we need to keep track of extensions modifying the renderables |
| 575 | // because then we need to reset the lists. |
| 576 | // FIXME: This should be revisited, as we can do better (hence the verbose name). |
| 577 | bool renderablesModifiedByExtension = false; |
| 578 | enum class DepthPrepassObject : quint8 |
| 579 | { |
| 580 | None = 0x0, |
| 581 | ScreenTexture = 0x1, |
| 582 | Transparent = 0x2, |
| 583 | Opaque = 0x4 |
| 584 | }; |
| 585 | using DepthPrepassObjectStateT = std::underlying_type_t<DepthPrepassObject>; |
| 586 | DepthPrepassObjectStateT depthPrepassObjectsState { DepthPrepassObjectStateT(DepthPrepassObject::None) }; |
| 587 | QSSGRenderShadowMapPtr shadowMapManager; |
| 588 | QSSGRenderReflectionMapPtr reflectionMapManager; |
| 589 | QHash<const QSSGModelContext *, QRhiTexture *> lightmapTextures; |
| 590 | QHash<const QSSGModelContext *, QRhiTexture *> bonemapTextures; |
| 591 | QSSGRhiRenderableTexture renderResults[6] {}; |
| 592 | QSSGOITRenderContext oitRenderContext; |
| 593 | }; |
| 594 | |
| 595 | QT_END_NAMESPACE |
| 596 | |
| 597 | #endif // QSSG_LAYER_RENDER_DATA_H |
| 598 | |
| 599 | |