From 184502dcc42c2fc6a8bd7d26b35aa62e26c6315a Mon Sep 17 00:00:00 2001 From: Anton Chernykh Date: Tue, 16 Apr 2024 21:18:50 +0300 Subject: [PATCH] Temporal fix for ChunkComponent baking issues --- .../AddMissedRenderingComponentSystem.cs | 29 ++ .../AddMissedRenderingComponentSystem.cs.meta | 3 + Rendering/Debug/ValidateChunkMappingSystem.cs | 318 +++++++++--------- package.json | 2 +- 4 files changed, 192 insertions(+), 160 deletions(-) create mode 100644 Rendering/Common/AddMissedRenderingComponentSystem.cs create mode 100644 Rendering/Common/AddMissedRenderingComponentSystem.cs.meta diff --git a/Rendering/Common/AddMissedRenderingComponentSystem.cs b/Rendering/Common/AddMissedRenderingComponentSystem.cs new file mode 100644 index 0000000..f5eb622 --- /dev/null +++ b/Rendering/Common/AddMissedRenderingComponentSystem.cs @@ -0,0 +1,29 @@ +using Unity.Burst; +using Unity.Entities; + +namespace NSprites +{ + [UpdateInGroup(typeof(PresentationSystemGroup))] + [UpdateBefore(typeof(SpriteRenderingSystem))] + [WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor | WorldSystemFilterFlags.EntitySceneOptimizations)] + public partial struct AddMissedRenderingComponentSystem : ISystem + { + private EntityQuery _query; + + [BurstCompile] + public void OnCreate(ref SystemState state) + { + _query = SystemAPI.QueryBuilder() + .WithAll() + .WithNoneChunkComponent() + .WithOptions(EntityQueryOptions.IncludePrefab | EntityQueryOptions.IncludeDisabledEntities | EntityQueryOptions.Default | EntityQueryOptions.IgnoreComponentEnabledState) + .Build(); + + state.RequireForUpdate(_query); + } + + [BurstCompile] + public void OnUpdate(ref SystemState state) + => state.EntityManager.AddChunkComponentData(_query, new PropertyPointerChunk()); + } +} \ No newline at end of file diff --git a/Rendering/Common/AddMissedRenderingComponentSystem.cs.meta b/Rendering/Common/AddMissedRenderingComponentSystem.cs.meta new file mode 100644 index 0000000..8ce4d04 --- /dev/null +++ b/Rendering/Common/AddMissedRenderingComponentSystem.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 098d7509424747e8ba2bbf7a93d519b4 +timeCreated: 1713191569 \ No newline at end of file diff --git a/Rendering/Debug/ValidateChunkMappingSystem.cs b/Rendering/Debug/ValidateChunkMappingSystem.cs index 332b233..435850c 100644 --- a/Rendering/Debug/ValidateChunkMappingSystem.cs +++ b/Rendering/Debug/ValidateChunkMappingSystem.cs @@ -1,159 +1,159 @@ -using System; -using System.Collections.Generic; -using Unity.Burst; -using Unity.Collections; -using Unity.Entities; -using Unity.Jobs; - -namespace NSprites -{ - [WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)] - public partial struct ValidateChunkMappingSystem : ISystem - { - [BurstCompile] - private struct FilterUninitializedChunks : IJobParallelFor - { - [ReadOnly][DeallocateOnJobCompletion] public NativeArray Chunks; - [ReadOnly] public ComponentTypeHandle PropertyPointerChunk_CTH_RO; - [WriteOnly] public NativeList.ParallelWriter InitializedChunks; - - public void Execute(int index) - { - var chunk = Chunks[index]; - if(chunk.GetChunkComponentData(ref PropertyPointerChunk_CTH_RO).Initialized) - InitializedChunks.AddNoResize(chunk); - } - } - - [BurstCompile] - private struct ExtractPropertyPointersToArrayJob : IJobParallelFor - { - [ReadOnly] public NativeList Chunks; - [ReadOnly] public ComponentTypeHandle PropertyPointerChunk_CTH_RO; - [WriteOnly] public NativeArray ChunkInfoArray; - - public void Execute(int index) - { - var chunk = Chunks[index]; - ChunkInfoArray[index] = new ChunkInfo - { - Chunk = chunk, - Ptr = chunk.GetChunkComponentData(ref PropertyPointerChunk_CTH_RO) - }; - } - } - - [BurstCompile] - private struct ValidateChunkMappingJob : IJobParallelFor - { - // should be sorted - [NativeDisableParallelForRestriction] public NativeArray ChunkInfoArray; - - public void Execute(int index) - { - var curr = ChunkInfoArray[index]; - - if (index == ChunkInfoArray.Length - 1) - curr.Validated = true; - else - { - var next = ChunkInfoArray[index + 1]; - - // * chunk might be newly created and have no map data yet, so such chunk is validated - // * prev chunk should start before next - // * prev chunk count nor capacity should end before next chunk starts - curr.Validated = !curr.Ptr.Initialized || (curr.Ptr.From < next.Ptr.From && curr.Ptr.From + curr.Chunk.Count <= next.Ptr.From && curr.Ptr.From + curr.Chunk.Capacity <= next.Ptr.From); - } - - ChunkInfoArray[index] = curr; - } - } - - private struct ChunkInfo : IComparable - { - public ArchetypeChunk Chunk; - public PropertyPointerChunk Ptr; - public bool Validated; - - public int CompareTo(ChunkInfo other) - => Ptr.From.CompareTo(other.Ptr.From); - } - - private struct SystemData : IComponentData - { - public EntityQuery RenderQuery; - } - - public void OnCreate(ref SystemState state) - { - state.EntityManager.AddComponentData(state.SystemHandle, new SystemData - { - RenderQuery = state.GetEntityQuery(ComponentType.ReadOnly()), - }); - } - - //[BurstCompile] - public void OnUpdate(ref SystemState state) - { - if (!SystemAPI.ManagedAPI.TryGetSingleton(out var renderArchetypeStorage) - || !SystemAPI.TryGetSingleton(out var systemData)) - return; - - for (var archetypeIndex = 0; archetypeIndex < renderArchetypeStorage.RenderArchetypes.Count; archetypeIndex++) - { - var renderArchetype = renderArchetypeStorage.RenderArchetypes[archetypeIndex]; - var query = systemData.RenderQuery; - query.SetSharedComponentFilter(new SpriteRenderID { id = renderArchetype.ID }); - - var chunks = query.ToArchetypeChunkArray(Allocator.TempJob); - var filteredChunks = new NativeList(chunks.Length, Allocator.TempJob); - - var filterChunksJob = new FilterUninitializedChunks - { - Chunks = chunks, - PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle(true), - InitializedChunks = filteredChunks.AsParallelWriter() - }; - state.Dependency = filterChunksJob.ScheduleByRef(chunks.Length, 32, state.Dependency); - state.Dependency.Complete(); - - var chunkInfoArray = new NativeArray(filteredChunks.Length, Allocator.TempJob); - - var extractPropPointersJob = new ExtractPropertyPointersToArrayJob - { - Chunks = filteredChunks, - PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle(true), - ChunkInfoArray = chunkInfoArray - }; - state.Dependency = extractPropPointersJob.ScheduleByRef(chunkInfoArray.Length, 32, state.Dependency); - state.Dependency.Complete(); - - state.Dependency = chunkInfoArray.SortJob().Schedule(); - - var validateJob = new ValidateChunkMappingJob - { - ChunkInfoArray = chunkInfoArray - }; - state.Dependency = validateJob.ScheduleByRef(chunkInfoArray.Length, 32, state.Dependency); - state.Dependency.Complete(); - - for (var i = 0; i < chunkInfoArray.Length - 1; i++) - { - var info = chunkInfoArray[i]; - var nextInfo = chunkInfoArray[i + 1]; - - if (!info.Validated) - { - filteredChunks.Dispose(); - chunkInfoArray.Dispose(); - throw new NSpritesException($"Chunk {i} starts from {info.Ptr.From} cap {info.Chunk.Count} / {info.Chunk.Capacity} init:{info.Ptr.Initialized} has problems with next chunk: {(info.Chunk.Archetype.StableHash == nextInfo.Chunk.Archetype.StableHash ? "same archetype" : "diff archetypes")} starts from {nextInfo.Ptr.From} cap {nextInfo.Chunk.Count} / {nextInfo.Chunk.Capacity} init:{nextInfo.Ptr.Initialized}"); - } - } - - filteredChunks.Dispose(); - chunkInfoArray.Dispose(); - query.ResetFilter(); - } - } - } -} \ No newline at end of file +// using System; +// using System.Collections.Generic; +// using Unity.Burst; +// using Unity.Collections; +// using Unity.Entities; +// using Unity.Jobs; +// +// namespace NSprites +// { +// [WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)] +// public partial struct ValidateChunkMappingSystem : ISystem +// { +// [BurstCompile] +// private struct FilterUninitializedChunks : IJobParallelFor +// { +// [ReadOnly][DeallocateOnJobCompletion] public NativeArray Chunks; +// [ReadOnly] public ComponentTypeHandle PropertyPointerChunk_CTH_RO; +// [WriteOnly] public NativeList.ParallelWriter InitializedChunks; +// +// public void Execute(int index) +// { +// var chunk = Chunks[index]; +// if(chunk.GetChunkComponentData(ref PropertyPointerChunk_CTH_RO).Initialized) +// InitializedChunks.AddNoResize(chunk); +// } +// } +// +// [BurstCompile] +// private struct ExtractPropertyPointersToArrayJob : IJobParallelFor +// { +// [ReadOnly] public NativeList Chunks; +// [ReadOnly] public ComponentTypeHandle PropertyPointerChunk_CTH_RO; +// [WriteOnly] public NativeArray ChunkInfoArray; +// +// public void Execute(int index) +// { +// var chunk = Chunks[index]; +// ChunkInfoArray[index] = new ChunkInfo +// { +// Chunk = chunk, +// Ptr = chunk.GetChunkComponentData(ref PropertyPointerChunk_CTH_RO) +// }; +// } +// } +// +// [BurstCompile] +// private struct ValidateChunkMappingJob : IJobParallelFor +// { +// // should be sorted +// [NativeDisableParallelForRestriction] public NativeArray ChunkInfoArray; +// +// public void Execute(int index) +// { +// var curr = ChunkInfoArray[index]; +// +// if (index == ChunkInfoArray.Length - 1) +// curr.Validated = true; +// else +// { +// var next = ChunkInfoArray[index + 1]; +// +// // * chunk might be newly created and have no map data yet, so such chunk is validated +// // * prev chunk should start before next +// // * prev chunk count nor capacity should end before next chunk starts +// curr.Validated = !curr.Ptr.Initialized || (curr.Ptr.From < next.Ptr.From && curr.Ptr.From + curr.Chunk.Count <= next.Ptr.From && curr.Ptr.From + curr.Chunk.Capacity <= next.Ptr.From); +// } +// +// ChunkInfoArray[index] = curr; +// } +// } +// +// private struct ChunkInfo : IComparable +// { +// public ArchetypeChunk Chunk; +// public PropertyPointerChunk Ptr; +// public bool Validated; +// +// public int CompareTo(ChunkInfo other) +// => Ptr.From.CompareTo(other.Ptr.From); +// } +// +// private struct SystemData : IComponentData +// { +// public EntityQuery RenderQuery; +// } +// +// public void OnCreate(ref SystemState state) +// { +// state.EntityManager.AddComponentData(state.SystemHandle, new SystemData +// { +// RenderQuery = state.GetEntityQuery(ComponentType.ReadOnly()), +// }); +// } +// +// //[BurstCompile] +// public void OnUpdate(ref SystemState state) +// { +// if (!SystemAPI.ManagedAPI.TryGetSingleton(out var renderArchetypeStorage) +// || !SystemAPI.TryGetSingleton(out var systemData)) +// return; +// +// for (var archetypeIndex = 0; archetypeIndex < renderArchetypeStorage.RenderArchetypes.Count; archetypeIndex++) +// { +// var renderArchetype = renderArchetypeStorage.RenderArchetypes[archetypeIndex]; +// var query = systemData.RenderQuery; +// query.SetSharedComponentFilter(new SpriteRenderID { id = renderArchetype.ID }); +// +// var chunks = query.ToArchetypeChunkArray(Allocator.TempJob); +// var filteredChunks = new NativeList(chunks.Length, Allocator.TempJob); +// +// var filterChunksJob = new FilterUninitializedChunks +// { +// Chunks = chunks, +// PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle(true), +// InitializedChunks = filteredChunks.AsParallelWriter() +// }; +// state.Dependency = filterChunksJob.ScheduleByRef(chunks.Length, 32, state.Dependency); +// state.Dependency.Complete(); +// +// var chunkInfoArray = new NativeArray(filteredChunks.Length, Allocator.TempJob); +// +// var extractPropPointersJob = new ExtractPropertyPointersToArrayJob +// { +// Chunks = filteredChunks, +// PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle(true), +// ChunkInfoArray = chunkInfoArray +// }; +// state.Dependency = extractPropPointersJob.ScheduleByRef(chunkInfoArray.Length, 32, state.Dependency); +// state.Dependency.Complete(); +// +// state.Dependency = chunkInfoArray.SortJob().Schedule(); +// +// var validateJob = new ValidateChunkMappingJob +// { +// ChunkInfoArray = chunkInfoArray +// }; +// state.Dependency = validateJob.ScheduleByRef(chunkInfoArray.Length, 32, state.Dependency); +// state.Dependency.Complete(); +// +// for (var i = 0; i < chunkInfoArray.Length - 1; i++) +// { +// var info = chunkInfoArray[i]; +// var nextInfo = chunkInfoArray[i + 1]; +// +// if (!info.Validated) +// { +// filteredChunks.Dispose(); +// chunkInfoArray.Dispose(); +// throw new NSpritesException($"Chunk {i} starts from {info.Ptr.From} cap {info.Chunk.Count} / {info.Chunk.Capacity} init:{info.Ptr.Initialized} has problems with next chunk: {(info.Chunk.Archetype.StableHash == nextInfo.Chunk.Archetype.StableHash ? "same archetype" : "diff archetypes")} starts from {nextInfo.Ptr.From} cap {nextInfo.Chunk.Count} / {nextInfo.Chunk.Capacity} init:{nextInfo.Ptr.Initialized}"); +// } +// } +// +// filteredChunks.Dispose(); +// chunkInfoArray.Dispose(); +// query.ResetFilter(); +// } +// } +// } +// } \ No newline at end of file diff --git a/package.json b/package.json index 526f86d..85b48e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.tonymax.nsprites", - "version": "4.0.0", + "version": "4.0.1", "displayName": "NSprites", "description": "Entities sprite rendering system. Uses GPU instancing with compute buffers to draw entities as sprites.", "unity": "2022.2",