Fix bugs in glow on web (#1092)

* Re-add check of WEBGL_debug_renderer_info to avoid OpenGL error

I removed this check in https://github.com/emilk/egui/pull/1020
because it produced a warning on Firefox. Better a warning
than an OpenGL error though.

* Bug fix: don't ask for webgl context and then later for webgl2 context

The browser will only allow the first thing we check, so this will
prevent webgl2 from working.
This commit is contained in:
Emil Ernerfeldt 2022-01-10 23:19:30 +01:00 committed by GitHub
parent d5673412dd
commit 205e04aa18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 83 additions and 81 deletions

View file

@ -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)).

View file

@ -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.

View file

@ -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,
@ -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"),
};

View file

@ -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

View file

@ -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

View file

@ -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,
@ -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 {}",
@ -38,7 +31,7 @@ impl WrappedGlowPainter {
.unwrap();
Self {
gl_ctx,
glow_ctx,
canvas,
canvas_id: canvas_id.to_owned(),
painter,
@ -46,28 +39,9 @@ impl WrappedGlowPainter {
}
}
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) {
@ -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(
@ -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,
@ -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.");
}

View file

@ -1238,6 +1238,18 @@ 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
@ -1245,8 +1257,17 @@ fn move_text_cursor(cursor: &Option<egui::Pos2>, canvas_id: &str) -> Option<()>
/// 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 Ok(renderer) =
gl.get_parameter(web_sys::WebglDebugRendererInfo::UNMASKED_RENDERER_WEBGL)
{
if let Some(renderer) = renderer.as_string() {
if renderer.contains("Apple") {
@ -1254,6 +1275,7 @@ pub(crate) fn is_safari_and_webkit_gtk(gl: &web_sys::WebGlRenderingContext) -> b
}
}
}
}
false
}

View file

@ -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
@ -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 {