Skip to content

Commit

Permalink
Temporal fix for ChunkComponent baking issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoshidza committed Apr 16, 2024
1 parent abf1821 commit 184502d
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 160 deletions.
29 changes: 29 additions & 0 deletions Rendering/Common/AddMissedRenderingComponentSystem.cs
Original file line number Diff line number Diff line change
@@ -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<PropertyPointer>()
.WithNoneChunkComponent<PropertyPointerChunk>()
.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());
}
}
3 changes: 3 additions & 0 deletions Rendering/Common/AddMissedRenderingComponentSystem.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

318 changes: 159 additions & 159 deletions Rendering/Debug/ValidateChunkMappingSystem.cs
Original file line number Diff line number Diff line change
@@ -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<ArchetypeChunk> Chunks;
[ReadOnly] public ComponentTypeHandle<PropertyPointerChunk> PropertyPointerChunk_CTH_RO;
[WriteOnly] public NativeList<ArchetypeChunk>.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<ArchetypeChunk> Chunks;
[ReadOnly] public ComponentTypeHandle<PropertyPointerChunk> PropertyPointerChunk_CTH_RO;
[WriteOnly] public NativeArray<ChunkInfo> 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<ChunkInfo> 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<ChunkInfo>
{
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<SpriteRenderID>()),
});
}

//[BurstCompile]
public void OnUpdate(ref SystemState state)
{
if (!SystemAPI.ManagedAPI.TryGetSingleton<RenderArchetypeStorage>(out var renderArchetypeStorage)
|| !SystemAPI.TryGetSingleton<SystemData>(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<ArchetypeChunk>(chunks.Length, Allocator.TempJob);

var filterChunksJob = new FilterUninitializedChunks
{
Chunks = chunks,
PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle<PropertyPointerChunk>(true),
InitializedChunks = filteredChunks.AsParallelWriter()
};
state.Dependency = filterChunksJob.ScheduleByRef(chunks.Length, 32, state.Dependency);
state.Dependency.Complete();

var chunkInfoArray = new NativeArray<ChunkInfo>(filteredChunks.Length, Allocator.TempJob);

var extractPropPointersJob = new ExtractPropertyPointersToArrayJob
{
Chunks = filteredChunks,
PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle<PropertyPointerChunk>(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();
}
}
}
}
// 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<ArchetypeChunk> Chunks;
// [ReadOnly] public ComponentTypeHandle<PropertyPointerChunk> PropertyPointerChunk_CTH_RO;
// [WriteOnly] public NativeList<ArchetypeChunk>.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<ArchetypeChunk> Chunks;
// [ReadOnly] public ComponentTypeHandle<PropertyPointerChunk> PropertyPointerChunk_CTH_RO;
// [WriteOnly] public NativeArray<ChunkInfo> 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<ChunkInfo> 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<ChunkInfo>
// {
// 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<SpriteRenderID>()),
// });
// }
//
// //[BurstCompile]
// public void OnUpdate(ref SystemState state)
// {
// if (!SystemAPI.ManagedAPI.TryGetSingleton<RenderArchetypeStorage>(out var renderArchetypeStorage)
// || !SystemAPI.TryGetSingleton<SystemData>(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<ArchetypeChunk>(chunks.Length, Allocator.TempJob);
//
// var filterChunksJob = new FilterUninitializedChunks
// {
// Chunks = chunks,
// PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle<PropertyPointerChunk>(true),
// InitializedChunks = filteredChunks.AsParallelWriter()
// };
// state.Dependency = filterChunksJob.ScheduleByRef(chunks.Length, 32, state.Dependency);
// state.Dependency.Complete();
//
// var chunkInfoArray = new NativeArray<ChunkInfo>(filteredChunks.Length, Allocator.TempJob);
//
// var extractPropPointersJob = new ExtractPropertyPointersToArrayJob
// {
// Chunks = filteredChunks,
// PropertyPointerChunk_CTH_RO = SystemAPI.GetComponentTypeHandle<PropertyPointerChunk>(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();
// }
// }
// }
// }
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down

0 comments on commit 184502d

Please sign in to comment.