From c7a1d9e96048746a65e4271a98bc8d113254f106 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 19 Feb 2019 12:03:02 -0800 Subject: [PATCH] Use stencil to integrate the vector scene into the 3D environment --- demo/common/src/lib.rs | 15 ++- gl/src/renderer.rs | 166 ++++++++++++++++----------- renderer/src/builder.rs | 23 +--- resources/shaders/mask_tile.vs.glsl | 33 +----- resources/shaders/solid_tile.vs.glsl | 34 +----- resources/shaders/stencil.fs.glsl | 20 ++++ resources/shaders/stencil.vs.glsl | 19 +++ 7 files changed, 154 insertions(+), 156 deletions(-) create mode 100644 resources/shaders/stencil.fs.glsl create mode 100644 resources/shaders/stencil.vs.glsl diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 70751ddb..88392e65 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -390,11 +390,12 @@ impl DemoApp { color.g(), color.b(), color.a()); - gl::DepthFunc(gl::LESS); - gl::DepthMask(gl::FALSE); + gl::DepthFunc(gl::ALWAYS); + gl::DepthMask(gl::TRUE); gl::Enable(gl::DEPTH_TEST); - gl::StencilFunc(gl::ALWAYS, 1, !0); + gl::StencilFunc(gl::ALWAYS, 2, 2); gl::StencilOp(gl::KEEP, gl::KEEP, gl::REPLACE); + gl::StencilMask(2); gl::Enable(gl::STENCIL_TEST); gl::Disable(gl::BLEND); gl::DrawArrays(gl::LINES, 0, (GRIDLINE_COUNT as GLsizei + 1) * 4); @@ -419,7 +420,7 @@ impl DemoApp { gl::DepthFunc(gl::LESS); gl::DepthMask(gl::TRUE); gl::Enable(gl::DEPTH_TEST); - gl::StencilFunc(gl::NOTEQUAL, 1, !0); + gl::StencilFunc(gl::NOTEQUAL, 2, 2); gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP); gl::Enable(gl::STENCIL_TEST); gl::Disable(gl::BLEND); @@ -442,6 +443,12 @@ impl DemoApp { self.renderer.disable_subpixel_aa(); } + if self.ui.threed_enabled { + self.renderer.enable_depth(); + } else { + self.renderer.disable_depth(); + } + self.renderer.render_scene(&built_scene); } diff --git a/gl/src/renderer.rs b/gl/src/renderer.rs index 2c81ef8b..97a40f4c 100644 --- a/gl/src/renderer.rs +++ b/gl/src/renderer.rs @@ -13,6 +13,7 @@ use crate::device::{Buffer, BufferTarget, BufferUploadMode, Device, Framebuffer, use crate::device::{TimerQuery, Uniform, VertexArray, VertexAttr}; use euclid::Size2D; use gl::types::{GLfloat, GLint}; +use pathfinder_geometry::basic::point::Point3DF32; use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive}; use pathfinder_renderer::paint::{ColorU, ObjectShader}; use pathfinder_renderer::post::DefringingKernel; @@ -52,6 +53,10 @@ pub struct Renderer { postprocess_vertex_array: PostprocessVertexArray, gamma_lut_texture: Texture, + // Stencil shader + stencil_program: StencilProgram, + stencil_vertex_array: StencilVertexArray, + // Debug pending_timer_queries: VecDeque, free_timer_queries: Vec, @@ -60,6 +65,7 @@ pub struct Renderer { // Extra info main_framebuffer_size: Size2D, postprocess_options: PostprocessOptions, + use_depth: bool, } impl Renderer { @@ -69,6 +75,7 @@ impl Renderer { let mask_tile_program = MaskTileProgram::new(device); let postprocess_program = PostprocessProgram::new(device); + let stencil_program = StencilProgram::new(device); let area_lut_texture = device.create_texture_from_png("area-lut"); let gamma_lut_texture = device.create_texture_from_png("gamma-lut"); @@ -86,6 +93,7 @@ impl Renderer { let postprocess_vertex_array = PostprocessVertexArray::new(&postprocess_program, &quad_vertex_positions_buffer); + let stencil_vertex_array = StencilVertexArray::new(&stencil_program); let mask_framebuffer_texture = Texture::new_r16f(&Size2D::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT)); @@ -113,6 +121,9 @@ impl Renderer { postprocess_vertex_array, gamma_lut_texture, + stencil_program, + stencil_vertex_array, + pending_timer_queries: VecDeque::new(), free_timer_queries: vec![], @@ -120,6 +131,7 @@ impl Renderer { main_framebuffer_size: *main_framebuffer_size, postprocess_options: PostprocessOptions::default(), + use_depth: false, } } @@ -131,16 +143,18 @@ impl Renderer { self.upload_shaders(&built_scene.shaders); + if self.use_depth { + self.draw_stencil(&built_scene.quad); + } + self.upload_solid_tiles(&built_scene.solid_tiles); self.draw_solid_tiles(&built_scene); - /* for batch in &built_scene.batches { self.upload_batch(batch); self.draw_batch_fills(batch); - self.draw_batch_mask_tiles(&built_scene, batch); + self.draw_batch_mask_tiles(batch); } - */ if self.postprocessing_needed() { self.postprocess(); @@ -187,6 +201,16 @@ impl Renderer { self.postprocess_options.gamma_correction_bg_color = Some(bg_color); } + #[inline] + pub fn disable_depth(&mut self) { + self.use_depth = false; + } + + #[inline] + pub fn enable_depth(&mut self) { + self.use_depth = true; + } + #[inline] pub fn quad_vertex_positions_buffer(&self) -> &Buffer { &self.quad_vertex_positions_buffer @@ -247,7 +271,7 @@ impl Renderer { } } - fn draw_batch_mask_tiles(&mut self, built_scene: &BuiltScene, batch: &Batch) { + fn draw_batch_mask_tiles(&mut self, batch: &Batch) { unsafe { self.bind_draw_framebuffer(); self.set_main_viewport(); @@ -272,26 +296,12 @@ impl Renderer { FILL_COLORS_TEXTURE_HEIGHT as GLfloat); // FIXME(pcwalton): Fill this in properly! gl::Uniform2f(self.mask_tile_program.view_box_origin_uniform.location, 0.0, 0.0); - gl::Uniform3f(self.mask_tile_program.quad_p0_uniform.location, - built_scene.quad[0].x(), - built_scene.quad[0].y(), - built_scene.quad[0].z()); - gl::Uniform3f(self.mask_tile_program.quad_p1_uniform.location, - built_scene.quad[1].x(), - built_scene.quad[1].y(), - built_scene.quad[1].z()); - gl::Uniform3f(self.mask_tile_program.quad_p2_uniform.location, - built_scene.quad[2].x(), - built_scene.quad[2].y(), - built_scene.quad[2].z()); - gl::Uniform3f(self.mask_tile_program.quad_p3_uniform.location, - built_scene.quad[3].x(), - built_scene.quad[3].y(), - built_scene.quad[3].z()); self.enable_blending(); - self.enable_depth_test(); + gl::Disable(gl::DEPTH_TEST); + self.setup_stencil_mask(); gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, batch.mask_tiles.len() as GLint); gl::Disable(gl::BLEND); + gl::Disable(gl::STENCIL_TEST); } } @@ -315,28 +325,12 @@ impl Renderer { FILL_COLORS_TEXTURE_HEIGHT as GLfloat); // FIXME(pcwalton): Fill this in properly! gl::Uniform2f(self.solid_tile_program.view_box_origin_uniform.location, 0.0, 0.0); - gl::Uniform3f(self.solid_tile_program.quad_p0_uniform.location, - built_scene.quad[0].x(), - built_scene.quad[0].y(), - built_scene.quad[0].z()); - gl::Uniform3f(self.solid_tile_program.quad_p1_uniform.location, - built_scene.quad[1].x(), - built_scene.quad[1].y(), - built_scene.quad[1].z()); - gl::Uniform3f(self.solid_tile_program.quad_p2_uniform.location, - built_scene.quad[2].x(), - built_scene.quad[2].y(), - built_scene.quad[2].z()); - gl::Uniform3f(self.solid_tile_program.quad_p3_uniform.location, - built_scene.quad[3].x(), - built_scene.quad[3].y(), - built_scene.quad[3].z()); gl::Disable(gl::BLEND); - gl::DepthMask(gl::FALSE); - gl::Enable(gl::DEPTH_TEST); - gl::Disable(gl::STENCIL_TEST); + gl::Disable(gl::DEPTH_TEST); + self.setup_stencil_mask(); let count = built_scene.solid_tiles.len(); gl::DrawArraysInstanced(gl::TRIANGLE_FAN, 0, 4, count as GLint); + gl::Disable(gl::STENCIL_TEST); } } @@ -388,6 +382,30 @@ impl Renderer { } } + fn draw_stencil(&self, quad_positions: &[Point3DF32]) { + self.stencil_vertex_array + .vertex_buffer + .upload(quad_positions, BufferTarget::Vertex, BufferUploadMode::Dynamic); + self.bind_draw_framebuffer(); + + unsafe { + gl::BindVertexArray(self.stencil_vertex_array.vertex_array.gl_vertex_array); + gl::UseProgram(self.stencil_program.program.gl_program); + gl::ColorMask(gl::FALSE, gl::FALSE, gl::FALSE, gl::FALSE); + gl::DepthFunc(gl::LESS); + gl::Enable(gl::DEPTH_TEST); + gl::StencilFunc(gl::ALWAYS, 1, 1); + gl::StencilOp(gl::KEEP, gl::KEEP, gl::REPLACE); + gl::StencilMask(1); + gl::Enable(gl::STENCIL_TEST); + gl::Disable(gl::BLEND); + gl::DrawArrays(gl::TRIANGLE_FAN, 0, quad_positions.len() as GLint); + gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); + gl::Disable(gl::DEPTH_TEST); + gl::Disable(gl::STENCIL_TEST); + } + } + fn bind_draw_framebuffer(&self) { unsafe { if self.postprocessing_needed() { @@ -443,11 +461,15 @@ impl Renderer { } } - fn enable_depth_test(&self) { + fn setup_stencil_mask(&self) { unsafe { - gl::DepthMask(gl::FALSE); - gl::Enable(gl::DEPTH_TEST); - gl::Disable(gl::STENCIL_TEST); + if self.use_depth { + gl::StencilFunc(gl::EQUAL, 1, 1); + gl::StencilOp(gl::KEEP, gl::KEEP, gl::KEEP); + gl::Enable(gl::STENCIL_TEST); + } else { + gl::Disable(gl::STENCIL_TEST); + } } } } @@ -574,10 +596,6 @@ struct SolidTileProgram { fill_colors_texture_uniform: Uniform, fill_colors_texture_size_uniform: Uniform, view_box_origin_uniform: Uniform, - quad_p0_uniform: Uniform, - quad_p1_uniform: Uniform, - quad_p2_uniform: Uniform, - quad_p3_uniform: Uniform, } impl SolidTileProgram { @@ -588,10 +606,6 @@ impl SolidTileProgram { let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture"); let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize"); let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin"); - let quad_p0_uniform = Uniform::new(&program, "QuadP0"); - let quad_p1_uniform = Uniform::new(&program, "QuadP1"); - let quad_p2_uniform = Uniform::new(&program, "QuadP2"); - let quad_p3_uniform = Uniform::new(&program, "QuadP3"); SolidTileProgram { program, framebuffer_size_uniform, @@ -599,10 +613,6 @@ impl SolidTileProgram { fill_colors_texture_uniform, fill_colors_texture_size_uniform, view_box_origin_uniform, - quad_p0_uniform, - quad_p1_uniform, - quad_p2_uniform, - quad_p3_uniform, } } } @@ -616,10 +626,6 @@ struct MaskTileProgram { fill_colors_texture_uniform: Uniform, fill_colors_texture_size_uniform: Uniform, view_box_origin_uniform: Uniform, - quad_p0_uniform: Uniform, - quad_p1_uniform: Uniform, - quad_p2_uniform: Uniform, - quad_p3_uniform: Uniform, } impl MaskTileProgram { @@ -632,10 +638,6 @@ impl MaskTileProgram { let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture"); let fill_colors_texture_size_uniform = Uniform::new(&program, "FillColorsTextureSize"); let view_box_origin_uniform = Uniform::new(&program, "ViewBoxOrigin"); - let quad_p0_uniform = Uniform::new(&program, "QuadP0"); - let quad_p1_uniform = Uniform::new(&program, "QuadP1"); - let quad_p2_uniform = Uniform::new(&program, "QuadP2"); - let quad_p3_uniform = Uniform::new(&program, "QuadP3"); MaskTileProgram { program, framebuffer_size_uniform, @@ -645,10 +647,6 @@ impl MaskTileProgram { fill_colors_texture_uniform, fill_colors_texture_size_uniform, view_box_origin_uniform, - quad_p0_uniform, - quad_p1_uniform, - quad_p2_uniform, - quad_p3_uniform, } } } @@ -701,3 +699,35 @@ impl PostprocessVertexArray { PostprocessVertexArray { vertex_array } } } + +struct StencilProgram { + program: Program, +} + +impl StencilProgram { + fn new(device: &Device) -> StencilProgram { + let program = device.create_program("stencil"); + StencilProgram { program } + } +} + +struct StencilVertexArray { + vertex_array: VertexArray, + vertex_buffer: Buffer, +} + +impl StencilVertexArray { + fn new(stencil_program: &StencilProgram) -> StencilVertexArray { + let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new()); + unsafe { + let position_attr = VertexAttr::new(&stencil_program.program, "Position"); + + gl::BindVertexArray(vertex_array.gl_vertex_array); + gl::UseProgram(stencil_program.program.gl_program); + gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer); + position_attr.configure_float(3, gl::FLOAT, false, 4 * 4, 0, 0); + } + + StencilVertexArray { vertex_array, vertex_buffer } + } +} diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 76d388b8..97cef66d 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -173,7 +173,7 @@ impl RenderTransform { for point in &mut points { *point = perspective.transform.transform_point(*point); } - println!("... PERSPECTIVE quad={:?}", points); + //println!("... PERSPECTIVE quad={:?}", points); // Compute depth. let quad = [ @@ -182,12 +182,7 @@ impl RenderTransform { points[2].perspective_divide(), points[3].perspective_divide(), ]; - println!("barycentric(0, 0) = {:?}", compute_barycentric(&[ - quad[0].to_2d(), - quad[1].to_2d(), - quad[2].to_2d(), - quad[3].to_2d(), - ], Point2DF32::new(0.0, 0.0))); + //println!("... PERSPECTIVE-DIVIDED points = {:?}", quad); points = PolygonClipper3D::new(points).clip(); //println!("... CLIPPED quad={:?}", points); @@ -200,20 +195,6 @@ impl RenderTransform { inverse_transform.transform_point(point).perspective_divide().to_2d() }).collect(); return PreparedRenderTransform::Perspective { perspective, clip_polygon, quad }; - - fn compute_barycentric(quad: &[Point2DF32], point: Point2DF32) -> [f32; 4] { - let (s0, s1) = (quad[0] - point, quad[1] - point); - let (s2, s3) = (quad[2] - point, quad[3] - point); - let (a0, a1, a2, a3) = (s0.det(s1), s1.det(s2), s2.det(s3), s3.det(s0)); - let (d0, d1, d2, d3) = (s0.dot(s1), s1.dot(s2), s2.dot(s3), s3.dot(s0)); - let (r0, r1, r2, r3) = (s0.length(), s1.length(), s2.length(), s3.length()); - let (t0, t1) = ((r0 * r1 - d0) / a0, (r1 * r2 - d1) / a1); - let (t2, t3) = ((r2 * r3 - d2) / a2, (r3 * r0 - d3) / a3); - let (u0, u1) = ((t3 + t0) / r0, (t2 + t1) / r1); - let (u2, u3) = ((t0 + t2) / r2, (t0 + t3) / r3); - let sum = u0 + u1 + u2 + u3; - [u0 / sum, u1 / sum, u2 / sum, u3 / sum] - } } } diff --git a/resources/shaders/mask_tile.vs.glsl b/resources/shaders/mask_tile.vs.glsl index 10584ecb..21b60485 100644 --- a/resources/shaders/mask_tile.vs.glsl +++ b/resources/shaders/mask_tile.vs.glsl @@ -18,10 +18,6 @@ uniform vec2 uStencilTextureSize; uniform sampler2D uFillColorsTexture; uniform vec2 uFillColorsTextureSize; uniform vec2 uViewBoxOrigin; -uniform vec3 uQuadP0; -uniform vec3 uQuadP1; -uniform vec3 uQuadP2; -uniform vec3 uQuadP3; in vec2 aTessCoord; in vec2 aTileOrigin; @@ -32,21 +28,6 @@ out vec2 vTexCoord; out float vBackdrop; out vec4 vColor; -float wedge(vec2 a, vec2 b) { - return a.x * b.y - a.y * b.x; -} - -// From "A Quadrilateral Rendering Primitive", Hormann and Tarini 2004. -vec4 barycentricQuad(vec2 p) { - vec2 s0 = uQuadP0.xy - p, s1 = uQuadP1.xy - p, s2 = uQuadP2.xy - p, s3 = uQuadP3.xy - p; - vec4 a = vec4(wedge(s0, s1), wedge(s1, s2), wedge(s2, s3), wedge(s3, s0)); - vec4 d = vec4(dot(s0, s1), dot(s1, s2), dot(s2, s3), dot(s3, s0)); - vec4 r = vec4(length(s0), length(s1), length(s2), length(s3)); - vec4 t = (r * r.yzwx - d) / a; - vec4 u = (t.wxyz + t) / r; - return u / dot(u, vec4(1.0)); -} - vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) { uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x); uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow); @@ -62,21 +43,11 @@ void main() { uint tileIndex = uint(gl_InstanceID); vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); - - vec4 lambda = barycentricQuad(position); - //vec4 depths = vec4(uQuadP0.z, uQuadP1.z, uQuadP2.z, uQuadP3.z); - //float depth = dot(lambda, depths); - float red = lambda.x; - float green = lambda.y; - float blue = lambda.z + 1.0; - float depth = 0.0; - vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize; vec2 colorTexCoord = computeFillColorTexCoord(aObject, uFillColorsTextureSize); vTexCoord = texCoord / uStencilTextureSize; vBackdrop = float(aBackdrop); - //vColor = texture(uFillColorsTexture, colorTexCoord); - vColor = vec4(red, green, blue, 1.0); - gl_Position = vec4(position, depth, 1.0); + vColor = texture(uFillColorsTexture, colorTexCoord); + gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/solid_tile.vs.glsl b/resources/shaders/solid_tile.vs.glsl index 7ac1018d..f1b536f0 100644 --- a/resources/shaders/solid_tile.vs.glsl +++ b/resources/shaders/solid_tile.vs.glsl @@ -17,10 +17,6 @@ uniform vec2 uTileSize; uniform sampler2D uFillColorsTexture; uniform vec2 uFillColorsTextureSize; uniform vec2 uViewBoxOrigin; -uniform vec3 uQuadP0; -uniform vec3 uQuadP1; -uniform vec3 uQuadP2; -uniform vec3 uQuadP3; in vec2 aTessCoord; in vec2 aTileOrigin; @@ -28,21 +24,6 @@ in uint aObject; out vec4 vColor; -float wedge(vec2 a, vec2 b) { - return a.x * b.y - a.y * b.x; -} - -// From "A Quadrilateral Rendering Primitive", Hormann and Tarini 2004. -vec4 barycentricQuad(vec2 p) { - vec2 s0 = uQuadP0.xy - p, s1 = uQuadP1.xy - p, s2 = uQuadP2.xy - p, s3 = uQuadP3.xy - p; - vec4 a = vec4(wedge(s0, s1), wedge(s1, s2), wedge(s2, s3), wedge(s3, s0)); - vec4 d = vec4(dot(s0, s1), dot(s1, s2), dot(s2, s3), dot(s3, s0)); - vec4 r = vec4(length(s0), length(s1), length(s2), length(s3)); - vec4 t = (r * r.yzwx - d) / a; - vec4 u = (t.wxyz + t) / r; - return u / dot(u, vec4(1.0)); -} - vec2 computeFillColorTexCoord(uint object, vec2 textureSize) { uint width = uint(textureSize.x); return (vec2(float(object % width), float(object / width)) + vec2(0.5)) / textureSize; @@ -51,19 +32,8 @@ vec2 computeFillColorTexCoord(uint object, vec2 textureSize) { void main() { vec2 pixelPosition = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin; vec2 position = (pixelPosition / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0); - - //vec4 depths = vec4(uQuadP0.z, uQuadP1.z, uQuadP2.z, uQuadP3.z); - //float depth = dot(barycentricQuad(position), depths); - - vec4 lambda = barycentricQuad(position); - float red = lambda.x; - float green = lambda.y; - float blue = lambda.z; - float depth = 0.0; - vec2 colorTexCoord = computeFillColorTexCoord(aObject, uFillColorsTextureSize); - //vColor = texture(uFillColorsTexture, colorTexCoord); - vColor = vec4(red, green, blue, 1.0); - gl_Position = vec4(position, depth, 1.0); + vColor = texture(uFillColorsTexture, colorTexCoord); + gl_Position = vec4(position, 0.0, 1.0); } diff --git a/resources/shaders/stencil.fs.glsl b/resources/shaders/stencil.fs.glsl new file mode 100644 index 00000000..ddf87a8d --- /dev/null +++ b/resources/shaders/stencil.fs.glsl @@ -0,0 +1,20 @@ +#version 330 + +// pathfinder/resources/shaders/stencil.fs.glsl +// +// Copyright © 2018 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +precision highp float; + +out vec4 oFragColor; + +void main() { + // This should be color masked out. + oFragColor = vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/resources/shaders/stencil.vs.glsl b/resources/shaders/stencil.vs.glsl new file mode 100644 index 00000000..01938788 --- /dev/null +++ b/resources/shaders/stencil.vs.glsl @@ -0,0 +1,19 @@ +#version 330 + +// pathfinder/resources/shaders/stencil.vs.glsl +// +// Copyright © 2018 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +precision highp float; + +in vec3 aPosition; + +void main() { + gl_Position = vec4(aPosition, 1.0); +}