Merge pull request #59 from thedjinn/disable-calayer-actions

Disable CALayer fade action when setting buffers
This commit is contained in:
Jeremy Soller 2023-01-06 09:06:51 -07:00 committed by GitHub
commit c0142e9faf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 1 deletions

100
examples/rectangle.rs Normal file
View file

@ -0,0 +1,100 @@
use softbuffer::GraphicsContext;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) {
for (index, color) in buffer.iter_mut().enumerate() {
let y = index / width;
let x = index % width;
if flag && x >= 100 && x < width - 100 && y >= 100 && y < height - 100 {
*color = 0x00ffffff;
} else {
let red = (x & 0xff) ^ (y & 0xff);
let green = (x & 0x7f) ^ (y & 0x7f);
let blue = (x & 0x3f) ^ (y & 0x3f);
*color = (blue | (green << 8) | (red << 16)) as u32;
}
}
}
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Press space to show/hide a rectangle")
.build(&event_loop)
.unwrap();
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;
web_sys::window()
.unwrap()
.document()
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.unwrap();
}
let mut graphics_context = unsafe { GraphicsContext::new(&window, &window) }.unwrap();
let mut buffer = Vec::new();
let mut flag = false;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
// Grab the window's client area dimensions
let (width, height) = {
let size = window.inner_size();
(size.width as usize, size.height as usize)
};
// Resize the off-screen buffer if the window size has changed
if buffer.len() != width * height {
buffer.resize(width * height, 0);
}
// Draw something in the offscreen buffer
redraw(&mut buffer, width, height, flag);
// Blit the offscreen buffer to the window's client area
graphics_context.set_buffer(&buffer, width as u16, height as u16);
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Space),
..
},
..
},
window_id,
} if window_id == window.id() => {
// Flip the rectangle flag and request a redraw to show the changed image
flag = !flag;
window.request_redraw();
}
_ => {}
}
});
}

View file

@ -9,7 +9,7 @@ use raw_window_handle::AppKitWindowHandle;
use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow};
use cocoa::base::{id, nil};
use cocoa::quartzcore::{CALayer, ContentsGravity};
use cocoa::quartzcore::{transaction, CALayer, ContentsGravity};
use foreign_types::ForeignType;
use std::sync::Arc;
@ -55,6 +55,15 @@ impl CGImpl {
false,
kCGRenderingIntentDefault,
);
// The CALayer has a default action associated with a change in the layer contents, causing
// a quarter second fade transition to happen every time a new buffer is applied. This can
// be mitigated by wrapping the operation in a transaction and disabling all actions.
transaction::begin();
transaction::set_disable_actions(true);
unsafe { self.layer.set_contents(image.as_ptr() as id) };
transaction::commit();
}
}