Conversation
src/backends/cg.rs
Outdated
| self.buffers.push(Buffer::new(self.width, self.height)); | ||
| // This should have no effect on latency, but it will affect the `buffer.age()` that | ||
| // users see, and unbounded allocation is undesirable too, so we should try to avoid it. | ||
| tracing::warn!("had to allocate extra buffer in `next_buffer`, you might be rendering faster than the display rate?"); |
There was a problem hiding this comment.
I see this warning printed a few times when I run the animation example. Presumably it shouldn't be if the example is using things correctly?
And animation is just calling next_buffer() on WindowEvent::RedrawRequested, so that seems correct enough.
There was a problem hiding this comment.
WindowEvent::RedrawRequested is actually currently emitted wrong on macOS, when resizing it may be issued twice in a single frame. So getting the warning once after resizing is "expected". We could lower it to a debug! when self.buffers.len() == 3 until the Winit issue is fixed?
Playing around with it a bit I did once manage to get the warning issued a bunch of times in a row, but now I can't reproduce it, so not sure what that's about.
There was a problem hiding this comment.
Yeah, I guess if it's a bug in winit, then it doesn't really make sense to log as a warning since there's no obvious way for the user of the library to actually fix it.
Leaving it as debug! with a comment to change this after wiinit is fixed sounds good.
There was a problem hiding this comment.
I've added a debug! comment now, could I get you to try again and see if you get the warning?
There was a problem hiding this comment.
Seems to still be producing warnings:
ian@Ians-Mac-mini-5 softbuffer % RUST_LOG=debug cargo run --example animation
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/examples/animation`
2026-03-12T03:26:24.358343Z DEBUG winit::ActiveEventLoop::create_window{window_attributes=WindowAttributes { inner_size: None, min_inner_size: None, max_inner_size: None, position: None, resizable: true, enabled_buttons: WindowButtons(CLOSE | MINIMIZE | MAXIMIZE), title: "winit window", maximized: false, visible: true, transparent: false, blur: false, decorations: true, window_icon: None, preferred_theme: None, resize_increments: None, content_protected: false, window_level: Normal, active: true, cursor: Icon(Default), parent_window: None, fullscreen: None, platform_specific: PlatformSpecificWindowAttributes { movable_by_window_background: false, titlebar_transparent: false, title_hidden: false, titlebar_hidden: false, titlebar_buttons_hidden: false, fullsize_content_view: false, disallow_hidpi: false, has_shadow: true, accepts_first_mouse: true, tabbing_identifier: None, option_as_alt: None, borderless_game: false } }}: winit::platform_impl::macos::app_state: had to queue event since another is currently being handled event=WindowEvent { window_id: WindowId(40792015488), event: Resized(PhysicalSize { width: 800, height: 600 }) }
2026-03-12T03:26:24.359300Z DEBUG winit::ActiveEventLoop::create_window{window_attributes=WindowAttributes { inner_size: None, min_inner_size: None, max_inner_size: None, position: None, resizable: true, enabled_buttons: WindowButtons(CLOSE | MINIMIZE | MAXIMIZE), title: "winit window", maximized: false, visible: true, transparent: false, blur: false, decorations: true, window_icon: None, preferred_theme: None, resize_increments: None, content_protected: false, window_level: Normal, active: true, cursor: Icon(Default), parent_window: None, fullscreen: None, platform_specific: PlatformSpecificWindowAttributes { movable_by_window_background: false, titlebar_transparent: false, title_hidden: false, titlebar_hidden: false, titlebar_buttons_hidden: false, fullsize_content_view: false, disallow_hidpi: false, has_shadow: true, accepts_first_mouse: true, tabbing_identifier: None, option_as_alt: None, borderless_game: false } }}: winit::platform_impl::macos::app_state: had to queue event since another is currently being handled event=WindowEvent { window_id: WindowId(40792015488), event: Focused(false) }
2026-03-12T03:26:27.004819Z DEBUG softbuffer::backends::cg: had to allocate extra buffer in `next_buffer`, this is probably a bug in Winit's RedrawRequested
2026-03-12T03:26:27.011200Z WARN softbuffer::backends::cg: had to allocate extra buffer in `next_buffer`, you might be rendering faster than the event loop can handle?
2026-03-12T03:26:27.017192Z WARN softbuffer::backends::cg: had to allocate extra buffer in `next_buffer`, you might be rendering faster than the event loop can handle?
2026-03-12T03:26:27.023131Z WARN softbuffer::backends::cg: had to allocate extra buffer in `next_buffer`, you might be rendering faster than the event loop can handle?
There was a problem hiding this comment.
Hmm, are you doing anything with the window? Resizing it? Moving the cursor a lot? Or does it just happen after time?
There was a problem hiding this comment.
The DEBUG and two WARN lines seems to happen pretty immediately (running the animation example on Tahoe 26.3.1 on an M1 Mac Mini). At least most of the time.
We currently create a new
Veceach timenext_bufferis called on macOS/iOS, which is inefficient, we should instead re-use previous buffers.Double-buffering seems to be enough here, but in degenerate cases such as the following:
The buffer is still referenced by QuartzCore somewhere, so we need to keep a (potentially infinite) queue of buffers around to be sure that we don't write to a buffer that's in use. Note that there is no way to wait for the buffers to be released since the release happens on the main thread (and besides, we probably don't want to wait either?).
All of this might be overly pedantic, I haven't yet found a case where the buffer is actually read from by QuartzCore while being the back buffer (unlike with
IOSurface).Tested on:
Should help with #83.
Extracted from #329 (since that one may be more difficult to land).