-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Minimal Compute Shader Example #4834
Comments
For newer Godot builds you have to change: var shader_bytecode = shader_file.get_bytecode()
var shader = rd.shader_create(shader_bytecode) to: var shader_spirv = shader_file.get_spirv()
var shader = rd.shader_create_from_spirv(shader_spirv) |
Would be nice to also have an example on how to modify a texture with a compute shader. I tried something but wasn't able to use a texture created with the rendering device with a Control. (something like)
|
Here is a gist from another person who adapted the above sample to a more recent version of the engine. https://gist.github.com/winston-yallow/aab20fa437bfa3dd80bfb0ed6605d28e |
Here are some simple real-world applications of Compute Shaders that could be added to the godot-demo-projects repository:
|
Isn't this better done with standard fragment shaders like in the 2D Sprite Shaders demo? |
Yeah probably. I just listed them because these are simple and approachable problems which demonstrate aspects of compute shaders which almost everyone needs when developing their own:
|
I think there is value in showing how to do it in compute shaders. Not necessarily for the image filters listed, but in a more general sense. Manipulating textures this way has quite a few advantages (for example only regenerating them on demand) and can be used for stuff like generating flow maps for fluid sims. |
I'm trying to achieve part of what is commented, share a texture between the compute pipeline and a viewport, but without success. The gist with the updated code was very helpfull to get basic compute shader up and running, but I'm really stuck on sharing a texture. Any news/example/something on that? I tried several things: It seems that maybe resources can be only shared from local rendering device to RenderingServer but not viceversa? If so, it seems that approch 1 is somehow the way. But probably I'm totally wrong altogether (very shallow insights). |
Right now it isnt possible to share resources between RenderingDevices. It is something we plan on adding in the future, but haven't had time to figure out quite yet. |
Thanks I understand. I'm guessing that is neither prepared to copy data between RenderingDevices within GPU realm, correct? Without doing GPU->CPU->GPU? |
Not yet, no. |
I'm trying to render a bunch of similar meshes over a area. I figured out the code above but I'm having trouble seeing what I need to add to draw meshes (from predefined triangles). Do I need to define a render pipeline, or does it fit into the compute pipeline. I saw some draw related functions that seem to match with a render pipeline, but I'm unsure of what I need to call when. |
The compute stuff is not made for rendering. I don't think there even is a way to share data from a compute shader to the main rendering device in Godot. You would need to pass it back the the CPU and then send it to the GPU again for rendering. If you are just looking to render many meshes that share the same geometry, then MultiMeshes may be better suited for this task than a compute shader. |
Using MultiMesh was my first thought, but instances don't work with Frustum culling. And since the objects are very dense and cover large areas (grass blades) having culling per-instance would help a lot with performance. So the solution seems to be to calculate the culled transform buffer and instance count in a compute shader and then let the renderer draw from it. I know how to do this in unity using the function "DrawMeshInstancedIndirect" which reads from a GPU buffer. If there is a way to make MultiMesh get its data from a GPU buffer that would be perfect, but that doesn't seem to be the case. |
You can use several MultiMeshInstances to reduce the number of draw calls while still benefiting from frustum culling and occlusion culling. This also makes distance-based culling more viable (as That said, Godot 4 automatically uses Vulkan instancing when possible, so you may find that using individual MeshInstance nodes is fast enough already. |
I have thought about using chunks of MultiMeshInstances, but if it is at all possible to use the rendering API to directly instantiate a meshes from a GPU buffer I would very much like implement that. Even if it ends up being unnecessary in a lot of cases, there will still be some where it is useful. |
We have plans to allow sharing GPU resources between the main RenderingDevice and user created devices (which includes using compute buffers for indirect drawing) however, we have pushed this feature to 4.1 or 4.2 as we have to prioritize other features for 4.0. for now you are stuck copying data back to the CPU from compute shaders if you want to use it. |
Ok cool, until that time I'll poke around the source and see what I can figure out. |
Feel free to join us over at chat.godotengine.org if you have questions or want to discuss the source in more detail! We wouldn't oppose extending the API for 4.0 if we had someone interested and motivated to do the work. |
Ok, sounds good! I'm very much still a novice when it comes to GPU related stuff and don't know how much time I can spend on this, but I'll definitely share if I get something to work. |
An example like this would also show real world usage of Compute Shaders in games: https://youtu.be/PGk0rnyTa1U?t=682 - 1M+ dust particles are spawned with no performance hit and react to the pull force of the world position of the vacuum cleaner (the project from the video is open-source, could be migrated from Unity to Godot). |
Interesting example, but syncing the texture data with the CPU every frame would likely result in too much lag. |
This should already be achievable in 4.0.alpha with GPUParticles3D and attractors + collision, without needing custom shaders 🙂 |
@Calinou but how to achieve something like the below with the proposed GPUParticles + Attractors? https://github.com/SebLague/Super-Chore-Man/blob/4b96e829d2d61fda9133c3dec5cd38256beaf11e/Assets/Scripts/Particles/DustCompute.compute#L13
The compute shader keeps uniforms to keep track of the cleaning progress, which communicates with the GameObject and updates the progress text in the UI each frame. |
How about enable Then binding an var img_tex: ImageTexture
var u = RDUniform.new()
u.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
u.binding = 0
u.add_id(img_tex.get_rd_texture_rid()) I think that covers most use-cases that require updating storage images by compute shader, for example, calculating ocean height fields with FFT by compute shader and apply the result in shader material. I do not see the point to use a local |
I just implemented these APIs in my fork huisedenanhai/godot@32a05a5 For testing, I created a simple compute shader. It initializes an image with uv coords. #[compute]
#version 450
layout(local_size_x = 32, local_size_y = 32) in;
layout(set = 0, binding = 0, rgba32f) writeonly uniform image2D target_image;
void main() {
ivec2 index = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(target_image);
if (index.x >= size.x || index.y >= size.y) {
return;
}
vec2 uv = (vec2(index) + 0.5) / vec2(size);
imageStore(target_image, index, vec4(uv, 0, 1.0));
} The ImageTexture should be created with proper usage bits var usage = RenderingDevice.TEXTURE_USAGE_STORAGE_BIT\
| RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT\
| RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT
var tex = ImageTexture.create_from_image_with_usage(image, usage) Then dispatch the compute shader to initialize the ImageTexture, and attach the exact same texture to a shader material as albedo. No need to copy data between GPU and CPU back and forth. I can make a PR if anyone like this. |
@huisedenanhai that's really cool, but I think it's a bit offtopic for a Godot documentation issue. The best way to get this into Godot would probably be to open a detailed proposal (and mention there that you already implemented this!) |
@huisedenanhai Reduz and I discussed your commit on RocketChat. The TLDR is that your API looks pretty good but we think we will go in a slightly different direction. But it is too early to decide now as we are in the middle of reorganizing the rendering code to make this sort of thing easier. If you want to discuss further feel free to open a proposal and/or join us on RocketChat
|
I agree with reduz. What I implemented is not the full solution for bridging RD RID with RenderingServer. Actually I tried to implement registering RD RID to texture storage before exposing RD RID from Texture, but it is not very easy at a glimpse. The relation between RID and RD RID is not a one-to-one mapping. A texture may hold two RD RID, the other one is for the SRGB view when the format supports it. The texture_get_rd_rid is always needed, even if there is some way to wrap a RD RID to resources RID. The compute shader might want to access ImageTextures loaded from disk, as a mask or whatever. Sorry for being off the topic. I did not notice this is a doc-issue. I will head to RocketChat if I have more for discussion. I will open a proposal after the rendering reorganization is done, if needed. |
Can someone explain how to run multiple shader passes in this example? Here is code as i understand this flow
i use constant to choose stage, maybe there is better way to achive this?
|
Fixed by #6159, I guess. |
Are there any updates on the sharing buffers between rendering devices? Or a task/issue? I feel like this really opens up what is possible with compute shaders, as the current workflow forces you to go gpu (compute) -> cpu -> gpu (render) which can be quite limiting. |
Have there been any updates on this? I am also trying to experiment with GPU-based instancing using the particles system and writing position data based on image textures, and it would be great to have a way to pass things from GPU to GPU. |
Going from gpu to cpu should already work with buffers. https://docs.godotengine.org/en/stable/tutorials/shaders/compute_shaders.html#retrieving-results |
The issue is more GPU -> GPU. I've raised a proposal here: godotengine/godot-proposals#6989 |
Your Godot version:
4.0 dev
Issue description:
Before 4.0 alpha releases we will need to put together some tutorials on using the new rendering device API. For starters we should write a compute shader tutorial that explains the below code:
And compute.glsl
The text was updated successfully, but these errors were encountered: