Update a meshFilter mesh directly into GPU memory

Hi there,

I’m using a compute buffer to change the vertices of a mesh. Then, I read this vertex data back into CPU code via myComputeBuffer.GetData() and update the mesh vertices with myMeshFilter.mesh.SetVertices().

This is working pretty well but the GetData method is a huge performance bottleneck in my situation: moving data back to the CPU is slow by design, and the GetData method have to wait for the GPU to complete all the pending dispatched kernels. In addition, the MeshFilter will have to send the updated mesh to the GPU again.

One solution would be to use the buffer into a rendering shader and move the vertices in place in the vertex method. This is what I do in HairStudio but that won’t work here, because I need the mesh to be renderable with any surface material.

It would be much faster if I could update the mesh that is stored on the GPU by the MeshFilter, directly from my compute shader (or by setting a compute buffer). Is there any way to do that?

1 Like

Thanks to GetNativeBufferPtr methods, I can get the GPU memory pointer for the vertices of a mesh, and the GPU pointer of a compte buffer. But that alone does not solve my issue.

I would need one of the following:

  • assign a GPU memory pointer for mesh vertex buffer or a compute buffer,
  • copy data from a native buffer to the other without locking the CPU code,
  • write on a buffer using a native buffer pointer from the compute shader directly.

Is one of these solution possible in the actual API? Any other solution? ( @bgolus help!)

One way to do this, although probably work-consuming and error-prone, would be to use GetNativeBufferPtr but in a plugin, where you have access to Vulkan/D3D11/D3D12/OGL/Metal APIs. But that is a last resort imho, given the complexity.

Thank you for the idea. Do you think there is a way to copy data from a GPU buffer to another in such a plugin, without actually reading that data in the CPU code? If it is only a matter of calling such a function, with the pointers as arguments, it may be no big deal at the end of the day.

Of course, it would be wonderfull to have the feature in the Unity API.

In the meantime, I’ve implemented the feature inside a custom shader, and the performance difference is an order of magnitude (100 to 1000fps). But I really need this tool to be useable with any shader.

@methusalah, yes, there’s a way for sure. Even without native plugin you can copy data via Compute Shader. You need to define structure for your mesh (you can check it up with RenderDoc or unity mesh preview and then use it as StructuredBuffer/RWStructuredBuffer. [pos(float3), normals(float3), uv1(float4), uv2(float4)…] is common layout. But be careful, I think unity can change the layout when mesh is changed by CPU with SetNormals/SetVertices e.t.c). I can’t say for sure, but there should also be indices buffer, AFAIK unity using separate buffers for indices/vertices.

You can also use DX11’s CopyResource, ComputeBuffer and Mesh Data is basically just a buffers.

Even more, you can try write directly to mesh buffer! This would save you 1 copy operation and memory bandwidth

Ok but how do you pass the mesh vertex buffer into your compute shader? AFAIK you can only pass compute buffers and not a pointer.

Can you give me details about the implementation?

methusalah999 oh, I’ve missed you can’t do that without native plugin and DX bind. But can you draw your mesh with DrawMeshProcedural straight from ComputeBuffer? May be this would help

In case you’ll go for DX11 native plugin there’s CopyResource function for copy two ID3D11Buffer* (which inherits ID3D11Resource*). And CSSetShaderResources for compute shader, you’ll need to declare buffer register explicitly like StructureBuffer _MyMesh : register(u1);

1 Like

As @Meetem mentioned, you’d use CopyResource function to copy one GPU buffer to the other. Although to be honest I am not sure if this will work that easily with DX11 buffers as when they are created, different sets of flags are set for various buffers (vertex, index, structured, etc.) and I am not sure how compatible they are with each other.

Anyway, if you decided to give plugins a try here (GitHub - Unity-Technologies/NativeRenderingPlugin: C++ Rendering Plugin example for Unity) is a core Unity sample on how to implement custom rendering plugin. You should be able to at least easily experiment with it.

Thanks. It seems that I will have to learn and experiment a lot before ending up with the simplest plugin ever ^^