Skip to content

Commit

Permalink
Merge pull request #12 from Fancyflame/fix/cant-run-on-macos
Browse files Browse the repository at this point in the history
fix: 在MacOS上无法创建Surface以及创建后卡死
  • Loading branch information
Fancyflame authored Oct 3, 2024
2 parents b6bad42 + 1c0bf1f commit 602b20c
Show file tree
Hide file tree
Showing 18 changed files with 196 additions and 94 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ members = [
"irisia-utils",
"examples",
"tests",
]
]
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ name = "simple_window"
path = "simple_window.rs"

[dev-dependencies]
tokio = { version = "1.27", features = ["sync", "rt-multi-thread", "macros"] }
tokio = { version = "1.40", features = ["sync", "rt-multi-thread", "macros"] }
irisia = { path = "../irisia" }
rand = "0.8"
#irisia_widgets = { path = "../irisia-widgets" }
6 changes: 2 additions & 4 deletions examples/simple_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ use irisia::{
element::{CompInputWatcher, ComponentTemplate, OneStructureCreate},
event::standard::{PointerDown, PointerMove},
skia_safe::Color,
style,
winit::window::WindowBuilder,
Result,
style, Result, WinitWindow,
};

use rand::Rng;
Expand All @@ -24,7 +22,7 @@ mod window_backend;
#[irisia::main]
async fn main() -> Result<()> {
Window::new(
WindowBuilder::new().with_title("hello irisia"),
WinitWindow::default_attributes().with_title("hello irisia"),
build!(App;),
)
.await
Expand Down
2 changes: 1 addition & 1 deletion examples/window_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct RectStyles {

impl ElementInterfaces for Rectangle {
type Props<'a> = RectProps;
const REQUIRE_INDEPENDENT_LAYER: bool = true;
const REQUIRE_INDEPENDENT_LAYER: bool = false;

fn create<Slt>(
props: Self::Props<'_>,
Expand Down
70 changes: 70 additions & 0 deletions examples/window_get_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::{
sync::{atomic::AtomicU32, Arc},
time::Duration,
};

use irisia::{
anyhow::Result,
winit::{
application::ApplicationHandler,
event::{Event, StartCause, WindowEvent},
event_loop::EventLoop,
window::Window,
},
WinitWindow,
};

struct App {
window: Option<Window>,
counter: Arc<AtomicU32>,
}

impl ApplicationHandler for App {
fn resumed(&mut self, event_loop: &irisia::winit::event_loop::ActiveEventLoop) {}

fn window_event(
&mut self,
event_loop: &irisia::winit::event_loop::ActiveEventLoop,
window_id: irisia::winit::window::WindowId,
event: irisia::winit::event::WindowEvent,
) {
if let WindowEvent::RedrawRequested = event {
self.counter
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
self.window.as_mut().unwrap().request_redraw();
}
}

fn new_events(
&mut self,
event_loop: &irisia::winit::event_loop::ActiveEventLoop,
cause: irisia::winit::event::StartCause,
) {
if let StartCause::Init = cause {
let window = event_loop
.create_window(Window::default_attributes())
.unwrap();

{
let counter = self.counter.clone();
std::thread::spawn(move || loop {
std::thread::sleep(Duration::from_secs(1));
let fps = counter.swap(0, std::sync::atomic::Ordering::Relaxed);
println!("{fps}fps");
})
};

self.window.insert(window).request_redraw();
}
}
}

fn main() -> Result<()> {
EventLoop::new()?
.run_app(&mut App {
window: None,
counter: Arc::new(AtomicU32::new(0)),
})
.unwrap();
Ok(())
}
8 changes: 4 additions & 4 deletions irisia-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
winit = { version = "0.29", features = ["android-native-activity", "rwh_05"] }
pixels = "0.13"
skia-safe = { version = "0.70", features = ["textlayout", "binary-cache"] }
tokio = { version = "1.28", features = ["rt-multi-thread"] }
winit = { version = "0.30", features = ["android-native-activity", "rwh_05"] }
pixels = "0.14"
skia-safe = { version = "0.78", features = ["textlayout", "binary-cache"] }
tokio = { version = "1.40", features = ["rt-multi-thread"] }
anyhow = "1"
lazy_static = "1"
futures = "0.3"
Expand Down
45 changes: 25 additions & 20 deletions irisia-backend/src/render_window/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::sync::{Arc, Condvar, Mutex as StdMutex};
use std::sync::Arc;

use anyhow::{anyhow, Result};
use pixels::Pixels;
use renderer::Renderer;
use tokio::{sync::mpsc, task::LocalSet};
use winit::event::WindowEvent;

Expand All @@ -18,36 +20,37 @@ enum Command {

pub struct RenderWindowController {
chan: mpsc::UnboundedSender<Command>,
draw_finished: Arc<(StdMutex<bool>, Condvar)>,
}

impl RenderWindowController {
pub fn new(app: AppBuildFn, window: Arc<WinitWindow>) -> Self {
let (tx, rx) = mpsc::unbounded_channel::<Command>();
let draw_finished = Arc::new((StdMutex::new(true), Condvar::new()));
let draw_finished_cloned = draw_finished.clone();

// because some system needs renderer to be created on main thread, like MacOS.
let pixels = Renderer::create_pixels(&window).expect("cannot create pixels");

std::thread::Builder::new()
.name("irisia window".into())
.spawn(move || window_runtime(app, window, rx, draw_finished_cloned))
.spawn(move || window_runtime(app, window, pixels, rx))
.unwrap();

Self {
chan: tx,
draw_finished,
}
Self { chan: tx }
}

pub fn redraw(&self) -> Result<()> {
let mut finished = self.draw_finished.0.lock().unwrap();
*finished = false;
/*let mut finished = self.draw_finished.lock().unwrap();
if !*finished {
return Ok(());
}
*finished = false;*/
self.chan
.send(Command::Redraw)
.map_err(|_| recv_shut_down_error())?;

while !*finished {
finished = self.draw_finished.1.wait(finished).unwrap();
}
//while !*finished {
// finished = self.draw_finished.1.wait(finished).unwrap();
//}
Ok(())
}

Expand All @@ -61,8 +64,8 @@ impl RenderWindowController {
fn window_runtime(
app: AppBuildFn,
window: Arc<WinitWindow>,
pixels: Pixels,
mut rx: mpsc::UnboundedReceiver<Command>,
draw_finished: Arc<(StdMutex<bool>, Condvar)>,
) {
let async_runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
Expand All @@ -71,7 +74,9 @@ fn window_runtime(

let local = LocalSet::new();
local.block_on(&async_runtime, async move {
let mut rw = RenderWindow::new(app, window.clone()).expect("cannot launch renderer");
let mut rw =
RenderWindow::new(app, pixels, window.clone()).expect("cannot launch renderer");

loop {
let Some(cmd) = rx.recv().await else {
break;
Expand All @@ -80,11 +85,11 @@ fn window_runtime(
match cmd {
Command::Redraw => {
rw.redraw();
*draw_finished.0.lock().unwrap() = true;
draw_finished.1.notify_all();
window.request_redraw();
//window.request_redraw();
}
Command::HandleEvent(ev) => {
rw.handle_event(ev);
}
Command::HandleEvent(ev) => rw.handle_event(ev),
}
}
});
Expand Down
61 changes: 29 additions & 32 deletions irisia-backend/src/render_window/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use std::{
};

use anyhow::{anyhow, Result};
use pixels::{
wgpu::{BlendState, DeviceDescriptor, Features, Limits},
Pixels, PixelsBuilder, SurfaceTexture,
};
use pixels::{wgpu::BlendState, Pixels, PixelsBuilder, SurfaceTexture};
use skia_safe::{Canvas, Color, ColorSpace, ColorType, ImageInfo, Surface};
use winit::dpi::PhysicalSize;

Expand All @@ -24,38 +21,22 @@ pub struct Renderer {
counter: Arc<AtomicU16>,
}

#[cfg(feature = "fps_recorder")]
fn fps_recorder() -> Arc<AtomicU16> {
let counter = Arc::new(AtomicU16::new(0));
let counter_cloned = counter.clone();

std::thread::spawn(move || loop {
std::thread::sleep(Duration::from_secs(2));
println!(
"{}fps",
counter.swap(0, std::sync::atomic::Ordering::Relaxed) / 2
);
});
counter_cloned
}

impl Renderer {
pub fn new(window: &Arc<WinitWindow>) -> Result<Self> {
pub fn create_pixels(window: &WinitWindow) -> Result<Pixels> {
let PhysicalSize { width, height } = window.inner_size();

let (w2x, h2x) = to_size2x(window.inner_size());

let pixels =
PixelsBuilder::new(width, height, SurfaceTexture::new(width, height, &**window))
Ok(
PixelsBuilder::new(width, height, SurfaceTexture::new(width, height, window))
.blend_state(BlendState::REPLACE)
.enable_vsync(false)
.device_descriptor(DeviceDescriptor {
label: Default::default(),
features: Features::empty(),
limits: Limits::downlevel_defaults().using_resolution(Limits::default()),
})
.enable_vsync(true)
.clear_color(pixels::wgpu::Color::BLUE)
.build()?;
.build()?,
)
}

pub fn new(pixels: Pixels, window: &Arc<WinitWindow>) -> Result<Self> {
let PhysicalSize { width, height } = window.inner_size();
println!("bar");
let (w2x, h2x) = to_size2x(window.inner_size());

let image_info = ImageInfo::new(
(width as _, height as _),
Expand Down Expand Up @@ -86,6 +67,7 @@ impl Renderer {
{
let canvas = self.surface.canvas();
canvas.clear(Color::TRANSPARENT);

f(canvas)?;

if !self.surface.read_pixels(
Expand Down Expand Up @@ -142,3 +124,18 @@ fn to_size2x(size: PhysicalSize<u32>) -> (u32, u32) {
(height as f32 / 256.0).ceil() as u32 * 256,
)
}

#[cfg(feature = "fps_recorder")]
fn fps_recorder() -> Arc<AtomicU16> {
let counter = Arc::new(AtomicU16::new(0));
let counter_cloned = counter.clone();

std::thread::spawn(move || loop {
std::thread::sleep(Duration::from_secs(2));
println!(
"{}fps",
counter.swap(0, std::sync::atomic::Ordering::Relaxed) / 2
);
});
counter_cloned
}
5 changes: 3 additions & 2 deletions irisia-backend/src/render_window/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
};

use anyhow::Result;
use pixels::Pixels;
use winit::event::WindowEvent;

use crate::{runtime::rt_event::AppBuildFn, AppWindow, WinitWindow};
Expand All @@ -18,10 +19,10 @@ pub struct RenderWindow {
}

impl RenderWindow {
pub fn new(app: AppBuildFn, window: Arc<WinitWindow>) -> Result<Self> {
pub fn new(app: AppBuildFn, pixels: Pixels, window: Arc<WinitWindow>) -> Result<Self> {
Ok(RenderWindow {
app: app(),
renderer: Renderer::new(&window)?,
renderer: Renderer::new(pixels, &window)?,
window,
last_frame_instant: None,
})
Expand Down
10 changes: 5 additions & 5 deletions irisia-backend/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Result;
use tokio::task::LocalSet;
use winit::{
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopBuilder},
event_loop::{ControlFlow, EventLoop},
window::WindowId,
};

Expand Down Expand Up @@ -39,7 +39,7 @@ where

let _guards = (tokio_runtime.enter(), local_set.enter());

let event_loop: EventLoop<WindowReg> = EventLoopBuilder::with_user_event().build()?;
let event_loop: EventLoop<WindowReg> = EventLoop::with_user_event().build()?;
let mut window_map: HashMap<WindowId, RenderWindowController> = HashMap::new();
WindowRegiterMutex::init(event_loop.create_proxy());

Expand Down Expand Up @@ -70,11 +70,11 @@ where

Event::UserEvent(window_reg) => match window_reg {
WindowReg::RawWindowRequest {
builder,
window_attributes,
window_giver,
} => {
let window = builder.build(window_target);
let _ = window_giver.send(window);
let result_window = window_target.create_window(window_attributes);
let _ = window_giver.send(result_window);
}

WindowReg::WindowRegister { app, raw_window } => {
Expand Down
Loading

0 comments on commit 602b20c

Please sign in to comment.