rt(mtl): rename librashader-runtime-metal to librashader-runtime-mtl to match existing convention and export from root crate
This commit is contained in:
parent
363657deef
commit
3b0531dc62
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -1506,6 +1506,7 @@ name = "librashader"
|
||||||
version = "0.2.0-beta.9"
|
version = "0.2.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ash",
|
"ash",
|
||||||
|
"icrate 0.1.0",
|
||||||
"librashader-cache",
|
"librashader-cache",
|
||||||
"librashader-common 0.2.0-beta.9",
|
"librashader-common 0.2.0-beta.9",
|
||||||
"librashader-preprocess",
|
"librashader-preprocess",
|
||||||
|
@ -1515,8 +1516,10 @@ dependencies = [
|
||||||
"librashader-runtime-d3d11",
|
"librashader-runtime-d3d11",
|
||||||
"librashader-runtime-d3d12",
|
"librashader-runtime-d3d12",
|
||||||
"librashader-runtime-gl",
|
"librashader-runtime-gl",
|
||||||
|
"librashader-runtime-mtl",
|
||||||
"librashader-runtime-vk",
|
"librashader-runtime-vk",
|
||||||
"librashader-runtime-wgpu",
|
"librashader-runtime-wgpu",
|
||||||
|
"objc2 0.5.0",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
"windows 0.48.0",
|
"windows 0.48.0",
|
||||||
|
@ -1725,8 +1728,8 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "librashader-runtime-metal"
|
name = "librashader-runtime-mtl"
|
||||||
version = "0.2.0-beta.7"
|
version = "0.2.0-beta.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-concat",
|
"array-concat",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
|
@ -10,10 +10,11 @@ members = [
|
||||||
"librashader-runtime-d3d12",
|
"librashader-runtime-d3d12",
|
||||||
"librashader-runtime-gl",
|
"librashader-runtime-gl",
|
||||||
"librashader-runtime-vk",
|
"librashader-runtime-vk",
|
||||||
|
"librashader-runtime-mtl",
|
||||||
|
"librashader-runtime-wgpu",
|
||||||
"librashader-cache",
|
"librashader-cache",
|
||||||
"librashader-capi",
|
"librashader-capi",
|
||||||
"librashader-build-script"
|
"librashader-build-script"]
|
||||||
, "librashader-runtime-wgpu", "librashader-runtime-metal"]
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.metadata.release]
|
[workspace.metadata.release]
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
use icrate::Metal::{
|
|
||||||
MTLCompareFunctionNever, MTLDevice, MTLSamplerAddressMode,
|
|
||||||
MTLSamplerBorderColorTransparentBlack, MTLSamplerDescriptor, MTLSamplerMinMagFilter,
|
|
||||||
MTLSamplerState,
|
|
||||||
};
|
|
||||||
use librashader_common::{FilterMode, WrapMode};
|
|
||||||
use objc2::rc::Id;
|
|
||||||
use objc2::runtime::ProtocolObject;
|
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
|
|
||||||
use crate::error::{FilterChainError, Result};
|
|
||||||
|
|
||||||
pub struct SamplerSet {
|
|
||||||
// todo: may need to deal with differences in mip filter.
|
|
||||||
samplers:
|
|
||||||
FxHashMap<(WrapMode, FilterMode, FilterMode), Id<ProtocolObject<dyn MTLSamplerState>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SamplerSet {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get(
|
|
||||||
&self,
|
|
||||||
wrap: WrapMode,
|
|
||||||
filter: FilterMode,
|
|
||||||
mipmap: FilterMode,
|
|
||||||
) -> &ProtocolObject<dyn MTLSamplerState> {
|
|
||||||
// eprintln!("{wrap}, {filter}, {mip}");
|
|
||||||
// SAFETY: the sampler set is complete for the matrix
|
|
||||||
// wrap x filter x mipmap
|
|
||||||
let id: &Id<ProtocolObject<dyn MTLSamplerState>> = unsafe {
|
|
||||||
self.samplers
|
|
||||||
.get(&(wrap, filter, mipmap))
|
|
||||||
.unwrap_unchecked()
|
|
||||||
};
|
|
||||||
|
|
||||||
id.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(device: &ProtocolObject<dyn MTLDevice>) -> Result<SamplerSet> {
|
|
||||||
let mut samplers = FxHashMap::default();
|
|
||||||
let wrap_modes = &[
|
|
||||||
WrapMode::ClampToBorder,
|
|
||||||
WrapMode::ClampToEdge,
|
|
||||||
WrapMode::Repeat,
|
|
||||||
WrapMode::MirroredRepeat,
|
|
||||||
];
|
|
||||||
for wrap_mode in wrap_modes {
|
|
||||||
for filter_mode in &[FilterMode::Linear, FilterMode::Nearest] {
|
|
||||||
for mipmap_filter in &[FilterMode::Linear, FilterMode::Nearest] {
|
|
||||||
let descriptor = MTLSamplerDescriptor::new();
|
|
||||||
descriptor.setRAddressMode(MTLSamplerAddressMode::from(*wrap_mode));
|
|
||||||
descriptor.setSAddressMode(MTLSamplerAddressMode::from(*wrap_mode));
|
|
||||||
descriptor.setTAddressMode(MTLSamplerAddressMode::from(*wrap_mode));
|
|
||||||
|
|
||||||
descriptor.setMagFilter(MTLSamplerMinMagFilter::from(*filter_mode));
|
|
||||||
|
|
||||||
descriptor.setMinFilter(MTLSamplerMinMagFilter::from(*filter_mode));
|
|
||||||
descriptor.setMipFilter(MTLSamplerMinMagFilter::from(*mipmap_filter));
|
|
||||||
descriptor.setLodMinClamp(0.0);
|
|
||||||
descriptor.setLodMaxClamp(1000.0);
|
|
||||||
descriptor.setCompareFunction(MTLCompareFunctionNever);
|
|
||||||
descriptor.setMaxAnisotropy(1);
|
|
||||||
descriptor.setBorderColor(MTLSamplerBorderColorTransparentBlack);
|
|
||||||
descriptor.setNormalizedCoordinates(true);
|
|
||||||
|
|
||||||
let Some(sampler_state) = device.newSamplerStateWithDescriptor(&descriptor)
|
|
||||||
else {
|
|
||||||
return Err(FilterChainError::SamplerError(
|
|
||||||
*wrap_mode,
|
|
||||||
*filter_mode,
|
|
||||||
*mipmap_filter,
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
samplers.insert((*wrap_mode, *filter_mode, *mipmap_filter), sampler_state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// assert all samplers were created.
|
|
||||||
assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2);
|
|
||||||
Ok(SamplerSet { samplers })
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,373 +0,0 @@
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
|
||||||
|
|
||||||
use core::{cell::OnceCell, ptr::NonNull};
|
|
||||||
|
|
||||||
use icrate::{
|
|
||||||
AppKit::{
|
|
||||||
NSApplication, NSApplicationActivationPolicyRegular, NSApplicationDelegate,
|
|
||||||
NSBackingStoreBuffered, NSWindow, NSWindowStyleMaskClosable, NSWindowStyleMaskResizable,
|
|
||||||
NSWindowStyleMaskTitled,
|
|
||||||
},
|
|
||||||
Foundation::{
|
|
||||||
ns_string, MainThreadMarker, NSDate, NSNotification, NSObject, NSObjectProtocol, NSPoint,
|
|
||||||
NSRect, NSSize,
|
|
||||||
},
|
|
||||||
Metal::{
|
|
||||||
MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue, MTLCreateSystemDefaultDevice,
|
|
||||||
MTLDevice, MTLDrawable, MTLLibrary, MTLPrimitiveTypeTriangle, MTLRenderCommandEncoder,
|
|
||||||
MTLRenderPipelineDescriptor, MTLRenderPipelineState,
|
|
||||||
},
|
|
||||||
MetalKit::{MTKView, MTKViewDelegate},
|
|
||||||
};
|
|
||||||
use objc2::{
|
|
||||||
declare_class, msg_send_id, mutability::MainThreadOnly, rc::Id, runtime::ProtocolObject,
|
|
||||||
ClassType, DeclaredClass,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
const SHADERS: &str = r#"
|
|
||||||
#include <metal_stdlib>
|
|
||||||
|
|
||||||
struct SceneProperties {
|
|
||||||
float time;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VertexInput {
|
|
||||||
metal::packed_float3 position;
|
|
||||||
metal::packed_float3 color;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VertexOutput {
|
|
||||||
metal::float4 position [[position]];
|
|
||||||
metal::float4 color;
|
|
||||||
};
|
|
||||||
|
|
||||||
vertex VertexOutput vertex_main(
|
|
||||||
device const SceneProperties& properties [[buffer(0)]],
|
|
||||||
device const VertexInput* vertices [[buffer(1)]],
|
|
||||||
uint vertex_idx [[vertex_id]]
|
|
||||||
) {
|
|
||||||
VertexOutput out;
|
|
||||||
VertexInput in = vertices[vertex_idx];
|
|
||||||
out.position =
|
|
||||||
metal::float4(
|
|
||||||
metal::float2x2(
|
|
||||||
metal::cos(properties.time), -metal::sin(properties.time),
|
|
||||||
metal::sin(properties.time), metal::cos(properties.time)
|
|
||||||
) * in.position.xy,
|
|
||||||
in.position.z,
|
|
||||||
1);
|
|
||||||
out.color = metal::float4(in.color, 1);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment metal::float4 fragment_main(VertexOutput in [[stage_in]]) {
|
|
||||||
return in.color;
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct SceneProperties {
|
|
||||||
pub time: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct VertexInput {
|
|
||||||
pub position: Position,
|
|
||||||
pub color: Color,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
// NOTE: this has the same ABI as `MTLPackedFloat3`
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Position {
|
|
||||||
pub x: f32,
|
|
||||||
pub y: f32,
|
|
||||||
pub z: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
// NOTE: this has the same ABI as `MTLPackedFloat3`
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Color {
|
|
||||||
pub r: f32,
|
|
||||||
pub g: f32,
|
|
||||||
pub b: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! idcell {
|
|
||||||
($name:ident => $this:expr) => {
|
|
||||||
$this.ivars().$name.set($name).expect(&format!(
|
|
||||||
"ivar should not already be initialized: `{}`",
|
|
||||||
stringify!($name)
|
|
||||||
));
|
|
||||||
};
|
|
||||||
($name:ident <= $this:expr) => {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
let Some($name) = $this.ivars().$name.get() else {
|
|
||||||
unreachable!(
|
|
||||||
"ivar should be initialized: `{}`",
|
|
||||||
stringify!($name)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// declare the desired instance variables
|
|
||||||
struct Ivars {
|
|
||||||
start_date: Id<NSDate>,
|
|
||||||
command_queue: OnceCell<Id<ProtocolObject<dyn MTLCommandQueue>>>,
|
|
||||||
pipeline_state: OnceCell<Id<ProtocolObject<dyn MTLRenderPipelineState>>>,
|
|
||||||
window: OnceCell<Id<NSWindow>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// declare the Objective-C class machinery
|
|
||||||
declare_class!(
|
|
||||||
struct Delegate;
|
|
||||||
|
|
||||||
// SAFETY:
|
|
||||||
// - The superclass NSObject does not have any subclassing requirements.
|
|
||||||
// - Main thread only mutability is correct, since this is an application delegate.
|
|
||||||
// - `Delegate` does not implement `Drop`.
|
|
||||||
unsafe impl ClassType for Delegate {
|
|
||||||
type Super = NSObject;
|
|
||||||
type Mutability = MainThreadOnly;
|
|
||||||
const NAME: &'static str = "Delegate";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeclaredClass for Delegate {
|
|
||||||
type Ivars = Ivars;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl NSObjectProtocol for Delegate {}
|
|
||||||
|
|
||||||
// define the delegate methods for the `NSApplicationDelegate` protocol
|
|
||||||
unsafe impl NSApplicationDelegate for Delegate {
|
|
||||||
#[method(applicationDidFinishLaunching:)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
unsafe fn applicationDidFinishLaunching(&self, _notification: &NSNotification) {
|
|
||||||
let mtm = MainThreadMarker::from(self);
|
|
||||||
// create the app window
|
|
||||||
let window = {
|
|
||||||
let content_rect = NSRect::new(NSPoint::new(0., 0.), NSSize::new(768., 768.));
|
|
||||||
let style = NSWindowStyleMaskClosable
|
|
||||||
| NSWindowStyleMaskResizable
|
|
||||||
| NSWindowStyleMaskTitled;
|
|
||||||
let backing_store_type = NSBackingStoreBuffered;
|
|
||||||
let flag = false;
|
|
||||||
unsafe {
|
|
||||||
NSWindow::initWithContentRect_styleMask_backing_defer(
|
|
||||||
mtm.alloc(),
|
|
||||||
content_rect,
|
|
||||||
style,
|
|
||||||
backing_store_type,
|
|
||||||
flag,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// get the default device
|
|
||||||
let device = {
|
|
||||||
let ptr = unsafe { MTLCreateSystemDefaultDevice() };
|
|
||||||
unsafe { Id::retain(ptr) }.expect("Failed to get default system device.")
|
|
||||||
};
|
|
||||||
|
|
||||||
// create the command queue
|
|
||||||
let command_queue = device
|
|
||||||
.newCommandQueue()
|
|
||||||
.expect("Failed to create a command queue.");
|
|
||||||
|
|
||||||
// create the metal view
|
|
||||||
let mtk_view = {
|
|
||||||
let frame_rect = window.frame();
|
|
||||||
unsafe { MTKView::initWithFrame_device(mtm.alloc(), frame_rect, Some(&device)) }
|
|
||||||
};
|
|
||||||
|
|
||||||
// create the pipeline descriptor
|
|
||||||
let pipeline_descriptor = MTLRenderPipelineDescriptor::new();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pipeline_descriptor
|
|
||||||
.colorAttachments()
|
|
||||||
.objectAtIndexedSubscript(0)
|
|
||||||
.setPixelFormat(mtk_view.colorPixelFormat());
|
|
||||||
}
|
|
||||||
|
|
||||||
// compile the shaders
|
|
||||||
let library = device
|
|
||||||
.newLibraryWithSource_options_error(ns_string!(SHADERS), None)
|
|
||||||
.expect("Failed to create a library.");
|
|
||||||
|
|
||||||
// configure the vertex shader
|
|
||||||
let vertex_function = library.newFunctionWithName(ns_string!("vertex_main"));
|
|
||||||
pipeline_descriptor.setVertexFunction(vertex_function.as_deref());
|
|
||||||
|
|
||||||
// configure the fragment shader
|
|
||||||
let fragment_function = library.newFunctionWithName(ns_string!("fragment_main"));
|
|
||||||
pipeline_descriptor.setFragmentFunction(fragment_function.as_deref());
|
|
||||||
|
|
||||||
// create the pipeline state
|
|
||||||
let pipeline_state = device
|
|
||||||
.newRenderPipelineStateWithDescriptor_error(&pipeline_descriptor)
|
|
||||||
.expect("Failed to create a pipeline state.");
|
|
||||||
|
|
||||||
// configure the metal view delegate
|
|
||||||
unsafe {
|
|
||||||
let object = ProtocolObject::from_ref(self);
|
|
||||||
mtk_view.setDelegate(Some(object));
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure the window
|
|
||||||
window.setContentView(Some(&mtk_view));
|
|
||||||
window.center();
|
|
||||||
window.setTitle(ns_string!("metal example"));
|
|
||||||
window.makeKeyAndOrderFront(None);
|
|
||||||
|
|
||||||
// initialize the delegate state
|
|
||||||
idcell!(command_queue => self);
|
|
||||||
idcell!(pipeline_state => self);
|
|
||||||
idcell!(window => self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// define the delegate methods for the `MTKViewDelegate` protocol
|
|
||||||
unsafe impl MTKViewDelegate for Delegate {
|
|
||||||
#[method(drawInMTKView:)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
unsafe fn drawInMTKView(&self, mtk_view: &MTKView) {
|
|
||||||
idcell!(command_queue <= self);
|
|
||||||
idcell!(pipeline_state <= self);
|
|
||||||
|
|
||||||
// FIXME: icrate `MTKView` doesn't have a generated binding for `currentDrawable` yet
|
|
||||||
// (because it needs a definition of `CAMetalDrawable`, which we don't support yet) so
|
|
||||||
// we have to use a raw `msg_send_id` call here instead.
|
|
||||||
let current_drawable: Option<Id<ProtocolObject<dyn MTLDrawable>>> =
|
|
||||||
msg_send_id![mtk_view, currentDrawable];
|
|
||||||
|
|
||||||
// prepare for drawing
|
|
||||||
let Some(current_drawable) = current_drawable else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(command_buffer) = command_queue.commandBuffer() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(pass_descriptor) = (unsafe { mtk_view.currentRenderPassDescriptor() }) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(encoder) = command_buffer.renderCommandEncoderWithDescriptor(&pass_descriptor)
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// compute the scene properties
|
|
||||||
let scene_properties_data = &SceneProperties {
|
|
||||||
time: unsafe { self.ivars().start_date.timeIntervalSinceNow() } as f32,
|
|
||||||
};
|
|
||||||
// write the scene properties to the vertex shader argument buffer at index 0
|
|
||||||
let scene_properties_bytes = NonNull::from(scene_properties_data);
|
|
||||||
unsafe {
|
|
||||||
encoder.setVertexBytes_length_atIndex(
|
|
||||||
scene_properties_bytes.cast::<core::ffi::c_void>(),
|
|
||||||
core::mem::size_of_val(scene_properties_data),
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// compute the triangle geometry
|
|
||||||
let vertex_input_data: &[VertexInput] = &[
|
|
||||||
VertexInput {
|
|
||||||
position: Position {
|
|
||||||
x: -f32::sqrt(3.0) / 4.0,
|
|
||||||
y: -0.25,
|
|
||||||
z: 0.,
|
|
||||||
},
|
|
||||||
color: Color {
|
|
||||||
r: 1.,
|
|
||||||
g: 0.,
|
|
||||||
b: 0.,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
VertexInput {
|
|
||||||
position: Position {
|
|
||||||
x: f32::sqrt(3.0) / 4.0,
|
|
||||||
y: -0.25,
|
|
||||||
z: 0.,
|
|
||||||
},
|
|
||||||
color: Color {
|
|
||||||
r: 0.,
|
|
||||||
g: 1.,
|
|
||||||
b: 0.,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
VertexInput {
|
|
||||||
position: Position {
|
|
||||||
x: 0.,
|
|
||||||
y: 0.5,
|
|
||||||
z: 0.,
|
|
||||||
},
|
|
||||||
color: Color {
|
|
||||||
r: 0.,
|
|
||||||
g: 0.,
|
|
||||||
b: 1.,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
// write the triangle geometry to the vertex shader argument buffer at index 1
|
|
||||||
let vertex_input_bytes = NonNull::from(vertex_input_data);
|
|
||||||
unsafe {
|
|
||||||
encoder.setVertexBytes_length_atIndex(
|
|
||||||
vertex_input_bytes.cast::<core::ffi::c_void>(),
|
|
||||||
core::mem::size_of_val(vertex_input_data),
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// configure the encoder with the pipeline and draw the triangle
|
|
||||||
encoder.setRenderPipelineState(pipeline_state);
|
|
||||||
unsafe {
|
|
||||||
encoder.drawPrimitives_vertexStart_vertexCount(MTLPrimitiveTypeTriangle, 0, 3)
|
|
||||||
};
|
|
||||||
encoder.endEncoding();
|
|
||||||
|
|
||||||
// schedule the command buffer for display and commit
|
|
||||||
command_buffer.presentDrawable(¤t_drawable);
|
|
||||||
command_buffer.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[method(mtkView:drawableSizeWillChange:)]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
unsafe fn mtkView_drawableSizeWillChange(&self, _view: &MTKView, _size: NSSize) {
|
|
||||||
// println!("mtkView_drawableSizeWillChange");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
impl Delegate {
|
|
||||||
pub fn new(mtm: MainThreadMarker) -> Id<Self> {
|
|
||||||
let this = mtm.alloc();
|
|
||||||
let this = this.set_ivars(Ivars {
|
|
||||||
start_date: unsafe { NSDate::now() },
|
|
||||||
command_queue: OnceCell::default(),
|
|
||||||
pipeline_state: OnceCell::default(),
|
|
||||||
window: OnceCell::default(),
|
|
||||||
});
|
|
||||||
unsafe { msg_send_id![super(this), init] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mtm = MainThreadMarker::new().unwrap();
|
|
||||||
// configure the app
|
|
||||||
let app = NSApplication::sharedApplication(mtm);
|
|
||||||
app.setActivationPolicy(NSApplicationActivationPolicyRegular);
|
|
||||||
|
|
||||||
// configure the application delegate
|
|
||||||
let delegate = Delegate::new(mtm);
|
|
||||||
let object = ProtocolObject::from_ref(&*delegate);
|
|
||||||
app.setDelegate(Some(object));
|
|
||||||
|
|
||||||
// run the app
|
|
||||||
unsafe { app.run() };
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
[package]
|
[package]
|
||||||
name = "librashader-runtime-metal"
|
name = "librashader-runtime-mtl"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
license = "MPL-2.0 OR GPL-3.0-only"
|
license = "MPL-2.0 OR GPL-3.0-only"
|
||||||
version = "0.2.0-beta.7"
|
version = "0.2.0-beta.9"
|
||||||
authors = ["Ronny Chan <ronny@ronnychan.ca>"]
|
authors = ["Ronny Chan <ronny@ronnychan.ca>"]
|
||||||
repository = "https://github.com/SnowflakePowered/librashader"
|
repository = "https://github.com/SnowflakePowered/librashader"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
|
@ -27,9 +27,9 @@ array-concat = "0.5.2"
|
||||||
bytemuck = { version = "1.12.3", features = ["derive"] }
|
bytemuck = { version = "1.12.3", features = ["derive"] }
|
||||||
rayon = "1.8.1"
|
rayon = "1.8.1"
|
||||||
|
|
||||||
[dependencies.icrate]
|
#[dependencies.icrate]
|
||||||
version = "0.1.0"
|
#version = "0.1.0"
|
||||||
features = ["AppKit", "AppKit_all", "Foundation", "Foundation_all", "MetalKit", "MetalKit_all", "Metal", "Metal_all"]
|
#features = ["AppKit", "AppKit_all", "Foundation", "Foundation_all", "MetalKit", "MetalKit_all", "Metal", "Metal_all"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "triangle"
|
name = "triangle"
|
||||||
|
@ -40,7 +40,7 @@ harness = false
|
||||||
features = ["librashader-cache/docsrs"]
|
features = ["librashader-cache/docsrs"]
|
||||||
|
|
||||||
[target.'cfg(target_vendor="apple")'.dependencies]
|
[target.'cfg(target_vendor="apple")'.dependencies]
|
||||||
#icrate = { version = "0.1.0" , features = [ "Metal", "Metal_all" ]}
|
icrate = { version = "0.1.0" , features = [ "Metal", "Metal_all" ]}
|
||||||
objc2 = { version = "0.5.0", features = ["apple"] }
|
objc2 = { version = "0.5.0", features = ["apple"] }
|
||||||
#
|
#
|
||||||
#[lib]
|
#[lib]
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
use icrate::Foundation::{NSRange, NSString};
|
use icrate::Foundation::NSString;
|
||||||
use icrate::Metal::{
|
use icrate::Metal::{
|
||||||
MTLBuffer, MTLDevice, MTLResource, MTLResourceStorageModeManaged, MTLResourceStorageModeShared,
|
MTLBuffer, MTLDevice, MTLResource, MTLResourceStorageModeManaged, MTLResourceStorageModeShared,
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,7 @@ impl MetalBuffer {
|
||||||
let resource_mode = if cfg!(target_os = "ios") {
|
let resource_mode = if cfg!(target_os = "ios") {
|
||||||
MTLResourceStorageModeShared
|
MTLResourceStorageModeShared
|
||||||
} else {
|
} else {
|
||||||
MTLResourceStorageModeShared
|
MTLResourceStorageModeManaged
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = device
|
let buffer = device
|
|
@ -58,24 +58,6 @@ const FINAL_VBO_DATA: [MetalVertex; 4] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
const VBO_OFFSCREEN: [f32; 16] = [
|
|
||||||
// Offscreen
|
|
||||||
-1.0f32, -1.0, 0.0, 0.0,
|
|
||||||
-1.0, 1.0, 0.0, 1.0,
|
|
||||||
1.0, -1.0, 1.0, 0.0,
|
|
||||||
1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
const VBO_DEFAULT_FINAL: [f32; 16] = [
|
|
||||||
// Final
|
|
||||||
0.0f32, 0.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0, 1.0,
|
|
||||||
1.0, 0.0, 1.0, 0.0,
|
|
||||||
1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
const VBO_DATA: [MetalVertex; 8] = concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA);
|
const VBO_DATA: [MetalVertex; 8] = concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA);
|
||||||
|
|
||||||
pub struct DrawQuad {
|
pub struct DrawQuad {
|
|
@ -7,7 +7,7 @@ use crate::graphics_pipeline::MetalGraphicsPipeline;
|
||||||
use crate::luts::LutTexture;
|
use crate::luts::LutTexture;
|
||||||
use crate::options::{FilterChainOptionsMetal, FrameOptionsMetal};
|
use crate::options::{FilterChainOptionsMetal, FrameOptionsMetal};
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::{get_texture_size, InputTexture, OwnedTexture};
|
use crate::texture::{get_texture_size, InputTexture, MetalOutputView, OwnedTexture};
|
||||||
use icrate::Foundation::NSString;
|
use icrate::Foundation::NSString;
|
||||||
use icrate::Metal::{
|
use icrate::Metal::{
|
||||||
MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue, MTLDevice, MTLPixelFormat,
|
MTLCommandBuffer, MTLCommandEncoder, MTLCommandQueue, MTLDevice, MTLPixelFormat,
|
||||||
|
@ -133,7 +133,7 @@ impl FilterChainMetal {
|
||||||
.map(|texture| Image::<BGRA8>::load(&texture.path, UVDirection::TopLeft))
|
.map(|texture| Image::<BGRA8>::load(&texture.path, UVDirection::TopLeft))
|
||||||
.collect::<Result<Vec<Image<BGRA8>>, ImageError>>()?;
|
.collect::<Result<Vec<Image<BGRA8>>, ImageError>>()?;
|
||||||
for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
|
for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
|
||||||
let texture = LutTexture::new(device, &mipmapper, image, texture)?;
|
let texture = LutTexture::new(device, image, texture)?;
|
||||||
luts.insert(index, texture);
|
luts.insert(index, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ impl FilterChainMetal {
|
||||||
pub fn frame(
|
pub fn frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: &ProtocolObject<dyn MTLTexture>,
|
input: &ProtocolObject<dyn MTLTexture>,
|
||||||
viewport: &Viewport<&ProtocolObject<dyn MTLTexture>>,
|
viewport: &Viewport<MetalOutputView>,
|
||||||
cmd_buffer: &ProtocolObject<dyn MTLCommandBuffer>,
|
cmd_buffer: &ProtocolObject<dyn MTLCommandBuffer>,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
options: Option<&FrameOptionsMetal>,
|
options: Option<&FrameOptionsMetal>,
|
|
@ -3,7 +3,7 @@ use crate::error::{FilterChainError, Result};
|
||||||
use crate::select_optimal_pixel_format;
|
use crate::select_optimal_pixel_format;
|
||||||
use icrate::Foundation::NSString;
|
use icrate::Foundation::NSString;
|
||||||
use icrate::Metal::{
|
use icrate::Metal::{
|
||||||
MTLBlendFactorOneMinusSourceAlpha, MTLBlendFactorSourceAlpha, MTLClearColor, MTLCommandBuffer,
|
MTLBlendFactorOneMinusSourceAlpha, MTLBlendFactorSourceAlpha, MTLCommandBuffer,
|
||||||
MTLCommandEncoder, MTLDevice, MTLFunction, MTLLibrary, MTLLoadActionDontCare, MTLPixelFormat,
|
MTLCommandEncoder, MTLDevice, MTLFunction, MTLLibrary, MTLLoadActionDontCare, MTLPixelFormat,
|
||||||
MTLPrimitiveTopologyClassTriangle, MTLRenderCommandEncoder, MTLRenderPassDescriptor,
|
MTLPrimitiveTopologyClassTriangle, MTLRenderCommandEncoder, MTLRenderPassDescriptor,
|
||||||
MTLRenderPipelineColorAttachmentDescriptor, MTLRenderPipelineDescriptor,
|
MTLRenderPipelineColorAttachmentDescriptor, MTLRenderPipelineDescriptor,
|
|
@ -21,6 +21,8 @@ pub mod options;
|
||||||
use librashader_runtime::impl_filter_chain_parameters;
|
use librashader_runtime::impl_filter_chain_parameters;
|
||||||
impl_filter_chain_parameters!(FilterChainMetal);
|
impl_filter_chain_parameters!(FilterChainMetal);
|
||||||
|
|
||||||
|
pub use texture::MetalOutputView;
|
||||||
|
|
||||||
fn select_optimal_pixel_format(format: MTLPixelFormat) -> MTLPixelFormat {
|
fn select_optimal_pixel_format(format: MTLPixelFormat) -> MTLPixelFormat {
|
||||||
if format == MTLPixelFormatRGBA8Unorm {
|
if format == MTLPixelFormatRGBA8Unorm {
|
||||||
return MTLPixelFormatBGRA8Unorm;
|
return MTLPixelFormatBGRA8Unorm;
|
|
@ -1,12 +1,11 @@
|
||||||
use crate::error::{FilterChainError, Result};
|
use crate::error::{FilterChainError, Result};
|
||||||
use crate::texture::InputTexture;
|
use crate::texture::InputTexture;
|
||||||
use icrate::Metal::{
|
use icrate::Metal::{
|
||||||
MTLBlitCommandEncoder, MTLDevice, MTLOrigin, MTLPixelFormatBGRA8Unorm, MTLRegion, MTLSize,
|
MTLDevice, MTLOrigin, MTLPixelFormatBGRA8Unorm, MTLRegion, MTLSize, MTLTexture,
|
||||||
MTLTexture, MTLTextureDescriptor, MTLTextureUsageShaderRead,
|
MTLTextureDescriptor, MTLTextureUsageShaderRead,
|
||||||
};
|
};
|
||||||
use librashader_presets::TextureConfig;
|
use librashader_presets::TextureConfig;
|
||||||
use librashader_runtime::image::{Image, BGRA8};
|
use librashader_runtime::image::{Image, BGRA8};
|
||||||
use librashader_runtime::scaling::MipmapSize;
|
|
||||||
use objc2::runtime::ProtocolObject;
|
use objc2::runtime::ProtocolObject;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
@ -22,7 +21,6 @@ impl AsRef<InputTexture> for LutTexture {
|
||||||
impl LutTexture {
|
impl LutTexture {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &ProtocolObject<dyn MTLDevice>,
|
device: &ProtocolObject<dyn MTLDevice>,
|
||||||
mipmapper: &ProtocolObject<dyn MTLBlitCommandEncoder>,
|
|
||||||
image: Image<BGRA8>,
|
image: Image<BGRA8>,
|
||||||
config: &TextureConfig,
|
config: &TextureConfig,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
|
@ -7,11 +7,12 @@ use icrate::Metal::{
|
||||||
};
|
};
|
||||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||||
use librashader_presets::Scale2D;
|
use librashader_presets::Scale2D;
|
||||||
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
|
use librashader_runtime::scaling::{ScaleFramebuffer, ViewportSize};
|
||||||
use objc2::rc::Id;
|
use objc2::rc::Id;
|
||||||
use objc2::runtime::ProtocolObject;
|
use objc2::runtime::ProtocolObject;
|
||||||
|
|
||||||
pub type MetalTexture = Id<ProtocolObject<dyn MTLTexture>>;
|
pub type MetalTexture = Id<ProtocolObject<dyn MTLTexture>>;
|
||||||
|
pub type MetalOutputView<'a> = &'a ProtocolObject<dyn MTLTexture>;
|
||||||
|
|
||||||
pub struct OwnedTexture {
|
pub struct OwnedTexture {
|
||||||
pub(crate) texture: MetalTexture,
|
pub(crate) texture: MetalTexture,
|
|
@ -23,6 +23,7 @@ librashader-runtime-d3d12 = { path = "../librashader-runtime-d3d12", version =
|
||||||
librashader-runtime-gl = { path = "../librashader-runtime-gl", version = "0.2.0-beta.9", optional = true }
|
librashader-runtime-gl = { path = "../librashader-runtime-gl", version = "0.2.0-beta.9", optional = true }
|
||||||
librashader-runtime-vk = { path = "../librashader-runtime-vk", version = "0.2.0-beta.9", optional = true }
|
librashader-runtime-vk = { path = "../librashader-runtime-vk", version = "0.2.0-beta.9", optional = true }
|
||||||
librashader-runtime-wgpu = { path = "../librashader-runtime-wgpu", version = "0.2.0-beta.9", optional = true }
|
librashader-runtime-wgpu = { path = "../librashader-runtime-wgpu", version = "0.2.0-beta.9", optional = true }
|
||||||
|
librashader-runtime-mtl = { path = "../librashader-runtime-mtl", version = "0.2.0-beta.9", optional = true }
|
||||||
|
|
||||||
librashader-cache = { path = "../librashader-cache", version = "0.2.0-beta.9" }
|
librashader-cache = { path = "../librashader-cache", version = "0.2.0-beta.9" }
|
||||||
|
|
||||||
|
@ -34,6 +35,10 @@ wgpu-types = { version = "0.19", optional = true }
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
|
[target.'cfg(target_vendor="apple")'.dependencies]
|
||||||
|
icrate = { version = "0.1.0" , features = [ "Metal", "Metal_all" ], optional = true}
|
||||||
|
objc2 = { version = "0.5.0", features = ["apple"] , optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# core features and definitions
|
# core features and definitions
|
||||||
runtime = []
|
runtime = []
|
||||||
|
@ -48,13 +53,14 @@ runtime-d3d11 = [ "runtime", "reflect-cross","librashader-common/d3d11", "libras
|
||||||
runtime-d3d12 = [ "runtime", "reflect-cross", "reflect-dxil", "librashader-common/d3d12", "librashader-runtime-d3d12", "windows/Win32_Graphics_Direct3D12" ]
|
runtime-d3d12 = [ "runtime", "reflect-cross", "reflect-dxil", "librashader-common/d3d12", "librashader-runtime-d3d12", "windows/Win32_Graphics_Direct3D12" ]
|
||||||
runtime-vk = ["runtime", "reflect-cross", "librashader-common/vulkan", "librashader-runtime-vk", "ash" ]
|
runtime-vk = ["runtime", "reflect-cross", "librashader-common/vulkan", "librashader-runtime-vk", "ash" ]
|
||||||
runtime-wgpu = [ "runtime", "reflect-naga", "librashader-common/wgpu", "librashader-runtime-wgpu", "wgpu", "wgpu-types" ]
|
runtime-wgpu = [ "runtime", "reflect-naga", "librashader-common/wgpu", "librashader-runtime-wgpu", "wgpu", "wgpu-types" ]
|
||||||
|
runtime-metal = [ "runtime", "reflect-naga", "reflect-cross", "librashader-common/metal", "librashader-runtime-mtl", "icrate", "objc2" ]
|
||||||
|
|
||||||
# reflection
|
# reflection
|
||||||
reflect-cross = ["reflect", "librashader-reflect/cross"]
|
reflect-cross = ["reflect", "librashader-reflect/cross"]
|
||||||
reflect-dxil = ["reflect", "librashader-reflect/dxil"]
|
reflect-dxil = ["reflect", "librashader-reflect/dxil"]
|
||||||
reflect-naga = ["reflect", "librashader-reflect/naga"]
|
reflect-naga = ["reflect", "librashader-reflect/naga"]
|
||||||
|
|
||||||
runtime-all = ["runtime-gl", "runtime-d3d11", "runtime-d3d12", "runtime-vk", "runtime-wgpu"]
|
runtime-all = ["runtime-gl", "runtime-d3d11", "runtime-d3d12", "runtime-vk", "runtime-wgpu", "runtime-metal"]
|
||||||
reflect-all = ["reflect-cross", "reflect-dxil", "reflect-naga"]
|
reflect-all = ["reflect-cross", "reflect-dxil", "reflect-naga"]
|
||||||
|
|
||||||
# enable all features by default
|
# enable all features by default
|
||||||
|
@ -67,5 +73,6 @@ full = ["runtime-all", "reflect-all", "preprocess", "presets"]
|
||||||
docsrs = ["librashader-cache/docsrs"]
|
docsrs = ["librashader-cache/docsrs"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
targets = ["x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu"]
|
targets = ["x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu",
|
||||||
|
"x86_64-apple-darwin", "aarch64-apple-darwin", "aarch64-apple-ios"]
|
||||||
features = [ "librashader-cache/docsrs" ]
|
features = [ "librashader-cache/docsrs" ]
|
||||||
|
|
|
@ -278,6 +278,19 @@ pub mod runtime {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_vendor = "apple", feature = "runtime-metal"))]
|
||||||
|
#[doc(cfg(all(target_vendor = "apple", feature = "runtime-metal")))]
|
||||||
|
/// Shader runtime for Metal
|
||||||
|
pub mod mtl {
|
||||||
|
pub use librashader_runtime_mtl::{
|
||||||
|
error,
|
||||||
|
options::{
|
||||||
|
FilterChainOptionsMetal as FilterChainOptions, FrameOptionsMetal as FrameOptions,
|
||||||
|
},
|
||||||
|
FilterChainMetal as FilterChain, MetalOutputView,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "runtime-wgpu")]
|
#[cfg(feature = "runtime-wgpu")]
|
||||||
#[doc(cfg(feature = "runtime-wgpu"))]
|
#[doc(cfg(feature = "runtime-wgpu"))]
|
||||||
/// Shader runtime for wgpu
|
/// Shader runtime for wgpu
|
||||||
|
|
Loading…
Reference in a new issue