Changing Mesh Vertex buffer with AMD graphics cards

Hi, I’ve encountered a predicament related to the vertex buffer provided by Unity and AMD graphics cards. Specifically, I can’t get a simple compute shader to modify the vertex data of a mesh on these graphics cards. It only manages to change the first vertexData element, whereas on other GPUs, it works as expected, modifying all vertices.

Here is the simple test code:

Compute Shader:

#pragma kernel TestKernel

struct MeshData
{
    float3 pos;
    float3 normal;
    float4 tangent;
};


uint expectedNumberOfThreads; //Each thread represents a vertex

[numthreads(64, 1, 1)]
void TestKernel(uint3 id : SV_DispatchThreadID, RWStructuredBuffer<MeshData> meshData)
{
    const uint threadId = id.x;
    if (threadId >= expectedNumberOfThreads) return;

    meshData[threadId].pos = float3(1.0, 2.0, 3.0);
    meshData[threadId].normal = float3(1.0, 2.0, 3.0);
    meshData[threadId].tangent = float4(1.0, 2.0, 3.0, 4.0);
}

C#:

    public class IT_VertexBufferTest : MonoBehaviour
    {
        [SerializeField] private ComputeShader _computeShader;
        
        public struct MeshData
        {
            public Vector3 position;
            public Vector3 normal;
            public Vector4 tangent;
        }

        [SerializeField] private Mesh _targetMesh;

        
        [ContextMenu("TestMeshComputeShader")]
        private void TestMeshComputeShader()
        {
            _targetMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
            var vertexAttributeStream = _targetMesh.GetVertexAttributeStream(VertexAttribute.Position);
            var targetMeshVertexBuffer = _targetMesh.GetVertexBuffer(vertexAttributeStream);
            
            _computeShader.SetInt("expectedNumberOfThreads", _targetMesh.vertexCount);
            _computeShader.SetBuffer(0, "meshData", targetMeshVertexBuffer);
            var numberOfThreadGroups = Mathf.CeilToInt(_targetMesh.vertexCount / 64f);
            _computeShader.Dispatch(0, numberOfThreadGroups, 1, 1);

            // Read back the data
            var data = new MeshData[_targetMesh.vertexCount];
            targetMeshVertexBuffer.GetData(data);
        }
    }

I’ve tested in both, Unity 2021.3.13f1 and 2023.2.20f1

Hi!
Internally, mesh buffers are not created as structured buffers but as simple raw buffers. This means that your compute shader need to use RWByteAddressBuffer to bind the vertex buffer. Check the attached compute shader that animates the vertices in a vertex buffer that contains positions only. You need to compute the address of the vertex attribute and use Load/Store functions to access the data. You also need to Dispose targetMeshVertexBuffer Unity - Scripting API: Mesh.GetVertexBuffer after using it to avoid leaks.
WaveMeshAnimation.txt (611 Bytes)

Hi!

Thank you for your prompt reply!!

Interesting! I’ve based mine on this.

And whoops yeah I forgot to dispose targetMeshVertexBuffer for this quick test, but in general we are! Thanks for the reminder.

I’ll give that way a go, and report back :ok_hand: