Fix wrong gamma in WebkitGTK (#888)

Closes https://github.com/emilk/egui/issues/794

Also refactor and improve VAO support detection

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
triangle drawer 2021-11-13 11:32:01 +00:00 committed by GitHub
parent 4d4c75c6f1
commit 008a971e73
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 115 additions and 22 deletions

View file

@ -58,7 +58,7 @@ pub fn run(app: Box<dyn epi::App>, native_options: &epi::NativeOptions) -> ! {
event_loop.create_proxy(), 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)) .map_err(|error| eprintln!("some OpenGL error occurred {}\n", error))
.unwrap(); .unwrap();
let mut integration = egui_winit::epi::EpiIntegration::new( let mut integration = egui_winit::epi::EpiIntegration::new(

View file

@ -123,7 +123,7 @@ impl EguiGlow {
Self { Self {
egui_ctx: Default::default(), egui_ctx: Default::default(),
egui_winit: egui_winit::State::new(gl_window.window()), egui_winit: egui_winit::State::new(gl_window.window()),
painter: crate::Painter::new(gl, None) painter: crate::Painter::new(gl, None, "")
.map_err(|error| { .map_err(|error| {
eprintln!("some error occurred in initializing painter\n{}", error); eprintln!("some error occurred in initializing painter\n{}", error);
}) })

View file

@ -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 web_sig = "WebGL ";
let es_sig = "OpenGL ES "; let es_sig = "OpenGL ES ";
let version_string = gl.get_parameter_string(glow::VERSION); 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() gl.supported_extensions()
.contains("OES_vertex_array_object") .contains("OES_vertex_array_object")
} else { } else {
false true
} }
} else if let Some(pos) = version_string.rfind(es_sig) { } 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 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() gl.supported_extensions()
.contains("OES_vertex_array_object") .contains("OES_vertex_array_object")
} else { } else {
false true
} }
} else { } else {
glow_debug_print(format!("detected OpenGL:{}", version_string)); 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() gl.supported_extensions()
.contains("ARB_vertex_array_object") .contains("ARB_vertex_array_object")
} else { } else {
false true
} }
} }
} }

View file

@ -61,18 +61,26 @@ impl Painter {
/// Create painter. /// Create painter.
/// ///
/// Set `pp_fb_extent` to the framebuffer size to enable `sRGB` support on OpenGL ES and WebGL. /// 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 /// # Errors
/// will return `Err` below cases /// will return `Err` below cases
/// * failed to compile shader /// * failed to compile shader
/// * failed to create postprocess on webgl with `sRGB` support /// * failed to create postprocess on webgl with `sRGB` support
/// * failed to create buffer /// * failed to create buffer
pub fn new(gl: &glow::Context, pp_fb_extent: Option<[i32; 2]>) -> Result<Painter, String> { pub fn new(
let need_to_emulate_vao = unsafe { crate::misc_util::need_to_emulate_vao(gl) }; gl: &glow::Context,
pp_fb_extent: Option<[i32; 2]>,
shader_prefix: &str,
) -> Result<Painter, String> {
let support_vao = unsafe { crate::misc_util::support_vao(gl) };
let shader_version = ShaderVersion::get(gl); let shader_version = ShaderVersion::get(gl);
let is_webgl_1 = shader_version == ShaderVersion::Es100; let is_webgl_1 = shader_version == ShaderVersion::Es100;
let header = shader_version.version(); let header = shader_version.version();
glow_debug_print(header); glow_debug_print(header);
let srgb_support = gl.supported_extensions().contains("EXT_sRGB"); let srgb_support = gl.supported_extensions().contains("EXT_sRGB");
let (post_process, srgb_support_define) = match (shader_version, srgb_support) { 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 { (ShaderVersion::Es300, _) | (ShaderVersion::Es100, true) => unsafe {
@ -83,7 +91,8 @@ impl Painter {
( (
Some(PostProcess::new( Some(PostProcess::new(
gl, gl,
need_to_emulate_vao, shader_prefix,
support_vao,
is_webgl_1, is_webgl_1,
width, width,
height, height,
@ -106,8 +115,9 @@ impl Painter {
gl, gl,
glow::VERTEX_SHADER, glow::VERTEX_SHADER,
&format!( &format!(
"{}\n{}\n{}", "{}\n{}\n{}\n{}",
header, header,
shader_prefix,
shader_version.is_new_shader_interface(), shader_version.is_new_shader_interface(),
VERT_SRC VERT_SRC
), ),
@ -116,8 +126,9 @@ impl Painter {
gl, gl,
glow::FRAGMENT_SHADER, glow::FRAGMENT_SHADER,
&format!( &format!(
"{}\n{}\n{}\n{}", "{}\n{}\n{}\n{}\n{}",
header, header,
shader_prefix,
srgb_support_define, srgb_support_define,
shader_version.is_new_shader_interface(), shader_version.is_new_shader_interface(),
FRAG_SRC FRAG_SRC
@ -136,10 +147,10 @@ impl Painter {
let a_pos_loc = gl.get_attrib_location(program, "a_pos").unwrap(); 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_tc_loc = gl.get_attrib_location(program, "a_tc").unwrap();
let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap(); let a_srgba_loc = gl.get_attrib_location(program, "a_srgba").unwrap();
let mut vertex_array = if need_to_emulate_vao { let mut vertex_array = if support_vao {
crate::misc_util::VAO::emulated()
} else {
crate::misc_util::VAO::native(gl) crate::misc_util::VAO::native(gl)
} else {
crate::misc_util::VAO::emulated()
}; };
vertex_array.bind_vertex_array(gl); vertex_array.bind_vertex_array(gl);
vertex_array.bind_buffer(gl, &vertex_buffer); vertex_array.bind_buffer(gl, &vertex_buffer);

View file

@ -19,6 +19,7 @@ pub(crate) struct PostProcess {
impl PostProcess { impl PostProcess {
pub(crate) unsafe fn new( pub(crate) unsafe fn new(
gl: &glow::Context, gl: &glow::Context,
shader_prefix: &str,
need_to_emulate_vao: bool, need_to_emulate_vao: bool,
is_webgl_1: bool, is_webgl_1: bool,
width: i32, width: i32,
@ -96,12 +97,20 @@ impl PostProcess {
let vert_shader = compile_shader( let vert_shader = compile_shader(
gl, gl,
glow::VERTEX_SHADER, 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( let frag_shader = compile_shader(
gl, gl,
glow::FRAGMENT_SHADER, 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())?; let program = link_program(gl, [vert_shader, frag_shader].iter())?;

View file

@ -19,4 +19,8 @@ void main() {
gl_FragColor = texture2D(u_sampler, v_tc); gl_FragColor = texture2D(u_sampler, v_tc);
gl_FragColor = srgba_from_linear(gl_FragColor) / 255.; 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
} }

View file

@ -4,7 +4,8 @@ All notable changes to the `egui_web` integration will be noted in this file.
## Unreleased ## 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 ## 0.15.0 - 2021-10-24
### Added ### Added

View file

@ -88,6 +88,7 @@ features = [
"TouchList", "TouchList",
"WebGl2RenderingContext", "WebGl2RenderingContext",
"WebGlBuffer", "WebGlBuffer",
"WebglDebugRendererInfo",
"WebGlFramebuffer", "WebGlFramebuffer",
"WebGlProgram", "WebGlProgram",
"WebGlRenderingContext", "WebGlRenderingContext",

View file

@ -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 crate::{canvas_element_or_die, console_error};
use egui::{ClippedMesh, Rgba, Texture}; use egui::{ClippedMesh, Rgba, Texture};
use egui_glow::glow; use egui_glow::glow;
use epi::TextureAllocator; use epi::TextureAllocator;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue; use wasm_bindgen::JsValue;
use web_sys::HtmlCanvasElement; use web_sys::HtmlCanvasElement;
@ -16,9 +19,29 @@ pub(crate) struct WrappedGlowPainter {
impl WrappedGlowPainter { impl WrappedGlowPainter {
pub fn new(canvas_id: &str) -> Self { pub fn new(canvas_id: &str) -> Self {
let canvas = canvas_element_or_die(canvas_id); 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::<WebGlRenderingContext>()
.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 gl_ctx = init_glow_context_from_canvas(&canvas);
let dimension = [canvas.width() as i32, canvas.height() as i32]; 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| { .map_err(|error| {
console_error(format!( console_error(format!(
"some error occurred in initializing glow painter\n {}", "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 { pub fn init_glow_context_from_canvas(canvas: &HtmlCanvasElement) -> glow::Context {
use wasm_bindgen::JsCast;
let ctx = canvas.get_context("webgl2"); let ctx = canvas.get_context("webgl2");
if let Ok(ctx) = ctx { if let Ok(ctx) = ctx {
crate::console_log("webgl found"); crate::console_log("webgl found");

View file

@ -19,4 +19,8 @@ void main() {
gl_FragColor = texture2D(u_sampler, v_tc); gl_FragColor = texture2D(u_sampler, v_tc);
gl_FragColor = srgba_from_linear(gl_FragColor) / 255.; 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
} }

View file

@ -3,10 +3,11 @@ use {
wasm_bindgen::{prelude::*, JsCast}, wasm_bindgen::{prelude::*, JsCast},
web_sys::{ web_sys::{
ExtSRgb, WebGlBuffer, WebGlFramebuffer, WebGlProgram, WebGlRenderingContext, WebGlShader, ExtSRgb, WebGlBuffer, WebGlFramebuffer, WebGlProgram, WebGlRenderingContext, WebGlShader,
WebGlTexture, WebGlTexture, WebglDebugRendererInfo,
}, },
}; };
use crate::console_log;
use egui::{ use egui::{
emath::vec2, emath::vec2,
epaint::{Color32, Texture}, epaint::{Color32, Texture},
@ -591,6 +592,17 @@ impl PostProcess {
gl.bind_texture(Gl::TEXTURE_2D, None); gl.bind_texture(Gl::TEXTURE_2D, None);
gl.bind_framebuffer(Gl::FRAMEBUFFER, 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( let vert_shader = compile_shader(
&gl, &gl,
@ -600,7 +612,11 @@ impl PostProcess {
let frag_shader = compile_shader( let frag_shader = compile_shader(
&gl, &gl,
Gl::FRAGMENT_SHADER, 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())?; let program = link_program(&gl, [vert_shader, frag_shader].iter())?;
@ -750,3 +766,27 @@ fn link_program<'a, T: IntoIterator<Item = &'a WebGlShader>>(
.unwrap_or_else(|| "Unknown error creating program object".into())) .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
}