Skip to content
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

Reminder: update WebGPU swapchain code in sokol_app.h #1116

Open
floooh opened this issue Sep 30, 2024 · 13 comments
Open

Reminder: update WebGPU swapchain code in sokol_app.h #1116

floooh opened this issue Sep 30, 2024 · 13 comments
Assignees

Comments

@floooh
Copy link
Owner

floooh commented Sep 30, 2024

...use the new surface functions instead of the deprecated swapchain functions.

See the updated wgpu_entry_* code in sokol-samples.

PS: while at it, also add 'native' support to the sokol_app.h WebGPU backend so that it is possible to use sokol_app.h with Dawn. It's not much code needed to connect WebGPU to the OS window system, see:

https://github.com/eliemichel/glfw3webgpu/blob/main/glfw3webgpu.c

@floooh
Copy link
Owner Author

floooh commented Oct 1, 2024

NOTE: on macOS this requires to drop MTKView because WebGPU wants a CAMetalLayer object to setup the swapchain surface, but MTKView doesn't seem to allow access to its internal CAMetalLayer.

...so probably better to move the 'native Dawn support in sokol_app.h' stuff into a separate update after the bindings cleanup.

@hb3p8
Copy link

hb3p8 commented Oct 11, 2024

@floooh Hi! Did you have a chance to start a CAMetalLayer thing yet? Maybe I can help if you could tell me roughly which parts of sokol app we need to adjust?

@floooh
Copy link
Owner Author

floooh commented Oct 11, 2024

Not yet, in any case, search for _sapp_macos_view and _sapp_ios_view in sokol_app.h these are 'subclasses' of MTKView and this stuff needs to be ripped out.

Also here's a (too simple) example which just uses a fixed-size CAMetalLayer without also managing depth-stencil and msaa-surface.

https://github.com/floooh/sokol-samples/blob/master/glfw/metal-glfw.m

E.g. what's missing is:

  • also create a depth-stencil-surface and if sample_count > 1 a MSAA surface
  • on window size change, discard and create all surfaces (I think the lifetime problems I had been seeing in earlier attempts are now solved inside sokol-gfx, because sokol-gfx convervatively holds a reference to all swapchain surfaces until they are guaranteed to be no longer in flight)

I think you can also look at the D3D11 and WebGPU swapchain management code both in sokol_app.h and in the 'raw' D3D11 and WebGPU samples for inspiration because their swapchain management looks quite similar, e.g.:

@floooh
Copy link
Owner Author

floooh commented Oct 11, 2024

Argh, I had written a comment here that was for another issue (deleted now), sorry for the confusion :D

@floooh
Copy link
Owner Author

floooh commented Oct 11, 2024

PS: I guess to actually drive the frame callback we might also need a DisplayLink object... (which isn't needed in the GLFW example because that just runs the rendering in a loop).

I had tinkered with CVDisplayLink in the abandondend multiwindow branch here:

https://github.com/floooh/sokol/blob/sapp-multiwindow/sokol_app.h

...just search for CVDisplayLink and you'll find all the relevant places.

...or maybe we can continue to just hook into the NSView's drawRect method? Not sure tbh, don't know enough Cocoa for that...

sokol/sokol_app.h

Lines 4208 to 4222 in 38e4c9a

- (void)drawRect:(NSRect)rect {
_SOKOL_UNUSED(rect);
#if defined(_SAPP_ANY_GL)
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer);
#endif
_sapp_timing_measure(&_sapp.timing);
/* Catch any last-moment input events */
_sapp_macos_poll_input_events();
@autoreleasepool {
_sapp_macos_frame();
}
#if defined(_SAPP_ANY_GL)
[[_sapp.macos.view openGLContext] flushBuffer];
#endif
}

@floooh
Copy link
Owner Author

floooh commented Oct 11, 2024

...I think I used this documentation page as reference when I worked on the CVDisplayLink stuff in the multiwindow-branch:

https://developer.apple.com/documentation/metal/onscreen_presentation/creating_a_custom_metal_view?language=objc

...maybe googling around a bit with the keywords Metal and CADisplayLink or CVDisplayLink also helps, e.g. bringing things like https://www.delasign.com/blog/metal-animations-cadisplaylink/

@floooh
Copy link
Owner Author

floooh commented Oct 11, 2024

Hmm, also apparently the macOS specific CVDisplayLink is deprecated, and the common CADisplayLink is now supposed to be also used on macOS, but only since macOS 14 (which is too recent IMHO)... not sure what to do about that, probably best to use CVDisplayLink for a little longer if it is not available before macOS 14...

https://developer.apple.com/documentation/quartzcore/cadisplaylink?language=objc

@hb3p8
Copy link

hb3p8 commented Oct 11, 2024

At times like this I kind of appreciate Win32 API 😅 I'll make some attempts next week, will see if anything works!

@floooh
Copy link
Owner Author

floooh commented Oct 12, 2024

Btw, one thing I didn't think of when arguing that WebGPU can't be used together with MTKView.

Since MTKView is a subclass of NSView, maybe we can access the CAMetalLayer needed by WebGPU via the parent class NSView.layer member. But I'm not sure if it's as simple as that, because I think both the MTKView and the WebGPU swapchain code need to call the nextDrawable method on the CAMetalLayer and that might confuse the view. Worth a try though and would require only little code.

...maybe I get around trying that in a separate branch. Long term I think it's a better idea to get rid of MTKView because it was a constant source of regressions between macOS updates.

@hb3p8
Copy link

hb3p8 commented Oct 21, 2024

@floooh It works! So here is roughly what I have so far: #1136
In a nutshell, I've tried merge WGPU and Metal backends as much as possible.

  • Grabbed some helpers from emscripten one.
  • Created CAMetalLayer and used CVDisplayLink to make a render loop.
  • Uncommented _sapp_macos_poll_input_events for events to work (was a wild guess).
  • Made lots of silly mistakes along the way (likely still a lot).

Hope it helps a bit!

@floooh
Copy link
Owner Author

floooh commented Oct 29, 2024

Just linking this here as reminder in case we run into a similar issue with the new code (see comment at the bottom):

gfx-rs/gfx#2460 (comment)

@hb3p8
Copy link

hb3p8 commented Oct 30, 2024

Didn't noticed anything like this yet. Though I had to add manual sync with wgpuQueueOnSubmittedWorkDone and

  while (!IsFrameReady)
  {
    usleep(1000);
    wgpuInstanceProcessEvents ((WGPUInstance) sapp_wgpu_get_instance());
  }

Otherwise it would accumulate a multiple frames worth of work before finally blocking and waiting for it to be done.
Strangely on Windows it was not necessary.

@floooh
Copy link
Owner Author

floooh commented Oct 30, 2024

Hmm, that looks very hacky :D

But now that you say it, I've seen Dawn queuing up to 4 (or was it even 8?) frames. I noticed this when building my own 'buffer conveyor belt' in early sokol-gfx WebGPU backends (that conveyor belt got very long with 4 or 8 buffers in flight).

In the web browser this extreme frame latency doesn't seem to exists...

(this was also on macOS btw, I didn't try to get the native wgpu samples in sokol-samples run anywhere else yet).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants