#Temp allocator invalidates other data

1 messages · Page 1 of 1 (latest)

lyric summit
#

I have this code updating a 10x10 texture:

Assert.AreEqual(tileTypeTex.format, TextureFormat.RG16);
NativeArray<byte> colors = new(2 * TEXTURE_RES * TEXTURE_RES, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

int idx = 0;
int xyMax = TEXTURE_RES - 1;
for (int ty = -1; ty < xyMax; ty++)
{
    for (int tx = -1; tx < xyMax; tx++)
    {
        int lx = blockData.x + tx;
        int ly = blockData.y + ty;
        var tilePtr = tilemap.TryGetPtr(lx, ly);
        var color = GetTileColor(tilePtr);
        colors[idx++] = (byte)(color.r);
        colors[idx++] = (byte)(color.g);
    }
}
tileTypeTex.SetPixelData(colors, 0);
tileTypeTex.Apply();

Right after this code, there is code updating meshes, for which data has been previously allocated inside a job with Allocator.TempJob. This mesh update code starts generating errors like this:
Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 12, VertexCount: 8
The erroneous indices are not deterministic.

If I change the allocator for the colors array to Allocator.TempJob allocator, there is no issue! Is this a facepalm moment? Or is there something peculiar with temp or temp job allocations that I don't know about?

#

The code runs a job per block of tiles, using an IJobParallelFor. If the mesh data requires updating, this job stores mesh data in unsafe arrays allocated with Allocator.TempJob (inside the job!) which are used to update the meshes.

A high-level overview:

// launch job somewhere
...
job.Complete();
for (int i = 0, l = numBlocks; i < l; ++i)
{
    var meshOutput = meshOutputs[i];
    if (!meshOutput.tris.IsCreated)
        continue;
    WriteTexture(...);
    UpdateMeshes(..., in meshOutput);
    meshOutput.Dispose();
}

The mesh update code (they're unsafe arrays, hence the safety handle juggling):

mesh.Clear(true);
var verts = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<float3>(meshData.verts.Ptr, meshData.verts.Length, Allocator.None);
var tris = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<int>(meshData.tris.Ptr, meshData.tris.Length, Allocator.None);
var uv0 = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<float2>(meshData.uv0.Ptr, meshData.uv0.Length, Allocator.None);
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref verts, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref tris, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref uv0, AtomicSafetyHandle.GetTempUnsafePtrSliceHandle());
mesh.SetVertices(verts);
mesh.SetIndices(tris, MeshTopology.Triangles, 0);
mesh.SetUVs(0, uv0);
lyric summit
#

Okay, I was being dumb. I wasn't always writing in my output array, but at the end of the job I always copied the output array back into the original array. So overwriting the data with garbage values.

Facepalm moment! 🤦‍♂️ UnityChanwow

#

The temp vs. temp job allocation mattered because the original values are not zero-initialized

#

(which I did on purpose to catch mistakes, there is some irony here)