Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make egui_glow painter to work on web #868

Merged
merged 30 commits into from
Nov 3, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
61cc0dc
glow painter webgl support.
KentaTheBugMaker Nov 1, 2021
fa22f04
Merge branch 'emilk:master' into master
KentaTheBugMaker Nov 1, 2021
33648f7
some clippy fix
KentaTheBugMaker Nov 1, 2021
2c3296e
Merge remote-tracking branch 'origin/master'
KentaTheBugMaker Nov 1, 2021
eaf58a0
some clippy workaround
KentaTheBugMaker Nov 2, 2021
4eb841e
clippy fix for web
KentaTheBugMaker Nov 2, 2021
d71656e
add workaround for painter_only
KentaTheBugMaker Nov 2, 2021
e3b4120
fix compatibility problem in fragment shader GLSL __VERSION__ <140
KentaTheBugMaker Nov 2, 2021
1887768
remove unneeded `gl_FragColor = v_rgba * texture_rgba;`
KentaTheBugMaker Nov 2, 2021
901cfa0
almost fixed issue
KentaTheBugMaker Nov 2, 2021
5bd0d5d
revert eframe change.
KentaTheBugMaker Nov 2, 2021
88027b1
small clippy fix ,toml fix and rewrite changelog
KentaTheBugMaker Nov 2, 2021
fb42a66
webgl2 return correct name.
KentaTheBugMaker Nov 2, 2021
51981c5
correct Cargo.toml for egui_glow.
KentaTheBugMaker Nov 2, 2021
18b05b9
clippy::needless-pass-by-value fix
KentaTheBugMaker Nov 2, 2021
dd2f8a6
Update egui_web/CHANGELOG.md
KentaTheBugMaker Nov 3, 2021
a4d7146
Update egui_glow/src/painter.rs
KentaTheBugMaker Nov 3, 2021
09c32b6
Update egui_glow/CHANGELOG.md
KentaTheBugMaker Nov 3, 2021
a47e7e5
Update egui_glow/src/painter.rs
KentaTheBugMaker Nov 3, 2021
ff25929
Update egui_glow/examples/pure_glow.rs
KentaTheBugMaker Nov 3, 2021
22245be
Update egui_glow/src/painter.rs
KentaTheBugMaker Nov 3, 2021
dc72728
Update egui_glow/src/painter.rs
KentaTheBugMaker Nov 3, 2021
e95ecb6
test we have to use emulated vao.
KentaTheBugMaker Nov 3, 2021
7faa359
report painter initializing error to caller.
KentaTheBugMaker Nov 3, 2021
7ac5c6a
merge upstream
KentaTheBugMaker Nov 3, 2021
a9c8b26
merge upstream
KentaTheBugMaker Nov 3, 2021
efcadb5
workaround for cargo check --all-target --all-feature
KentaTheBugMaker Nov 3, 2021
58ab9e6
fix docstring
KentaTheBugMaker Nov 3, 2021
c496e92
fix unfixed clippy issue
KentaTheBugMaker Nov 3, 2021
385c1fb
check glow backend build
KentaTheBugMaker Nov 3, 2021
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 egui_glow/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ All notable changes to the `egui_glow` integration will be noted in this file.


## Unreleased

* no glutin dependency in painter .
KentaTheBugMaker marked this conversation as resolved.
Show resolved Hide resolved

## 0.15.0 - 2021-10-24
`egui_glow` has been newly created, with feature parity to `egui_glium`.
Expand Down
19 changes: 15 additions & 4 deletions egui_glow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,24 @@ all-features = true

[dependencies]
egui = { version = "0.15.0", path = "../egui", default-features = false, features = ["single_threaded"] }
egui-winit = { version = "0.15.0", path = "../egui-winit", default-features = false, features = ["epi"] }
epi = { version = "0.15.0", path = "../epi", optional = true }

epi = { version = "0.15.0", path = "../epi", optional = true }
glow = "0.11"
glutin = "0.27"
memoffset = "0.6"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
egui-winit = { version = "0.15.0", path = "../egui-winit", default-features = false, features = ["epi"], optional = true }
glutin = { version = "0.27.0", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3", features=["console"] }
wasm-bindgen = { version = "0.2" }

[dev-dependencies]
image = { version = "0.23", default-features = false, features = ["png"] }

[features]
default = ["clipboard", "default_fonts", "links", "persistence"]
default = ["clipboard", "default_fonts", "links", "persistence", "winit"]

# enable cut/copy/paste to OS clipboard.
# if disabled a clipboard will be simulated so you can still copy/paste within the egui app.
Expand All @@ -58,3 +64,8 @@ persistence = [

# experimental support for a screen reader
screen_reader = ["egui-winit/screen_reader"]

# enable glutin/winit integration.
# if you want to use glow painter on web disable it.
# if disabled reduce crate size and build time.
winit= ["egui-winit","glutin"]
1 change: 0 additions & 1 deletion egui_glow/examples/pure_glow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ fn create_display(

(gl_window, gl)
}

fn main() {
KentaTheBugMaker marked this conversation as resolved.
Show resolved Hide resolved
let event_loop = glutin::event_loop::EventLoop::with_user_event();
let (gl_window, gl) = create_display(&event_loop);
Expand Down
18 changes: 1 addition & 17 deletions egui_glow/src/epi_backend.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,8 @@
use crate::*;
use egui::Color32;
#[cfg(target_os = "windows")]
use glutin::platform::windows::WindowBuilderExtWindows;
use std::time::Instant;

impl epi::TextureAllocator for Painter {
fn alloc_srgba_premultiplied(
&mut self,
size: (usize, usize),
srgba_pixels: &[Color32],
) -> egui::TextureId {
let id = self.alloc_user_texture();
self.set_user_texture(id, size, srgba_pixels);
id
}

fn free(&mut self, id: egui::TextureId) {
self.free_user_texture(id);
}
}
use std::time::Instant;

struct RequestRepaintEvent;

Expand Down
25 changes: 17 additions & 8 deletions egui_glow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,32 @@
#![allow(clippy::float_cmp)]
#![allow(clippy::manual_range_contains)]

mod painter;
pub mod painter;
pub use glow;
pub use painter::Painter;

#[cfg(feature = "epi")]
#[cfg(feature = "winit")]
mod epi_backend;
#[cfg(feature = "epi")]
pub use epi_backend::{run, NativeOptions};
mod misc_util;
mod post_process;
mod shader_version;
mod vao_emulate;

#[cfg(not(target_arch = "wasm32"))]
pub use egui_winit;
#[cfg(all(feature = "epi", feature = "winit"))]
pub use epi_backend::{run, NativeOptions};

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

/// Use [`egui`] from a [`glow`] app.
#[cfg(feature = "winit")]
pub struct EguiGlow {
egui_ctx: egui::CtxRef,
egui_winit: egui_winit::State,
painter: crate::Painter,
}

#[cfg(feature = "winit")]
impl EguiGlow {
pub fn new(
gl_window: &glutin::WindowedContext<glutin::PossiblyCurrent>,
Expand All @@ -114,7 +121,7 @@ impl EguiGlow {
Self {
egui_ctx: Default::default(),
egui_winit: egui_winit::State::new(gl_window.window()),
painter: crate::Painter::new(gl),
painter: crate::Painter::new(gl, None),
}
}

Expand Down Expand Up @@ -190,12 +197,14 @@ impl EguiGlow {
shapes: Vec<egui::epaint::ClippedShape>,
) {
let clipped_meshes = self.egui_ctx.tessellate(shapes);
let dimensions: [u32; 2] = gl_window.window().inner_size().into();
self.painter
.upload_egui_texture(gl, &self.egui_ctx.texture());
self.painter.paint_meshes(
gl_window,
dimensions,
gl,
self.egui_ctx.pixels_per_point(),
clipped_meshes,
&self.egui_ctx.texture(),
);
}

Expand Down
186 changes: 186 additions & 0 deletions egui_glow/src/misc_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#![allow(unsafe_code)]
use glow::HasContext;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::JsValue;

pub(crate) fn srgbtexture2d(
gl: &glow::Context,
is_webgl_1: bool,
srgb_support: bool,
data: &[u8],
w: usize,
h: usize,
) -> glow::Texture {
assert_eq!(data.len(), w * h * 4);
assert!(w >= 1);
assert!(h >= 1);
unsafe {
let tex = gl.create_texture().unwrap();
gl.bind_texture(glow::TEXTURE_2D, Some(tex));

gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MAG_FILTER,
glow::LINEAR as i32,
);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MIN_FILTER,
glow::LINEAR as i32,
);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_WRAP_S,
glow::CLAMP_TO_EDGE as i32,
);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_WRAP_T,
glow::CLAMP_TO_EDGE as i32,
);
if is_webgl_1 {
let format = if srgb_support {
glow::SRGB_ALPHA
} else {
glow::RGBA
};
gl.tex_image_2d(
glow::TEXTURE_2D,
0,
format as i32,
w as i32,
h as i32,
0,
format,
glow::UNSIGNED_BYTE,
Some(data),
);
} else {
gl.tex_storage_2d(glow::TEXTURE_2D, 1, glow::SRGB8_ALPHA8, w as i32, h as i32);
gl.tex_sub_image_2d(
glow::TEXTURE_2D,
0,
0,
0,
w as i32,
h as i32,
glow::RGBA,
glow::UNSIGNED_BYTE,
glow::PixelUnpackData::Slice(data),
);
}
assert_eq!(gl.get_error(), glow::NO_ERROR, "OpenGL error occurred!");
tex
}
}

pub(crate) unsafe fn as_u8_slice<T>(s: &[T]) -> &[u8] {
std::slice::from_raw_parts(s.as_ptr().cast::<u8>(), s.len() * std::mem::size_of::<T>())
}

#[cfg(target_arch = "wasm32")]
pub(crate) fn glow_debug_print(s: impl Into<JsValue>) {
web_sys::console::log_1(&s.into());
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn glow_debug_print(s: impl std::fmt::Display) {
println!("{}", s);
}

pub(crate) fn compile_shader(
gl: &glow::Context,
shader_type: u32,
source: &str,
) -> Result<glow::Shader, String> {
let shader = unsafe { gl.create_shader(shader_type) }?;
unsafe {
gl.shader_source(shader, source);
}
unsafe {
gl.compile_shader(shader);
}

if unsafe { gl.get_shader_compile_status(shader) } {
Ok(shader)
} else {
Err(unsafe { gl.get_shader_info_log(shader) })
}
}

pub(crate) fn link_program<'a, T: IntoIterator<Item = &'a glow::Shader>>(
gl: &glow::Context,
shaders: T,
) -> Result<glow::Program, String> {
let program = unsafe { gl.create_program() }?;
unsafe {
for shader in shaders {
gl.attach_shader(program, *shader);
}
}
unsafe {
gl.link_program(program);
}

if unsafe { gl.get_program_link_status(program) } {
Ok(program)
} else {
Err(unsafe { gl.get_program_info_log(program) })
}
}
///Wrapper around Emulated VAO and GL's VAO
pub(crate) enum VAO {
Emulated(crate::vao_emulate::EmulatedVao),
Native(crate::glow::VertexArray),
}

impl VAO {
pub(crate) unsafe fn new(gl: &glow::Context, is_native_vao: bool) -> Self {
if is_native_vao {
Self::Native(gl.create_vertex_array().unwrap())
} else {
Self::Emulated(crate::vao_emulate::EmulatedVao::new())
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nitpicky, but I think it would make sense to offer two constructors here instead of one.

Suggested change
pub(crate) unsafe fn new(gl: &glow::Context, is_native_vao: bool) -> Self {
if is_native_vao {
Self::Native(gl.create_vertex_array().unwrap())
} else {
Self::Emulated(crate::vao_emulate::EmulatedVao::new())
}
}
pub(crate) unsafe fn native(gl: &glow::Context) -> Self {
Self::Native(gl.create_vertex_array().unwrap())
}
pub(crate) fn emulated() -> Self {
Self::Emulated(crate::vao_emulate::EmulatedVao::new())
}

Also, wouldn't the API be nicer if the constructor captured the &glow::Context here so it doesn't need to be passed to the other methods? That might also help reduce some confusion about why VAO::bind_vertex_array is unsafe, but the others are not?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about two constructors 👍

Capturing &glow::Context leads to a lot of ugly lifetime issues. Passing it in by reference is also more explicit, i.e. easier to see what is actually doing graphics calls. This was discussed in the original glow PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok i will split constructor.
but is there good way to switch emulated mode?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capturing &glow::Context leads to a lot of ugly lifetime issues. Passing it in by reference is also more explicit, i.e. easier to see what is actually doing graphics calls. This was discussed in the original glow PR.

Ok! Good to know, I didn't follow that conversation closely.

Ok i will split constructor.
but is there good way to switch emulated mode?

This question implies there is a way to switch the emulation mode with just one constructor? I don't believe that is the case before or after the suggested patch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this procedure good enough to switch emulated mode .
Is there any suggestion?
vao_switch_procedure

pub(crate) unsafe fn bind_vertex_array(&self, gl: &glow::Context) {
match self {
VAO::Emulated(vao) => vao.bind_vertex_array(gl),
VAO::Native(vao) => gl.bind_vertex_array(Some(*vao)),
}
}
pub(crate) fn bind_buffer(&mut self, gl: &glow::Context, buffer: &glow::Buffer) {
match self {
VAO::Emulated(vao) => vao.bind_buffer(buffer),
VAO::Native(_) => unsafe {
gl.bind_buffer(glow::ARRAY_BUFFER, Some(*buffer));
},
}
}
pub(crate) fn add_new_attribute(
&mut self,
gl: &glow::Context,
buffer_info: crate::vao_emulate::BufferInfo,
) {
match self {
VAO::Emulated(vao) => vao.add_new_attribute(buffer_info),
VAO::Native(_) => unsafe {
gl.vertex_attrib_pointer_f32(
buffer_info.location,
buffer_info.vector_size,
buffer_info.data_type,
buffer_info.normalized,
buffer_info.stride,
buffer_info.offset,
);
gl.enable_vertex_attrib_array(buffer_info.location);
},
}
}
pub(crate) fn unbind_vertex_array(&self, gl: &glow::Context) {
match self {
VAO::Emulated(vao) => vao.unbind_vertex_array(gl),
VAO::Native(_) => unsafe {
gl.bind_vertex_array(None);
},
}
}
}
Loading