diff --git a/Source/Editor/Utilities/ViewportIconsRenderer.cpp b/Source/Editor/Utilities/ViewportIconsRenderer.cpp index dcdc99cd6..7687a635a 100644 --- a/Source/Editor/Utilities/ViewportIconsRenderer.cpp +++ b/Source/Editor/Utilities/ViewportIconsRenderer.cpp @@ -130,8 +130,6 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Scene const BoundingFrustum frustum = view.Frustum; const auto& icons = scene->GetSceneRendering()->ViewportIcons; Matrix m1, m2, world; - GeometryDrawStateData drawState; - draw.DrawState = &drawState; draw.World = &world; AssetReference texture; for (Actor* icon : icons) @@ -211,10 +209,6 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor Matrix::Billboard(sphere.Center, view.Position, Vector3::Up, view.Direction, m2); Matrix::Multiply(m1, m2, world); - // Draw icon - GeometryDrawStateData drawState; - draw.DrawState = &drawState; - // Support custom icons through types, but not ones that were added through actors, since they cant register while in prefab view anyway if (ActorTypeToTexture.TryGet(actor->GetTypeHandle(), texture)) { @@ -227,9 +221,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor draw.Buffer->At(0).ReceiveDecals = false; draw.Buffer->At(0).ShadowsMode = ShadowsCastingMode::None; } - AssetReference material; - if (!TextureToMaterial.TryGet(texture, material)) { // Create custom material per custom texture @@ -237,7 +229,6 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor TextureToMaterial[texture]->SetParameterValue(TEXT("Image"), Variant(texture)); material = TextureToMaterial[texture]; } - draw.Buffer->At(0).Material = material; } else @@ -246,6 +237,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor draw.Buffer = &InstanceBuffers[static_cast(iconType)]; } + // Draw icon draw.World = &world; draw.Bounds = sphere; QuadModel->Draw(renderContext, draw); diff --git a/Source/Engine/Core/Collections/Array.h b/Source/Engine/Core/Collections/Array.h index dff1e4c6a..a852d63d6 100644 --- a/Source/Engine/Core/Collections/Array.h +++ b/Source/Engine/Core/Collections/Array.h @@ -228,7 +228,7 @@ public: /// /// The index. /// true if is valid a index; otherwise, false. - bool IsValidIndex(const int32 index) const + FORCE_INLINE bool IsValidIndex(const int32 index) const { return index < _count && index >= 0; } diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp index 7c091d5a6..b3dcb27b1 100644 --- a/Source/Engine/Foliage/Foliage.cpp +++ b/Source/Engine/Foliage/Foliage.cpp @@ -356,8 +356,6 @@ void Foliage::DrawCluster(DrawContext& context, FoliageCluster* cluster, Mesh::D Matrix::Transformation(transform.Scale, transform.Orientation, translation, world); // Disable motion blur - GeometryDrawStateData drawState; - drawState.PrevWorld = world; instance.DrawState.PrevWorld = world; // Draw model @@ -365,7 +363,6 @@ void Foliage::DrawCluster(DrawContext& context, FoliageCluster* cluster, Mesh::D draw.LightmapUVs = &instance.Lightmap.UVsArea; draw.Buffer = &type.Entries; draw.World = &world; - draw.DrawState = &drawState; draw.Bounds = sphere; draw.PerInstanceRandom = instance.Random; draw.DrawModes = type._drawModes; @@ -1290,15 +1287,12 @@ void Foliage::Draw(RenderContext& renderContext) Matrix world; const Transform transform = _transform.LocalToWorld(instance.Transform); renderContext.View.GetWorldMatrix(transform, world); - GeometryDrawStateData drawState; - drawState.PrevWorld = world; Mesh::DrawInfo draw; draw.Flags = GetStaticFlags(); draw.Lightmap = _scene ? _scene->LightmapsData.GetReadyLightmap(instance.LightmapTextureIndex) : nullptr; draw.LightmapUVs = &instance.LightmapUVsArea; draw.Buffer = &type.Entries; draw.World = &world; - draw.DrawState = &drawState; draw.Bounds = instance.Bounds; draw.PerInstanceRandom = instance.Random; draw.DrawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode); diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp index 7f461b8c2..28b73a28f 100644 --- a/Source/Engine/Graphics/Models/Mesh.cpp +++ b/Source/Engine/Graphics/Models/Mesh.cpp @@ -302,7 +302,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition? drawCall.Surface.GeometrySize = _box.GetSize(); - drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; + drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World; drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr; drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Half4::Zero; drawCall.Surface.LODDitherFactor = (int8)(lodDitherFactor * 127); @@ -365,7 +365,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition? drawCall.Surface.GeometrySize = _box.GetSize(); - drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; + drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World; drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr; drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Half4::Zero; drawCall.Surface.LODDitherFactor = (int8)(lodDitherFactor * 127); diff --git a/Source/Engine/Graphics/Models/MeshBase.h b/Source/Engine/Graphics/Models/MeshBase.h index f0f261cfa..4b61eb470 100644 --- a/Source/Engine/Graphics/Models/MeshBase.h +++ b/Source/Engine/Graphics/Models/MeshBase.h @@ -14,7 +14,7 @@ #include "CollisionProxy.h" #endif -struct GeometryDrawStateData; +struct GeometryDrawState; struct RenderContext; struct RenderContextBatch; class Task; @@ -347,9 +347,9 @@ public: Matrix* World; /// - /// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating. + /// The instance drawing state data container (optional). Used for LOD transition handling and previous world transformation matrix updating. /// - GeometryDrawStateData* DrawState; + GeometryDrawState* DrawState; /// /// The instance deformation utility. diff --git a/Source/Engine/Graphics/Models/ModelDraw.h b/Source/Engine/Graphics/Models/ModelDraw.h index 2867499f3..6e4e28145 100644 --- a/Source/Engine/Graphics/Models/ModelDraw.h +++ b/Source/Engine/Graphics/Models/ModelDraw.h @@ -31,6 +31,18 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext return; if (!info.Buffer->IsValidFor(model)) info.Buffer->Setup(model); + if (!info.DrawState || renderContext.View.IsSingleFrame) + { + // No LOD transition + int32 lodIndex = info.ForcedLOD != -1 ? info.ForcedLOD : RenderTools::ComputeModelLOD(model, info.Bounds.Center, (float)info.Bounds.Radius, renderContext); + if (lodIndex != -1) + { + lodIndex += info.LODBias + renderContext.View.ModelLODBias; + lodIndex = model->ClampLODIndex(lodIndex); + model->LODs.Get()[lodIndex].Draw(context, info, 0.0f); + } + return; + } const auto frame = Engine::FrameCount; const auto modelFrame = info.DrawState->PrevFrame + 1; @@ -46,7 +58,7 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext if (lodIndex == -1) { // Handling model fade-out transition - if (modelFrame == frame && info.DrawState->PrevLOD != -1 && !renderContext.View.IsSingleFrame && ModelDrawTransition(model, info)) + if (modelFrame == frame && info.DrawState->PrevLOD != -1 && ModelDrawTransition(model, info)) { // Check if start transition if (info.DrawState->LODTransition == 255) @@ -75,11 +87,8 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext lodIndex += info.LODBias + renderContext.View.ModelLODBias; lodIndex = model->ClampLODIndex(lodIndex); - if (renderContext.View.IsSingleFrame) - { - } // Check if it's the new frame and could update the drawing state (note: model instance could be rendered many times per frame to different viewports) - else if (modelFrame == frame) + if (modelFrame == frame) { // Check if materials use transition if (!ModelDrawTransition(model, info)) @@ -111,7 +120,7 @@ FORCE_INLINE void ModelDraw(ModelType* model, const RenderContext& renderContext } // Draw - if (info.DrawState->PrevLOD == lodIndex || info.DrawState->LODTransition == 255 || renderContext.View.IsSingleFrame) + if (info.DrawState->PrevLOD == lodIndex || info.DrawState->LODTransition == 255) { model->LODs.Get()[lodIndex].Draw(context, info, 0.0f); } diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp index e953c0ac1..312a74f41 100644 --- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp +++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp @@ -377,7 +377,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info, drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition? drawCall.Surface.GeometrySize = _box.GetSize(); - drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; + drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World; drawCall.Surface.Skinning = info.WithPrevBones ? DrawCall::SkinningMode::WithPrevBones : DrawCall::SkinningMode::Active; drawCall.Surface.SkinningBones = info.SkinningBones; drawCall.Surface.SkinningBonesOffset = info.SkinningBonesOffset; @@ -422,7 +422,7 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectRadius = (float)info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition? drawCall.Surface.GeometrySize = _box.GetSize(); - drawCall.Surface.PrevWorld = info.DrawState->PrevWorld; + drawCall.Surface.PrevWorld = info.DrawState ? info.DrawState->PrevWorld : drawCall.World; drawCall.Surface.Skinning = info.WithPrevBones ? DrawCall::SkinningMode::WithPrevBones : DrawCall::SkinningMode::Active; drawCall.Surface.SkinningBones = info.SkinningBones; drawCall.Surface.SkinningBonesOffset = info.SkinningBonesOffset; diff --git a/Source/Engine/Graphics/RenderBuffers.cpp b/Source/Engine/Graphics/RenderBuffers.cpp index b1eefd1ec..3e0422d24 100644 --- a/Source/Engine/Graphics/RenderBuffers.cpp +++ b/Source/Engine/Graphics/RenderBuffers.cpp @@ -304,3 +304,66 @@ RenderBuffers::ReadOnlyDepthBuffer RenderBuffers::GetReadOnlyDepthBuffer() const GPUTextureView* depthBufferSRV = depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View(); return { depthBufferRTV, depthBufferSRV }; } + +void RenderBuffers::OnSceneRendering(SceneRendering* scene) +{ + if (!Scenes.ContainsKey(scene)) + { + PROFILE_CPU_NAMED("Init Scene"); + + // Register scene + auto& sceneData = Scenes[scene]; + ListenSceneRendering(scene); + + // Put all existing actors into the render buffer geo storage used for LOD transitions, etc. + for (int32 i = 0; i < SceneRendering::MAX; i++) + { + auto& list = scene->Actors[i]; + auto& geo = sceneData.Geo[i]; + geo.Resize(list.Count()); + auto geoPtr = geo.Get(); + for (int32 j = 0; j < list.Count(); j++) + geoPtr[j] = GeometryDrawState(); + } + } +} + +GeometryDrawState* RenderBuffers::GetGeometryDrawState(SceneRendering* scene, int32 key, const Actor* actor) const +{ + if (auto* sceneData = Scenes.TryGet(scene)) + { + auto& list = sceneData->Geo[actor->_drawCategory]; + if (list.IsValidIndex(key)) + { + return list.Get() + key; + } + } + // TODO: what about loose actors drawn from code? dynamically manage their state here? + return nullptr; +} + +void RenderBuffers::OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) +{ + // Init geo state of that object + if (auto* sceneData = Scenes.TryGet(scene)) + { + auto& list = sceneData->Geo[a->_drawCategory]; + ASSERT(key >= 0); + if (list.Count() <= key) + list.Resize(key + 1); + list.Get()[key] = GeometryDrawState(); + } +} + +void RenderBuffers::OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) +{ +} + +void RenderBuffers::OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) +{ +} + +void RenderBuffers::OnSceneRenderingClear(SceneRendering* scene) +{ + Scenes.Remove(scene); +} diff --git a/Source/Engine/Graphics/RenderBuffers.h b/Source/Engine/Graphics/RenderBuffers.h index 57eb9e372..2b4cd9bb3 100644 --- a/Source/Engine/Graphics/RenderBuffers.h +++ b/Source/Engine/Graphics/RenderBuffers.h @@ -4,8 +4,11 @@ #include "Engine/Core/Math/Viewport.h" #include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Scripting/ScriptingObject.h" #include "Engine/Graphics/Textures/GPUTexture.h" +#include "Engine/Level/Scene/SceneRendering.h" +#include "Engine/Renderer/DrawCall.h" // GBuffer render targets formats #define GBUFFER0_FORMAT PixelFormat::R8G8B8A8_UNorm @@ -24,10 +27,13 @@ // [7] | #define STENCIL_BUFFER_OBJECT_LAYER(value) uint8(value & 0x1f) +class Actor; +class SceneRendering; + /// /// The scene rendering buffers container. /// -API_CLASS() class FLAXENGINE_API RenderBuffers : public ScriptingObject +API_CLASS() class FLAXENGINE_API RenderBuffers : public ScriptingObject, private ISceneRenderingListener { DECLARE_SCRIPTING_TYPE(RenderBuffers); @@ -114,6 +120,14 @@ public: // Maps the custom buffer type into the object that holds the state. Array CustomBuffers; + // Scene drawing cache with the per-object state (eg. LOD transitions, motion-vectors movement) + struct SceneData + { + // Per-object drawing state (eg. LOD transition). Indexing matches actor/object key of object registered in SceneRendering. + Array Geo[SceneRendering::DrawCategory::MAX]; + }; + Dictionary Scenes; + public: /// /// Finalizes an instance of the class. @@ -268,4 +282,19 @@ public: /// Gets the depth buffer binding for rendering as read-only (both shader resource and render target). /// ReadOnlyDepthBuffer GetReadOnlyDepthBuffer() const; + + // Internal event called by SceneRendering to initiate drawing. + void OnSceneRendering(SceneRendering* scene); + + /// + /// Gets the geometry drawing state container for a specific actor/object. Returns null for invalid object (-1) or when view is not using LOD transitions (single-shot frame). + /// + GeometryDrawState* GetGeometryDrawState(SceneRendering* scene, int32 key, const Actor* actor) const; + +public: + // [ISceneRenderingListener] + void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override; + void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override; + void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override; + void OnSceneRenderingClear(SceneRendering* scene) override; }; diff --git a/Source/Engine/Graphics/RenderTask.h b/Source/Engine/Graphics/RenderTask.h index eaf9be635..770d59a2e 100644 --- a/Source/Engine/Graphics/RenderTask.h +++ b/Source/Engine/Graphics/RenderTask.h @@ -468,12 +468,12 @@ API_STRUCT(NoDefault) struct FLAXENGINE_API RenderContext DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContext); /// - /// The render buffers. + /// The render buffers that contain drawing state (eg. LOD transitions) and scene buffers (eg. GBuffer, DDGI, Shadow Maps). /// API_FIELD() RenderBuffers* Buffers = nullptr; /// - /// The render list. + /// The render list that collects draw calls. /// API_FIELD() RenderList* List = nullptr; diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index 62a032312..79944fb51 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -32,6 +32,7 @@ API_CLASS(Abstract) class FLAXENGINE_API Actor : public SceneObject friend SceneRendering; friend Prefab; friend PrefabInstanceData; + friend class RenderBuffers; protected: uint16 _isActive : 1; uint16 _isActiveInHierarchy : 1; @@ -48,7 +49,7 @@ protected: BoundingBox _box; String _name; Scene* _scene; - PhysicsScene* _physicsScene; + PhysicsScene* _physicsScene; // TODO: move it into physics-related actors (coliders, rigidbodies, etc.) private: // Disable copying diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 47e67f8fd..c17d883af 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -16,8 +16,10 @@ #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUPass.h" #include "Engine/Graphics/RenderTask.h" +#include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/Models/MeshAccessor.h" #include "Engine/Graphics/Models/MeshDeformation.h" +#include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Level/Scene/Scene.h" #include "Engine/Level/SceneObjectsFactory.h" @@ -1256,8 +1258,9 @@ void AnimatedModel::Draw(RenderContext& renderContext) return; if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas) return; // Not supported + auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this); ACTOR_GET_WORLD_MATRIX(this, view, world); - GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world); _lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition)); if (_bones.IsAllocated) @@ -1281,7 +1284,7 @@ void AnimatedModel::Draw(RenderContext& renderContext) } } draw.World = &world; - draw.DrawState = &_drawState; + draw.DrawState = drawState; draw.Deformation = _deformation; PRAGMA_DISABLE_DEPRECATION_WARNINGS draw.DrawModes = DrawModes & renderContext.View.GetShadowsDrawPassMask(ShadowsMode); @@ -1297,7 +1300,7 @@ void AnimatedModel::Draw(RenderContext& renderContext) SkinnedModel->Draw(renderContext, draw); } - GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_END(drawState, world); } void AnimatedModel::Draw(RenderContextBatch& renderContextBatch) @@ -1308,7 +1311,8 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch) Matrix world; const Float3 translation = _transform.Translation - renderContext.View.Origin; Matrix::Transformation(_transform.Scale, _transform.Orientation, translation, world); - GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world); + auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this); + GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world); _lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition)); if (_bones.IsAllocated) @@ -1332,7 +1336,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch) } } draw.World = &world; - draw.DrawState = &_drawState; + draw.DrawState = drawState; draw.Deformation = _deformation; draw.DrawModes = DrawModes; draw.Bounds = _sphere; @@ -1361,7 +1365,7 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch) PRAGMA_ENABLE_DEPRECATION_WARNINGS } - GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_END(drawState, world); } #if USE_EDITOR diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index f7d196f30..97cebde7c 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -5,7 +5,6 @@ #include "ModelInstanceActor.h" #include "Engine/Content/Assets/SkinnedModel.h" #include "Engine/Content/Assets/AnimationGraph.h" -#include "Engine/Renderer/DrawCall.h" #include "Engine/Core/Delegate.h" /// @@ -96,7 +95,6 @@ private: void Flush(); }; - GeometryDrawStateData _drawState; AnimationUpdateMode _actualMode; SkinnedBones _bones; uint32 _counter; diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index 76d02a8cb..6e3c939fe 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -366,11 +366,9 @@ void Camera::Draw(RenderContext& renderContext) renderContext.View.GetWorldMatrix(_transform, tmp); Matrix::RotationY(PI * -0.5f, rot); Matrix::Multiply(rot, tmp, world); - GeometryDrawStateData drawState; Mesh::DrawInfo draw; draw.Buffer = &_previewModelBuffer; draw.World = &world; - draw.DrawState = &drawState; draw.Flags = StaticFlags::Transform; draw.DrawModes = (DrawPass::Depth | DrawPass::GBuffer | DrawPass::Forward) & renderContext.View.Pass; BoundingSphere::FromBox(_previewModelBox, draw.Bounds); diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index 0ccb9c54c..a75d7b916 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -8,12 +8,14 @@ #include "Engine/Graphics/GPUBufferDescription.h" #include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPUDevice.h" +#include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/Models/MeshDeformation.h" #include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Level/Prefabs/PrefabManager.h" #include "Engine/Level/Scene/Scene.h" +#include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/GlobalSignDistanceFieldPass.h" #include "Engine/Renderer/GI/GlobalSurfaceAtlasPass.h" #include "Engine/Utilities/Encryption.h" @@ -380,15 +382,16 @@ void StaticModel::Draw(RenderContext& renderContext) GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox()); return; } + auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this); ACTOR_GET_WORLD_MATRIX(this, view, world); - GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world); if (_vertexColorsDirty) FlushVertexColors(); Mesh::DrawInfo draw; draw.Buffer = &Entries; draw.World = &world; - draw.DrawState = &_drawState; + draw.DrawState = drawState; draw.Deformation = _deformation; draw.Lightmap = _scene && Lightmap.TextureIndex != -1 ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr; draw.LightmapUVs = &Lightmap.UVsArea; @@ -409,7 +412,7 @@ void StaticModel::Draw(RenderContext& renderContext) Model->Draw(renderContext, draw); - GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_END(drawState, world); } void StaticModel::Draw(RenderContextBatch& renderContextBatch) @@ -417,15 +420,16 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch) if (!Model || !Model->IsLoaded()) return; const RenderContext& renderContext = renderContextBatch.GetMainContext(); + auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this); ACTOR_GET_WORLD_MATRIX(this, view, world); - GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world); if (_vertexColorsDirty) FlushVertexColors(); Mesh::DrawInfo draw; draw.Buffer = &Entries; draw.World = &world; - draw.DrawState = &_drawState; + draw.DrawState = drawState; draw.Deformation = _deformation; draw.Lightmap = _scene && Lightmap.TextureIndex != -1 ? _scene->LightmapsData.GetReadyLightmap(Lightmap.TextureIndex) : nullptr; draw.LightmapUVs = &Lightmap.UVsArea; @@ -446,7 +450,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch) Model->Draw(renderContextBatch, draw); - GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_END(drawState, world); } bool StaticModel::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h index 598b56118..d7e63144b 100644 --- a/Source/Engine/Level/Actors/StaticModel.h +++ b/Source/Engine/Level/Actors/StaticModel.h @@ -4,7 +4,6 @@ #include "ModelInstanceActor.h" #include "Engine/Content/Assets/Model.h" -#include "Engine/Renderer/DrawCall.h" #include "Engine/Renderer/Lightmaps.h" /// @@ -15,15 +14,14 @@ class FLAXENGINE_API StaticModel : public ModelInstanceActor, IAssetReference { DECLARE_SCENE_OBJECT(StaticModel); private: - GeometryDrawStateData _drawState; float _scaleInLightmap; float _boundsScale; + DrawPass _drawModes = DrawPass::Default; char _lodBias; char _forcedLod; bool _vertexColorsDirty; byte _vertexColorsCount; int8 _sortOrder; - DrawPass _drawModes = DrawPass::Default; Array _vertexColorsData[MODEL_MAX_LODS]; GPUBuffer* _vertexColorsBuffer[MODEL_MAX_LODS]; Model* _residencyChangedModel = nullptr; diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index 565f1f3ac..caf987bbb 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -1,11 +1,13 @@ // Copyright (c) Wojciech Figat. All rights reserved. +// Enable to put CPU profiler sections for each actor drawing to inspect slow actors draw issues #define SCENE_RENDERING_USE_PROFILER_PER_ACTOR 0 #include "SceneRendering.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Renderer/RenderList.h" +#include "Engine/Graphics/RenderBuffers.h" #include "Engine/Threading/JobSystem.h" #include "Engine/Physics/Actors/IPhysicsDebug.h" #include "Engine/Profiler/ProfilerCPU.h" @@ -38,6 +40,7 @@ void ISceneRenderingListener::ListenSceneRendering(SceneRendering* scene) { if (!_scenes.Contains(scene)) { + PROFILE_MEM(Graphics); _scenes.Add(scene); scene->_listeners.Add(this); } @@ -67,6 +70,8 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c // Register scene for (const auto& renderContext : renderContextBatch.Contexts) renderContext.List->Scenes.Add(this); + auto buffers = renderContextBatch.GetMainContext().Buffers; + buffers->OnSceneRendering(this); } else if (category == PostRender) { @@ -188,7 +193,7 @@ void SceneRendering::AddActor(Actor* a, int32& key) e.Bounds = a->GetSphere(); e.NoCulling = a->_drawNoCulling; for (auto* listener : _listeners) - listener->OnSceneRenderingAddActor(a); + listener->OnSceneRenderingAddActor(this, key, a); } void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::UpdateFlags flags) @@ -204,7 +209,7 @@ void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener:: if (e.Actor == a) { for (auto* listener : _listeners) - listener->OnSceneRenderingUpdateActor(a, e.Bounds, flags); + listener->OnSceneRenderingUpdateActor(this, key, a, e.Bounds, flags); if (flags & ISceneRenderingListener::Layer) e.LayerMask = a->GetLayerMask(); if (flags & ISceneRenderingListener::Bounds) @@ -227,7 +232,7 @@ void SceneRendering::RemoveActor(Actor* a, int32& key) if (e.Actor == a) { for (auto* listener : _listeners) - listener->OnSceneRenderingRemoveActor(a); + listener->OnSceneRenderingRemoveActor(this, key, a); e.Actor = nullptr; e.LayerMask = 0; FreeActors[category].Add(key); diff --git a/Source/Engine/Level/Scene/SceneRendering.h b/Source/Engine/Level/Scene/SceneRendering.h index 68dfa57db..51f71715a 100644 --- a/Source/Engine/Level/Scene/SceneRendering.h +++ b/Source/Engine/Level/Scene/SceneRendering.h @@ -51,22 +51,22 @@ public: // Actor properties that were modified. enum UpdateFlags { - Visual = 1, - Bounds = 2, - Layer = 4, - StaticFlags = 8, - AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked - DrawModes = 32, - Auto = Visual | Bounds | Layer, + Visual = 1, // Visual appearance of the object (eg. material changed). + Bounds = 2, // Object bounding volume was changed (eg. after scaling). + Layer = 4, // Object changed layer. + StaticFlags = 8, // Object changed static state. + AutoDelayDuringRendering = 16, // Conditionally allow updating data during rendering when writes are locked. + DrawModes = 32, // Object changed draw modes flags. + Auto = Visual | Bounds | Layer, // Default set of flags for common changes. }; // Starts listening to the scene rendering events. void ListenSceneRendering(SceneRendering* scene); // Events called by Scene Rendering - virtual void OnSceneRenderingAddActor(Actor* a) = 0; - virtual void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags = Auto) = 0; - virtual void OnSceneRenderingRemoveActor(Actor* a) = 0; + virtual void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) = 0; + virtual void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags = Auto) = 0; + virtual void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) = 0; virtual void OnSceneRenderingClear(SceneRendering* scene) = 0; }; diff --git a/Source/Engine/Renderer/DrawCall.h b/Source/Engine/Renderer/DrawCall.h index 8881715ef..1cce61aa0 100644 --- a/Source/Engine/Renderer/DrawCall.h +++ b/Source/Engine/Renderer/DrawCall.h @@ -322,7 +322,7 @@ struct TIsPODType /// Data container for meshes and skinned meshes rendering with minimal state caching. /// Used to update previous world transformation matrix for motion vectors pass and handle LOD transitions blending. /// -struct GeometryDrawStateData +struct GeometryDrawState { /// /// The previous frame world transformation matrix for the given geometry instance. @@ -347,23 +347,23 @@ struct GeometryDrawStateData }; template<> -struct TIsPODType +struct TIsPODType { enum { Value = true }; }; #define GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, worldMatrix) \ const auto frame = Engine::FrameCount; \ - if (drawState.PrevFrame + 1 < frame && !renderContext.View.IsSingleFrame) \ + if (drawState && drawState->PrevFrame + 1 < frame && !renderContext.View.IsSingleFrame) \ { \ - drawState.PrevWorld = worldMatrix; \ + drawState->PrevWorld = worldMatrix; \ } #define GEOMETRY_DRAW_STATE_EVENT_END(drawState, worldMatrix) \ - if (drawState.PrevFrame != frame && !renderContext.View.IsSingleFrame) \ + if (drawState && drawState->PrevFrame != frame && !renderContext.View.IsSingleFrame) \ { \ - drawState.PrevWorld = worldMatrix; \ - drawState.PrevFrame = frame; \ + drawState->PrevWorld = worldMatrix; \ + drawState->PrevFrame = frame; \ } #if USE_LARGE_WORLDS diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 114be3fdc..48bb9959c 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -716,11 +716,11 @@ public: } // [ISceneRenderingListener] - void OnSceneRenderingAddActor(Actor* a) override + void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override { } - void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override + void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override { GlobalSurfaceAtlasObject* object = Objects.TryGet(a); if (object) @@ -744,7 +744,7 @@ public: } } - void OnSceneRenderingRemoveActor(Actor* a) override + void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override { // TODO: use it to speed up atlas/buffers defragmentation when streaming out scenes (CompactObjects cleans up objects) } diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 155a58d6a..686cd732a 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -475,17 +475,17 @@ public: } // [ISceneRenderingListener] - void OnSceneRenderingAddActor(Actor* a) override + void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override { OnSceneRenderingDirty(a); } - void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override + void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override { OnSceneRenderingDirty(a, &prevBounds, flags); } - void OnSceneRenderingRemoveActor(Actor* a) override + void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override { OnSceneRenderingDirty(a); } diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index 957778e18..3a1389c1a 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -328,7 +328,7 @@ struct RenderListAlloc }; /// -/// Rendering cache container object for the draw calls collecting, sorting and executing. +/// Rendering cache container object for the draw calls collecting, sorting and executing. Reusable between frames or drawing tasks. /// API_CLASS(Sealed) class FLAXENGINE_API RenderList : public ScriptingObject { diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index f2c5edc03..4a260380a 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -409,13 +409,13 @@ public: } // [ISceneRenderingListener] - void OnSceneRenderingAddActor(Actor* a) override + void OnSceneRenderingAddActor(SceneRendering* scene, int32 key, Actor* a) override { if (a->HasStaticFlag(StaticFlags::Shadow)) DirtyStaticBounds(a->GetSphere()); } - void OnSceneRenderingUpdateActor(Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override + void OnSceneRenderingUpdateActor(SceneRendering* scene, int32 key, Actor* a, const BoundingSphere& prevBounds, UpdateFlags flags) override { // Dirty static objects to redraw when changed (eg. material modification) if (a->HasStaticFlag(StaticFlags::Shadow)) @@ -438,7 +438,7 @@ public: } } - void OnSceneRenderingRemoveActor(Actor* a) override + void OnSceneRenderingRemoveActor(SceneRendering* scene, int32 key, Actor* a) override { if (a->HasStaticFlag(StaticFlags::Shadow)) DirtyStaticBounds(a->GetSphere()); diff --git a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp index 0f3a2eca3..1a7d98312 100644 --- a/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp +++ b/Source/Engine/ShadowsOfMordor/Builder.Jobs.cpp @@ -5,6 +5,8 @@ #include "Engine/Core/Types/TimeSpan.h" #include "Engine/Engine/Engine.h" #include "Engine/Renderer/Renderer.h" +#include "Engine/Renderer/DrawCall.h" +#include "Engine/Renderer/Lightmaps.h" #include "Engine/Level/Scene/Lightmap.h" #include "Engine/Level/Actors/StaticModel.h" #include "Engine/Level/Actors/BoxBrush.h" diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index c2f6789c7..2a933f59d 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -7,7 +7,9 @@ #include "Engine/Graphics/Models/Types.h" #include "Engine/Graphics/RenderView.h" #include "Engine/Graphics/RenderTask.h" -#include "Engine/Level/Scene/SceneRendering.h" +#include "Engine/Graphics/RenderBuffers.h" +#include "Engine/Graphics/RenderTools.h" +#include "Engine/Graphics/Shaders/GPUVertexLayout.h" #include "Engine/Render2D/Font.h" #include "Engine/Render2D/FontAsset.h" #include "Engine/Render2D/FontManager.h" @@ -20,8 +22,8 @@ #include "Engine/Content/Content.h" #include "Engine/Content/Deprecated.h" #include "Engine/Core/Types/Variant.h" -#include "Engine/Graphics/RenderTools.h" -#include "Engine/Graphics/Shaders/GPUVertexLayout.h" +#include "Engine/Level/Scene/Scene.h" +#include "Engine/Level/Scene/SceneRendering.h" #include "Engine/Localization/Localization.h" #if USE_EDITOR #include "Editor/Editor.h" @@ -370,7 +372,8 @@ void TextRender::Draw(RenderContext& renderContext) UpdateLayout(); Matrix world; renderContext.View.GetWorldMatrix(_transform, world); - GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world); + auto drawState = renderContext.Buffers->GetGeometryDrawState(&GetScene()->Rendering, _sceneRenderingKey, this); + GEOMETRY_DRAW_STATE_EVENT_BEGIN(drawState, world); const DrawPass drawModes = DrawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(ShadowsMode); if (_vb.Data.Count() > 0 && drawModes != DrawPass::None) @@ -389,7 +392,7 @@ void TextRender::Draw(RenderContext& renderContext) drawCall.ObjectPosition = drawCall.World.GetTranslation(); drawCall.ObjectRadius = (float)_sphere.Radius; drawCall.Surface.GeometrySize = _localBox.GetSize(); - drawCall.Surface.PrevWorld = _drawState.PrevWorld; + drawCall.Surface.PrevWorld = drawState ? drawState->PrevWorld : world; drawCall.PerInstanceRandom = GetPerInstanceRandom(); drawCall.SetStencilValue(_layer); drawCall.Geometry.IndexBuffer = _ib.GetBuffer(); @@ -409,7 +412,7 @@ void TextRender::Draw(RenderContext& renderContext) } } - GEOMETRY_DRAW_STATE_EVENT_END(_drawState, world); + GEOMETRY_DRAW_STATE_EVENT_END(drawState, world); } #if USE_EDITOR diff --git a/Source/Engine/UI/TextRender.h b/Source/Engine/UI/TextRender.h index a7739f1c6..1f599f98d 100644 --- a/Source/Engine/UI/TextRender.h +++ b/Source/Engine/UI/TextRender.h @@ -42,7 +42,6 @@ private: int32 _sceneRenderingKey = -1; BoundingBox _localBox; - GeometryDrawStateData _drawState; DynamicIndexBuffer _ib; DynamicVertexBuffer _vb; #if MODEL_USE_PRECISE_MESH_INTERSECTS