Start on metal rendering infrastructure
This commit is contained in:
parent
d14c943150
commit
292b41ad57
8 changed files with 320 additions and 76 deletions
43
Cargo.lock
generated
43
Cargo.lock
generated
|
@ -336,7 +336,7 @@ dependencies = [
|
||||||
"cocoa-foundation",
|
"cocoa-foundation",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"foreign-types 0.3.2",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -351,7 +351,7 @@ dependencies = [
|
||||||
"block",
|
"block",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types 0.3.2",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -396,7 +396,7 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types 0.3.2",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -408,7 +408,7 @@ checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"foreign-types 0.3.2",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -420,7 +420,7 @@ checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"foreign-types 0.3.2",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -616,28 +616,7 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foreign-types-shared 0.1.1",
|
"foreign-types-shared",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
|
||||||
dependencies = [
|
|
||||||
"foreign-types-macros",
|
|
||||||
"foreign-types-shared 0.3.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-macros"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "63f713f8b2aa9e24fec85b0e290c56caee12e3b6ae0aeeda238a75b28251afd6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -646,12 +625,6 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-shared"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7684cf33bb7f28497939e8c7cf17e3e4e3b8d9a0080ffa4f8ae2f515442ee855"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "freetype"
|
name = "freetype"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -773,7 +746,7 @@ dependencies = [
|
||||||
"core-text",
|
"core-text",
|
||||||
"ctor",
|
"ctor",
|
||||||
"font-kit",
|
"font-kit",
|
||||||
"foreign-types 0.5.0",
|
"foreign-types",
|
||||||
"log",
|
"log",
|
||||||
"metal",
|
"metal",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
|
@ -924,7 +897,7 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"block",
|
"block",
|
||||||
"cocoa-foundation",
|
"cocoa-foundation",
|
||||||
"foreign-types 0.3.2",
|
"foreign-types",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,7 +29,7 @@ core-foundation = "0.9"
|
||||||
core-graphics = "0.22.2"
|
core-graphics = "0.22.2"
|
||||||
core-text = "19.2"
|
core-text = "19.2"
|
||||||
font-kit = {git = "https://github.com/zed-industries/font-kit", rev = "8eaf7a918eafa28b0a37dc759e2e0e7683fa24f1"}
|
font-kit = {git = "https://github.com/zed-industries/font-kit", rev = "8eaf7a918eafa28b0a37dc759e2e0e7683fa24f1"}
|
||||||
foreign-types = "0.5"
|
foreign-types = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
metal = "0.21"
|
metal = "0.21.0"
|
||||||
objc = "0.2"
|
objc = "0.2"
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
use std::{env, path::PathBuf};
|
use std::{
|
||||||
|
env,
|
||||||
|
path::PathBuf,
|
||||||
|
process::{self, Command},
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
generate_dispatch_bindings();
|
generate_dispatch_bindings();
|
||||||
compile_context_predicate_parser();
|
compile_context_predicate_parser();
|
||||||
|
compile_metal_shaders();
|
||||||
|
generate_shader_bindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_dispatch_bindings() {
|
fn generate_dispatch_bindings() {
|
||||||
|
@ -20,7 +26,7 @@ fn generate_dispatch_bindings() {
|
||||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
bindings
|
bindings
|
||||||
.write_to_file(out_path.join("dispatch_sys.rs"))
|
.write_to_file(out_path.join("dispatch_sys.rs"))
|
||||||
.expect("couldn't write bindings");
|
.expect("couldn't write dispatch bindings");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_context_predicate_parser() {
|
fn compile_context_predicate_parser() {
|
||||||
|
@ -33,3 +39,60 @@ fn compile_context_predicate_parser() {
|
||||||
.file(parser_c)
|
.file(parser_c)
|
||||||
.compile("tree_sitter_context_predicate");
|
.compile("tree_sitter_context_predicate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SHADER_HEADER_PATH: &'static str = "./src/platform/mac/shaders/shaders.h";
|
||||||
|
|
||||||
|
fn compile_metal_shaders() {
|
||||||
|
let shader_path = "./src/platform/mac/shaders/shaders.metal";
|
||||||
|
let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air");
|
||||||
|
let metallib_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib");
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed={}", SHADER_HEADER_PATH);
|
||||||
|
println!("cargo:rerun-if-changed={}", shader_path);
|
||||||
|
|
||||||
|
let output = Command::new("xcrun")
|
||||||
|
.args(&["-sdk", "macosx", "metal", "-c", shader_path, "-o"])
|
||||||
|
.arg(&air_output_path)
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!(
|
||||||
|
"metal shader compilation failed:\n{}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = Command::new("xcrun")
|
||||||
|
.args(&["-sdk", "macosx", "metallib"])
|
||||||
|
.arg(air_output_path)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(metallib_output_path)
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!(
|
||||||
|
"metallib compilation failed:\n{}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_shader_bindings() {
|
||||||
|
let bindings = bindgen::Builder::default()
|
||||||
|
.header(SHADER_HEADER_PATH)
|
||||||
|
.whitelist_type("GPUIQuadInputIndex")
|
||||||
|
.whitelist_type("GPUIQuad")
|
||||||
|
.whitelist_type("GPUIQuadUniforms")
|
||||||
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||||
|
.generate()
|
||||||
|
.expect("unable to generate bindings");
|
||||||
|
|
||||||
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
bindings
|
||||||
|
.write_to_file(out_path.join("shaders.rs"))
|
||||||
|
.expect("couldn't write shader bindings");
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ mod app;
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
mod event;
|
mod event;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
|
mod renderer;
|
||||||
mod runner;
|
mod runner;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
|
|
63
gpui/src/platform/mac/renderer.rs
Normal file
63
gpui/src/platform/mac/renderer.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use crate::Scene;
|
||||||
|
|
||||||
|
use super::window::RenderContext;
|
||||||
|
|
||||||
|
const SHADERS_METALLIB: &'static [u8] =
|
||||||
|
include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
|
||||||
|
|
||||||
|
pub struct Renderer {
|
||||||
|
quad_pipeline_state: metal::RenderPipelineState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
pub fn new(device: &metal::DeviceRef, pixel_format: metal::MTLPixelFormat) -> Result<Self> {
|
||||||
|
let library = device
|
||||||
|
.new_library_with_data(SHADERS_METALLIB)
|
||||||
|
.map_err(|message| anyhow!("error building metal library: {}", message))?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
quad_pipeline_state: build_pipeline_state(
|
||||||
|
device,
|
||||||
|
&library,
|
||||||
|
"quad",
|
||||||
|
"quad_vertex",
|
||||||
|
"quad_fragment",
|
||||||
|
pixel_format,
|
||||||
|
)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self, scene: &Scene, ctx: RenderContext) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_pipeline_state(
|
||||||
|
device: &metal::DeviceRef,
|
||||||
|
library: &metal::LibraryRef,
|
||||||
|
label: &str,
|
||||||
|
vertex_fn_name: &str,
|
||||||
|
fragment_fn_name: &str,
|
||||||
|
pixel_format: metal::MTLPixelFormat,
|
||||||
|
) -> Result<metal::RenderPipelineState> {
|
||||||
|
let vertex_fn = library
|
||||||
|
.get_function(vertex_fn_name, None)
|
||||||
|
.map_err(|message| anyhow!("error locating vertex function: {}", message))?;
|
||||||
|
let fragment_fn = library
|
||||||
|
.get_function(fragment_fn_name, None)
|
||||||
|
.map_err(|message| anyhow!("error locating fragment function: {}", message))?;
|
||||||
|
|
||||||
|
let mut descriptor = metal::RenderPipelineDescriptor::new();
|
||||||
|
descriptor.set_label(label);
|
||||||
|
descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
|
||||||
|
descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
|
||||||
|
descriptor
|
||||||
|
.color_attachments()
|
||||||
|
.object_at(0)
|
||||||
|
.unwrap()
|
||||||
|
.set_pixel_format(pixel_format);
|
||||||
|
|
||||||
|
device
|
||||||
|
.new_render_pipeline_state(&descriptor)
|
||||||
|
.map_err(|message| anyhow!("could not create render pipeline state: {}", message))
|
||||||
|
}
|
17
gpui/src/platform/mac/shaders/shaders.h
Normal file
17
gpui/src/platform/mac/shaders/shaders.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GPUIQuadInputIndexVertices = 0,
|
||||||
|
GPUIQuadInputIndexQuads = 1,
|
||||||
|
GPUIQuadInputIndexUniforms = 2,
|
||||||
|
} GPUIQuadInputIndex;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vector_float2 origin;
|
||||||
|
vector_float2 size;
|
||||||
|
vector_float4 background_color;
|
||||||
|
} GPUIQuad;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vector_float2 viewport_size;
|
||||||
|
} GPUIQuadUniforms;
|
30
gpui/src/platform/mac/shaders/shaders.metal
Normal file
30
gpui/src/platform/mac/shaders/shaders.metal
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include "shaders.h"
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct QuadFragmentInput {
|
||||||
|
float4 position [[position]];
|
||||||
|
GPUIQuad quad;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex QuadFragmentInput quad_vertex(
|
||||||
|
uint unit_vertex_id [[vertex_id]],
|
||||||
|
uint quad_id [[instance_id]],
|
||||||
|
constant float2 *unit_vertices [[buffer(GPUIQuadInputIndexVertices)]],
|
||||||
|
constant GPUIQuad *quads [[buffer(GPUIQuadInputIndexQuads)]],
|
||||||
|
constant GPUIQuadUniforms *uniforms [[buffer(GPUIQuadInputIndexUniforms)]]
|
||||||
|
) {
|
||||||
|
float2 unit_vertex = unit_vertices[unit_vertex_id];
|
||||||
|
GPUIQuad quad = quads[quad_id];
|
||||||
|
float4 position = float4((unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0), 0.0, 1.0);
|
||||||
|
|
||||||
|
return QuadFragmentInput {
|
||||||
|
position,
|
||||||
|
quad,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]]) {
|
||||||
|
return input.quad.background_color;
|
||||||
|
}
|
|
@ -12,13 +12,16 @@ use cocoa::{
|
||||||
},
|
},
|
||||||
base::{id, nil},
|
base::{id, nil},
|
||||||
foundation::{NSAutoreleasePool, NSSize, NSString},
|
foundation::{NSAutoreleasePool, NSSize, NSString},
|
||||||
|
quartzcore::AutoresizingMask,
|
||||||
};
|
};
|
||||||
use ctor::ctor;
|
use ctor::ctor;
|
||||||
|
use foreign_types::ForeignType as _;
|
||||||
|
use metal::{MTLClearColor, MTLLoadAction, MTLStoreAction};
|
||||||
use objc::{
|
use objc::{
|
||||||
class,
|
class,
|
||||||
declare::ClassDecl,
|
declare::ClassDecl,
|
||||||
msg_send,
|
msg_send,
|
||||||
runtime::{Class, Object, Sel, BOOL, NO, YES},
|
runtime::{Class, Object, Protocol, Sel, BOOL, NO, YES},
|
||||||
sel, sel_impl,
|
sel, sel_impl,
|
||||||
};
|
};
|
||||||
use pathfinder_geometry::vector::vec2f;
|
use pathfinder_geometry::vector::vec2f;
|
||||||
|
@ -31,13 +34,12 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::geometry::RectFExt;
|
use super::{geometry::RectFExt, renderer::Renderer};
|
||||||
|
|
||||||
const WINDOW_STATE_IVAR: &'static str = "windowState";
|
const WINDOW_STATE_IVAR: &'static str = "windowState";
|
||||||
|
|
||||||
static mut WINDOW_CLASS: *const Class = ptr::null();
|
static mut WINDOW_CLASS: *const Class = ptr::null();
|
||||||
static mut VIEW_CLASS: *const Class = ptr::null();
|
static mut VIEW_CLASS: *const Class = ptr::null();
|
||||||
static mut DELEGATE_CLASS: *const Class = ptr::null();
|
|
||||||
|
|
||||||
#[ctor]
|
#[ctor]
|
||||||
unsafe fn build_classes() {
|
unsafe fn build_classes() {
|
||||||
|
@ -63,7 +65,9 @@ unsafe fn build_classes() {
|
||||||
VIEW_CLASS = {
|
VIEW_CLASS = {
|
||||||
let mut decl = ClassDecl::new("GPUIView", class!(NSView)).unwrap();
|
let mut decl = ClassDecl::new("GPUIView", class!(NSView)).unwrap();
|
||||||
decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);
|
decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);
|
||||||
|
|
||||||
decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel));
|
decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel));
|
||||||
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(keyDown:),
|
sel!(keyDown:),
|
||||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||||
|
@ -84,20 +88,25 @@ unsafe fn build_classes() {
|
||||||
sel!(scrollWheel:),
|
sel!(scrollWheel:),
|
||||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
decl.register()
|
|
||||||
};
|
|
||||||
|
|
||||||
DELEGATE_CLASS = {
|
decl.add_protocol(Protocol::get("CALayerDelegate").unwrap());
|
||||||
let mut decl = ClassDecl::new("GPUIWindowDelegate", class!(NSObject)).unwrap();
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(dealloc),
|
sel!(makeBackingLayer),
|
||||||
dealloc_delegate as extern "C" fn(&Object, Sel),
|
make_backing_layer as extern "C" fn(&Object, Sel) -> id,
|
||||||
);
|
);
|
||||||
decl.add_ivar::<*mut c_void>(WINDOW_STATE_IVAR);
|
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(windowDidResize:),
|
sel!(viewDidChangeBackingProperties),
|
||||||
window_did_resize as extern "C" fn(&Object, Sel, id),
|
view_did_change_backing_properties as extern "C" fn(&Object, Sel),
|
||||||
);
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(setFrameSize:),
|
||||||
|
set_frame_size as extern "C" fn(&Object, Sel, NSSize),
|
||||||
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(displayLayer:),
|
||||||
|
display_layer as extern "C" fn(&Object, Sel, id),
|
||||||
|
);
|
||||||
|
|
||||||
decl.register()
|
decl.register()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -110,6 +119,17 @@ struct WindowState {
|
||||||
resize_callback: RefCell<Option<Box<dyn FnMut(Vector2F, f32)>>>,
|
resize_callback: RefCell<Option<Box<dyn FnMut(Vector2F, f32)>>>,
|
||||||
synthetic_drag_counter: Cell<usize>,
|
synthetic_drag_counter: Cell<usize>,
|
||||||
executor: Rc<executor::Foreground>,
|
executor: Rc<executor::Foreground>,
|
||||||
|
scene_to_render: RefCell<Option<Scene>>,
|
||||||
|
renderer: RefCell<Renderer>,
|
||||||
|
command_queue: metal::CommandQueue,
|
||||||
|
device: metal::Device,
|
||||||
|
layer: id,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RenderContext<'a> {
|
||||||
|
pub drawable_size: Vector2F,
|
||||||
|
pub device: &'a metal::Device,
|
||||||
|
pub command_encoder: &'a metal::RenderCommandEncoderRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
@ -117,6 +137,8 @@ impl Window {
|
||||||
options: platform::WindowOptions,
|
options: platform::WindowOptions,
|
||||||
executor: Rc<executor::Foreground>,
|
executor: Rc<executor::Foreground>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
|
const PIXEL_FORMAT: metal::MTLPixelFormat = metal::MTLPixelFormat::BGRA8Unorm;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let pool = NSAutoreleasePool::new(nil);
|
let pool = NSAutoreleasePool::new(nil);
|
||||||
|
|
||||||
|
@ -138,12 +160,20 @@ impl Window {
|
||||||
return Err(anyhow!("window returned nil from initializer"));
|
return Err(anyhow!("window returned nil from initializer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let delegate: id = msg_send![DELEGATE_CLASS, alloc];
|
let device = metal::Device::system_default()
|
||||||
let delegate = delegate.init();
|
.ok_or_else(|| anyhow!("could not find default metal device"))?;
|
||||||
if native_window == nil {
|
|
||||||
return Err(anyhow!("delegate returned nil from initializer"));
|
let layer: id = msg_send![class!(CAMetalLayer), layer];
|
||||||
}
|
let _: () = msg_send![layer, setDevice: device.as_ptr()];
|
||||||
native_window.setDelegate_(delegate);
|
let _: () = msg_send![layer, setPixelFormat: PIXEL_FORMAT];
|
||||||
|
let _: () = msg_send![layer, setAllowsNextDrawableTimeout: NO];
|
||||||
|
let _: () = msg_send![layer, setNeedsDisplayOnBoundsChange: YES];
|
||||||
|
let _: () = msg_send![layer, setPresentsWithTransaction: YES];
|
||||||
|
let _: () = msg_send![
|
||||||
|
layer,
|
||||||
|
setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE
|
||||||
|
| AutoresizingMask::HEIGHT_SIZABLE
|
||||||
|
];
|
||||||
|
|
||||||
let native_view: id = msg_send![VIEW_CLASS, alloc];
|
let native_view: id = msg_send![VIEW_CLASS, alloc];
|
||||||
let native_view = NSView::init(native_view);
|
let native_view = NSView::init(native_view);
|
||||||
|
@ -157,6 +187,11 @@ impl Window {
|
||||||
resize_callback: RefCell::new(None),
|
resize_callback: RefCell::new(None),
|
||||||
synthetic_drag_counter: Cell::new(0),
|
synthetic_drag_counter: Cell::new(0),
|
||||||
executor,
|
executor,
|
||||||
|
scene_to_render: Default::default(),
|
||||||
|
renderer: RefCell::new(Renderer::new(&device, PIXEL_FORMAT)?),
|
||||||
|
command_queue: device.new_command_queue(),
|
||||||
|
device,
|
||||||
|
layer,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
(*native_window).set_ivar(
|
(*native_window).set_ivar(
|
||||||
|
@ -167,10 +202,6 @@ impl Window {
|
||||||
WINDOW_STATE_IVAR,
|
WINDOW_STATE_IVAR,
|
||||||
Rc::into_raw(window.0.clone()) as *const c_void,
|
Rc::into_raw(window.0.clone()) as *const c_void,
|
||||||
);
|
);
|
||||||
(*delegate).set_ivar(
|
|
||||||
WINDOW_STATE_IVAR,
|
|
||||||
Rc::into_raw(window.0.clone()) as *const c_void,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(title) = options.title.as_ref() {
|
if let Some(title) = options.title.as_ref() {
|
||||||
native_window.setTitle_(NSString::alloc(nil).init_str(title));
|
native_window.setTitle_(NSString::alloc(nil).init_str(title));
|
||||||
|
@ -237,7 +268,10 @@ impl platform::Window for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_scene(&self, scene: Scene) {
|
fn render_scene(&self, scene: Scene) {
|
||||||
log::info!("render scene");
|
*self.0.scene_to_render.borrow_mut() = Some(scene);
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![self.0.native_window.contentView(), setNeedsDisplay: YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,14 +327,6 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn dealloc_delegate(this: &Object, _: Sel) {
|
|
||||||
unsafe {
|
|
||||||
let raw: *mut c_void = *this.get_ivar(WINDOW_STATE_IVAR);
|
|
||||||
Rc::from_raw(raw as *mut WindowState);
|
|
||||||
let () = msg_send![super(this, class!(NSObject)), dealloc];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||||
let window = unsafe { window_state(this) };
|
let window = unsafe { window_state(this) };
|
||||||
|
|
||||||
|
@ -329,14 +355,85 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
|
extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id {
|
||||||
let window = unsafe { window_state(this) };
|
let window = unsafe { window_state(this) };
|
||||||
let size = window.size();
|
window.layer
|
||||||
let scale_factor = window.scale_factor();
|
}
|
||||||
if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
|
|
||||||
callback(size, scale_factor);
|
extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) {
|
||||||
|
let window;
|
||||||
|
unsafe {
|
||||||
|
window = window_state(this);
|
||||||
|
let _: () = msg_send![window.layer, setContentsScale: window.scale_factor() as f64];
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
|
||||||
|
let size = window.size();
|
||||||
|
let scale_factor = window.scale_factor();
|
||||||
|
callback(size, scale_factor);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
|
||||||
|
let window;
|
||||||
|
unsafe {
|
||||||
|
window = window_state(this);
|
||||||
|
if window.size() == vec2f(size.width as f32, size.height as f32) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size];
|
||||||
|
|
||||||
|
let scale_factor = window.scale_factor() as f64;
|
||||||
|
let drawable_size: NSSize = NSSize {
|
||||||
|
width: size.width * scale_factor,
|
||||||
|
height: size.height * scale_factor,
|
||||||
|
};
|
||||||
|
let _: () = msg_send![window.layer, setDrawableSize: drawable_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
|
||||||
|
let size = window.size();
|
||||||
|
let scale_factor = window.scale_factor();
|
||||||
|
callback(size, scale_factor);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
|
||||||
|
unsafe {
|
||||||
|
let window = window_state(this);
|
||||||
|
|
||||||
|
if let Some(scene) = window.scene_to_render.borrow_mut().take() {
|
||||||
|
let drawable: &metal::MetalDrawableRef = msg_send![window.layer, nextDrawable];
|
||||||
|
|
||||||
|
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
||||||
|
let color_attachment = render_pass_descriptor
|
||||||
|
.color_attachments()
|
||||||
|
.object_at(0)
|
||||||
|
.unwrap();
|
||||||
|
color_attachment.set_texture(Some(drawable.texture()));
|
||||||
|
color_attachment.set_load_action(MTLLoadAction::Clear);
|
||||||
|
color_attachment.set_store_action(MTLStoreAction::Store);
|
||||||
|
color_attachment.set_clear_color(MTLClearColor::new(0., 0., 0., 1.));
|
||||||
|
|
||||||
|
let command_buffer = window.command_queue.new_command_buffer();
|
||||||
|
let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor);
|
||||||
|
|
||||||
|
window.renderer.borrow_mut().render(
|
||||||
|
&scene,
|
||||||
|
RenderContext {
|
||||||
|
drawable_size: window.size() * window.scale_factor(),
|
||||||
|
device: &window.device,
|
||||||
|
command_encoder,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
command_encoder.end_encoding();
|
||||||
|
command_buffer.commit();
|
||||||
|
command_buffer.wait_until_completed();
|
||||||
|
drawable.present();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
drop(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule_synthetic_drag(window_state: &Rc<WindowState>, position: Vector2F) {
|
fn schedule_synthetic_drag(window_state: &Rc<WindowState>, position: Vector2F) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue