diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 077bf9b80..447e6cabc 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -94,6 +94,13 @@ struct DebugLine float TimeLeft; }; +struct DebugGeometryBuffer +{ + GPUBuffer* Buffer; + float TimeLeft; + Matrix Transform; +}; + struct DebugTriangle { Float3 V0; @@ -122,12 +129,9 @@ struct DebugText3D float TimeLeft; }; -PACK_STRUCT(struct Vertex { - Float3 Position; - Color32 Color; - }); +typedef DebugDraw::Vertex Vertex; -GPU_CB_STRUCT(Data { +GPU_CB_STRUCT(ShaderData { Matrix ViewProjection; Float2 Padding; float ClipPosZBias; @@ -231,6 +235,7 @@ void TeleportList(const Float3& delta, Array& list) struct DebugDrawData { + Array GeometryBuffers; Array DefaultLines; Array OneFrameLines; Array DefaultTriangles; @@ -244,7 +249,7 @@ struct DebugDrawData inline int32 Count() const { - return LinesCount() + TrianglesCount() + TextCount(); + return LinesCount() + TrianglesCount() + TextCount() + GeometryBuffers.Count(); } inline int32 LinesCount() const @@ -280,6 +285,7 @@ struct DebugDrawData inline void Update(float deltaTime) { + UpdateList(deltaTime, GeometryBuffers); UpdateList(deltaTime, DefaultLines); UpdateList(deltaTime, DefaultTriangles); UpdateList(deltaTime, DefaultWireTriangles); @@ -784,7 +790,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe // Update constant buffer const auto cb = DebugDrawShader->GetShader()->GetCB(0); - Data data; + ShaderData data; Matrix vp; Matrix::Multiply(view.View, view.Projection, vp); Matrix::Transpose(vp, data.ViewProjection); @@ -830,6 +836,22 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe context->Draw(depthTestTriangles.StartVertex, depthTestTriangles.VertexCount); } + // Geometries + for (auto& geometry : Context->DebugDrawDepthTest.GeometryBuffers) + { + auto tmp = data; + Matrix mvp; + Matrix::Multiply(geometry.Transform, vp, mvp); + Matrix::Transpose(mvp, tmp.ViewProjection); + context->UpdateCB(cb, &tmp); + auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault; + context->SetState(state->Get(enableDepthWrite, true)); + context->BindVB(ToSpan(&geometry.Buffer, 1)); + context->Draw(0, geometry.Buffer->GetElementsCount()); + } + if (Context->DebugDrawDepthTest.GeometryBuffers.HasItems()) + context->UpdateCB(cb, &data); + if (data.EnableDepthTest) context->UnBindSR(0); } @@ -862,6 +884,19 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe context->BindVB(ToSpan(&vb, 1)); context->Draw(defaultTriangles.StartVertex, defaultTriangles.VertexCount); } + + // Geometries + for (auto& geometry : Context->DebugDrawDefault.GeometryBuffers) + { + auto tmp = data; + Matrix mvp; + Matrix::Multiply(geometry.Transform, vp, mvp); + Matrix::Transpose(mvp, tmp.ViewProjection); + context->UpdateCB(cb, &tmp); + context->SetState(DebugDrawPsLinesDefault.Get(false, false)); + context->BindVB(ToSpan(&geometry.Buffer, 1)); + context->Draw(0, geometry.Buffer->GetElementsCount()); + } } // Text @@ -1088,6 +1123,24 @@ void DebugDraw::DrawLines(const Span& lines, const Matrix& transform, co } } +void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float duration, bool depthTest) +{ + if (lines == nullptr || lines->GetSize() == 0) + return; + if (lines->GetSize() % (sizeof(Vertex) * 2) != 0) + { + DebugLog::ThrowException("Cannot draw debug lines with uneven amount of items in array"); + return; + } + + // Draw lines + auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault; + auto& geometry = debugDrawData.GeometryBuffers.AddOne(); + geometry.Buffer = lines; + geometry.TimeLeft = duration; + geometry.Transform = transform * Matrix::Translation(-Context->Origin); +} + void DebugDraw::DrawLines(const Array& lines, const Matrix& transform, const Color& color, float duration, bool depthTest) { DrawLines(Span(lines.Get(), lines.Count()), transform, color, duration, depthTest); @@ -2147,6 +2200,7 @@ void DebugDraw::DrawText(const StringView& text, const Transform& transform, con void DebugDraw::Clear(void* context) { - DebugDraw::UpdateContext(context, MAX_float); + UpdateContext(context, MAX_float); } + #endif diff --git a/Source/Engine/Debug/DebugDraw.h b/Source/Engine/Debug/DebugDraw.h index bb5cf2e50..6cfceca6d 100644 --- a/Source/Engine/Debug/DebugDraw.h +++ b/Source/Engine/Debug/DebugDraw.h @@ -6,6 +6,8 @@ #include "Engine/Scripting/ScriptingType.h" #include "Engine/Core/Math/Color.h" +#include "Engine/Core/Math/Color32.h" +#include "Engine/Core/Math/Vector3.h" #include "Engine/Core/Types/Span.h" struct RenderView; @@ -14,6 +16,7 @@ class Light; struct RenderContext; class GPUTextureView; class GPUContext; +class GPUBuffer; class RenderTask; class SceneRenderTask; class Actor; @@ -26,6 +29,14 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw { DECLARE_SCRIPTING_TYPE_NO_SPAWN(DebugDraw); + /// + /// Vertex data for debug shapes. + /// + PACK_STRUCT(struct Vertex { + Float3 Position; + Color32 Color; + }); + #if USE_EDITOR /// /// Allocates the context for Debug Drawing. Can be use to redirect debug shapes collecting to a separate container (instead of global state). @@ -175,6 +186,15 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw /// If set to true depth test will be performed, otherwise depth will be ignored. API_FUNCTION() static void DrawLines(const Span& lines, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true); + /// + /// Draws the lines using the provided vertex buffer that contains pairs of Vertex elements. Line positions are located one after another (e.g. l0.start, l0.end, l1.start, l1.end,...). + /// + /// The GPU buffer with vertices for lines (must have multiple of 2 elements). + /// The custom matrix used to transform all line vertices. + /// The duration (in seconds). Use 0 to draw it only once. + /// If set to true depth test will be performed, otherwise depth will be ignored. + API_FUNCTION() static void DrawLines(GPUBuffer* lines, const Matrix& transform, float duration = 0.0f, bool depthTest = true); + /// /// Draws the lines. Line positions are located one after another (e.g. l0.start, l0.end, l1.start, l1.end,...). /// @@ -691,9 +711,9 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw API_FUNCTION() static void DrawText(const StringView& text, const Transform& transform, const Color& color = Color::White, int32 size = 32, float duration = 0.0f); /// - /// Clear all debug draw displayed on sceen. + /// Clears all debug shapes displayed on screen. /// - /// + /// The context. API_FUNCTION() static void Clear(void* context = nullptr); }; diff --git a/Source/Engine/Graphics/GPUBuffer.cpp b/Source/Engine/Graphics/GPUBuffer.cpp index 32681b4ce..6a0221b14 100644 --- a/Source/Engine/Graphics/GPUBuffer.cpp +++ b/Source/Engine/Graphics/GPUBuffer.cpp @@ -5,6 +5,7 @@ #include "GPUResourceProperty.h" #include "GPUBufferDescription.h" #include "PixelFormatExtensions.h" +#include "RenderTask.h" #include "Async/Tasks/GPUCopyResourceTask.h" #include "Engine/Core/Utilities.h" #include "Engine/Core/Types/String.h" @@ -358,6 +359,16 @@ void GPUBuffer::SetData(const void* data, uint32 size) Log::ArgumentOutOfRangeException(TEXT("Buffer.SetData")); return; } + + if (_desc.Usage == GPUResourceUsage::Default && GPUDevice::Instance->IsRendering()) + { + // Upload using the context (will use internal staging buffer inside command buffer) + RenderContext::GPULocker.Lock(); + GPUDevice::Instance->GetMainContext()->UpdateBuffer(this, data, size); + RenderContext::GPULocker.Unlock(); + return; + } + void* mapped = Map(GPUResourceMapMode::Write); if (!mapped) return; diff --git a/Source/Engine/Graphics/GPUBuffer.h b/Source/Engine/Graphics/GPUBuffer.h index cbdc39c4f..d40b7744d 100644 --- a/Source/Engine/Graphics/GPUBuffer.h +++ b/Source/Engine/Graphics/GPUBuffer.h @@ -74,8 +74,7 @@ public: /// API_PROPERTY() FORCE_INLINE uint32 GetElementsCount() const { - ASSERT(_desc.Stride > 0); - return _desc.Size / _desc.Stride; + return _desc.Stride > 0 ? _desc.Size / _desc.Stride : 0; } /// diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp index 3dbbd113f..4e2a84661 100644 --- a/Source/Engine/Level/Scene/SceneRendering.cpp +++ b/Source/Engine/Level/Scene/SceneRendering.cpp @@ -90,6 +90,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c // Draw physics shapes if (EnumHasAnyFlags(view.Flags, ViewFlags::PhysicsDebug) || view.Mode == ViewMode::PhysicsColliders) { + PROFILE_CPU_NAMED("PhysicsDebug"); const PhysicsDebugCallback* physicsDebugData = PhysicsDebug.Get(); for (int32 i = 0; i < PhysicsDebug.Count(); i++) { @@ -100,6 +101,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c // Draw light shapes if (EnumHasAnyFlags(view.Flags, ViewFlags::LightsDebug)) { + PROFILE_CPU_NAMED("LightsDebug"); const LightsDebugCallback* lightsDebugData = LightsDebug.Get(); for (int32 i = 0; i < LightsDebug.Count(); i++) { diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index 96dc35d49..5ff02cf36 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -33,6 +33,11 @@ #if USE_EDITOR #include "Engine/Debug/DebugDraw.h" #endif +#if TERRAIN_USE_PHYSICS_DEBUG +#include "Engine/Graphics/GPUDevice.h" +#include "Engine/Graphics/DynamicBuffer.h" +#include "Engine/Engine/Units.h" +#endif #include "Engine/Content/Content.h" #include "Engine/Content/Assets/RawDataAsset.h" @@ -94,7 +99,8 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z) } #endif #if TERRAIN_USE_PHYSICS_DEBUG - _debugLines.Resize(0); + SAFE_DELETE(_debugLines); + _debugLinesDirty = true; #endif #if USE_EDITOR _collisionTriangles.Resize(0); @@ -1822,7 +1828,7 @@ bool TerrainPatch::UpdateHeightData(TerrainDataUpdateInfo& info, const Int2& mod // Invalidate cache #if TERRAIN_USE_PHYSICS_DEBUG - _debugLines.Resize(0); + _debugLinesDirty = true; #endif #if USE_EDITOR _collisionTriangles.Resize(0); @@ -1940,7 +1946,7 @@ bool TerrainPatch::UpdateCollision() { // Invalidate cache #if TERRAIN_USE_PHYSICS_DEBUG - _debugLines.Resize(0); + _debugLinesDirty = true; #endif #if USE_EDITOR _collisionTriangles.Resize(0); @@ -2082,7 +2088,7 @@ void TerrainPatch::UpdatePostManualDeserialization() { // Invalidate cache #if TERRAIN_USE_PHYSICS_DEBUG - _debugLines.Resize(0); + _debugLinesDirty = true; #endif #if USE_EDITOR _collisionTriangles.Resize(0); @@ -2211,7 +2217,8 @@ void TerrainPatch::DestroyCollision() _physicsShape = nullptr; _physicsHeightField = nullptr; #if TERRAIN_USE_PHYSICS_DEBUG - _debugLines.Resize(0); + _debugLinesDirty = true; + SAFE_DELETE(_debugLines); #endif #if USE_EDITOR _collisionTriangles.Resize(0); @@ -2224,15 +2231,26 @@ void TerrainPatch::DestroyCollision() void TerrainPatch::CacheDebugLines() { PROFILE_CPU(); - ASSERT(_debugLines.IsEmpty() && _physicsHeightField); + ASSERT(_physicsHeightField); + _debugLinesDirty = false; + if (!_debugLines) + _debugLines = GPUDevice::Instance->CreateBuffer(TEXT("Terrain.DebugLines")); int32 rows, cols; PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols); + const int32 count = (rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2; + typedef DebugDraw::Vertex Vertex; + if (_debugLines->GetElementsCount() != count) + { + if (_debugLines->Init(GPUBufferDescription::Vertex(sizeof(Vertex), count))) + return; + } + Array debugLines; + debugLines.Resize(count); + auto* data = debugLines.Get(); + const Color32 color(Color::GreenYellow * 0.8f); - _debugLines.Resize((rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2); - Vector3* data = _debugLines.Get(); - -#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))) +#define GET_VERTEX(x, y) const Vertex v##x##y = { Float3((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))), color } for (int32 row = 0; row < rows - 1; row++) { @@ -2243,7 +2261,7 @@ void TerrainPatch::CacheDebugLines() if (sample.MaterialIndex0 == (uint8)PhysicsBackend::HeightFieldMaterial::Hole) { for (int32 i = 0; i < 6; i++) - *data++ = Vector3::Zero; + *data++ = Vertex { Float3::Zero, Color32::Black }; continue; } @@ -2284,18 +2302,16 @@ void TerrainPatch::CacheDebugLines() } #undef GET_VERTEX + + _debugLines->SetData(debugLines.Get(), _debugLines->GetSize()); } void TerrainPatch::DrawPhysicsDebug(RenderView& view) { +#if COMPILE_WITH_DEBUG_DRAW const BoundingBox bounds(_bounds.Minimum - view.Origin, _bounds.Maximum - view.Origin); if (!_physicsShape || !view.CullingFrustum.Intersects(bounds)) return; - - const Transform terrainTransform = _terrain->_transform; - const Transform localTransform(Vector3(0, _yOffset, 0), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ)); - const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld(); - if (view.Mode == ViewMode::PhysicsColliders) { DEBUG_DRAW_TRIANGLES(GetCollisionTriangles(), Color::DarkOliveGreen, 0, true); @@ -2304,13 +2320,17 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view) { BoundingSphere sphere; BoundingSphere::FromBox(bounds, sphere); - if (Vector3::Distance(sphere.Center, view.Position) - sphere.Radius < 4000.0f) + if (Vector3::Distance(sphere.Center, view.Position) - sphere.Radius < METERS_TO_UNITS(500)) { - if (_debugLines.IsEmpty()) + if (!_debugLines || _debugLinesDirty) CacheDebugLines(); - DEBUG_DRAW_LINES(_debugLines, world, Color::GreenYellow * 0.8f, 0, true); + const Transform terrainTransform = _terrain->_transform; + const Transform localTransform(Vector3(0, _yOffset, 0), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ)); + const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld(); + DebugDraw::DrawLines(_debugLines, world); } } +#endif } #endif diff --git a/Source/Engine/Terrain/TerrainPatch.h b/Source/Engine/Terrain/TerrainPatch.h index 05a7693fe..5eedf6e6d 100644 --- a/Source/Engine/Terrain/TerrainPatch.h +++ b/Source/Engine/Terrain/TerrainPatch.h @@ -40,12 +40,13 @@ private: Array _cachedSplatMap[TERRAIN_MAX_SPLATMAPS_COUNT]; bool _wasHeightModified; bool _wasSplatmapModified[TERRAIN_MAX_SPLATMAPS_COUNT]; +#if TERRAIN_USE_PHYSICS_DEBUG + bool _debugLinesDirty = true; + class GPUBuffer* _debugLines = nullptr; +#endif TextureBase::InitData* _dataHeightmap = nullptr; TextureBase::InitData* _dataSplatmap[TERRAIN_MAX_SPLATMAPS_COUNT] = {}; #endif -#if TERRAIN_USE_PHYSICS_DEBUG - Array _debugLines; // TODO: large-worlds -#endif #if USE_EDITOR Array _collisionTriangles; // TODO: large-worlds #endif