diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index e4f69b5f..8f38d854 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -58,7 +58,7 @@ pub fn run(app: Box, native_options: &epi::NativeOptions) -> ! { event_loop.create_proxy(), ))); - let mut painter = crate::Painter::new(&gl, None) + let mut painter = crate::Painter::new(&gl, None, "") .map_err(|error| eprintln!("some OpenGL error occurred {}\n", error)) .unwrap(); let mut integration = egui_winit::epi::EpiIntegration::new( diff --git a/egui_glow/src/lib.rs b/egui_glow/src/lib.rs index 3d703ae6..f1daded6 100644 --- a/egui_glow/src/lib.rs +++ b/egui_glow/src/lib.rs @@ -123,7 +123,7 @@ impl EguiGlow { Self { egui_ctx: Default::default(), egui_winit: egui_winit::State::new(gl_window.window()), - painter: crate::Painter::new(gl, None) + painter: crate::Painter::new(gl, None, "") .map_err(|error| { eprintln!("some error occurred in initializing painter\n{}", error); }) diff --git a/egui_glow/src/misc_util.rs b/egui_glow/src/misc_util.rs index c6e6923c..a211f455 100644 --- a/egui_glow/src/misc_util.rs +++ b/egui_glow/src/misc_util.rs @@ -184,7 +184,8 @@ impl VAO { } } -pub(crate) unsafe fn need_to_emulate_vao(gl: &glow::Context) -> bool { +/// If returned true no need to emulate vao +pub(crate) unsafe fn support_vao(gl: &glow::Context) -> bool { let web_sig = "WebGL "; let es_sig = "OpenGL ES "; let version_string = gl.get_parameter_string(glow::VERSION); @@ -200,7 +201,7 @@ pub(crate) unsafe fn need_to_emulate_vao(gl: &glow::Context) -> bool { gl.supported_extensions() .contains("OES_vertex_array_object") } else { - false + 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 @@ -214,7 +215,7 @@ pub(crate) unsafe fn need_to_emulate_vao(gl: &glow::Context) -> bool { gl.supported_extensions() .contains("OES_vertex_array_object") } else { - false + true } } else { glow_debug_print(format!("detected OpenGL:{}", version_string)); @@ -225,7 +226,7 @@ pub(crate) unsafe fn need_to_emulate_vao(gl: &glow::Context) -> bool { gl.supported_extensions() .contains("ARB_vertex_array_object") } else { - false + true } } } diff --git a/egui_glow/src/painter.rs b/egui_glow/src/painter.rs index d1076572..9e82218f 100644 --- a/egui_glow/src/painter.rs +++ b/egui_glow/src/painter.rs @@ -61,18 +61,26 @@ impl Painter { /// Create painter. /// /// Set `pp_fb_extent` to the framebuffer size to enable `sRGB` support on OpenGL ES and WebGL. + /// Set `shader_prefix` if you want to turn on shader workaround e.g. `"#define EPIPHANY_WORKAROUND\n"`. + /// + /// this fix [Everything is super dark in epiphany](https://github.com/emilk/egui/issues/794) /// # Errors /// will return `Err` below cases /// * failed to compile shader /// * failed to create postprocess on webgl with `sRGB` support /// * failed to create buffer - pub fn new(gl: &glow::Context, pp_fb_extent: Option<[i32; 2]>) -> Result { - let need_to_emulate_vao = unsafe { crate::misc_util::need_to_emulate_vao(gl) }; + pub fn new( + gl: &glow::Context, + pp_fb_extent: Option<[i32; 2]>, + shader_prefix: &str, + ) -> Result { + let support_vao = unsafe { crate::misc_util::support_vao(gl) }; let shader_version = ShaderVersion::get(gl); let is_webgl_1 = shader_version == ShaderVersion::Es100; let header = shader_version.version(); glow_debug_print(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 (ShaderVersion::Es300, _) | (ShaderVersion::Es100, true) => unsafe { @@ -83,7 +91,8 @@ impl Painter { ( Some(PostProcess::new( gl, - need_to_emulate_vao, + shader_prefix, + support_vao, is_webgl_1, width, height, @@ -106,8 +115,9 @@ impl Painter { gl, glow::VERTEX_SHADER, &format!( - "{}\n{}\n{}", + "{}\n{}\n{}\n{}", header, + shader_prefix, shader_version.is_new_shader_interface(), VERT_SRC ), @@ -116,8 +126,9 @@ impl Painter { gl, glow::FRAGMENT_SHADER, &format!( - "{}\n{}\n{}\n{}", + "{}\n{}\n{}\n{}\n{}", header, + shader_prefix, srgb_support_define, shader_version.is_new_shader_interface(), FRAG_SRC @@ -136,10 +147,10 @@ impl Painter { let a_pos_loc = gl.get_attrib_location(program, "a_pos").unwrap(); let a_tc_loc = gl.get_attrib_location(program, "a_tc").unwrap(); let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap(); - let mut vertex_array = if need_to_emulate_vao { - crate::misc_util::VAO::emulated() - } else { + let mut vertex_array = if support_vao { crate::misc_util::VAO::native(gl) + } else { + crate::misc_util::VAO::emulated() }; vertex_array.bind_vertex_array(gl); vertex_array.bind_buffer(gl, &vertex_buffer); diff --git a/egui_glow/src/post_process.rs b/egui_glow/src/post_process.rs index 4c85ff9d..7a4ef3d1 100644 --- a/egui_glow/src/post_process.rs +++ b/egui_glow/src/post_process.rs @@ -19,6 +19,7 @@ pub(crate) struct PostProcess { impl PostProcess { pub(crate) unsafe fn new( gl: &glow::Context, + shader_prefix: &str, need_to_emulate_vao: bool, is_webgl_1: bool, width: i32, @@ -96,12 +97,20 @@ impl PostProcess { let vert_shader = compile_shader( gl, glow::VERTEX_SHADER, - include_str!("shader/post_vertex_100es.glsl"), + &format!( + "{}\n{}", + shader_prefix, + include_str!("shader/post_vertex_100es.glsl") + ), )?; let frag_shader = compile_shader( gl, glow::FRAGMENT_SHADER, - include_str!("shader/post_fragment_100es.glsl"), + &format!( + "{}\n{}", + shader_prefix, + include_str!("shader/post_fragment_100es.glsl") + ), )?; let program = link_program(gl, [vert_shader, frag_shader].iter())?; diff --git a/egui_glow/src/shader/post_fragment_100es.glsl b/egui_glow/src/shader/post_fragment_100es.glsl index 001f8a3f..f3e7959f 100644 --- a/egui_glow/src/shader/post_fragment_100es.glsl +++ b/egui_glow/src/shader/post_fragment_100es.glsl @@ -19,4 +19,8 @@ void main() { gl_FragColor = texture2D(u_sampler, v_tc); gl_FragColor = srgba_from_linear(gl_FragColor) / 255.; + #ifdef WEBKITGTK_WORKAROUND + //this is better than double apply + gl_FragColor = vec4(pow(gl_FragColor.rgb,vec3(1.0/2.2)),gl_FragColor.a); + #endif } diff --git a/egui_web/CHANGELOG.md b/egui_web/CHANGELOG.md index 94773637..201655d4 100644 --- a/egui_web/CHANGELOG.md +++ b/egui_web/CHANGELOG.md @@ -4,7 +4,8 @@ All notable changes to the `egui_web` integration will be noted in this file. ## Unreleased -*Add feature `glow` to switch to a [`glow`](https://github.com/grovesNL/glow) based painter ([#868](https://github.com/emilk/egui/pull/868)). +* Fix [dark rendering in epiphany](https://github.com/emilk/egui/issues/794) for WebGL1 and glow based painter ([#888](https://github.com/emilk/egui/pull/888/)). +* Add feature `glow` to switch to a [`glow`](https://github.com/grovesNL/glow) based painter ([#868](https://github.com/emilk/egui/pull/868)). ## 0.15.0 - 2021-10-24 ### Added diff --git a/egui_web/Cargo.toml b/egui_web/Cargo.toml index 1fa00e67..da45cc48 100644 --- a/egui_web/Cargo.toml +++ b/egui_web/Cargo.toml @@ -88,6 +88,7 @@ features = [ "TouchList", "WebGl2RenderingContext", "WebGlBuffer", + "WebglDebugRendererInfo", "WebGlFramebuffer", "WebGlProgram", "WebGlRenderingContext", diff --git a/egui_web/src/glow_wrapping.rs b/egui_web/src/glow_wrapping.rs index f9512a58..fbbc5f6d 100644 --- a/egui_web/src/glow_wrapping.rs +++ b/egui_web/src/glow_wrapping.rs @@ -1,8 +1,11 @@ -use crate::web_sys::{WebGl2RenderingContext, WebGlRenderingContext}; +#[cfg(not(target_arch = "wasm32"))] +use crate::web_sys::WebGl2RenderingContext; +use crate::web_sys::WebGlRenderingContext; use crate::{canvas_element_or_die, console_error}; use egui::{ClippedMesh, Rgba, Texture}; use egui_glow::glow; use epi::TextureAllocator; +use wasm_bindgen::JsCast; use wasm_bindgen::JsValue; use web_sys::HtmlCanvasElement; @@ -16,9 +19,29 @@ pub(crate) struct WrappedGlowPainter { impl WrappedGlowPainter { pub fn new(canvas_id: &str) -> Self { let canvas = canvas_element_or_die(canvas_id); + // 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::() + .unwrap(); + let user_agent = web_sys::window().unwrap().navigator().user_agent().unwrap(); + let webkit_gtk_wr = if !user_agent.contains("Mac OS X") + && crate::webgl1::detect_safari_and_webkit_gtk(&gl) + { + "#define WEBKITGTK_WORKAROUND" + } else { + "" + }; + 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)) + let painter = egui_glow::Painter::new(&gl_ctx, Some(dimension), webkit_gtk_wr) .map_err(|error| { console_error(format!( "some error occurred in initializing glow painter\n {}", @@ -82,7 +105,6 @@ impl crate::Painter for WrappedGlowPainter { } pub fn init_glow_context_from_canvas(canvas: &HtmlCanvasElement) -> glow::Context { - use wasm_bindgen::JsCast; let ctx = canvas.get_context("webgl2"); if let Ok(ctx) = ctx { crate::console_log("webgl found"); diff --git a/egui_web/src/shader/post_fragment_100es.glsl b/egui_web/src/shader/post_fragment_100es.glsl index 001f8a3f..f3e7959f 100644 --- a/egui_web/src/shader/post_fragment_100es.glsl +++ b/egui_web/src/shader/post_fragment_100es.glsl @@ -19,4 +19,8 @@ void main() { gl_FragColor = texture2D(u_sampler, v_tc); gl_FragColor = srgba_from_linear(gl_FragColor) / 255.; + #ifdef WEBKITGTK_WORKAROUND + //this is better than double apply + gl_FragColor = vec4(pow(gl_FragColor.rgb,vec3(1.0/2.2)),gl_FragColor.a); + #endif } diff --git a/egui_web/src/webgl1.rs b/egui_web/src/webgl1.rs index 91343dc2..f59ce5d4 100644 --- a/egui_web/src/webgl1.rs +++ b/egui_web/src/webgl1.rs @@ -3,10 +3,11 @@ use { wasm_bindgen::{prelude::*, JsCast}, web_sys::{ ExtSRgb, WebGlBuffer, WebGlFramebuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, - WebGlTexture, + WebGlTexture, WebglDebugRendererInfo, }, }; +use crate::console_log; use egui::{ emath::vec2, epaint::{Color32, Texture}, @@ -591,6 +592,17 @@ impl PostProcess { gl.bind_texture(Gl::TEXTURE_2D, None); gl.bind_framebuffer(Gl::FRAMEBUFFER, None); + // 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(); + let webkit_gtk_wr = if !user_agent.contains("Mac OS X") && detect_safari_and_webkit_gtk(&gl) + { + "#define WEBKITGTK_WORKAROUND" + } else { + "" + }; let vert_shader = compile_shader( &gl, @@ -600,7 +612,11 @@ impl PostProcess { let frag_shader = compile_shader( &gl, Gl::FRAGMENT_SHADER, - include_str!("shader/post_fragment_100es.glsl"), + &format!( + "{}{}", + webkit_gtk_wr, + include_str!("shader/post_fragment_100es.glsl") + ), )?; let program = link_program(&gl, [vert_shader, frag_shader].iter())?; @@ -750,3 +766,27 @@ fn link_program<'a, T: IntoIterator>( .unwrap_or_else(|| "Unknown error creating program object".into())) } } + +/// 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 detect_safari_and_webkit_gtk(gl: &web_sys::WebGlRenderingContext) -> bool { + if gl + .get_extension("WEBGL_debug_renderer_info") + .unwrap() + .is_some() + { + let renderer: JsValue = gl + .get_parameter(WebglDebugRendererInfo::UNMASKED_RENDERER_WEBGL) + .unwrap(); + if renderer.as_string().unwrap().contains("Apple") { + console_log("Enabling webkitGTK workaround"); + return true; + } + } + false +}