Skip to content

Implement MeshRD for RenderingDevice buffers#117836

Open
maidopi-usagi wants to merge 1 commit into
godotengine:masterfrom
maidopi-usagi:impl_meshrd
Open

Implement MeshRD for RenderingDevice buffers#117836
maidopi-usagi wants to merge 1 commit into
godotengine:masterfrom
maidopi-usagi:impl_meshrd

Conversation

@maidopi-usagi

@maidopi-usagi maidopi-usagi commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Closes (partially) godotengine/godot-proposals#7209.

This PR adds MeshRD, a low-level Mesh resource for indirect procedural GPU meshes.

The basic idea is simple: users create the RenderingDevice buffers themselves, pass those RIDs to MeshRD.add_surface(), then fill the buffers from compute shaders. MeshRD makes the result usable as a normal Mesh resource, so it can be assigned to MeshInstance3D.mesh.

This avoids the GPU -> CPU -> GPU roundtrip that ArrayMesh requires, and keeps ownership clear: MeshRD does not allocate, own, free, expose, or serialize the buffers passed to it. The caller owns all RD buffers.

Since #118973 already exposes existing mesh surface RD buffer RIDs, this PR no longer tries to cover that use case. It only focuses on creating a mesh from caller-owned buffers and drawing it indirectly.


Tested locally on macOS arm64.

Demo project:

https://github.com/maidopi-usagi/godot_meshrd_demo

Includes the following demos:

Marching Cube Metaball Procedural ClipMap Terrain Animated Ribbons

API Overview

MeshRD

Method Description
add_surface(format, primitive, vertex_count, vertex_buffer, aabb, attribute_buffer, index_count, index_buffer, ...) Attach caller-owned RD buffers as a mesh surface.
surface_set_indirect_buffer(surf_idx, indirect_buffer, offset) Set or replace the indirect draw buffer for a surface.
clear_surfaces() / surface_remove(surf_idx) Surface management.

Minimal Usage

var rd := RenderingServer.get_rendering_device()

var vb := rd.vertex_buffer_create(vertex_buffer_size, PackedByteArray(), RenderingDevice.BUFFER_CREATION_AS_STORAGE_BIT)
var ib := rd.index_buffer_create(max_indices, RenderingDevice.INDEX_BUFFER_FORMAT_UINT32, PackedByteArray(), false, RenderingDevice.BUFFER_CREATION_AS_STORAGE_BIT)
var ind := rd.storage_buffer_create(20, PackedByteArray(), RenderingDevice.STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT)

var mesh_rd := MeshRD.new()
mesh_rd.add_surface(
    Mesh.ARRAY_FORMAT_VERTEX | Mesh.ARRAY_FORMAT_INDEX,
    Mesh.PRIMITIVE_TRIANGLES,
    max_vertices,
    vb,
    aabb,
    RID(),
    max_indices,
    ib,
    null,
    Vector4(),
    ind,
)

Disclaimer: AI was used to resolve the conflicts and update the example demo project. The core changes and documentations were written by hand.

@AThousandShips AThousandShips added this to the 4.x milestone Mar 25, 2026
@maidopi-usagi maidopi-usagi force-pushed the impl_meshrd branch 5 times, most recently from fcf3140 to e62fc91 Compare March 25, 2026 18:26
youfch added a commit to youfch/godot that referenced this pull request Mar 26, 2026
@maidopi-usagi maidopi-usagi marked this pull request as ready for review March 26, 2026 20:27
@maidopi-usagi maidopi-usagi requested review from a team as code owners March 26, 2026 20:27
@maidopi-usagi maidopi-usagi changed the title [Draft] Add MeshRD for RenderingDevice Add MeshRD for RenderingDevice Mar 26, 2026
@maidopi-usagi maidopi-usagi changed the title Add MeshRD for RenderingDevice Implement MeshRD and SurfaceDataRD Mar 26, 2026
@pcwalkerpro

This comment was marked as off-topic.

@Zireael07

This comment was marked as off-topic.

@clayjohn

Copy link
Copy Markdown
Member

I think the exposed API needs some work, especially in light of godotengine/godot-proposals#14741.

Right now the API suffers a few problems:

  1. Its needlessly complex. There appears to be several ways to use it (i.e. create buffers and add surface, add_surface_storage to create for you, create a normal surface and request buffers back, create a RS::SurfaceDataRD). Further, from the example above, it appears the basic usage is very complicated and requires the user to be responsible for creating some buffers and not others, and the API needs certain functions to be called in a certain order. I strongly suggest taking a step back and massively simplifying this API. Trying to provide several ways of doing the same thing makes this code way more complicated than it needs to be.

  2. It exposes way to much low level interface into user-space. After reading through the code for a few minutes I can't understand why this creates a complex MeshRD class and a complex RS::SurfaceDataRD class and then exposes both to users. In general the RS should never return data to users. Returning an entire mesh is out of the question. Again, try to think about what is actually needed for this API to operate and remove the parts that are unnecessary.

  3. Way too much complexity deep in the RenderingServer. It looks like this API can automatically allocate buffers both in the MeshRD class and in the MeshStorageRD class. And both cases need to be handled uniquely. And the API tries to enable the user to access those buffers in both cases. I appreciate that you attempted to make ownership clear and automatic. But the current state is prone to a lot of issues, but from a usability perspective and from a maintenance perspective. MeshStorageRD should never need to coordinate with a high level resource. Data should only flow one way, users create and configure a resource using the Scene-level API and then the information flows into the RenderingServer and gets handled there. At most, MeshStorageRD should allocate internal buffers when it needs them. It should never allocate quietly allocate buffers that will be exposed to user-space in cases where those buffers may or may not have been supplied by user-space.

For the simplest case (dynamically modifying a Mesh, users can just retrieve the RD buffers and manipulate the mesh from a compute shader (once godotengine/godot-proposals#14741 is merged). So keep in mind that this API should be supporting a different workflow and a different subset of tradeoffs. As I mentioned in godotengine/godot-proposals#7209, I'm pretty sure the majority of users will be happy with just having access to the raw buffers godotengine/godot-proposals#14741.

The users that need more likely need:

  1. Ability to draw with a dynamic or unknown amount of vertices
  2. Indirect drawing (especially if vertex count is dynamic, since reading back vertex count every frame defeats the purpose of having a Mesh RD)

My gut feeling is that a MeshRD API should be a very thin API wrapping a few RD functions to create a mesh from existing buffers (vertex, index + indirect) and leaves the responsibility with managing the buffers to the user. I feel that building up all of this very high level "automagic" API is counter productive for a feature that already requires users to write very complex compute shaders.

@Deltt

Deltt commented May 31, 2026

Copy link
Copy Markdown

As someone whos been excitedly waiting for these kinds of features, i definitely agree with what clayjohn says;

buffer access + indirect draw would be all that is needed in terms of API, any sort of further abstraction would be kind of unnecessary if not even a potential limitation

@maidopi-usagi maidopi-usagi changed the title Implement MeshRD and SurfaceDataRD Implement MeshRD for RenderingDevice buffers Jun 19, 2026
@maidopi-usagi

maidopi-usagi commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Refactored this PR around the narrower indirect procedural GPU meshes use case.

MeshRD no longer tries to manage or expose mesh buffers. Users create the RenderingDevice buffers themselves, pass the buffer RIDs to MeshRD.add_surface(), then update those buffers from compute shaders.

Since #118973 already exposes RD buffer RIDs for existing mesh surfaces, I removed that overlapping workflow from this PR’s old code, and kept this focused on creating a mesh from caller-owned buffers.

The demo project has also been updated to use the new API

@maidopi-usagi maidopi-usagi force-pushed the impl_meshrd branch 2 times, most recently from 44bc38d to 7e77e04 Compare June 19, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants