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

Fix bugs in glow on web #1092

Merged
merged 5 commits into from
Jan 10, 2022
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
1 change: 1 addition & 0 deletions egui_glow/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to the `egui_glow` integration will be noted in this file.

## Unreleased
* Added `set_texture_filter` method to `Painter` ((#1041)[https://github.com/emilk/egui/pull/1041]).
* Fix failure to run in Chrome ((#1092)[https://github.com/emilk/egui/pull/1092]).

## 0.16.0 - 2021-12-29
* Made winit/glutin an optional dependency ([#868](https://github.com/emilk/egui/pull/868)).
Expand Down
36 changes: 16 additions & 20 deletions egui_glow/src/misc_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,40 +204,36 @@ impl VAO {

/// If returned true no need to emulate vao
pub(crate) fn supports_vao(gl: &glow::Context) -> bool {
let web_sig = "WebGL ";
let es_sig = "OpenGL ES ";
const WEBGL_PREFIX: &str = "WebGL ";
const OPENGL_ES_PREFIX: &str = "OpenGL ES ";

let version_string = unsafe { gl.get_parameter_string(glow::VERSION) };
if let Some(pos) = version_string.rfind(web_sig) {
let version_str = &version_string[pos + web_sig.len()..];
glow_print(format!(
"detected WebGL prefix at {}:{}",
pos + web_sig.len(),
version_str
));
glow_print(format!("GL version: {:?}.", version_string));

// Examples:
// * "WebGL 2.0 (OpenGL ES 3.0 Chromium)"
// * "WebGL 2.0"

if let Some(pos) = version_string.rfind(WEBGL_PREFIX) {
let version_str = &version_string[pos + WEBGL_PREFIX.len()..];
if version_str.contains("1.0") {
//need to test OES_vertex_array_object .
// need to test OES_vertex_array_object .
gl.supported_extensions()
.contains("OES_vertex_array_object")
} else {
true
}
} else if let Some(pos) = version_string.rfind(es_sig) {
//glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL
glow_print(format!(
"detected OpenGL ES prefix at {}:{}",
pos + es_sig.len(),
&version_string[pos + es_sig.len()..]
));
} else if version_string.contains(OPENGL_ES_PREFIX) {
// glow targets es2.0+ so we don't concern about OpenGL ES-CM,OpenGL ES-CL
if version_string.contains("2.0") {
//need to test OES_vertex_array_object .
// need to test OES_vertex_array_object .
gl.supported_extensions()
.contains("OES_vertex_array_object")
} else {
true
}
} else {
glow_print(format!("detected OpenGL: {:?}", version_string));
//from OpenGL 3 vao into core
// from OpenGL 3 vao into core
if version_string.starts_with('2') {
// I found APPLE_vertex_array_object , GL_ATI_vertex_array_object ,ARB_vertex_array_object
// but APPLE's and ATI's very old extension.
Expand Down
16 changes: 9 additions & 7 deletions egui_glow/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,16 @@ impl Painter {
let shader_version = ShaderVersion::get(gl);
let is_webgl_1 = shader_version == ShaderVersion::Es100;
let header = shader_version.version();
glow_print(format!("Shader header: {:?}", header));
glow_print(format!("Shader header: {:?}.", header));
let srgb_support = gl.supported_extensions().contains("EXT_sRGB");

let (post_process, srgb_support_define) = match (shader_version, srgb_support) {
//WebGL2 support sRGB default
// WebGL2 support sRGB default
(ShaderVersion::Es300, _) | (ShaderVersion::Es100, true) => unsafe {
//Add sRGB support marker for fragment shader
// Add sRGB support marker for fragment shader
if let Some([width, height]) = pp_fb_extent {
glow_print("WebGL with sRGB enabled so turn on post process");
//install post process to correct sRGB color
glow_print("WebGL with sRGB enabled. Turning on post processing for linear framebuffer blending.");
// install post process to correct sRGB color:
(
Some(PostProcess::new(
gl,
Expand All @@ -125,9 +125,11 @@ impl Painter {
(None, "")
}
},
//WebGL1 without sRGB support disable postprocess and use fallback shader

// WebGL1 without sRGB support disable postprocess and use fallback shader
(ShaderVersion::Es100, false) => (None, ""),
//OpenGL 2.1 or above always support sRGB so add sRGB support marker

// OpenGL 2.1 or above always support sRGB so add sRGB support marker
_ => (None, "#define SRGB_SUPPORTED"),
};

Expand Down
2 changes: 1 addition & 1 deletion egui_glow/src/shader_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl ShaderVersion {
unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
let shader_version = Self::parse(&shading_lang_string);
glow_print(format!(
"Shader version: {:?} ({:?})",
"Shader version: {:?} ({:?}).",
shader_version, shading_lang_string
));
shader_version
Expand Down
1 change: 1 addition & 0 deletions egui_web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All notable changes to the `egui_web` integration will be noted in this file.
## Unreleased
* The default painter is now glow instead of WebGL ([#1020](https://github.com/emilk/egui/pull/1020)).
* Made the WebGL painter opt-in ([#1020](https://github.com/emilk/egui/pull/1020)).
* Fix glow failure Chrome ((#1092)[https://github.com/emilk/egui/pull/1092]).


## 0.16.0 - 2021-12-29
Expand Down
67 changes: 27 additions & 40 deletions egui_web/src/glow_wrapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
use web_sys::HtmlCanvasElement;
#[cfg(not(target_arch = "wasm32"))]
use web_sys::WebGl2RenderingContext;
use web_sys::WebGlRenderingContext;
use web_sys::{WebGl2RenderingContext, WebGlRenderingContext};

pub(crate) struct WrappedGlowPainter {
pub(crate) gl_ctx: glow::Context,
pub(crate) glow_ctx: glow::Context,
pub(crate) canvas: HtmlCanvasElement,
pub(crate) canvas_id: String,
pub(crate) painter: egui_glow::Painter,
Expand All @@ -19,16 +18,10 @@ impl WrappedGlowPainter {
pub fn new(canvas_id: &str) -> Self {
let canvas = canvas_element_or_die(canvas_id);

let shader_prefix = if requires_brightening(&canvas) {
crate::console_log("Enabling webkitGTK brightening workaround");
"#define APPLY_BRIGHTENING_GAMMA"
} else {
""
};
let (glow_ctx, shader_prefix) = init_glow_context_from_canvas(&canvas);

let gl_ctx = init_glow_context_from_canvas(&canvas);
let dimension = [canvas.width() as i32, canvas.height() as i32];
let painter = egui_glow::Painter::new(&gl_ctx, Some(dimension), shader_prefix)
let painter = egui_glow::Painter::new(&glow_ctx, Some(dimension), shader_prefix)
.map_err(|error| {
console_error(format!(
"some error occurred in initializing glow painter\n {}",
Expand All @@ -38,36 +31,17 @@ impl WrappedGlowPainter {
.unwrap();

Self {
gl_ctx,
glow_ctx,
canvas,
canvas_id: canvas_id.to_owned(),
painter,
}
}
}

fn requires_brightening(canvas: &web_sys::HtmlCanvasElement) -> bool {
// See https://github.com/emilk/egui/issues/794

// detect WebKitGTK

// WebKitGTK currently support only webgl,so request webgl context.
// WebKitGTK use WebKit default unmasked vendor and renderer
// but safari use same vendor and renderer
// so exclude "Mac OS X" user-agent.
let gl = canvas
.get_context("webgl")
.unwrap()
.unwrap()
.dyn_into::<WebGlRenderingContext>()
.unwrap();
let user_agent = web_sys::window().unwrap().navigator().user_agent().unwrap();
crate::is_safari_and_webkit_gtk(&gl) && !user_agent.contains("Mac OS X")
}

impl crate::Painter for WrappedGlowPainter {
fn set_texture(&mut self, tex_id: u64, image: epi::Image) {
self.painter.set_texture(&self.gl_ctx, tex_id, &image);
self.painter.set_texture(&self.glow_ctx, tex_id, &image);
}

fn free_texture(&mut self, tex_id: u64) {
Expand All @@ -87,12 +61,12 @@ impl crate::Painter for WrappedGlowPainter {
}

fn upload_egui_texture(&mut self, font_image: &FontImage) {
self.painter.upload_egui_texture(&self.gl_ctx, font_image)
self.painter.upload_egui_texture(&self.glow_ctx, font_image)
}

fn clear(&mut self, clear_color: Rgba) {
let canvas_dimension = [self.canvas.width(), self.canvas.height()];
egui_glow::painter::clear(&self.gl_ctx, canvas_dimension, clear_color)
egui_glow::painter::clear(&self.glow_ctx, canvas_dimension, clear_color)
}

fn paint_meshes(
Expand All @@ -102,7 +76,7 @@ impl crate::Painter for WrappedGlowPainter {
) -> Result<(), JsValue> {
let canvas_dimension = [self.canvas.width(), self.canvas.height()];
self.painter.paint_meshes(
&self.gl_ctx,
&self.glow_ctx,
canvas_dimension,
pixels_per_point,
clipped_meshes,
Expand All @@ -115,26 +89,39 @@ impl crate::Painter for WrappedGlowPainter {
}
}

pub fn init_glow_context_from_canvas(canvas: &HtmlCanvasElement) -> glow::Context {
/// Returns glow context and shader prefix.
fn init_glow_context_from_canvas(canvas: &HtmlCanvasElement) -> (glow::Context, &str) {
let gl2_ctx = canvas
.get_context("webgl2")
.expect("Failed to query about WebGL2 context");

if let Some(gl2_ctx) = gl2_ctx {
crate::console_log("WebGL2 found");
crate::console_log("WebGL2 found.");
let gl2_ctx = gl2_ctx
.dyn_into::<web_sys::WebGl2RenderingContext>()
.unwrap();
glow::Context::from_webgl2_context(gl2_ctx)
let glow_ctx = glow::Context::from_webgl2_context(gl2_ctx);
let shader_prefix = "";
(glow_ctx, shader_prefix)
} else {
let gl1 = canvas
.get_context("webgl")
.expect("Failed to query about WebGL1 context");

if let Some(gl1) = gl1 {
crate::console_log("WebGL2 not available - falling back to WebGL1");
crate::console_log("WebGL2 not available - falling back to WebGL1.");
let gl1_ctx = gl1.dyn_into::<web_sys::WebGlRenderingContext>().unwrap();
glow::Context::from_webgl1_context(gl1_ctx)

let shader_prefix = if crate::webgl1_requires_brightening(&gl1_ctx) {
crate::console_log("Enabling webkitGTK brightening workaround.");
"#define APPLY_BRIGHTENING_GAMMA"
} else {
""
};

let glow_ctx = glow::Context::from_webgl1_context(gl1_ctx);

(glow_ctx, shader_prefix)
} else {
panic!("Failed to get WebGL context.");
}
Expand Down
32 changes: 27 additions & 5 deletions egui_web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,19 +1238,41 @@ fn move_text_cursor(cursor: &Option<egui::Pos2>, canvas_id: &str) -> Option<()>
}
}

pub(crate) fn webgl1_requires_brightening(gl: &web_sys::WebGlRenderingContext) -> bool {
// See https://github.com/emilk/egui/issues/794

// detect WebKitGTK

// WebKitGTK use WebKit default unmasked vendor and renderer
// but safari use same vendor and renderer
// so exclude "Mac OS X" user-agent.
let user_agent = web_sys::window().unwrap().navigator().user_agent().unwrap();
!user_agent.contains("Mac OS X") && crate::is_safari_and_webkit_gtk(gl)
}

/// detecting Safari and webkitGTK.
///
/// Safari and webkitGTK use unmasked renderer :Apple GPU
///
/// If we detect safari or webkitGTK returns true.
///
/// This function used to avoid displaying linear color with `sRGB` supported systems.
pub(crate) fn is_safari_and_webkit_gtk(gl: &web_sys::WebGlRenderingContext) -> bool {
if let Ok(renderer) = gl.get_parameter(web_sys::WebglDebugRendererInfo::UNMASKED_RENDERER_WEBGL)
fn is_safari_and_webkit_gtk(gl: &web_sys::WebGlRenderingContext) -> bool {
// This call produces a warning in Firefox ("WEBGL_debug_renderer_info is deprecated in Firefox and will be removed.")
// but unless we call it we get errors in Chrome when we call `get_parameter` below.
// TODO: do something smart based on user agent?
if gl
.get_extension("WEBGL_debug_renderer_info")
.unwrap()
.is_some()
{
if let Some(renderer) = renderer.as_string() {
if renderer.contains("Apple") {
return true;
if let Ok(renderer) =
gl.get_parameter(web_sys::WebglDebugRendererInfo::UNMASKED_RENDERER_WEBGL)
{
if let Some(renderer) = renderer.as_string() {
if renderer.contains("Apple") {
return true;
}
}
}
}
Expand Down
9 changes: 1 addition & 8 deletions egui_web/src/webgl1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,13 +475,6 @@ struct PostProcess {
program: WebGlProgram,
}

fn requires_brightening(gl: &web_sys::WebGlRenderingContext) -> bool {
// See https://github.com/emilk/egui/issues/794

let user_agent = web_sys::window().unwrap().navigator().user_agent().unwrap();
crate::is_safari_and_webkit_gtk(gl) && !user_agent.contains("Mac OS X")
}

impl PostProcess {
fn new(gl: Gl, width: i32, height: i32) -> Result<PostProcess, JsValue> {
let fbo = gl
Expand Down Expand Up @@ -519,7 +512,7 @@ impl PostProcess {
gl.bind_texture(Gl::TEXTURE_2D, None);
gl.bind_framebuffer(Gl::FRAMEBUFFER, None);

let shader_prefix = if requires_brightening(&gl) {
let shader_prefix = if crate::webgl1_requires_brightening(&gl) {
crate::console_log("Enabling webkitGTK brightening workaround");
"#define APPLY_BRIGHTENING_GAMMA"
} else {
Expand Down