Skip to content

Commit

Permalink
eframe glow backend: Clear render target before calling App::update (
Browse files Browse the repository at this point in the history
…#3665)

* Closes #3659
  • Loading branch information
emilk authored Nov 30, 2023
1 parent bd9bc25 commit 4b1523a
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 60 deletions.
10 changes: 8 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

125 changes: 78 additions & 47 deletions crates/eframe/src/native/glow_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,31 @@ impl GlowWinitRunning {
(raw_input, viewport_ui_cb)
};

{
// clear before we call update, so users can paint between clear-color and egui windows:

let clear_color = self
.app
.clear_color(&self.integration.egui_ctx.style().visuals);
let mut glutin = self.glutin.borrow_mut();
let GlutinWindowContext {
viewports,
current_gl_context,
..
} = &mut *glutin;
let viewport = &viewports[&viewport_id];
let window = viewport.window.as_ref().unwrap();
let gl_surface = viewport.gl_surface.as_ref().unwrap();

let screen_size_in_pixels: [u32; 2] = window.inner_size().into();

change_gl_context(current_gl_context, gl_surface);

self.painter
.borrow()
.clear(screen_size_in_pixels, clear_color);
}

// ------------------------------------------------------------
// The update function, which could call immediate viewports,
// so make sure we don't hold any locks here required by the immediate viewports rendeer.
Expand Down Expand Up @@ -579,30 +604,11 @@ impl GlowWinitRunning {

let clipped_primitives = integration.egui_ctx.tessellate(shapes, pixels_per_point);

{
// TODO: only do this if we actually have multiple viewports
crate::profile_scope!("change_gl_context");

let not_current = {
crate::profile_scope!("make_not_current");
current_gl_context
.take()
.unwrap()
.make_not_current()
.unwrap()
};

crate::profile_scope!("make_current");
*current_gl_context = Some(not_current.make_current(gl_surface).unwrap());
}
// We may need to switch contexts again, because of immediate viewports:
change_gl_context(current_gl_context, gl_surface);

let screen_size_in_pixels: [u32; 2] = window.inner_size().into();

painter.clear(
screen_size_in_pixels,
app.clear_color(&integration.egui_ctx.style().visuals),
);

painter.paint_and_update_textures(
screen_size_in_pixels,
pixels_per_point,
Expand Down Expand Up @@ -770,6 +776,24 @@ impl GlowWinitRunning {
}
}

fn change_gl_context(
current_gl_context: &mut Option<glutin::context::PossiblyCurrentContext>,
gl_surface: &glutin::surface::Surface<glutin::surface::WindowSurface>,
) {
crate::profile_function!();

let not_current = {
crate::profile_scope!("make_not_current");
current_gl_context
.take()
.unwrap()
.make_not_current()
.unwrap()
};
crate::profile_scope!("make_current");
*current_gl_context = Some(not_current.make_current(gl_surface).unwrap());
}

impl GlutinWindowContext {
#[allow(unsafe_code)]
unsafe fn new(
Expand Down Expand Up @@ -1289,10 +1313,7 @@ fn render_immediate_viewport(
let Some(viewport) = glutin.viewports.get_mut(&ids.this) else {
return;
};
let Some(egui_winit) = &mut viewport.egui_winit else {
return;
};
let Some(window) = &viewport.window else {
let (Some(egui_winit), Some(window)) = (&mut viewport.egui_winit, &viewport.window) else {
return;
};
egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window);
Expand Down Expand Up @@ -1324,6 +1345,8 @@ fn render_immediate_viewport(

// ---------------------------------------------------

let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);

let mut glutin = glutin.borrow_mut();

let GlutinWindowContext {
Expand All @@ -1335,41 +1358,49 @@ fn render_immediate_viewport(
let Some(viewport) = viewports.get_mut(&ids.this) else {
return;
};

viewport.info.events.clear(); // they should have been processed

let Some(winit_state) = &mut viewport.egui_winit else {
return;
};
let (Some(window), Some(gl_surface)) = (&viewport.window, &viewport.gl_surface) else {
let (Some(egui_winit), Some(window), Some(gl_surface)) = (
&mut viewport.egui_winit,
&viewport.window,
&viewport.gl_surface,
) else {
return;
};

let screen_size_in_pixels: [u32; 2] = window.inner_size().into();

let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point);

let mut painter = painter.borrow_mut();

*current_gl_context = Some(
current_gl_context
.take()
.unwrap()
.make_not_current()
.unwrap()
.make_current(gl_surface)
.unwrap(),
);
{
crate::profile_function!("context-switch");
*current_gl_context = Some(
current_gl_context
.take()
.unwrap()
.make_not_current()
.unwrap()
.make_current(gl_surface)
.unwrap(),
);
}

let current_gl_context = current_gl_context.as_ref().unwrap();

if !gl_surface.is_current(current_gl_context) {
log::error!("egui::show_viewport_immediate: viewport {:?} ({:?}) is not created in main thread, try to use wgpu!", viewport.ids.this, viewport.builder.title);
log::error!(
"egui::show_viewport_immediate: viewport {:?} ({:?}) was not created on main thread.",
viewport.ids.this,
viewport.builder.title
);
}

let gl = &painter.gl().clone();
egui_glow::painter::clear(gl, screen_size_in_pixels, [0.0, 0.0, 0.0, 0.0]);
egui_glow::painter::clear(
painter.borrow().gl(),
screen_size_in_pixels,
[0.0, 0.0, 0.0, 0.0],
);

painter.paint_and_update_textures(
painter.borrow_mut().paint_and_update_textures(
screen_size_in_pixels,
pixels_per_point,
&clipped_primitives,
Expand All @@ -1383,7 +1414,7 @@ fn render_immediate_viewport(
}
}

winit_state.handle_platform_output(window, egui_ctx, platform_output);
egui_winit.handle_platform_output(window, egui_ctx, platform_output);

glutin.handle_viewport_output(egui_ctx, viewport_output);
}
Expand Down
13 changes: 5 additions & 8 deletions crates/eframe/src/native/wgpu_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,13 +875,13 @@ fn render_immediate_viewport(
viewport.init_window(egui_ctx, viewport_from_window, painter, event_loop);
}

let (Some(window), Some(winit_state)) = (&viewport.window, &mut viewport.egui_winit) else {
let (Some(window), Some(egui_winit)) = (&viewport.window, &mut viewport.egui_winit) else {
return;
};
egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window);

winit_state.update_pixels_per_point(egui_ctx, window);
let mut input = winit_state.take_egui_input(window);
egui_winit.update_pixels_per_point(egui_ctx, window);
let mut input = egui_winit.take_egui_input(window);
input.viewports = viewports
.iter()
.map(|(id, viewport)| (*id, viewport.info.clone()))
Expand Down Expand Up @@ -920,10 +920,7 @@ fn render_immediate_viewport(
return;
};
viewport.info.events.clear(); // they should have been processed
let Some(winit_state) = &mut viewport.egui_winit else {
return;
};
let Some(window) = &viewport.window else {
let (Some(egui_winit), Some(window)) = (&mut viewport.egui_winit, &viewport.window) else {
return;
};

Expand All @@ -947,7 +944,7 @@ fn render_immediate_viewport(
false,
);

winit_state.handle_platform_output(window, &egui_ctx, platform_output);
egui_winit.handle_platform_output(window, &egui_ctx, platform_output);

handle_viewport_output(&egui_ctx, viewport_output, viewports, *focused_viewport);
}
Expand Down
2 changes: 0 additions & 2 deletions examples/custom_3d_glow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,4 @@ publish = false
eframe = { path = "../../crates/eframe", features = [
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
egui_glow = { path = "../../crates/egui_glow" }
env_logger = "0.10"
glow = "0.12"
2 changes: 1 addition & 1 deletion examples/custom_3d_glow/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(unsafe_code)]

use eframe::egui;
use eframe::{egui, egui_glow, glow};

use egui::mutex::Mutex;
use std::sync::Arc;
Expand Down
14 changes: 14 additions & 0 deletions examples/test_inline_glow_paint/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "test_inline_glow_paint"
version = "0.1.0"
authors = ["Emil Ernerfeldt <[email protected]>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.72"
publish = false

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
eframe = { path = "../../crates/eframe" }
env_logger = "0.10"
40 changes: 40 additions & 0 deletions examples/test_inline_glow_paint/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Test that we can paint to the screen using glow directly.

use eframe::egui;
use eframe::glow;

fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let options = eframe::NativeOptions {
renderer: eframe::Renderer::Glow,
..Default::default()
};
eframe::run_native(
"My test app",
options,
Box::new(|_cc| Box::<MyTestApp>::default()),
)?;
Ok(())
}

#[derive(Default)]
struct MyTestApp {}

impl eframe::App for MyTestApp {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
use glow::HasContext as _;
let gl = frame.gl().unwrap();

#[allow(unsafe_code)]
unsafe {
gl.disable(glow::SCISSOR_TEST);
gl.viewport(0, 0, 100, 100);
gl.clear_color(1.0, 0.0, 1.0, 1.0); // purple
gl.clear(glow::COLOR_BUFFER_BIT);
}

egui::Window::new("Floating Window").show(ctx, |ui| {
ui.label("The background should be purple.");
});
}
}

0 comments on commit 4b1523a

Please sign in to comment.