Skip to content

Commit

Permalink
Manually Do sRGB Conversion During Web Present
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Jul 25, 2021
1 parent e34ae34 commit fbde22a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 33 deletions.
103 changes: 70 additions & 33 deletions wgpu-hal/src/gles/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ impl crate::Instance<super::Api> for Instance {

Ok(Surface {
canvas,
present_program: None,
swapchain: None,
renderbuffer: None,
texture: None,
presentable: true,
enable_srgb: true, // WebGL only supports sRGB
})
Expand All @@ -115,9 +116,10 @@ impl crate::Instance<super::Api> for Instance {
pub struct Surface {
canvas: web_sys::HtmlCanvasElement,
pub(super) swapchain: Option<Swapchain>,
renderbuffer: Option<glow::Renderbuffer>,
texture: Option<glow::Texture>,
pub(super) presentable: bool,
pub(super) enable_srgb: bool,
present_program: Option<glow::Program>,
}

// SAFE: Because web doesn't have threads ( yet )
Expand All @@ -139,29 +141,45 @@ impl Surface {
_suf_texture: super::Texture,
gl: &glow::Context,
) -> Result<(), crate::SurfaceError> {
let swapchain = self.swapchain.as_ref().unwrap();

gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(swapchain.framebuffer));
// Note the Y-flipping here. GL's presentation is not flipped,
// but main rendering is. Therefore, we Y-flip the output positions
// in the shader, and also this blit.
gl.blit_framebuffer(
0,
swapchain.extent.height as i32,
swapchain.extent.width as i32,
0,
0,
0,
swapchain.extent.width as i32,
swapchain.extent.height as i32,
glow::COLOR_BUFFER_BIT,
glow::NEAREST,
);
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
gl.bind_sampler(0, None);
gl.active_texture(glow::TEXTURE0);
gl.bind_texture(glow::TEXTURE_2D, self.texture);
gl.use_program(self.present_program);
gl.disable(glow::DEPTH_TEST);
gl.disable(glow::STENCIL_TEST);
gl.disable(glow::SCISSOR_TEST);
gl.disable(glow::BLEND);
gl.disable(glow::CULL_FACE);
gl.draw_buffers(&[glow::BACK]);
gl.draw_arrays(glow::TRIANGLES, 0, 3);

Ok(())
}

unsafe fn create_present_program(gl: &glow::Context) -> glow::Program {
let program = gl
.create_program()
.expect("Could not create shader program");
let vertex = gl
.create_shader(glow::VERTEX_SHADER)
.expect("Could not create shader");
gl.shader_source(vertex, include_str!("./web/present.vert"));
gl.compile_shader(vertex);
let fragment = gl
.create_shader(glow::FRAGMENT_SHADER)
.expect("Could not create shader");
gl.shader_source(fragment, include_str!("./web/present.frag"));
gl.compile_shader(fragment);
gl.attach_shader(program, vertex);
gl.attach_shader(program, fragment);
gl.link_program(program);
gl.delete_shader(vertex);
gl.delete_shader(fragment);
gl.bind_texture(glow::TEXTURE_2D, None);

program
}
}

impl crate::Surface<super::Api> for Surface {
Expand All @@ -177,27 +195,45 @@ impl crate::Surface<super::Api> for Surface {
gl.delete_framebuffer(swapchain.framebuffer);
}

if self.renderbuffer.is_none() {
self.renderbuffer = Some(gl.create_renderbuffer().unwrap());
if self.present_program.is_none() {
self.present_program = Some(Self::create_present_program(gl));
}

if self.texture.is_none() {
self.texture = Some(gl.create_texture().unwrap());
}

let desc = device.shared.describe_texture_format(config.format);
gl.bind_renderbuffer(glow::RENDERBUFFER, self.renderbuffer);
gl.renderbuffer_storage(
glow::RENDERBUFFER,
gl.bind_texture(glow::TEXTURE_2D, self.texture);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MIN_FILTER,
glow::NEAREST as _,
);
gl.tex_parameter_i32(
glow::TEXTURE_2D,
glow::TEXTURE_MAG_FILTER,
glow::NEAREST as _,
);
gl.tex_storage_2d(
glow::TEXTURE_2D,
1,
desc.internal,
config.extent.width as i32,
config.extent.height as i32,
);

let framebuffer = gl.create_framebuffer().unwrap();
gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
gl.framebuffer_renderbuffer(
gl.framebuffer_texture_2d(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::RENDERBUFFER,
self.renderbuffer,
glow::TEXTURE_2D,
self.texture,
0,
);
gl.bind_texture(glow::TEXTURE_2D, None);

self.swapchain = Some(Swapchain {
extent: config.extent,
// channel: config.format.base_format().1,
Expand All @@ -213,8 +249,8 @@ impl crate::Surface<super::Api> for Surface {
if let Some(swapchain) = self.swapchain.take() {
gl.delete_framebuffer(swapchain.framebuffer);
}
if let Some(renderbuffer) = self.renderbuffer.take() {
gl.delete_renderbuffer(renderbuffer);
if let Some(renderbuffer) = self.texture.take() {
gl.delete_texture(renderbuffer);
}
}

Expand All @@ -224,8 +260,9 @@ impl crate::Surface<super::Api> for Surface {
) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
let sc = self.swapchain.as_ref().unwrap();
let texture = super::Texture {
inner: super::TextureInner::Renderbuffer {
raw: self.renderbuffer.unwrap(),
inner: super::TextureInner::Texture {
raw: self.texture.unwrap(),
target: glow::TEXTURE_2D,
},
array_layer_count: 1,
mip_level_count: 1,
Expand Down
16 changes: 16 additions & 0 deletions wgpu-hal/src/gles/web/present.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#version 300 es
precision mediump float;
in vec2 uv;
uniform sampler2D present_texture;
out vec4 frag;
vec4 linear_to_srgb(vec4 linear) {
vec3 color_linear = linear.rgb;
vec3 selector = ceil(color_linear - 0.0031308); // 0 if under value, 1 if over
vec3 under = 12.92 * color_linear;
vec3 over = 1.055 * pow(color_linear, vec3(0.41666)) - 0.055;
vec3 result = mix(under, over, selector);
return vec4(result, linear.a);
}
void main() {
frag = linear_to_srgb(texture(present_texture, uv));
}
18 changes: 18 additions & 0 deletions wgpu-hal/src/gles/web/present.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#version 300 es
precision mediump float;
// A triangle that fills the whole screen
const vec2[3] TRIANGLE_POS = vec2[](
vec2( 0.0, -3.0),
vec2(-3.0, 1.0),
vec2( 3.0, 1.0)
);
const vec2[3] TRIANGLE_UV = vec2[](
vec2( 0.5, 1.),
vec2( -1.0, -1.0),
vec2( 2.0, -1.0)
);
out vec2 uv;
void main() {
uv = TRIANGLE_UV[gl_VertexID];
gl_Position = vec4(TRIANGLE_POS[gl_VertexID], 0.0, 1.0);
}

0 comments on commit fbde22a

Please sign in to comment.