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

WIP: macos: Copy to IOSurface on present #96

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make winit example work with IOSurface, using alpha 255, stride
ids1024 committed Apr 11, 2023
commit 8c1ee39210278325d78a1518f02d0b408c8c4822
3 changes: 2 additions & 1 deletion examples/animation.rs
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ fn main() {
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();

let mut old_size = (0, 0);
// TODO: need to pre-render with right stride?
let mut frames = pre_render_frames(0, 0);

let start = Instant::now();
@@ -89,7 +90,7 @@ fn pre_render_frames(width: usize, height: usize) -> Vec<Vec<u32>> {
let blue =
((((y - elapsed).cos() * 0.5 + 0.5) * 255.0).round() as u32).clamp(0, 255);

blue | (green << 8) | (red << 16)
blue | (green << 8) | (red << 16) | (255 << 24)
})
.collect::<Vec<_>>()
};
17 changes: 9 additions & 8 deletions examples/winit.rs
Original file line number Diff line number Diff line change
@@ -42,14 +42,15 @@ fn main() {
.unwrap();

let mut buffer = surface.buffer_mut().unwrap();
for index in 0..(width * height) {
let y = index / width;
let x = index % width;
let red = x % 255;
let green = y % 255;
let blue = (x * y) % 255;

buffer[index as usize] = blue | (green << 8) | (red << 16);
let stride = buffer.stride();
for y in 0..height {
for x in 0..width {
let red = x % 255;
let green = y % 255;
let blue = (x * y) % 255;
let index = y as usize * stride + x as usize;
buffer[index] = blue | (green << 8) | (red << 16) | (255 << 24);
}
}

buffer.present().unwrap();
35 changes: 17 additions & 18 deletions src/cg/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core_foundation::{
base::TCFType, dictionary::CFDictionary, number::CFNumber, string::CFString,
base::TCFType, boolean::CFBoolean, dictionary::CFDictionary, number::CFNumber, string::CFString,
};
use io_surface::{
kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight, kIOSurfacePixelFormat,
@@ -17,8 +17,9 @@ extern "C" {

pub struct Buffer {
io_surface: IOSurface,
ptr: *mut u8,
pixels: usize,
ptr: *mut u32,
stride: usize,
len: usize,
}

impl Buffer {
@@ -37,35 +38,33 @@ impl Buffer {
CFString::wrap_under_get_rule(kIOSurfaceBytesPerElement),
CFNumber::from(4).as_CFType(),
),
// TODO: Can we always use stride = width? Is it efficient?
/*
(
CFString::wrap_under_get_rule(kIOSurfaceBytesPerRow),
CFNumber::from(width).as_CFType(),
),
*/
(
CFString::wrap_under_get_rule(kIOSurfacePixelFormat),
CFNumber::from(i32::from_be_bytes([b'B', b'G', b'R', b'A'])).as_CFType(),
CFNumber::from(i32::from_be_bytes(*b"BGRA")).as_CFType(),
),
])
};
let io_surface = io_surface::new(&properties);
let ptr = unsafe { IOSurfaceGetBaseAddress(io_surface.obj) };
dbg!(width);
dbg!(unsafe { IOSurfaceGetBytesPerRow(io_surface.obj) } / 4);
let pixels = width as usize * height as usize;
let ptr = unsafe { IOSurfaceGetBaseAddress(io_surface.obj) } as *mut u32;
let stride = unsafe { IOSurfaceGetBytesPerRow(io_surface.obj) } / 4;
let len = stride * height as usize;
Self {
io_surface,
ptr,
pixels,
stride,
len,
}
}

pub fn as_ptr(&self) -> IOSurfaceRef {
self.io_surface.obj
}

#[inline]
pub fn stride(&self) -> usize {
self.stride
}

pub unsafe fn lock(&mut self) {
let mut seed = 0;
unsafe {
@@ -83,11 +82,11 @@ impl Buffer {
// TODO: We can assume alignment, right?
#[inline]
pub unsafe fn pixels_ref(&self) -> &[u32] {
unsafe { slice::from_raw_parts(self.ptr as *mut u32, self.pixels) }
unsafe { slice::from_raw_parts(self.ptr, self.len) }
}

#[inline]
pub unsafe fn pixels_mut(&self) -> &mut [u32] {
unsafe { slice::from_raw_parts_mut(self.ptr as *mut u32, self.pixels) }
unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
}
}
5 changes: 5 additions & 0 deletions src/cg/mod.rs
Original file line number Diff line number Diff line change
@@ -81,6 +81,11 @@ impl<'a> BufferImpl<'a> {
unsafe { self.buffer.pixels_mut() }
}

#[inline]
pub fn stride(&self) -> usize {
self.buffer.stride()
}

pub fn present(mut self) -> Result<(), SoftBufferError> {
// 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
15 changes: 15 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -124,6 +124,16 @@ macro_rules! make_dispatch {
}
}

#[inline]
pub fn stride(&self) -> usize {
match self {
$(
$(#[$attr])*
Self::$name(inner) => inner.stride(),
)*
}
}

pub fn present(self) -> Result<(), SoftBufferError> {
match self {
$(
@@ -355,6 +365,11 @@ pub struct Buffer<'a> {
}

impl<'a> Buffer<'a> {
#[inline]
pub fn stride(&self) -> usize {
self.buffer_impl.stride()
}

/// Presents buffer to the window.
///
/// # Platform dependent behavior