diff --git a/Cargo.toml b/Cargo.toml index 3f68d2b..4cdd7be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,4 @@ members = [ "irisia-utils", "examples", "tests", -] +] \ No newline at end of file diff --git a/examples/Cargo.toml b/examples/Cargo.toml index ebe096a..a1c35b7 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -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" } diff --git a/examples/simple_window.rs b/examples/simple_window.rs index 6be24b9..1f43975 100644 --- a/examples/simple_window.rs +++ b/examples/simple_window.rs @@ -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; @@ -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 diff --git a/examples/window_backend.rs b/examples/window_backend.rs index 9614b2b..6918097 100644 --- a/examples/window_backend.rs +++ b/examples/window_backend.rs @@ -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( props: Self::Props<'_>, diff --git a/examples/window_get_id.rs b/examples/window_get_id.rs new file mode 100644 index 0000000..58c66f4 --- /dev/null +++ b/examples/window_get_id.rs @@ -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, + counter: Arc, +} + +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(()) +} diff --git a/irisia-backend/Cargo.toml b/irisia-backend/Cargo.toml index db3a604..f580473 100644 --- a/irisia-backend/Cargo.toml +++ b/irisia-backend/Cargo.toml @@ -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" diff --git a/irisia-backend/src/render_window/mod.rs b/irisia-backend/src/render_window/mod.rs index fc12cc1..ebc6199 100644 --- a/irisia-backend/src/render_window/mod.rs +++ b/irisia-backend/src/render_window/mod.rs @@ -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; @@ -18,36 +20,37 @@ enum Command { pub struct RenderWindowController { chan: mpsc::UnboundedSender, - draw_finished: Arc<(StdMutex, Condvar)>, } impl RenderWindowController { pub fn new(app: AppBuildFn, window: Arc) -> Self { let (tx, rx) = mpsc::unbounded_channel::(); - 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(()) } @@ -61,8 +64,8 @@ impl RenderWindowController { fn window_runtime( app: AppBuildFn, window: Arc, + pixels: Pixels, mut rx: mpsc::UnboundedReceiver, - draw_finished: Arc<(StdMutex, Condvar)>, ) { let async_runtime = tokio::runtime::Builder::new_current_thread() .enable_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; @@ -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), } } }); diff --git a/irisia-backend/src/render_window/renderer.rs b/irisia-backend/src/render_window/renderer.rs index fc940ff..37c471e 100644 --- a/irisia-backend/src/render_window/renderer.rs +++ b/irisia-backend/src/render_window/renderer.rs @@ -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; @@ -24,38 +21,22 @@ pub struct Renderer { counter: Arc, } -#[cfg(feature = "fps_recorder")] -fn fps_recorder() -> Arc { - 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) -> Result { + pub fn create_pixels(window: &WinitWindow) -> Result { 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) -> Result { + 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 _), @@ -86,6 +67,7 @@ impl Renderer { { let canvas = self.surface.canvas(); canvas.clear(Color::TRANSPARENT); + f(canvas)?; if !self.surface.read_pixels( @@ -142,3 +124,18 @@ fn to_size2x(size: PhysicalSize) -> (u32, u32) { (height as f32 / 256.0).ceil() as u32 * 256, ) } + +#[cfg(feature = "fps_recorder")] +fn fps_recorder() -> Arc { + 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 +} diff --git a/irisia-backend/src/render_window/window.rs b/irisia-backend/src/render_window/window.rs index dcb78a8..8fe755a 100644 --- a/irisia-backend/src/render_window/window.rs +++ b/irisia-backend/src/render_window/window.rs @@ -4,6 +4,7 @@ use std::{ }; use anyhow::Result; +use pixels::Pixels; use winit::event::WindowEvent; use crate::{runtime::rt_event::AppBuildFn, AppWindow, WinitWindow}; @@ -18,10 +19,10 @@ pub struct RenderWindow { } impl RenderWindow { - pub fn new(app: AppBuildFn, window: Arc) -> Result { + pub fn new(app: AppBuildFn, pixels: Pixels, window: Arc) -> Result { Ok(RenderWindow { app: app(), - renderer: Renderer::new(&window)?, + renderer: Renderer::new(pixels, &window)?, window, last_frame_instant: None, }) diff --git a/irisia-backend/src/runtime/mod.rs b/irisia-backend/src/runtime/mod.rs index 29bf431..aafd06c 100644 --- a/irisia-backend/src/runtime/mod.rs +++ b/irisia-backend/src/runtime/mod.rs @@ -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, }; @@ -39,7 +39,7 @@ where let _guards = (tokio_runtime.enter(), local_set.enter()); - let event_loop: EventLoop = EventLoopBuilder::with_user_event().build()?; + let event_loop: EventLoop = EventLoop::with_user_event().build()?; let mut window_map: HashMap = HashMap::new(); WindowRegiterMutex::init(event_loop.create_proxy()); @@ -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 } => { diff --git a/irisia-backend/src/runtime/rt_event.rs b/irisia-backend/src/runtime/rt_event.rs index 7c4109d..1640250 100644 --- a/irisia-backend/src/runtime/rt_event.rs +++ b/irisia-backend/src/runtime/rt_event.rs @@ -1,9 +1,9 @@ -use std::sync::Arc; +use std::{fmt::Debug, sync::Arc}; use tokio::sync::oneshot; use winit::{ error::OsError, - window::{WindowBuilder, WindowId}, + window::{WindowAttributes, WindowId}, }; use crate::{AppWindow, WinitWindow}; @@ -12,7 +12,7 @@ pub(crate) type AppBuildFn = Box Box + Send>; pub(crate) enum WindowReg { RawWindowRequest { - builder: WindowBuilder, + window_attributes: WindowAttributes, window_giver: oneshot::Sender>, }, @@ -25,3 +25,14 @@ pub(crate) enum WindowReg { Exit, } + +impl Debug for WindowReg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + WindowReg::RawWindowRequest { .. } => f.debug_struct("RawWindowRequest").finish(), + WindowReg::WindowRegister { .. } => f.debug_struct("WindowRegister").finish(), + WindowReg::WindowDestroyed(..) => f.debug_tuple("WindowDestroyed").finish(), + WindowReg::Exit => f.write_str("Exit"), + } + } +} diff --git a/irisia-backend/src/window_handle/create.rs b/irisia-backend/src/window_handle/create.rs index 30eac01..1e8b6fd 100644 --- a/irisia-backend/src/window_handle/create.rs +++ b/irisia-backend/src/window_handle/create.rs @@ -7,12 +7,12 @@ use crate::{ use anyhow::Result; use tokio::sync::oneshot; -use winit::window::WindowBuilder; +use winit::window::WindowAttributes; use super::{close_handle::CloseHandle, RawWindowHandle}; impl RawWindowHandle { - pub async fn create(create_app: F, wb: WindowBuilder) -> Result + pub async fn create(create_app: F, wa: WindowAttributes) -> Result where A: AppWindow, F: FnOnce(Arc, CloseHandle) -> A + Send + 'static, @@ -22,7 +22,7 @@ impl RawWindowHandle { WindowRegiterMutex::lock() .await .send(WindowReg::RawWindowRequest { - builder: wb, + window_attributes: wa, window_giver, }); diff --git a/irisia-backend/src/window_handle/mod.rs b/irisia-backend/src/window_handle/mod.rs index 3b95fb4..7d23bf2 100644 --- a/irisia-backend/src/window_handle/mod.rs +++ b/irisia-backend/src/window_handle/mod.rs @@ -2,8 +2,6 @@ use std::{ops::Deref, sync::Arc}; use crate::WinitWindow; -pub use winit::window::WindowBuilder; - pub use self::close_handle::CloseHandle; mod close_handle; diff --git a/irisia-macros/src/lib.rs b/irisia-macros/src/lib.rs index d1e5e9b..b882bc3 100644 --- a/irisia-macros/src/lib.rs +++ b/irisia-macros/src/lib.rs @@ -3,7 +3,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::{ parse::{ParseStream, Parser}, - parse_macro_input, DeriveInput, Item, ItemFn, Result, + parse_macro_input, DeriveInput, Item, Result, }; mod build_macro; @@ -25,8 +25,7 @@ pub fn style(input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn main(_: TokenStream, input: TokenStream) -> TokenStream { - let item_fn = parse_macro_input!(input as ItemFn); - result_into_stream(main_macro::main_macro(item_fn)) + main_macro::main_macro(input) } #[proc_macro_derive(Event)] diff --git a/irisia-macros/src/main_macro.rs b/irisia-macros/src/main_macro.rs index 9a3e425..a42cddc 100644 --- a/irisia-macros/src/main_macro.rs +++ b/irisia-macros/src/main_macro.rs @@ -1,8 +1,12 @@ -use proc_macro2::TokenStream; -use quote::ToTokens; -use syn::{parse_quote, Error, ItemFn, Result}; +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::{quote, ToTokens}; +use syn::{ + parse::{Parse, Parser}, + parse_quote, Error, ItemFn, Result, +}; -pub fn main_macro(mut item: ItemFn) -> Result { +fn handle(mut item: ItemFn) -> Result { if item.sig.asyncness.take().is_none() { return Err(Error::new_spanned( &item.sig, @@ -20,3 +24,19 @@ pub fn main_macro(mut item: ItemFn) -> Result { Ok(item.into_token_stream()) } + +pub fn main_macro(input: TokenStream) -> TokenStream { + let input: TokenStream2 = input.into(); + + match ItemFn::parse.parse2(input.clone()).and_then(handle) { + Ok(result) => result, + Err(err) => { + let err = err.to_compile_error(); + quote! { + #err + #input + } + } + } + .into() +} diff --git a/irisia/src/application/backend.rs b/irisia/src/application/backend.rs index 18903a0..c65e510 100644 --- a/irisia/src/application/backend.rs +++ b/irisia/src/application/backend.rs @@ -2,8 +2,8 @@ use std::{cell::Cell, rc::Rc, sync::Arc, time::Duration}; use irisia_backend::{ skia_safe::{colors::WHITE, Canvas}, - window_handle::{RawWindowHandle, WindowBuilder}, - winit::{dpi::PhysicalSize, event::WindowEvent}, + window_handle::RawWindowHandle, + winit::{dpi::PhysicalSize, event::WindowEvent, window::WindowAttributes}, AppWindow, WinitWindow, }; @@ -36,7 +36,6 @@ where fn on_redraw(&mut self, canvas: &Canvas, interval: Duration) -> Result<()> { self.gc.redraw_scheduler.redraw(canvas, interval)?; - // composite canvas.reset_matrix(); canvas.clear(WHITE); @@ -74,7 +73,7 @@ fn window_size_to_draw_region(size: PhysicalSize) -> Region { } pub(super) async fn new_window( - window_builder: WindowBuilder, + window_attributes: WindowAttributes, root_creator: F, ) -> Result where @@ -116,7 +115,7 @@ where let RawWindowHandle { raw_window, close_handle, - } = RawWindowHandle::create(create_app, window_builder).await?; + } = RawWindowHandle::create(create_app, window_attributes).await?; Ok(Window { winit_window: Arc::downgrade(&raw_window), diff --git a/irisia/src/application/event_comp/global/mod.rs b/irisia/src/application/event_comp/global/mod.rs index f01da21..2c3d6ee 100644 --- a/irisia/src/application/event_comp/global/mod.rs +++ b/irisia/src/application/event_comp/global/mod.rs @@ -95,7 +95,11 @@ fn emit_physical_pointer_event( }), (PointerStateChange::LeaveViewport, None) => ed.emit_trusted(PointerOut), _ => { - unreachable!("unexpected new-pointer-state and optioned position combination") + eprintln!( + "warning: unexpected new-pointer-state and optioned position combination ({}:{})", + file!(), + line!() - 2 + ) } } } diff --git a/irisia/src/application/mod.rs b/irisia/src/application/mod.rs index dd3b00d..0c9baa1 100644 --- a/irisia/src/application/mod.rs +++ b/irisia/src/application/mod.rs @@ -1,6 +1,6 @@ use std::sync::Weak; -use irisia_backend::{window_handle::WindowBuilder, WinitWindow}; +use irisia_backend::{winit::window::WindowAttributes, WinitWindow}; use crate::{ el_model::SharedEM, @@ -28,12 +28,12 @@ pub struct Window { } impl Window { - pub async fn new(wb: WindowBuilder, dom: T) -> Result + pub async fn new(wa: WindowAttributes, dom: T) -> Result where T: StructureCreate> + Send + 'static, El: ElementInterfaces, { - new_window(wb, dom).await + new_window(wa, dom).await } pub fn winit_window(&self) -> &Weak {