In VR mode, render one eye and then reproject to both eyes instead of rendering

twice.

This reduces both CPU and GPU time a lot in exchange for a small loss in
quality.
This commit is contained in:
Patrick Walton 2019-04-22 13:50:38 -07:00
parent 7cd05cd3ef
commit 6c31e1bc01
18 changed files with 559 additions and 156 deletions

107
Cargo.lock generated
View File

@ -64,6 +64,15 @@ dependencies = [
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "argon2rs"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayvec"
version = "0.4.10"
@ -128,6 +137,15 @@ name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "blake2-rfc"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "block"
version = "0.1.6"
@ -198,6 +216,15 @@ dependencies = [
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "color-backtrace"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "color_quant"
version = "1.0.1"
@ -215,6 +242,11 @@ dependencies = [
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "core-foundation"
version = "0.6.4"
@ -292,6 +324,7 @@ dependencies = [
name = "demo"
version = "0.1.0"
dependencies = [
"color-backtrace 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -304,6 +337,16 @@ dependencies = [
"sdl2-sys 0.32.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dirs"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dlib"
version = "0.4.1"
@ -370,6 +413,26 @@ dependencies = [
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fixedbitset"
version = "0.1.9"
@ -1274,6 +1337,17 @@ dependencies = [
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_users"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.80"
@ -1550,6 +1624,27 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termcolor"
version = "1.0.4"
@ -1715,7 +1810,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1836,6 +1931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
@ -1844,6 +1940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4390a3b5f4f6bce9c1d0c00128379df433e53777fdd30e92f16a529332baec4e"
@ -1853,8 +1950,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b"
"checksum color-backtrace 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "90242aff9b6439332beb77ee416126367adcd6376b0dc80b39250e7debdd913d"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
"checksum combine 3.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d2623b3542b48f4427e15ddd4995186decb594ebbd70271463886584b4a114b9"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
@ -1863,6 +1962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86"
"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
"checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a"
"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f"
"checksum egl 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a373bc9844200b1ff15bd1b245931d1c20d09d06e4ec09f361171f29a4b0752d"
@ -1871,6 +1971,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
"checksum euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a7698bdda3d7444a79d33bdc96e8b518d44ea3ff101d8492a6ca1207b886ea"
"checksum euclid_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcb84c18ea5037a1c5a23039b4ff29403abce2e0d6b1daa11cf0bde2b30be15"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
@ -1961,6 +2063,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
@ -1996,6 +2099,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9b53b3ed152fc6b871f7232a8772c640567fd25d056941450637ecba32924d"
"checksum svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c43c25e6de7264024b5e351eb0c342039eb5acf51f2e9d0099bbd324b661453b"
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
"checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"

View File

@ -18,6 +18,7 @@ import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@ -61,13 +62,8 @@ public class PathfinderDemoActivity extends Activity {
@RequiresApi(api = Build.VERSION_CODES.N)
void setVRMode(boolean enabled) {
try {
setVrModeEnabled(false, mVRListenerComponentName);
mContentView.setStereoModeEnabled(enabled);
mContentView.setDistortionCorrectionEnabled(false);
} catch (PackageManager.NameNotFoundException exception) {
startActivity(new Intent(Settings.ACTION_VR_LISTENER_SETTINGS));
}
mContentView.setStereoModeEnabled(enabled);
mContentView.setDistortionCorrectionEnabled(false);
}
@RequiresApi(api = Build.VERSION_CODES.N)

View File

@ -44,5 +44,4 @@ public class PathfinderDemoFileBrowserActivity extends Activity {
}
});
}
}

View File

@ -2,6 +2,7 @@ package graphics.pathfinder.pathfinderdemo;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.Log;
import com.google.vr.sdk.base.Eye;
import com.google.vr.sdk.base.GvrView;
@ -52,6 +53,7 @@ public class PathfinderDemoRenderer extends Object implements GvrView.Renderer {
mInVRMode = inVR;
try {
mActivity.setVrModeEnabled(mInVRMode, mActivity.mVRListenerComponentName);
mActivity.setVRMode(inVR);
} catch (PackageManager.NameNotFoundException exception) {
throw new RuntimeException(exception);
}

View File

@ -12,19 +12,18 @@
use crate::device::{GroundLineVertexArray, GroundProgram, GroundSolidVertexArray};
use crate::ui::{DemoUI, UIAction};
use crate::window::{CameraTransform, Event, Keycode, SVGPath, View, Window, WindowSize};
use crate::window::{Event, Keycode, OcularTransform, SVGPath, View, Window, WindowSize};
use clap::{App, Arg};
use image::ColorType;
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
use pathfinder_geometry::color::ColorU;
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
use pathfinder_geometry::color::{ColorF, ColorU};
use pathfinder_gl::GLDevice;
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc};
use pathfinder_gpu::{StencilState, UniformData};
use pathfinder_gpu::{ClearParams, DepthFunc, DepthState, Device, Primitive, RenderState};
use pathfinder_gpu::{StencilFunc, StencilState, TextureFormat, UniformData};
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, RenderMode, RenderStats, Renderer};
use pathfinder_renderer::gpu_data::RenderCommand;
@ -37,7 +36,6 @@ use std::f32::consts::FRAC_PI_4;
use std::fmt::{Debug, Formatter, Result as DebugResult};
use std::fs::File;
use std::io::Read;
use std::iter;
use std::panic::{self, AssertUnwindSafe};
use std::path::PathBuf;
use std::process;
@ -72,6 +70,9 @@ const MESSAGE_TIMEOUT_SECS: u64 = 5;
const MAX_MESSAGES_IN_FLIGHT: usize = 256;
// Half of the eye separation distance.
const DEFAULT_EYE_OFFSET: f32 = 0.025;
pub const GRIDLINE_COUNT: u8 = 10;
pub mod window;
@ -104,6 +105,8 @@ pub struct DemoApp<W> where W: Window {
scene_thread_proxy: SceneThreadProxy,
renderer: Renderer<GLDevice>,
scene_framebuffer: Option<<GLDevice as Device>::Framebuffer>,
ground_program: GroundProgram<GLDevice>,
ground_solid_vertex_array: GroundSolidVertexArray<GLDevice>,
ground_line_vertex_array: GroundLineVertexArray<GLDevice>,
@ -178,6 +181,8 @@ impl<W> DemoApp<W> where W: Window {
scene_thread_proxy,
renderer,
scene_framebuffer: None,
ground_program,
ground_solid_vertex_array,
ground_line_vertex_array,
@ -195,61 +200,96 @@ impl<W> DemoApp<W> where W: Window {
self.build_scene();
// Get the render message, and determine how many scenes it contains.
let transforms = match self.scene_thread_proxy.receiver.recv().unwrap() {
SceneToMainMsg::BeginFrame { transforms } => transforms,
let transform = match self.scene_thread_proxy.receiver.recv().unwrap() {
SceneToMainMsg::BeginFrame { transform } => transform,
msg => panic!("Expected BeginFrame message, found {:?}!", msg),
};
let render_scene_count = transforms.len() as u32;
// Save the frame.
self.current_frame = Some(Frame::new(transforms, ui_events));
self.current_frame = Some(Frame::new(transform, ui_events));
// Initialize and set the appropriate framebuffer.
let view = self.ui.mode.view(0);
self.window.make_current(view);
let window_size = self.window_size.device_size();
let scene_count = match self.camera.mode() {
Mode::VR => {
let viewport = self.window.viewport(View::Stereo(0));
if self.scene_framebuffer.is_none() ||
self.renderer
.device
.texture_size(&self.renderer
.device
.framebuffer_texture(self.scene_framebuffer
.as_ref()
.unwrap())) !=
viewport.size() {
let scene_texture = self.renderer.device.create_texture(TextureFormat::RGBA8,
viewport.size());
self.scene_framebuffer =
Some(self.renderer.device.create_framebuffer(scene_texture));
}
self.renderer
.replace_dest_framebuffer(DestFramebuffer::Other(self.scene_framebuffer
.take()
.unwrap()));
2
}
_ => {
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport: self.window.viewport(View::Mono),
window_size,
});
1
}
};
// Begin drawing the scene.
for render_scene_index in 0..render_scene_count {
let view = self.ui.mode.view(render_scene_index);
let viewport = self.window.viewport(view);
self.window.make_current(view);
self.renderer.set_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.renderer.device.clear(Some(self.background_color().to_f32().0), Some(1.0), Some(0));
}
self.renderer.bind_dest_framebuffer();
render_scene_count
// Clear to the appropriate color.
let clear_color = if scene_count == 2 {
ColorF::transparent_black()
} else {
self.background_color().to_f32()
};
self.renderer.device.clear(&ClearParams {
color: Some(clear_color),
depth: Some(1.0),
stencil: Some(0),
..ClearParams::default()
});
scene_count
}
fn build_scene(&mut self) {
let render_transforms = match self.camera {
Camera::ThreeD { ref transforms, ref mut transform, ref mut velocity, .. } => {
if transform.offset(*velocity) {
let render_transform = match self.camera {
Camera::ThreeD {
ref scene_transform,
ref mut modelview_transform,
ref mut velocity,
..
} => {
if modelview_transform.offset(*velocity) {
self.dirty = true;
}
transforms.iter()
.map(|tr| {
let perspective = tr.perspective
.post_mul(&tr.view)
.post_mul(&transform.to_transform());
RenderTransform::Perspective(perspective)
}).collect()
let perspective = scene_transform.perspective
.post_mul(&scene_transform.modelview_to_eye)
.post_mul(&modelview_transform.to_transform());
RenderTransform::Perspective(perspective)
}
Camera::TwoD(transform) => vec![RenderTransform::Transform2D(transform)],
};
let barrel_distortion = match self.ui.mode {
Mode::VR => Some(self.window.barrel_distortion_coefficients()),
_ => None,
Camera::TwoD(transform) => RenderTransform::Transform2D(transform),
};
self.scene_thread_proxy.sender.send(MainToSceneMsg::Build(BuildOptions {
render_transforms,
render_transform,
stem_darkening_font_size: if self.ui.stem_darkening_effect_enabled {
Some(APPROX_FONT_SIZE * self.window_size.backing_scale_factor)
} else {
None
},
subpixel_aa_enabled: self.ui.subpixel_aa_effect_enabled,
barrel_distortion,
})).unwrap();
}
@ -277,12 +317,12 @@ impl<W> DemoApp<W> where W: Window {
}
Event::MouseMoved(new_position) if self.mouselook_enabled => {
let mouse_position = self.process_mouse_position(new_position);
if let Camera::ThreeD { ref mut transform, .. } = self.camera {
if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera {
let rotation = mouse_position.relative
.to_f32()
.scale(MOUSELOOK_ROTATION_SPEED);
transform.yaw += rotation.x();
transform.pitch += rotation.y();
modelview_transform.yaw += rotation.x();
modelview_transform.pitch += rotation.y();
self.dirty = true;
}
}
@ -302,14 +342,14 @@ impl<W> DemoApp<W> where W: Window {
}
}
Event::Look { pitch, yaw } => {
if let Camera::ThreeD { ref mut transform, .. } = self.camera {
transform.pitch += pitch;
transform.yaw += yaw;
if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera {
modelview_transform.pitch += pitch;
modelview_transform.yaw += yaw;
}
}
Event::CameraTransforms(new_transforms) => {
if let Camera::ThreeD { ref mut transforms, .. } = self.camera {
*transforms = new_transforms;
Event::SetEyeTransforms(new_eye_transforms) => {
if let Camera::ThreeD { ref mut eye_transforms, .. } = self.camera {
*eye_transforms = new_eye_transforms;
}
}
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {
@ -392,23 +432,101 @@ impl<W> DemoApp<W> where W: Window {
MousePosition { absolute, relative }
}
pub fn draw_scene(&mut self, render_scene_index: u32) {
let view = self.ui.mode.view(render_scene_index);
let viewport = self.window.viewport(view);
pub fn draw_scene(&mut self) {
let view = self.ui.mode.view(0);
self.window.make_current(view);
self.renderer.set_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.draw_environment(render_scene_index);
if self.camera.mode() != Mode::VR {
self.draw_environment(0);
}
self.render_vector_scene();
if let Some(rendering_time) = self.renderer.shift_timer_query() {
self.current_frame.as_mut().unwrap().scene_rendering_times.push(rendering_time)
// Reattach default framebuffer.
if self.camera.mode() != Mode::VR {
return;
}
if let DestFramebuffer::Other(scene_framebuffer) =
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport: self.window.viewport(View::Mono),
window_size: self.window_size.device_size(),
}) {
self.scene_framebuffer = Some(scene_framebuffer);
}
}
pub fn composite_scene(&mut self, render_scene_index: u32) {
let (eye_transforms, scene_transform, modelview_transform) = match self.camera {
Camera::ThreeD {
ref eye_transforms,
ref scene_transform,
ref modelview_transform,
..
} if eye_transforms.len() > 1 => {
(eye_transforms, scene_transform, modelview_transform)
}
_ => return,
};
/*
println!("scene_transform.perspective={:?}", scene_transform.perspective);
println!("scene_transform.modelview_to_eye={:?}", scene_transform.modelview_to_eye);
println!("modelview transform={:?}", modelview_transform);
*/
let viewport = self.window.viewport(View::Stereo(render_scene_index));
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
self.renderer.bind_draw_framebuffer();
self.renderer.device.clear(&ClearParams {
color: Some(self.background_color().to_f32()),
depth: Some(1.0),
stencil: Some(0),
rect: Some(viewport),
});
self.draw_environment(render_scene_index);
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
let quad_scale_transform = Transform3DF32::from_scale(self.scene_view_box.size().x(),
self.scene_view_box.size().y(),
1.0);
let scene_transform_matrix = scene_transform.perspective
.post_mul(&scene_transform.modelview_to_eye)
.post_mul(&modelview_transform.to_transform())
.post_mul(&quad_scale_transform);
let eye_transform = &eye_transforms[render_scene_index as usize];
let eye_transform_matrix = eye_transform.perspective
.post_mul(&eye_transform.modelview_to_eye)
.post_mul(&modelview_transform.to_transform())
.post_mul(&quad_scale_transform);
/*
println!("eye transform({}).modelview_to_eye={:?}",
render_scene_index,
eye_transform.modelview_to_eye);
println!("eye transform_matrix({})={:?}", render_scene_index, eye_transform_matrix);
println!("---");
*/
self.renderer.reproject_texture(scene_texture,
&scene_transform_matrix.transform,
&eye_transform_matrix.transform);
}
pub fn finish_drawing_frame(&mut self) {
if let Some(rendering_time) = self.renderer.shift_timer_query() {
self.current_frame.as_mut().unwrap().scene_rendering_times.push(rendering_time);
}
let tile_time = match self.scene_thread_proxy.receiver.recv().unwrap() {
SceneToMainMsg::EndFrame { tile_time } => tile_time,
_ => panic!("Expected `EndFrame`!"),
@ -435,7 +553,7 @@ impl<W> DemoApp<W> where W: Window {
if self.options.ui != UIVisibility::None {
let viewport = self.window.viewport(View::Mono);
self.window.make_current(View::Mono);
self.renderer.set_dest_framebuffer(DestFramebuffer::Default {
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
viewport,
window_size: self.window_size.device_size(),
});
@ -489,10 +607,11 @@ impl<W> DemoApp<W> where W: Window {
}
fn draw_environment(&self, viewport_index: u32) {
let frame = &self.current_frame.as_ref().unwrap();
let render_transform = &frame.transforms[viewport_index as usize].clone();
// TODO(pcwalton): Use the viewport index!
let perspective = match *render_transform {
let frame = &self.current_frame.as_ref().unwrap();
let perspective = match frame.transform {
RenderTransform::Transform2D(..) => return,
RenderTransform::Perspective(perspective) => perspective,
};
@ -542,12 +661,8 @@ impl<W> DemoApp<W> where W: Window {
transform.post_mul(&Transform3DF32::from_scale(ground_scale, 1.0, ground_scale));
device.bind_vertex_array(&self.ground_solid_vertex_array.vertex_array);
device.use_program(&self.ground_program.program);
device.set_uniform(&self.ground_program.transform_uniform, UniformData::Mat4([
transform.c0,
transform.c1,
transform.c2,
transform.c3,
]));
device.set_uniform(&self.ground_program.transform_uniform,
UniformData::from_transform_3d(&transform));
device.set_uniform(&self.ground_program.color_uniform,
UniformData::Vec4(GROUND_SOLID_COLOR.to_f32().0));
device.draw_arrays(Primitive::TriangleFan, 4, &RenderState {
@ -716,16 +831,10 @@ impl SceneThread {
}
MainToSceneMsg::Build(build_options) => {
self.sender.send(SceneToMainMsg::BeginFrame {
transforms: build_options.render_transforms.clone(),
transform: build_options.render_transform.clone(),
}).unwrap();
let start_time = Instant::now();
for render_transform in &build_options.render_transforms {
build_scene(&self.scene,
&build_options,
(*render_transform).clone(),
self.options.jobs,
&mut self.sender);
}
build_scene(&self.scene, &build_options, self.options.jobs, &mut self.sender);
let tile_time = Instant::now() - start_time;
self.sender.send(SceneToMainMsg::EndFrame { tile_time }).unwrap();
}
@ -743,14 +852,13 @@ enum MainToSceneMsg {
#[derive(Clone)]
struct BuildOptions {
render_transforms: Vec<RenderTransform>,
render_transform: RenderTransform,
stem_darkening_font_size: Option<f32>,
barrel_distortion: Option<BarrelDistortionCoefficients>,
subpixel_aa_enabled: bool,
}
enum SceneToMainMsg {
BeginFrame { transforms: Vec<RenderTransform> },
BeginFrame { transform: RenderTransform },
EndFrame { tile_time: Duration },
BeginRenderScene(SceneDescriptor),
Execute(RenderCommand),
@ -772,11 +880,10 @@ impl Debug for SceneToMainMsg {
fn build_scene(scene: &Scene,
build_options: &BuildOptions,
render_transform: RenderTransform,
jobs: Option<usize>,
sink: &mut SyncSender<SceneToMainMsg>) {
let render_options = RenderOptions {
transform: render_transform.clone(),
transform: build_options.render_transform.clone(),
dilation: match build_options.stem_darkening_font_size {
None => Point2DF32::default(),
Some(font_size) => {
@ -784,7 +891,6 @@ fn build_scene(scene: &Scene,
Point2DF32::new(x, y).scale(font_size)
}
},
barrel_distortion: build_options.barrel_distortion,
subpixel_aa_enabled: build_options.subpixel_aa_enabled,
};
@ -954,11 +1060,15 @@ fn center_of_window(window_size: &WindowSize) -> Point2DF32 {
enum Camera {
TwoD(Transform2DF32),
ThreeD {
// For each camera, the perspective from camera coordinates to display coordinates,
// The ocular transform used for rendering of the scene to the scene framebuffer. If we are
// performing stereoscopic rendering, this is then reprojected according to the eye
// transforms below.
scene_transform: OcularTransform,
// For each eye, the perspective from camera coordinates to display coordinates,
// and the view transform from world coordinates to camera coordinates.
transforms: Vec<CameraTransform>,
// The model transform from world coordinates to SVG coordinates
transform: CameraTransform3D,
eye_transforms: Vec<OcularTransform>,
// The modelview transform from world coordinates to SVG coordinates
modelview_transform: CameraTransform3D,
// The camera's velocity (in world coordinates)
velocity: Point3DF32,
},
@ -982,17 +1092,37 @@ impl Camera {
fn new_3d(mode: Mode, view_box: RectF32, viewport_size: Point2DI32) -> Camera {
let viewport_count = mode.viewport_count();
let fov_y = FRAC_PI_4;
let aspect = viewport_size.x() as f32 / viewport_size.y() as f32;
let projection = Transform3DF32::from_perspective(FRAC_PI_4, aspect, NEAR_CLIP_PLANE, FAR_CLIP_PLANE);
let transform = CameraTransform {
perspective: Perspective::new(&projection, viewport_size),
view: Transform3DF32::default(),
let projection = Transform3DF32::from_perspective(fov_y,
aspect,
NEAR_CLIP_PLANE,
FAR_CLIP_PLANE);
let perspective = Perspective::new(&projection, viewport_size);
// Create a scene transform by moving the camera back from the center of the eyes so that
// its field of view encompasses the field of view of both eyes.
let z_offset = -DEFAULT_EYE_OFFSET * projection.c0.x();
let scene_transform = OcularTransform {
perspective,
modelview_to_eye: Transform3DF32::from_translation(0.0, 0.0, z_offset),
};
let transforms = iter::repeat(transform).take(viewport_count).collect();
// For now, initialize the eye transforms as copies of the scene transform.
let eye_offset = DEFAULT_EYE_OFFSET;
let eye_transforms = (0..viewport_count).map(|viewport_index| {
let this_eye_offset = if viewport_index == 0 { eye_offset } else { -eye_offset };
OcularTransform {
perspective,
modelview_to_eye: Transform3DF32::from_translation(this_eye_offset, 0.0, 0.0),
}
}).collect();
Camera::ThreeD {
transforms,
transform: CameraTransform3D::new(view_box),
scene_transform,
eye_transforms,
modelview_transform: CameraTransform3D::new(view_box),
velocity: Point3DF32::default(),
}
}
@ -1003,14 +1133,14 @@ impl Camera {
fn mode(&self) -> Mode {
match *self {
Camera::ThreeD { ref transforms, .. } if 2 <= transforms.len() => Mode::VR,
Camera::ThreeD { ref eye_transforms, .. } if eye_transforms.len() >= 2 => Mode::VR,
Camera::ThreeD { .. } => Mode::ThreeD,
Camera::TwoD { .. } => Mode::TwoD,
}
}
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
struct CameraTransform3D {
position: Point3DF32,
yaw: f32,
@ -1089,15 +1219,15 @@ fn emit_message<W>(ui: &mut DemoUI<GLDevice>,
}
struct Frame {
transforms: Vec<RenderTransform>,
transform: RenderTransform,
ui_events: Vec<UIEvent>,
scene_rendering_times: Vec<Duration>,
scene_stats: Vec<RenderStats>,
}
impl Frame {
fn new(transforms: Vec<RenderTransform>, ui_events: Vec<UIEvent>) -> Frame {
Frame { transforms, ui_events, scene_rendering_times: vec![], scene_stats: vec![] }
fn new(transform: RenderTransform, ui_events: Vec<UIEvent>) -> Frame {
Frame { transform, ui_events, scene_rendering_times: vec![], scene_stats: vec![] }
}
}

View File

@ -53,7 +53,7 @@ pub enum Event {
MouseDragged(Point2DI32),
Zoom(f32),
Look { pitch: f32, yaw: f32 },
CameraTransforms(Vec<CameraTransform>),
SetEyeTransforms(Vec<OcularTransform>),
OpenSVG(SVGPath),
User { message_type: u32, message_data: u32 },
}
@ -85,12 +85,12 @@ pub enum View {
}
#[derive(Clone, Copy, Debug)]
pub struct CameraTransform {
pub struct OcularTransform {
// The perspective which converts from camera coordinates to display coordinates
pub perspective: Perspective,
// The view transform which converts from world coordinates to camera coordinates
pub view: Transform3DF32,
pub modelview_to_eye: Transform3DF32,
}
#[derive(Clone)]

View File

@ -8,6 +8,7 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
pf-no-simd = ["pathfinder_simd/pf-no-simd"]
[dependencies]
color-backtrace = "0.1"
gl = "0.6"
jemallocator = "0.1"
nfd = "0.0.4"

View File

@ -34,6 +34,8 @@ const DEFAULT_WINDOW_WIDTH: u32 = 1067;
const DEFAULT_WINDOW_HEIGHT: u32 = 800;
fn main() {
color_backtrace::install();
let window = WindowImpl::new();
let window_size = window.size();
let options = Options::default();
@ -49,8 +51,9 @@ fn main() {
}
let scene_count = app.prepare_frame(events);
app.draw_scene();
for scene_index in 0..scene_count {
app.draw_scene(scene_index);
app.composite_scene(scene_index);
}
app.finish_drawing_frame();
}
@ -84,17 +87,14 @@ impl Window for WindowImpl {
fn viewport(&self, view: View) -> RectI32 {
let (width, height) = self.window.drawable_size();
let mut width = width as i32;
let height = height as i32;
let mut x_offset = 0;
let mut width = width as i32;
let height = height as i32;
let mut x_offset = 0;
if let View::Stereo(index) = view {
width = width / 2;
x_offset = width * (index as i32);
x_offset = width * (index as i32);
}
RectI32::new (
Point2DI32::new(x_offset, 0),
Point2DI32::new(width, height),
)
RectI32::new(Point2DI32::new(x_offset, 0), Point2DI32::new(width, height))
}
fn make_current(&mut self, _view: View) {

View File

@ -56,6 +56,11 @@ impl Debug for ColorU {
pub struct ColorF(pub F32x4);
impl ColorF {
#[inline]
pub fn transparent_black() -> ColorF {
ColorF(F32x4::default())
}
#[inline]
pub fn r(&self) -> f32 {
self.0[0]

View File

@ -13,9 +13,9 @@
use gl::types::{GLboolean, GLchar, GLenum, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, DepthFunc, Device};
use pathfinder_gpu::{Primitive, RenderState, ShaderKind, StencilFunc, TextureFormat};
use pathfinder_gpu::{UniformData, VertexAttrType};
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams};
use pathfinder_gpu::{DepthFunc, Device, Primitive, RenderState, ShaderKind, StencilFunc};
use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrType};
use pathfinder_simd::default::F32x4;
use rustache::{HashBuilder, Render};
use std::ffi::CString;
@ -367,6 +367,14 @@ impl Device for GLDevice {
UniformData::Int(value) => {
gl::Uniform1i(uniform.location, value); ck();
}
UniformData::Mat2(data) => {
assert_eq!(mem::size_of::<F32x4>(), 4 * 4);
let data_ptr: *const F32x4 = &data;
gl::UniformMatrix2fv(uniform.location,
1,
gl::FALSE,
data_ptr as *const GLfloat);
}
UniformData::Mat4(data) => {
assert_eq!(mem::size_of::<[F32x4; 4]>(), 4 * 4 * 4);
let data_ptr: *const F32x4 = data.as_ptr();
@ -487,21 +495,26 @@ impl Device for GLDevice {
pixels
}
// TODO(pcwalton): Switch to `ColorF`!
fn clear(&self, color: Option<F32x4>, depth: Option<f32>, stencil: Option<u8>) {
fn clear(&self, params: &ClearParams) {
unsafe {
if let Some(rect) = params.rect {
let (origin, size) = (rect.origin(), rect.size());
gl::Scissor(origin.x(), origin.y(), size.x(), size.y()); ck();
gl::Enable(gl::SCISSOR_TEST); ck();
}
let mut flags = 0;
if let Some(color) = color {
if let Some(color) = params.color {
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); ck();
gl::ClearColor(color.x(), color.y(), color.z(), color.w()); ck();
gl::ClearColor(color.r(), color.g(), color.b(), color.a()); ck();
flags |= gl::COLOR_BUFFER_BIT;
}
if let Some(depth) = depth {
if let Some(depth) = params.depth {
gl::DepthMask(gl::TRUE); ck();
gl::ClearDepthf(depth as _); ck(); // FIXME(pcwalton): GLES
flags |= gl::DEPTH_BUFFER_BIT;
}
if let Some(stencil) = stencil {
if let Some(stencil) = params.stencil {
gl::StencilMask(!0); ck();
gl::ClearStencil(stencil as GLint); ck();
flags |= gl::STENCIL_BUFFER_BIT;
@ -509,6 +522,10 @@ impl Device for GLDevice {
if flags != 0 {
gl::Clear(flags); ck();
}
if params.rect.is_some() {
gl::Disable(gl::SCISSOR_TEST); ck();
}
}
}

View File

@ -14,6 +14,8 @@ use crate::resources::ResourceLoader;
use image::ImageFormat;
use pathfinder_geometry::basic::point::Point2DI32;
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_geometry::basic::transform3d::Transform3DF32;
use pathfinder_geometry::color::ColorF;
use pathfinder_simd::default::F32x4;
use rustache::HashBuilder;
use std::time::Duration;
@ -75,8 +77,7 @@ pub trait Device {
fn texture_size(&self, texture: &Self::Texture) -> Point2DI32;
fn upload_to_texture(&self, texture: &Self::Texture, size: Point2DI32, data: &[u8]);
fn read_pixels_from_default_framebuffer(&self, size: Point2DI32) -> Vec<u8>;
// TODO(pcwalton): Switch to `ColorF`!
fn clear(&self, color: Option<F32x4>, depth: Option<f32>, stencil: Option<u8>);
fn clear(&self, params: &ClearParams);
fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
fn draw_arrays_instanced(&self,
@ -199,6 +200,7 @@ pub enum ShaderKind {
#[derive(Clone, Copy)]
pub enum UniformData {
Int(i32),
Mat2(F32x4),
Mat4([F32x4; 4]),
Vec2(F32x4),
Vec4(F32x4),
@ -212,6 +214,14 @@ pub enum Primitive {
Lines,
}
#[derive(Clone, Copy, Default)]
pub struct ClearParams {
pub color: Option<ColorF>,
pub rect: Option<RectI32>,
pub depth: Option<f32>,
pub stencil: Option<u8>,
}
#[derive(Clone, Debug)]
pub struct RenderState {
pub blend: BlendState,
@ -290,6 +300,13 @@ impl Default for StencilFunc {
}
}
impl UniformData {
#[inline]
pub fn from_transform_3d(transform: &Transform3DF32) -> UniformData {
UniformData::Mat4([transform.c0, transform.c1, transform.c2, transform.c3])
}
}
fn load_shader_include(resources: &dyn ResourceLoader, include_name: &str) -> String {
let resource = resources.slurp(&format!("shaders/{}.inc.glsl", include_name)).unwrap();
String::from_utf8_lossy(&resource).to_string()

View File

@ -19,14 +19,10 @@ use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::clip::PolygonClipper3D;
use pathfinder_geometry::distortion::BarrelDistortionCoefficients;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::sync::atomic::AtomicUsize;
use std::u16;
// Must be a power of two.
pub const MAX_FILLS_PER_BATCH: u32 = 0x1000;
pub trait RenderCommandListener: Send + Sync {
fn send(&self, command: RenderCommand);
}
@ -134,7 +130,6 @@ impl<'a> SceneBuilder<'a> {
pub struct RenderOptions {
pub transform: RenderTransform,
pub dilation: Point2DF32,
pub barrel_distortion: Option<BarrelDistortionCoefficients>,
pub subpixel_aa_enabled: bool,
}
@ -143,7 +138,6 @@ impl RenderOptions {
PreparedRenderOptions {
transform: self.transform.prepare(bounds),
dilation: self.dilation,
barrel_distortion: self.barrel_distortion,
subpixel_aa_enabled: self.subpixel_aa_enabled,
}
}
@ -213,7 +207,6 @@ impl RenderTransform {
pub struct PreparedRenderOptions {
pub transform: PreparedRenderTransform,
pub dilation: Point2DF32,
pub barrel_distortion: Option<BarrelDistortionCoefficients>,
pub subpixel_aa_enabled: bool,
}

View File

@ -16,14 +16,16 @@ use crate::scene::{ObjectShader, SceneDescriptor};
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use pathfinder_geometry::basic::point::{Point2DI32, Point3DF32};
use pathfinder_geometry::basic::rect::RectI32;
use pathfinder_geometry::basic::transform3d::Transform3DF32;
use pathfinder_geometry::color::ColorF;
use pathfinder_gpu::resources::ResourceLoader;
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, DepthFunc};
use pathfinder_gpu::{DepthState, Device, Primitive, RenderState, StencilFunc, StencilState};
use pathfinder_gpu::{TextureFormat, UniformData, VertexAttrType};
use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, ClearParams};
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, StencilFunc};
use pathfinder_gpu::{StencilState, TextureFormat, UniformData, VertexAttrType};
use pathfinder_simd::default::{F32x4, I32x4};
use std::cmp;
use std::collections::VecDeque;
use std::mem;
use std::ops::{Add, Div};
use std::time::Duration;
use std::u32;
@ -75,6 +77,10 @@ pub struct Renderer<D> where D: Device {
stencil_program: StencilProgram<D>,
stencil_vertex_array: StencilVertexArray<D>,
// Reprojection shader
reprojection_program: ReprojectionProgram<D>,
reprojection_vertex_array: ReprojectionVertexArray<D>,
// Rendering state
mask_framebuffer_cleared: bool,
buffered_fills: Vec<FillBatchPrimitive>,
@ -103,6 +109,7 @@ impl<D> Renderer<D> where D: Device {
let postprocess_program = PostprocessProgram::new(&device, resources);
let stencil_program = StencilProgram::new(&device, resources);
let reprojection_program = ReprojectionProgram::new(&device, resources);
let area_lut_texture = device.create_texture_from_png(resources, "area-lut");
let gamma_lut_texture = device.create_texture_from_png(resources, "gamma-lut");
@ -136,6 +143,10 @@ impl<D> Renderer<D> where D: Device {
&postprocess_program,
&quad_vertex_positions_buffer);
let stencil_vertex_array = StencilVertexArray::new(&device, &stencil_program);
let reprojection_vertex_array =
ReprojectionVertexArray::new(&device,
&reprojection_program,
&quad_vertex_positions_buffer);
let mask_framebuffer_size = Point2DI32::new(MASK_FRAMEBUFFER_WIDTH,
MASK_FRAMEBUFFER_HEIGHT);
@ -176,6 +187,9 @@ impl<D> Renderer<D> where D: Device {
stencil_program,
stencil_vertex_array,
reprojection_program,
reprojection_vertex_array,
stats: RenderStats::default(),
current_timer_query: None,
pending_timer_queries: VecDeque::new(),
@ -240,7 +254,7 @@ impl<D> Renderer<D> where D: Device {
}
pub fn draw_debug_ui(&self) {
self.bind_main_framebuffer();
self.bind_dest_framebuffer();
self.debug_ui.draw(&self.device);
}
@ -256,8 +270,14 @@ impl<D> Renderer<D> where D: Device {
}
#[inline]
pub fn set_dest_framebuffer(&mut self, new_dest_framebuffer: DestFramebuffer<D>) {
self.dest_framebuffer = new_dest_framebuffer;
pub fn dest_framebuffer(&self) -> &DestFramebuffer<D> {
&self.dest_framebuffer
}
#[inline]
pub fn replace_dest_framebuffer(&mut self, new_dest_framebuffer: DestFramebuffer<D>)
-> DestFramebuffer<D> {
mem::replace(&mut self.dest_framebuffer, new_dest_framebuffer)
}
#[inline]
@ -315,7 +335,10 @@ impl<D> Renderer<D> where D: Device {
self.device.bind_framebuffer(&self.mask_framebuffer);
// TODO(pcwalton): Only clear the appropriate portion?
self.device.clear(Some(F32x4::splat(0.0)), None, None);
self.device.clear(&ClearParams {
color: Some(ColorF::transparent_black()),
..ClearParams::default()
});
}
fn add_fills(&mut self, mut fills: &[FillBatchPrimitive]) {
@ -504,7 +527,7 @@ impl<D> Renderer<D> where D: Device {
}
}
self.bind_main_framebuffer();
self.bind_dest_framebuffer();
self.device.bind_vertex_array(&self.postprocess_vertex_array.vertex_array);
self.device.use_program(&self.postprocess_program.program);
@ -596,15 +619,37 @@ impl<D> Renderer<D> where D: Device {
})
}
fn bind_draw_framebuffer(&self) {
pub fn reproject_texture(&self,
texture: &D::Texture,
old_transform: &Transform3DF32,
new_transform: &Transform3DF32) {
self.bind_draw_framebuffer();
self.device.bind_vertex_array(&self.reprojection_vertex_array.vertex_array);
self.device.use_program(&self.reprojection_program.program);
self.device.set_uniform(&self.reprojection_program.old_transform_uniform,
UniformData::from_transform_3d(old_transform));
self.device.set_uniform(&self.reprojection_program.new_transform_uniform,
UniformData::from_transform_3d(new_transform));
self.device.bind_texture(texture, 0);
self.device.set_uniform(&self.reprojection_program.texture_uniform,
UniformData::TextureUnit(0));
self.device.draw_arrays(Primitive::TriangleFan, 4, &RenderState {
blend: BlendState::RGBSrcAlphaAlphaOneMinusSrcAlpha,
depth: Some(DepthState { func: DepthFunc::Less, write: false }),
..RenderState::default()
});
}
pub fn bind_draw_framebuffer(&self) {
if self.postprocessing_needed() {
self.device.bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap());
} else {
self.bind_main_framebuffer();
self.bind_dest_framebuffer();
}
}
fn bind_main_framebuffer(&self) {
pub fn bind_dest_framebuffer(&self) {
match self.dest_framebuffer {
DestFramebuffer::Default { viewport, .. } => {
self.device.bind_default_framebuffer(viewport)
@ -634,7 +679,10 @@ impl<D> Renderer<D> where D: Device {
};
self.device.bind_framebuffer(self.postprocess_source_framebuffer.as_ref().unwrap());
self.device.clear(Some(F32x4::default()), None, None);
self.device.clear(&ClearParams {
color: Some(ColorF::transparent_black()),
..ClearParams::default()
});
}
fn postprocessing_needed(&self) -> bool {
@ -1099,6 +1147,51 @@ impl<D> StencilVertexArray<D> where D: Device {
}
}
struct ReprojectionProgram<D> where D: Device {
program: D::Program,
old_transform_uniform: D::Uniform,
new_transform_uniform: D::Uniform,
texture_uniform: D::Uniform,
}
impl<D> ReprojectionProgram<D> where D: Device {
fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram<D> {
let program = device.create_program(resources, "reproject");
let old_transform_uniform = device.get_uniform(&program, "OldTransform");
let new_transform_uniform = device.get_uniform(&program, "NewTransform");
let texture_uniform = device.get_uniform(&program, "Texture");
ReprojectionProgram {
program,
old_transform_uniform,
new_transform_uniform,
texture_uniform,
}
}
}
struct ReprojectionVertexArray<D> where D: Device {
vertex_array: D::VertexArray,
}
impl<D> ReprojectionVertexArray<D> where D: Device {
fn new(device: &D,
reprojection_program: &ReprojectionProgram<D>,
quad_vertex_positions_buffer: &D::Buffer)
-> ReprojectionVertexArray<D> {
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position");
device.bind_vertex_array(&vertex_array);
device.use_program(&reprojection_program.program);
device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_float_vertex_attr(&position_attr, 2, VertexAttrType::U8, false, 0, 0, 0);
ReprojectionVertexArray { vertex_array }
}
}
#[derive(Clone)]
pub enum DestFramebuffer<D> where D: Device {
Default { viewport: RectI32, window_size: Point2DI32 },

View File

@ -83,11 +83,6 @@ impl Scene {
outline.clip_against_polygon(clip_polygon);
outline.apply_perspective(perspective);
// TODO(pcwalton): Support this in 2D too.
if let Some(barrel_distortion) = options.barrel_distortion {
outline.barrel_distort(barrel_distortion, perspective.window_size);
}
// TODO(pcwalton): Support subpixel AA in 3D.
}
}

View File

@ -1,6 +1,6 @@
#version {{version}}
// pathfinder/demo/shaders/debug_texture.fs.glsl
// pathfinder/resources/shaders/debug_texture.fs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//

View File

@ -1,6 +1,6 @@
#version {{version}}
// pathfinder/demo/shaders/post.vs.glsl
// pathfinder/resources/shaders/post.vs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//

View File

@ -0,0 +1,26 @@
#version {{version}}
// pathfinder/resources/shaders/reproject.fs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
uniform mat4 uOldTransform;
uniform sampler2D uTexture;
in vec2 vTexCoord;
out vec4 oFragColor;
void main() {
vec4 normTexCoord = uOldTransform * vec4(vTexCoord, 0.0, 1.0);
vec2 texCoord = ((normTexCoord.xy / normTexCoord.w) + 1.0) * 0.5;
oFragColor = texture(uTexture, texCoord);
}

View File

@ -0,0 +1,24 @@
#version {{version}}
// pathfinder/resources/shaders/reproject.vs.glsl
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
precision highp float;
uniform mat4 uNewTransform;
in vec2 aPosition;
out vec2 vTexCoord;
void main() {
vTexCoord = aPosition;
gl_Position = uNewTransform * vec4(aPosition, 0.0, 1.0);
}