floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
7.11k stars 501 forks source link

Metal error when using swapchain pass twice #1140

Closed terrybrash closed 4 weeks ago

terrybrash commented 4 weeks ago

On Mac, doing a swapchain pass twice prints an error/warning: Each CAMetalLayerDrawable can only be presented once!

This doesn't happen on Windows using the D3D11 backend. It's not clear if this is a bug or just misuse of sokol.

I've modified the "clear" example in sokol-rust to reproduce the issue: https://github.com/terrybrash/sokol-rust/commit/f153ae8448fb852caedb0eb38e3f788779d16d58

terrybrash commented 4 weeks ago

Does Metal only allow using the swapchain once per frame?

floooh commented 4 weeks ago

It's expected behaviour. It's probably not documented anywhere and also not caught by the sokol-gfx validation layer, but there should only be one render pass per swapchain (or in general: render target) and frame.

For offscreen render targets, doing multiple passes to the same render target is at most less efficient, but for rendering to the window system swapchains there are additional restrictions (as you noticed with that Metal error).

Basically, you shouldn't think of render passes as a way to group draw calls with similar render state (which was often the case in 'traditional' DX9 style engines - those often had separate passes to split opaque and alpha rendering into the same render target), but instead as nodes in a dependency tree of render targets, with a final swapchain pass at the root which depends on the entire node tree.

TL;DR: rule of thumb: one render pass per render target (or swapchain) and frame :)

PS: before the 'render pass cleanup' this probably worked by accident because the 'present' call was in the final sg_commit() but with the render-pass cleanup this had to move into sg_end_pass() to allow rendering into multiple independent swapchains per frame. In any case, there shouldn't be a reason to do multiple render passes into the same render target.

terrybrash commented 4 weeks ago

Ok that makes sense. Thanks for the knowledge!