Skip to content

Commit

Permalink
feat: add metal
Browse files Browse the repository at this point in the history
  • Loading branch information
Phong committed Sep 17, 2024
1 parent 1b1a24a commit 0b7b847
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 117 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dioxus-hot-reload = { version = "0.5", features = ["file_watcher"], default-feat
dioxus-router = { version = "0.5", default-features = false }
dioxus-sdk = { version = "0.5", features = ["clipboard"]}

skia-safe = { version = "0.75.0", features = ["gl", "textlayout", "svg"] }
skia-safe = { version = "0.75.0", features = ["gl", "metal", "textlayout", "svg"] }

gl = "0.14.0"
glutin = "0.32.0"
Expand Down
95 changes: 16 additions & 79 deletions crates/engine/src/skia.rs
Original file line number Diff line number Diff line change
@@ -1,94 +1,31 @@
pub use skia_safe::{
font_style::{
Slant,
Weight,
Width,
},
font_style::{Slant, Weight, Width},
gpu::{
backend_render_targets,
direct_contexts,
gl::{
Format,
FramebufferInfo,
Interface,
},
backend_render_targets, direct_contexts,
gl::{Format, FramebufferInfo, Interface},
mtl::{BackendContext, Handle, TextureInfo},
surfaces::wrap_backend_render_target,
BackendRenderTarget,
DirectContext,
RecordingContext,
SurfaceOrigin,
BackendRenderTarget, DirectContext, RecordingContext, SurfaceOrigin,
},
gradient_shader::GradientShaderColors,
graphics::{
set_resource_cache_single_allocation_byte_limit,
set_resource_cache_total_bytes_limit,
set_resource_cache_single_allocation_byte_limit, set_resource_cache_total_bytes_limit,
},
path::ArcSize,
rrect::Corner,
runtime_effect::Uniform,
scalar,
surfaces::raster_n32_premul,
svg,
textlayout::{
paragraph::GlyphClusterInfo,
Decoration,
FontCollection,
FontFeature,
LineMetrics,
Paragraph,
ParagraphBuilder,
ParagraphStyle,
PlaceholderStyle,
PositionWithAffinity,
RectHeightStyle,
RectWidthStyle,
StrutStyle,
TextAlign,
TextBaseline,
TextBox,
TextDecoration,
TextDecorationStyle,
TextDirection,
TextHeightBehavior,
TextIndex,
TextRange,
TextShadow,
TextStyle,
TypefaceFontProvider,
paragraph::GlyphClusterInfo, Decoration, FontCollection, FontFeature, LineMetrics,
Paragraph, ParagraphBuilder, ParagraphStyle, PlaceholderStyle, PositionWithAffinity,
RectHeightStyle, RectWidthStyle, StrutStyle, TextAlign, TextBaseline, TextBox,
TextDecoration, TextDecorationStyle, TextDirection, TextHeightBehavior, TextIndex,
TextRange, TextShadow, TextStyle, TypefaceFontProvider,
},
Bitmap,
BlurStyle,
Canvas,
ClipOp,
Color,
ColorSpace,
ColorType,
Data,
EncodedImageFormat,
FilterMode,
FontArguments,
FontMgr,
FontStyle,
IPoint,
IRect,
Image,
ImageInfo,
MaskFilter,
Matrix,
Paint,
PaintStyle,
Path,
PathDirection,
Point,
RRect,
Rect,
RuntimeEffect,
SamplingOptions,
Shader,
Surface,
TileMode,
Typeface,
HSV,
M44,
RGB,
V3,
Bitmap, BlurStyle, Canvas, ClipOp, Color, ColorSpace, ColorType, Data, EncodedImageFormat,
FilterMode, FontArguments, FontMgr, FontStyle, IPoint, IRect, Image, ImageInfo, MaskFilter,
Matrix, Paint, PaintStyle, Path, PathDirection, Point, RRect, Rect, RuntimeEffect,
SamplingOptions, Shader, Surface, TileMode, Typeface, HSV, M44, RGB, V3,
};
7 changes: 7 additions & 0 deletions crates/renderer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,10 @@ itertools = "0.13.0"
uuid = { workspace = true }
image = "0.25.0"
pin-utils = "0.1.0"

[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25.0"
objc = "0.2.7"
core-graphics-types = "0.1.3"
metal = "0.29.0"
foreign-types-shared = "0.3.1"
137 changes: 137 additions & 0 deletions crates/renderer/src/drivers/metal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use foreign_types_shared::{ForeignType, ForeignTypeRef};
use freya_engine::prelude::{
backend_render_targets, direct_contexts, scalar, wrap_backend_render_target, BackendContext,
ColorType, DirectContext, Handle, Surface as SkiaSurface, SurfaceOrigin, TextureInfo,
};
use metal::{CommandQueue, Device, MTLPixelFormat, MetalLayer};
use objc::runtime::YES;
use raw_window_handle::HasWindowHandle;
use winit::{
dpi::PhysicalSize,
event_loop::ActiveEventLoop,
window::{Window, WindowAttributes},
};

use crate::{size::WinitSize, LaunchConfig};

/// Graphics driver using Metal.
pub struct MetalDriver {
pub(crate) gr_context: DirectContext,
pub(crate) metal_layer: MetalLayer,
pub(crate) command_queue: CommandQueue,
pub(crate) scale_factor: f64,
}

impl MetalDriver {
pub fn new<State: Clone + 'static>(
event_loop: &ActiveEventLoop,
window_attributes: WindowAttributes,
_config: &LaunchConfig<State>,
) -> (Self, Window, SkiaSurface) {
let window = event_loop
.create_window(window_attributes)
.expect("Failed to create Window");

let scale_factor = window.scale_factor();
let window_handle = window
.window_handle()
.expect("Failed to retrieve a window handle");
let raw_window_handle = window_handle.as_raw();

let device = Device::system_default().expect("no device found");
let command_queue = device.new_command_queue();

let metal_layer = {
let draw_size = window.inner_size();
let layer = MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
layer.set_presents_with_transaction(false);
// Disabling this option allows Skia's Blend Mode to work.
// More about: https://developer.apple.com/documentation/quartzcore/cametallayer/1478168-framebufferonly
layer.set_framebuffer_only(false);

unsafe {
let view = match raw_window_handle {
raw_window_handle::RawWindowHandle::AppKit(appkit) => appkit.ns_view.as_ptr(),
_ => panic!("Wrong window handle type"),
} as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(layer.as_ref() as *const _ as _);
}
layer.set_drawable_size(CGSize::new(draw_size.width as f64, draw_size.height as f64));
layer
};

let backend = unsafe {
BackendContext::new(device.as_ptr() as Handle, command_queue.as_ptr() as Handle)
};

let mut gr_context =
direct_contexts::make_metal(&backend, None).expect("Could not create Metal context");

let drawable = metal_layer.next_drawable().unwrap();
let (drawable_width, drawable_height) = {
let size = metal_layer.drawable_size();
(size.width as scalar, size.height as scalar)
};

let skia_surface = unsafe {
let texture_info = TextureInfo::new(drawable.texture().as_ptr() as Handle);

let backend_render_target = backend_render_targets::make_mtl(
(drawable_width as i32, drawable_height as i32),
&texture_info,
);

wrap_backend_render_target(
&mut gr_context,
&backend_render_target,
SurfaceOrigin::TopLeft,
ColorType::BGRA8888,
None,
None,
)
.unwrap()
};

let driver = MetalDriver {
gr_context,
metal_layer,
command_queue,
scale_factor,
};

(driver, window, skia_surface)
}

pub fn resize(&mut self, size: PhysicalSize<u32>) -> (SkiaSurface, SkiaSurface) {
let drawable = self.metal_layer.next_drawable().unwrap();

let mut surface = unsafe {
let texture_info = TextureInfo::new(drawable.texture().as_ptr() as Handle);

let backend_render_target =
backend_render_targets::make_mtl(size.to_skia(), &texture_info);

wrap_backend_render_target(
&mut self.gr_context,
&backend_render_target,
SurfaceOrigin::TopLeft,
ColorType::BGRA8888,
None,
None,
)
.unwrap()
};

let dirty_surface = surface.new_surface_with_dimensions(size.to_skia()).unwrap();

self.metal_layer
.set_drawable_size(CGSize::new(size.width as f64, size.height as f64));

(surface, dirty_surface)
}
}
23 changes: 18 additions & 5 deletions crates/renderer/src/drivers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
mod gl;
mod metal;

use freya_engine::prelude::Surface as SkiaSurface;
pub use gl::*;
pub use metal::*;

use freya_engine::prelude::Surface as SkiaSurface;
use glutin::surface::GlSurface;
use metal::MetalDriver;
use winit::{
dpi::PhysicalSize,
event_loop::ActiveEventLoop,
window::{
Window,
WindowAttributes,
},
window::{Window, WindowAttributes},
};

use crate::LaunchConfig;

pub enum GraphicsDriver {
OpenGl(OpenGLDriver),
Metal(MetalDriver),
}

impl GraphicsDriver {
Expand All @@ -31,6 +33,7 @@ impl GraphicsDriver {
pub fn make_current(&mut self) {
match self {
Self::OpenGl(gl) => gl.make_current(),
Self::Metal(_) => {}
}
}

Expand All @@ -40,12 +43,22 @@ impl GraphicsDriver {
gl.gr_context.flush_and_submit();
gl.gl_surface.swap_buffers(&gl.gl_context).unwrap();
}
Self::Metal(mtl) => {
if let Some(drawable) = mtl.metal_layer.next_drawable() {
mtl.gr_context.flush_and_submit();

let command_buffer = mtl.command_queue.new_command_buffer();
command_buffer.present_drawable(drawable);
command_buffer.commit();
}
}
}
}

pub fn resize(&mut self, size: PhysicalSize<u32>) -> (SkiaSurface, SkiaSurface) {
match self {
Self::OpenGl(gl) => gl.resize(size),
Self::Metal(mtl) => mtl.resize(size),
}
}
}
Loading

0 comments on commit 0b7b847

Please sign in to comment.