diff --git a/Cargo.lock b/Cargo.lock index d6ef533..0858faf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,10 +127,13 @@ dependencies = [ "egui", "egui-winit", "egui_glium", + "egui_glow", "egui_vulkano", "epaint", "epi", "glium", + "glow", + "glutin", "gumdrop", "log", "nix 0.23.1", @@ -754,6 +757,20 @@ dependencies = [ "glium", ] +[[package]] +name = "egui_glow" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fba815b217b8d4c17dcd080497d9ea2ad0e2047aec8d584db1c7c4a28e978db" +dependencies = [ + "egui", + "egui-winit", + "epi", + "glow", + "glutin", + "memoffset", +] + [[package]] name = "egui_vulkano" version = "0.4.0" @@ -881,6 +898,18 @@ dependencies = [ "takeable-option", ] +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glutin" version = "0.27.0" @@ -1777,6 +1806,15 @@ dependencies = [ "libc", ] +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.7.0" diff --git a/amdguid/Cargo.toml b/amdguid/Cargo.toml index 405c39a..1bc49aa 100644 --- a/amdguid/Cargo.toml +++ b/amdguid/Cargo.toml @@ -16,7 +16,8 @@ wayland = [ "vulkano-shaders", "_gui" ] -xorg = ["glium", "egui_glium", "_gui"] +xorg-glium = ["glium", "egui_glium", "_gui"] +xorg-glow = ["glow", "egui_glow", "glutin", "_gui"] default = ["wayland"] _gui = [ "egui", @@ -49,9 +50,13 @@ egui_vulkano = { version = "0.4.0", optional = true } vulkano-win = { version = "0.25.0", optional = true } vulkano = { version = "0.25.0", optional = true } vulkano-shaders = { version = "0.25.0", optional = true } -# xorg +# xorg glium glium = { version = "0.30", optional = true } egui_glium = { version = "0.15.0", optional = true } +# xorg glow +glutin = { version = "0.27.0", optional = true } +glow = { version = "0.11.2", optional = true } +egui_glow = { version = "0.15.0", optional = true } tokio = { version = "1.15.0", features = ["full"] } parking_lot = { version = "0.11.2" } diff --git a/amdguid/src/backend/xorg.rs b/amdguid/src/backend/glium_backend.rs similarity index 51% rename from amdguid/src/backend/xorg.rs rename to amdguid/src/backend/glium_backend.rs index abece09..a0ca948 100644 --- a/amdguid/src/backend/xorg.rs +++ b/amdguid/src/backend/glium_backend.rs @@ -1,10 +1,9 @@ -use egui::panel::TopBottomSide; -use egui::{Layout, PointerButton}; -use epaint::TextStyle; use parking_lot::Mutex; use std::sync::Arc; +use tokio::sync::mpsc::UnboundedReceiver; -use crate::app::{AmdGui, Page}; +use crate::app::AmdGui; +use crate::backend::create_ui; use glium::glutin; fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display { @@ -25,57 +24,28 @@ fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Disp glium::Display::new(window_builder, context_builder, event_loop).unwrap() } -pub fn run_app(amd_gui: Arc>) { +pub fn run_app(amd_gui: Arc>, mut receiver: UnboundedReceiver) { let event_loop = glutin::event_loop::EventLoop::with_user_event(); let display = create_display(&event_loop); let mut egui = egui_glium::EguiGlium::new(&display); + let proxy = event_loop.create_proxy(); + tokio::spawn(async move { + loop { + if receiver.recv().await.is_some() { + if let Err(e) = proxy.send_event(()) { + log::error!("{:?}", e); + } + } + } + }); + event_loop.run(move |event, _, control_flow| { let mut redraw = || { egui.begin_frame(&display); - egui::containers::TopBottomPanel::new(TopBottomSide::Top, "menu").show( - egui.ctx(), - |ui| { - let mut child = - ui.child_ui(ui.available_rect_before_wrap(), Layout::left_to_right()); - if child - .add(egui::Button::new("Config").text_style(TextStyle::Heading)) - .clicked_by(PointerButton::Primary) - { - amd_gui.lock().page = Page::Config; - } - if child - .add(egui::Button::new("Monitoring").text_style(TextStyle::Heading)) - .clicked_by(PointerButton::Primary) - { - amd_gui.lock().page = Page::Monitoring; - } - if child - .add(egui::Button::new("Settings").text_style(TextStyle::Heading)) - .clicked_by(PointerButton::Primary) - { - amd_gui.lock().page = Page::Settings; - } - }, - ); - - egui::containers::CentralPanel::default().show(egui.ctx(), |ui| { - let mut gui = amd_gui.lock(); - let page = gui.page; - match page { - Page::Config => { - gui.ui(ui); - } - Page::Monitoring => { - gui.ui(ui); - } - Page::Settings => { - egui.ctx().settings_ui(ui); - } - } - }); + create_ui(amd_gui.clone(), egui.ctx()); let (needs_repaint, shapes) = egui.end_frame(&display); @@ -98,7 +68,9 @@ pub fn run_app(amd_gui: Arc>) { }; match event { - glutin::event::Event::RedrawRequested(_) => redraw(), + glutin::event::Event::UserEvent(_) | glutin::event::Event::RedrawRequested(_) => { + redraw() + } glutin::event::Event::WindowEvent { event, .. } => { if egui.is_quit_event(&event) { *control_flow = glium::glutin::event_loop::ControlFlow::Exit; diff --git a/amdguid/src/backend/glow_backend.rs b/amdguid/src/backend/glow_backend.rs new file mode 100644 index 0000000..7cbdc9d --- /dev/null +++ b/amdguid/src/backend/glow_backend.rs @@ -0,0 +1,120 @@ +use std::sync::Arc; + +use parking_lot::Mutex; +use tokio::sync::mpsc::UnboundedReceiver; + +use crate::backend::create_ui; +use crate::AmdGui; + +fn create_display( + event_loop: &glutin::event_loop::EventLoop<()>, +) -> ( + glutin::WindowedContext, + ::glow::Context, +) { + let window_builder = glutin::window::WindowBuilder::new() + .with_resizable(true) + .with_inner_size(glutin::dpi::LogicalSize { + width: 800.0, + height: 600.0, + }) + .with_title("AMD GUI"); + + let gl_window = unsafe { + glutin::ContextBuilder::new() + .with_depth_buffer(0) + .with_srgb(true) + .with_stencil_buffer(0) + .with_vsync(true) + .build_windowed(window_builder, event_loop) + .unwrap() + .make_current() + .unwrap() + }; + + let gl = unsafe { ::glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) }; + + unsafe { + use glow::HasContext as _; + gl.enable(glow::FRAMEBUFFER_SRGB); + } + + (gl_window, gl) +} + +pub fn run_app(amd_gui: Arc>, mut receiver: UnboundedReceiver) { + let event_loop = glutin::event_loop::EventLoop::with_user_event(); + let (gl_window, gl) = create_display(&event_loop); + + let mut egui = egui_glow::EguiGlow::new(&gl_window, &gl); + let proxy = event_loop.create_proxy(); + + tokio::spawn(async move { + loop { + if receiver.recv().await.is_some() { + if let Err(e) = proxy.send_event(()) { + log::error!("{:?}", e); + } + } + } + }); + + event_loop.run(move |event, _, control_flow| { + let mut redraw = || { + egui.begin_frame(gl_window.window()); + + create_ui(amd_gui.clone(), egui.ctx()); + + let (needs_repaint, shapes) = egui.end_frame(gl_window.window()); + + *control_flow = if needs_repaint { + gl_window.window().request_redraw(); + glutin::event_loop::ControlFlow::Poll + } else { + glutin::event_loop::ControlFlow::Wait + }; + + { + let color = egui::Rgba::from_rgb(0.1, 0.3, 0.2); + unsafe { + use glow::HasContext as _; + gl.clear_color(color[0], color[1], color[2], color[3]); + gl.clear(glow::COLOR_BUFFER_BIT); + } + + // draw things behind egui here + + egui.paint(&gl_window, &gl, shapes); + + // draw things on top of egui here + + gl_window.swap_buffers().unwrap(); + } + }; + + match event { + glutin::event::Event::UserEvent(_) | glutin::event::Event::RedrawRequested(_) => { + redraw() + } + + glutin::event::Event::WindowEvent { event, .. } => { + if egui.is_quit_event(&event) { + *control_flow = glutin::event_loop::ControlFlow::Exit; + } + + if let glutin::event::WindowEvent::Resized(physical_size) = event { + gl_window.resize(physical_size); + } + + egui.on_event(&event); + + gl_window.window().request_redraw(); // TODO: ask egui if the events warrants a repaint instead + } + glutin::event::Event::LoopDestroyed => { + egui.destroy(&gl); + } + + _ => (), + } + }); +} diff --git a/amdguid/src/backend/mod.rs b/amdguid/src/backend/mod.rs index c33963e..9a4273e 100644 --- a/amdguid/src/backend/mod.rs +++ b/amdguid/src/backend/mod.rs @@ -1,10 +1,62 @@ +#[cfg(feature = "xorg-glium")] +pub mod glium_backend; +#[cfg(feature = "xorg-glow")] +pub mod glow_backend; #[cfg(feature = "wayland")] -pub mod wayland; -#[cfg(feature = "xorg")] -pub mod xorg; +pub mod wayland_backend; +use egui::panel::TopBottomSide; +use egui::{Layout, PointerButton}; +use epaint::TextStyle; +use parking_lot::Mutex; +use std::sync::Arc; #[cfg(feature = "wayland")] -pub use wayland::run_app; +pub use wayland_backend::run_app; -#[cfg(feature = "xorg")] -pub use xorg::run_app; +#[cfg(feature = "xorg-glow")] +pub use glow_backend::run_app; + +use crate::app::Page; +use crate::AmdGui; +#[cfg(feature = "xorg-glium")] +pub use glium_backend::run_app; + +pub fn create_ui(amd_gui: Arc>, ctx: &egui::CtxRef) { + egui::containers::TopBottomPanel::new(TopBottomSide::Top, "menu").show(ctx, |ui| { + let mut child = ui.child_ui(ui.available_rect_before_wrap(), Layout::left_to_right()); + if child + .add(egui::Button::new("Config").text_style(TextStyle::Heading)) + .clicked_by(PointerButton::Primary) + { + amd_gui.lock().page = Page::Config; + } + if child + .add(egui::Button::new("Monitoring").text_style(TextStyle::Heading)) + .clicked_by(PointerButton::Primary) + { + amd_gui.lock().page = Page::Monitoring; + } + if child + .add(egui::Button::new("Settings").text_style(TextStyle::Heading)) + .clicked_by(PointerButton::Primary) + { + amd_gui.lock().page = Page::Settings; + } + }); + + egui::containers::CentralPanel::default().show(ctx, |ui| { + let mut gui = amd_gui.lock(); + let page = gui.page; + match page { + Page::Config => { + gui.ui(ui); + } + Page::Monitoring => { + gui.ui(ui); + } + Page::Settings => { + ctx.settings_ui(ui); + } + } + }); +} diff --git a/amdguid/src/backend/wayland.rs b/amdguid/src/backend/wayland_backend.rs similarity index 84% rename from amdguid/src/backend/wayland.rs rename to amdguid/src/backend/wayland_backend.rs index 31ba9ce..f03bbae 100644 --- a/amdguid/src/backend/wayland.rs +++ b/amdguid/src/backend/wayland_backend.rs @@ -1,9 +1,8 @@ -use crate::app::{AmdGui, Page}; -use egui::panel::TopBottomSide; -use egui::{Layout, PointerButton}; -use epaint::TextStyle; +use crate::app::AmdGui; +use crate::backend::create_ui; use parking_lot::Mutex; use std::sync::Arc; +use tokio::sync::mpsc::UnboundedReceiver; use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; use vulkano::command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents, @@ -52,7 +51,7 @@ struct Vertex { position: [f32; 2], } -pub fn run_app(amd_gui: Arc>) { +pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) { let required_extensions = vulkano_win::required_extensions(); let instance = vulkano::instance::Instance::new(None, Version::V1_0, &required_extensions, None).unwrap(); @@ -213,7 +212,7 @@ pub fn run_app(amd_gui: Arc>) { // do your own event handling here }; } - Event::RedrawEventsCleared => { + Event::UserEvent(_) | Event::RedrawEventsCleared => { previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swap_chain { @@ -275,47 +274,7 @@ pub fn run_app(amd_gui: Arc>) { egui_ctx.begin_frame(egui_winit.take_egui_input(surface.window())); - egui::containers::TopBottomPanel::new(TopBottomSide::Top, "menu").show( - &egui_ctx, - |ui| { - let mut child = - ui.child_ui(ui.available_rect_before_wrap(), Layout::left_to_right()); - if child - .add(egui::Button::new("Config").text_style(TextStyle::Heading)) - .clicked_by(PointerButton::Primary) - { - amd_gui.lock().page = Page::Config; - } - if child - .add(egui::Button::new("Monitoring").text_style(TextStyle::Heading)) - .clicked_by(PointerButton::Primary) - { - amd_gui.lock().page = Page::Monitoring; - } - if child - .add(egui::Button::new("Settings").text_style(TextStyle::Heading)) - .clicked_by(PointerButton::Primary) - { - amd_gui.lock().page = Page::Settings; - } - }, - ); - - egui::containers::CentralPanel::default().show(&egui_ctx, |ui| { - let mut gui = amd_gui.lock(); - let page = gui.page; - match page { - Page::Config => { - gui.ui(ui); - } - Page::Monitoring => { - gui.ui(ui); - } - Page::Settings => { - egui_ctx.settings_ui(ui); - } - } - }); + create_ui(amd_gui.clone(), &egui_ctx); let (egui_output, clipped_shapes) = egui_ctx.end_frame(); egui_winit.handle_output(surface.window(), &egui_ctx, egui_output); diff --git a/amdguid/src/main.rs b/amdguid/src/main.rs index 533331d..9180d9d 100644 --- a/amdguid/src/main.rs +++ b/amdguid/src/main.rs @@ -1,4 +1,5 @@ use app::AmdGui; +use tokio::sync::mpsc::UnboundedReceiver; mod app; mod backend; @@ -22,16 +23,22 @@ async fn main() { )); let amd_gui = Arc::new(Mutex::new(AmdGui::new_with_config(config))); - schedule_tick(amd_gui.clone()); + let receiver = schedule_tick(amd_gui.clone()); - backend::run_app(amd_gui); + backend::run_app(amd_gui, receiver); } -fn schedule_tick(amd_gui: std::sync::Arc>) { +fn schedule_tick(amd_gui: std::sync::Arc>) -> UnboundedReceiver { + let (sender, receiver) = tokio::sync::mpsc::unbounded_channel(); tokio::spawn(async move { + let sender = sender; loop { amd_gui.lock().tick(); + if let Err(e) = sender.send(true) { + log::error!("Failed to propagate tick update. {:?}", e); + } tokio::time::sleep(tokio::time::Duration::from_millis(166)).await; } }); + receiver } diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..8613465 Binary files /dev/null and b/assets/logo.png differ diff --git a/scripts/build.sh b/scripts/build.sh index 9d95097..ad7fbe0 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -8,16 +8,21 @@ strip target/x86_64-unknown-linux-musl/release/amdfand strip target/x86_64-unknown-linux-musl/release/amdvold strip target/x86_64-unknown-linux-musl/release/amdmond -upx --best --lzma target/x86_64-unknown-linux-musl/release/amdfand -upx --best --lzma target/x86_64-unknown-linux-musl/release/amdvold -upx --best --lzma target/x86_64-unknown-linux-musl/release/amdmond +#upx --best --lzma target/x86_64-unknown-linux-musl/release/amdfand +#upx --best --lzma target/x86_64-unknown-linux-musl/release/amdvold +#upx --best --lzma target/x86_64-unknown-linux-musl/release/amdmond -cargo build --release --target x86_64-unknown-linux-gnu --bin amdguid --no-default-features --features xorg +cargo build --release --target x86_64-unknown-linux-gnu --bin amdguid --no-default-features --features xorg-glium strip target/x86_64-unknown-linux-gnu/release/amdguid -upx --best --lzma target/x86_64-unknown-linux-gnu/release/amdguid +#upx --best --lzma target/x86_64-unknown-linux-gnu/release/amdguid zip ./target/amdguid-glium.zip ./target/x86_64-unknown-linux-gnu/release/amdguid +cargo build --release --target x86_64-unknown-linux-gnu --bin amdguid --no-default-features --features xorg-glow +strip target/x86_64-unknown-linux-gnu/release/amdguid +#upx --best --lzma target/x86_64-unknown-linux-gnu/release/amdguid +zip ./target/amdguid-glow.zip ./target/x86_64-unknown-linux-gnu/release/amdguid + cargo build --release --target x86_64-unknown-linux-gnu --bin amdguid --no-default-features --features wayland strip target/x86_64-unknown-linux-gnu/release/amdguid -upx --best --lzma target/x86_64-unknown-linux-gnu/release/amdguid +#upx --best --lzma target/x86_64-unknown-linux-gnu/release/amdguid zip ./target/amdguid-wayland.zip ./target/x86_64-unknown-linux-gnu/release/amdguid diff --git a/scripts/compile.sh b/scripts/compile.sh index fcdf8b4..726d06c 100755 --- a/scripts/compile.sh +++ b/scripts/compile.sh @@ -6,4 +6,4 @@ cargo build --release --target x86_64-unknown-linux-musl --bin amdfand cargo build --release --target x86_64-unknown-linux-musl --bin amdmond cargo build --release --target x86_64-unknown-linux-musl --bin amdvold cargo build --release --target x86_64-unknown-linux-musl --bin amdgui-helper -cargo build --release --target x86_64-unknown-linux-gnu --bin amdguid --no-default-features --features xorg +cargo build --release --target x86_64-unknown-linux-gnu --bin amdguid --no-default-features --features xorg-glium diff --git a/scripts/zip-ci.sh b/scripts/zip-ci.sh index a2d7f8a..13acc4c 100755 --- a/scripts/zip-ci.sh +++ b/scripts/zip-ci.sh @@ -6,3 +6,4 @@ zip binaries-$1.zip ./target/x86_64-unknown-linux-musl/release/amdvold; zip binaries-$1.zip ./target/x86_64-unknown-linux-musl/release/amdgui-helper; zip binaries-$1.zip ./target/amdguid-wayland.zip; zip binaries-$1.zip ./target/amdguid-glium.zip +zip binaries-$1.zip ./target/amdguid-glow.zip diff --git a/scripts/zip-local.sh b/scripts/zip-local.sh new file mode 100755 index 0000000..1db95f0 --- /dev/null +++ b/scripts/zip-local.sh @@ -0,0 +1,17 @@ +cd "$(git rev-parse --show-toplevel)" + +echo Building archlinux.zip + +rm -Rf ./tmp/*.zip + +cp ./target/x86_64-unknown-linux-musl/release/amdfand ./tmp +cp ./target/x86_64-unknown-linux-musl/release/amdmond ./tmp +cp ./target/x86_64-unknown-linux-musl/release/amdvold ./tmp +cp ./target/x86_64-unknown-linux-musl/release/amdgui-helper ./tmp +cp ./target/amdguid-wayland.zip ./tmp +cp ./target/amdguid-glium.zip ./tmp +cp ./target/amdguid-glow.zip ./tmp + +cd ./tmp + +zip -R archlinux.zip *