Godot Version
4.5.1
Forward+
Question
Hi everyone,
I am developing a real-time spray-painting mechanic using Decals in Godot 4.x. I’ve encountered a significant bottleneck where the only method that successfully renders updates in-game is also causing severe performance degradation and eventual GPU driver hangups.
The Problem
To reflect CPU-side Image changes on a Decal, I am forced to use: texture_albedo = ImageTexture.create_from_image(canvas_image)
While this works visually, it is a destructive workaround for a real-time use case. On integrated graphics (Intel Iris/HD), calling this at 20-30 FPS causes:
-
Frame Stutters: Frequent spikes, likely due to Godot re-packing the global Decal Atlas and generating new RIDs.
-
Driver Timeout (TDR): After 30-60 seconds of continuous painting, the GPU hangs/crashes, despite no detectable spikes in VRAM or total texture memory usage.
The “Ghost Update” Issue
I have attempted more performant, “in-place” update methods to avoid generating new RIDs, but they fail to update the Decal visually:
-
RenderingServer.texture_2d_update(): The data reaches the GPU (verified viaimage.save_png()and checking the texture in the inspector), but the Decal itself remains unchanged or invisible in the 3D world. -
canvas_texture.update(canvas_image): Similar to the RenderingServer method, the underlying resource updates, but the Decal does not refresh its visual representation.
It appears that Decals only “notice” a texture change if the texture_albedo property is assigned an entirely new ImageTexture object, which triggers the expensive Atlas re-bake.
Specific Question
Is there a supported way to update a Decal’s texture data in-place without creating a new RID or forcing a full Atlas re-pack?
Specifically, how can I notify the Decal/RenderingServer that the existing texture_albedo RID has new data so it can refresh its position in the Atlas efficiently, rather than treating it as a brand new resource?