Skip to content

Commit

Permalink
metal: surface API
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Nov 17, 2024
1 parent 107297d commit 99df34e
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 85 deletions.
38 changes: 2 additions & 36 deletions blade-graphics/src/metal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ mod surface;

const MAX_TIMESTAMPS: u64 = crate::limits::PASS_COUNT as u64 * 2;

//TODO: better errors
pub type PlatformError = ();

struct Surface {
pub struct Surface {
view: *mut objc::runtime::Object,
render_layer: metal::MetalLayer,
info: crate::SurfaceInfo,
}

unsafe impl Send for Surface {}
Expand Down Expand Up @@ -56,7 +56,6 @@ struct PrivateInfo {
pub struct Context {
device: Mutex<metal::Device>,
queue: Arc<Mutex<metal::CommandQueue>>,
surface: Option<Mutex<Surface>>,
capture: Option<metal::CaptureManager>,
info: PrivateInfo,
device_information: crate::DeviceInformation,
Expand Down Expand Up @@ -464,7 +463,6 @@ impl Context {
Ok(Context {
device: Mutex::new(device),
queue: Arc::new(Mutex::new(queue)),
surface: None,
capture,
info: PrivateInfo {
//TODO: determine based on OS version
Expand All @@ -477,30 +475,6 @@ impl Context {
})
}

pub unsafe fn init_windowed<
I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
>(
window: &I,
desc: super::ContextDesc,
) -> Result<Self, super::NotSupportedError> {
let mut context = Self::init(desc)?;

let surface = match window.window_handle().unwrap().as_raw() {
#[cfg(target_os = "ios")]
raw_window_handle::RawWindowHandle::UiKit(handle) => {
Surface::from_view(handle.ui_view.as_ptr() as *mut _)
}
#[cfg(target_os = "macos")]
raw_window_handle::RawWindowHandle::AppKit(handle) => {
Surface::from_view(handle.ns_view.as_ptr() as *mut _)
}
_ => return Err(crate::NotSupportedError::PlatformNotSupported),
};

context.surface = Some(Mutex::new(surface));
Ok(context)
}

pub fn capabilities(&self) -> crate::Capabilities {
let device = self.device.lock().unwrap();
crate::Capabilities {
Expand All @@ -520,14 +494,6 @@ impl Context {
&self.device_information
}

/// Get the CALayerMetal for this surface, if any.
/// This is platform specific API.
pub fn metal_layer(&self) -> Option<metal::MetalLayer> {
self.surface
.as_ref()
.map(|suf| suf.lock().unwrap().render_layer.clone())
}

/// Get an MTLDevice of this context.
/// This is platform specific API.
pub fn metal_device(&self) -> metal::Device {
Expand Down
124 changes: 75 additions & 49 deletions blade-graphics/src/metal/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use objc::{
sel, sel_impl,
};

use std::mem;
use std::{mem, ptr};

#[cfg(target_os = "macos")]
#[link(name = "QuartzCore", kind = "framework")]
Expand All @@ -17,14 +17,6 @@ extern "C" {
static kCAGravityTopLeft: *mut Object;
}

impl Drop for super::Surface {
fn drop(&mut self) {
unsafe {
let () = msg_send![self.view, release];
}
}
}

impl super::Surface {
pub unsafe fn from_view(view: *mut Object) -> Self {
let main_layer: *mut Object = msg_send![view, layer];
Expand Down Expand Up @@ -63,63 +55,97 @@ impl super::Surface {
Self {
view: msg_send![view, retain],
render_layer: mem::transmute::<_, &metal::MetalLayerRef>(raw_layer).to_owned(),
info: crate::SurfaceInfo {
format: crate::TextureFormat::Rgba8Unorm,
alpha: crate::AlphaMode::Ignored,
},
}
}

fn reconfigure(
&mut self,
device: &metal::DeviceRef,
/// Get the CALayerMetal for this surface, if any.
/// This is platform specific API.
pub fn metal_layer(&self) -> metal::MetalLayer {
self.render_layer.clone()
}

pub fn info(&self) -> crate::SurfaceInfo {
self.info
}

pub fn acquire_frame(&self) -> super::Frame {
let (drawable, texture) = objc::rc::autoreleasepool(|| {
let drawable = self.render_layer.next_drawable().unwrap();
(drawable.to_owned(), drawable.texture().to_owned())
});
super::Frame { drawable, texture }
}
}

impl super::Context {
pub fn create_surface<
I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
>(
&self,
window: &I,
config: crate::SurfaceConfig,
) -> crate::SurfaceInfo {
let format = match config.color_space {
crate::ColorSpace::Linear => crate::TextureFormat::Bgra8UnormSrgb,
crate::ColorSpace::Srgb => crate::TextureFormat::Bgra8Unorm,
) -> Result<super::Surface, crate::NotSupportedError> {
let mut surface = match window.window_handle().unwrap().as_raw() {
#[cfg(target_os = "ios")]
raw_window_handle::RawWindowHandle::UiKit(handle) => unsafe {
super::Surface::from_view(handle.ui_view.as_ptr() as *mut _)
},
#[cfg(target_os = "macos")]
raw_window_handle::RawWindowHandle::AppKit(handle) => unsafe {
super::Surface::from_view(handle.ns_view.as_ptr() as *mut _)
},
_ => return Err(crate::NotSupportedError::PlatformNotSupported),
};
self.reconfigure_surface(&mut surface, config);
Ok(surface)
}

pub fn reconfigure_surface(&self, surface: &mut super::Surface, config: crate::SurfaceConfig) {
let device = self.device.lock().unwrap();
surface.info = crate::SurfaceInfo {
format: match config.color_space {
crate::ColorSpace::Linear => crate::TextureFormat::Bgra8UnormSrgb,
crate::ColorSpace::Srgb => crate::TextureFormat::Bgra8Unorm,
},
alpha: if config.transparent {
crate::AlphaMode::PostMultiplied
} else {
//Warning: it's not really ignored! Instead, it's assumed to be 1:
// https://developer.apple.com/documentation/quartzcore/calayer/1410763-isopaque
crate::AlphaMode::Ignored
},
};
let vsync = match config.display_sync {
crate::DisplaySync::Block => true,
crate::DisplaySync::Recent | crate::DisplaySync::Tear => false,
};

self.render_layer.set_opaque(!config.transparent);
self.render_layer.set_device(device);
self.render_layer
.set_pixel_format(super::map_texture_format(format));
self.render_layer
surface.render_layer.set_opaque(!config.transparent);
surface.render_layer.set_device(&*device);
surface
.render_layer
.set_pixel_format(super::map_texture_format(surface.info.format));
surface
.render_layer
.set_framebuffer_only(config.usage == crate::TextureUsage::TARGET);
self.render_layer.set_maximum_drawable_count(3);
self.render_layer.set_drawable_size(CGSize::new(
surface.render_layer.set_maximum_drawable_count(3);
surface.render_layer.set_drawable_size(CGSize::new(
config.size.width as f64,
config.size.height as f64,
));
unsafe {
let () = msg_send![self.render_layer, setDisplaySyncEnabled: vsync];
}

crate::SurfaceInfo {
format,
alpha: if config.transparent {
crate::AlphaMode::PostMultiplied
} else {
//Warning: it's not really ignored! Instead, it's assumed to be 1:
// https://developer.apple.com/documentation/quartzcore/calayer/1410763-isopaque
crate::AlphaMode::Ignored
},
let () = msg_send![surface.render_layer, setDisplaySyncEnabled: vsync];
}
}
}

impl super::Context {
pub fn resize(&self, config: crate::SurfaceConfig) -> crate::SurfaceInfo {
let mut surface = self.surface.as_ref().unwrap().lock().unwrap();
surface.reconfigure(&*self.device.lock().unwrap(), config)
}

pub fn acquire_frame(&self) -> super::Frame {
let surface = self.surface.as_ref().unwrap().lock().unwrap();
let (drawable, texture) = objc::rc::autoreleasepool(|| {
let drawable = surface.render_layer.next_drawable().unwrap();
(drawable.to_owned(), drawable.texture().to_owned())
});
super::Frame { drawable, texture }
pub fn destroy_surface(&self, surface: &mut super::Surface) {
unsafe {
let () = msg_send![surface.view, release];
}
surface.view = ptr::null_mut();
}
}

0 comments on commit 99df34e

Please sign in to comment.