Hello!
I apologize if I chose the wrong prefix but I may or may not have found a bug.
I have been working on a DOTS/ECS terrain system (yes, me too), but at the moment it’s mostly just generating meshes from heightmap images and then dividing it using a quadtree system. I am receiving an access violation exception when running my test project from a player build (.exe).
When my system starts up it gets a reference to the EntitiesGraphicsSystem and uses RegisterMesh when new child meshes are created, since the general consensus is that this is the most optimal way without implementing your own BatchRendererGroup, then when they are no longer needed call UnregisterMesh and finally, destroy the mesh.
To test, I’m just using the standard “Free Camera” script on a normal MonoBehaviour (not converted) camera and flying around the terrain (2048x2048) at relatively high speeds. Generating and destroying lots of meshes quickly (which it does very well!!) the total number depending on how many LOD levels there are.
At first everything runs smooth, but at some point the game will just crash. Sometimes it takes seconds, other times it takes several minutes.
Below is the stack trace the access violation was occurring in:
Exception Code: 0xc0000005
Exception Information: The thread tried to read from or write to a virtual address for which it does not have the appropriate access.
========== OUTPUTTING STACK TRACE ==================
0x00007FF9FC90F33B (UnityPlayer) ScriptableBatchRenderer::RenderMultipleMeshes
0x00007FF9FC90AD8C (UnityPlayer) ScriptableBatchRenderer::Flush
0x00007FF9FC9032A1 (UnityPlayer) RenderShadowCasterPartsSRPBatcher
0x00007FF9FC90375C (UnityPlayer) ScriptableRenderLoopShadowsJob
0x00007FF9FD0FA842 (UnityPlayer) ExecuteAsyncSetup12
0x00007FF9FC9591F0 (UnityPlayer) ujob_execute_job
0x00007FF9FC95859D (UnityPlayer) lane_guts
0x00007FF9FC95AFB4 (UnityPlayer) worker_thread_routine
0x00007FF9FCD9B741 (UnityPlayer) Thread::RunThreadWrapper
0x00007FFB1E84257D (KERNEL32) BaseThreadInitThunk
- This is always the same. Some posts I read mentioned their stacks were random. Mine was not, it was always the same output. In Visual Studio with the debugger attached and in the crash dump.
My first thought was that something was trying to use the Mesh object after I destroyed it. So I commented out the call to Object.Destroy. The exception still occurred and the application was now leaking orphaned meshes (obviously). So I tried tweaking some lighting / shadow settings. No affect.
After re-organizing, and commenting, and uncommenting out code I finally figured out 2 solutions:
The 1st was to simply turn off “Cast Shadows” on the Mesh Renderer component prior to baking. Not my preferred solution.
The 2nd is to not call UnregisterMesh at all and just calling Object.Destroy on the mesh. For whatever reason this works, and after memory profiling it several times and taking a few dozen snapshots I’m not seeing it leaking or retaining any sort of reference to the Mesh itself.
I minimize any interactions with the RenderMeshArray component (just once at start up to generate the authored entities) and use the ID returned from RegisterMaterial and RegisterMesh without issue. I’m sure only 1 “parent count” to each mesh exists as it’s only registered directly after each mesh is generated.
Below is the code that executes on entities with the “RemoveNodeTag”:
private void ExecuteRemoveQuery(ref SystemState state) {
var em = state.EntityManager;
var gfx = GetEntitiesGraphics(ref state);
var entities = _remove_query.ToEntityArray(Allocator.Temp);
for (int i = 0; i < entities.Length; i++) {
var entity = entities[i];
var meshInfo = em.GetComponentData<MaterialMeshInfo>(entity);
if (meshInfo.Mesh > 0) {
var mesh = gfx.GetMesh(meshInfo.MeshID);
//UnregisterMesh() is causing access violation in:
//ScriptableBatchRenderer::RenderMultipleMeshes(class RenderNodeQueue const &,struct BatchInstanceDataSRPB const *,int,class VertexInputMasks)
//gfx.UnregisterMesh(meshInfo.MeshID);
if (mesh) Object.Destroy(mesh); // this is not!?
}
if (_colliders.TryGetValue(entity, out var collider)) {
collider.Dispose();
_colliders.Remove(entity);
}
em.DestroyEntity(entity);
}
entities.Dispose();
}
Currently, I’m just leaving the call to UnregisterMesh commented out. I can’t tell if it’s happening immediately when this call is made, or some time later. I can try to supply more information if the request is fairly specific, but I’m pretty new to Unity and the stacktrace is really all I had to go by. I commented UnregisterMesh out of desperation, if someone could confirm this is in fact a bug or offer any insight into why this is happening (and how I could avoid it) I would be very grateful.
I have no idea how I would repackage this into a smaller demo project at this moment.
Windows 11 (up-to-date)
Unity 2022.3.29f1
Fairly basic settings (Outdoors Scene)
“Balanced” quality
Thank you for reading this novel.