Post

Replies

Boosts

Views

Activity

Reply to Generating vertex data in compute shader
Follow up on this: Mesh shaders were not viable for my use case here as it involves a triple-nested for loop over 10,000+ terrain blocks for each thread, ideally for thousands of chunks of terrain. Using a compute shader to generate vertices is working great. The biggest difference from the initial approach I described is cutting out the step where I synchronize with the CPU and copy vertex and index data back into another correctly-sized buffer. This is unnecessary, and if you can afford a bit of extra memory just specify the size when you call set_vertex_buffer in the indirect command encoder. This way, the generated vertex and index buffers never have to be touched by the CPU at all and can be set to storage mode private. I would think about combining them all into one buffer, but there doesn't seem to be a set_vertex_buffer command that can be used in the kernel that allows for specifying offset. All in all, this seems like a fine approach for me. Also: Tier 2 Argument Buffers are amazing! A game changer. One it clicks it's very natural and makes development simpler.
Jul ’23
Reply to Generating vertex data in compute shader
Mesh shaders are fascinating but appear to be about generating - or modifying existing - geometry each frame. Whereas I need only to generate the geometry when new terrain is loaded in, and for it to use buffer memory to avoid repeating the work. It sounds like compute shader and temporary buffers are the way to go.
Jul ’23
Reply to Generating vertex data in compute shader
Reusing one big buffer instead of many seems like a great idea. Less moving parts the better here. Why the vertices are expensive to compute is mostly a question of scale. For instance, with indirect draw calls I can handle 4000+ chunks of terrain and 25 million+ vertices at 60 fps. With much lower terrain distances the meshing on the CPU can keep up fine, but when I push it there is a lot of frame dropping when moving over the terrain and generating meshes for dozens or hundreds of chunks. Part of this is that my meshing is single-threaded on the CPU, but my experience with Swift multi-threading is so far hit and miss for this kind of thing. As such, parallelism is the entire point of trying to offload this to a compute shader. The process of vertex generation is pretty standard for block/Minecraft-style terrain. We loop through all the blocks in a chunk, and if a block is solid, we check if any of its neighbours are air, and therefore if we should put a quad opposite it. Roughly: for y in i..<CHUNK_SIZE_Y { for z in i..<CHUNK_SIZE { for x in i..<CHUNK_SIZE { let index = blockIndex(x, y, z) let block = block(at: index) if block.type != BLOCK_TYPE_AIR { for faceOffset in blockFaceOffsets { let neighbourPosition = chunkPosition + faceOffset if shouldDrawFace(at: neighbourPosition, in: chunk) { // add interleaved vertices plus indices for the face } } } } } } There is no doubt room for optimization in what I am doing, but there is also the limitation of not doing this in parallel. I think it's appropriate, since each result does not depend on any other result. I'll experiment with using a single buffer for copying the compute shader results + offsets. Also curious if there are any other obvious approaches I'm missing to take advantage of the parallelism of GPU shaders!
Jul ’23
Reply to Metal debugger results I can't explain (geometry shows in debugger not final drawable)
This may have been posted prematurely. I found that by removing the skyboxRenderPass that was running after Render Pass B, I now see the expected geometry. This issue doesn't occur with Render Pass A, nor in any previous experimentation I've done. Guessing it has something to do with the particularities of the indirect rendering I am doing in Render Pass B. If anyone reads this and has a clear explanation for why, I would be interested. But the issue is solved, at least practically speaking for me.
Jul ’23
Reply to Tier 2 Argument Buffers in Swift?
Hi. I confirmed that this works. Thank you very much! One note: it does not seem possible to share ArgumentBuffer struct in the way you recommend. Example: Say you have 3 files: Renderer.swift ShaderTypes.h (BRIDGING HEADER) ArgumentBuffers.h Using the example struct struct VertexShaderArguments { device Uniforms &uniforms; device Material *materials; }; Whether this is declared directly in the bridging header, or in the other header which the bridging header then imports, it will never be visible or able to be referenced in the Swift file. My guess was that this has to do with the fact that the struct specifies address space, while other structs that I share successfully between Metal Shader Language and Swift do not. In either case, using your explanation I can have one Swift struct and one C struct for any Tier 2 argument buffer. Although sharing a struct would indeed be more convenient. I really, really appreciate the explanation!
Jun ’23
Reply to Bindless/GPU-Driven approach with dynamic scenes?
Yes, I understand that. The part I am stuck on is whether anything like this could be done with procedural geometry, e.g. chunks of terrain that may have a totally different number of vertices as the ones from previous frames. This would results in a vertices array/buffer with either some old vertices or bad memory, or constantly moving array elements around to ensure no blank spots and recreating the buffer, which sounds too expensive. I can solve the problem with a models buffer instead of a vertices buffer, because I can designate the first n elements as representing chunks of terrain and update them as needed. But I can do no such thing, at least as far as I can tell, with a shared vertex buffer. Thanks for your response and I would appreciate any other thoughts. I am indeed a beginner but using Metal has been a treat.
Jun ’23
Reply to Big Sur - LaunchAgents - Load error 5: input/output error
Had the same thing when trying to start a LaunchAgent with this plist file: [...] XML version, etc. <plist version="1.0"> <dict> &#9;<key>Label</key> &#9;<string>gnu.emacs.daemon</string> &#9;<key>ProgramArguments</key> &#9;<array> &#9;&#9;<string>/usr/local/Cellar/emacs-mac/emacs-27.1-mac-8.0/Emacs.App</string> &#9;&#9;<string>--daemon</string> &#9;</array> &#9;<key>RunAtLoad</key> &#9;<true/> </dict> </plist>
Nov ’20