Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion desktop/bundle/src/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use crate::common::*;

const PACKAGE: &str = "graphite-desktop-platform-win";
const EXECUTABLE: &str = "graphite-editor.exe";
const EXECUTABLE: &str = "graphite.exe";

pub fn main() -> Result<(), Box<dyn Error>> {
let app_bin = build_bin(PACKAGE, None)?;
Expand Down
84 changes: 49 additions & 35 deletions desktop/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ use crate::cef;
use crate::consts::CEF_MESSAGE_LOOP_MAX_ITERATIONS;
use crate::event::{AppEvent, AppEventScheduler};
use crate::persist::PersistentData;
use crate::render::GraphicsState;
use crate::render::{RenderError, RenderState};
use crate::window::Window;
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, Platform};
use crate::wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};

pub(crate) struct App {
cef_context: Box<dyn cef::CefContext>,
render_state: Option<RenderState>,
wgpu_context: WgpuContext,
window: Option<Window>,
window_scale: f64,
cef_schedule: Option<Instant>,
cef_view_info_sender: Sender<cef::ViewInfoUpdate>,
graphics_state: Option<GraphicsState>,
wgpu_context: WgpuContext,
app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler,
desktop_wrapper: DesktopWrapper,
cef_context: Box<dyn cef::CefContext>,
cef_schedule: Option<Instant>,
cef_view_info_sender: Sender<cef::ViewInfoUpdate>,
last_ui_update: Instant,
avg_frame_time: f32,
start_render_sender: SyncSender<()>,
Expand Down Expand Up @@ -77,17 +77,17 @@ impl App {
persistent_data.load_from_disk();

Self {
cef_context,
window: None,
window_scale: 1.0,
cef_schedule: Some(Instant::now()),
graphics_state: None,
cef_view_info_sender,
render_state: None,
wgpu_context,
window: None,
window_scale: 1.,
app_event_receiver,
app_event_scheduler,
desktop_wrapper: DesktopWrapper::new(),
last_ui_update: Instant::now(),
cef_context,
cef_schedule: Some(Instant::now()),
cef_view_info_sender,
avg_frame_time: 0.,
start_render_sender,
web_communication_initialized: false,
Expand Down Expand Up @@ -162,23 +162,23 @@ impl App {
});
}
DesktopFrontendMessage::UpdateViewportPhysicalBounds { x, y, width, height } => {
if let Some(graphics_state) = &mut self.graphics_state
if let Some(render_state) = &mut self.render_state
&& let Some(window) = &self.window
{
let window_size = window.surface_size();

let viewport_offset_x = x / window_size.width as f64;
let viewport_offset_y = y / window_size.height as f64;
graphics_state.set_viewport_offset([viewport_offset_x as f32, viewport_offset_y as f32]);
render_state.set_viewport_offset([viewport_offset_x as f32, viewport_offset_y as f32]);

let viewport_scale_x = if width != 0.0 { window_size.width as f64 / width } else { 1.0 };
let viewport_scale_y = if height != 0.0 { window_size.height as f64 / height } else { 1.0 };
graphics_state.set_viewport_scale([viewport_scale_x as f32, viewport_scale_y as f32]);
render_state.set_viewport_scale([viewport_scale_x as f32, viewport_scale_y as f32]);
}
}
DesktopFrontendMessage::UpdateOverlays(scene) => {
if let Some(graphics_state) = &mut self.graphics_state {
graphics_state.set_overlays_scene(scene);
if let Some(render_state) = &mut self.render_state {
render_state.set_overlays_scene(scene);
}
}
DesktopFrontendMessage::PersistenceWriteDocument { id, document } => {
Expand Down Expand Up @@ -331,19 +331,18 @@ impl App {
NodeGraphExecutionResult::HasRun(texture) => {
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::PollNodeGraphEvaluation);
if let Some(texture) = texture
&& let Some(graphics_state) = self.graphics_state.as_mut()
&& let Some(render_state) = self.render_state.as_mut()
&& let Some(window) = self.window.as_ref()
{
graphics_state.bind_viewport_texture(texture);
render_state.bind_viewport_texture(texture);
window.request_redraw();
}
}
NodeGraphExecutionResult::NotRun => {}
},
AppEvent::UiUpdate(texture) => {
if let Some(graphics_state) = self.graphics_state.as_mut() {
graphics_state.resize(texture.width(), texture.height());
graphics_state.bind_ui_texture(texture);
if let Some(render_state) = self.render_state.as_mut() {
render_state.bind_ui_texture(texture);
let elapsed = self.last_ui_update.elapsed().as_secs_f32();
self.last_ui_update = Instant::now();
if elapsed < 0.5 {
Expand Down Expand Up @@ -385,13 +384,18 @@ impl ApplicationHandler for App {

self.window_scale = window.scale_factor();
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Scale(self.window_scale));

// Ensures the CEF texture does not remain at 1x1 pixels until the window is resized by the user
// Affects only some Mac devices (issue found on 2023 M2 Mac Mini).
let PhysicalSize { width, height } = window.surface_size();
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size { width, height });

self.cef_context.notify_view_info_changed();

self.window = Some(window);

let graphics_state = GraphicsState::new(self.window.as_ref().unwrap(), self.wgpu_context.clone());

self.graphics_state = Some(graphics_state);
let render_state = RenderState::new(self.window.as_ref().unwrap(), self.wgpu_context.clone());
self.render_state = Some(render_state);

self.desktop_wrapper.init(self.wgpu_context.clone());

Expand All @@ -418,14 +422,18 @@ impl ApplicationHandler for App {
self.app_event_scheduler.schedule(AppEvent::CloseWindow);
}
WindowEvent::SurfaceResized(PhysicalSize { width, height }) => {
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size {
width: width as usize,
height: height as usize,
});
let _ = self.cef_view_info_sender.send(cef::ViewInfoUpdate::Size { width, height });
self.cef_context.notify_view_info_changed();

if let Some(render_state) = &mut self.render_state {
render_state.resize(width, height);
}

if let Some(window) = &self.window {
let maximized = window.is_maximized();
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(DesktopWrapperMessage::UpdateMaximized { maximized }));

window.request_redraw();
}
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
Expand All @@ -434,18 +442,24 @@ impl ApplicationHandler for App {
self.cef_context.notify_view_info_changed();
}
WindowEvent::RedrawRequested => {
let Some(ref mut graphics_state) = self.graphics_state else { return };
// Only rerender once we have a new UI texture to display
let Some(render_state) = &mut self.render_state else { return };
if let Some(window) = &self.window {
match graphics_state.render(window) {
let size = window.surface_size();
render_state.resize(size.width, size.height);

match render_state.render(window) {
Ok(_) => {}
Err(wgpu::SurfaceError::Lost) => {
Err(RenderError::OutdatedUITextureError) => {
self.cef_context.notify_view_info_changed();
}
Err(RenderError::SurfaceError(wgpu::SurfaceError::Lost)) => {
tracing::warn!("lost surface");
}
Err(wgpu::SurfaceError::OutOfMemory) => {
Err(RenderError::SurfaceError(wgpu::SurfaceError::OutOfMemory)) => {
tracing::error!("GPU out of memory");
event_loop.exit();
}
Err(e) => tracing::error!("{:?}", e),
Err(RenderError::SurfaceError(e)) => tracing::error!("Render error: {:?}", e),
}
let _ = self.start_render_sender.try_send(());
}
Expand Down
10 changes: 5 additions & 5 deletions desktop/src/cef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ pub(crate) trait CefEventHandler: Send + Sync + 'static {

#[derive(Clone, Copy)]
pub(crate) struct ViewInfo {
width: usize,
height: usize,
width: u32,
height: u32,
scale: f64,
}
impl ViewInfo {
Expand All @@ -78,10 +78,10 @@ impl ViewInfo {
pub(crate) fn zoom(&self) -> f64 {
self.scale.ln() / 1.2_f64.ln()
}
pub(crate) fn width(&self) -> usize {
pub(crate) fn width(&self) -> u32 {
self.width
}
pub(crate) fn height(&self) -> usize {
pub(crate) fn height(&self) -> u32 {
self.height
}
}
Expand All @@ -92,7 +92,7 @@ impl Default for ViewInfo {
}

pub(crate) enum ViewInfoUpdate {
Size { width: usize, height: usize },
Size { width: u32, height: u32 },
Scale(f64),
}

Expand Down
2 changes: 1 addition & 1 deletion desktop/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[derive(clap::Parser)]
#[clap(name = "graphite-editor", version)]
#[clap(name = "graphite", version)]
pub struct Cli {
#[arg(help = "Files to open on startup")]
pub files: Vec<std::path::PathBuf>,
Expand Down
1 change: 1 addition & 0 deletions desktop/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub(crate) const APP_NAME: &str = "Graphite";
#[cfg(target_os = "linux")]
pub(crate) const APP_ID: &str = "rs.graphite.Graphite";

pub(crate) const APP_DIRECTORY_NAME: &str = "graphite";
Expand Down
4 changes: 2 additions & 2 deletions desktop/src/render.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod frame_buffer_ref;
pub(crate) use frame_buffer_ref::FrameBufferRef;

mod graphics_state;
pub(crate) use graphics_state::GraphicsState;
mod state;
pub(crate) use state::{RenderError, RenderState};
20 changes: 16 additions & 4 deletions desktop/src/render/composite_shader.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
struct Constants {
viewport_scale: vec2<f32>,
viewport_offset: vec2<f32>,
ui_scale: vec2<f32>,
background_color: vec4<f32>,
};

var<push_constant> constants: Constants;
Expand All @@ -38,19 +40,29 @@ var s_diffuse: sampler;

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let ui_linear = srgb_to_linear(textureSample(t_ui, s_diffuse, in.tex_coords));
let ui_coordinate = in.tex_coords * constants.ui_scale;
if (ui_coordinate.x < 0.0 || ui_coordinate.x > 1.0 ||
ui_coordinate.y < 0.0 || ui_coordinate.y > 1.0) {
return srgb_to_linear(constants.background_color);
}

let ui_linear = srgb_to_linear(textureSample(t_ui, s_diffuse, ui_coordinate));
if (ui_linear.a >= 0.999) {
return ui_linear;
}

// UI texture is premultiplied, we need to unpremultiply before blending
let ui_srgb = linear_to_srgb(unpremultiply(ui_linear));

let viewport_coordinate = (in.tex_coords - constants.viewport_offset) * constants.viewport_scale;
if (viewport_coordinate.x < 0.0 || viewport_coordinate.x > 1.0 ||
viewport_coordinate.y < 0.0 || viewport_coordinate.y > 1.0) {
return srgb_to_linear(constants.background_color);
}

let overlay_srgb = textureSample(t_overlays, s_diffuse, viewport_coordinate);
let viewport_srgb = textureSample(t_viewport, s_diffuse, viewport_coordinate);

// UI texture is premultiplied, we need to unpremultiply before blending
let ui_srgb = linear_to_srgb(unpremultiply(ui_linear));

if (overlay_srgb.a < 0.001) {
if (ui_srgb.a < 0.001) {
return srgb_to_linear(viewport_srgb);
Expand Down
Loading