Merge pull request #350 from pcwalton/gpu-tiling-dicing
Add a rendering path for Direct3D 11-class hardware that uses compute shader for most stages.
This commit is contained in:
commit
3dc70e0111
|
@ -142,6 +142,11 @@ name = "base64"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
@ -172,6 +177,11 @@ name = "bumpalo"
|
||||||
version = "3.2.1"
|
version = "3.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-slice-cast"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -465,7 +475,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pathfinder_export 0.1.0",
|
"pathfinder_export 0.1.0",
|
||||||
"pathfinder_svg 0.5.0",
|
"pathfinder_svg 0.5.0",
|
||||||
"usvg 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1242,7 +1252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kurbo"
|
name = "kurbo"
|
||||||
version = "0.5.11"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1748,7 +1758,7 @@ dependencies = [
|
||||||
"pathfinder_svg 0.5.0",
|
"pathfinder_svg 0.5.0",
|
||||||
"pathfinder_ui 0.5.0",
|
"pathfinder_ui 0.5.0",
|
||||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"usvg 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1788,8 +1798,10 @@ name = "pathfinder_gpu"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pathfinder_color 0.5.0",
|
"pathfinder_color 0.5.0",
|
||||||
"pathfinder_geometry 0.5.1",
|
"pathfinder_geometry 0.5.1",
|
||||||
"pathfinder_resources 0.5.0",
|
"pathfinder_resources 0.5.0",
|
||||||
|
@ -1825,7 +1837,7 @@ dependencies = [
|
||||||
"pathfinder_ui 0.5.0",
|
"pathfinder_ui 0.5.0",
|
||||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"usvg 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1837,6 +1849,7 @@ dependencies = [
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dispatch 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"io-surface 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"io-surface 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1854,6 +1867,7 @@ name = "pathfinder_renderer"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"byte-slice-cast 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1898,7 +1912,7 @@ dependencies = [
|
||||||
"pathfinder_geometry 0.5.1",
|
"pathfinder_geometry 0.5.1",
|
||||||
"pathfinder_renderer 0.5.0",
|
"pathfinder_renderer 0.5.0",
|
||||||
"pathfinder_simd 0.5.0",
|
"pathfinder_simd 0.5.0",
|
||||||
"usvg 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2163,7 +2177,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roxmltree"
|
name = "roxmltree"
|
||||||
version = "0.9.1"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"xmlparser 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xmlparser 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -2481,7 +2495,7 @@ dependencies = [
|
||||||
name = "svg-to-skia"
|
name = "svg-to-skia"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"usvg 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2614,7 +2628,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttf-parser"
|
name = "ttf-parser"
|
||||||
version = "0.3.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2668,22 +2682,22 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usvg"
|
name = "usvg"
|
||||||
version = "0.9.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base64 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"data-url 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"harfbuzz_rs 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"harfbuzz_rs 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"kurbo 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kurbo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memmap2 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memmap2 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rctree 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rctree 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"roxmltree 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"roxmltree 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"simplecss 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"simplecss 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"svgtypes 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"svgtypes 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ttf-parser 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ttf-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-script 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-script 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-vo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3059,11 +3073,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
"checksum backtrace 0.3.46 (registry+https://github.com/rust-lang/crates.io-index)" = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
||||||
"checksum backtrace-sys 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
|
"checksum backtrace-sys 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
|
||||||
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||||
|
"checksum base64 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||||
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
||||||
"checksum bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
|
"checksum bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
|
||||||
|
"checksum byte-slice-cast 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3"
|
||||||
"checksum bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431"
|
"checksum bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431"
|
||||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
"checksum calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160"
|
"checksum calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160"
|
||||||
|
@ -3166,7 +3182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum khronos 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c0711aaa80e6ba6eb1fa8978f1f46bfcb38ceb2f3f33f3736efbff39dac89f50"
|
"checksum khronos 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c0711aaa80e6ba6eb1fa8978f1f46bfcb38ceb2f3f33f3736efbff39dac89f50"
|
||||||
"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||||
"checksum kurbo 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bf50e17a1697110c694d47c5b1a6b64faf5eb3ffe5a286df23fb8cd516e33be6"
|
"checksum kurbo 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2520c9c9010461ec2b4573599bca458272319a314fd0b9476cacfcb9b6e5adc8"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||||
"checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73"
|
"checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73"
|
||||||
|
@ -3239,7 +3255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
||||||
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||||
"checksum roxmltree 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "99d696b20b92d3e02e08fd8456f0ab03007c99e6b111a6205b9cb6fc044d0957"
|
"checksum roxmltree 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5001f134077069d87f77c8b9452b690df2445f7a43f1c7ca4a1af8dd505789d"
|
||||||
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
@ -3287,7 +3303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum tiff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "002351e428db1eb1d8656d4ca61947c3519ac3191e1c804d4600cd32093b77ad"
|
"checksum tiff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "002351e428db1eb1d8656d4ca61947c3519ac3191e1c804d4600cd32093b77ad"
|
||||||
"checksum time-point 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06535c958d6abe68dc4b4ef9e6845f758fc42fe463d0093d0aca40254f03fb14"
|
"checksum time-point 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06535c958d6abe68dc4b4ef9e6845f758fc42fe463d0093d0aca40254f03fb14"
|
||||||
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||||
"checksum ttf-parser 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a67a691cd15aae8f55fcc6e68efec96ec9e6e3ad967ac16f18681e2268c92037"
|
"checksum ttf-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52fbe7769f5af5d7d25aea74b9443b64e544a5ffb4d2b2968295ddea934f1a06"
|
||||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||||
"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
||||||
"checksum unicode-script 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc3ca3febe3d301fa4ff250e63a11d9da58390c3f079c736fc6602bcd36449d2"
|
"checksum unicode-script 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc3ca3febe3d301fa4ff250e63a11d9da58390c3f079c736fc6602bcd36449d2"
|
||||||
|
@ -3296,7 +3312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||||
"checksum usvg 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4725473a52c4ebc949d3141d39c97b5131a575a96bea4912ccd5b03a720d7a1b"
|
"checksum usvg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5d98fe4bbd8cfe811fb84dabebd670d26b1e633ecb4d3a4ef3a4b8c10252448d"
|
||||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
63
c/src/lib.rs
63
c/src/lib.rs
|
@ -23,11 +23,13 @@ use pathfinder_geometry::transform2d::{Matrix2x2F, Transform2F};
|
||||||
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
use pathfinder_geometry::transform3d::{Perspective, Transform4F};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
|
||||||
|
use pathfinder_renderer::gpu::options::{RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
|
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
|
@ -39,7 +41,7 @@ use std::slice;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
use metal::{CAMetalLayer, CoreAnimationLayerRef, Device};
|
use metal::{self, CAMetalLayer, CoreAnimationLayerRef};
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
use pathfinder_metal::MetalDevice;
|
use pathfinder_metal::MetalDevice;
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
|
@ -74,6 +76,10 @@ pub const PF_GL_VERSION_GLES3: u8 = 1;
|
||||||
// `renderer`
|
// `renderer`
|
||||||
|
|
||||||
pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1;
|
pub const PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR: u8 = 0x1;
|
||||||
|
pub const PF_RENDERER_OPTIONS_FLAGS_SHOW_DEBUG_UI: u8 = 0x2;
|
||||||
|
|
||||||
|
pub const PF_RENDERER_LEVEL_D3D9: u8 = 0x1;
|
||||||
|
pub const PF_RENDERER_LEVEL_D3D11: u8 = 0x2;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
|
@ -182,13 +188,20 @@ pub type PFMetalDeviceRef = *mut MetalDevice;
|
||||||
pub type PFSceneRef = *mut Scene;
|
pub type PFSceneRef = *mut Scene;
|
||||||
pub type PFSceneProxyRef = *mut SceneProxy;
|
pub type PFSceneProxyRef = *mut SceneProxy;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
pub struct PFRendererMode {
|
||||||
|
pub level: PFRendererLevel,
|
||||||
|
}
|
||||||
|
pub type PFDestFramebufferRef = *mut c_void;
|
||||||
|
#[repr(C)]
|
||||||
pub struct PFRendererOptions {
|
pub struct PFRendererOptions {
|
||||||
|
pub dest: PFDestFramebufferRef,
|
||||||
pub background_color: PFColorF,
|
pub background_color: PFColorF,
|
||||||
pub flags: PFRendererOptionsFlags,
|
pub flags: PFRendererOptionsFlags,
|
||||||
}
|
}
|
||||||
pub type PFRendererOptionsFlags = u8;
|
pub type PFRendererOptionsFlags = u8;
|
||||||
pub type PFBuildOptionsRef = *mut BuildOptions;
|
pub type PFBuildOptionsRef = *mut BuildOptions;
|
||||||
pub type PFRenderTransformRef = *mut RenderTransform;
|
pub type PFRenderTransformRef = *mut RenderTransform;
|
||||||
|
pub type PFRendererLevel = u8;
|
||||||
|
|
||||||
// `canvas`
|
// `canvas`
|
||||||
|
|
||||||
|
@ -541,12 +554,12 @@ pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFr
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
|
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
|
||||||
resources: PFResourceLoaderRef,
|
resources: PFResourceLoaderRef,
|
||||||
dest_framebuffer: PFGLDestFramebufferRef,
|
mode: *const PFRendererMode,
|
||||||
options: *const PFRendererOptions)
|
options: *const PFRendererOptions)
|
||||||
-> PFGLRendererRef {
|
-> PFGLRendererRef {
|
||||||
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
||||||
&*((*resources).0),
|
&*((*resources).0),
|
||||||
*Box::from_raw(dest_framebuffer),
|
(*mode).to_rust(),
|
||||||
(*options).to_rust())))
|
(*options).to_rust())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +570,7 @@ pub unsafe extern "C" fn PFGLRendererDestroy(renderer: PFGLRendererRef) {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFGLDeviceRef {
|
pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFGLDeviceRef {
|
||||||
&mut (*renderer).device
|
(*renderer).device_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
|
||||||
|
@ -581,12 +594,12 @@ pub unsafe extern "C" fn PFMetalDestFramebufferDestroy(dest_framebuffer:
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
|
pub unsafe extern "C" fn PFMetalRendererCreate(device: PFMetalDeviceRef,
|
||||||
resources: PFResourceLoaderRef,
|
resources: PFResourceLoaderRef,
|
||||||
dest_framebuffer: PFMetalDestFramebufferRef,
|
mode: *const PFRendererMode,
|
||||||
options: *const PFRendererOptions)
|
options: *const PFRendererOptions)
|
||||||
-> PFMetalRendererRef {
|
-> PFMetalRendererRef {
|
||||||
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
|
||||||
&*((*resources).0),
|
&*((*resources).0),
|
||||||
*Box::from_raw(dest_framebuffer),
|
(*mode).to_rust(),
|
||||||
(*options).to_rust())))
|
(*options).to_rust())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,7 +616,7 @@ pub unsafe extern "C" fn PFMetalRendererDestroy(renderer: PFMetalRendererRef) {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef)
|
pub unsafe extern "C" fn PFMetalRendererGetDevice(renderer: PFMetalRendererRef)
|
||||||
-> PFMetalDeviceRef {
|
-> PFMetalDeviceRef {
|
||||||
&mut (*renderer).device
|
(*renderer).device_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function does not take ownership of `renderer` or `build_options`. Therefore, if you
|
/// This function does not take ownership of `renderer` or `build_options`. Therefore, if you
|
||||||
|
@ -631,7 +644,8 @@ pub unsafe extern "C" fn PFSceneProxyBuildAndRenderMetal(scene_proxy: PFScenePro
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFMetalDeviceCreate(layer: *mut CAMetalLayer)
|
pub unsafe extern "C" fn PFMetalDeviceCreate(layer: *mut CAMetalLayer)
|
||||||
-> PFMetalDeviceRef {
|
-> PFMetalDeviceRef {
|
||||||
let device = Device::system_default().expect("Failed to get Metal system default device!");
|
let device =
|
||||||
|
metal::Device::system_default().expect("Failed to get Metal system default device!");
|
||||||
let layer = CoreAnimationLayerRef::from_ptr(layer);
|
let layer = CoreAnimationLayerRef::from_ptr(layer);
|
||||||
Box::into_raw(Box::new(MetalDevice::new(device, layer.next_drawable().unwrap())))
|
Box::into_raw(Box::new(MetalDevice::new(device, layer.next_drawable().unwrap())))
|
||||||
}
|
}
|
||||||
|
@ -696,9 +710,12 @@ pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef)
|
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef,
|
||||||
|
level: PFRendererLevel)
|
||||||
-> PFSceneProxyRef {
|
-> PFSceneProxyRef {
|
||||||
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene), RayonExecutor)))
|
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene),
|
||||||
|
to_rust_renderer_level(level),
|
||||||
|
RayonExecutor)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -807,17 +824,35 @@ impl PFPerspective {
|
||||||
|
|
||||||
// Helpers for `renderer`
|
// Helpers for `renderer`
|
||||||
|
|
||||||
|
impl PFRendererMode {
|
||||||
|
pub fn to_rust(&self) -> RendererMode {
|
||||||
|
RendererMode {
|
||||||
|
level: to_rust_renderer_level(self.level),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PFRendererOptions {
|
impl PFRendererOptions {
|
||||||
pub fn to_rust(&self) -> RendererOptions {
|
pub fn to_rust<D>(&self) -> RendererOptions<D> where D: Device {
|
||||||
let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR;
|
let has_background_color = self.flags & PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR;
|
||||||
|
let show_debug_ui = (self.flags & PF_RENDERER_OPTIONS_FLAGS_SHOW_DEBUG_UI) != 0;
|
||||||
|
unsafe {
|
||||||
RendererOptions {
|
RendererOptions {
|
||||||
background_color: if has_background_color != 0 {
|
background_color: if has_background_color != 0 {
|
||||||
Some(self.background_color.to_rust())
|
Some(self.background_color.to_rust())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
// TODO(pcwalton): Expose this in the C API.
|
dest: *Box::from_raw(self.dest as *mut DestFramebuffer<D>),
|
||||||
no_compute: false,
|
show_debug_ui,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_rust_renderer_level(level: PFRendererLevel) -> RendererLevel {
|
||||||
|
match level {
|
||||||
|
PF_RENDERER_LEVEL_D3D9 => RendererLevel::D3D9,
|
||||||
|
_ => RendererLevel::D3D11,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let mut path = DrawPath::new(outline, paint_id);
|
let mut path = DrawPath::new(outline, paint_id);
|
||||||
path.set_blend_mode(BlendMode::Clear);
|
path.set_blend_mode(BlendMode::Clear);
|
||||||
self.canvas.scene.push_path(path);
|
self.canvas.scene.push_draw_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line styles
|
// Line styles
|
||||||
|
@ -345,7 +345,7 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
path.set_fill_rule(fill_rule);
|
path.set_fill_rule(fill_rule);
|
||||||
path.set_blend_mode(blend_mode);
|
path.set_blend_mode(blend_mode);
|
||||||
self.canvas.scene.push_path(path);
|
self.canvas.scene.push_draw_path(path);
|
||||||
|
|
||||||
composite_shadow_blur_render_targets_if_needed(&mut self.canvas.scene,
|
composite_shadow_blur_render_targets_if_needed(&mut self.canvas.scene,
|
||||||
shadow_blur_info,
|
shadow_blur_info,
|
||||||
|
@ -356,7 +356,7 @@ impl CanvasRenderingContext2D {
|
||||||
path.set_clip_path(clip_path);
|
path.set_clip_path(clip_path);
|
||||||
path.set_fill_rule(fill_rule);
|
path.set_fill_rule(fill_rule);
|
||||||
path.set_blend_mode(blend_mode);
|
path.set_blend_mode(blend_mode);
|
||||||
self.canvas.scene.push_path(path);
|
self.canvas.scene.push_draw_path(path);
|
||||||
|
|
||||||
fn push_shadow_blur_render_targets_if_needed(scene: &mut Scene,
|
fn push_shadow_blur_render_targets_if_needed(scene: &mut Scene,
|
||||||
current_state: &State,
|
current_state: &State,
|
||||||
|
@ -410,9 +410,9 @@ impl CanvasRenderingContext2D {
|
||||||
path_y.set_clip_path(clip_path);
|
path_y.set_clip_path(clip_path);
|
||||||
|
|
||||||
scene.pop_render_target();
|
scene.pop_render_target();
|
||||||
scene.push_path(path_x);
|
scene.push_draw_path(path_x);
|
||||||
scene.pop_render_target();
|
scene.pop_render_target();
|
||||||
scene.push_path(path_y);
|
scene.push_draw_path(path_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -333,6 +333,11 @@ impl Contour {
|
||||||
self.points[self.points.len() - index as usize]
|
self.points[self.points.len() - index as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn flags_of(&self, index: u32) -> PointFlags {
|
||||||
|
self.flags[index as usize]
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn push_endpoint(&mut self, point: Vector2F) {
|
pub fn push_endpoint(&mut self, point: Vector2F) {
|
||||||
self.push_point(point, PointFlags::empty(), true);
|
self.push_point(point, PointFlags::empty(), true);
|
||||||
|
|
|
@ -12,13 +12,11 @@
|
||||||
|
|
||||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::util::{self, EPSILON};
|
use pathfinder_geometry::util::EPSILON;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::f32::consts::SQRT_2;
|
use std::f32::consts::SQRT_2;
|
||||||
|
|
||||||
const MAX_NEWTON_ITERATIONS: u32 = 32;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Segment {
|
pub struct Segment {
|
||||||
pub baseline: LineSegment2F,
|
pub baseline: LineSegment2F,
|
||||||
|
@ -155,16 +153,6 @@ impl Segment {
|
||||||
new_segment
|
new_segment
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_monotonic(&self) -> bool {
|
|
||||||
// FIXME(pcwalton): Don't degree elevate!
|
|
||||||
match self.kind {
|
|
||||||
SegmentKind::None | SegmentKind::Line => true,
|
|
||||||
SegmentKind::Quadratic => self.to_cubic().as_cubic_segment().is_monotonic(),
|
|
||||||
SegmentKind::Cubic => self.as_cubic_segment().is_monotonic(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reversed(&self) -> Segment {
|
pub fn reversed(&self) -> Segment {
|
||||||
Segment {
|
Segment {
|
||||||
|
@ -341,72 +329,6 @@ impl<'s> CubicSegment<'s> {
|
||||||
self.split(t).0.baseline.to()
|
self.split(t).0.baseline.to()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_monotonic(self) -> bool {
|
|
||||||
// TODO(pcwalton): Optimize this.
|
|
||||||
let (p0, p3) = (self.0.baseline.from_y(), self.0.baseline.to_y());
|
|
||||||
let (p1, p2) = (self.0.ctrl.from_y(), self.0.ctrl.to_y());
|
|
||||||
(p0 <= p1 && p1 <= p2 && p2 <= p3) || (p0 >= p1 && p1 >= p2 && p2 >= p3)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn y_extrema(self) -> (Option<f32>, Option<f32>) {
|
|
||||||
if self.is_monotonic() {
|
|
||||||
return (None, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let p0p1p2p3 = F32x4::new(
|
|
||||||
self.0.baseline.from_y(),
|
|
||||||
self.0.ctrl.from_y(),
|
|
||||||
self.0.ctrl.to_y(),
|
|
||||||
self.0.baseline.to_y(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let pxp0p1p2 = p0p1p2p3.wxyz();
|
|
||||||
let pxv0v1v2 = p0p1p2p3 - pxp0p1p2;
|
|
||||||
let (v0, v1, v2) = (pxv0v1v2[1], pxv0v1v2[2], pxv0v1v2[3]);
|
|
||||||
|
|
||||||
let (t0, t1);
|
|
||||||
let (v0_to_v1, v2_to_v1) = (v0 - v1, v2 - v1);
|
|
||||||
let denom = v0_to_v1 + v2_to_v1;
|
|
||||||
|
|
||||||
if util::approx_eq(denom, 0.0) {
|
|
||||||
// Let's not divide by zero (issue #146). Fall back to Newton's method.
|
|
||||||
// FIXME(pcwalton): Can we have two roots here?
|
|
||||||
let mut t = 0.5;
|
|
||||||
for _ in 0..MAX_NEWTON_ITERATIONS {
|
|
||||||
let dydt = 3.0 * ((denom * t - v0_to_v1 - v0_to_v1) * t + v0);
|
|
||||||
if f32::abs(dydt) <= EPSILON {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
let d2ydt2 = 6.0 * (denom * t - v0_to_v1);
|
|
||||||
t -= dydt / d2ydt2;
|
|
||||||
}
|
|
||||||
t0 = t;
|
|
||||||
t1 = 0.0;
|
|
||||||
debug!("... t=(newton) {}", t);
|
|
||||||
} else {
|
|
||||||
// Algebraically compute the values for t.
|
|
||||||
let discrim = f32::sqrt(v1 * v1 - v0 * v2);
|
|
||||||
let denom_recip = 1.0 / denom;
|
|
||||||
|
|
||||||
t0 = (v0_to_v1 + discrim) * denom_recip;
|
|
||||||
t1 = (v0_to_v1 - discrim) * denom_recip;
|
|
||||||
|
|
||||||
debug!("... t=({} +/- {})/{} t0={} t1={}", v0_to_v1, discrim, denom, t0, t1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return match (
|
|
||||||
t0 > EPSILON && t0 < 1.0 - EPSILON,
|
|
||||||
t1 > EPSILON && t1 < 1.0 - EPSILON,
|
|
||||||
) {
|
|
||||||
(false, false) => (None, None),
|
|
||||||
(true, false) => (Some(t0), None),
|
|
||||||
(false, true) => (Some(t1), None),
|
|
||||||
(true, true) => (Some(f32::min(t0, t1)), Some(f32::max(t0, t1))),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn min_x(&self) -> f32 {
|
pub fn min_x(&self) -> f32 {
|
||||||
f32::min(self.0.baseline.min_x(), self.0.ctrl.min_x())
|
f32::min(self.0.baseline.min_x(), self.0.ctrl.min_x())
|
||||||
|
|
|
@ -34,9 +34,10 @@ use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::Transform4F;
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::{RenderCommandStream, SceneProxy};
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
|
||||||
use pathfinder_renderer::gpu::renderer::{RenderStats, RenderTime, Renderer};
|
use pathfinder_renderer::gpu::options::{RendererMode, RendererOptions};
|
||||||
|
use pathfinder_renderer::gpu::renderer::{DebugUIPresenterInfo, Renderer};
|
||||||
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
|
use pathfinder_renderer::options::{BuildOptions, RenderTransform};
|
||||||
use pathfinder_renderer::paint::Paint;
|
use pathfinder_renderer::paint::Paint;
|
||||||
use pathfinder_renderer::scene::{DrawPath, RenderTarget, Scene};
|
use pathfinder_renderer::scene::{DrawPath, RenderTarget, Scene};
|
||||||
|
@ -90,7 +91,6 @@ pub struct DemoApp<W> where W: Window {
|
||||||
svg_tree: Tree,
|
svg_tree: Tree,
|
||||||
scene_metadata: SceneMetadata,
|
scene_metadata: SceneMetadata,
|
||||||
render_transform: Option<RenderTransform>,
|
render_transform: Option<RenderTransform>,
|
||||||
render_command_stream: Option<RenderCommandStream>,
|
|
||||||
|
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
frame_counter: u32,
|
frame_counter: u32,
|
||||||
|
@ -135,14 +135,25 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let executor = DemoExecutor::new(options.jobs);
|
let executor = DemoExecutor::new(options.jobs);
|
||||||
|
|
||||||
let mut ui_model = DemoUIModel::new(&options);
|
let mut ui_model = DemoUIModel::new(&options);
|
||||||
|
|
||||||
|
let level = match options.renderer_level {
|
||||||
|
Some(level) => level,
|
||||||
|
None => RendererLevel::default_for_device(&device),
|
||||||
|
};
|
||||||
|
let viewport = window.viewport(options.mode.view(0));
|
||||||
|
let dest_framebuffer = DestFramebuffer::Default {
|
||||||
|
viewport,
|
||||||
|
window_size: window_size.device_size(),
|
||||||
|
};
|
||||||
|
let render_mode = RendererMode { level };
|
||||||
let render_options = RendererOptions {
|
let render_options = RendererOptions {
|
||||||
|
dest: dest_framebuffer,
|
||||||
background_color: None,
|
background_color: None,
|
||||||
no_compute: options.no_compute,
|
show_debug_ui: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let filter = build_filter(&ui_model);
|
let filter = build_filter(&ui_model);
|
||||||
|
|
||||||
let viewport = window.viewport(options.mode.view(0));
|
|
||||||
let (mut built_svg, svg_tree) = load_scene(resources,
|
let (mut built_svg, svg_tree) = load_scene(resources,
|
||||||
&options.input_path,
|
&options.input_path,
|
||||||
viewport.size(),
|
viewport.size(),
|
||||||
|
@ -150,21 +161,16 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
|
|
||||||
let message = get_svg_building_message(&built_svg);
|
let message = get_svg_building_message(&built_svg);
|
||||||
|
|
||||||
let dest_framebuffer = DestFramebuffer::Default {
|
let renderer = Renderer::new(device, resources, render_mode, render_options);
|
||||||
viewport,
|
|
||||||
window_size: window_size.device_size(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let renderer = Renderer::new(device, resources, dest_framebuffer, render_options);
|
|
||||||
|
|
||||||
let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene,
|
let scene_metadata = SceneMetadata::new_clipping_view_box(&mut built_svg.scene,
|
||||||
viewport.size());
|
viewport.size());
|
||||||
let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size());
|
let camera = Camera::new(options.mode, scene_metadata.view_box, viewport.size());
|
||||||
|
|
||||||
let scene_proxy = SceneProxy::from_scene(built_svg.scene, executor);
|
let scene_proxy = SceneProxy::from_scene(built_svg.scene, level, executor);
|
||||||
|
|
||||||
let ground_program = GroundProgram::new(&renderer.device, resources);
|
let ground_program = GroundProgram::new(renderer.device(), resources);
|
||||||
let ground_vertex_array = GroundVertexArray::new(&renderer.device,
|
let ground_vertex_array = GroundVertexArray::new(renderer.device(),
|
||||||
&ground_program,
|
&ground_program,
|
||||||
&renderer.quad_vertex_positions_buffer(),
|
&renderer.quad_vertex_positions_buffer(),
|
||||||
&renderer.quad_vertex_indices_buffer());
|
&renderer.quad_vertex_indices_buffer());
|
||||||
|
@ -177,7 +183,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
message,
|
message,
|
||||||
);
|
);
|
||||||
|
|
||||||
let ui_presenter = DemoUIPresenter::new(&renderer.device, resources);
|
let ui_presenter = DemoUIPresenter::new(renderer.device(), resources);
|
||||||
|
|
||||||
DemoApp {
|
DemoApp {
|
||||||
window,
|
window,
|
||||||
|
@ -189,7 +195,6 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
svg_tree,
|
svg_tree,
|
||||||
scene_metadata,
|
scene_metadata,
|
||||||
render_transform: None,
|
render_transform: None,
|
||||||
render_command_stream: None,
|
|
||||||
|
|
||||||
camera,
|
camera,
|
||||||
frame_counter: 0,
|
frame_counter: 0,
|
||||||
|
@ -265,7 +270,11 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled,
|
subpixel_aa_enabled: self.ui_model.subpixel_aa_effect_enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.render_command_stream = Some(self.scene_proxy.build_with_stream(build_options));
|
self.scene_proxy.build(build_options);
|
||||||
|
/*
|
||||||
|
self.render_command_stream =
|
||||||
|
Some(self.scene_proxy.build_with_stream(build_options, self.renderer.gpu_features()));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_events(&mut self, events: Vec<Event>) -> Vec<UIEvent> {
|
fn handle_events(&mut self, events: Vec<Event>) -> Vec<UIEvent> {
|
||||||
|
@ -469,57 +478,41 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
|
|
||||||
pub fn finish_drawing_frame(&mut self) {
|
pub fn finish_drawing_frame(&mut self) {
|
||||||
self.maybe_take_screenshot();
|
self.maybe_take_screenshot();
|
||||||
self.update_stats();
|
|
||||||
self.draw_debug_ui();
|
|
||||||
|
|
||||||
let frame = self.current_frame.take().unwrap();
|
let frame = self.current_frame.take().unwrap();
|
||||||
for ui_event in &frame.ui_events {
|
for ui_event in &frame.ui_events {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
self.renderer.debug_ui_presenter.ui_presenter.event_queue.push(*ui_event);
|
self.renderer
|
||||||
|
.debug_ui_presenter_mut()
|
||||||
|
.debug_ui_presenter
|
||||||
|
.ui_presenter
|
||||||
|
.event_queue
|
||||||
|
.push(*ui_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.renderer.debug_ui_presenter.ui_presenter.mouse_position =
|
self.renderer.debug_ui_presenter_mut().debug_ui_presenter.ui_presenter.mouse_position =
|
||||||
self.last_mouse_position.to_f32() * self.window_size.backing_scale_factor;
|
self.last_mouse_position.to_f32() * self.window_size.backing_scale_factor;
|
||||||
|
|
||||||
let mut ui_action = UIAction::None;
|
let mut ui_action = UIAction::None;
|
||||||
if self.options.ui == UIVisibility::All {
|
if self.options.ui == UIVisibility::All {
|
||||||
self.ui_presenter.update(
|
let DebugUIPresenterInfo { device, allocator, debug_ui_presenter } =
|
||||||
&self.renderer.device,
|
self.renderer.debug_ui_presenter_mut();
|
||||||
|
self.ui_presenter.update(device,
|
||||||
|
allocator,
|
||||||
&mut self.window,
|
&mut self.window,
|
||||||
&mut self.renderer.debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
&mut ui_action,
|
&mut ui_action,
|
||||||
&mut self.ui_model,
|
&mut self.ui_model);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handle_ui_events(frame, &mut ui_action);
|
self.handle_ui_events(frame, &mut ui_action);
|
||||||
|
|
||||||
self.renderer.device.end_commands();
|
self.renderer.device().end_commands();
|
||||||
|
|
||||||
self.window.present(&mut self.renderer.device);
|
self.window.present(self.renderer.device_mut());
|
||||||
self.frame_counter += 1;
|
self.frame_counter += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_stats(&mut self) {
|
|
||||||
let frame = self.current_frame.as_mut().unwrap();
|
|
||||||
if let Some(rendering_time) = self.renderer.shift_rendering_time() {
|
|
||||||
frame.scene_rendering_times.push(rendering_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
if frame.scene_stats.is_empty() && frame.scene_rendering_times.is_empty() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let zero = RenderStats::default();
|
|
||||||
let aggregate_stats = frame.scene_stats.iter().fold(zero, |sum, item| sum + *item);
|
|
||||||
if !frame.scene_rendering_times.is_empty() {
|
|
||||||
let total_rendering_time = frame.scene_rendering_times
|
|
||||||
.iter()
|
|
||||||
.fold(RenderTime::default(), |sum, item| sum + *item);
|
|
||||||
self.renderer.debug_ui_presenter.add_sample(aggregate_stats, total_rendering_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maybe_take_screenshot(&mut self) {
|
fn maybe_take_screenshot(&mut self) {
|
||||||
match self.pending_screenshot_info.take() {
|
match self.pending_screenshot_info.take() {
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -535,7 +528,12 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_ui_events(&mut self, mut frame: Frame, ui_action: &mut UIAction) {
|
fn handle_ui_events(&mut self, mut frame: Frame, ui_action: &mut UIAction) {
|
||||||
frame.ui_events = self.renderer.debug_ui_presenter.ui_presenter.event_queue.drain();
|
frame.ui_events = self.renderer
|
||||||
|
.debug_ui_presenter_mut()
|
||||||
|
.debug_ui_presenter
|
||||||
|
.ui_presenter
|
||||||
|
.event_queue
|
||||||
|
.drain();
|
||||||
|
|
||||||
self.handle_ui_action(ui_action);
|
self.handle_ui_action(ui_action);
|
||||||
|
|
||||||
|
@ -625,7 +623,7 @@ pub struct Options {
|
||||||
pub ui: UIVisibility,
|
pub ui: UIVisibility,
|
||||||
pub background_color: BackgroundColor,
|
pub background_color: BackgroundColor,
|
||||||
pub high_performance_gpu: bool,
|
pub high_performance_gpu: bool,
|
||||||
pub no_compute: bool,
|
pub renderer_level: Option<RendererLevel>,
|
||||||
hidden_field_for_future_proofing: (),
|
hidden_field_for_future_proofing: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,7 +636,7 @@ impl Default for Options {
|
||||||
ui: UIVisibility::All,
|
ui: UIVisibility::All,
|
||||||
background_color: BackgroundColor::Light,
|
background_color: BackgroundColor::Light,
|
||||||
high_performance_gpu: false,
|
high_performance_gpu: false,
|
||||||
no_compute: false,
|
renderer_level: None,
|
||||||
hidden_field_for_future_proofing: (),
|
hidden_field_for_future_proofing: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,7 +644,7 @@ impl Default for Options {
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
pub fn command_line_overrides(&mut self) {
|
pub fn command_line_overrides(&mut self) {
|
||||||
let matches = App::new("tile-svg")
|
let matches = App::new("demo")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("jobs")
|
Arg::with_name("jobs")
|
||||||
.short("j")
|
.short("j")
|
||||||
|
@ -692,10 +690,12 @@ impl Options {
|
||||||
.help("Use the high-performance (discrete) GPU, if available")
|
.help("Use the high-performance (discrete) GPU, if available")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("no-compute")
|
Arg::with_name("level")
|
||||||
.short("c")
|
.long("level")
|
||||||
.long("no-compute")
|
.short("l")
|
||||||
.help("Never use compute shaders")
|
.help("Set the renderer feature level as a Direct3D version equivalent")
|
||||||
|
.takes_value(true)
|
||||||
|
.possible_values(&["9", "11"])
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("INPUT")
|
Arg::with_name("INPUT")
|
||||||
|
@ -734,13 +734,17 @@ impl Options {
|
||||||
self.high_performance_gpu = true;
|
self.high_performance_gpu = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("no-compute") {
|
if let Some(renderer_level) = matches.value_of("level") {
|
||||||
self.no_compute = true;
|
if renderer_level == "11" {
|
||||||
|
self.renderer_level = Some(RendererLevel::D3D11);
|
||||||
|
} else if renderer_level == "9" {
|
||||||
|
self.renderer_level = Some(RendererLevel::D3D9);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = matches.value_of("INPUT") {
|
if let Some(path) = matches.value_of("INPUT") {
|
||||||
self.input_path = SVGPath::Path(PathBuf::from(path));
|
self.input_path = SVGPath::Path(PathBuf::from(path));
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -798,7 +802,7 @@ fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, filter: Option<PatternFi
|
||||||
let path = DrawPath::new(outline, paint_id);
|
let path = DrawPath::new(outline, paint_id);
|
||||||
|
|
||||||
built_svg.scene.pop_render_target();
|
built_svg.scene.pop_render_target();
|
||||||
built_svg.scene.push_path(path);
|
built_svg.scene.push_draw_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return built_svg;
|
return built_svg;
|
||||||
|
@ -848,18 +852,11 @@ fn emit_message<W>(
|
||||||
struct Frame {
|
struct Frame {
|
||||||
transform: RenderTransform,
|
transform: RenderTransform,
|
||||||
ui_events: Vec<UIEvent>,
|
ui_events: Vec<UIEvent>,
|
||||||
scene_rendering_times: Vec<RenderTime>,
|
|
||||||
scene_stats: Vec<RenderStats>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
fn new(transform: RenderTransform, ui_events: Vec<UIEvent>) -> Frame {
|
fn new(transform: RenderTransform, ui_events: Vec<UIEvent>) -> Frame {
|
||||||
Frame {
|
Frame { transform, ui_events }
|
||||||
transform,
|
|
||||||
ui_events,
|
|
||||||
scene_rendering_times: vec![],
|
|
||||||
scene_stats: vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
||||||
use pathfinder_renderer::options::RenderTransform;
|
use pathfinder_renderer::options::RenderTransform;
|
||||||
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
const GROUND_SOLID_COLOR: ColorU = ColorU {
|
const GROUND_SOLID_COLOR: ColorU = ColorU {
|
||||||
|
@ -46,59 +47,58 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let view = self.ui_model.mode.view(0);
|
let view = self.ui_model.mode.view(0);
|
||||||
self.window.make_current(view);
|
self.window.make_current(view);
|
||||||
|
|
||||||
// Set up framebuffers.
|
|
||||||
let window_size = self.window_size.device_size();
|
|
||||||
let mode = self.camera.mode();
|
|
||||||
let scene_count = match 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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear to the appropriate color.
|
// Clear to the appropriate color.
|
||||||
|
let mode = self.camera.mode();
|
||||||
let clear_color = match mode {
|
let clear_color = match mode {
|
||||||
Mode::TwoD => Some(self.ui_model.background_color().to_f32()),
|
Mode::TwoD => Some(self.ui_model.background_color().to_f32()),
|
||||||
Mode::ThreeD => None,
|
Mode::ThreeD => None,
|
||||||
Mode::VR => Some(ColorF::transparent_black()),
|
Mode::VR => Some(ColorF::transparent_black()),
|
||||||
};
|
};
|
||||||
self.renderer.set_options(RendererOptions {
|
|
||||||
|
// Set up framebuffers.
|
||||||
|
let window_size = self.window_size.device_size();
|
||||||
|
let scene_count = match 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.options_mut() = RendererOptions {
|
||||||
|
dest: DestFramebuffer::Other(self.scene_framebuffer.take().unwrap()),
|
||||||
background_color: clear_color,
|
background_color: clear_color,
|
||||||
no_compute: self.options.no_compute,
|
show_debug_ui: self.options.ui != UIVisibility::None,
|
||||||
});
|
};
|
||||||
|
2
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
*self.renderer.options_mut() = RendererOptions {
|
||||||
|
dest: DestFramebuffer::Default {
|
||||||
|
viewport: self.window.viewport(View::Mono),
|
||||||
|
window_size,
|
||||||
|
},
|
||||||
|
background_color: clear_color,
|
||||||
|
show_debug_ui: self.options.ui != UIVisibility::None,
|
||||||
|
};
|
||||||
|
1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
scene_count
|
scene_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_scene(&mut self) {
|
pub fn draw_scene(&mut self) {
|
||||||
self.renderer.device.begin_commands();
|
self.renderer.device().begin_commands();
|
||||||
|
|
||||||
let view = self.ui_model.mode.view(0);
|
let view = self.ui_model.mode.view(0);
|
||||||
self.window.make_current(view);
|
self.window.make_current(view);
|
||||||
|
@ -107,26 +107,29 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
self.draw_environment(0);
|
self.draw_environment(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.renderer.device.end_commands();
|
self.renderer.device().end_commands();
|
||||||
|
|
||||||
self.render_vector_scene();
|
self.render_vector_scene();
|
||||||
|
|
||||||
// Reattach default framebuffer.
|
// Reattach default framebuffer.
|
||||||
if self.camera.mode() == Mode::VR {
|
if self.camera.mode() == Mode::VR {
|
||||||
if let DestFramebuffer::Other(scene_framebuffer) =
|
let new_options = RendererOptions {
|
||||||
self.renderer
|
dest: DestFramebuffer::Default {
|
||||||
.replace_dest_framebuffer(DestFramebuffer::Default {
|
|
||||||
viewport: self.window.viewport(View::Mono),
|
viewport: self.window.viewport(View::Mono),
|
||||||
window_size: self.window_size.device_size(),
|
window_size: self.window_size.device_size(),
|
||||||
})
|
},
|
||||||
{
|
..*self.renderer.options()
|
||||||
|
};
|
||||||
|
if let DestFramebuffer::Other(scene_framebuffer) = mem::replace(self.renderer
|
||||||
|
.options_mut(),
|
||||||
|
new_options).dest {
|
||||||
self.scene_framebuffer = Some(scene_framebuffer);
|
self.scene_framebuffer = Some(scene_framebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin_compositing(&mut self) {
|
pub fn begin_compositing(&mut self) {
|
||||||
self.renderer.device.begin_commands();
|
self.renderer.device().begin_commands();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn composite_scene(&mut self, render_scene_index: u32) {
|
pub fn composite_scene(&mut self, render_scene_index: u32) {
|
||||||
|
@ -153,15 +156,15 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let viewport = self.window.viewport(View::Stereo(render_scene_index));
|
let viewport = self.window.viewport(View::Stereo(render_scene_index));
|
||||||
self.window.make_current(View::Stereo(render_scene_index));
|
self.window.make_current(View::Stereo(render_scene_index));
|
||||||
|
|
||||||
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
|
self.renderer.options_mut().dest = DestFramebuffer::Default {
|
||||||
viewport,
|
viewport,
|
||||||
window_size: self.window_size.device_size(),
|
window_size: self.window_size.device_size(),
|
||||||
});
|
};
|
||||||
|
|
||||||
self.draw_environment(render_scene_index);
|
self.draw_environment(render_scene_index);
|
||||||
|
|
||||||
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
||||||
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
|
let scene_texture = self.renderer.device().framebuffer_texture(scene_framebuffer);
|
||||||
|
|
||||||
let mut quad_scale = self.scene_metadata.view_box.size().to_4d();
|
let mut quad_scale = self.scene_metadata.view_box.size().to_4d();
|
||||||
quad_scale.set_z(1.0);
|
quad_scale.set_z(1.0);
|
||||||
|
@ -226,13 +229,14 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
self.renderer.device.draw_elements(6, &RenderState {
|
self.renderer.device().draw_elements(6, &RenderState {
|
||||||
target: &self.renderer.draw_render_target(),
|
target: &self.renderer.draw_render_target(),
|
||||||
program: &self.ground_program.program,
|
program: &self.ground_program.program,
|
||||||
vertex_array: &self.ground_vertex_array.vertex_array,
|
vertex_array: &self.ground_vertex_array.vertex_array,
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &[],
|
textures: &[],
|
||||||
images: &[],
|
images: &[],
|
||||||
|
storage_buffers: &[],
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.ground_program.transform_uniform,
|
(&self.ground_program.transform_uniform,
|
||||||
UniformData::from_transform_3d(&transform)),
|
UniformData::from_transform_3d(&transform)),
|
||||||
|
@ -258,27 +262,16 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
self.renderer.enable_depth();
|
self.renderer.enable_depth();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.renderer.begin_scene();
|
|
||||||
|
|
||||||
// Issue render commands!
|
// Issue render commands!
|
||||||
for command in self.render_command_stream.as_mut().unwrap() {
|
self.scene_proxy.render(&mut self.renderer);
|
||||||
self.renderer.render_command(&command);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.current_frame
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scene_stats
|
|
||||||
.push(self.renderer.stats);
|
|
||||||
self.renderer.end_scene();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_raster_screenshot(&mut self, path: PathBuf) {
|
pub fn take_raster_screenshot(&mut self, path: PathBuf) {
|
||||||
let drawable_size = self.window_size.device_size();
|
let drawable_size = self.window_size.device_size();
|
||||||
let viewport = RectI::new(Vector2I::default(), drawable_size);
|
let viewport = RectI::new(Vector2I::default(), drawable_size);
|
||||||
let texture_data_receiver =
|
let texture_data_receiver =
|
||||||
self.renderer.device.read_pixels(&RenderTarget::Default, viewport);
|
self.renderer.device().read_pixels(&RenderTarget::Default, viewport);
|
||||||
let pixels = match self.renderer.device.recv_texture_data(&texture_data_receiver) {
|
let pixels = match self.renderer.device().recv_texture_data(&texture_data_receiver) {
|
||||||
TextureData::U8(pixels) => pixels,
|
TextureData::U8(pixels) => pixels,
|
||||||
_ => panic!("Unexpected pixel format for default framebuffer!"),
|
_ => panic!("Unexpected pixel format for default framebuffer!"),
|
||||||
};
|
};
|
||||||
|
@ -291,19 +284,4 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_debug_ui(&mut self) {
|
|
||||||
if self.options.ui == UIVisibility::None {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let viewport = self.window.viewport(View::Mono);
|
|
||||||
self.window.make_current(View::Mono);
|
|
||||||
self.renderer.replace_dest_framebuffer(DestFramebuffer::Default {
|
|
||||||
viewport,
|
|
||||||
window_size: self.window_size.device_size(),
|
|
||||||
});
|
|
||||||
|
|
||||||
self.renderer.draw_debug_ui();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::{BackgroundColor, Options};
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
||||||
|
use pathfinder_gpu::allocator::GPUMemoryAllocator;
|
||||||
use pathfinder_gpu::{Device, TextureFormat};
|
use pathfinder_gpu::{Device, TextureFormat};
|
||||||
use pathfinder_renderer::gpu::debug::DebugUIPresenter;
|
use pathfinder_renderer::gpu::debug::DebugUIPresenter;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
@ -97,10 +98,7 @@ impl DemoUIModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DemoUIPresenter<D>
|
pub struct DemoUIPresenter<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
effects_texture: D::Texture,
|
effects_texture: D::Texture,
|
||||||
open_texture: D::Texture,
|
open_texture: D::Texture,
|
||||||
rotate_texture: D::Texture,
|
rotate_texture: D::Texture,
|
||||||
|
@ -116,11 +114,10 @@ where
|
||||||
rotate_panel_visible: bool,
|
rotate_panel_visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DemoUIPresenter<D>
|
impl<D> DemoUIPresenter<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DemoUIPresenter<D> {
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DemoUIPresenter<D> {
|
||||||
|
device.begin_commands();
|
||||||
|
|
||||||
let effects_texture = device.create_texture_from_png(resources,
|
let effects_texture = device.create_texture_from_png(resources,
|
||||||
EFFECTS_PNG_NAME,
|
EFFECTS_PNG_NAME,
|
||||||
TextureFormat::R8);
|
TextureFormat::R8);
|
||||||
|
@ -146,6 +143,8 @@ where
|
||||||
SCREENSHOT_PNG_NAME,
|
SCREENSHOT_PNG_NAME,
|
||||||
TextureFormat::R8);
|
TextureFormat::R8);
|
||||||
|
|
||||||
|
device.end_commands();
|
||||||
|
|
||||||
DemoUIPresenter {
|
DemoUIPresenter {
|
||||||
effects_texture,
|
effects_texture,
|
||||||
open_texture,
|
open_texture,
|
||||||
|
@ -163,19 +162,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<W>(
|
pub fn update<W>(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
window: &mut W,
|
window: &mut W,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel
|
model: &mut DemoUIModel)
|
||||||
) where
|
where W: Window {
|
||||||
W: Window,
|
|
||||||
{
|
|
||||||
// Draw message text.
|
// Draw message text.
|
||||||
|
|
||||||
self.draw_message_text(device, debug_ui_presenter, model);
|
self.draw_message_text(device, allocator, debug_ui_presenter, model);
|
||||||
|
|
||||||
// Draw button strip.
|
// Draw button strip.
|
||||||
|
|
||||||
|
@ -185,50 +182,57 @@ where
|
||||||
let button_size = vec2i(BUTTON_WIDTH, BUTTON_HEIGHT);
|
let button_size = vec2i(BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||||
|
|
||||||
// Draw effects button.
|
// Draw effects button.
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device, position, &self.effects_texture) {
|
if debug_ui_presenter.ui_presenter
|
||||||
|
.draw_button(device, allocator, position, &self.effects_texture) {
|
||||||
self.effects_panel_visible = !self.effects_panel_visible;
|
self.effects_panel_visible = !self.effects_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.effects_panel_visible {
|
if !self.effects_panel_visible {
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(
|
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
||||||
device,
|
allocator,
|
||||||
"Effects",
|
"Effects",
|
||||||
RectI::new(position, button_size),
|
RectI::new(position, button_size));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
position += vec2i(button_size.x() + PADDING, 0);
|
position += vec2i(button_size.x() + PADDING, 0);
|
||||||
|
|
||||||
// Draw open button.
|
// Draw open button.
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device, position, &self.open_texture) {
|
if debug_ui_presenter.ui_presenter
|
||||||
|
.draw_button(device, allocator, position, &self.open_texture) {
|
||||||
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
|
// FIXME(pcwalton): This is not sufficient for Android, where we will need to take in
|
||||||
// the contents of the file.
|
// the contents of the file.
|
||||||
window.present_open_svg_dialog();
|
window.present_open_svg_dialog();
|
||||||
}
|
}
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
||||||
|
allocator,
|
||||||
"Open SVG",
|
"Open SVG",
|
||||||
RectI::new(position, button_size));
|
RectI::new(position, button_size));
|
||||||
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
||||||
|
|
||||||
// Draw screenshot button.
|
// Draw screenshot button.
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device,
|
if debug_ui_presenter.ui_presenter
|
||||||
position,
|
.draw_button(device, allocator, position, &self.screenshot_texture) {
|
||||||
&self.screenshot_texture) {
|
|
||||||
self.screenshot_panel_visible = !self.screenshot_panel_visible;
|
self.screenshot_panel_visible = !self.screenshot_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.screenshot_panel_visible {
|
if !self.screenshot_panel_visible {
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
"Take Screenshot",
|
"Take Screenshot",
|
||||||
RectI::new(position, button_size),
|
RectI::new(position, button_size),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw screenshot panel, if necessary.
|
// Draw screenshot panel, if necessary.
|
||||||
self.draw_screenshot_panel(device, window, debug_ui_presenter, position.x(), action);
|
self.draw_screenshot_panel(device,
|
||||||
|
allocator,
|
||||||
|
window,
|
||||||
|
debug_ui_presenter,
|
||||||
|
position.x(),
|
||||||
|
action);
|
||||||
position += vec2i(button_size.x() + PADDING, 0);
|
position += vec2i(button_size.x() + PADDING, 0);
|
||||||
|
|
||||||
// Draw mode switch.
|
// Draw mode switch.
|
||||||
let new_mode = debug_ui_presenter.ui_presenter.draw_text_switch(
|
let new_mode = debug_ui_presenter.ui_presenter.draw_text_switch(device,
|
||||||
device,
|
allocator,
|
||||||
position,
|
position,
|
||||||
&["2D", "3D", "VR"],
|
&["2D", "3D", "VR"],
|
||||||
model.mode as u8);
|
model.mode as u8);
|
||||||
|
@ -245,6 +249,7 @@ where
|
||||||
let mode_switch_size = vec2i(mode_switch_width, BUTTON_HEIGHT);
|
let mode_switch_size = vec2i(mode_switch_width, BUTTON_HEIGHT);
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
"2D/3D/VR Mode",
|
"2D/3D/VR Mode",
|
||||||
RectI::new(position, mode_switch_size),
|
RectI::new(position, mode_switch_size),
|
||||||
);
|
);
|
||||||
|
@ -252,6 +257,7 @@ where
|
||||||
|
|
||||||
// Draw background switch.
|
// Draw background switch.
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device,
|
if debug_ui_presenter.ui_presenter.draw_button(device,
|
||||||
|
allocator,
|
||||||
position,
|
position,
|
||||||
&self.background_texture) {
|
&self.background_texture) {
|
||||||
self.background_panel_visible = !self.background_panel_visible;
|
self.background_panel_visible = !self.background_panel_visible;
|
||||||
|
@ -259,50 +265,60 @@ where
|
||||||
if !self.background_panel_visible {
|
if !self.background_panel_visible {
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(
|
debug_ui_presenter.ui_presenter.draw_tooltip(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
"Background Color",
|
"Background Color",
|
||||||
RectI::new(position, button_size),
|
RectI::new(position, button_size),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw background panel, if necessary.
|
// Draw background panel, if necessary.
|
||||||
self.draw_background_panel(device, debug_ui_presenter, position.x(), action, model);
|
self.draw_background_panel(device,
|
||||||
|
allocator,
|
||||||
|
debug_ui_presenter,
|
||||||
|
position.x(),
|
||||||
|
action,
|
||||||
|
model);
|
||||||
position += vec2i(button_size.x() + PADDING, 0);
|
position += vec2i(button_size.x() + PADDING, 0);
|
||||||
|
|
||||||
// Draw effects panel, if necessary.
|
// Draw effects panel, if necessary.
|
||||||
self.draw_effects_panel(device, debug_ui_presenter, model, action);
|
self.draw_effects_panel(device, allocator, debug_ui_presenter, model, action);
|
||||||
|
|
||||||
// Draw rotate and zoom buttons, if applicable.
|
// Draw rotate and zoom buttons, if applicable.
|
||||||
if model.mode != Mode::TwoD {
|
if model.mode != Mode::TwoD {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug_ui_presenter.ui_presenter.draw_button(device, position, &self.rotate_texture) {
|
if debug_ui_presenter.ui_presenter.draw_button(device,
|
||||||
|
allocator,
|
||||||
|
position,
|
||||||
|
&self.rotate_texture) {
|
||||||
self.rotate_panel_visible = !self.rotate_panel_visible;
|
self.rotate_panel_visible = !self.rotate_panel_visible;
|
||||||
}
|
}
|
||||||
if !self.rotate_panel_visible {
|
if !self.rotate_panel_visible {
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
debug_ui_presenter.ui_presenter.draw_tooltip(device,
|
||||||
|
allocator,
|
||||||
"Rotate",
|
"Rotate",
|
||||||
RectI::new(position, button_size));
|
RectI::new(position, button_size));
|
||||||
}
|
}
|
||||||
self.draw_rotate_panel(device, debug_ui_presenter, position.x(), action, model);
|
self.draw_rotate_panel(device, allocator, debug_ui_presenter, position.x(), action, model);
|
||||||
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
position += vec2i(BUTTON_WIDTH + PADDING, 0);
|
||||||
|
|
||||||
// Draw zoom control.
|
// Draw zoom control.
|
||||||
self.draw_zoom_control(device, debug_ui_presenter, position, action);
|
self.draw_zoom_control(device, allocator, debug_ui_presenter, position, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_zoom_control(
|
fn draw_zoom_control(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
position: Vector2I,
|
position: Vector2I,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction) {
|
||||||
) {
|
|
||||||
let zoom_segmented_control_width =
|
let zoom_segmented_control_width =
|
||||||
debug_ui_presenter.ui_presenter.measure_segmented_control(3);
|
debug_ui_presenter.ui_presenter.measure_segmented_control(3);
|
||||||
let zoom_segmented_control_rect =
|
let zoom_segmented_control_rect =
|
||||||
RectI::new(position, vec2i(zoom_segmented_control_width, BUTTON_HEIGHT));
|
RectI::new(position, vec2i(zoom_segmented_control_width, BUTTON_HEIGHT));
|
||||||
debug_ui_presenter.ui_presenter.draw_tooltip(device, "Zoom", zoom_segmented_control_rect);
|
debug_ui_presenter.ui_presenter
|
||||||
|
.draw_tooltip(device, allocator, "Zoom", zoom_segmented_control_rect);
|
||||||
|
|
||||||
let zoom_textures = &[
|
let zoom_textures = &[
|
||||||
&self.zoom_in_texture,
|
&self.zoom_in_texture,
|
||||||
|
@ -311,6 +327,7 @@ where
|
||||||
];
|
];
|
||||||
|
|
||||||
match debug_ui_presenter.ui_presenter.draw_image_segmented_control(device,
|
match debug_ui_presenter.ui_presenter.draw_image_segmented_control(device,
|
||||||
|
allocator,
|
||||||
position,
|
position,
|
||||||
zoom_textures,
|
zoom_textures,
|
||||||
None) {
|
None) {
|
||||||
|
@ -323,6 +340,7 @@ where
|
||||||
|
|
||||||
fn draw_message_text(&mut self,
|
fn draw_message_text(&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
model: &mut DemoUIModel) {
|
model: &mut DemoUIModel) {
|
||||||
if model.message.is_empty() {
|
if model.message.is_empty() {
|
||||||
|
@ -334,11 +352,13 @@ where
|
||||||
let window_size = vec2i(PADDING * 2 + message_size, TOOLTIP_HEIGHT);
|
let window_size = vec2i(PADDING * 2 + message_size, TOOLTIP_HEIGHT);
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
RectI::new(window_origin, window_size),
|
RectI::new(window_origin, window_size),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR,
|
||||||
);
|
);
|
||||||
debug_ui_presenter.ui_presenter.draw_text(
|
debug_ui_presenter.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
&model.message,
|
&model.message,
|
||||||
window_origin + vec2i(PADDING, PADDING + FONT_ASCENT),
|
window_origin + vec2i(PADDING, PADDING + FONT_ASCENT),
|
||||||
false,
|
false,
|
||||||
|
@ -347,6 +367,7 @@ where
|
||||||
|
|
||||||
fn draw_effects_panel(&mut self,
|
fn draw_effects_panel(&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
model: &mut DemoUIModel,
|
model: &mut DemoUIModel,
|
||||||
action: &mut UIAction) {
|
action: &mut UIAction) {
|
||||||
|
@ -358,29 +379,29 @@ where
|
||||||
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
RectI::new(vec2i(PADDING, effects_panel_y),
|
RectI::new(vec2i(PADDING, effects_panel_y),
|
||||||
vec2i(EFFECTS_PANEL_WIDTH, EFFECTS_PANEL_HEIGHT)),
|
vec2i(EFFECTS_PANEL_WIDTH, EFFECTS_PANEL_HEIGHT)),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR);
|
||||||
);
|
|
||||||
|
|
||||||
self.draw_effects_switch(
|
self.draw_effects_switch(device,
|
||||||
device,
|
allocator,
|
||||||
action,
|
action,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
"Gamma Correction",
|
"Gamma Correction",
|
||||||
0,
|
0,
|
||||||
effects_panel_y,
|
effects_panel_y,
|
||||||
&mut model.gamma_correction_effect_enabled);
|
&mut model.gamma_correction_effect_enabled);
|
||||||
self.draw_effects_switch(
|
self.draw_effects_switch(device,
|
||||||
device,
|
allocator,
|
||||||
action,
|
action,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
"Stem Darkening",
|
"Stem Darkening",
|
||||||
1,
|
1,
|
||||||
effects_panel_y,
|
effects_panel_y,
|
||||||
&mut model.stem_darkening_effect_enabled);
|
&mut model.stem_darkening_effect_enabled);
|
||||||
self.draw_effects_switch(
|
self.draw_effects_switch(device,
|
||||||
device,
|
allocator,
|
||||||
action,
|
action,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
"Subpixel AA",
|
"Subpixel AA",
|
||||||
|
@ -389,14 +410,14 @@ where
|
||||||
&mut model.subpixel_aa_effect_enabled);
|
&mut model.subpixel_aa_effect_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_screenshot_panel<W>(
|
fn draw_screenshot_panel<W>(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
window: &mut W,
|
window: &mut W,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
panel_x: i32,
|
panel_x: i32,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction)
|
||||||
) where W: Window {
|
where W: Window {
|
||||||
if !self.screenshot_panel_visible {
|
if !self.screenshot_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -406,36 +427,34 @@ where
|
||||||
let panel_position = vec2i(panel_x, panel_y);
|
let panel_position = vec2i(panel_x, panel_y);
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
RectI::new(panel_position, vec2i(SCREENSHOT_PANEL_WIDTH, SCREENSHOT_PANEL_HEIGHT)),
|
RectI::new(panel_position, vec2i(SCREENSHOT_PANEL_WIDTH, SCREENSHOT_PANEL_HEIGHT)),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.draw_screenshot_menu_item(
|
self.draw_screenshot_menu_item(device,
|
||||||
device,
|
allocator,
|
||||||
window,
|
window,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
ScreenshotType::PNG,
|
ScreenshotType::PNG,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action);
|
||||||
);
|
self.draw_screenshot_menu_item(device,
|
||||||
self.draw_screenshot_menu_item(
|
allocator,
|
||||||
device,
|
|
||||||
window,
|
window,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
ScreenshotType::SVG,
|
ScreenshotType::SVG,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_background_panel(
|
fn draw_background_panel(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
panel_x: i32,
|
panel_x: i32,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel,
|
model: &mut DemoUIModel) {
|
||||||
) {
|
|
||||||
if !self.background_panel_visible {
|
if !self.background_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -445,44 +464,41 @@ where
|
||||||
let panel_position = vec2i(panel_x, panel_y);
|
let panel_position = vec2i(panel_x, panel_y);
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
RectI::new(panel_position, vec2i(BACKGROUND_PANEL_WIDTH, BACKGROUND_PANEL_HEIGHT)),
|
RectI::new(panel_position, vec2i(BACKGROUND_PANEL_WIDTH, BACKGROUND_PANEL_HEIGHT)),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.draw_background_menu_item(
|
self.draw_background_menu_item(device,
|
||||||
device,
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
BackgroundColor::Light,
|
BackgroundColor::Light,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action,
|
||||||
model,
|
model);
|
||||||
);
|
self.draw_background_menu_item(device,
|
||||||
self.draw_background_menu_item(
|
allocator,
|
||||||
device,
|
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
BackgroundColor::Dark,
|
BackgroundColor::Dark,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action,
|
||||||
model,
|
model);
|
||||||
);
|
self.draw_background_menu_item(device,
|
||||||
self.draw_background_menu_item(
|
allocator,
|
||||||
device,
|
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
BackgroundColor::Transparent,
|
BackgroundColor::Transparent,
|
||||||
panel_position,
|
panel_position,
|
||||||
action,
|
action,
|
||||||
model,
|
model);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_rotate_panel(
|
fn draw_rotate_panel(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
rotate_panel_x: i32,
|
rotate_panel_x: i32,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel
|
model: &mut DemoUIModel) {
|
||||||
) {
|
|
||||||
if !self.rotate_panel_visible {
|
if !self.rotate_panel_visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -493,9 +509,9 @@ where
|
||||||
let rotate_panel_size = vec2i(ROTATE_PANEL_WIDTH, ROTATE_PANEL_HEIGHT);
|
let rotate_panel_size = vec2i(ROTATE_PANEL_WIDTH, ROTATE_PANEL_HEIGHT);
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
RectI::new(rotate_panel_origin, rotate_panel_size),
|
RectI::new(rotate_panel_origin, rotate_panel_size),
|
||||||
WINDOW_COLOR,
|
WINDOW_COLOR);
|
||||||
);
|
|
||||||
|
|
||||||
let (widget_x, widget_y) = (rotate_panel_x + PADDING, rotate_panel_y + PADDING);
|
let (widget_x, widget_y) = (rotate_panel_x + PADDING, rotate_panel_y + PADDING);
|
||||||
let widget_rect = RectI::new(vec2i(widget_x, widget_y),
|
let widget_rect = RectI::new(vec2i(widget_x, widget_y),
|
||||||
|
@ -503,8 +519,7 @@ where
|
||||||
if let Some(position) = debug_ui_presenter
|
if let Some(position) = debug_ui_presenter
|
||||||
.ui_presenter
|
.ui_presenter
|
||||||
.event_queue
|
.event_queue
|
||||||
.handle_mouse_down_or_dragged_in_rect(widget_rect)
|
.handle_mouse_down_or_dragged_in_rect(widget_rect) {
|
||||||
{
|
|
||||||
model.rotation = position.x();
|
model.rotation = position.x();
|
||||||
*action = UIAction::Rotate(model.rotation());
|
*action = UIAction::Rotate(model.rotation());
|
||||||
}
|
}
|
||||||
|
@ -513,23 +528,25 @@ where
|
||||||
rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 - SLIDER_TRACK_HEIGHT / 2;
|
rotate_panel_y + PADDING + SLIDER_KNOB_HEIGHT / 2 - SLIDER_TRACK_HEIGHT / 2;
|
||||||
let slider_track_rect = RectI::new(vec2i(widget_x, slider_track_y),
|
let slider_track_rect = RectI::new(vec2i(widget_x, slider_track_y),
|
||||||
vec2i(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
|
vec2i(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
|
||||||
debug_ui_presenter.ui_presenter.draw_rect_outline(device, slider_track_rect, TEXT_COLOR);
|
debug_ui_presenter.ui_presenter
|
||||||
|
.draw_rect_outline(device, allocator, slider_track_rect, TEXT_COLOR);
|
||||||
|
|
||||||
let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2;
|
let slider_knob_x = widget_x + model.rotation - SLIDER_KNOB_WIDTH / 2;
|
||||||
let slider_knob_rect = RectI::new(vec2i(slider_knob_x, widget_y),
|
let slider_knob_rect = RectI::new(vec2i(slider_knob_x, widget_y),
|
||||||
vec2i(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
|
vec2i(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rect(device, slider_knob_rect, TEXT_COLOR);
|
debug_ui_presenter.ui_presenter
|
||||||
|
.draw_solid_rect(device, allocator, slider_knob_rect, TEXT_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_screenshot_menu_item<W>(
|
fn draw_screenshot_menu_item<W>(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
window: &mut W,
|
window: &mut W,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
screenshot_type: ScreenshotType,
|
screenshot_type: ScreenshotType,
|
||||||
panel_position: Vector2I,
|
panel_position: Vector2I,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction)
|
||||||
) where W: Window {
|
where W: Window {
|
||||||
let index = screenshot_type as i32;
|
let index = screenshot_type as i32;
|
||||||
let text = format!("Save as {}...", screenshot_type.as_str());
|
let text = format!("Save as {}...", screenshot_type.as_str());
|
||||||
|
|
||||||
|
@ -538,6 +555,7 @@ where
|
||||||
let widget_rect = RectI::new(widget_origin, widget_size);
|
let widget_rect = RectI::new(widget_origin, widget_size);
|
||||||
|
|
||||||
if self.draw_menu_item(device,
|
if self.draw_menu_item(device,
|
||||||
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
&text,
|
&text,
|
||||||
widget_rect,
|
widget_rect,
|
||||||
|
@ -551,15 +569,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_background_menu_item(
|
fn draw_background_menu_item(&mut self,
|
||||||
&mut self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
color: BackgroundColor,
|
color: BackgroundColor,
|
||||||
panel_position: Vector2I,
|
panel_position: Vector2I,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
model: &mut DemoUIModel,
|
model: &mut DemoUIModel) {
|
||||||
) {
|
|
||||||
let (text, index) = (color.as_str(), color as i32);
|
let (text, index) = (color.as_str(), color as i32);
|
||||||
|
|
||||||
let widget_size = vec2i(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT);
|
let widget_size = vec2i(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT);
|
||||||
|
@ -568,6 +585,7 @@ where
|
||||||
|
|
||||||
let selected = color == model.background_color;
|
let selected = color == model.background_color;
|
||||||
if self.draw_menu_item(device,
|
if self.draw_menu_item(device,
|
||||||
|
allocator,
|
||||||
debug_ui_presenter,
|
debug_ui_presenter,
|
||||||
text,
|
text,
|
||||||
widget_rect,
|
widget_rect,
|
||||||
|
@ -579,20 +597,21 @@ where
|
||||||
|
|
||||||
fn draw_menu_item(&self,
|
fn draw_menu_item(&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
text: &str,
|
text: &str,
|
||||||
widget_rect: RectI,
|
widget_rect: RectI,
|
||||||
selected: bool)
|
selected: bool)
|
||||||
-> bool {
|
-> bool {
|
||||||
if selected {
|
if selected {
|
||||||
debug_ui_presenter.ui_presenter.draw_solid_rounded_rect(device,
|
debug_ui_presenter.ui_presenter
|
||||||
widget_rect,
|
.draw_solid_rounded_rect(device, allocator, widget_rect, TEXT_COLOR);
|
||||||
TEXT_COLOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (text_x, text_y) = (PADDING * 2, BUTTON_TEXT_OFFSET);
|
let (text_x, text_y) = (PADDING * 2, BUTTON_TEXT_OFFSET);
|
||||||
let text_position = widget_rect.origin() + vec2i(text_x, text_y);
|
let text_position = widget_rect.origin() + vec2i(text_x, text_y);
|
||||||
debug_ui_presenter.ui_presenter.draw_text(device, text, text_position, selected);
|
debug_ui_presenter.ui_presenter
|
||||||
|
.draw_text(device, allocator, text, text_position, selected);
|
||||||
|
|
||||||
debug_ui_presenter.ui_presenter
|
debug_ui_presenter.ui_presenter
|
||||||
.event_queue
|
.event_queue
|
||||||
|
@ -600,9 +619,9 @@ where
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_effects_switch(
|
fn draw_effects_switch(&self,
|
||||||
&self,
|
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
action: &mut UIAction,
|
action: &mut UIAction,
|
||||||
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
debug_ui_presenter: &mut DebugUIPresenter<D>,
|
||||||
text: &str,
|
text: &str,
|
||||||
|
@ -611,17 +630,20 @@ where
|
||||||
value: &mut bool) {
|
value: &mut bool) {
|
||||||
let text_x = PADDING * 2;
|
let text_x = PADDING * 2;
|
||||||
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
||||||
debug_ui_presenter.ui_presenter.draw_text(device, text, vec2i(text_x, text_y), false);
|
debug_ui_presenter.ui_presenter
|
||||||
|
.draw_text(device, allocator, text, vec2i(text_x, text_y), false);
|
||||||
|
|
||||||
let switch_width = debug_ui_presenter.ui_presenter.measure_segmented_control(2);
|
let switch_width = debug_ui_presenter.ui_presenter.measure_segmented_control(2);
|
||||||
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (switch_width + PADDING);
|
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (switch_width + PADDING);
|
||||||
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
||||||
let switch_position = vec2i(switch_x, switch_y);
|
let switch_position = vec2i(switch_x, switch_y);
|
||||||
|
|
||||||
let new_value =
|
let new_value = debug_ui_presenter.ui_presenter
|
||||||
debug_ui_presenter
|
.draw_text_switch(device,
|
||||||
.ui_presenter
|
allocator,
|
||||||
.draw_text_switch(device, switch_position, &["Off", "On"], *value as u8) != 0;
|
switch_position,
|
||||||
|
&["Off", "On"],
|
||||||
|
*value as u8) != 0;
|
||||||
|
|
||||||
if new_value != *value {
|
if new_value != *value {
|
||||||
*action = UIAction::EffectsChanged;
|
*action = UIAction::EffectsChanged;
|
||||||
|
|
|
@ -58,9 +58,11 @@ int main(int argc, const char **argv) {
|
||||||
PFGLDestFramebufferCreateFullWindow(&(PFVector2I){640, 480});
|
PFGLDestFramebufferCreateFullWindow(&(PFVector2I){640, 480});
|
||||||
PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0),
|
PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0),
|
||||||
PFFilesystemResourceLoaderLocate(),
|
PFFilesystemResourceLoaderLocate(),
|
||||||
dest_framebuffer,
|
&(PFRendererMode){PF_RENDERER_LEVEL_D3D9},
|
||||||
&(PFRendererOptions){
|
&(PFRendererOptions){
|
||||||
(PFColorF){1.0, 1.0, 1.0, 1.0}, PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR
|
dest_framebuffer,
|
||||||
|
(PFColorF){1.0, 1.0, 1.0, 1.0},
|
||||||
|
PF_RENDERER_OPTIONS_FLAGS_HAS_BACKGROUND_COLOR
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make a canvas. We're going to draw a house.
|
// Make a canvas. We're going to draw a house.
|
||||||
|
@ -86,7 +88,8 @@ int main(int argc, const char **argv) {
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
PFSceneRef scene = PFCanvasCreateScene(canvas);
|
PFSceneRef scene = PFCanvasCreateScene(canvas);
|
||||||
PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene);
|
PFSceneProxyRef scene_proxy =
|
||||||
|
PFSceneProxyCreateFromSceneAndRayonExecutor(scene, PF_RENDERER_LEVEL_D3D9);
|
||||||
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, PFBuildOptionsCreate());
|
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, PFBuildOptionsCreate());
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -48,13 +48,14 @@ fn main() {
|
||||||
gl::load_with(|name| gl_context.get_proc_address(name) as *const _);
|
gl::load_with(|name| gl_context.get_proc_address(name) as *const _);
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0),
|
let device = GLDevice::new(GLVersion::GL3, 0);
|
||||||
&EmbeddedResourceLoader,
|
let mode = RendererMode::default_for_device(&device);
|
||||||
DestFramebuffer::full_window(window_size),
|
let options = RendererOptions {
|
||||||
RendererOptions {
|
|
||||||
background_color: Some(ColorF::white()),
|
background_color: Some(ColorF::white()),
|
||||||
|
dest: DestFramebuffer::full_window(window_size),
|
||||||
..RendererOptions::default()
|
..RendererOptions::default()
|
||||||
});
|
};
|
||||||
|
let mut renderer = Renderer::new(device, &EmbeddedResourceLoader, mode, options);
|
||||||
|
|
||||||
// Make a canvas. We're going to draw a house.
|
// Make a canvas. We're going to draw a house.
|
||||||
let font_context = CanvasFontContext::from_system_source();
|
let font_context = CanvasFontContext::from_system_source();
|
||||||
|
@ -78,7 +79,9 @@ fn main() {
|
||||||
canvas.stroke_path(path);
|
canvas.stroke_path(path);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(), RayonExecutor);
|
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
||||||
|
renderer.mode().level,
|
||||||
|
RayonExecutor);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
gl_context.swap_buffers().unwrap();
|
gl_context.swap_buffers().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
|
|
||||||
use foreign_types::ForeignTypeRef;
|
use foreign_types::ForeignTypeRef;
|
||||||
use metal::{CAMetalLayer, CoreAnimationLayerRef};
|
use metal::{CAMetalLayer, CoreAnimationLayerRef};
|
||||||
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
|
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
|
||||||
use pathfinder_color::ColorF;
|
use pathfinder_color::ColorF;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
use pathfinder_geometry::vector::{vec2f, vec2i};
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_metal::MetalDevice;
|
use pathfinder_metal::MetalDevice;
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
|
@ -46,14 +46,18 @@ fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
let mut renderer = Renderer::new(MetalDevice::new(metal_layer),
|
let device = MetalDevice::new(metal_layer);
|
||||||
&EmbeddedResourceLoader,
|
let mode = RendererMode::default_for_device(&device);
|
||||||
DestFramebuffer::full_window(window_size),
|
let options = RendererOptions {
|
||||||
RendererOptions { background_color: Some(ColorF::white()) });
|
dest: DestFramebuffer::full_window(window_size),
|
||||||
|
background_color: Some(ColorF::white()),
|
||||||
|
..RendererOptions::default()
|
||||||
|
};
|
||||||
|
let mut renderer = Renderer::new(device, &EmbeddedResourceLoader, mode, options);
|
||||||
|
|
||||||
// Make a canvas. We're going to draw a house.
|
// Make a canvas. We're going to draw a house.
|
||||||
let mut canvas = CanvasRenderingContext2D::new(CanvasFontContext::from_system_source(),
|
let canvas = Canvas::new(window_size.to_f32());
|
||||||
window_size.to_f32());
|
let mut canvas = canvas.get_context_2d(CanvasFontContext::from_system_source());
|
||||||
|
|
||||||
// Set line width.
|
// Set line width.
|
||||||
canvas.set_line_width(10.0);
|
canvas.set_line_width(10.0);
|
||||||
|
@ -73,9 +77,11 @@ fn main() {
|
||||||
canvas.stroke_path(path);
|
canvas.stroke_path(path);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
|
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
||||||
|
renderer.mode().level,
|
||||||
|
RayonExecutor);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
renderer.device.present_drawable();
|
renderer.device().present_drawable();
|
||||||
|
|
||||||
// Wait for a keypress.
|
// Wait for a keypress.
|
||||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||||
|
|
|
@ -16,7 +16,7 @@ use pathfinder_geometry::vector::{vec2f, vec2i};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
|
@ -72,13 +72,14 @@ fn main() {
|
||||||
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
let mut renderer = Renderer::new(pathfinder_device,
|
let mode = RendererMode::default_for_device(&pathfinder_device);
|
||||||
&EmbeddedResourceLoader::new(),
|
let options = RendererOptions {
|
||||||
DestFramebuffer::full_window(framebuffer_size),
|
dest: DestFramebuffer::full_window(framebuffer_size),
|
||||||
RendererOptions {
|
|
||||||
background_color: Some(ColorF::white()),
|
background_color: Some(ColorF::white()),
|
||||||
..RendererOptions::default()
|
..RendererOptions::default()
|
||||||
});
|
};
|
||||||
|
let resource_loader = EmbeddedResourceLoader::new();
|
||||||
|
let mut renderer = Renderer::new(pathfinder_device, &resource_loader, mode, options);
|
||||||
|
|
||||||
// Make a canvas. We're going to draw a house.
|
// Make a canvas. We're going to draw a house.
|
||||||
let font_context = CanvasFontContext::from_system_source();
|
let font_context = CanvasFontContext::from_system_source();
|
||||||
|
@ -102,7 +103,9 @@ fn main() {
|
||||||
canvas.stroke_path(path);
|
canvas.stroke_path(path);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(), RayonExecutor);
|
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
||||||
|
renderer.mode().level,
|
||||||
|
RayonExecutor);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
|
|
||||||
// Present the surface.
|
// Present the surface.
|
||||||
|
|
|
@ -15,7 +15,7 @@ use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
|
@ -85,13 +85,13 @@ fn main() {
|
||||||
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
||||||
|
|
||||||
// Create our renderers.
|
// Create our renderers.
|
||||||
let renderer = Renderer::new(pathfinder_device,
|
let mode = RendererMode::default_for_device(&pathfinder_device);
|
||||||
&EmbeddedResourceLoader,
|
let options = RendererOptions {
|
||||||
DestFramebuffer::full_window(framebuffer_size),
|
|
||||||
RendererOptions {
|
|
||||||
background_color: Some(ColorF::white()),
|
background_color: Some(ColorF::white()),
|
||||||
|
dest: DestFramebuffer::full_window(framebuffer_size),
|
||||||
..RendererOptions::default()
|
..RendererOptions::default()
|
||||||
});
|
};
|
||||||
|
let renderer = Renderer::new(pathfinder_device, &EmbeddedResourceLoader, mode, options);
|
||||||
let window_size = vec2i(window_size.width, window_size.height);
|
let window_size = vec2i(window_size.width, window_size.height);
|
||||||
let mut moire_renderer = MoireRenderer::new(renderer, window_size, framebuffer_size);
|
let mut moire_renderer = MoireRenderer::new(renderer, window_size, framebuffer_size);
|
||||||
|
|
||||||
|
@ -129,10 +129,11 @@ struct MoireRenderer {
|
||||||
impl MoireRenderer {
|
impl MoireRenderer {
|
||||||
fn new(renderer: Renderer<GLDevice>, window_size: Vector2I, drawable_size: Vector2I)
|
fn new(renderer: Renderer<GLDevice>, window_size: Vector2I, drawable_size: Vector2I)
|
||||||
-> MoireRenderer {
|
-> MoireRenderer {
|
||||||
|
let level = renderer.mode().level;
|
||||||
MoireRenderer {
|
MoireRenderer {
|
||||||
renderer,
|
renderer,
|
||||||
font_context: CanvasFontContext::from_system_source(),
|
font_context: CanvasFontContext::from_system_source(),
|
||||||
scene: SceneProxy::new(RayonExecutor),
|
scene: SceneProxy::new(level, RayonExecutor),
|
||||||
frame: 0,
|
frame: 0,
|
||||||
window_size,
|
window_size,
|
||||||
drawable_size,
|
drawable_size,
|
||||||
|
@ -155,10 +156,7 @@ impl MoireRenderer {
|
||||||
let inner_center = window_center + vec2f(1.0, sin_time) * (cos_time * INNER_RADIUS);
|
let inner_center = window_center + vec2f(1.0, sin_time) * (cos_time * INNER_RADIUS);
|
||||||
|
|
||||||
// Clear to background color.
|
// Clear to background color.
|
||||||
self.renderer.set_options(RendererOptions {
|
self.renderer.options_mut().background_color = Some(background_color);
|
||||||
background_color: Some(background_color),
|
|
||||||
..RendererOptions::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make a canvas.
|
// Make a canvas.
|
||||||
let mut canvas =
|
let mut canvas =
|
||||||
|
|
|
@ -1517,13 +1517,14 @@ fn main() {
|
||||||
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
|
let renderer_options = RendererOptions {
|
||||||
|
background_color: Some(rgbf(0.3, 0.3, 0.32)),
|
||||||
|
..RendererOptions::default_for_device(&pathfinder_device)
|
||||||
|
};
|
||||||
let mut renderer = Renderer::new(pathfinder_device,
|
let mut renderer = Renderer::new(pathfinder_device,
|
||||||
&resources,
|
&resources,
|
||||||
DestFramebuffer::full_window(framebuffer_size),
|
DestFramebuffer::full_window(framebuffer_size),
|
||||||
RendererOptions {
|
renderer_options);
|
||||||
background_color: Some(rgbf(0.3, 0.3, 0.32)),
|
|
||||||
..RendererOptions::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize font state.
|
// Initialize font state.
|
||||||
let font_source = Arc::new(MemSource::from_fonts(font_data.into_iter()).unwrap());
|
let font_source = Arc::new(MemSource::from_fonts(font_data.into_iter()).unwrap());
|
||||||
|
@ -1566,7 +1567,9 @@ fn main() {
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let canvas = context.into_canvas();
|
let canvas = context.into_canvas();
|
||||||
let scene = SceneProxy::from_scene(canvas.into_scene(), RayonExecutor);
|
let mut scene = SceneProxy::from_scene(canvas.into_scene(),
|
||||||
|
renderer.level(),
|
||||||
|
RayonExecutor);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
|
|
||||||
// Present the rendered canvas via `surfman`.
|
// Present the rendered canvas via `surfman`.
|
||||||
|
@ -1575,9 +1578,9 @@ fn main() {
|
||||||
device.bind_surface_to_context(&mut gl_context, surface).unwrap();
|
device.bind_surface_to_context(&mut gl_context, surface).unwrap();
|
||||||
|
|
||||||
// Add stats to performance graphs.
|
// Add stats to performance graphs.
|
||||||
if let Some(gpu_time) = renderer.shift_rendering_time() {
|
if let Some(gpu_time) = renderer.last_rendering_time() {
|
||||||
let cpu_build_time = renderer.stats.cpu_build_time.as_secs_f32();
|
let cpu_build_time = renderer.stats().cpu_build_time.as_secs_f32();
|
||||||
let gpu_time = gpu_time.gpu_time.as_secs_f32();
|
let gpu_time = gpu_time.total_time().as_secs_f32();
|
||||||
fps_graph.push(cpu_frame_elapsed_time + cpu_build_time.max(gpu_time));
|
fps_graph.push(cpu_frame_elapsed_time + cpu_build_time.max(gpu_time));
|
||||||
cpu_graph.push(cpu_frame_elapsed_time + cpu_build_time);
|
cpu_graph.push(cpu_frame_elapsed_time + cpu_build_time);
|
||||||
gpu_graph.push(gpu_time);
|
gpu_graph.push(gpu_time);
|
||||||
|
|
|
@ -15,11 +15,11 @@ use pathfinder_geometry::vector::{vec2f, vec2i};
|
||||||
use pathfinder_gl::{GLDevice, GLVersion};
|
use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::options::BuildOptions;
|
use pathfinder_renderer::options::BuildOptions;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::video::GLProfile;
|
use sdl2::video::GLProfile;
|
||||||
|
@ -49,14 +49,15 @@ fn main() {
|
||||||
window.gl_make_current(&gl_context).unwrap();
|
window.gl_make_current(&gl_context).unwrap();
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
let resource_loader = EmbeddedResourceLoader;
|
let resource_loader = FilesystemResourceLoader::locate();
|
||||||
let mut renderer = Renderer::new(GLDevice::new(GLVersion::GL3, 0),
|
let device = GLDevice::new(GLVersion::GL3, 0);
|
||||||
&resource_loader,
|
let mode = RendererMode::default_for_device(&device);
|
||||||
DestFramebuffer::full_window(window_size),
|
let options = RendererOptions {
|
||||||
RendererOptions {
|
|
||||||
background_color: Some(ColorF::white()),
|
background_color: Some(ColorF::white()),
|
||||||
|
dest: DestFramebuffer::full_window(window_size),
|
||||||
..RendererOptions::default()
|
..RendererOptions::default()
|
||||||
});
|
};
|
||||||
|
let mut renderer = Renderer::new(device, &resource_loader, mode, options);
|
||||||
|
|
||||||
// Load a font.
|
// Load a font.
|
||||||
let font_data = Arc::new(resource_loader.slurp("fonts/Overpass-Regular.otf").unwrap());
|
let font_data = Arc::new(resource_loader.slurp("fonts/Overpass-Regular.otf").unwrap());
|
||||||
|
@ -74,7 +75,9 @@ fn main() {
|
||||||
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
|
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(), RayonExecutor);
|
let mut scene = SceneProxy::from_scene(canvas.into_canvas().into_scene(),
|
||||||
|
renderer.mode().level,
|
||||||
|
RayonExecutor);
|
||||||
scene.build_and_render(&mut renderer, BuildOptions::default());
|
scene.build_and_render(&mut renderer, BuildOptions::default());
|
||||||
window.gl_swap_window();
|
window.gl_swap_window();
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use pathfinder_gl::{GLDevice, GLVersion};
|
||||||
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
|
||||||
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererMode, RendererOptions};
|
||||||
use pathfinder_renderer::options::{RenderTransform, BuildOptions};
|
use pathfinder_renderer::options::{RenderTransform, BuildOptions};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
use pathfinder_resources::embedded::EmbeddedResourceLoader;
|
||||||
|
@ -98,15 +98,15 @@ fn main() {
|
||||||
window.gl_make_current(&gl_context).unwrap();
|
window.gl_make_current(&gl_context).unwrap();
|
||||||
|
|
||||||
// Create a Pathfinder renderer.
|
// Create a Pathfinder renderer.
|
||||||
let mut renderer = Renderer::new(
|
let device = GLDevice::new(GLVersion::GL3, 0);
|
||||||
GLDevice::new(GLVersion::GL3, 0),
|
let mode = RendererMode::default_for_device(&device);
|
||||||
&resource_loader,
|
let options = RendererOptions {
|
||||||
DestFramebuffer::full_window(pixel_size),
|
|
||||||
RendererOptions {
|
|
||||||
background_color: Some(stage.background_color()),
|
background_color: Some(stage.background_color()),
|
||||||
|
dest: DestFramebuffer::full_window(pixel_size),
|
||||||
..RendererOptions::default()
|
..RendererOptions::default()
|
||||||
}
|
};
|
||||||
);
|
let mut renderer = Renderer::new(device, &resource_loader, mode, options);
|
||||||
|
|
||||||
// Clear to swf stage background color.
|
// Clear to swf stage background color.
|
||||||
let mut scene = Scene::new();
|
let mut scene = Scene::new();
|
||||||
scene.set_view_box(RectF::new(Vector2F::zero(),
|
scene.set_view_box(RectF::new(Vector2F::zero(),
|
||||||
|
@ -115,7 +115,7 @@ fn main() {
|
||||||
draw_paths_into_scene(&library, &mut scene);
|
draw_paths_into_scene(&library, &mut scene);
|
||||||
|
|
||||||
// Render the canvas to screen.
|
// Render the canvas to screen.
|
||||||
let scene = SceneProxy::from_scene(scene, RayonExecutor);
|
let mut scene = SceneProxy::from_scene(scene, renderer.mode().level, RayonExecutor);
|
||||||
let mut build_options = BuildOptions::default();
|
let mut build_options = BuildOptions::default();
|
||||||
let scale_transform = Transform2F::from_scale(device_pixel_ratio);
|
let scale_transform = Transform2F::from_scale(device_pixel_ratio);
|
||||||
build_options.transform = RenderTransform::Transform2D(scale_transform);
|
build_options.transform = RenderTransform::Transform2D(scale_transform);
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
use pathfinder_content::outline::ContourIterFlags;
|
use pathfinder_content::outline::ContourIterFlags;
|
||||||
use pathfinder_content::segment::SegmentKind;
|
use pathfinder_content::segment::SegmentKind;
|
||||||
use pathfinder_renderer::scene::Scene;
|
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
||||||
|
use pathfinder_renderer::scene::{DrawPath, Scene};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@ fn export_svg<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
view_box.size().x(),
|
view_box.size().x(),
|
||||||
view_box.size().y()
|
view_box.size().y()
|
||||||
)?;
|
)?;
|
||||||
for (paint, outline, name) in scene.paths() {
|
for &DrawPath { paint: paint_id, ref outline, ref name, .. } in scene.draw_paths() {
|
||||||
|
let paint = scene.palette().paints.get(paint_id.0 as usize).unwrap();
|
||||||
write!(writer, " <path")?;
|
write!(writer, " <path")?;
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
write!(writer, " id=\"{}\"", name)?;
|
write!(writer, " id=\"{}\"", name)?;
|
||||||
|
@ -75,8 +76,9 @@ fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
vec2f(r.x(), height - r.y())
|
vec2f(r.x(), height - r.y())
|
||||||
};
|
};
|
||||||
|
|
||||||
for (paint, outline, _) in scene.paths() {
|
for &DrawPath { paint: paint_id, ref outline, .. } in scene.draw_paths() {
|
||||||
// TODO(pcwalton): Gradients and patterns.
|
// TODO(pcwalton): Gradients and patterns.
|
||||||
|
let paint = scene.palette().paints.get(paint_id.0 as usize).unwrap();
|
||||||
if paint.is_color() {
|
if paint.is_color() {
|
||||||
pdf.set_fill_color(paint.base_color());
|
pdf.set_fill_color(paint.base_color());
|
||||||
}
|
}
|
||||||
|
@ -138,7 +140,7 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
writeln!(writer, "0 {} translate", view_box.size().y())?;
|
writeln!(writer, "0 {} translate", view_box.size().y())?;
|
||||||
writeln!(writer, "1 -1 scale")?;
|
writeln!(writer, "1 -1 scale")?;
|
||||||
|
|
||||||
for (paint, outline, name) in scene.paths() {
|
for &DrawPath { paint: paint_id, ref outline, ref name, .. } in scene.draw_paths() {
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
writeln!(writer, "newpath % {}", name)?;
|
writeln!(writer, "newpath % {}", name)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -180,6 +182,7 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Gradients and patterns.
|
// TODO(pcwalton): Gradients and patterns.
|
||||||
|
let paint = scene.palette().paints.get(paint_id.0 as usize).unwrap();
|
||||||
if paint.is_color() {
|
if paint.is_color() {
|
||||||
let color = paint.base_color();
|
let color = paint.base_color();
|
||||||
writeln!(writer, "{} {} {} setrgbcolor", color.r, color.g, color.b)?;
|
writeln!(writer, "{} {} {} setrgbcolor", color.r, color.g, color.b)?;
|
||||||
|
|
|
@ -293,16 +293,9 @@ impl MulAssign<Vector2F> for LineSegment2F {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct LineSegmentU4 {
|
pub struct LineSegmentU16 {
|
||||||
pub from: u8,
|
pub from_x: u16,
|
||||||
pub to: u8,
|
pub from_y: u16,
|
||||||
}
|
pub to_x: u16,
|
||||||
|
pub to_y: u16,
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct LineSegmentU8 {
|
|
||||||
pub from_x: u8,
|
|
||||||
pub from_y: u8,
|
|
||||||
pub to_x: u8,
|
|
||||||
pub to_y: u8,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,6 +327,11 @@ impl RectI {
|
||||||
self.0.w() - self.0.y()
|
self.0.w() - self.0.y()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn area(self) -> i32 {
|
||||||
|
self.width() * self.height()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn upper_right(&self) -> Vector2I {
|
pub fn upper_right(&self) -> Vector2I {
|
||||||
Vector2I(self.0.zy())
|
Vector2I(self.0.zy())
|
||||||
|
|
|
@ -349,6 +349,11 @@ impl Vector2I {
|
||||||
Vector2I(self.0.max(other.0))
|
Vector2I(self.0.max(other.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn area(self) -> i32 {
|
||||||
|
self.x() * self.y()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_f32(self) -> Vector2F {
|
pub fn to_f32(self) -> Vector2F {
|
||||||
Vector2F(self.0.to_f32x2())
|
Vector2F(self.0.to_f32x2())
|
||||||
|
|
115
gl/src/lib.rs
115
gl/src/lib.rs
|
@ -21,15 +21,18 @@ use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
||||||
use pathfinder_gpu::{ComputeDimensions, ComputeState, DepthFunc, Device, FeatureLevel};
|
use pathfinder_gpu::{ComputeDimensions, ComputeState, DepthFunc, Device, FeatureLevel};
|
||||||
use pathfinder_gpu::{ImageAccess, ImageBinding, Primitive, ProgramKind, RenderOptions};
|
use pathfinder_gpu::{ImageAccess, ImageBinding, Primitive, ProgramKind, RenderOptions};
|
||||||
use pathfinder_gpu::{RenderState, RenderTarget, ShaderKind, StencilFunc, TextureBinding, TextureData};
|
use pathfinder_gpu::{RenderState, RenderTarget, ShaderKind, StencilFunc, TextureBinding};
|
||||||
use pathfinder_gpu::{TextureDataRef, TextureFormat, TextureSamplingFlags, UniformData};
|
use pathfinder_gpu::{TextureData, TextureDataRef, TextureFormat, TextureSamplingFlags, UniformData};
|
||||||
use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::CString;
|
use std::ffi::{CStr, CString};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::ops::Range;
|
||||||
|
use std::os::raw::c_char;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -83,6 +86,10 @@ impl GLDevice {
|
||||||
&render_state.textures,
|
&render_state.textures,
|
||||||
&render_state.images);
|
&render_state.images);
|
||||||
|
|
||||||
|
for &(storage_buffer, buffer) in render_state.storage_buffers {
|
||||||
|
self.set_storage_buffer(storage_buffer, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data));
|
render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data));
|
||||||
|
|
||||||
self.set_render_options(&render_state.options);
|
self.set_render_options(&render_state.options);
|
||||||
|
@ -241,7 +248,7 @@ impl GLDevice {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindBufferBase(gl::SHADER_STORAGE_BUFFER,
|
gl::BindBufferBase(gl::SHADER_STORAGE_BUFFER,
|
||||||
storage_buffer.location as GLuint,
|
storage_buffer.location as GLuint,
|
||||||
buffer.gl_buffer);
|
buffer.object.gl_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +261,10 @@ impl GLDevice {
|
||||||
fn reset_render_state(&self, render_state: &RenderState<GLDevice>) {
|
fn reset_render_state(&self, render_state: &RenderState<GLDevice>) {
|
||||||
self.reset_render_options(&render_state.options);
|
self.reset_render_options(&render_state.options);
|
||||||
|
|
||||||
|
for &(storage_buffer, _) in render_state.storage_buffers {
|
||||||
|
self.unset_storage_buffer(storage_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
for image_binding in render_state.images {
|
for image_binding in render_state.images {
|
||||||
self.unbind_image(image_binding.0.image_unit);
|
self.unbind_image(image_binding.0.image_unit);
|
||||||
|
@ -310,6 +321,7 @@ impl GLDevice {
|
||||||
|
|
||||||
impl Device for GLDevice {
|
impl Device for GLDevice {
|
||||||
type Buffer = GLBuffer;
|
type Buffer = GLBuffer;
|
||||||
|
type BufferDataReceiver = GLBufferDataReceiver;
|
||||||
type Fence = GLFence;
|
type Fence = GLFence;
|
||||||
type Framebuffer = GLFramebuffer;
|
type Framebuffer = GLFramebuffer;
|
||||||
type ImageParameter = GLImageParameter;
|
type ImageParameter = GLImageParameter;
|
||||||
|
@ -324,6 +336,19 @@ impl Device for GLDevice {
|
||||||
type VertexArray = GLVertexArray;
|
type VertexArray = GLVertexArray;
|
||||||
type VertexAttr = GLVertexAttr;
|
type VertexAttr = GLVertexAttr;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn backend_name(&self) -> &'static str {
|
||||||
|
"OpenGL"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn device_name(&self) -> String {
|
||||||
|
unsafe {
|
||||||
|
CStr::from_ptr(gl::GetString(gl::RENDERER) as *const c_char).to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn feature_level(&self) -> FeatureLevel {
|
fn feature_level(&self) -> FeatureLevel {
|
||||||
match self.version {
|
match self.version {
|
||||||
GLVersion::GL3 | GLVersion::GLES3 => FeatureLevel::D3D10,
|
GLVersion::GL3 | GLVersion::GLES3 => FeatureLevel::D3D10,
|
||||||
|
@ -582,14 +607,12 @@ impl Device for GLDevice {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut gl_buffer = 0;
|
let mut gl_buffer = 0;
|
||||||
gl::GenBuffers(1, &mut gl_buffer); ck();
|
gl::GenBuffers(1, &mut gl_buffer); ck();
|
||||||
GLBuffer { gl_buffer, mode }
|
let object = Rc::new(GLBufferObject { gl_buffer });
|
||||||
|
GLBuffer { object, mode }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_buffer<T>(&self,
|
fn allocate_buffer<T>(&self, buffer: &GLBuffer, data: BufferData<T>, target: BufferTarget) {
|
||||||
buffer: &GLBuffer,
|
|
||||||
data: BufferData<T>,
|
|
||||||
target: BufferTarget) {
|
|
||||||
let target = target.to_gl_target();
|
let target = target.to_gl_target();
|
||||||
let (ptr, len) = match data {
|
let (ptr, len) = match data {
|
||||||
BufferData::Uninitialized(len) => (ptr::null(), len),
|
BufferData::Uninitialized(len) => (ptr::null(), len),
|
||||||
|
@ -598,7 +621,7 @@ impl Device for GLDevice {
|
||||||
let len = (len * mem::size_of::<T>()) as GLsizeiptr;
|
let len = (len * mem::size_of::<T>()) as GLsizeiptr;
|
||||||
let usage = buffer.mode.to_gl_usage();
|
let usage = buffer.mode.to_gl_usage();
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindBuffer(target, buffer.gl_buffer); ck();
|
gl::BindBuffer(target, buffer.object.gl_buffer); ck();
|
||||||
gl::BufferData(target, len, ptr, usage); ck();
|
gl::BufferData(target, len, ptr, usage); ck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -611,7 +634,7 @@ impl Device for GLDevice {
|
||||||
let target = target.to_gl_target();
|
let target = target.to_gl_target();
|
||||||
let len = (data.len() * mem::size_of::<T>()) as GLsizeiptr;
|
let len = (data.len() * mem::size_of::<T>()) as GLsizeiptr;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindBuffer(target, buffer.gl_buffer); ck();
|
gl::BindBuffer(target, buffer.object.gl_buffer); ck();
|
||||||
gl::BufferSubData(target,
|
gl::BufferSubData(target,
|
||||||
position as GLintptr,
|
position as GLintptr,
|
||||||
len,
|
len,
|
||||||
|
@ -748,6 +771,14 @@ impl Device for GLDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_buffer(&self, buffer: &GLBuffer, target: BufferTarget, range: Range<usize>)
|
||||||
|
-> GLBufferDataReceiver {
|
||||||
|
unsafe {
|
||||||
|
let gl_sync = gl::FenceSync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
GLBufferDataReceiver { object: buffer.object.clone(), gl_sync, range, target }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn begin_commands(&self) {
|
fn begin_commands(&self) {
|
||||||
// TODO(pcwalton): Add some checks in debug mode to make sure render commands are bracketed
|
// TODO(pcwalton): Add some checks in debug mode to make sure render commands are bracketed
|
||||||
// by these?
|
// by these?
|
||||||
|
@ -867,11 +898,34 @@ impl Device for GLDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Option<Vec<u8>> {
|
||||||
|
unsafe {
|
||||||
|
let result = gl::ClientWaitSync(receiver.gl_sync,
|
||||||
|
gl::SYNC_FLUSH_COMMANDS_BIT,
|
||||||
|
0); ck();
|
||||||
|
if result == gl::TIMEOUT_EXPIRED || result == gl::WAIT_FAILED {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.get_buffer_data(receiver))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Vec<u8> {
|
||||||
|
unsafe {
|
||||||
|
let result = gl::ClientWaitSync(receiver.gl_sync,
|
||||||
|
gl::SYNC_FLUSH_COMMANDS_BIT,
|
||||||
|
!0); ck();
|
||||||
|
debug_assert!(result != gl::TIMEOUT_EXPIRED && result != gl::WAIT_FAILED);
|
||||||
|
self.get_buffer_data(receiver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bind_buffer(&self, vertex_array: &GLVertexArray, buffer: &GLBuffer, target: BufferTarget) {
|
fn bind_buffer(&self, vertex_array: &GLVertexArray, buffer: &GLBuffer, target: BufferTarget) {
|
||||||
self.bind_vertex_array(vertex_array);
|
self.bind_vertex_array(vertex_array);
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer); ck();
|
gl::BindBuffer(target.to_gl_target(), buffer.object.gl_buffer); ck();
|
||||||
}
|
}
|
||||||
self.unbind_vertex_array();
|
self.unbind_vertex_array();
|
||||||
}
|
}
|
||||||
|
@ -964,7 +1018,7 @@ impl GLDevice {
|
||||||
|
|
||||||
fn unbind_image(&self, unit: u32) {
|
fn unbind_image(&self, unit: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindImageTexture(unit, 0, 0, gl::FALSE, 0, 0, 0); ck();
|
gl::BindImageTexture(unit, 0, 0, gl::FALSE, 0, gl::READ_ONLY, gl::RGBA8); ck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1092,6 +1146,19 @@ impl GLDevice {
|
||||||
texture_data
|
texture_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_buffer_data(&self, receiver: &GLBufferDataReceiver) -> Vec<u8> {
|
||||||
|
let mut dest = vec![0; receiver.range.end - receiver.range.start];
|
||||||
|
let gl_target = receiver.target.to_gl_target();
|
||||||
|
unsafe {
|
||||||
|
gl::BindBuffer(gl_target, receiver.object.gl_buffer); ck();
|
||||||
|
gl::GetBufferSubData(gl_target,
|
||||||
|
receiver.range.start as GLintptr,
|
||||||
|
(receiver.range.end - receiver.range.start) as GLsizeiptr,
|
||||||
|
dest.as_mut_ptr() as *mut GLvoid); ck();
|
||||||
|
}
|
||||||
|
dest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GLVertexArray {
|
pub struct GLVertexArray {
|
||||||
|
@ -1175,11 +1242,15 @@ impl Drop for GLFramebuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GLBuffer {
|
pub struct GLBuffer {
|
||||||
pub gl_buffer: GLuint,
|
pub object: Rc<GLBufferObject>,
|
||||||
pub mode: BufferUploadMode,
|
pub mode: BufferUploadMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for GLBuffer {
|
pub struct GLBufferObject {
|
||||||
|
pub gl_buffer: GLuint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for GLBufferObject {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::DeleteBuffers(1, &mut self.gl_buffer); ck();
|
gl::DeleteBuffers(1, &mut self.gl_buffer); ck();
|
||||||
|
@ -1397,7 +1468,7 @@ impl TextureFormatExt for TextureFormat {
|
||||||
match self {
|
match self {
|
||||||
TextureFormat::R8 => gl::R8 as GLint,
|
TextureFormat::R8 => gl::R8 as GLint,
|
||||||
TextureFormat::R16F => gl::R16F as GLint,
|
TextureFormat::R16F => gl::R16F as GLint,
|
||||||
TextureFormat::RGBA8 => gl::RGBA as GLint,
|
TextureFormat::RGBA8 => gl::RGBA8 as GLint,
|
||||||
TextureFormat::RGBA16F => gl::RGBA16F as GLint,
|
TextureFormat::RGBA16F => gl::RGBA16F as GLint,
|
||||||
TextureFormat::RGBA32F => gl::RGBA32F as GLint,
|
TextureFormat::RGBA32F => gl::RGBA32F as GLint,
|
||||||
}
|
}
|
||||||
|
@ -1427,14 +1498,22 @@ impl VertexAttrTypeExt for VertexAttrType {
|
||||||
fn to_gl_type(self) -> GLuint {
|
fn to_gl_type(self) -> GLuint {
|
||||||
match self {
|
match self {
|
||||||
VertexAttrType::F32 => gl::FLOAT,
|
VertexAttrType::F32 => gl::FLOAT,
|
||||||
VertexAttrType::I16 => gl::SHORT,
|
|
||||||
VertexAttrType::I8 => gl::BYTE,
|
VertexAttrType::I8 => gl::BYTE,
|
||||||
VertexAttrType::U16 => gl::UNSIGNED_SHORT,
|
VertexAttrType::I16 => gl::SHORT,
|
||||||
|
VertexAttrType::I32 => gl::INT,
|
||||||
VertexAttrType::U8 => gl::UNSIGNED_BYTE,
|
VertexAttrType::U8 => gl::UNSIGNED_BYTE,
|
||||||
|
VertexAttrType::U16 => gl::UNSIGNED_SHORT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GLBufferDataReceiver {
|
||||||
|
object: Rc<GLBufferObject>,
|
||||||
|
gl_sync: GLsync,
|
||||||
|
range: Range<usize>,
|
||||||
|
target: BufferTarget,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct GLTextureDataReceiver {
|
pub struct GLTextureDataReceiver {
|
||||||
gl_pixel_buffer: GLuint,
|
gl_pixel_buffer: GLuint,
|
||||||
gl_sync: GLsync,
|
gl_sync: GLsync,
|
||||||
|
|
|
@ -10,7 +10,9 @@ homepage = "https://github.com/servo/pathfinder"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
|
fxhash = "0.2"
|
||||||
half = "1.5"
|
half = "1.5"
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
[dependencies.image]
|
[dependencies.image]
|
||||||
version = "0.23"
|
version = "0.23"
|
||||||
|
|
|
@ -0,0 +1,400 @@
|
||||||
|
// pathfinder/gpu/src/gpu/allocator.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
//! GPU memory management.
|
||||||
|
|
||||||
|
use crate::{BufferData, BufferTarget, BufferUploadMode, Device, TextureFormat};
|
||||||
|
use fxhash::FxHashMap;
|
||||||
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::default::Default;
|
||||||
|
use std::mem;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// Everything above 16 MB is allocated exactly.
|
||||||
|
const MAX_BUFFER_SIZE_CLASS: u64 = 16 * 1024 * 1024;
|
||||||
|
|
||||||
|
// Number of seconds before unused memory is purged.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): jemalloc uses a sigmoidal decay curve here. Consider something similar.
|
||||||
|
const DECAY_TIME: f32 = 0.250;
|
||||||
|
|
||||||
|
// Number of seconds before we can reuse an object buffer.
|
||||||
|
//
|
||||||
|
// This helps avoid stalls. This is admittedly a bit of a hack.
|
||||||
|
const REUSE_TIME: f32 = 0.015;
|
||||||
|
|
||||||
|
pub struct GPUMemoryAllocator<D> where D: Device {
|
||||||
|
buffers_in_use: FxHashMap<BufferID, BufferAllocation<D>>,
|
||||||
|
textures_in_use: FxHashMap<TextureID, TextureAllocation<D>>,
|
||||||
|
framebuffers_in_use: FxHashMap<FramebufferID, FramebufferAllocation<D>>,
|
||||||
|
free_objects: VecDeque<FreeObject<D>>,
|
||||||
|
next_buffer_id: BufferID,
|
||||||
|
next_texture_id: TextureID,
|
||||||
|
next_framebuffer_id: FramebufferID,
|
||||||
|
bytes_committed: u64,
|
||||||
|
bytes_allocated: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BufferAllocation<D> where D: Device {
|
||||||
|
buffer: D::Buffer,
|
||||||
|
size: u64,
|
||||||
|
tag: BufferTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TextureAllocation<D> where D: Device {
|
||||||
|
texture: D::Texture,
|
||||||
|
descriptor: TextureDescriptor,
|
||||||
|
tag: TextureTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FramebufferAllocation<D> where D: Device {
|
||||||
|
framebuffer: D::Framebuffer,
|
||||||
|
descriptor: TextureDescriptor,
|
||||||
|
tag: FramebufferTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FreeObject<D> where D: Device {
|
||||||
|
timestamp: Instant,
|
||||||
|
kind: FreeObjectKind<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FreeObjectKind<D> where D: Device {
|
||||||
|
Buffer { id: BufferID, allocation: BufferAllocation<D> },
|
||||||
|
Texture { id: TextureID, allocation: TextureAllocation<D> },
|
||||||
|
Framebuffer { id: FramebufferID, allocation: FramebufferAllocation<D> },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct TextureDescriptor {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: TextureFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct BufferID(pub u64);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct TextureID(pub u64);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct FramebufferID(pub u64);
|
||||||
|
|
||||||
|
// For debugging and profiling.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||||
|
pub struct BufferTag(pub &'static str);
|
||||||
|
|
||||||
|
// For debugging and profiling.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct TextureTag(pub &'static str);
|
||||||
|
|
||||||
|
// For debugging and profiling.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct FramebufferTag(pub &'static str);
|
||||||
|
|
||||||
|
impl<D> GPUMemoryAllocator<D> where D: Device {
|
||||||
|
pub fn new() -> GPUMemoryAllocator<D> {
|
||||||
|
GPUMemoryAllocator {
|
||||||
|
buffers_in_use: FxHashMap::default(),
|
||||||
|
textures_in_use: FxHashMap::default(),
|
||||||
|
framebuffers_in_use: FxHashMap::default(),
|
||||||
|
free_objects: VecDeque::new(),
|
||||||
|
next_buffer_id: BufferID(0),
|
||||||
|
next_texture_id: TextureID(0),
|
||||||
|
next_framebuffer_id: FramebufferID(0),
|
||||||
|
bytes_committed: 0,
|
||||||
|
bytes_allocated: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_buffer<T>(&mut self, device: &D, size: u64, tag: BufferTag) -> BufferID {
|
||||||
|
let mut byte_size = size * mem::size_of::<T>() as u64;
|
||||||
|
if byte_size < MAX_BUFFER_SIZE_CLASS {
|
||||||
|
byte_size = byte_size.next_power_of_two();
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
for free_object_index in 0..self.free_objects.len() {
|
||||||
|
match self.free_objects[free_object_index] {
|
||||||
|
FreeObject {
|
||||||
|
ref timestamp,
|
||||||
|
kind: FreeObjectKind::Buffer { ref allocation, .. },
|
||||||
|
} if allocation.size == byte_size &&
|
||||||
|
(now - *timestamp).as_secs_f32() >= REUSE_TIME => {}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
||||||
|
Some(FreeObject { kind: FreeObjectKind::Buffer { id, allocation }, .. }) => {
|
||||||
|
(id, allocation)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
allocation.tag = tag;
|
||||||
|
self.bytes_committed += allocation.size;
|
||||||
|
self.buffers_in_use.insert(id, allocation);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
||||||
|
device.allocate_buffer::<u8>(&buffer,
|
||||||
|
BufferData::Uninitialized(byte_size as usize),
|
||||||
|
BufferTarget::Vertex);
|
||||||
|
|
||||||
|
let id = self.next_buffer_id;
|
||||||
|
self.next_buffer_id.0 += 1;
|
||||||
|
|
||||||
|
debug!("mapping buffer: {:?} {} ({}x{}) {:?}",
|
||||||
|
id,
|
||||||
|
byte_size,
|
||||||
|
size,
|
||||||
|
mem::size_of::<T>(),
|
||||||
|
tag);
|
||||||
|
|
||||||
|
self.buffers_in_use.insert(id, BufferAllocation { buffer, size: byte_size, tag });
|
||||||
|
self.bytes_allocated += byte_size;
|
||||||
|
self.bytes_committed += byte_size;
|
||||||
|
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_texture(&mut self,
|
||||||
|
device: &D,
|
||||||
|
size: Vector2I,
|
||||||
|
format: TextureFormat,
|
||||||
|
tag: TextureTag)
|
||||||
|
-> TextureID {
|
||||||
|
let descriptor = TextureDescriptor {
|
||||||
|
width: size.x() as u32,
|
||||||
|
height: size.y() as u32,
|
||||||
|
format,
|
||||||
|
};
|
||||||
|
let byte_size = descriptor.byte_size();
|
||||||
|
|
||||||
|
for free_object_index in 0..self.free_objects.len() {
|
||||||
|
match self.free_objects[free_object_index] {
|
||||||
|
FreeObject { kind: FreeObjectKind::Texture { ref allocation, .. }, .. } if
|
||||||
|
allocation.descriptor == descriptor => {}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
||||||
|
Some(FreeObject { kind: FreeObjectKind::Texture { id, allocation }, .. }) => {
|
||||||
|
(id, allocation)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
allocation.tag = tag;
|
||||||
|
self.bytes_committed += allocation.descriptor.byte_size();
|
||||||
|
self.textures_in_use.insert(id, allocation);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("mapping texture: {:?} {:?}", descriptor, tag);
|
||||||
|
|
||||||
|
let texture = device.create_texture(format, size);
|
||||||
|
let id = self.next_texture_id;
|
||||||
|
self.next_texture_id.0 += 1;
|
||||||
|
|
||||||
|
self.textures_in_use.insert(id, TextureAllocation { texture, descriptor, tag });
|
||||||
|
|
||||||
|
self.bytes_allocated += byte_size;
|
||||||
|
self.bytes_committed += byte_size;
|
||||||
|
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_framebuffer(&mut self,
|
||||||
|
device: &D,
|
||||||
|
size: Vector2I,
|
||||||
|
format: TextureFormat,
|
||||||
|
tag: FramebufferTag)
|
||||||
|
-> FramebufferID {
|
||||||
|
let descriptor = TextureDescriptor {
|
||||||
|
width: size.x() as u32,
|
||||||
|
height: size.y() as u32,
|
||||||
|
format,
|
||||||
|
};
|
||||||
|
let byte_size = descriptor.byte_size();
|
||||||
|
|
||||||
|
for free_object_index in 0..self.free_objects.len() {
|
||||||
|
match self.free_objects[free_object_index].kind {
|
||||||
|
FreeObjectKind::Framebuffer { ref allocation, .. } if allocation.descriptor ==
|
||||||
|
descriptor => {}
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (id, mut allocation) = match self.free_objects.remove(free_object_index) {
|
||||||
|
Some(FreeObject { kind: FreeObjectKind::Framebuffer { id, allocation }, .. }) => {
|
||||||
|
(id, allocation)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
allocation.tag = tag;
|
||||||
|
self.bytes_committed += allocation.descriptor.byte_size();
|
||||||
|
self.framebuffers_in_use.insert(id, allocation);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("mapping framebuffer: {:?} {:?}", descriptor, tag);
|
||||||
|
|
||||||
|
let texture = device.create_texture(format, size);
|
||||||
|
let framebuffer = device.create_framebuffer(texture);
|
||||||
|
let id = self.next_framebuffer_id;
|
||||||
|
self.next_framebuffer_id.0 += 1;
|
||||||
|
|
||||||
|
self.framebuffers_in_use.insert(id, FramebufferAllocation {
|
||||||
|
framebuffer,
|
||||||
|
descriptor,
|
||||||
|
tag,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.bytes_allocated += byte_size;
|
||||||
|
self.bytes_committed += byte_size;
|
||||||
|
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn purge_if_needed(&mut self) {
|
||||||
|
let now = Instant::now();
|
||||||
|
loop {
|
||||||
|
match self.free_objects.front() {
|
||||||
|
Some(FreeObject { timestamp, .. }) if (now - *timestamp).as_secs_f32() >=
|
||||||
|
DECAY_TIME => {}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
match self.free_objects.pop_front() {
|
||||||
|
None => break,
|
||||||
|
Some(FreeObject { kind: FreeObjectKind::Buffer { allocation, .. }, .. }) => {
|
||||||
|
debug!("purging buffer: {}", allocation.size);
|
||||||
|
self.bytes_allocated -= allocation.size;
|
||||||
|
}
|
||||||
|
Some(FreeObject { kind: FreeObjectKind::Texture { allocation, .. }, .. }) => {
|
||||||
|
debug!("purging texture: {:?}", allocation.descriptor);
|
||||||
|
self.bytes_allocated -= allocation.descriptor.byte_size();
|
||||||
|
}
|
||||||
|
Some(FreeObject { kind: FreeObjectKind::Framebuffer { allocation, .. }, .. }) => {
|
||||||
|
debug!("purging framebuffer: {:?}", allocation.descriptor);
|
||||||
|
self.bytes_allocated -= allocation.descriptor.byte_size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_buffer(&mut self, id: BufferID) {
|
||||||
|
let allocation = self.buffers_in_use
|
||||||
|
.remove(&id)
|
||||||
|
.expect("Attempted to free unallocated buffer!");
|
||||||
|
self.bytes_committed -= allocation.size;
|
||||||
|
self.free_objects.push_back(FreeObject {
|
||||||
|
timestamp: Instant::now(),
|
||||||
|
kind: FreeObjectKind::Buffer { id, allocation },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_texture(&mut self, id: TextureID) {
|
||||||
|
let allocation = self.textures_in_use
|
||||||
|
.remove(&id)
|
||||||
|
.expect("Attempted to free unallocated texture!");
|
||||||
|
let byte_size = allocation.descriptor.byte_size();
|
||||||
|
self.bytes_committed -= byte_size;
|
||||||
|
self.free_objects.push_back(FreeObject {
|
||||||
|
timestamp: Instant::now(),
|
||||||
|
kind: FreeObjectKind::Texture { id, allocation },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_framebuffer(&mut self, id: FramebufferID) {
|
||||||
|
let allocation = self.framebuffers_in_use
|
||||||
|
.remove(&id)
|
||||||
|
.expect("Attempted to free unallocated framebuffer!");
|
||||||
|
let byte_size = allocation.descriptor.byte_size();
|
||||||
|
self.bytes_committed -= byte_size;
|
||||||
|
self.free_objects.push_back(FreeObject {
|
||||||
|
timestamp: Instant::now(),
|
||||||
|
kind: FreeObjectKind::Framebuffer { id, allocation },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_buffer(&self, id: BufferID) -> &D::Buffer {
|
||||||
|
&self.buffers_in_use[&id].buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_texture(&self, id: TextureID) -> &D::Texture {
|
||||||
|
&self.textures_in_use[&id].texture
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_framebuffer(&self, id: FramebufferID) -> &D::Framebuffer {
|
||||||
|
&self.framebuffers_in_use[&id].framebuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn bytes_allocated(&self) -> u64 {
|
||||||
|
self.bytes_allocated
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn bytes_committed(&self) -> u64 {
|
||||||
|
self.bytes_committed
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn dump(&self) {
|
||||||
|
println!("GPU memory dump");
|
||||||
|
println!("---------------");
|
||||||
|
|
||||||
|
println!("Buffers:");
|
||||||
|
let mut ids: Vec<BufferID> = self.buffers_in_use.keys().cloned().collect();
|
||||||
|
ids.sort();
|
||||||
|
for id in ids {
|
||||||
|
let allocation = &self.buffers_in_use[&id];
|
||||||
|
println!("id {:?}: {:?} ({:?} B)", id, allocation.tag, allocation.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Textures:");
|
||||||
|
let mut ids: Vec<TextureID> = self.textures_in_use.keys().cloned().collect();
|
||||||
|
ids.sort();
|
||||||
|
for id in ids {
|
||||||
|
let allocation = &self.textures_in_use[&id];
|
||||||
|
println!("id {:?}: {:?} {:?}x{:?} {:?} ({:?} B)",
|
||||||
|
id,
|
||||||
|
allocation.tag,
|
||||||
|
allocation.descriptor.width,
|
||||||
|
allocation.descriptor.height,
|
||||||
|
allocation.descriptor.format,
|
||||||
|
allocation.descriptor.byte_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Framebuffers:");
|
||||||
|
let mut ids: Vec<FramebufferID> = self.framebuffers_in_use.keys().cloned().collect();
|
||||||
|
ids.sort();
|
||||||
|
for id in ids {
|
||||||
|
let allocation = &self.framebuffers_in_use[&id];
|
||||||
|
println!("id {:?}: {:?} {:?}x{:?} {:?} ({:?} B)",
|
||||||
|
id,
|
||||||
|
allocation.tag,
|
||||||
|
allocation.descriptor.width,
|
||||||
|
allocation.descriptor.height,
|
||||||
|
allocation.descriptor.format,
|
||||||
|
allocation.descriptor.byte_size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextureDescriptor {
|
||||||
|
fn byte_size(&self) -> u64 {
|
||||||
|
self.width as u64 * self.height as u64 * self.format.bytes_per_pixel() as u64
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,10 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
pub mod allocator;
|
||||||
|
|
||||||
use half::f16;
|
use half::f16;
|
||||||
use image::ImageFormat;
|
use image::ImageFormat;
|
||||||
|
@ -21,11 +25,13 @@ use pathfinder_geometry::transform3d::Transform4F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
|
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
|
||||||
|
use std::ops::Range;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub trait Device: Sized {
|
pub trait Device: Sized {
|
||||||
type Buffer;
|
type Buffer;
|
||||||
|
type BufferDataReceiver;
|
||||||
type Fence;
|
type Fence;
|
||||||
type Framebuffer;
|
type Framebuffer;
|
||||||
type ImageParameter;
|
type ImageParameter;
|
||||||
|
@ -40,6 +46,8 @@ pub trait Device: Sized {
|
||||||
type VertexArray;
|
type VertexArray;
|
||||||
type VertexAttr;
|
type VertexAttr;
|
||||||
|
|
||||||
|
fn backend_name(&self) -> &'static str;
|
||||||
|
fn device_name(&self) -> String;
|
||||||
fn feature_level(&self) -> FeatureLevel;
|
fn feature_level(&self) -> FeatureLevel;
|
||||||
fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture;
|
fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture;
|
||||||
fn create_texture_from_data(&self, format: TextureFormat, size: Vector2I, data: TextureDataRef)
|
fn create_texture_from_data(&self, format: TextureFormat, size: Vector2I, data: TextureDataRef)
|
||||||
|
@ -90,6 +98,8 @@ pub trait Device: Sized {
|
||||||
fn upload_to_texture(&self, texture: &Self::Texture, rect: RectI, data: TextureDataRef);
|
fn upload_to_texture(&self, texture: &Self::Texture, rect: RectI, data: TextureDataRef);
|
||||||
fn read_pixels(&self, target: &RenderTarget<Self>, viewport: RectI)
|
fn read_pixels(&self, target: &RenderTarget<Self>, viewport: RectI)
|
||||||
-> Self::TextureDataReceiver;
|
-> Self::TextureDataReceiver;
|
||||||
|
fn read_buffer(&self, buffer: &Self::Buffer, target: BufferTarget, range: Range<usize>)
|
||||||
|
-> Self::BufferDataReceiver;
|
||||||
fn begin_commands(&self);
|
fn begin_commands(&self);
|
||||||
fn end_commands(&self);
|
fn end_commands(&self);
|
||||||
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>);
|
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>);
|
||||||
|
@ -108,6 +118,8 @@ pub trait Device: Sized {
|
||||||
fn recv_timer_query(&self, query: &Self::TimerQuery) -> Duration;
|
fn recv_timer_query(&self, query: &Self::TimerQuery) -> Duration;
|
||||||
fn try_recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> Option<TextureData>;
|
fn try_recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> Option<TextureData>;
|
||||||
fn recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> TextureData;
|
fn recv_texture_data(&self, receiver: &Self::TextureDataReceiver) -> TextureData;
|
||||||
|
fn try_recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Option<Vec<u8>>;
|
||||||
|
fn recv_buffer(&self, receiver: &Self::BufferDataReceiver) -> Vec<u8>;
|
||||||
|
|
||||||
fn create_texture_from_png(&self,
|
fn create_texture_from_png(&self,
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
|
@ -131,6 +143,30 @@ pub trait Device: Sized {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upload_png_to_texture(&self,
|
||||||
|
resources: &dyn ResourceLoader,
|
||||||
|
name: &str,
|
||||||
|
texture: &Self::Texture,
|
||||||
|
format: TextureFormat) {
|
||||||
|
let data = resources.slurp(&format!("textures/{}.png", name)).unwrap();
|
||||||
|
let image = image::load_from_memory_with_format(&data, ImageFormat::Png).unwrap();
|
||||||
|
match format {
|
||||||
|
TextureFormat::R8 => {
|
||||||
|
let image = image.to_luma();
|
||||||
|
let size = vec2i(image.width() as i32, image.height() as i32);
|
||||||
|
let rect = RectI::new(Vector2I::default(), size);
|
||||||
|
self.upload_to_texture(&texture, rect, TextureDataRef::U8(&image))
|
||||||
|
}
|
||||||
|
TextureFormat::RGBA8 => {
|
||||||
|
let image = image.to_rgba();
|
||||||
|
let size = vec2i(image.width() as i32, image.height() as i32);
|
||||||
|
let rect = RectI::new(Vector2I::default(), size);
|
||||||
|
self.upload_to_texture(&texture, rect, TextureDataRef::U8(&image))
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_program_from_shader_names(
|
fn create_program_from_shader_names(
|
||||||
&self,
|
&self,
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
|
@ -170,7 +206,7 @@ pub enum FeatureLevel {
|
||||||
D3D11,
|
D3D11,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum TextureFormat {
|
pub enum TextureFormat {
|
||||||
R8,
|
R8,
|
||||||
R16F,
|
R16F,
|
||||||
|
@ -182,10 +218,11 @@ pub enum TextureFormat {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum VertexAttrType {
|
pub enum VertexAttrType {
|
||||||
F32,
|
F32,
|
||||||
I16,
|
|
||||||
I8,
|
I8,
|
||||||
U16,
|
I16,
|
||||||
|
I32,
|
||||||
U8,
|
U8,
|
||||||
|
U16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
@ -258,6 +295,7 @@ pub struct RenderState<'a, D> where D: Device {
|
||||||
pub uniforms: &'a [UniformBinding<'a, D::Uniform>],
|
pub uniforms: &'a [UniformBinding<'a, D::Uniform>],
|
||||||
pub textures: &'a [TextureBinding<'a, D::TextureParameter, D::Texture>],
|
pub textures: &'a [TextureBinding<'a, D::TextureParameter, D::Texture>],
|
||||||
pub images: &'a [ImageBinding<'a, D::ImageParameter, D::Texture>],
|
pub images: &'a [ImageBinding<'a, D::ImageParameter, D::Texture>],
|
||||||
|
pub storage_buffers: &'a [(&'a D::StorageBuffer, &'a D::Buffer)],
|
||||||
pub viewport: RectI,
|
pub viewport: RectI,
|
||||||
pub options: RenderOptions,
|
pub options: RenderOptions,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ byteorder = "1.3"
|
||||||
block = "0.1"
|
block = "0.1"
|
||||||
cocoa = "0.19"
|
cocoa = "0.19"
|
||||||
core-foundation = "0.6"
|
core-foundation = "0.6"
|
||||||
|
dispatch = "0.2"
|
||||||
foreign-types = "0.3"
|
foreign-types = "0.3"
|
||||||
half = "1.5"
|
half = "1.5"
|
||||||
io-surface = "0.12"
|
io-surface = "0.12"
|
||||||
|
|
738
metal/src/lib.rs
738
metal/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -10,11 +10,13 @@ homepage = "https://github.com/servo/pathfinder"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
|
byte-slice-cast = "0.3"
|
||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
crossbeam-channel = "0.4"
|
crossbeam-channel = "0.4"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
half = "1.5"
|
half = "1.5"
|
||||||
hashbrown = "0.7"
|
hashbrown = "0.7"
|
||||||
|
log = "0.4"
|
||||||
rayon = "1.0"
|
rayon = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -22,9 +24,6 @@ smallvec = "1.2"
|
||||||
vec_map = "0.8"
|
vec_map = "0.8"
|
||||||
instant = { version = "0.1.2", features = ["wasm-bindgen"] }
|
instant = { version = "0.1.2", features = ["wasm-bindgen"] }
|
||||||
|
|
||||||
[dependencies.log]
|
|
||||||
version = "0.4"
|
|
||||||
|
|
||||||
[dependencies.pathfinder_color]
|
[dependencies.pathfinder_color]
|
||||||
path = "../color"
|
path = "../color"
|
||||||
version = "0.5"
|
version = "0.5"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,10 +20,11 @@
|
||||||
//! You don't need to use this API to use Pathfinder; it's only a convenience.
|
//! You don't need to use this API to use Pathfinder; it's only a convenience.
|
||||||
|
|
||||||
use crate::concurrent::executor::Executor;
|
use crate::concurrent::executor::Executor;
|
||||||
|
use crate::gpu::options::RendererLevel;
|
||||||
use crate::gpu::renderer::Renderer;
|
use crate::gpu::renderer::Renderer;
|
||||||
use crate::gpu_data::RenderCommand;
|
use crate::gpu_data::RenderCommand;
|
||||||
use crate::options::{BuildOptions, RenderCommandListener};
|
use crate::options::{BuildOptions, RenderCommandListener};
|
||||||
use crate::scene::Scene;
|
use crate::scene::{Scene, SceneSink};
|
||||||
use crossbeam_channel::{self, Receiver, Sender};
|
use crossbeam_channel::{self, Receiver, Sender};
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
|
@ -33,19 +34,28 @@ const MAX_MESSAGES_IN_FLIGHT: usize = 1024;
|
||||||
|
|
||||||
pub struct SceneProxy {
|
pub struct SceneProxy {
|
||||||
sender: Sender<MainToWorkerMsg>,
|
sender: Sender<MainToWorkerMsg>,
|
||||||
|
receiver: Receiver<RenderCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneProxy {
|
impl SceneProxy {
|
||||||
pub fn new<E>(executor: E) -> SceneProxy where E: Executor + Send + 'static {
|
pub fn new<E>(renderer_level: RendererLevel, executor: E) -> SceneProxy
|
||||||
SceneProxy::from_scene(Scene::new(), executor)
|
where E: Executor + Send + 'static {
|
||||||
|
SceneProxy::from_scene(Scene::new(), renderer_level, executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_scene<E>(scene: Scene, executor: E) -> SceneProxy
|
pub fn from_scene<E>(scene: Scene, renderer_level: RendererLevel, executor: E)
|
||||||
|
-> SceneProxy
|
||||||
where E: Executor + Send + 'static {
|
where E: Executor + Send + 'static {
|
||||||
let (main_to_worker_sender, main_to_worker_receiver) =
|
let (main_to_worker_sender, main_to_worker_receiver) =
|
||||||
crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT);
|
crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT);
|
||||||
thread::spawn(move || scene_thread(scene, executor, main_to_worker_receiver));
|
let (worker_to_main_sender, worker_to_main_receiver) =
|
||||||
SceneProxy { sender: main_to_worker_sender }
|
crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT);
|
||||||
|
let listener = RenderCommandListener::new(Box::new(move |command| {
|
||||||
|
drop(worker_to_main_sender.send(command))
|
||||||
|
}));
|
||||||
|
let sink = SceneSink::new(listener, renderer_level);
|
||||||
|
thread::spawn(move || scene_thread(scene, executor, sink, main_to_worker_receiver));
|
||||||
|
SceneProxy { sender: main_to_worker_sender, receiver: worker_to_main_receiver }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -59,18 +69,22 @@ impl SceneProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_with_listener(&self,
|
pub fn build(&self, options: BuildOptions) {
|
||||||
options: BuildOptions,
|
self.sender.send(MainToWorkerMsg::Build(options)).unwrap();
|
||||||
listener: Box<dyn RenderCommandListener>) {
|
|
||||||
self.sender.send(MainToWorkerMsg::Build(options, listener)).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends all queued commands to the given renderer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_with_stream(&self, options: BuildOptions) -> RenderCommandStream {
|
pub fn render<D>(&mut self, renderer: &mut Renderer<D>) where D: Device {
|
||||||
let (sender, receiver) = crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT);
|
renderer.begin_scene();
|
||||||
let listener = Box::new(move |command| drop(sender.send(command)));
|
while let Ok(command) = self.receiver.recv() {
|
||||||
self.build_with_listener(options, listener);
|
renderer.render_command(&command);
|
||||||
RenderCommandStream::new(receiver)
|
match command {
|
||||||
|
RenderCommand::Finish { .. } => break,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderer.end_scene();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience method to build a scene and send the resulting commands
|
/// A convenience method to build a scene and send the resulting commands
|
||||||
|
@ -79,18 +93,15 @@ impl SceneProxy {
|
||||||
/// Exactly equivalent to:
|
/// Exactly equivalent to:
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```norun
|
||||||
/// for command in scene_proxy.build_with_stream(options) {
|
/// scene_proxy.build(build_options);
|
||||||
/// renderer.render_command(&command)
|
/// scene_proxy.render(renderer);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_and_render<D>(&self, renderer: &mut Renderer<D>, build_options: BuildOptions)
|
pub fn build_and_render<D>(&mut self, renderer: &mut Renderer<D>, build_options: BuildOptions)
|
||||||
where D: Device {
|
where D: Device {
|
||||||
renderer.begin_scene();
|
self.build(build_options);
|
||||||
for command in self.build_with_stream(build_options) {
|
self.render(renderer);
|
||||||
renderer.render_command(&command);
|
|
||||||
}
|
|
||||||
renderer.end_scene();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -103,6 +114,7 @@ impl SceneProxy {
|
||||||
|
|
||||||
fn scene_thread<E>(mut scene: Scene,
|
fn scene_thread<E>(mut scene: Scene,
|
||||||
executor: E,
|
executor: E,
|
||||||
|
mut sink: SceneSink<'static>,
|
||||||
main_to_worker_receiver: Receiver<MainToWorkerMsg>)
|
main_to_worker_receiver: Receiver<MainToWorkerMsg>)
|
||||||
where E: Executor {
|
where E: Executor {
|
||||||
while let Ok(msg) = main_to_worker_receiver.recv() {
|
while let Ok(msg) = main_to_worker_receiver.recv() {
|
||||||
|
@ -110,7 +122,7 @@ fn scene_thread<E>(mut scene: Scene,
|
||||||
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
|
MainToWorkerMsg::ReplaceScene(new_scene) => scene = new_scene,
|
||||||
MainToWorkerMsg::CopyScene(sender) => sender.send(scene.clone()).unwrap(),
|
MainToWorkerMsg::CopyScene(sender) => sender.send(scene.clone()).unwrap(),
|
||||||
MainToWorkerMsg::SetViewBox(new_view_box) => scene.set_view_box(new_view_box),
|
MainToWorkerMsg::SetViewBox(new_view_box) => scene.set_view_box(new_view_box),
|
||||||
MainToWorkerMsg::Build(options, listener) => scene.build(options, listener, &executor)
|
MainToWorkerMsg::Build(options) => scene.build(options, &mut sink, &executor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,33 +131,5 @@ enum MainToWorkerMsg {
|
||||||
ReplaceScene(Scene),
|
ReplaceScene(Scene),
|
||||||
CopyScene(Sender<Scene>),
|
CopyScene(Sender<Scene>),
|
||||||
SetViewBox(RectF),
|
SetViewBox(RectF),
|
||||||
Build(BuildOptions, Box<dyn RenderCommandListener>),
|
Build(BuildOptions),
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RenderCommandStream {
|
|
||||||
receiver: Receiver<RenderCommand>,
|
|
||||||
done: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderCommandStream {
|
|
||||||
fn new(receiver: Receiver<RenderCommand>) -> RenderCommandStream {
|
|
||||||
RenderCommandStream { receiver, done: false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for RenderCommandStream {
|
|
||||||
type Item = RenderCommand;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<RenderCommand> {
|
|
||||||
if self.done {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let command = self.receiver.recv().unwrap();
|
|
||||||
if let RenderCommand::Finish { .. } = command {
|
|
||||||
self.done = true;
|
|
||||||
}
|
|
||||||
Some(command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
// pathfinder/renderer/src/gpu/blend.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
//! Helpers for blending.
|
||||||
|
|
||||||
|
use crate::gpu_data::ColorCombineMode;
|
||||||
|
use crate::paint::PaintCompositeOp;
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
|
use pathfinder_gpu::{BlendFactor, BlendState};
|
||||||
|
|
||||||
|
const COMBINER_CTRL_COLOR_COMBINE_SRC_IN: i32 = 0x1;
|
||||||
|
const COMBINER_CTRL_COLOR_COMBINE_DEST_IN: i32 = 0x2;
|
||||||
|
|
||||||
|
const COMBINER_CTRL_COMPOSITE_NORMAL: i32 = 0x0;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_MULTIPLY: i32 = 0x1;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_SCREEN: i32 = 0x2;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_OVERLAY: i32 = 0x3;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_DARKEN: i32 = 0x4;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_LIGHTEN: i32 = 0x5;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_COLOR_DODGE: i32 = 0x6;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_COLOR_BURN: i32 = 0x7;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_HARD_LIGHT: i32 = 0x8;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_SOFT_LIGHT: i32 = 0x9;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_DIFFERENCE: i32 = 0xa;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_EXCLUSION: i32 = 0xb;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_HUE: i32 = 0xc;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_SATURATION: i32 = 0xd;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_COLOR: i32 = 0xe;
|
||||||
|
const COMBINER_CTRL_COMPOSITE_LUMINOSITY: i32 = 0xf;
|
||||||
|
|
||||||
|
pub(crate) trait ToBlendState {
|
||||||
|
fn to_blend_state(self) -> Option<BlendState>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToBlendState for BlendMode {
|
||||||
|
fn to_blend_state(self) -> Option<BlendState> {
|
||||||
|
match self {
|
||||||
|
BlendMode::Clear => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
|
dest_rgb_factor: BlendFactor::Zero,
|
||||||
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
|
dest_alpha_factor: BlendFactor::Zero,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::SrcOver => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::One,
|
||||||
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::One,
|
||||||
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::DestOver => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::One,
|
||||||
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_alpha_factor: BlendFactor::One,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::SrcIn => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::DestAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::Zero,
|
||||||
|
src_alpha_factor: BlendFactor::DestAlpha,
|
||||||
|
dest_alpha_factor: BlendFactor::Zero,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::DestIn => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
|
dest_rgb_factor: BlendFactor::SrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
|
dest_alpha_factor: BlendFactor::SrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::SrcOut => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::Zero,
|
||||||
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_alpha_factor: BlendFactor::Zero,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::DestOut => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::SrcAtop => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::DestAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::DestAlpha,
|
||||||
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::DestAtop => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::SrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_alpha_factor: BlendFactor::SrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::Xor => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::OneMinusDestAlpha,
|
||||||
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::Lighter => {
|
||||||
|
Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::One,
|
||||||
|
dest_rgb_factor: BlendFactor::One,
|
||||||
|
src_alpha_factor: BlendFactor::One,
|
||||||
|
dest_alpha_factor: BlendFactor::One,
|
||||||
|
..BlendState::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
BlendMode::Copy |
|
||||||
|
BlendMode::Darken |
|
||||||
|
BlendMode::Lighten |
|
||||||
|
BlendMode::Multiply |
|
||||||
|
BlendMode::Screen |
|
||||||
|
BlendMode::HardLight |
|
||||||
|
BlendMode::Overlay |
|
||||||
|
BlendMode::ColorDodge |
|
||||||
|
BlendMode::ColorBurn |
|
||||||
|
BlendMode::SoftLight |
|
||||||
|
BlendMode::Difference |
|
||||||
|
BlendMode::Exclusion |
|
||||||
|
BlendMode::Hue |
|
||||||
|
BlendMode::Saturation |
|
||||||
|
BlendMode::Color |
|
||||||
|
BlendMode::Luminosity => {
|
||||||
|
// Blending is done manually in the shader.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait ToCompositeCtrl {
|
||||||
|
fn to_composite_ctrl(&self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCompositeCtrl for BlendMode {
|
||||||
|
fn to_composite_ctrl(&self) -> i32 {
|
||||||
|
match *self {
|
||||||
|
BlendMode::SrcOver |
|
||||||
|
BlendMode::SrcAtop |
|
||||||
|
BlendMode::DestOver |
|
||||||
|
BlendMode::DestOut |
|
||||||
|
BlendMode::Xor |
|
||||||
|
BlendMode::Lighter |
|
||||||
|
BlendMode::Clear |
|
||||||
|
BlendMode::Copy |
|
||||||
|
BlendMode::SrcIn |
|
||||||
|
BlendMode::SrcOut |
|
||||||
|
BlendMode::DestIn |
|
||||||
|
BlendMode::DestAtop => COMBINER_CTRL_COMPOSITE_NORMAL,
|
||||||
|
BlendMode::Multiply => COMBINER_CTRL_COMPOSITE_MULTIPLY,
|
||||||
|
BlendMode::Darken => COMBINER_CTRL_COMPOSITE_DARKEN,
|
||||||
|
BlendMode::Lighten => COMBINER_CTRL_COMPOSITE_LIGHTEN,
|
||||||
|
BlendMode::Screen => COMBINER_CTRL_COMPOSITE_SCREEN,
|
||||||
|
BlendMode::Overlay => COMBINER_CTRL_COMPOSITE_OVERLAY,
|
||||||
|
BlendMode::ColorDodge => COMBINER_CTRL_COMPOSITE_COLOR_DODGE,
|
||||||
|
BlendMode::ColorBurn => COMBINER_CTRL_COMPOSITE_COLOR_BURN,
|
||||||
|
BlendMode::HardLight => COMBINER_CTRL_COMPOSITE_HARD_LIGHT,
|
||||||
|
BlendMode::SoftLight => COMBINER_CTRL_COMPOSITE_SOFT_LIGHT,
|
||||||
|
BlendMode::Difference => COMBINER_CTRL_COMPOSITE_DIFFERENCE,
|
||||||
|
BlendMode::Exclusion => COMBINER_CTRL_COMPOSITE_EXCLUSION,
|
||||||
|
BlendMode::Hue => COMBINER_CTRL_COMPOSITE_HUE,
|
||||||
|
BlendMode::Saturation => COMBINER_CTRL_COMPOSITE_SATURATION,
|
||||||
|
BlendMode::Color => COMBINER_CTRL_COMPOSITE_COLOR,
|
||||||
|
BlendMode::Luminosity => COMBINER_CTRL_COMPOSITE_LUMINOSITY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCompositeCtrl for ColorCombineMode {
|
||||||
|
fn to_composite_ctrl(&self) -> i32 {
|
||||||
|
match *self {
|
||||||
|
ColorCombineMode::None => 0,
|
||||||
|
ColorCombineMode::SrcIn => COMBINER_CTRL_COLOR_COMBINE_SRC_IN,
|
||||||
|
ColorCombineMode::DestIn => COMBINER_CTRL_COLOR_COMBINE_DEST_IN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait BlendModeExt {
|
||||||
|
fn needs_readable_framebuffer(self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlendModeExt for BlendMode {
|
||||||
|
fn needs_readable_framebuffer(self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlendMode::Clear |
|
||||||
|
BlendMode::SrcOver |
|
||||||
|
BlendMode::DestOver |
|
||||||
|
BlendMode::SrcIn |
|
||||||
|
BlendMode::DestIn |
|
||||||
|
BlendMode::SrcOut |
|
||||||
|
BlendMode::DestOut |
|
||||||
|
BlendMode::SrcAtop |
|
||||||
|
BlendMode::DestAtop |
|
||||||
|
BlendMode::Xor |
|
||||||
|
BlendMode::Lighter |
|
||||||
|
BlendMode::Copy => false,
|
||||||
|
BlendMode::Lighten |
|
||||||
|
BlendMode::Darken |
|
||||||
|
BlendMode::Multiply |
|
||||||
|
BlendMode::Screen |
|
||||||
|
BlendMode::HardLight |
|
||||||
|
BlendMode::Overlay |
|
||||||
|
BlendMode::ColorDodge |
|
||||||
|
BlendMode::ColorBurn |
|
||||||
|
BlendMode::SoftLight |
|
||||||
|
BlendMode::Difference |
|
||||||
|
BlendMode::Exclusion |
|
||||||
|
BlendMode::Hue |
|
||||||
|
BlendMode::Saturation |
|
||||||
|
BlendMode::Color |
|
||||||
|
BlendMode::Luminosity => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait ToCombineMode {
|
||||||
|
fn to_combine_mode(self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCombineMode for PaintCompositeOp {
|
||||||
|
fn to_combine_mode(self) -> i32 {
|
||||||
|
match self {
|
||||||
|
PaintCompositeOp::DestIn => COMBINER_CTRL_COLOR_COMBINE_DEST_IN,
|
||||||
|
PaintCompositeOp::SrcIn => COMBINER_CTRL_COLOR_COMBINE_SRC_IN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pathfinder/renderer/src/gpu/d3d11/mod.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
pub mod renderer;
|
||||||
|
pub mod shaders;
|
|
@ -0,0 +1,897 @@
|
||||||
|
// pathfinder/renderer/src/gpu/d3d11/renderer.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
use crate::gpu::d3d11::shaders::{BOUND_WORKGROUP_SIZE, DICE_WORKGROUP_SIZE};
|
||||||
|
use crate::gpu::d3d11::shaders::{PROPAGATE_WORKGROUP_SIZE, ProgramsD3D11, SORT_WORKGROUP_SIZE};
|
||||||
|
use crate::gpu::perf::TimerFuture;
|
||||||
|
use crate::gpu::renderer::{FramebufferFlags, RendererCore};
|
||||||
|
use crate::gpu_data::{AlphaTileD3D11, BackdropInfoD3D11, DiceMetadataD3D11, DrawTileBatchD3D11};
|
||||||
|
use crate::gpu_data::{Fill, FirstTileD3D11, MicrolineD3D11, PathSource, PropagateMetadataD3D11};
|
||||||
|
use crate::gpu_data::{SegmentIndicesD3D11, SegmentsD3D11, TileD3D11, TileBatchDataD3D11};
|
||||||
|
use crate::gpu_data::{TileBatchTexture, TilePathInfoD3D11};
|
||||||
|
use byte_slice_cast::AsSliceOf;
|
||||||
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
|
use pathfinder_gpu::allocator::{BufferID, BufferTag, GPUMemoryAllocator};
|
||||||
|
use pathfinder_gpu::{BufferTarget, ComputeDimensions, ComputeState, Device, ImageAccess};
|
||||||
|
use pathfinder_gpu::{RenderTarget, UniformData};
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
use pathfinder_simd::default::{F32x4, I32x2};
|
||||||
|
use std::ops::Range;
|
||||||
|
use vec_map::VecMap;
|
||||||
|
|
||||||
|
const FILL_INDIRECT_DRAW_PARAMS_INSTANCE_COUNT_INDEX: usize = 1;
|
||||||
|
const FILL_INDIRECT_DRAW_PARAMS_ALPHA_TILE_COUNT_INDEX: usize = 4;
|
||||||
|
|
||||||
|
const BIN_INDIRECT_DRAW_PARAMS_MICROLINE_COUNT_INDEX: usize = 3;
|
||||||
|
|
||||||
|
const LOAD_ACTION_CLEAR: i32 = 0;
|
||||||
|
const LOAD_ACTION_LOAD: i32 = 1;
|
||||||
|
|
||||||
|
const INITIAL_ALLOCATED_MICROLINE_COUNT: u32 = 1024 * 16;
|
||||||
|
const INITIAL_ALLOCATED_FILL_COUNT: u32 = 1024 * 16;
|
||||||
|
|
||||||
|
pub(crate) struct RendererD3D11<D> where D: Device {
|
||||||
|
programs: ProgramsD3D11<D>,
|
||||||
|
allocated_microline_count: u32,
|
||||||
|
allocated_fill_count: u32,
|
||||||
|
scene_buffers: SceneBuffers,
|
||||||
|
tile_batch_info: VecMap<TileBatchInfoD3D11>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> RendererD3D11<D> where D: Device {
|
||||||
|
pub(crate) fn new(core: &mut RendererCore<D>, resources: &dyn ResourceLoader)
|
||||||
|
-> RendererD3D11<D> {
|
||||||
|
let programs = ProgramsD3D11::new(&core.device, resources);
|
||||||
|
RendererD3D11 {
|
||||||
|
programs,
|
||||||
|
allocated_fill_count: INITIAL_ALLOCATED_FILL_COUNT,
|
||||||
|
allocated_microline_count: INITIAL_ALLOCATED_MICROLINE_COUNT,
|
||||||
|
scene_buffers: SceneBuffers::new(),
|
||||||
|
tile_batch_info: VecMap::<TileBatchInfoD3D11>::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bound(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
tiles_d3d11_buffer_id: BufferID,
|
||||||
|
tile_count: u32,
|
||||||
|
tile_path_info: &[TilePathInfoD3D11]) {
|
||||||
|
let bound_program = &self.programs.bound_program;
|
||||||
|
|
||||||
|
let path_info_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<TilePathInfoD3D11>(&core.device,
|
||||||
|
tile_path_info.len() as u64,
|
||||||
|
BufferTag("TilePathInfoD3D11"));
|
||||||
|
let tile_path_info_buffer = core.allocator.get_buffer(path_info_buffer_id);
|
||||||
|
core.device.upload_to_buffer(tile_path_info_buffer,
|
||||||
|
0,
|
||||||
|
tile_path_info,
|
||||||
|
BufferTarget::Storage);
|
||||||
|
|
||||||
|
let tiles_buffer = core.allocator.get_buffer(tiles_d3d11_buffer_id);
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let compute_dimensions = ComputeDimensions {
|
||||||
|
x: (tile_count + BOUND_WORKGROUP_SIZE - 1) / BOUND_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
|
core.device.dispatch_compute(compute_dimensions, &ComputeState {
|
||||||
|
program: &bound_program.program,
|
||||||
|
textures: &[],
|
||||||
|
uniforms: &[
|
||||||
|
(&bound_program.path_count_uniform, UniformData::Int(tile_path_info.len() as i32)),
|
||||||
|
(&bound_program.tile_count_uniform, UniformData::Int(tile_count as i32)),
|
||||||
|
],
|
||||||
|
images: &[],
|
||||||
|
storage_buffers: &[
|
||||||
|
(&bound_program.tile_path_info_storage_buffer, tile_path_info_buffer),
|
||||||
|
(&bound_program.tiles_storage_buffer, tiles_buffer),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().other_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
core.allocator.free_buffer(path_info_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_propagate_metadata(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
propagate_metadata: &[PropagateMetadataD3D11],
|
||||||
|
backdrops: &[BackdropInfoD3D11])
|
||||||
|
-> PropagateMetadataBufferIDsD3D11 {
|
||||||
|
let propagate_metadata_storage_id =
|
||||||
|
core.allocator
|
||||||
|
.allocate_buffer::<PropagateMetadataD3D11>(&core.device,
|
||||||
|
propagate_metadata.len() as u64,
|
||||||
|
BufferTag("PropagateMetadataD3D11"));
|
||||||
|
let propagate_metadata_buffer = core.allocator.get_buffer(propagate_metadata_storage_id);
|
||||||
|
core.device.upload_to_buffer(propagate_metadata_buffer,
|
||||||
|
0,
|
||||||
|
propagate_metadata,
|
||||||
|
BufferTarget::Storage);
|
||||||
|
|
||||||
|
let backdrops_storage_id =
|
||||||
|
core.allocator.allocate_buffer::<BackdropInfoD3D11>(&core.device,
|
||||||
|
backdrops.len() as u64,
|
||||||
|
BufferTag("BackdropInfoD3D11"));
|
||||||
|
|
||||||
|
PropagateMetadataBufferIDsD3D11 {
|
||||||
|
propagate_metadata: propagate_metadata_storage_id,
|
||||||
|
backdrops: backdrops_storage_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_initial_backdrops(&self,
|
||||||
|
core: &RendererCore<D>,
|
||||||
|
backdrops_buffer_id: BufferID,
|
||||||
|
backdrops: &[BackdropInfoD3D11]) {
|
||||||
|
let backdrops_buffer = core.allocator.get_buffer(backdrops_buffer_id);
|
||||||
|
core.device.upload_to_buffer(backdrops_buffer, 0, backdrops, BufferTarget::Storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bin_segments(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
microlines_storage: &MicrolinesBufferIDsD3D11,
|
||||||
|
propagate_metadata_buffer_ids: &PropagateMetadataBufferIDsD3D11,
|
||||||
|
tiles_d3d11_buffer_id: BufferID)
|
||||||
|
-> Option<FillBufferInfoD3D11> {
|
||||||
|
let bin_program = &self.programs.bin_program;
|
||||||
|
|
||||||
|
let fill_vertex_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<Fill>(&core.device,
|
||||||
|
self.allocated_fill_count as u64,
|
||||||
|
BufferTag("Fill"));
|
||||||
|
let fill_indirect_draw_params_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<u32>(&core.device,
|
||||||
|
8,
|
||||||
|
BufferTag("FillIndirectDrawParamsD3D11"));
|
||||||
|
|
||||||
|
let fill_vertex_buffer = core.allocator.get_buffer(fill_vertex_buffer_id);
|
||||||
|
let microlines_buffer = core.allocator.get_buffer(microlines_storage.buffer_id);
|
||||||
|
let tiles_buffer = core.allocator.get_buffer(tiles_d3d11_buffer_id);
|
||||||
|
let propagate_metadata_buffer =
|
||||||
|
core.allocator.get_buffer(propagate_metadata_buffer_ids.propagate_metadata);
|
||||||
|
let backdrops_buffer = core.allocator.get_buffer(propagate_metadata_buffer_ids.backdrops);
|
||||||
|
|
||||||
|
let fill_indirect_draw_params_buffer =
|
||||||
|
core.allocator.get_buffer(fill_indirect_draw_params_buffer_id);
|
||||||
|
let indirect_draw_params = [6, 0, 0, 0, 0, microlines_storage.count, 0, 0];
|
||||||
|
core.device.upload_to_buffer::<u32>(&fill_indirect_draw_params_buffer,
|
||||||
|
0,
|
||||||
|
&indirect_draw_params,
|
||||||
|
BufferTarget::Storage);
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let compute_dimensions = ComputeDimensions {
|
||||||
|
x: (microlines_storage.count + 63) / 64,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
core.device.dispatch_compute(compute_dimensions, &ComputeState {
|
||||||
|
program: &bin_program.program,
|
||||||
|
textures: &[],
|
||||||
|
uniforms: &[
|
||||||
|
(&bin_program.microline_count_uniform,
|
||||||
|
UniformData::Int(microlines_storage.count as i32)),
|
||||||
|
(&bin_program.max_fill_count_uniform,
|
||||||
|
UniformData::Int(self.allocated_fill_count as i32)),
|
||||||
|
],
|
||||||
|
images: &[],
|
||||||
|
storage_buffers: &[
|
||||||
|
(&bin_program.microlines_storage_buffer, microlines_buffer),
|
||||||
|
(&bin_program.metadata_storage_buffer, propagate_metadata_buffer),
|
||||||
|
(&bin_program.indirect_draw_params_storage_buffer,
|
||||||
|
fill_indirect_draw_params_buffer),
|
||||||
|
(&bin_program.fills_storage_buffer, fill_vertex_buffer),
|
||||||
|
(&bin_program.tiles_storage_buffer, tiles_buffer),
|
||||||
|
(&bin_program.backdrops_storage_buffer, backdrops_buffer),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().bin_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
let indirect_draw_params_receiver =
|
||||||
|
core.device.read_buffer(fill_indirect_draw_params_buffer,
|
||||||
|
BufferTarget::Storage,
|
||||||
|
0..32);
|
||||||
|
let indirect_draw_params = core.device.recv_buffer(&indirect_draw_params_receiver);
|
||||||
|
let indirect_draw_params: &[u32] = indirect_draw_params.as_slice_of().unwrap();
|
||||||
|
|
||||||
|
let needed_fill_count =
|
||||||
|
indirect_draw_params[FILL_INDIRECT_DRAW_PARAMS_INSTANCE_COUNT_INDEX];
|
||||||
|
if needed_fill_count > self.allocated_fill_count {
|
||||||
|
self.allocated_fill_count = needed_fill_count.next_power_of_two();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.stats.fill_count += needed_fill_count as usize;
|
||||||
|
|
||||||
|
Some(FillBufferInfoD3D11 { fill_vertex_buffer_id, fill_indirect_draw_params_buffer_id })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn upload_scene(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
draw_segments: &SegmentsD3D11,
|
||||||
|
clip_segments: &SegmentsD3D11) {
|
||||||
|
self.scene_buffers.upload(&mut core.allocator, &core.device, draw_segments, clip_segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_tiles(&mut self, core: &mut RendererCore<D>, tile_count: u32) -> BufferID {
|
||||||
|
core.allocator.allocate_buffer::<TileD3D11>(&core.device,
|
||||||
|
tile_count as u64,
|
||||||
|
BufferTag("TileD3D11"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dice_segments(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
dice_metadata: &[DiceMetadataD3D11],
|
||||||
|
batch_segment_count: u32,
|
||||||
|
path_source: PathSource,
|
||||||
|
transform: Transform2F)
|
||||||
|
-> Option<MicrolinesBufferIDsD3D11> {
|
||||||
|
let dice_program = &self.programs.dice_program;
|
||||||
|
|
||||||
|
let microlines_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<MicrolineD3D11>(&core.device,
|
||||||
|
self.allocated_microline_count as u64,
|
||||||
|
BufferTag("MicrolineD3D11"));
|
||||||
|
let dice_metadata_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<DiceMetadataD3D11>(&core.device,
|
||||||
|
dice_metadata.len() as u64,
|
||||||
|
BufferTag("DiceMetadataD3D11"));
|
||||||
|
let dice_indirect_draw_params_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<u32>(&core.device,
|
||||||
|
8,
|
||||||
|
BufferTag("DiceIndirectDrawParamsD3D11"));
|
||||||
|
|
||||||
|
let microlines_buffer = core.allocator.get_buffer(microlines_buffer_id);
|
||||||
|
let dice_metadata_storage_buffer = core.allocator.get_buffer(dice_metadata_buffer_id);
|
||||||
|
let dice_indirect_draw_params_buffer =
|
||||||
|
core.allocator.get_buffer(dice_indirect_draw_params_buffer_id);
|
||||||
|
|
||||||
|
let scene_buffers = &self.scene_buffers;
|
||||||
|
let scene_source_buffers = match path_source {
|
||||||
|
PathSource::Draw => &scene_buffers.draw,
|
||||||
|
PathSource::Clip => &scene_buffers.clip,
|
||||||
|
};
|
||||||
|
let SceneSourceBuffers {
|
||||||
|
points_buffer: points_buffer_id,
|
||||||
|
point_indices_buffer: point_indices_buffer_id,
|
||||||
|
point_indices_count,
|
||||||
|
..
|
||||||
|
} = *scene_source_buffers;
|
||||||
|
|
||||||
|
let points_buffer =
|
||||||
|
core.allocator.get_buffer(points_buffer_id.expect("Where's the points buffer?"));
|
||||||
|
let point_indices_buffer =
|
||||||
|
core.allocator
|
||||||
|
.get_buffer(point_indices_buffer_id.expect("Where's the point indices buffer?"));
|
||||||
|
|
||||||
|
core.device.upload_to_buffer(dice_indirect_draw_params_buffer,
|
||||||
|
0,
|
||||||
|
&[0, 0, 0, 0, point_indices_count, 0, 0, 0],
|
||||||
|
BufferTarget::Storage);
|
||||||
|
core.device.upload_to_buffer(dice_metadata_storage_buffer,
|
||||||
|
0,
|
||||||
|
dice_metadata,
|
||||||
|
BufferTarget::Storage);
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let workgroup_count = (batch_segment_count + DICE_WORKGROUP_SIZE - 1) /
|
||||||
|
DICE_WORKGROUP_SIZE;
|
||||||
|
let compute_dimensions = ComputeDimensions { x: workgroup_count, y: 1, z: 1 };
|
||||||
|
|
||||||
|
core.device.dispatch_compute(compute_dimensions, &ComputeState {
|
||||||
|
program: &dice_program.program,
|
||||||
|
textures: &[],
|
||||||
|
uniforms: &[
|
||||||
|
(&dice_program.transform_uniform, UniformData::Mat2(transform.matrix.0)),
|
||||||
|
(&dice_program.translation_uniform, UniformData::Vec2(transform.vector.0)),
|
||||||
|
(&dice_program.path_count_uniform,
|
||||||
|
UniformData::Int(dice_metadata.len() as i32)),
|
||||||
|
(&dice_program.last_batch_segment_index_uniform,
|
||||||
|
UniformData::Int(batch_segment_count as i32)),
|
||||||
|
(&dice_program.max_microline_count_uniform,
|
||||||
|
UniformData::Int(self.allocated_microline_count as i32)),
|
||||||
|
],
|
||||||
|
images: &[],
|
||||||
|
storage_buffers: &[
|
||||||
|
(&dice_program.compute_indirect_params_storage_buffer,
|
||||||
|
dice_indirect_draw_params_buffer),
|
||||||
|
(&dice_program.points_storage_buffer, points_buffer),
|
||||||
|
(&dice_program.input_indices_storage_buffer, point_indices_buffer),
|
||||||
|
(&dice_program.microlines_storage_buffer, microlines_buffer),
|
||||||
|
(&dice_program.dice_metadata_storage_buffer, &dice_metadata_storage_buffer),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().dice_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
let indirect_compute_params_receiver =
|
||||||
|
core.device.read_buffer(&dice_indirect_draw_params_buffer,
|
||||||
|
BufferTarget::Storage,
|
||||||
|
0..32);
|
||||||
|
let indirect_compute_params = core.device.recv_buffer(&indirect_compute_params_receiver);
|
||||||
|
let indirect_compute_params: &[u32] = indirect_compute_params.as_slice_of().unwrap();
|
||||||
|
|
||||||
|
core.allocator.free_buffer(dice_metadata_buffer_id);
|
||||||
|
core.allocator.free_buffer(dice_indirect_draw_params_buffer_id);
|
||||||
|
|
||||||
|
let microline_count =
|
||||||
|
indirect_compute_params[BIN_INDIRECT_DRAW_PARAMS_MICROLINE_COUNT_INDEX];
|
||||||
|
if microline_count > self.allocated_microline_count {
|
||||||
|
self.allocated_microline_count = microline_count.next_power_of_two();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(MicrolinesBufferIDsD3D11 { buffer_id: microlines_buffer_id, count: microline_count })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_fills(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
fill_storage_info: &FillBufferInfoD3D11,
|
||||||
|
tiles_d3d11_buffer_id: BufferID,
|
||||||
|
alpha_tiles_buffer_id: BufferID,
|
||||||
|
propagate_tiles_info: &PropagateTilesInfoD3D11) {
|
||||||
|
let &FillBufferInfoD3D11 {
|
||||||
|
fill_vertex_buffer_id,
|
||||||
|
fill_indirect_draw_params_buffer_id: _,
|
||||||
|
} = fill_storage_info;
|
||||||
|
let &PropagateTilesInfoD3D11 { ref alpha_tile_range } = propagate_tiles_info;
|
||||||
|
|
||||||
|
let fill_program = &self.programs.fill_program;
|
||||||
|
let fill_vertex_buffer = core.allocator.get_buffer(fill_vertex_buffer_id);
|
||||||
|
|
||||||
|
let mask_storage = core.mask_storage.as_ref().expect("Where's the mask storage?");
|
||||||
|
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
||||||
|
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
||||||
|
let image_texture = core.device.framebuffer_texture(mask_framebuffer);
|
||||||
|
|
||||||
|
let tiles_d3d11_buffer = core.allocator.get_buffer(tiles_d3d11_buffer_id);
|
||||||
|
let alpha_tiles_buffer = core.allocator.get_buffer(alpha_tiles_buffer_id);
|
||||||
|
|
||||||
|
let area_lut_texture = core.allocator.get_texture(core.area_lut_texture_id);
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
// This setup is an annoying workaround for the 64K limit of compute invocation in OpenGL.
|
||||||
|
let alpha_tile_count = alpha_tile_range.end - alpha_tile_range.start;
|
||||||
|
let dimensions = ComputeDimensions {
|
||||||
|
x: alpha_tile_count.min(1 << 15) as u32,
|
||||||
|
y: ((alpha_tile_count + (1 << 15) - 1) >> 15) as u32,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
core.device.dispatch_compute(dimensions, &ComputeState {
|
||||||
|
program: &fill_program.program,
|
||||||
|
textures: &[(&fill_program.area_lut_texture, area_lut_texture)],
|
||||||
|
images: &[(&fill_program.dest_image, image_texture, ImageAccess::ReadWrite)],
|
||||||
|
uniforms: &[
|
||||||
|
(&fill_program.alpha_tile_range_uniform,
|
||||||
|
UniformData::IVec2(I32x2::new(alpha_tile_range.start as i32,
|
||||||
|
alpha_tile_range.end as i32))),
|
||||||
|
],
|
||||||
|
storage_buffers: &[
|
||||||
|
(&fill_program.fills_storage_buffer, fill_vertex_buffer),
|
||||||
|
(&fill_program.tiles_storage_buffer, tiles_d3d11_buffer),
|
||||||
|
(&fill_program.alpha_tiles_storage_buffer, &alpha_tiles_buffer),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().fill_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
core.framebuffer_flags.insert(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn prepare_and_draw_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
batch: &DrawTileBatchD3D11) {
|
||||||
|
let tile_batch_id = batch.tile_batch_data.batch_id;
|
||||||
|
self.prepare_tiles(core, &batch.tile_batch_data);
|
||||||
|
let batch_info = self.tile_batch_info[tile_batch_id.0 as usize].clone();
|
||||||
|
self.draw_tiles(core,
|
||||||
|
batch_info.tiles_d3d11_buffer_id,
|
||||||
|
batch_info.first_tile_map_buffer_id,
|
||||||
|
batch.color_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes backdrops, performs clipping, and populates Z buffers on GPU.
|
||||||
|
pub(crate) fn prepare_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
batch: &TileBatchDataD3D11) {
|
||||||
|
core.stats.total_tile_count += batch.tile_count as usize;
|
||||||
|
|
||||||
|
// Upload tiles to GPU or allocate them as appropriate.
|
||||||
|
let tiles_d3d11_buffer_id = self.allocate_tiles(core, batch.tile_count);
|
||||||
|
|
||||||
|
// Fetch and/or allocate clip storage as needed.
|
||||||
|
let clip_buffer_ids = match batch.clipped_path_info {
|
||||||
|
Some(ref clipped_path_info) => {
|
||||||
|
let clip_batch_id = clipped_path_info.clip_batch_id;
|
||||||
|
let clip_tile_batch_info = &self.tile_batch_info[clip_batch_id.0 as usize];
|
||||||
|
let metadata = clip_tile_batch_info.propagate_metadata_buffer_id;
|
||||||
|
let tiles = clip_tile_batch_info.tiles_d3d11_buffer_id;
|
||||||
|
Some(ClipBufferIDs { metadata: Some(metadata), tiles })
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allocate a Z-buffer.
|
||||||
|
let z_buffer_id = self.allocate_z_buffer(core);
|
||||||
|
|
||||||
|
// Propagate backdrops, bin fills, render fills, and/or perform clipping on GPU if
|
||||||
|
// necessary.
|
||||||
|
// Allocate space for tile lists.
|
||||||
|
let first_tile_map_buffer_id = self.allocate_first_tile_map(core);
|
||||||
|
|
||||||
|
let propagate_metadata_buffer_ids =
|
||||||
|
self.upload_propagate_metadata(core,
|
||||||
|
&batch.prepare_info.propagate_metadata,
|
||||||
|
&batch.prepare_info.backdrops);
|
||||||
|
|
||||||
|
// Dice (flatten) segments into microlines. We might have to do this twice if our
|
||||||
|
// first attempt runs out of space in the storage buffer.
|
||||||
|
let mut microlines_storage = None;
|
||||||
|
for _ in 0..2 {
|
||||||
|
microlines_storage = self.dice_segments(core,
|
||||||
|
&batch.prepare_info.dice_metadata,
|
||||||
|
batch.segment_count,
|
||||||
|
batch.path_source,
|
||||||
|
batch.prepare_info.transform);
|
||||||
|
if microlines_storage.is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let microlines_storage =
|
||||||
|
microlines_storage.expect("Ran out of space for microlines when dicing!");
|
||||||
|
|
||||||
|
// Initialize tiles, and bin segments. We might have to do this twice if our first
|
||||||
|
// attempt runs out of space in the fill buffer.
|
||||||
|
let mut fill_buffer_info = None;
|
||||||
|
for _ in 0..2 {
|
||||||
|
self.bound(core,
|
||||||
|
tiles_d3d11_buffer_id,
|
||||||
|
batch.tile_count,
|
||||||
|
&batch.prepare_info.tile_path_info);
|
||||||
|
|
||||||
|
self.upload_initial_backdrops(core,
|
||||||
|
propagate_metadata_buffer_ids.backdrops,
|
||||||
|
&batch.prepare_info.backdrops);
|
||||||
|
|
||||||
|
fill_buffer_info = self.bin_segments(core,
|
||||||
|
µlines_storage,
|
||||||
|
&propagate_metadata_buffer_ids,
|
||||||
|
tiles_d3d11_buffer_id);
|
||||||
|
if fill_buffer_info.is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let fill_buffer_info =
|
||||||
|
fill_buffer_info.expect("Ran out of space for fills when binning!");
|
||||||
|
|
||||||
|
core.allocator.free_buffer(microlines_storage.buffer_id);
|
||||||
|
|
||||||
|
// TODO(pcwalton): If we run out of space for alpha tile indices, propagate
|
||||||
|
// multiple times.
|
||||||
|
|
||||||
|
let alpha_tiles_buffer_id = self.allocate_alpha_tile_info(core, batch.tile_count);
|
||||||
|
|
||||||
|
let propagate_tiles_info =
|
||||||
|
self.propagate_tiles(core,
|
||||||
|
batch.prepare_info.backdrops.len() as u32,
|
||||||
|
tiles_d3d11_buffer_id,
|
||||||
|
fill_buffer_info.fill_indirect_draw_params_buffer_id,
|
||||||
|
z_buffer_id,
|
||||||
|
first_tile_map_buffer_id,
|
||||||
|
alpha_tiles_buffer_id,
|
||||||
|
&propagate_metadata_buffer_ids,
|
||||||
|
clip_buffer_ids.as_ref());
|
||||||
|
|
||||||
|
core.allocator.free_buffer(propagate_metadata_buffer_ids.backdrops);
|
||||||
|
|
||||||
|
// FIXME(pcwalton): Don't unconditionally pass true for copying here.
|
||||||
|
core.reallocate_alpha_tile_pages_if_necessary(true);
|
||||||
|
self.draw_fills(core,
|
||||||
|
&fill_buffer_info,
|
||||||
|
tiles_d3d11_buffer_id,
|
||||||
|
alpha_tiles_buffer_id,
|
||||||
|
&propagate_tiles_info);
|
||||||
|
|
||||||
|
core.allocator.free_buffer(fill_buffer_info.fill_vertex_buffer_id);
|
||||||
|
core.allocator.free_buffer(fill_buffer_info.fill_indirect_draw_params_buffer_id);
|
||||||
|
core.allocator.free_buffer(alpha_tiles_buffer_id);
|
||||||
|
|
||||||
|
// FIXME(pcwalton): This seems like the wrong place to do this...
|
||||||
|
self.sort_tiles(core, tiles_d3d11_buffer_id, first_tile_map_buffer_id, z_buffer_id);
|
||||||
|
|
||||||
|
// Record tile batch info.
|
||||||
|
self.tile_batch_info.insert(batch.batch_id.0 as usize, TileBatchInfoD3D11 {
|
||||||
|
tile_count: batch.tile_count,
|
||||||
|
z_buffer_id,
|
||||||
|
tiles_d3d11_buffer_id,
|
||||||
|
propagate_metadata_buffer_id: propagate_metadata_buffer_ids.propagate_metadata,
|
||||||
|
first_tile_map_buffer_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
column_count: u32,
|
||||||
|
tiles_d3d11_buffer_id: BufferID,
|
||||||
|
fill_indirect_draw_params_buffer_id: BufferID,
|
||||||
|
z_buffer_id: BufferID,
|
||||||
|
first_tile_map_buffer_id: BufferID,
|
||||||
|
alpha_tiles_buffer_id: BufferID,
|
||||||
|
propagate_metadata_buffer_ids: &PropagateMetadataBufferIDsD3D11,
|
||||||
|
clip_buffer_ids: Option<&ClipBufferIDs>)
|
||||||
|
-> PropagateTilesInfoD3D11 {
|
||||||
|
let propagate_program = &self.programs.propagate_program;
|
||||||
|
|
||||||
|
let tiles_d3d11_buffer = core.allocator.get_buffer(tiles_d3d11_buffer_id);
|
||||||
|
let propagate_metadata_storage_buffer =
|
||||||
|
core.allocator.get_buffer(propagate_metadata_buffer_ids.propagate_metadata);
|
||||||
|
let backdrops_storage_buffer =
|
||||||
|
core.allocator.get_buffer(propagate_metadata_buffer_ids.backdrops);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Zero out the Z-buffer on GPU?
|
||||||
|
let z_buffer = core.allocator.get_buffer(z_buffer_id);
|
||||||
|
let z_buffer_size = core.tile_size();
|
||||||
|
let tile_area = z_buffer_size.area() as usize;
|
||||||
|
core.device.upload_to_buffer(z_buffer, 0, &vec![0i32; tile_area], BufferTarget::Storage);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Initialize the first tiles buffer on GPU?
|
||||||
|
let first_tile_map_storage_buffer = core.allocator.get_buffer(first_tile_map_buffer_id);
|
||||||
|
core.device.upload_to_buffer::<FirstTileD3D11>(&first_tile_map_storage_buffer,
|
||||||
|
0,
|
||||||
|
&vec![FirstTileD3D11::default(); tile_area],
|
||||||
|
BufferTarget::Storage);
|
||||||
|
|
||||||
|
let alpha_tiles_storage_buffer = core.allocator.get_buffer(alpha_tiles_buffer_id);
|
||||||
|
let fill_indirect_draw_params_buffer =
|
||||||
|
core.allocator.get_buffer(fill_indirect_draw_params_buffer_id);
|
||||||
|
|
||||||
|
let mut storage_buffers = vec![
|
||||||
|
(&propagate_program.draw_metadata_storage_buffer, propagate_metadata_storage_buffer),
|
||||||
|
(&propagate_program.backdrops_storage_buffer, &backdrops_storage_buffer),
|
||||||
|
(&propagate_program.draw_tiles_storage_buffer, tiles_d3d11_buffer),
|
||||||
|
(&propagate_program.z_buffer_storage_buffer, z_buffer),
|
||||||
|
(&propagate_program.first_tile_map_storage_buffer, first_tile_map_storage_buffer),
|
||||||
|
(&propagate_program.indirect_draw_params_storage_buffer,
|
||||||
|
fill_indirect_draw_params_buffer),
|
||||||
|
(&propagate_program.alpha_tiles_storage_buffer, alpha_tiles_storage_buffer),
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Some(clip_buffer_ids) = clip_buffer_ids {
|
||||||
|
let clip_metadata_buffer_id =
|
||||||
|
clip_buffer_ids.metadata.expect("Where's the clip metadata storage?");
|
||||||
|
let clip_metadata_buffer = core.allocator.get_buffer(clip_metadata_buffer_id);
|
||||||
|
let clip_tile_buffer = core.allocator.get_buffer(clip_buffer_ids.tiles);
|
||||||
|
storage_buffers.push((&propagate_program.clip_metadata_storage_buffer,
|
||||||
|
clip_metadata_buffer));
|
||||||
|
storage_buffers.push((&propagate_program.clip_tiles_storage_buffer, clip_tile_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let dimensions = ComputeDimensions {
|
||||||
|
x: (column_count + PROPAGATE_WORKGROUP_SIZE - 1) / PROPAGATE_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
|
core.device.dispatch_compute(dimensions, &ComputeState {
|
||||||
|
program: &propagate_program.program,
|
||||||
|
textures: &[],
|
||||||
|
images: &[],
|
||||||
|
uniforms: &[
|
||||||
|
(&propagate_program.framebuffer_tile_size_uniform,
|
||||||
|
UniformData::IVec2(core.framebuffer_tile_size().0)),
|
||||||
|
(&propagate_program.column_count_uniform, UniformData::Int(column_count as i32)),
|
||||||
|
(&propagate_program.first_alpha_tile_index_uniform,
|
||||||
|
UniformData::Int(core.alpha_tile_count as i32)),
|
||||||
|
],
|
||||||
|
storage_buffers: &storage_buffers,
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().other_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
let fill_indirect_draw_params_receiver =
|
||||||
|
core.device.read_buffer(&fill_indirect_draw_params_buffer,
|
||||||
|
BufferTarget::Storage,
|
||||||
|
0..32);
|
||||||
|
let fill_indirect_draw_params = core.device
|
||||||
|
.recv_buffer(&fill_indirect_draw_params_receiver);
|
||||||
|
let fill_indirect_draw_params: &[u32] = fill_indirect_draw_params.as_slice_of().unwrap();
|
||||||
|
|
||||||
|
let batch_alpha_tile_count =
|
||||||
|
fill_indirect_draw_params[FILL_INDIRECT_DRAW_PARAMS_ALPHA_TILE_COUNT_INDEX];
|
||||||
|
|
||||||
|
let alpha_tile_start = core.alpha_tile_count;
|
||||||
|
core.alpha_tile_count += batch_alpha_tile_count;
|
||||||
|
core.stats.alpha_tile_count += batch_alpha_tile_count as usize;
|
||||||
|
let alpha_tile_end = core.alpha_tile_count;
|
||||||
|
|
||||||
|
PropagateTilesInfoD3D11 { alpha_tile_range: alpha_tile_start..alpha_tile_end }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
tiles_d3d11_buffer_id: BufferID,
|
||||||
|
first_tile_map_buffer_id: BufferID,
|
||||||
|
z_buffer_id: BufferID) {
|
||||||
|
let sort_program = &self.programs.sort_program;
|
||||||
|
|
||||||
|
let tiles_d3d11_buffer = core.allocator.get_buffer(tiles_d3d11_buffer_id);
|
||||||
|
let first_tile_map_buffer = core.allocator.get_buffer(first_tile_map_buffer_id);
|
||||||
|
let z_buffer = core.allocator.get_buffer(z_buffer_id);
|
||||||
|
|
||||||
|
let tile_count = core.framebuffer_tile_size().area();
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let dimensions = ComputeDimensions {
|
||||||
|
x: (tile_count as u32 + SORT_WORKGROUP_SIZE - 1) / SORT_WORKGROUP_SIZE,
|
||||||
|
y: 1,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
|
core.device.dispatch_compute(dimensions, &ComputeState {
|
||||||
|
program: &sort_program.program,
|
||||||
|
textures: &[],
|
||||||
|
images: &[],
|
||||||
|
uniforms: &[(&sort_program.tile_count_uniform, UniformData::Int(tile_count))],
|
||||||
|
storage_buffers: &[
|
||||||
|
(&sort_program.tiles_storage_buffer, tiles_d3d11_buffer),
|
||||||
|
(&sort_program.first_tile_map_storage_buffer, first_tile_map_buffer),
|
||||||
|
(&sort_program.z_buffer_storage_buffer, z_buffer),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().other_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_first_tile_map(&mut self, core: &mut RendererCore<D>) -> BufferID {
|
||||||
|
core.allocator.allocate_buffer::<FirstTileD3D11>(&core.device,
|
||||||
|
core.tile_size().area() as u64,
|
||||||
|
BufferTag("FirstTileD3D11"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_alpha_tile_info(&mut self, core: &mut RendererCore<D>, index_count: u32)
|
||||||
|
-> BufferID {
|
||||||
|
core.allocator.allocate_buffer::<AlphaTileD3D11>(&core.device,
|
||||||
|
index_count as u64,
|
||||||
|
BufferTag("AlphaTileD3D11"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocate_z_buffer(&mut self, core: &mut RendererCore<D>) -> BufferID {
|
||||||
|
core.allocator.allocate_buffer::<i32>(&core.device,
|
||||||
|
core.tile_size().area() as u64,
|
||||||
|
BufferTag("ZBufferD3D11"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn draw_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
tiles_d3d11_buffer_id: BufferID,
|
||||||
|
first_tile_map_buffer_id: BufferID,
|
||||||
|
color_texture_0: Option<TileBatchTexture>) {
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let tile_program = &self.programs.tile_program;
|
||||||
|
|
||||||
|
let (mut textures, mut uniforms, mut images) = (vec![], vec![], vec![]);
|
||||||
|
|
||||||
|
core.set_uniforms_for_drawing_tiles(&tile_program.common,
|
||||||
|
&mut textures,
|
||||||
|
&mut uniforms,
|
||||||
|
color_texture_0);
|
||||||
|
|
||||||
|
uniforms.push((&tile_program.framebuffer_tile_size_uniform,
|
||||||
|
UniformData::IVec2(core.framebuffer_tile_size().0)));
|
||||||
|
|
||||||
|
match core.draw_render_target() {
|
||||||
|
RenderTarget::Default => panic!("Can't draw to the default framebuffer with compute!"),
|
||||||
|
RenderTarget::Framebuffer(ref framebuffer) => {
|
||||||
|
let dest_texture = core.device.framebuffer_texture(framebuffer);
|
||||||
|
images.push((&tile_program.dest_image, dest_texture, ImageAccess::ReadWrite));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let clear_color = core.clear_color_for_draw_operation();
|
||||||
|
match clear_color {
|
||||||
|
None => {
|
||||||
|
uniforms.push((&tile_program.load_action_uniform,
|
||||||
|
UniformData::Int(LOAD_ACTION_LOAD)));
|
||||||
|
uniforms.push((&tile_program.clear_color_uniform,
|
||||||
|
UniformData::Vec4(F32x4::default())));
|
||||||
|
}
|
||||||
|
Some(clear_color) => {
|
||||||
|
uniforms.push((&tile_program.load_action_uniform,
|
||||||
|
UniformData::Int(LOAD_ACTION_CLEAR)));
|
||||||
|
uniforms.push((&tile_program.clear_color_uniform,
|
||||||
|
UniformData::Vec4(clear_color.0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tiles_d3d11_buffer = core.allocator.get_buffer(tiles_d3d11_buffer_id);
|
||||||
|
let first_tile_map_storage_buffer = core.allocator.get_buffer(first_tile_map_buffer_id);
|
||||||
|
|
||||||
|
let framebuffer_tile_size = core.framebuffer_tile_size().0;
|
||||||
|
let compute_dimensions = ComputeDimensions {
|
||||||
|
x: framebuffer_tile_size.x() as u32,
|
||||||
|
y: framebuffer_tile_size.y() as u32,
|
||||||
|
z: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
core.device.dispatch_compute(compute_dimensions, &ComputeState {
|
||||||
|
program: &tile_program.common.program,
|
||||||
|
textures: &textures,
|
||||||
|
images: &images,
|
||||||
|
storage_buffers: &[
|
||||||
|
(&tile_program.tiles_storage_buffer, tiles_d3d11_buffer),
|
||||||
|
(&tile_program.first_tile_map_storage_buffer, first_tile_map_storage_buffer),
|
||||||
|
],
|
||||||
|
uniforms: &uniforms,
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().composite_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
core.preserve_draw_framebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn end_frame(&mut self, core: &mut RendererCore<D>) {
|
||||||
|
self.free_tile_batch_buffers(core);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free_tile_batch_buffers(&mut self, core: &mut RendererCore<D>) {
|
||||||
|
for (_, tile_batch_info) in self.tile_batch_info.drain() {
|
||||||
|
core.allocator.free_buffer(tile_batch_info.z_buffer_id);
|
||||||
|
core.allocator.free_buffer(tile_batch_info.tiles_d3d11_buffer_id);
|
||||||
|
core.allocator.free_buffer(tile_batch_info.propagate_metadata_buffer_id);
|
||||||
|
core.allocator.free_buffer(tile_batch_info.first_tile_map_buffer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer data
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct TileBatchInfoD3D11 {
|
||||||
|
tile_count: u32,
|
||||||
|
z_buffer_id: BufferID,
|
||||||
|
tiles_d3d11_buffer_id: BufferID,
|
||||||
|
propagate_metadata_buffer_id: BufferID,
|
||||||
|
first_tile_map_buffer_id: BufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct FillBufferInfoD3D11 {
|
||||||
|
fill_vertex_buffer_id: BufferID,
|
||||||
|
fill_indirect_draw_params_buffer_id: BufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PropagateMetadataBufferIDsD3D11 {
|
||||||
|
propagate_metadata: BufferID,
|
||||||
|
backdrops: BufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MicrolinesBufferIDsD3D11 {
|
||||||
|
buffer_id: BufferID,
|
||||||
|
count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct ClipBufferIDs {
|
||||||
|
metadata: Option<BufferID>,
|
||||||
|
tiles: BufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SceneBuffers {
|
||||||
|
draw: SceneSourceBuffers,
|
||||||
|
clip: SceneSourceBuffers,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SceneSourceBuffers {
|
||||||
|
points_buffer: Option<BufferID>,
|
||||||
|
points_capacity: u32,
|
||||||
|
point_indices_buffer: Option<BufferID>,
|
||||||
|
point_indices_count: u32,
|
||||||
|
point_indices_capacity: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PropagateTilesInfoD3D11 {
|
||||||
|
alpha_tile_range: Range<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SceneBuffers {
|
||||||
|
fn new() -> SceneBuffers {
|
||||||
|
SceneBuffers { draw: SceneSourceBuffers::new(), clip: SceneSourceBuffers::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload<D>(&mut self,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
device: &D,
|
||||||
|
draw_segments: &SegmentsD3D11,
|
||||||
|
clip_segments: &SegmentsD3D11)
|
||||||
|
where D: Device {
|
||||||
|
self.draw.upload(allocator, device, draw_segments);
|
||||||
|
self.clip.upload(allocator, device, clip_segments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SceneSourceBuffers {
|
||||||
|
fn new() -> SceneSourceBuffers {
|
||||||
|
SceneSourceBuffers {
|
||||||
|
points_buffer: None,
|
||||||
|
points_capacity: 0,
|
||||||
|
point_indices_buffer: None,
|
||||||
|
point_indices_count: 0,
|
||||||
|
point_indices_capacity: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload<D>(&mut self,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
device: &D,
|
||||||
|
segments: &SegmentsD3D11)
|
||||||
|
where D: Device {
|
||||||
|
let needed_points_capacity = (segments.points.len() as u32).next_power_of_two();
|
||||||
|
let needed_point_indices_capacity = (segments.indices.len() as u32).next_power_of_two();
|
||||||
|
if self.points_capacity < needed_points_capacity {
|
||||||
|
self.points_buffer =
|
||||||
|
Some(allocator.allocate_buffer::<Vector2F>(device,
|
||||||
|
needed_points_capacity as u64,
|
||||||
|
BufferTag("PointsD3D11")));
|
||||||
|
self.points_capacity = needed_points_capacity;
|
||||||
|
}
|
||||||
|
if self.point_indices_capacity < needed_point_indices_capacity {
|
||||||
|
self.point_indices_buffer = Some(allocator.allocate_buffer::<SegmentIndicesD3D11>(
|
||||||
|
device,
|
||||||
|
needed_point_indices_capacity as u64,
|
||||||
|
BufferTag("PointIndicesD3D11")));
|
||||||
|
self.point_indices_capacity = needed_point_indices_capacity;
|
||||||
|
}
|
||||||
|
device.upload_to_buffer(allocator.get_buffer(self.points_buffer.unwrap()),
|
||||||
|
0,
|
||||||
|
&segments.points,
|
||||||
|
BufferTarget::Storage);
|
||||||
|
device.upload_to_buffer(allocator.get_buffer(self.point_indices_buffer.unwrap()),
|
||||||
|
0,
|
||||||
|
&segments.indices,
|
||||||
|
BufferTarget::Storage);
|
||||||
|
self.point_indices_count = segments.indices.len() as u32;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,321 @@
|
||||||
|
// pathfinder/renderer/src/gpu/d3d11/shaders.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
use crate::gpu::shaders::TileProgramCommon;
|
||||||
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
|
use pathfinder_gpu::{ComputeDimensions, Device};
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
|
||||||
|
pub const BOUND_WORKGROUP_SIZE: u32 = 64;
|
||||||
|
pub const DICE_WORKGROUP_SIZE: u32 = 64;
|
||||||
|
pub const BIN_WORKGROUP_SIZE: u32 = 64;
|
||||||
|
pub const PROPAGATE_WORKGROUP_SIZE: u32 = 64;
|
||||||
|
pub const SORT_WORKGROUP_SIZE: u32 = 64;
|
||||||
|
|
||||||
|
pub struct ProgramsD3D11<D> where D: Device {
|
||||||
|
pub bound_program: BoundProgramD3D11<D>,
|
||||||
|
pub dice_program: DiceProgramD3D11<D>,
|
||||||
|
pub bin_program: BinProgramD3D11<D>,
|
||||||
|
pub propagate_program: PropagateProgramD3D11<D>,
|
||||||
|
pub sort_program: SortProgramD3D11<D>,
|
||||||
|
pub fill_program: FillProgramD3D11<D>,
|
||||||
|
pub tile_program: TileProgramD3D11<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ProgramsD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D11<D> {
|
||||||
|
ProgramsD3D11 {
|
||||||
|
bound_program: BoundProgramD3D11::new(device, resources),
|
||||||
|
dice_program: DiceProgramD3D11::new(device, resources),
|
||||||
|
bin_program: BinProgramD3D11::new(device, resources),
|
||||||
|
propagate_program: PropagateProgramD3D11::new(device, resources),
|
||||||
|
sort_program: SortProgramD3D11::new(device, resources),
|
||||||
|
fill_program: FillProgramD3D11::new(device, resources),
|
||||||
|
tile_program: TileProgramD3D11::new(device, resources),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PropagateProgramD3D11<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub framebuffer_tile_size_uniform: D::Uniform,
|
||||||
|
pub column_count_uniform: D::Uniform,
|
||||||
|
pub first_alpha_tile_index_uniform: D::Uniform,
|
||||||
|
pub draw_metadata_storage_buffer: D::StorageBuffer,
|
||||||
|
pub clip_metadata_storage_buffer: D::StorageBuffer,
|
||||||
|
pub backdrops_storage_buffer: D::StorageBuffer,
|
||||||
|
pub draw_tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
pub clip_tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
pub z_buffer_storage_buffer: D::StorageBuffer,
|
||||||
|
pub first_tile_map_storage_buffer: D::StorageBuffer,
|
||||||
|
pub indirect_draw_params_storage_buffer: D::StorageBuffer,
|
||||||
|
pub alpha_tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> PropagateProgramD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> PropagateProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/propagate");
|
||||||
|
let local_size = ComputeDimensions { x: PROPAGATE_WORKGROUP_SIZE, y: 1, z: 1 };
|
||||||
|
device.set_compute_program_local_size(&mut program, local_size);
|
||||||
|
|
||||||
|
let framebuffer_tile_size_uniform = device.get_uniform(&program, "FramebufferTileSize");
|
||||||
|
let column_count_uniform = device.get_uniform(&program, "ColumnCount");
|
||||||
|
let first_alpha_tile_index_uniform = device.get_uniform(&program, "FirstAlphaTileIndex");
|
||||||
|
let draw_metadata_storage_buffer = device.get_storage_buffer(&program, "DrawMetadata", 0);
|
||||||
|
let clip_metadata_storage_buffer = device.get_storage_buffer(&program, "ClipMetadata", 1);
|
||||||
|
let backdrops_storage_buffer = device.get_storage_buffer(&program, "Backdrops", 2);
|
||||||
|
let draw_tiles_storage_buffer = device.get_storage_buffer(&program, "DrawTiles", 3);
|
||||||
|
let clip_tiles_storage_buffer = device.get_storage_buffer(&program, "ClipTiles", 4);
|
||||||
|
let z_buffer_storage_buffer = device.get_storage_buffer(&program, "ZBuffer", 5);
|
||||||
|
let first_tile_map_storage_buffer = device.get_storage_buffer(&program, "FirstTileMap", 6);
|
||||||
|
let indirect_draw_params_storage_buffer =
|
||||||
|
device.get_storage_buffer(&program, "IndirectDrawParams", 7);
|
||||||
|
let alpha_tiles_storage_buffer = device.get_storage_buffer(&program, "AlphaTiles", 8);
|
||||||
|
|
||||||
|
PropagateProgramD3D11 {
|
||||||
|
program,
|
||||||
|
framebuffer_tile_size_uniform,
|
||||||
|
column_count_uniform,
|
||||||
|
first_alpha_tile_index_uniform,
|
||||||
|
draw_metadata_storage_buffer,
|
||||||
|
clip_metadata_storage_buffer,
|
||||||
|
backdrops_storage_buffer,
|
||||||
|
draw_tiles_storage_buffer,
|
||||||
|
clip_tiles_storage_buffer,
|
||||||
|
z_buffer_storage_buffer,
|
||||||
|
first_tile_map_storage_buffer,
|
||||||
|
indirect_draw_params_storage_buffer,
|
||||||
|
alpha_tiles_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FillProgramD3D11<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub dest_image: D::ImageParameter,
|
||||||
|
pub area_lut_texture: D::TextureParameter,
|
||||||
|
pub alpha_tile_range_uniform: D::Uniform,
|
||||||
|
pub fills_storage_buffer: D::StorageBuffer,
|
||||||
|
pub tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
pub alpha_tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> FillProgramD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/fill");
|
||||||
|
let local_size = ComputeDimensions { x: TILE_WIDTH, y: TILE_HEIGHT / 4, z: 1 };
|
||||||
|
device.set_compute_program_local_size(&mut program, local_size);
|
||||||
|
|
||||||
|
let dest_image = device.get_image_parameter(&program, "Dest");
|
||||||
|
let area_lut_texture = device.get_texture_parameter(&program, "AreaLUT");
|
||||||
|
let alpha_tile_range_uniform = device.get_uniform(&program, "AlphaTileRange");
|
||||||
|
let fills_storage_buffer = device.get_storage_buffer(&program, "Fills", 0);
|
||||||
|
let tiles_storage_buffer = device.get_storage_buffer(&program, "Tiles", 1);
|
||||||
|
let alpha_tiles_storage_buffer = device.get_storage_buffer(&program, "AlphaTiles", 2);
|
||||||
|
|
||||||
|
FillProgramD3D11 {
|
||||||
|
program,
|
||||||
|
dest_image,
|
||||||
|
area_lut_texture,
|
||||||
|
alpha_tile_range_uniform,
|
||||||
|
fills_storage_buffer,
|
||||||
|
tiles_storage_buffer,
|
||||||
|
alpha_tiles_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TileProgramD3D11<D> where D: Device {
|
||||||
|
pub common: TileProgramCommon<D>,
|
||||||
|
pub load_action_uniform: D::Uniform,
|
||||||
|
pub clear_color_uniform: D::Uniform,
|
||||||
|
pub framebuffer_tile_size_uniform: D::Uniform,
|
||||||
|
pub dest_image: D::ImageParameter,
|
||||||
|
pub tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
pub first_tile_map_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TileProgramD3D11<D> where D: Device {
|
||||||
|
fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/tile");
|
||||||
|
device.set_compute_program_local_size(&mut program,
|
||||||
|
ComputeDimensions { x: 16, y: 4, z: 1 });
|
||||||
|
|
||||||
|
let load_action_uniform = device.get_uniform(&program, "LoadAction");
|
||||||
|
let clear_color_uniform = device.get_uniform(&program, "ClearColor");
|
||||||
|
let framebuffer_tile_size_uniform = device.get_uniform(&program, "FramebufferTileSize");
|
||||||
|
let dest_image = device.get_image_parameter(&program, "DestImage");
|
||||||
|
let tiles_storage_buffer = device.get_storage_buffer(&program, "Tiles", 0);
|
||||||
|
let first_tile_map_storage_buffer = device.get_storage_buffer(&program, "FirstTileMap", 1);
|
||||||
|
|
||||||
|
let common = TileProgramCommon::new(device, program);
|
||||||
|
TileProgramD3D11 {
|
||||||
|
common,
|
||||||
|
load_action_uniform,
|
||||||
|
clear_color_uniform,
|
||||||
|
framebuffer_tile_size_uniform,
|
||||||
|
dest_image,
|
||||||
|
tiles_storage_buffer,
|
||||||
|
first_tile_map_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BinProgramD3D11<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub microline_count_uniform: D::Uniform,
|
||||||
|
pub max_fill_count_uniform: D::Uniform,
|
||||||
|
pub microlines_storage_buffer: D::StorageBuffer,
|
||||||
|
pub metadata_storage_buffer: D::StorageBuffer,
|
||||||
|
pub indirect_draw_params_storage_buffer: D::StorageBuffer,
|
||||||
|
pub fills_storage_buffer: D::StorageBuffer,
|
||||||
|
pub tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
pub backdrops_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> BinProgramD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BinProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/bin");
|
||||||
|
let dimensions = ComputeDimensions { x: BIN_WORKGROUP_SIZE, y: 1, z: 1 };
|
||||||
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
|
let microline_count_uniform = device.get_uniform(&program, "MicrolineCount");
|
||||||
|
let max_fill_count_uniform = device.get_uniform(&program, "MaxFillCount");
|
||||||
|
|
||||||
|
let microlines_storage_buffer = device.get_storage_buffer(&program, "Microlines", 0);
|
||||||
|
let metadata_storage_buffer = device.get_storage_buffer(&program, "Metadata", 1);
|
||||||
|
let indirect_draw_params_storage_buffer =
|
||||||
|
device.get_storage_buffer(&program, "IndirectDrawParams", 2);
|
||||||
|
let fills_storage_buffer = device.get_storage_buffer(&program, "Fills", 3);
|
||||||
|
let tiles_storage_buffer = device.get_storage_buffer(&program, "Tiles", 4);
|
||||||
|
let backdrops_storage_buffer = device.get_storage_buffer(&program, "Backdrops", 5);
|
||||||
|
|
||||||
|
BinProgramD3D11 {
|
||||||
|
program,
|
||||||
|
microline_count_uniform,
|
||||||
|
max_fill_count_uniform,
|
||||||
|
metadata_storage_buffer,
|
||||||
|
indirect_draw_params_storage_buffer,
|
||||||
|
fills_storage_buffer,
|
||||||
|
tiles_storage_buffer,
|
||||||
|
microlines_storage_buffer,
|
||||||
|
backdrops_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiceProgramD3D11<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub transform_uniform: D::Uniform,
|
||||||
|
pub translation_uniform: D::Uniform,
|
||||||
|
pub path_count_uniform: D::Uniform,
|
||||||
|
pub last_batch_segment_index_uniform: D::Uniform,
|
||||||
|
pub max_microline_count_uniform: D::Uniform,
|
||||||
|
pub compute_indirect_params_storage_buffer: D::StorageBuffer,
|
||||||
|
pub dice_metadata_storage_buffer: D::StorageBuffer,
|
||||||
|
pub points_storage_buffer: D::StorageBuffer,
|
||||||
|
pub input_indices_storage_buffer: D::StorageBuffer,
|
||||||
|
pub microlines_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> DiceProgramD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DiceProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/dice");
|
||||||
|
let dimensions = ComputeDimensions { x: DICE_WORKGROUP_SIZE, y: 1, z: 1 };
|
||||||
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
|
let translation_uniform = device.get_uniform(&program, "Translation");
|
||||||
|
let path_count_uniform = device.get_uniform(&program, "PathCount");
|
||||||
|
let last_batch_segment_index_uniform = device.get_uniform(&program,
|
||||||
|
"LastBatchSegmentIndex");
|
||||||
|
let max_microline_count_uniform = device.get_uniform(&program, "MaxMicrolineCount");
|
||||||
|
|
||||||
|
let compute_indirect_params_storage_buffer =
|
||||||
|
device.get_storage_buffer(&program, "ComputeIndirectParams", 0);
|
||||||
|
let dice_metadata_storage_buffer = device.get_storage_buffer(&program, "DiceMetadata", 1);
|
||||||
|
let points_storage_buffer = device.get_storage_buffer(&program, "Points", 2);
|
||||||
|
let input_indices_storage_buffer = device.get_storage_buffer(&program, "InputIndices", 3);
|
||||||
|
let microlines_storage_buffer = device.get_storage_buffer(&program, "Microlines", 4);
|
||||||
|
|
||||||
|
DiceProgramD3D11 {
|
||||||
|
program,
|
||||||
|
transform_uniform,
|
||||||
|
translation_uniform,
|
||||||
|
path_count_uniform,
|
||||||
|
last_batch_segment_index_uniform,
|
||||||
|
max_microline_count_uniform,
|
||||||
|
compute_indirect_params_storage_buffer,
|
||||||
|
dice_metadata_storage_buffer,
|
||||||
|
points_storage_buffer,
|
||||||
|
input_indices_storage_buffer,
|
||||||
|
microlines_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BoundProgramD3D11<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub path_count_uniform: D::Uniform,
|
||||||
|
pub tile_count_uniform: D::Uniform,
|
||||||
|
pub tile_path_info_storage_buffer: D::StorageBuffer,
|
||||||
|
pub tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> BoundProgramD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BoundProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/bound");
|
||||||
|
let dimensions = ComputeDimensions { x: BOUND_WORKGROUP_SIZE, y: 1, z: 1 };
|
||||||
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
|
let path_count_uniform = device.get_uniform(&program, "PathCount");
|
||||||
|
let tile_count_uniform = device.get_uniform(&program, "TileCount");
|
||||||
|
|
||||||
|
let tile_path_info_storage_buffer = device.get_storage_buffer(&program, "TilePathInfo", 0);
|
||||||
|
let tiles_storage_buffer = device.get_storage_buffer(&program, "Tiles", 1);
|
||||||
|
|
||||||
|
BoundProgramD3D11 {
|
||||||
|
program,
|
||||||
|
path_count_uniform,
|
||||||
|
tile_count_uniform,
|
||||||
|
tile_path_info_storage_buffer,
|
||||||
|
tiles_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SortProgramD3D11<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub tile_count_uniform: D::Uniform,
|
||||||
|
pub tiles_storage_buffer: D::StorageBuffer,
|
||||||
|
pub first_tile_map_storage_buffer: D::StorageBuffer,
|
||||||
|
pub z_buffer_storage_buffer: D::StorageBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> SortProgramD3D11<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> SortProgramD3D11<D> {
|
||||||
|
let mut program = device.create_compute_program(resources, "d3d11/sort");
|
||||||
|
let dimensions = ComputeDimensions { x: SORT_WORKGROUP_SIZE, y: 1, z: 1 };
|
||||||
|
device.set_compute_program_local_size(&mut program, dimensions);
|
||||||
|
|
||||||
|
let tile_count_uniform = device.get_uniform(&program, "TileCount");
|
||||||
|
let tiles_storage_buffer = device.get_storage_buffer(&program, "Tiles", 0);
|
||||||
|
let first_tile_map_storage_buffer = device.get_storage_buffer(&program, "FirstTileMap", 1);
|
||||||
|
let z_buffer_storage_buffer = device.get_storage_buffer(&program, "ZBuffer", 2);
|
||||||
|
|
||||||
|
SortProgramD3D11 {
|
||||||
|
program,
|
||||||
|
tile_count_uniform,
|
||||||
|
tiles_storage_buffer,
|
||||||
|
first_tile_map_storage_buffer,
|
||||||
|
z_buffer_storage_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
// pathfinder/renderer/src/gpu/d3d9/mod.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
pub mod renderer;
|
||||||
|
pub mod shaders;
|
|
@ -0,0 +1,573 @@
|
||||||
|
// pathfinder/renderer/src/gpu/d3d9/renderer.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
use crate::gpu::blend::{BlendModeExt, ToBlendState};
|
||||||
|
use crate::gpu::perf::TimerFuture;
|
||||||
|
use crate::gpu::renderer::{FramebufferFlags, MASK_FRAMEBUFFER_HEIGHT, MASK_FRAMEBUFFER_WIDTH};
|
||||||
|
use crate::gpu::renderer::{RendererCore, RendererFlags};
|
||||||
|
use crate::gpu::d3d9::shaders::{ClipTileCombineVertexArrayD3D9, ClipTileCopyVertexArrayD3D9};
|
||||||
|
use crate::gpu::d3d9::shaders::{CopyTileVertexArray, FillVertexArrayD3D9};
|
||||||
|
use crate::gpu::d3d9::shaders::{ProgramsD3D9, TileVertexArrayD3D9};
|
||||||
|
use crate::gpu_data::{Clip, DrawTileBatchD3D9, Fill, TileBatchTexture, TileObjectPrimitive};
|
||||||
|
use crate::tile_map::DenseTileMap;
|
||||||
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
|
use byte_slice_cast::AsByteSlice;
|
||||||
|
use pathfinder_color::ColorF;
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
|
use pathfinder_geometry::rect::RectI;
|
||||||
|
use pathfinder_geometry::transform3d::Transform4F;
|
||||||
|
use pathfinder_geometry::vector::{Vector2I, Vector4F, vec2i};
|
||||||
|
use pathfinder_gpu::allocator::{BufferID, BufferTag, FramebufferID, FramebufferTag};
|
||||||
|
use pathfinder_gpu::allocator::{TextureID, TextureTag};
|
||||||
|
use pathfinder_gpu::{BlendFactor, BlendState, BufferTarget, ClearOps, Device, Primitive};
|
||||||
|
use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, StencilFunc, StencilState};
|
||||||
|
use pathfinder_gpu::{TextureDataRef, TextureFormat, UniformData};
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
use pathfinder_simd::default::F32x2;
|
||||||
|
use std::u32;
|
||||||
|
|
||||||
|
const MAX_FILLS_PER_BATCH: usize = 0x10000;
|
||||||
|
|
||||||
|
pub(crate) struct RendererD3D9<D> where D: Device {
|
||||||
|
// Basic data
|
||||||
|
programs: ProgramsD3D9<D>,
|
||||||
|
quads_vertex_indices_buffer_id: Option<BufferID>,
|
||||||
|
quads_vertex_indices_length: usize,
|
||||||
|
|
||||||
|
// Fills.
|
||||||
|
buffered_fills: Vec<Fill>,
|
||||||
|
pending_fills: Vec<Fill>,
|
||||||
|
|
||||||
|
// Temporary framebuffers
|
||||||
|
dest_blend_framebuffer_id: FramebufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> RendererD3D9<D> where D: Device {
|
||||||
|
pub(crate) fn new(core: &mut RendererCore<D>, resources: &dyn ResourceLoader)
|
||||||
|
-> RendererD3D9<D> {
|
||||||
|
let programs = ProgramsD3D9::new(&core.device, resources);
|
||||||
|
|
||||||
|
let window_size = core.options.dest.window_size(&core.device);
|
||||||
|
let dest_blend_framebuffer_id =
|
||||||
|
core.allocator.allocate_framebuffer(&core.device,
|
||||||
|
window_size,
|
||||||
|
TextureFormat::RGBA8,
|
||||||
|
FramebufferTag("DestBlendD3D9"));
|
||||||
|
|
||||||
|
RendererD3D9 {
|
||||||
|
programs,
|
||||||
|
quads_vertex_indices_buffer_id: None,
|
||||||
|
quads_vertex_indices_length: 0,
|
||||||
|
|
||||||
|
buffered_fills: vec![],
|
||||||
|
pending_fills: vec![],
|
||||||
|
|
||||||
|
dest_blend_framebuffer_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn upload_and_draw_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
batch: &DrawTileBatchD3D9) {
|
||||||
|
if !batch.clips.is_empty() {
|
||||||
|
let clip_buffer_info = self.upload_clip_tiles(core, &batch.clips);
|
||||||
|
self.clip_tiles(core, &clip_buffer_info);
|
||||||
|
core.allocator.free_buffer(clip_buffer_info.clip_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile_buffer = self.upload_tiles(core, &batch.tiles);
|
||||||
|
let z_buffer_texture_id = self.upload_z_buffer(core, &batch.z_buffer_data);
|
||||||
|
|
||||||
|
self.draw_tiles(core,
|
||||||
|
batch.tiles.len() as u32,
|
||||||
|
tile_buffer.tile_vertex_buffer_id,
|
||||||
|
batch.color_texture,
|
||||||
|
batch.blend_mode,
|
||||||
|
z_buffer_texture_id);
|
||||||
|
|
||||||
|
core.allocator.free_texture(z_buffer_texture_id);
|
||||||
|
core.allocator.free_buffer(tile_buffer.tile_vertex_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_tiles(&mut self, core: &mut RendererCore<D>, tiles: &[TileObjectPrimitive])
|
||||||
|
-> TileBufferD3D9 {
|
||||||
|
let tile_vertex_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<TileObjectPrimitive>(&core.device,
|
||||||
|
tiles.len() as u64,
|
||||||
|
BufferTag("TileD3D9"));
|
||||||
|
let tile_vertex_buffer = &core.allocator.get_buffer(tile_vertex_buffer_id);
|
||||||
|
core.device.upload_to_buffer(tile_vertex_buffer, 0, tiles, BufferTarget::Vertex);
|
||||||
|
self.ensure_index_buffer(core, tiles.len());
|
||||||
|
|
||||||
|
TileBufferD3D9 { tile_vertex_buffer_id }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn ensure_index_buffer(&mut self, core: &mut RendererCore<D>, mut length: usize) {
|
||||||
|
length = length.next_power_of_two();
|
||||||
|
if self.quads_vertex_indices_length >= length {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Generate these with SIMD.
|
||||||
|
let mut indices: Vec<u32> = Vec::with_capacity(length * 6);
|
||||||
|
for index in 0..(length as u32) {
|
||||||
|
indices.extend_from_slice(&[
|
||||||
|
index * 4 + 0, index * 4 + 1, index * 4 + 2,
|
||||||
|
index * 4 + 1, index * 4 + 3, index * 4 + 2,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(quads_vertex_indices_buffer_id) = self.quads_vertex_indices_buffer_id.take() {
|
||||||
|
core.allocator.free_buffer(quads_vertex_indices_buffer_id);
|
||||||
|
}
|
||||||
|
let quads_vertex_indices_buffer_id =
|
||||||
|
core.allocator.allocate_buffer::<u32>(&core.device,
|
||||||
|
indices.len() as u64,
|
||||||
|
BufferTag("QuadsVertexIndicesD3D9"));
|
||||||
|
let quads_vertex_indices_buffer =
|
||||||
|
core.allocator.get_buffer(quads_vertex_indices_buffer_id);
|
||||||
|
core.device.upload_to_buffer(quads_vertex_indices_buffer,
|
||||||
|
0,
|
||||||
|
&indices,
|
||||||
|
BufferTarget::Index);
|
||||||
|
self.quads_vertex_indices_buffer_id = Some(quads_vertex_indices_buffer_id);
|
||||||
|
self.quads_vertex_indices_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_fills(&mut self, core: &mut RendererCore<D>, fill_batch: &[Fill]) {
|
||||||
|
if fill_batch.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.stats.fill_count += fill_batch.len();
|
||||||
|
|
||||||
|
let preserve_alpha_mask_contents = core.alpha_tile_count > 0;
|
||||||
|
|
||||||
|
self.pending_fills.reserve(fill_batch.len());
|
||||||
|
for fill in fill_batch {
|
||||||
|
core.alpha_tile_count = core.alpha_tile_count.max(fill.link + 1);
|
||||||
|
self.pending_fills.push(*fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
core.stats.alpha_tile_count = core.alpha_tile_count as usize;
|
||||||
|
|
||||||
|
core.reallocate_alpha_tile_pages_if_necessary(preserve_alpha_mask_contents);
|
||||||
|
|
||||||
|
if self.buffered_fills.len() + self.pending_fills.len() > MAX_FILLS_PER_BATCH {
|
||||||
|
self.draw_buffered_fills(core);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buffered_fills.extend(self.pending_fills.drain(..));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn draw_buffered_fills(&mut self, core: &mut RendererCore<D>) {
|
||||||
|
if self.buffered_fills.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fill_storage_info = self.upload_buffered_fills(core);
|
||||||
|
self.draw_fills(core, fill_storage_info.fill_buffer_id, fill_storage_info.fill_count);
|
||||||
|
core.allocator.free_buffer(fill_storage_info.fill_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_buffered_fills(&mut self, core: &mut RendererCore<D>) -> FillBufferInfoD3D9 {
|
||||||
|
let buffered_fills = &mut self.buffered_fills;
|
||||||
|
debug_assert!(!buffered_fills.is_empty());
|
||||||
|
|
||||||
|
let fill_buffer_id = core.allocator.allocate_buffer::<Fill>(&core.device,
|
||||||
|
MAX_FILLS_PER_BATCH as u64,
|
||||||
|
BufferTag("Fill"));
|
||||||
|
let fill_vertex_buffer = core.allocator.get_buffer(fill_buffer_id);
|
||||||
|
debug_assert!(buffered_fills.len() <= u32::MAX as usize);
|
||||||
|
core.device.upload_to_buffer(fill_vertex_buffer, 0, &buffered_fills, BufferTarget::Vertex);
|
||||||
|
|
||||||
|
let fill_count = buffered_fills.len() as u32;
|
||||||
|
buffered_fills.clear();
|
||||||
|
|
||||||
|
FillBufferInfoD3D9 { fill_buffer_id, fill_count }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_fills(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
fill_buffer_id: BufferID,
|
||||||
|
fill_count: u32) {
|
||||||
|
let fill_raster_program = &self.programs.fill_program;
|
||||||
|
|
||||||
|
let fill_vertex_buffer = core.allocator.get_buffer(fill_buffer_id);
|
||||||
|
let quad_vertex_positions_buffer = core.allocator
|
||||||
|
.get_buffer(core.quad_vertex_positions_buffer_id);
|
||||||
|
let quad_vertex_indices_buffer = core.allocator
|
||||||
|
.get_buffer(core.quad_vertex_indices_buffer_id);
|
||||||
|
|
||||||
|
let area_lut_texture = core.allocator.get_texture(core.area_lut_texture_id);
|
||||||
|
|
||||||
|
let mask_viewport = self.mask_viewport(core);
|
||||||
|
let mask_storage = core.mask_storage.as_ref().expect("Where's the mask storage?");
|
||||||
|
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
||||||
|
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
||||||
|
|
||||||
|
let fill_vertex_array = FillVertexArrayD3D9::new(&core.device,
|
||||||
|
fill_raster_program,
|
||||||
|
fill_vertex_buffer,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
quad_vertex_indices_buffer);
|
||||||
|
|
||||||
|
let mut clear_color = None;
|
||||||
|
if !core.framebuffer_flags.contains(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY) {
|
||||||
|
clear_color = Some(ColorF::default());
|
||||||
|
};
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
core.device.draw_elements_instanced(6, fill_count, &RenderState {
|
||||||
|
target: &RenderTarget::Framebuffer(mask_framebuffer),
|
||||||
|
program: &fill_raster_program.program,
|
||||||
|
vertex_array: &fill_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &[(&fill_raster_program.area_lut_texture, area_lut_texture)],
|
||||||
|
uniforms: &[
|
||||||
|
(&fill_raster_program.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(mask_viewport.size().to_f32().0)),
|
||||||
|
(&fill_raster_program.tile_size_uniform,
|
||||||
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
|
],
|
||||||
|
images: &[],
|
||||||
|
storage_buffers: &[],
|
||||||
|
viewport: mask_viewport,
|
||||||
|
options: RenderOptions {
|
||||||
|
blend: Some(BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::One,
|
||||||
|
src_alpha_factor: BlendFactor::One,
|
||||||
|
dest_rgb_factor: BlendFactor::One,
|
||||||
|
dest_alpha_factor: BlendFactor::One,
|
||||||
|
..BlendState::default()
|
||||||
|
}),
|
||||||
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
|
..RenderOptions::default()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().fill_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
core.framebuffer_flags.insert(FramebufferFlags::MASK_FRAMEBUFFER_IS_DIRTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clip_tiles(&mut self, core: &mut RendererCore<D>, clip_buffer_info: &ClipBufferInfo) {
|
||||||
|
// Allocate temp mask framebuffer.
|
||||||
|
let mask_temp_framebuffer_id =
|
||||||
|
core.allocator.allocate_framebuffer(&core.device,
|
||||||
|
self.mask_viewport(core).size(),
|
||||||
|
core.mask_texture_format(),
|
||||||
|
FramebufferTag("TempClipMaskD3D9"));
|
||||||
|
let mask_temp_framebuffer = core.allocator.get_framebuffer(mask_temp_framebuffer_id);
|
||||||
|
|
||||||
|
let mask_storage = core.mask_storage.as_ref().expect("Where's the mask storage?");
|
||||||
|
let mask_framebuffer_id = mask_storage.framebuffer_id;
|
||||||
|
let mask_framebuffer = core.allocator.get_framebuffer(mask_framebuffer_id);
|
||||||
|
let mask_texture = core.device.framebuffer_texture(mask_framebuffer);
|
||||||
|
let mask_texture_size = core.device.texture_size(&mask_texture);
|
||||||
|
|
||||||
|
let clip_vertex_buffer = core.allocator.get_buffer(clip_buffer_info.clip_buffer_id);
|
||||||
|
let quad_vertex_positions_buffer = core.allocator
|
||||||
|
.get_buffer(core.quad_vertex_positions_buffer_id);
|
||||||
|
let quad_vertex_indices_buffer = core.allocator
|
||||||
|
.get_buffer(core.quad_vertex_indices_buffer_id);
|
||||||
|
|
||||||
|
let tile_clip_copy_vertex_array =
|
||||||
|
ClipTileCopyVertexArrayD3D9::new(&core.device,
|
||||||
|
&self.programs.tile_clip_copy_program,
|
||||||
|
clip_vertex_buffer,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
quad_vertex_indices_buffer);
|
||||||
|
let tile_clip_combine_vertex_array =
|
||||||
|
ClipTileCombineVertexArrayD3D9::new(&core.device,
|
||||||
|
&self.programs.tile_clip_combine_program,
|
||||||
|
clip_vertex_buffer,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
quad_vertex_indices_buffer);
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
// Copy out tiles.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): Don't do this on GL4.
|
||||||
|
core.device.draw_elements_instanced(6, clip_buffer_info.clip_count * 2, &RenderState {
|
||||||
|
target: &RenderTarget::Framebuffer(mask_temp_framebuffer),
|
||||||
|
program: &self.programs.tile_clip_copy_program.program,
|
||||||
|
vertex_array: &tile_clip_copy_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &[
|
||||||
|
(&self.programs.tile_clip_copy_program.src_texture,
|
||||||
|
core.device.framebuffer_texture(mask_framebuffer)),
|
||||||
|
],
|
||||||
|
images: &[],
|
||||||
|
uniforms: &[
|
||||||
|
(&self.programs.tile_clip_copy_program.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(mask_texture_size.to_f32().0)),
|
||||||
|
],
|
||||||
|
storage_buffers: &[],
|
||||||
|
viewport: RectI::new(Vector2I::zero(), mask_texture_size),
|
||||||
|
options: RenderOptions::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Combine clip tiles.
|
||||||
|
core.device.draw_elements_instanced(6, clip_buffer_info.clip_count, &RenderState {
|
||||||
|
target: &RenderTarget::Framebuffer(mask_framebuffer),
|
||||||
|
program: &self.programs.tile_clip_combine_program.program,
|
||||||
|
vertex_array: &tile_clip_combine_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &[
|
||||||
|
(&self.programs.tile_clip_combine_program.src_texture,
|
||||||
|
core.device.framebuffer_texture(&mask_temp_framebuffer)),
|
||||||
|
],
|
||||||
|
images: &[],
|
||||||
|
uniforms: &[
|
||||||
|
(&self.programs.tile_clip_combine_program.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(mask_texture_size.to_f32().0)),
|
||||||
|
],
|
||||||
|
storage_buffers: &[],
|
||||||
|
viewport: RectI::new(Vector2I::zero(), mask_texture_size),
|
||||||
|
options: RenderOptions::default(),
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().other_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 2;
|
||||||
|
|
||||||
|
core.allocator.free_framebuffer(mask_temp_framebuffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_z_buffer(&mut self, core: &mut RendererCore<D>, z_buffer_map: &DenseTileMap<i32>)
|
||||||
|
-> TextureID {
|
||||||
|
let z_buffer_texture_id = core.allocator.allocate_texture(&core.device,
|
||||||
|
z_buffer_map.rect.size(),
|
||||||
|
TextureFormat::RGBA8,
|
||||||
|
TextureTag("ZBufferD3D9"));
|
||||||
|
let z_buffer_texture = core.allocator.get_texture(z_buffer_texture_id);
|
||||||
|
debug_assert_eq!(z_buffer_map.rect.origin(), Vector2I::default());
|
||||||
|
let z_data: &[u8] = z_buffer_map.data.as_byte_slice();
|
||||||
|
core.device.upload_to_texture(z_buffer_texture,
|
||||||
|
z_buffer_map.rect,
|
||||||
|
TextureDataRef::U8(&z_data));
|
||||||
|
z_buffer_texture_id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uploads clip tiles from CPU to GPU.
|
||||||
|
fn upload_clip_tiles(&mut self, core: &mut RendererCore<D>, clips: &[Clip]) -> ClipBufferInfo {
|
||||||
|
let clip_buffer_id = core.allocator.allocate_buffer::<Clip>(&core.device,
|
||||||
|
clips.len() as u64,
|
||||||
|
BufferTag("ClipD3D9"));
|
||||||
|
let clip_buffer = core.allocator.get_buffer(clip_buffer_id);
|
||||||
|
core.device.upload_to_buffer(clip_buffer, 0, clips, BufferTarget::Vertex);
|
||||||
|
ClipBufferInfo { clip_buffer_id, clip_count: clips.len() as u32 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_tiles(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
tile_count: u32,
|
||||||
|
tile_vertex_buffer_id: BufferID,
|
||||||
|
color_texture_0: Option<TileBatchTexture>,
|
||||||
|
blend_mode: BlendMode,
|
||||||
|
z_buffer_texture_id: TextureID) {
|
||||||
|
// TODO(pcwalton): Disable blend for solid tiles.
|
||||||
|
|
||||||
|
if tile_count == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.stats.total_tile_count += tile_count as usize;
|
||||||
|
|
||||||
|
let needs_readable_framebuffer = blend_mode.needs_readable_framebuffer();
|
||||||
|
if needs_readable_framebuffer {
|
||||||
|
self.copy_alpha_tiles_to_dest_blend_texture(core, tile_count, tile_vertex_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let clear_color = core.clear_color_for_draw_operation();
|
||||||
|
let draw_viewport = core.draw_viewport();
|
||||||
|
|
||||||
|
let timer_query = core.timer_query_cache.alloc(&core.device);
|
||||||
|
core.device.begin_timer_query(&timer_query);
|
||||||
|
|
||||||
|
let tile_raster_program = &self.programs.tile_program;
|
||||||
|
|
||||||
|
let tile_vertex_buffer = core.allocator.get_buffer(tile_vertex_buffer_id);
|
||||||
|
let quad_vertex_positions_buffer = core.allocator
|
||||||
|
.get_buffer(core.quad_vertex_positions_buffer_id);
|
||||||
|
let quad_vertex_indices_buffer = core.allocator
|
||||||
|
.get_buffer(core.quad_vertex_indices_buffer_id);
|
||||||
|
let dest_blend_framebuffer = core.allocator
|
||||||
|
.get_framebuffer(self.dest_blend_framebuffer_id);
|
||||||
|
|
||||||
|
let (mut textures, mut uniforms) = (vec![], vec![]);
|
||||||
|
|
||||||
|
core.set_uniforms_for_drawing_tiles(&tile_raster_program.common,
|
||||||
|
&mut textures,
|
||||||
|
&mut uniforms,
|
||||||
|
color_texture_0);
|
||||||
|
|
||||||
|
uniforms.push((&tile_raster_program.transform_uniform,
|
||||||
|
UniformData::Mat4(self.tile_transform(core).to_columns())));
|
||||||
|
|
||||||
|
if needs_readable_framebuffer {
|
||||||
|
textures.push((&tile_raster_program.dest_texture,
|
||||||
|
core.device.framebuffer_texture(dest_blend_framebuffer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let z_buffer_texture = core.allocator.get_texture(z_buffer_texture_id);
|
||||||
|
textures.push((&tile_raster_program.common.z_buffer_texture, z_buffer_texture));
|
||||||
|
uniforms.push((&tile_raster_program.common.z_buffer_texture_size_uniform,
|
||||||
|
UniformData::IVec2(core.device.texture_size(z_buffer_texture).0)));
|
||||||
|
|
||||||
|
let tile_vertex_array = TileVertexArrayD3D9::new(&core.device,
|
||||||
|
&self.programs.tile_program,
|
||||||
|
tile_vertex_buffer,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
quad_vertex_indices_buffer);
|
||||||
|
|
||||||
|
core.device.draw_elements_instanced(6, tile_count, &RenderState {
|
||||||
|
target: &core.draw_render_target(),
|
||||||
|
program: &tile_raster_program.common.program,
|
||||||
|
vertex_array: &tile_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &textures,
|
||||||
|
images: &[],
|
||||||
|
storage_buffers: &[],
|
||||||
|
uniforms: &uniforms,
|
||||||
|
viewport: draw_viewport,
|
||||||
|
options: RenderOptions {
|
||||||
|
blend: blend_mode.to_blend_state(),
|
||||||
|
stencil: self.stencil_state(core),
|
||||||
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
|
..RenderOptions::default()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
core.device.end_timer_query(&timer_query);
|
||||||
|
core.current_timer.as_mut().unwrap().composite_times.push(TimerFuture::new(timer_query));
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
|
||||||
|
core.preserve_draw_framebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_alpha_tiles_to_dest_blend_texture(&mut self,
|
||||||
|
core: &mut RendererCore<D>,
|
||||||
|
tile_count: u32,
|
||||||
|
vertex_buffer_id: BufferID) {
|
||||||
|
let draw_viewport = core.draw_viewport();
|
||||||
|
|
||||||
|
let mut textures = vec![];
|
||||||
|
let mut uniforms = vec![
|
||||||
|
(&self.programs.tile_copy_program.transform_uniform,
|
||||||
|
UniformData::Mat4(self.tile_transform(core).to_columns())),
|
||||||
|
(&self.programs.tile_copy_program.tile_size_uniform,
|
||||||
|
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||||
|
];
|
||||||
|
|
||||||
|
let draw_framebuffer = match core.draw_render_target() {
|
||||||
|
RenderTarget::Framebuffer(framebuffer) => framebuffer,
|
||||||
|
RenderTarget::Default => panic!("Can't copy alpha tiles from default framebuffer!"),
|
||||||
|
};
|
||||||
|
let draw_texture = core.device.framebuffer_texture(&draw_framebuffer);
|
||||||
|
|
||||||
|
textures.push((&self.programs.tile_copy_program.src_texture, draw_texture));
|
||||||
|
uniforms.push((&self.programs.tile_copy_program.framebuffer_size_uniform,
|
||||||
|
UniformData::Vec2(draw_viewport.size().to_f32().0)));
|
||||||
|
|
||||||
|
let quads_vertex_indices_buffer_id = self.quads_vertex_indices_buffer_id
|
||||||
|
.expect("Where's the quads vertex buffer?");
|
||||||
|
let quads_vertex_indices_buffer = core.allocator
|
||||||
|
.get_buffer(quads_vertex_indices_buffer_id);
|
||||||
|
let vertex_buffer = core.allocator.get_buffer(vertex_buffer_id);
|
||||||
|
|
||||||
|
let tile_copy_vertex_array = CopyTileVertexArray::new(&core.device,
|
||||||
|
&self.programs.tile_copy_program,
|
||||||
|
vertex_buffer,
|
||||||
|
quads_vertex_indices_buffer);
|
||||||
|
|
||||||
|
let dest_blend_framebuffer = core.allocator
|
||||||
|
.get_framebuffer(self.dest_blend_framebuffer_id);
|
||||||
|
|
||||||
|
core.device.draw_elements(tile_count * 6, &RenderState {
|
||||||
|
target: &RenderTarget::Framebuffer(dest_blend_framebuffer),
|
||||||
|
program: &self.programs.tile_copy_program.program,
|
||||||
|
vertex_array: &tile_copy_vertex_array.vertex_array,
|
||||||
|
primitive: Primitive::Triangles,
|
||||||
|
textures: &textures,
|
||||||
|
images: &[],
|
||||||
|
storage_buffers: &[],
|
||||||
|
uniforms: &uniforms,
|
||||||
|
viewport: draw_viewport,
|
||||||
|
options: RenderOptions {
|
||||||
|
clear_ops: ClearOps {
|
||||||
|
color: Some(ColorF::new(1.0, 0.0, 0.0, 1.0)),
|
||||||
|
..ClearOps::default()
|
||||||
|
},
|
||||||
|
..RenderOptions::default()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
core.stats.drawcall_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stencil_state(&self, core: &RendererCore<D>) -> Option<StencilState> {
|
||||||
|
if !core.renderer_flags.contains(RendererFlags::USE_DEPTH) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(StencilState {
|
||||||
|
func: StencilFunc::Equal,
|
||||||
|
reference: 1,
|
||||||
|
mask: 1,
|
||||||
|
write: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mask_viewport(&self, core: &RendererCore<D>) -> RectI {
|
||||||
|
let page_count = match core.mask_storage {
|
||||||
|
Some(ref mask_storage) => mask_storage.allocated_page_count as i32,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
let height = MASK_FRAMEBUFFER_HEIGHT * page_count;
|
||||||
|
RectI::new(Vector2I::default(), vec2i(MASK_FRAMEBUFFER_WIDTH, height))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tile_transform(&self, core: &RendererCore<D>) -> Transform4F {
|
||||||
|
let draw_viewport = core.draw_viewport().size().to_f32();
|
||||||
|
let scale = Vector4F::new(2.0 / draw_viewport.x(), -2.0 / draw_viewport.y(), 1.0, 1.0);
|
||||||
|
Transform4F::from_scale(scale).translate(Vector4F::new(-1.0, 1.0, 0.0, 1.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct TileBatchInfoD3D9 {
|
||||||
|
pub(crate) tile_count: u32,
|
||||||
|
pub(crate) z_buffer_id: BufferID,
|
||||||
|
tile_vertex_buffer_id: BufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct FillBufferInfoD3D9 {
|
||||||
|
fill_buffer_id: BufferID,
|
||||||
|
fill_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TileBufferD3D9 {
|
||||||
|
tile_vertex_buffer_id: BufferID,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClipBufferInfo {
|
||||||
|
clip_buffer_id: BufferID,
|
||||||
|
clip_count: u32,
|
||||||
|
}
|
|
@ -0,0 +1,441 @@
|
||||||
|
// pathfinder/renderer/src/gpu/d3d9/shaders.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
use crate::gpu::shaders::{TILE_INSTANCE_SIZE, TileProgramCommon};
|
||||||
|
use pathfinder_gpu::{BufferTarget, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
||||||
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
|
||||||
|
const FILL_INSTANCE_SIZE: usize = 12;
|
||||||
|
const CLIP_TILE_INSTANCE_SIZE: usize = 16;
|
||||||
|
|
||||||
|
pub struct FillVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub vertex_array: D::VertexArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> FillVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D,
|
||||||
|
fill_program: &FillProgramD3D9<D>,
|
||||||
|
vertex_buffer: &D::Buffer,
|
||||||
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
|
quad_vertex_indices_buffer: &D::Buffer)
|
||||||
|
-> FillVertexArrayD3D9<D> {
|
||||||
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
|
let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap();
|
||||||
|
let line_segment_attr = device.get_vertex_attr(&fill_program.program, "LineSegment")
|
||||||
|
.unwrap();
|
||||||
|
let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap();
|
||||||
|
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::U16,
|
||||||
|
stride: 4,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 0,
|
||||||
|
buffer_index: 0,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &line_segment_attr, &VertexAttrDescriptor {
|
||||||
|
size: 4,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::U16,
|
||||||
|
stride: FILL_INSTANCE_SIZE,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: FILL_INSTANCE_SIZE,
|
||||||
|
offset: 8,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
|
FillVertexArrayD3D9 { vertex_array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TileVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub vertex_array: D::VertexArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TileVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D,
|
||||||
|
tile_program: &TileProgramD3D9<D>,
|
||||||
|
tile_vertex_buffer: &D::Buffer,
|
||||||
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
|
quad_vertex_indices_buffer: &D::Buffer)
|
||||||
|
-> TileVertexArrayD3D9<D> {
|
||||||
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
|
let tile_offset_attr =
|
||||||
|
device.get_vertex_attr(&tile_program.common.program, "TileOffset").unwrap();
|
||||||
|
let tile_origin_attr =
|
||||||
|
device.get_vertex_attr(&tile_program.common.program, "TileOrigin").unwrap();
|
||||||
|
let mask_0_tex_coord_attr =
|
||||||
|
device.get_vertex_attr(&tile_program.common.program, "MaskTexCoord0").unwrap();
|
||||||
|
let ctrl_backdrop_attr =
|
||||||
|
device.get_vertex_attr(&tile_program.common.program, "CtrlBackdrop").unwrap();
|
||||||
|
let color_attr = device.get_vertex_attr(&tile_program.common.program, "Color").unwrap();
|
||||||
|
let path_index_attr = device.get_vertex_attr(&tile_program.common.program, "PathIndex")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: 4,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 0,
|
||||||
|
buffer_index: 0,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: TILE_INSTANCE_SIZE,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &mask_0_tex_coord_attr, &VertexAttrDescriptor {
|
||||||
|
size: 4,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::U8,
|
||||||
|
stride: TILE_INSTANCE_SIZE,
|
||||||
|
offset: 4,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &path_index_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: TILE_INSTANCE_SIZE,
|
||||||
|
offset: 8,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &color_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: TILE_INSTANCE_SIZE,
|
||||||
|
offset: 12,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &ctrl_backdrop_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I8,
|
||||||
|
stride: TILE_INSTANCE_SIZE,
|
||||||
|
offset: 14,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
|
TileVertexArrayD3D9 { vertex_array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClipTileCopyVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub vertex_array: D::VertexArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D,
|
||||||
|
clip_tile_copy_program: &ClipTileCopyProgramD3D9<D>,
|
||||||
|
vertex_buffer: &D::Buffer,
|
||||||
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
|
quad_vertex_indices_buffer: &D::Buffer)
|
||||||
|
-> ClipTileCopyVertexArrayD3D9<D> {
|
||||||
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
|
let tile_offset_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_copy_program.program, "TileOffset").unwrap();
|
||||||
|
let tile_index_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_copy_program.program, "TileIndex").unwrap();
|
||||||
|
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: 4,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 0,
|
||||||
|
buffer_index: 0,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: CLIP_TILE_INSTANCE_SIZE / 2,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
|
ClipTileCopyVertexArrayD3D9 { vertex_array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub vertex_array: D::VertexArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D,
|
||||||
|
clip_tile_combine_program: &ClipTileCombineProgramD3D9<D>,
|
||||||
|
vertex_buffer: &D::Buffer,
|
||||||
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
|
quad_vertex_indices_buffer: &D::Buffer)
|
||||||
|
-> ClipTileCombineVertexArrayD3D9<D> {
|
||||||
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
|
let tile_offset_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_combine_program.program, "TileOffset").unwrap();
|
||||||
|
let dest_tile_index_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_combine_program.program, "DestTileIndex").unwrap();
|
||||||
|
let dest_backdrop_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_combine_program.program, "DestBackdrop").unwrap();
|
||||||
|
let src_tile_index_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_combine_program.program, "SrcTileIndex").unwrap();
|
||||||
|
let src_backdrop_attr =
|
||||||
|
device.get_vertex_attr(&clip_tile_combine_program.program, "SrcBackdrop").unwrap();
|
||||||
|
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: 4,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 0,
|
||||||
|
buffer_index: 0,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &dest_tile_index_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: CLIP_TILE_INSTANCE_SIZE,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &dest_backdrop_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: CLIP_TILE_INSTANCE_SIZE,
|
||||||
|
offset: 4,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &src_tile_index_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: CLIP_TILE_INSTANCE_SIZE,
|
||||||
|
offset: 8,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.configure_vertex_attr(&vertex_array, &src_backdrop_attr, &VertexAttrDescriptor {
|
||||||
|
size: 1,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I32,
|
||||||
|
stride: CLIP_TILE_INSTANCE_SIZE,
|
||||||
|
offset: 12,
|
||||||
|
divisor: 1,
|
||||||
|
buffer_index: 1,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
|
ClipTileCombineVertexArrayD3D9 { vertex_array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyTileVertexArray<D> where D: Device {
|
||||||
|
pub vertex_array: D::VertexArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> CopyTileVertexArray<D> where D: Device {
|
||||||
|
pub fn new(device: &D,
|
||||||
|
copy_tile_program: &CopyTileProgram<D>,
|
||||||
|
copy_tile_vertex_buffer: &D::Buffer,
|
||||||
|
quads_vertex_indices_buffer: &D::Buffer)
|
||||||
|
-> CopyTileVertexArray<D> {
|
||||||
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
|
let tile_position_attr =
|
||||||
|
device.get_vertex_attr(©_tile_program.program, "TilePosition").unwrap();
|
||||||
|
|
||||||
|
device.bind_buffer(&vertex_array, copy_tile_vertex_buffer, BufferTarget::Vertex);
|
||||||
|
device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
|
||||||
|
size: 2,
|
||||||
|
class: VertexAttrClass::Int,
|
||||||
|
attr_type: VertexAttrType::I16,
|
||||||
|
stride: TILE_INSTANCE_SIZE,
|
||||||
|
offset: 0,
|
||||||
|
divisor: 0,
|
||||||
|
buffer_index: 0,
|
||||||
|
});
|
||||||
|
device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
|
||||||
|
|
||||||
|
CopyTileVertexArray { vertex_array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FillProgramD3D9<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
|
pub tile_size_uniform: D::Uniform,
|
||||||
|
pub area_lut_texture: D::TextureParameter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> FillProgramD3D9<D> where D: Device {
|
||||||
|
fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D9<D> {
|
||||||
|
let program = device.create_raster_program(resources, "d3d9/fill");
|
||||||
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
|
let area_lut_texture = device.get_texture_parameter(&program, "AreaLUT");
|
||||||
|
FillProgramD3D9 {
|
||||||
|
program,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
tile_size_uniform,
|
||||||
|
area_lut_texture,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TileProgramD3D9<D> where D: Device {
|
||||||
|
pub common: TileProgramCommon<D>,
|
||||||
|
pub dest_texture: D::TextureParameter,
|
||||||
|
pub transform_uniform: D::Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TileProgramD3D9<D> where D: Device {
|
||||||
|
fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgramD3D9<D> {
|
||||||
|
let program = device.create_raster_program(resources, "d3d9/tile");
|
||||||
|
let dest_texture = device.get_texture_parameter(&program, "DestTexture");
|
||||||
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
|
let common = TileProgramCommon::new(device, program);
|
||||||
|
TileProgramD3D9 { common, dest_texture, transform_uniform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClipTileCombineProgramD3D9<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub src_texture: D::TextureParameter,
|
||||||
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ClipTileCombineProgramD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCombineProgramD3D9<D> {
|
||||||
|
let program = device.create_raster_program(resources, "d3d9/tile_clip_combine");
|
||||||
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
|
ClipTileCombineProgramD3D9 { program, src_texture, framebuffer_size_uniform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ClipTileCopyProgramD3D9<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub src_texture: D::TextureParameter,
|
||||||
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ClipTileCopyProgramD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCopyProgramD3D9<D> {
|
||||||
|
let program = device.create_raster_program(resources, "d3d9/tile_clip_copy");
|
||||||
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
|
ClipTileCopyProgramD3D9 { program, src_texture, framebuffer_size_uniform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyTileProgram<D> where D: Device {
|
||||||
|
pub program: D::Program,
|
||||||
|
pub transform_uniform: D::Uniform,
|
||||||
|
pub tile_size_uniform: D::Uniform,
|
||||||
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
|
pub src_texture: D::TextureParameter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> CopyTileProgram<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> {
|
||||||
|
let program = device.create_raster_program(resources, "d3d9/tile_copy");
|
||||||
|
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||||
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
|
CopyTileProgram {
|
||||||
|
program,
|
||||||
|
transform_uniform,
|
||||||
|
tile_size_uniform,
|
||||||
|
framebuffer_size_uniform,
|
||||||
|
src_texture,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct D3D9Programs<D> where D: Device {
|
||||||
|
pub fill_program: FillProgramD3D9<D>,
|
||||||
|
pub tile_program: TileProgramD3D9<D>,
|
||||||
|
pub tile_clip_combine_program: ClipTileCombineProgramD3D9<D>,
|
||||||
|
pub tile_clip_copy_program: ClipTileCopyProgramD3D9<D>,
|
||||||
|
pub tile_copy_program: CopyTileProgram<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> D3D9Programs<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> D3D9Programs<D> {
|
||||||
|
D3D9Programs {
|
||||||
|
fill_program: FillProgramD3D9::new(device, resources),
|
||||||
|
tile_program: TileProgramD3D9::new(device, resources),
|
||||||
|
tile_clip_combine_program: ClipTileCombineProgramD3D9::new(device, resources),
|
||||||
|
tile_clip_copy_program: ClipTileCopyProgramD3D9::new(device, resources),
|
||||||
|
tile_copy_program: CopyTileProgram::new(device, resources),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProgramsD3D9<D> where D: Device {
|
||||||
|
pub fill_program: FillProgramD3D9<D>,
|
||||||
|
pub tile_program: TileProgramD3D9<D>,
|
||||||
|
pub tile_clip_copy_program: ClipTileCopyProgramD3D9<D>,
|
||||||
|
pub tile_clip_combine_program: ClipTileCombineProgramD3D9<D>,
|
||||||
|
pub tile_copy_program: CopyTileProgram<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ProgramsD3D9<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D9<D> {
|
||||||
|
ProgramsD3D9 {
|
||||||
|
fill_program: FillProgramD3D9::new(device, resources),
|
||||||
|
tile_program: TileProgramD3D9::new(device, resources),
|
||||||
|
tile_clip_copy_program: ClipTileCopyProgramD3D9::new(device, resources),
|
||||||
|
tile_clip_combine_program: ClipTileCombineProgramD3D9::new(device, resources),
|
||||||
|
tile_copy_program: CopyTileProgram::new(device, resources),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,10 +15,12 @@
|
||||||
//!
|
//!
|
||||||
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
||||||
|
|
||||||
use crate::gpu::renderer::{RenderStats, RenderTime};
|
use crate::gpu::options::RendererLevel;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use crate::gpu::perf::{RenderStats, RenderTime};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
|
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::Device;
|
||||||
|
use pathfinder_gpu::allocator::GPUMemoryAllocator;
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR};
|
use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
@ -27,35 +29,39 @@ use std::time::Duration;
|
||||||
|
|
||||||
const SAMPLE_BUFFER_SIZE: usize = 60;
|
const SAMPLE_BUFFER_SIZE: usize = 60;
|
||||||
|
|
||||||
const STATS_WINDOW_WIDTH: i32 = 325;
|
const STATS_WINDOW_WIDTH: i32 = 275;
|
||||||
const STATS_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 4 + PADDING + 2;
|
const STATS_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 4 + PADDING + 2;
|
||||||
|
|
||||||
const PERFORMANCE_WINDOW_WIDTH: i32 = 400;
|
const PERFORMANCE_WINDOW_WIDTH: i32 = 400;
|
||||||
const PERFORMANCE_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 4 + PADDING + 2;
|
const PERFORMANCE_WINDOW_HEIGHT_D3D9: i32 = LINE_HEIGHT * 8 + PADDING + 2;
|
||||||
|
const PERFORMANCE_WINDOW_HEIGHT_D3D11: i32 = LINE_HEIGHT * 10 + PADDING + 2;
|
||||||
|
|
||||||
pub struct DebugUIPresenter<D>
|
const INFO_WINDOW_WIDTH: i32 = 425;
|
||||||
where
|
const INFO_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
|
||||||
D: Device,
|
|
||||||
{
|
pub struct DebugUIPresenter<D> where D: Device {
|
||||||
pub ui_presenter: UIPresenter<D>,
|
pub ui_presenter: UIPresenter<D>,
|
||||||
cpu_samples: SampleBuffer<RenderStats>,
|
cpu_samples: SampleBuffer<RenderStats>,
|
||||||
gpu_samples: SampleBuffer<RenderTime>,
|
gpu_samples: SampleBuffer<RenderTime>,
|
||||||
|
backend_name: &'static str,
|
||||||
|
device_name: String,
|
||||||
|
renderer_level: RendererLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DebugUIPresenter<D>
|
impl<D> DebugUIPresenter<D> where D: Device {
|
||||||
where
|
pub fn new(device: &D,
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub fn new(
|
|
||||||
device: &D,
|
|
||||||
resources: &dyn ResourceLoader,
|
resources: &dyn ResourceLoader,
|
||||||
framebuffer_size: Vector2I,
|
framebuffer_size: Vector2I,
|
||||||
) -> DebugUIPresenter<D> {
|
renderer_level: RendererLevel)
|
||||||
|
-> DebugUIPresenter<D> {
|
||||||
let ui_presenter = UIPresenter::new(device, resources, framebuffer_size);
|
let ui_presenter = UIPresenter::new(device, resources, framebuffer_size);
|
||||||
DebugUIPresenter {
|
DebugUIPresenter {
|
||||||
ui_presenter,
|
ui_presenter,
|
||||||
cpu_samples: SampleBuffer::new(),
|
cpu_samples: SampleBuffer::new(),
|
||||||
gpu_samples: SampleBuffer::new(),
|
gpu_samples: SampleBuffer::new(),
|
||||||
|
backend_name: device.backend_name(),
|
||||||
|
device_name: device.device_name(),
|
||||||
|
renderer_level,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,84 +70,222 @@ where
|
||||||
self.gpu_samples.push(rendering_time);
|
self.gpu_samples.push(rendering_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, device: &D) {
|
pub fn draw(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
|
||||||
self.draw_stats_window(device);
|
self.draw_stats_window(device, allocator);
|
||||||
self.draw_performance_window(device);
|
self.draw_performance_window(device, allocator);
|
||||||
|
self.draw_info_window(device, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_stats_window(&self, device: &D) {
|
#[inline]
|
||||||
|
pub fn set_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) {
|
||||||
|
self.ui_presenter.set_framebuffer_size(new_framebuffer_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_info_window(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
|
||||||
|
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
||||||
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
|
let window_rect = RectI::new(
|
||||||
|
vec2i(framebuffer_size.x() - PADDING - INFO_WINDOW_WIDTH,
|
||||||
|
bottom - INFO_WINDOW_HEIGHT),
|
||||||
|
vec2i(INFO_WINDOW_WIDTH, INFO_WINDOW_HEIGHT),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
||||||
|
|
||||||
|
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
||||||
|
let level = match self.renderer_level {
|
||||||
|
RendererLevel::D3D9 => "D3D9",
|
||||||
|
RendererLevel::D3D11 => "D3D11",
|
||||||
|
};
|
||||||
|
self.ui_presenter.draw_text(device,
|
||||||
|
allocator,
|
||||||
|
&format!("{} ({} level)", self.backend_name, level),
|
||||||
|
origin + vec2i(0, LINE_HEIGHT * 0),
|
||||||
|
false);
|
||||||
|
self.ui_presenter.draw_text(device,
|
||||||
|
allocator,
|
||||||
|
&self.device_name,
|
||||||
|
origin + vec2i(0, LINE_HEIGHT * 1),
|
||||||
|
false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn performance_window_size(&self) -> Vector2I {
|
||||||
|
match self.renderer_level {
|
||||||
|
RendererLevel::D3D9 => vec2i(PERFORMANCE_WINDOW_WIDTH, PERFORMANCE_WINDOW_HEIGHT_D3D9),
|
||||||
|
RendererLevel::D3D11 => {
|
||||||
|
vec2i(PERFORMANCE_WINDOW_WIDTH, PERFORMANCE_WINDOW_HEIGHT_D3D11)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_stats_window(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
|
||||||
|
let performance_window_height = self.performance_window_size().y();
|
||||||
|
|
||||||
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
||||||
let bottom = framebuffer_size.y() - PADDING;
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
let window_rect = RectI::new(
|
let window_rect = RectI::new(
|
||||||
vec2i(framebuffer_size.x() - PADDING - STATS_WINDOW_WIDTH,
|
vec2i(framebuffer_size.x() - PADDING - STATS_WINDOW_WIDTH,
|
||||||
bottom - PERFORMANCE_WINDOW_HEIGHT - PADDING - STATS_WINDOW_HEIGHT),
|
bottom -
|
||||||
vec2i(STATS_WINDOW_WIDTH, STATS_WINDOW_HEIGHT),
|
PADDING -
|
||||||
);
|
INFO_WINDOW_HEIGHT -
|
||||||
|
performance_window_height -
|
||||||
|
PADDING -
|
||||||
|
STATS_WINDOW_HEIGHT),
|
||||||
|
vec2i(STATS_WINDOW_WIDTH, STATS_WINDOW_HEIGHT));
|
||||||
|
|
||||||
self.ui_presenter.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
||||||
|
|
||||||
let mean_cpu_sample = self.cpu_samples.mean();
|
let mean_cpu_sample = self.cpu_samples.mean();
|
||||||
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
&format!("Paths: {}", mean_cpu_sample.path_count),
|
&format!("Paths: {}", mean_cpu_sample.path_count),
|
||||||
origin,
|
origin,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
&format!("Solid Tiles: {}", mean_cpu_sample.solid_tile_count),
|
allocator,
|
||||||
|
&format!("Tiles: {}", mean_cpu_sample.total_tile_count),
|
||||||
origin + vec2i(0, LINE_HEIGHT * 1),
|
origin + vec2i(0, LINE_HEIGHT * 1),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
&format!("Alpha Tiles: {}", mean_cpu_sample.alpha_tile_count),
|
allocator,
|
||||||
|
&format!("Masks: {}", mean_cpu_sample.alpha_tile_count),
|
||||||
origin + vec2i(0, LINE_HEIGHT * 2),
|
origin + vec2i(0, LINE_HEIGHT * 2),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
&format!("Fills: {}", mean_cpu_sample.fill_count),
|
&format!("Fills: {}", mean_cpu_sample.fill_count),
|
||||||
origin + vec2i(0, LINE_HEIGHT * 3),
|
origin + vec2i(0, LINE_HEIGHT * 3),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_performance_window(&self, device: &D) {
|
fn draw_performance_window(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
|
||||||
|
let performance_window_size = self.performance_window_size();
|
||||||
|
|
||||||
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
let framebuffer_size = self.ui_presenter.framebuffer_size();
|
||||||
let bottom = framebuffer_size.y() - PADDING;
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
let window_rect = RectI::new(
|
let window_rect = RectI::new(
|
||||||
vec2i(framebuffer_size.x() - PADDING - PERFORMANCE_WINDOW_WIDTH,
|
vec2i(framebuffer_size.x() - PADDING - performance_window_size.x(),
|
||||||
bottom - PERFORMANCE_WINDOW_HEIGHT),
|
bottom - INFO_WINDOW_HEIGHT - PADDING - performance_window_size.y()),
|
||||||
vec2i(PERFORMANCE_WINDOW_WIDTH, PERFORMANCE_WINDOW_HEIGHT),
|
performance_window_size);
|
||||||
);
|
|
||||||
|
|
||||||
self.ui_presenter.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
|
||||||
|
|
||||||
let mean_cpu_sample = self.cpu_samples.mean();
|
let mean_cpu_sample = self.cpu_samples.mean();
|
||||||
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
|
||||||
self.ui_presenter.draw_text(
|
|
||||||
device,
|
|
||||||
&format!("CPU: {:.3} ms", duration_to_ms(mean_cpu_sample.cpu_build_time)),
|
|
||||||
origin,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mean_gpu_sample = self.gpu_samples.mean();
|
let mean_gpu_sample = self.gpu_samples.mean();
|
||||||
|
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
|
||||||
|
|
||||||
|
let mut current_y = 0;
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
&format!("GPU: {:.3} ms", duration_to_ms(mean_gpu_sample.gpu_time)),
|
allocator,
|
||||||
origin + vec2i(0, LINE_HEIGHT * 1),
|
&format!("Drawcalls: {}", mean_cpu_sample.drawcall_count),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
let wallclock_time = f64::max(duration_to_ms(mean_gpu_sample.gpu_time),
|
|
||||||
duration_to_ms(mean_cpu_sample.cpu_build_time));
|
|
||||||
self.ui_presenter.draw_text(
|
self.ui_presenter.draw_text(
|
||||||
device,
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("VRAM Alloc.: {:.1} MB",
|
||||||
|
mean_cpu_sample.gpu_bytes_allocated as f64 / (1024.0 * 1024.0)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("VRAM Commit: {:.1} MB",
|
||||||
|
mean_cpu_sample.gpu_bytes_committed as f64 / (1024.0 * 1024.0)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("CPU: {:.3} ms", duration_to_ms(mean_cpu_sample.cpu_build_time)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
|
||||||
|
match self.renderer_level {
|
||||||
|
RendererLevel::D3D11 => {
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("GPU Dice: {:.3} ms", duration_to_ms(mean_gpu_sample.dice_time)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("GPU Bin: {:.3} ms", duration_to_ms(mean_gpu_sample.bin_time)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
}
|
||||||
|
RendererLevel::D3D9 => {}
|
||||||
|
}
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("GPU Fill: {:.3} ms", duration_to_ms(mean_gpu_sample.fill_time)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("GPU Comp.: {:.3} ms", duration_to_ms(mean_gpu_sample.composite_time)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
|
&format!("GPU Other: {:.3} ms", duration_to_ms(mean_gpu_sample.other_time)),
|
||||||
|
origin + vec2i(0, current_y),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
current_y += LINE_HEIGHT;
|
||||||
|
|
||||||
|
let mut wallclock_time = match self.renderer_level {
|
||||||
|
RendererLevel::D3D11 => {
|
||||||
|
duration_to_ms(mean_cpu_sample.cpu_build_time) +
|
||||||
|
duration_to_ms(mean_gpu_sample.fill_time)
|
||||||
|
}
|
||||||
|
RendererLevel::D3D9 => {
|
||||||
|
f64::max(duration_to_ms(mean_cpu_sample.cpu_build_time),
|
||||||
|
duration_to_ms(mean_gpu_sample.fill_time))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
wallclock_time += duration_to_ms(mean_gpu_sample.composite_time) +
|
||||||
|
duration_to_ms(mean_gpu_sample.dice_time) +
|
||||||
|
duration_to_ms(mean_gpu_sample.bin_time) +
|
||||||
|
duration_to_ms(mean_gpu_sample.other_time);
|
||||||
|
self.ui_presenter.draw_text(
|
||||||
|
device,
|
||||||
|
allocator,
|
||||||
&format!("Wallclock: {:.3} ms", wallclock_time),
|
&format!("Wallclock: {:.3} ms", wallclock_time),
|
||||||
origin + vec2i(0, LINE_HEIGHT * 3),
|
origin + vec2i(0, current_y),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,12 @@
|
||||||
|
|
||||||
//! The GPU renderer for Pathfinder 3.
|
//! The GPU renderer for Pathfinder 3.
|
||||||
|
|
||||||
|
pub mod d3d9;
|
||||||
|
pub mod d3d11;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod options;
|
pub mod options;
|
||||||
|
pub mod perf;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
|
|
||||||
|
pub(crate) mod blend;
|
||||||
pub(crate) mod shaders;
|
pub(crate) mod shaders;
|
||||||
|
|
|
@ -11,13 +11,58 @@
|
||||||
use pathfinder_color::ColorF;
|
use pathfinder_color::ColorF;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_gpu::Device;
|
use pathfinder_gpu::{Device, FeatureLevel};
|
||||||
|
|
||||||
/// Options that influence rendering.
|
/// Renderer options that can't be changed after the renderer is created.
|
||||||
#[derive(Default)]
|
pub struct RendererMode {
|
||||||
pub struct RendererOptions {
|
/// The level of hardware features that the renderer will attempt to use.
|
||||||
|
pub level: RendererLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Options that influence rendering that can be changed at runtime.
|
||||||
|
pub struct RendererOptions<D> where D: Device {
|
||||||
|
/// Where the rendering should go: either to the default framebuffer (i.e. screen) or to a
|
||||||
|
/// custom framebuffer.
|
||||||
|
pub dest: DestFramebuffer<D>,
|
||||||
|
/// The background color. If not present, transparent is assumed.
|
||||||
pub background_color: Option<ColorF>,
|
pub background_color: Option<ColorF>,
|
||||||
pub no_compute: bool,
|
/// Whether to display the debug UI.
|
||||||
|
pub show_debug_ui: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum RendererLevel {
|
||||||
|
/// Direct3D 9/OpenGL 3.0/WebGL 2.0 compatibility. Bin on CPU, fill and composite on GPU.
|
||||||
|
D3D9,
|
||||||
|
/// Direct3D 11/OpenGL 4.3/Metal/Vulkan/WebGPU compatibility. Bin, fill, and composite on GPU.
|
||||||
|
D3D11,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RendererMode {
|
||||||
|
#[inline]
|
||||||
|
pub fn default_for_device<D>(device: &D) -> RendererMode where D: Device {
|
||||||
|
RendererMode { level: RendererLevel::default_for_device(device) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> Default for RendererOptions<D> where D: Device {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> RendererOptions<D> {
|
||||||
|
RendererOptions {
|
||||||
|
dest: DestFramebuffer::default(),
|
||||||
|
background_color: None,
|
||||||
|
show_debug_ui: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RendererLevel {
|
||||||
|
pub fn default_for_device<D>(device: &D) -> RendererLevel where D: Device {
|
||||||
|
match device.feature_level() {
|
||||||
|
FeatureLevel::D3D10 => RendererLevel::D3D9,
|
||||||
|
FeatureLevel::D3D11 => RendererLevel::D3D11,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
// pathfinder/renderer/src/gpu/perf.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
//! Performance monitoring infrastructure.
|
||||||
|
|
||||||
|
use pathfinder_gpu::Device;
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{Add, Div};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct RenderStats {
|
||||||
|
pub path_count: usize,
|
||||||
|
pub fill_count: usize,
|
||||||
|
pub alpha_tile_count: usize,
|
||||||
|
pub total_tile_count: usize,
|
||||||
|
pub cpu_build_time: Duration,
|
||||||
|
pub drawcall_count: u32,
|
||||||
|
pub gpu_bytes_allocated: u64,
|
||||||
|
pub gpu_bytes_committed: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<RenderStats> for RenderStats {
|
||||||
|
type Output = RenderStats;
|
||||||
|
fn add(self, other: RenderStats) -> RenderStats {
|
||||||
|
RenderStats {
|
||||||
|
path_count: self.path_count + other.path_count,
|
||||||
|
alpha_tile_count: self.alpha_tile_count + other.alpha_tile_count,
|
||||||
|
total_tile_count: self.total_tile_count + other.total_tile_count,
|
||||||
|
fill_count: self.fill_count + other.fill_count,
|
||||||
|
cpu_build_time: self.cpu_build_time + other.cpu_build_time,
|
||||||
|
drawcall_count: self.drawcall_count + other.drawcall_count,
|
||||||
|
gpu_bytes_allocated: self.gpu_bytes_allocated + other.gpu_bytes_allocated,
|
||||||
|
gpu_bytes_committed: self.gpu_bytes_committed + other.gpu_bytes_committed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<usize> for RenderStats {
|
||||||
|
type Output = RenderStats;
|
||||||
|
fn div(self, divisor: usize) -> RenderStats {
|
||||||
|
RenderStats {
|
||||||
|
path_count: self.path_count / divisor,
|
||||||
|
alpha_tile_count: self.alpha_tile_count / divisor,
|
||||||
|
total_tile_count: self.total_tile_count / divisor,
|
||||||
|
fill_count: self.fill_count / divisor,
|
||||||
|
cpu_build_time: self.cpu_build_time / divisor as u32,
|
||||||
|
drawcall_count: self.drawcall_count / divisor as u32,
|
||||||
|
gpu_bytes_allocated: self.gpu_bytes_allocated / divisor as u64,
|
||||||
|
gpu_bytes_committed: self.gpu_bytes_committed / divisor as u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TimerQueryCache<D> where D: Device {
|
||||||
|
free_queries: Vec<D::TimerQuery>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct PendingTimer<D> where D: Device {
|
||||||
|
pub(crate) dice_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) bin_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) fill_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) composite_times: Vec<TimerFuture<D>>,
|
||||||
|
pub(crate) other_times: Vec<TimerFuture<D>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum TimerFuture<D> where D: Device {
|
||||||
|
Pending(D::TimerQuery),
|
||||||
|
Resolved(Duration),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TimerQueryCache<D> where D: Device {
|
||||||
|
pub(crate) fn new() -> TimerQueryCache<D> {
|
||||||
|
TimerQueryCache { free_queries: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn alloc(&mut self, device: &D) -> D::TimerQuery {
|
||||||
|
self.free_queries.pop().unwrap_or_else(|| device.create_timer_query())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn free(&mut self, old_query: D::TimerQuery) {
|
||||||
|
self.free_queries.push(old_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> PendingTimer<D> where D: Device {
|
||||||
|
pub(crate) fn new() -> PendingTimer<D> {
|
||||||
|
PendingTimer {
|
||||||
|
dice_times: vec![],
|
||||||
|
bin_times: vec![],
|
||||||
|
fill_times: vec![],
|
||||||
|
composite_times: vec![],
|
||||||
|
other_times: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn poll(&mut self, device: &D) -> Vec<D::TimerQuery> {
|
||||||
|
let mut old_queries = vec![];
|
||||||
|
for future in self.dice_times.iter_mut().chain(self.bin_times.iter_mut())
|
||||||
|
.chain(self.fill_times.iter_mut())
|
||||||
|
.chain(self.composite_times.iter_mut())
|
||||||
|
.chain(self.other_times.iter_mut()) {
|
||||||
|
if let Some(old_query) = future.poll(device) {
|
||||||
|
old_queries.push(old_query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_queries
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn total_time(&self) -> Option<RenderTime> {
|
||||||
|
let dice_time = total_time_of_timer_futures(&self.dice_times);
|
||||||
|
let bin_time = total_time_of_timer_futures(&self.bin_times);
|
||||||
|
let fill_time = total_time_of_timer_futures(&self.fill_times);
|
||||||
|
let composite_time = total_time_of_timer_futures(&self.composite_times);
|
||||||
|
let other_time = total_time_of_timer_futures(&self.other_times);
|
||||||
|
match (dice_time, bin_time, fill_time, composite_time, other_time) {
|
||||||
|
(Some(dice_time),
|
||||||
|
Some(bin_time),
|
||||||
|
Some(fill_time),
|
||||||
|
Some(composite_time),
|
||||||
|
Some(other_time)) => {
|
||||||
|
Some(RenderTime { dice_time, bin_time, fill_time, composite_time, other_time })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> TimerFuture<D> where D: Device {
|
||||||
|
pub(crate) fn new(query: D::TimerQuery) -> TimerFuture<D> {
|
||||||
|
TimerFuture::Pending(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&mut self, device: &D) -> Option<D::TimerQuery> {
|
||||||
|
let duration = match *self {
|
||||||
|
TimerFuture::Pending(ref query) => device.try_recv_timer_query(query),
|
||||||
|
TimerFuture::Resolved(_) => None,
|
||||||
|
};
|
||||||
|
match duration {
|
||||||
|
None => None,
|
||||||
|
Some(duration) => {
|
||||||
|
match mem::replace(self, TimerFuture::Resolved(duration)) {
|
||||||
|
TimerFuture::Resolved(_) => unreachable!(),
|
||||||
|
TimerFuture::Pending(old_query) => Some(old_query),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn total_time_of_timer_futures<D>(futures: &[TimerFuture<D>]) -> Option<Duration> where D: Device {
|
||||||
|
let mut total = Duration::default();
|
||||||
|
for future in futures {
|
||||||
|
match *future {
|
||||||
|
TimerFuture::Pending(_) => return None,
|
||||||
|
TimerFuture::Resolved(time) => total += time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct RenderTime {
|
||||||
|
pub dice_time: Duration,
|
||||||
|
pub bin_time: Duration,
|
||||||
|
pub fill_time: Duration,
|
||||||
|
pub composite_time: Duration,
|
||||||
|
pub other_time: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderTime {
|
||||||
|
#[inline]
|
||||||
|
pub fn total_time(&self) -> Duration {
|
||||||
|
self.dice_time + self.bin_time + self.fill_time + self.composite_time + self.other_time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RenderTime {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> RenderTime {
|
||||||
|
RenderTime {
|
||||||
|
dice_time: Duration::new(0, 0),
|
||||||
|
bin_time: Duration::new(0, 0),
|
||||||
|
fill_time: Duration::new(0, 0),
|
||||||
|
composite_time: Duration::new(0, 0),
|
||||||
|
other_time: Duration::new(0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<RenderTime> for RenderTime {
|
||||||
|
type Output = RenderTime;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: RenderTime) -> RenderTime {
|
||||||
|
RenderTime {
|
||||||
|
dice_time: self.dice_time + other.dice_time,
|
||||||
|
bin_time: self.bin_time + other.bin_time,
|
||||||
|
fill_time: self.fill_time + other.fill_time,
|
||||||
|
composite_time: self.composite_time + other.composite_time,
|
||||||
|
other_time: self.other_time + other.other_time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<usize> for RenderTime {
|
||||||
|
type Output = RenderTime;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn div(self, divisor: usize) -> RenderTime {
|
||||||
|
let divisor = divisor as u32;
|
||||||
|
RenderTime {
|
||||||
|
dice_time: self.dice_time / divisor,
|
||||||
|
bin_time: self.bin_time / divisor,
|
||||||
|
fill_time: self.fill_time / divisor,
|
||||||
|
composite_time: self.composite_time / divisor,
|
||||||
|
other_time: self.other_time / divisor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -8,20 +8,12 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::gpu::options::RendererOptions;
|
use pathfinder_gpu::{BufferTarget, BufferUploadMode, Device, VertexAttrClass};
|
||||||
use crate::gpu::renderer::{MASK_TILES_ACROSS, MASK_TILES_DOWN};
|
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
|
||||||
use pathfinder_gpu::{BufferTarget, BufferUploadMode, ComputeDimensions, Device, FeatureLevel};
|
|
||||||
use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
|
|
||||||
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
// TODO(pcwalton): Replace with `mem::size_of` calls?
|
||||||
pub(crate) const TILE_INSTANCE_SIZE: usize = 12;
|
pub(crate) const TILE_INSTANCE_SIZE: usize = 16;
|
||||||
const FILL_INSTANCE_SIZE: usize = 8;
|
|
||||||
const CLIP_TILE_INSTANCE_SIZE: usize = 8;
|
|
||||||
|
|
||||||
pub const MAX_FILLS_PER_BATCH: usize = 0x10000;
|
|
||||||
pub const MAX_TILES_PER_BATCH: usize = MASK_TILES_ACROSS as usize * MASK_TILES_DOWN as usize;
|
|
||||||
|
|
||||||
pub struct BlitVertexArray<D> where D: Device {
|
pub struct BlitVertexArray<D> where D: Device {
|
||||||
pub vertex_array: D::VertexArray,
|
pub vertex_array: D::VertexArray,
|
||||||
|
@ -52,6 +44,25 @@ impl<D> BlitVertexArray<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VertexArraysCore<D> where D: Device {
|
||||||
|
pub blit_vertex_array: BlitVertexArray<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> VertexArraysCore<D> where D: Device {
|
||||||
|
pub fn new(device: &D,
|
||||||
|
programs: &ProgramsCore<D>,
|
||||||
|
quad_vertex_positions_buffer: &D::Buffer,
|
||||||
|
quad_vertex_indices_buffer: &D::Buffer)
|
||||||
|
-> VertexArraysCore<D> {
|
||||||
|
VertexArraysCore {
|
||||||
|
blit_vertex_array: BlitVertexArray::new(device,
|
||||||
|
&programs.blit_program,
|
||||||
|
quad_vertex_positions_buffer,
|
||||||
|
quad_vertex_indices_buffer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ClearVertexArray<D> where D: Device {
|
pub struct ClearVertexArray<D> where D: Device {
|
||||||
pub vertex_array: D::VertexArray,
|
pub vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
@ -81,288 +92,32 @@ impl<D> ClearVertexArray<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FillVertexArray<D> where D: Device {
|
|
||||||
pub vertex_array: D::VertexArray,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> FillVertexArray<D>
|
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub fn new(
|
|
||||||
device: &D,
|
|
||||||
fill_program: &FillRasterProgram<D>,
|
|
||||||
vertex_buffer: &D::Buffer,
|
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
|
||||||
quad_vertex_indices_buffer: &D::Buffer,
|
|
||||||
) -> FillVertexArray<D> {
|
|
||||||
let vertex_array = device.create_vertex_array();
|
|
||||||
|
|
||||||
let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap();
|
|
||||||
let from_px_attr = device.get_vertex_attr(&fill_program.program, "FromPx").unwrap();
|
|
||||||
let to_px_attr = device.get_vertex_attr(&fill_program.program, "ToPx").unwrap();
|
|
||||||
let from_subpx_attr = device.get_vertex_attr(&fill_program.program, "FromSubpx").unwrap();
|
|
||||||
let to_subpx_attr = device.get_vertex_attr(&fill_program.program, "ToSubpx").unwrap();
|
|
||||||
let tile_index_attr = device.get_vertex_attr(&fill_program.program, "TileIndex").unwrap();
|
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U16,
|
|
||||||
stride: 4,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 0,
|
|
||||||
buffer_index: 0,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &from_subpx_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::FloatNorm,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: FILL_INSTANCE_SIZE,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &to_subpx_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::FloatNorm,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: FILL_INSTANCE_SIZE,
|
|
||||||
offset: 2,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &from_px_attr, &VertexAttrDescriptor {
|
|
||||||
size: 1,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: FILL_INSTANCE_SIZE,
|
|
||||||
offset: 4,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &to_px_attr, &VertexAttrDescriptor {
|
|
||||||
size: 1,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: FILL_INSTANCE_SIZE,
|
|
||||||
offset: 5,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor {
|
|
||||||
size: 1,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U16,
|
|
||||||
stride: FILL_INSTANCE_SIZE,
|
|
||||||
offset: 6,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
|
||||||
|
|
||||||
FillVertexArray { vertex_array }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TileVertexArray<D> where D: Device {
|
|
||||||
pub vertex_array: D::VertexArray,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> TileVertexArray<D> where D: Device {
|
|
||||||
pub fn new(device: &D,
|
|
||||||
tile_program: &TileProgram<D>,
|
|
||||||
tile_vertex_buffer: &D::Buffer,
|
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
|
||||||
-> TileVertexArray<D> {
|
|
||||||
let vertex_array = device.create_vertex_array();
|
|
||||||
|
|
||||||
let tile_offset_attr =
|
|
||||||
device.get_vertex_attr(&tile_program.program, "TileOffset").unwrap();
|
|
||||||
let tile_origin_attr =
|
|
||||||
device.get_vertex_attr(&tile_program.program, "TileOrigin").unwrap();
|
|
||||||
let mask_0_tex_coord_attr =
|
|
||||||
device.get_vertex_attr(&tile_program.program, "MaskTexCoord0").unwrap();
|
|
||||||
let mask_backdrop_attr =
|
|
||||||
device.get_vertex_attr(&tile_program.program, "MaskBackdrop").unwrap();
|
|
||||||
let color_attr = device.get_vertex_attr(&tile_program.program, "Color").unwrap();
|
|
||||||
let tile_ctrl_attr = device.get_vertex_attr(&tile_program.program, "TileCtrl").unwrap();
|
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I16,
|
|
||||||
stride: 4,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 0,
|
|
||||||
buffer_index: 0,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I16,
|
|
||||||
stride: TILE_INSTANCE_SIZE,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &mask_0_tex_coord_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: TILE_INSTANCE_SIZE,
|
|
||||||
offset: 4,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &mask_backdrop_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I8,
|
|
||||||
stride: TILE_INSTANCE_SIZE,
|
|
||||||
offset: 6,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &color_attr, &VertexAttrDescriptor {
|
|
||||||
size: 1,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I16,
|
|
||||||
stride: TILE_INSTANCE_SIZE,
|
|
||||||
offset: 8,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_ctrl_attr, &VertexAttrDescriptor {
|
|
||||||
size: 1,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I16,
|
|
||||||
stride: TILE_INSTANCE_SIZE,
|
|
||||||
offset: 10,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
|
||||||
|
|
||||||
TileVertexArray { vertex_array }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CopyTileVertexArray<D> where D: Device {
|
|
||||||
pub vertex_array: D::VertexArray,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> CopyTileVertexArray<D> where D: Device {
|
|
||||||
pub fn new(
|
|
||||||
device: &D,
|
|
||||||
copy_tile_program: &CopyTileProgram<D>,
|
|
||||||
copy_tile_vertex_buffer: &D::Buffer,
|
|
||||||
quads_vertex_indices_buffer: &D::Buffer,
|
|
||||||
) -> CopyTileVertexArray<D> {
|
|
||||||
let vertex_array = device.create_vertex_array();
|
|
||||||
|
|
||||||
let tile_position_attr =
|
|
||||||
device.get_vertex_attr(©_tile_program.program, "TilePosition").unwrap();
|
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, copy_tile_vertex_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I16,
|
|
||||||
stride: TILE_INSTANCE_SIZE,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 0,
|
|
||||||
buffer_index: 0,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
|
|
||||||
|
|
||||||
CopyTileVertexArray { vertex_array }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ClipTileVertexArray<D> where D: Device {
|
|
||||||
pub vertex_array: D::VertexArray,
|
|
||||||
pub vertex_buffer: D::Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> ClipTileVertexArray<D> where D: Device {
|
|
||||||
pub fn new(device: &D,
|
|
||||||
clip_tile_program: &ClipTileProgram<D>,
|
|
||||||
quad_vertex_positions_buffer: &D::Buffer,
|
|
||||||
quad_vertex_indices_buffer: &D::Buffer)
|
|
||||||
-> ClipTileVertexArray<D> {
|
|
||||||
let vertex_array = device.create_vertex_array();
|
|
||||||
let vertex_buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
|
||||||
|
|
||||||
let tile_offset_attr =
|
|
||||||
device.get_vertex_attr(&clip_tile_program.program, "TileOffset").unwrap();
|
|
||||||
let dest_tile_origin_attr =
|
|
||||||
device.get_vertex_attr(&clip_tile_program.program, "DestTileOrigin").unwrap();
|
|
||||||
let src_tile_origin_attr =
|
|
||||||
device.get_vertex_attr(&clip_tile_program.program, "SrcTileOrigin").unwrap();
|
|
||||||
let src_backdrop_attr =
|
|
||||||
device.get_vertex_attr(&clip_tile_program.program, "SrcBackdrop").unwrap();
|
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I16,
|
|
||||||
stride: 4,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 0,
|
|
||||||
buffer_index: 0,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
|
||||||
device.configure_vertex_attr(&vertex_array, &dest_tile_origin_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: CLIP_TILE_INSTANCE_SIZE,
|
|
||||||
offset: 0,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &src_tile_origin_attr, &VertexAttrDescriptor {
|
|
||||||
size: 2,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::U8,
|
|
||||||
stride: CLIP_TILE_INSTANCE_SIZE,
|
|
||||||
offset: 2,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.configure_vertex_attr(&vertex_array, &src_backdrop_attr, &VertexAttrDescriptor {
|
|
||||||
size: 1,
|
|
||||||
class: VertexAttrClass::Int,
|
|
||||||
attr_type: VertexAttrType::I8,
|
|
||||||
stride: CLIP_TILE_INSTANCE_SIZE,
|
|
||||||
offset: 4,
|
|
||||||
divisor: 1,
|
|
||||||
buffer_index: 1,
|
|
||||||
});
|
|
||||||
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
|
|
||||||
|
|
||||||
ClipTileVertexArray { vertex_array, vertex_buffer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct BlitProgram<D> where D: Device {
|
pub struct BlitProgram<D> where D: Device {
|
||||||
pub program: D::Program,
|
pub program: D::Program,
|
||||||
|
pub dest_rect_uniform: D::Uniform,
|
||||||
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
pub src_texture: D::TextureParameter,
|
pub src_texture: D::TextureParameter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> BlitProgram<D> where D: Device {
|
impl<D> BlitProgram<D> where D: Device {
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> {
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "blit");
|
let program = device.create_raster_program(resources, "blit");
|
||||||
|
let dest_rect_uniform = device.get_uniform(&program, "DestRect");
|
||||||
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let src_texture = device.get_texture_parameter(&program, "Src");
|
let src_texture = device.get_texture_parameter(&program, "Src");
|
||||||
BlitProgram { program, src_texture }
|
BlitProgram { program, dest_rect_uniform, framebuffer_size_uniform, src_texture }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProgramsCore<D> where D: Device {
|
||||||
|
pub blit_program: BlitProgram<D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> ProgramsCore<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsCore<D> {
|
||||||
|
ProgramsCore {
|
||||||
|
blit_program: BlitProgram::new(device, resources),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,211 +138,73 @@ impl<D> ClearProgram<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FillProgram<D> where D: Device {
|
pub struct TileProgramCommon<D> where D: Device {
|
||||||
Raster(FillRasterProgram<D>),
|
|
||||||
Compute(FillComputeProgram<D>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> FillProgram<D> where D: Device {
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader, options: &RendererOptions)
|
|
||||||
-> FillProgram<D> {
|
|
||||||
match (options.no_compute, device.feature_level()) {
|
|
||||||
(false, FeatureLevel::D3D11) => {
|
|
||||||
FillProgram::Compute(FillComputeProgram::new(device, resources))
|
|
||||||
}
|
|
||||||
(_, FeatureLevel::D3D10) | (true, _) => {
|
|
||||||
FillProgram::Raster(FillRasterProgram::new(device, resources))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FillRasterProgram<D> where D: Device {
|
|
||||||
pub program: D::Program,
|
pub program: D::Program,
|
||||||
pub framebuffer_size_uniform: D::Uniform,
|
|
||||||
pub tile_size_uniform: D::Uniform,
|
|
||||||
pub area_lut_texture: D::TextureParameter,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> FillRasterProgram<D> where D: Device {
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> FillRasterProgram<D> {
|
|
||||||
let program = device.create_raster_program(resources, "fill");
|
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
|
||||||
let area_lut_texture = device.get_texture_parameter(&program, "AreaLUT");
|
|
||||||
FillRasterProgram {
|
|
||||||
program,
|
|
||||||
framebuffer_size_uniform,
|
|
||||||
tile_size_uniform,
|
|
||||||
area_lut_texture,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FillComputeProgram<D> where D: Device {
|
|
||||||
pub program: D::Program,
|
|
||||||
pub dest_image: D::ImageParameter,
|
|
||||||
pub area_lut_texture: D::TextureParameter,
|
|
||||||
pub first_tile_index_uniform: D::Uniform,
|
|
||||||
pub fills_storage_buffer: D::StorageBuffer,
|
|
||||||
pub next_fills_storage_buffer: D::StorageBuffer,
|
|
||||||
pub fill_tile_map_storage_buffer: D::StorageBuffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> FillComputeProgram<D> where D: Device {
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> FillComputeProgram<D> {
|
|
||||||
let mut program = device.create_compute_program(resources, "fill");
|
|
||||||
let local_size = ComputeDimensions { x: TILE_WIDTH, y: TILE_HEIGHT / 4, z: 1 };
|
|
||||||
device.set_compute_program_local_size(&mut program, local_size);
|
|
||||||
|
|
||||||
let dest_image = device.get_image_parameter(&program, "Dest");
|
|
||||||
let area_lut_texture = device.get_texture_parameter(&program, "AreaLUT");
|
|
||||||
let first_tile_index_uniform = device.get_uniform(&program, "FirstTileIndex");
|
|
||||||
let fills_storage_buffer = device.get_storage_buffer(&program, "Fills", 0);
|
|
||||||
let next_fills_storage_buffer = device.get_storage_buffer(&program, "NextFills", 1);
|
|
||||||
let fill_tile_map_storage_buffer = device.get_storage_buffer(&program, "FillTileMap", 2);
|
|
||||||
|
|
||||||
FillComputeProgram {
|
|
||||||
program,
|
|
||||||
dest_image,
|
|
||||||
area_lut_texture,
|
|
||||||
first_tile_index_uniform,
|
|
||||||
fills_storage_buffer,
|
|
||||||
next_fills_storage_buffer,
|
|
||||||
fill_tile_map_storage_buffer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TileProgram<D> where D: Device {
|
|
||||||
pub program: D::Program,
|
|
||||||
pub transform_uniform: D::Uniform,
|
|
||||||
pub tile_size_uniform: D::Uniform,
|
pub tile_size_uniform: D::Uniform,
|
||||||
pub texture_metadata_texture: D::TextureParameter,
|
pub texture_metadata_texture: D::TextureParameter,
|
||||||
pub texture_metadata_size_uniform: D::Uniform,
|
pub texture_metadata_size_uniform: D::Uniform,
|
||||||
pub dest_texture: D::TextureParameter,
|
pub z_buffer_texture: D::TextureParameter,
|
||||||
|
pub z_buffer_texture_size_uniform: D::Uniform,
|
||||||
pub color_texture_0: D::TextureParameter,
|
pub color_texture_0: D::TextureParameter,
|
||||||
pub color_texture_size_0_uniform: D::Uniform,
|
pub color_texture_size_0_uniform: D::Uniform,
|
||||||
pub color_texture_1: D::TextureParameter,
|
pub color_texture_1: D::TextureParameter,
|
||||||
pub mask_texture_0: D::TextureParameter,
|
pub mask_texture_0: D::TextureParameter,
|
||||||
pub mask_texture_size_0_uniform: D::Uniform,
|
pub mask_texture_size_0_uniform: D::Uniform,
|
||||||
pub gamma_lut_texture: D::TextureParameter,
|
pub gamma_lut_texture: D::TextureParameter,
|
||||||
pub filter_params_0_uniform: D::Uniform,
|
|
||||||
pub filter_params_1_uniform: D::Uniform,
|
|
||||||
pub filter_params_2_uniform: D::Uniform,
|
|
||||||
pub framebuffer_size_uniform: D::Uniform,
|
pub framebuffer_size_uniform: D::Uniform,
|
||||||
pub ctrl_uniform: D::Uniform,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TileProgram<D> where D: Device {
|
impl<D> TileProgramCommon<D> where D: Device {
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> TileProgram<D> {
|
pub(crate) fn new(device: &D, program: D::Program) -> TileProgramCommon<D> {
|
||||||
let program = device.create_raster_program(resources, "tile");
|
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
||||||
let texture_metadata_texture = device.get_texture_parameter(&program, "TextureMetadata");
|
let texture_metadata_texture = device.get_texture_parameter(&program, "TextureMetadata");
|
||||||
let texture_metadata_size_uniform = device.get_uniform(&program, "TextureMetadataSize");
|
let texture_metadata_size_uniform = device.get_uniform(&program, "TextureMetadataSize");
|
||||||
let dest_texture = device.get_texture_parameter(&program, "DestTexture");
|
let z_buffer_texture = device.get_texture_parameter(&program, "ZBuffer");
|
||||||
|
let z_buffer_texture_size_uniform = device.get_uniform(&program, "ZBufferSize");
|
||||||
let color_texture_0 = device.get_texture_parameter(&program, "ColorTexture0");
|
let color_texture_0 = device.get_texture_parameter(&program, "ColorTexture0");
|
||||||
let color_texture_size_0_uniform = device.get_uniform(&program, "ColorTextureSize0");
|
let color_texture_size_0_uniform = device.get_uniform(&program, "ColorTextureSize0");
|
||||||
let color_texture_1 = device.get_texture_parameter(&program, "ColorTexture1");
|
let color_texture_1 = device.get_texture_parameter(&program, "ColorTexture1");
|
||||||
let mask_texture_0 = device.get_texture_parameter(&program, "MaskTexture0");
|
let mask_texture_0 = device.get_texture_parameter(&program, "MaskTexture0");
|
||||||
let mask_texture_size_0_uniform = device.get_uniform(&program, "MaskTextureSize0");
|
let mask_texture_size_0_uniform = device.get_uniform(&program, "MaskTextureSize0");
|
||||||
let gamma_lut_texture = device.get_texture_parameter(&program, "GammaLUT");
|
let gamma_lut_texture = device.get_texture_parameter(&program, "GammaLUT");
|
||||||
let filter_params_0_uniform = device.get_uniform(&program, "FilterParams0");
|
|
||||||
let filter_params_1_uniform = device.get_uniform(&program, "FilterParams1");
|
|
||||||
let filter_params_2_uniform = device.get_uniform(&program, "FilterParams2");
|
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let ctrl_uniform = device.get_uniform(&program, "Ctrl");
|
|
||||||
TileProgram {
|
TileProgramCommon {
|
||||||
program,
|
program,
|
||||||
transform_uniform,
|
|
||||||
tile_size_uniform,
|
tile_size_uniform,
|
||||||
texture_metadata_texture,
|
texture_metadata_texture,
|
||||||
texture_metadata_size_uniform,
|
texture_metadata_size_uniform,
|
||||||
dest_texture,
|
z_buffer_texture,
|
||||||
|
z_buffer_texture_size_uniform,
|
||||||
color_texture_0,
|
color_texture_0,
|
||||||
color_texture_size_0_uniform,
|
color_texture_size_0_uniform,
|
||||||
color_texture_1,
|
color_texture_1,
|
||||||
mask_texture_0,
|
mask_texture_0,
|
||||||
mask_texture_size_0_uniform,
|
mask_texture_size_0_uniform,
|
||||||
gamma_lut_texture,
|
gamma_lut_texture,
|
||||||
filter_params_0_uniform,
|
|
||||||
filter_params_1_uniform,
|
|
||||||
filter_params_2_uniform,
|
|
||||||
framebuffer_size_uniform,
|
framebuffer_size_uniform,
|
||||||
ctrl_uniform,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CopyTileProgram<D> where D: Device {
|
pub struct StencilProgram<D> where D: Device {
|
||||||
pub program: D::Program,
|
|
||||||
pub transform_uniform: D::Uniform,
|
|
||||||
pub tile_size_uniform: D::Uniform,
|
|
||||||
pub framebuffer_size_uniform: D::Uniform,
|
|
||||||
pub src_texture: D::TextureParameter,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> CopyTileProgram<D> where D: Device {
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> {
|
|
||||||
let program = device.create_raster_program(resources, "tile_copy");
|
|
||||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
|
||||||
let tile_size_uniform = device.get_uniform(&program, "TileSize");
|
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
|
||||||
let src_texture = device.get_texture_parameter(&program, "Src");
|
|
||||||
CopyTileProgram {
|
|
||||||
program,
|
|
||||||
transform_uniform,
|
|
||||||
tile_size_uniform,
|
|
||||||
framebuffer_size_uniform,
|
|
||||||
src_texture,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ClipTileProgram<D> where D: Device {
|
|
||||||
pub program: D::Program,
|
|
||||||
pub src_texture: D::TextureParameter,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> ClipTileProgram<D> where D: Device {
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileProgram<D> {
|
|
||||||
let program = device.create_raster_program(resources, "tile_clip");
|
|
||||||
let src_texture = device.get_texture_parameter(&program, "Src");
|
|
||||||
ClipTileProgram { program, src_texture }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct StencilProgram<D>
|
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub program: D::Program,
|
pub program: D::Program,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> StencilProgram<D>
|
impl<D> StencilProgram<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram<D> {
|
pub fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "stencil");
|
let program = device.create_raster_program(resources, "stencil");
|
||||||
StencilProgram { program }
|
StencilProgram { program }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StencilVertexArray<D>
|
pub struct StencilVertexArray<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub vertex_array: D::VertexArray,
|
pub vertex_array: D::VertexArray,
|
||||||
pub vertex_buffer: D::Buffer,
|
pub vertex_buffer: D::Buffer,
|
||||||
pub index_buffer: D::Buffer,
|
pub index_buffer: D::Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> StencilVertexArray<D>
|
impl<D> StencilVertexArray<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub fn new(device: &D, stencil_program: &StencilProgram<D>) -> StencilVertexArray<D> {
|
pub fn new(device: &D, stencil_program: &StencilProgram<D>) -> StencilVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
let vertex_buffer = device.create_buffer(BufferUploadMode::Static);
|
let vertex_buffer = device.create_buffer(BufferUploadMode::Static);
|
||||||
|
@ -628,17 +245,11 @@ impl<D> ReprojectionProgram<D> where D: Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReprojectionVertexArray<D>
|
pub struct ReprojectionVertexArray<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub vertex_array: D::VertexArray,
|
pub vertex_array: D::VertexArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> ReprojectionVertexArray<D>
|
impl<D> ReprojectionVertexArray<D> where D: Device {
|
||||||
where
|
|
||||||
D: Device,
|
|
||||||
{
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &D,
|
device: &D,
|
||||||
reprojection_program: &ReprojectionProgram<D>,
|
reprojection_program: &ReprojectionProgram<D>,
|
||||||
|
|
|
@ -13,13 +13,15 @@
|
||||||
use crate::builder::{ALPHA_TILES_PER_LEVEL, ALPHA_TILE_LEVEL_COUNT};
|
use crate::builder::{ALPHA_TILES_PER_LEVEL, ALPHA_TILE_LEVEL_COUNT};
|
||||||
use crate::options::BoundingQuad;
|
use crate::options::BoundingQuad;
|
||||||
use crate::paint::PaintCompositeOp;
|
use crate::paint::PaintCompositeOp;
|
||||||
|
use crate::scene::PathId;
|
||||||
|
use crate::tile_map::DenseTileMap;
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_content::effects::{BlendMode, Filter};
|
use pathfinder_content::effects::{BlendMode, Filter};
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU16};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -64,13 +66,18 @@ pub enum RenderCommand {
|
||||||
UploadTextureMetadata(Vec<TextureMetadataEntry>),
|
UploadTextureMetadata(Vec<TextureMetadataEntry>),
|
||||||
|
|
||||||
// Adds fills to the queue.
|
// Adds fills to the queue.
|
||||||
AddFills(Vec<FillBatchEntry>),
|
AddFillsD3D9(Vec<Fill>),
|
||||||
|
|
||||||
// Flushes the queue of fills.
|
// Flushes the queue of fills.
|
||||||
FlushFills,
|
FlushFillsD3D9,
|
||||||
|
|
||||||
// Renders clips to the mask tile.
|
/// Upload a scene to GPU.
|
||||||
ClipTiles(Vec<ClipBatch>),
|
///
|
||||||
|
/// This will only be sent if dicing and binning is done on GPU.
|
||||||
|
UploadSceneD3D11 {
|
||||||
|
draw_segments: SegmentsD3D11,
|
||||||
|
clip_segments: SegmentsD3D11,
|
||||||
|
},
|
||||||
|
|
||||||
// Pushes a render target onto the stack. Draw commands go to the render target on top of the
|
// Pushes a render target onto the stack. Draw commands go to the render target on top of the
|
||||||
// stack.
|
// stack.
|
||||||
|
@ -79,11 +86,14 @@ pub enum RenderCommand {
|
||||||
// Pops a render target from the stack.
|
// Pops a render target from the stack.
|
||||||
PopRenderTarget,
|
PopRenderTarget,
|
||||||
|
|
||||||
// Marks that tile compositing is about to begin.
|
// Computes backdrops for tiles, prepares any Z-buffers, and performs clipping.
|
||||||
BeginTileDrawing,
|
PrepareClipTilesD3D11(TileBatchDataD3D11),
|
||||||
|
|
||||||
// Draws a batch of tiles to the render target on top of the stack.
|
// Draws a batch of tiles to the render target on top of the stack.
|
||||||
DrawTiles(TileBatch),
|
DrawTilesD3D9(DrawTileBatchD3D9),
|
||||||
|
|
||||||
|
// Draws a batch of tiles to the render target on top of the stack.
|
||||||
|
DrawTilesD3D11(DrawTileBatchD3D11),
|
||||||
|
|
||||||
// Presents a rendered frame.
|
// Presents a rendered frame.
|
||||||
Finish { cpu_build_time: Duration },
|
Finish { cpu_build_time: Duration },
|
||||||
|
@ -103,13 +113,125 @@ pub struct TextureLocation {
|
||||||
pub rect: RectI,
|
pub rect: RectI,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about a batch of tiles to be prepared (postprocessed).
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TileBatch {
|
pub struct TileBatchDataD3D11 {
|
||||||
pub tiles: Vec<Tile>,
|
/// The ID of this batch.
|
||||||
|
///
|
||||||
|
/// The renderer should not assume that these values are consecutive.
|
||||||
|
pub batch_id: TileBatchId,
|
||||||
|
/// The number of paths in this batch.
|
||||||
|
pub path_count: u32,
|
||||||
|
/// The number of tiles in this batch.
|
||||||
|
pub tile_count: u32,
|
||||||
|
/// The total number of segments in this batch.
|
||||||
|
pub segment_count: u32,
|
||||||
|
/// Information needed to prepare the tiles.
|
||||||
|
pub prepare_info: PrepareTilesInfoD3D11,
|
||||||
|
/// Where the paths come from (draw or clip).
|
||||||
|
pub path_source: PathSource,
|
||||||
|
/// Information about clips applied to paths, if any of the paths have clips.
|
||||||
|
pub clipped_path_info: Option<ClippedPathInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Where a path should come from (draw or clip).
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub enum PathSource {
|
||||||
|
Draw,
|
||||||
|
Clip,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about a batch of tiles to be prepared on GPU.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct PrepareTilesInfoD3D11 {
|
||||||
|
/// Initial backdrop values for each tile column, packed together.
|
||||||
|
pub backdrops: Vec<BackdropInfoD3D11>,
|
||||||
|
|
||||||
|
/// Mapping from path index to metadata needed to compute propagation on GPU.
|
||||||
|
///
|
||||||
|
/// This contains indices into the `tiles` vector.
|
||||||
|
pub propagate_metadata: Vec<PropagateMetadataD3D11>,
|
||||||
|
|
||||||
|
/// Metadata about each path that will be diced (flattened).
|
||||||
|
pub dice_metadata: Vec<DiceMetadataD3D11>,
|
||||||
|
|
||||||
|
/// Sparse information about all the allocated tiles.
|
||||||
|
pub tile_path_info: Vec<TilePathInfoD3D11>,
|
||||||
|
|
||||||
|
/// A transform to apply to the segments.
|
||||||
|
pub transform: Transform2F,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SegmentsD3D11 {
|
||||||
|
pub points: Vec<Vector2F>,
|
||||||
|
pub indices: Vec<SegmentIndicesD3D11>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SegmentIndicesD3D11 {
|
||||||
|
pub first_point_index: u32,
|
||||||
|
pub flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about clips applied to paths in a batch.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ClippedPathInfo {
|
||||||
|
/// The ID of the batch containing the clips.
|
||||||
|
///
|
||||||
|
/// In the current implementation, this is always 0.
|
||||||
|
pub clip_batch_id: TileBatchId,
|
||||||
|
|
||||||
|
/// The number of paths that have clips.
|
||||||
|
pub clipped_path_count: u32,
|
||||||
|
|
||||||
|
/// The maximum number of clipped tiles.
|
||||||
|
///
|
||||||
|
/// This is used to allocate vertex buffers.
|
||||||
|
pub max_clipped_tile_count: u32,
|
||||||
|
|
||||||
|
/// The actual clips, if calculated on CPU.
|
||||||
|
pub clips: Option<Vec<Clip>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Together with the `TileBatchId`, uniquely identifies a path on the renderer side.
|
||||||
|
///
|
||||||
|
/// Generally, `PathIndex(!0)` represents no path.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct PathBatchIndex(pub u32);
|
||||||
|
|
||||||
|
/// Unique ID that identifies a batch of tiles.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub struct TileBatchId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum DrawTileBatch {
|
||||||
|
D3D9(DrawTileBatchD3D9),
|
||||||
|
D3D11(DrawTileBatchD3D11),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information needed to draw a batch of tiles in D3D9.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DrawTileBatchD3D9 {
|
||||||
|
pub tiles: Vec<TileObjectPrimitive>,
|
||||||
|
pub clips: Vec<Clip>,
|
||||||
|
pub z_buffer_data: DenseTileMap<i32>,
|
||||||
|
/// The color texture to use.
|
||||||
pub color_texture: Option<TileBatchTexture>,
|
pub color_texture: Option<TileBatchTexture>,
|
||||||
|
/// The filter to use.
|
||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
|
/// The blend mode to composite these tiles with.
|
||||||
pub blend_mode: BlendMode,
|
pub blend_mode: BlendMode,
|
||||||
pub tile_page: u16,
|
}
|
||||||
|
|
||||||
|
/// Information needed to draw a batch of tiles in D3D11.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DrawTileBatchD3D11 {
|
||||||
|
/// Data for the tile batch.
|
||||||
|
pub tile_batch_data: TileBatchDataD3D11,
|
||||||
|
/// The color texture to use.
|
||||||
|
pub color_texture: Option<TileBatchTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -119,90 +241,198 @@ pub struct TileBatchTexture {
|
||||||
pub composite_op: PaintCompositeOp,
|
pub composite_op: PaintCompositeOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TileId(pub i32);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct FillId(pub i32);
|
||||||
|
|
||||||
|
// TODO(pcwalton): Pack better.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct FillObjectPrimitive {
|
#[repr(C)]
|
||||||
pub px: LineSegmentU4,
|
pub struct TileObjectPrimitive {
|
||||||
pub subpx: LineSegmentU8,
|
|
||||||
pub tile_x: i16,
|
pub tile_x: i16,
|
||||||
pub tile_y: i16,
|
pub tile_y: i16,
|
||||||
|
pub alpha_tile_id: AlphaTileId,
|
||||||
|
pub path_id: PathId,
|
||||||
|
// TODO(pcwalton): Maybe look the color up based on path ID?
|
||||||
|
pub color: u16,
|
||||||
|
pub ctrl: u8,
|
||||||
|
pub backdrop: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TileObjectPrimitive {
|
pub struct TileD3D11 {
|
||||||
pub alpha_tile_id: AlphaTileId,
|
pub next_tile_id: TileId,
|
||||||
|
pub first_fill_id: FillId,
|
||||||
|
pub alpha_tile_id_lo: i16,
|
||||||
|
pub alpha_tile_id_hi: i8,
|
||||||
|
pub backdrop_delta: i8,
|
||||||
|
pub color: u16,
|
||||||
|
pub ctrl: u8,
|
||||||
pub backdrop: i8,
|
pub backdrop: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AlphaTileD3D11 {
|
||||||
|
pub alpha_tile_index: AlphaTileId,
|
||||||
|
pub clip_tile_index: AlphaTileId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TilePathInfoD3D11 {
|
||||||
|
pub tile_min_x: i16,
|
||||||
|
pub tile_min_y: i16,
|
||||||
|
pub tile_max_x: i16,
|
||||||
|
pub tile_max_y: i16,
|
||||||
|
pub first_tile_index: u32,
|
||||||
|
// Must match the order in `TileD3D11`.
|
||||||
|
pub color: u16,
|
||||||
|
pub ctrl: u8,
|
||||||
|
pub backdrop: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Pack better!
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PropagateMetadataD3D11 {
|
||||||
|
pub tile_rect: RectI,
|
||||||
|
pub tile_offset: u32,
|
||||||
|
pub path_index: PathBatchIndex,
|
||||||
|
pub z_write: u32,
|
||||||
|
// This will generally not refer to the same batch as `path_index`.
|
||||||
|
pub clip_path_index: PathBatchIndex,
|
||||||
|
pub backdrop_offset: u32,
|
||||||
|
pub pad0: u32,
|
||||||
|
pub pad1: u32,
|
||||||
|
pub pad2: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct DiceMetadataD3D11 {
|
||||||
|
pub global_path_id: PathId,
|
||||||
|
pub first_global_segment_index: u32,
|
||||||
|
pub first_batch_segment_index: u32,
|
||||||
|
pub pad: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TextureMetadataEntry {
|
pub struct TextureMetadataEntry {
|
||||||
pub color_0_transform: Transform2F,
|
pub color_0_transform: Transform2F,
|
||||||
|
pub color_0_combine_mode: ColorCombineMode,
|
||||||
pub base_color: ColorU,
|
pub base_color: ColorU,
|
||||||
|
pub filter: Filter,
|
||||||
|
pub blend_mode: BlendMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct FillBatchEntry {
|
#[repr(C)]
|
||||||
pub fill: Fill,
|
pub enum ColorCombineMode {
|
||||||
pub page: u16,
|
None,
|
||||||
|
SrcIn,
|
||||||
|
DestIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Fill {
|
pub struct Fill {
|
||||||
pub subpx: LineSegmentU8,
|
pub line_segment: LineSegmentU16,
|
||||||
pub px: LineSegmentU4,
|
// The meaning of this field depends on whether fills are being done with the GPU rasterizer or
|
||||||
pub alpha_tile_index: u16,
|
// GPU compute. If raster, this field names the index of the alpha tile that this fill belongs
|
||||||
|
// to. If compute, this field names the index of the next fill in the singly-linked list of
|
||||||
|
// fills belonging to this alpha tile.
|
||||||
|
pub link: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ClipBatch {
|
#[repr(C)]
|
||||||
pub clips: Vec<Clip>,
|
pub struct ClipMetadata {
|
||||||
pub key: ClipBatchKey,
|
pub draw_tile_rect: RectI,
|
||||||
|
pub clip_tile_rect: RectI,
|
||||||
|
pub draw_tile_offset: u32,
|
||||||
|
pub clip_tile_offset: u32,
|
||||||
|
pub pad0: u32,
|
||||||
|
pub pad1: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ClipBatchKey {
|
|
||||||
pub dest_page: u16,
|
|
||||||
pub src_page: u16,
|
|
||||||
pub kind: ClipBatchKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order is significant here.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub enum ClipBatchKind {
|
|
||||||
Draw,
|
|
||||||
Clip,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Clip {
|
pub struct Clip {
|
||||||
pub dest_u: u8,
|
pub dest_tile_id: AlphaTileId,
|
||||||
pub dest_v: u8,
|
pub dest_backdrop: i32,
|
||||||
pub src_u: u8,
|
pub src_tile_id: AlphaTileId,
|
||||||
pub src_v: u8,
|
pub src_backdrop: i32,
|
||||||
pub backdrop: i8,
|
|
||||||
pub pad_0: u8,
|
|
||||||
pub pad_1: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
impl Default for Clip {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Clip {
|
||||||
|
Clip {
|
||||||
|
dest_tile_id: AlphaTileId(!0),
|
||||||
|
dest_backdrop: 0,
|
||||||
|
src_tile_id: AlphaTileId(!0),
|
||||||
|
src_backdrop: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Tile {
|
pub struct BinSegment {
|
||||||
pub tile_x: i16,
|
pub segment: LineSegment2F,
|
||||||
pub tile_y: i16,
|
pub path_index: PathId,
|
||||||
pub mask_0_u: u8,
|
pub pad0: u32,
|
||||||
pub mask_0_v: u8,
|
pub pad1: u32,
|
||||||
pub mask_0_backdrop: i8,
|
pub pad2: u32,
|
||||||
pub pad: u8,
|
}
|
||||||
pub color: u16,
|
|
||||||
pub ctrl: u16,
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct BackdropInfoD3D11 {
|
||||||
|
pub initial_backdrop: i32,
|
||||||
|
// Column number, where 0 is the leftmost column in the tile rect.
|
||||||
|
pub tile_x_offset: i32,
|
||||||
|
pub path_index: PathBatchIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct MicrolineD3D11 {
|
||||||
|
from_x_px: i16,
|
||||||
|
from_y_px: i16,
|
||||||
|
to_x_px: i16,
|
||||||
|
to_y_px: i16,
|
||||||
|
from_x_subpx: u8,
|
||||||
|
from_y_subpx: u8,
|
||||||
|
to_x_subpx: u8,
|
||||||
|
to_y_subpx: u8,
|
||||||
|
path_index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct FirstTileD3D11 {
|
||||||
|
first_tile: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
pub struct AlphaTileId(pub u32);
|
pub struct AlphaTileId(pub u32);
|
||||||
|
|
||||||
|
impl PathBatchIndex {
|
||||||
|
#[inline]
|
||||||
|
pub fn none() -> PathBatchIndex {
|
||||||
|
PathBatchIndex(!0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AlphaTileId {
|
impl AlphaTileId {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(next_alpha_tile_index: &[AtomicUsize; ALPHA_TILE_LEVEL_COUNT], level: usize)
|
pub fn new(next_alpha_tile_index: &[AtomicUsize; ALPHA_TILE_LEVEL_COUNT], level: usize)
|
||||||
|
@ -249,24 +479,40 @@ impl Debug for RenderCommand {
|
||||||
RenderCommand::UploadTextureMetadata(ref metadata) => {
|
RenderCommand::UploadTextureMetadata(ref metadata) => {
|
||||||
write!(formatter, "UploadTextureMetadata(x{})", metadata.len())
|
write!(formatter, "UploadTextureMetadata(x{})", metadata.len())
|
||||||
}
|
}
|
||||||
RenderCommand::AddFills(ref fills) => {
|
RenderCommand::AddFillsD3D9(ref fills) => {
|
||||||
write!(formatter, "AddFills(x{})", fills.len())
|
write!(formatter, "AddFillsD3D9(x{})", fills.len())
|
||||||
}
|
}
|
||||||
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
|
RenderCommand::FlushFillsD3D9 => write!(formatter, "FlushFills"),
|
||||||
RenderCommand::ClipTiles(ref batches) => {
|
RenderCommand::UploadSceneD3D11 { ref draw_segments, ref clip_segments } => {
|
||||||
write!(formatter, "ClipTiles(x{})", batches.len())
|
write!(formatter,
|
||||||
|
"UploadSceneD3D11(DP x{}, DI x{}, CP x{}, CI x{})",
|
||||||
|
draw_segments.points.len(),
|
||||||
|
draw_segments.indices.len(),
|
||||||
|
clip_segments.points.len(),
|
||||||
|
clip_segments.indices.len())
|
||||||
|
}
|
||||||
|
RenderCommand::PrepareClipTilesD3D11(ref batch) => {
|
||||||
|
let clipped_path_count = match batch.clipped_path_info {
|
||||||
|
None => 0,
|
||||||
|
Some(ref clipped_path_info) => clipped_path_info.clipped_path_count,
|
||||||
|
};
|
||||||
|
write!(formatter,
|
||||||
|
"PrepareClipTilesD3D11({:?}, C {})",
|
||||||
|
batch.batch_id,
|
||||||
|
clipped_path_count)
|
||||||
}
|
}
|
||||||
RenderCommand::PushRenderTarget(render_target_id) => {
|
RenderCommand::PushRenderTarget(render_target_id) => {
|
||||||
write!(formatter, "PushRenderTarget({:?})", render_target_id)
|
write!(formatter, "PushRenderTarget({:?})", render_target_id)
|
||||||
}
|
}
|
||||||
RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"),
|
RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"),
|
||||||
RenderCommand::BeginTileDrawing => write!(formatter, "BeginTileDrawing"),
|
RenderCommand::DrawTilesD3D9(ref batch) => {
|
||||||
RenderCommand::DrawTiles(ref batch) => {
|
write!(formatter, "DrawTilesD3D9(x{:?})", batch.tiles.len())
|
||||||
|
}
|
||||||
|
RenderCommand::DrawTilesD3D11(ref batch) => {
|
||||||
write!(formatter,
|
write!(formatter,
|
||||||
"DrawTiles(x{}, C0 {:?}, {:?})",
|
"DrawTilesD3D11({:?}, C0 {:?})",
|
||||||
batch.tiles.len(),
|
batch.tile_batch_data.batch_id,
|
||||||
batch.color_texture,
|
batch.color_texture)
|
||||||
batch.blend_mode)
|
|
||||||
}
|
}
|
||||||
RenderCommand::Finish { cpu_build_time } => {
|
RenderCommand::Finish { cpu_build_time } => {
|
||||||
write!(formatter, "Finish({} ms)", cpu_build_time.as_secs_f64() * 1000.0)
|
write!(formatter, "Finish({} ms)", cpu_build_time.as_secs_f64() * 1000.0)
|
||||||
|
@ -274,3 +520,10 @@ impl Debug for RenderCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for FirstTileD3D11 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> FirstTileD3D11 {
|
||||||
|
FirstTileD3D11 { first_tile: -1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// pathfinder/renderer/src/lib.rs
|
// pathfinder/renderer/src/lib.rs
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
@ -27,4 +27,3 @@ mod builder;
|
||||||
mod tile_map;
|
mod tile_map;
|
||||||
mod tiler;
|
mod tiler;
|
||||||
mod tiles;
|
mod tiles;
|
||||||
mod z_buffer;
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
//! Options that control how rendering is to be performed.
|
//! Options that control how rendering is to be performed.
|
||||||
|
|
||||||
|
use crate::gpu::options::RendererLevel;
|
||||||
use crate::gpu_data::RenderCommand;
|
use crate::gpu_data::RenderCommand;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
|
@ -17,17 +18,21 @@ use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector4F};
|
use pathfinder_geometry::vector::{Vector2F, Vector4F};
|
||||||
use pathfinder_content::clip::PolygonClipper3D;
|
use pathfinder_content::clip::PolygonClipper3D;
|
||||||
|
|
||||||
pub trait RenderCommandListener: Send + Sync {
|
pub struct RenderCommandListener<'a> {
|
||||||
fn send(&self, command: RenderCommand);
|
send_fn: RenderCommandSendFunction<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> RenderCommandListener for F
|
pub type RenderCommandSendFunction<'a> = Box<dyn Fn(RenderCommand) + Send + Sync + 'a>;
|
||||||
where
|
|
||||||
F: Fn(RenderCommand) + Send + Sync,
|
impl<'a> RenderCommandListener<'a> {
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send(&self, command: RenderCommand) {
|
pub fn new(send_fn: RenderCommandSendFunction<'a>) -> RenderCommandListener<'a> {
|
||||||
(*self)(command)
|
RenderCommandListener { send_fn }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn send(&self, render_command: RenderCommand) {
|
||||||
|
(self.send_fn)(render_command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +125,13 @@ pub(crate) struct PreparedBuildOptions {
|
||||||
pub(crate) subpixel_aa_enabled: bool,
|
pub(crate) subpixel_aa_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) enum PrepareMode {
|
||||||
|
CPU,
|
||||||
|
TransformCPUBinGPU,
|
||||||
|
GPU { transform: Transform2F },
|
||||||
|
}
|
||||||
|
|
||||||
impl PreparedBuildOptions {
|
impl PreparedBuildOptions {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn bounding_quad(&self) -> BoundingQuad {
|
pub(crate) fn bounding_quad(&self) -> BoundingQuad {
|
||||||
|
@ -128,6 +140,24 @@ impl PreparedBuildOptions {
|
||||||
_ => [Vector4F::default(); 4],
|
_ => [Vector4F::default(); 4],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_prepare_mode(&self, renderer_level: RendererLevel) -> PrepareMode {
|
||||||
|
match renderer_level {
|
||||||
|
RendererLevel::D3D9 => PrepareMode::CPU,
|
||||||
|
RendererLevel::D3D11 => {
|
||||||
|
match self.transform {
|
||||||
|
PreparedRenderTransform::Perspective { .. } => PrepareMode::TransformCPUBinGPU,
|
||||||
|
PreparedRenderTransform::None => {
|
||||||
|
PrepareMode::GPU { transform: Transform2F::default() }
|
||||||
|
}
|
||||||
|
PreparedRenderTransform::Transform2D(transform) => {
|
||||||
|
PrepareMode::GPU { transform }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type BoundingQuad = [Vector4F; 4];
|
pub(crate) type BoundingQuad = [Vector4F; 4];
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::allocator::{AllocationMode, TextureAllocator};
|
use crate::allocator::{AllocationMode, TextureAllocator};
|
||||||
use crate::gpu_data::{RenderCommand, TextureLocation, TextureMetadataEntry, TexturePageDescriptor};
|
use crate::gpu_data::{ColorCombineMode, RenderCommand, TextureLocation, TextureMetadataEntry, TexturePageDescriptor};
|
||||||
use crate::gpu_data::{TexturePageId, TileBatchTexture};
|
use crate::gpu_data::{TexturePageId, TileBatchTexture};
|
||||||
use crate::scene::{RenderTarget, SceneId};
|
use crate::scene::{RenderTarget, SceneId};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_content::effects::{Filter, PatternFilter};
|
use pathfinder_content::effects::{BlendMode, Filter, PatternFilter};
|
||||||
use pathfinder_content::gradient::{Gradient, GradientGeometry};
|
use pathfinder_content::gradient::{Gradient, GradientGeometry};
|
||||||
use pathfinder_content::pattern::{Pattern, PatternSource};
|
use pathfinder_content::pattern::{Pattern, PatternSource};
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
use pathfinder_content::render_target::RenderTargetId;
|
||||||
|
@ -285,6 +285,7 @@ pub struct PaintMetadata {
|
||||||
pub color_texture_metadata: Option<PaintColorTextureMetadata>,
|
pub color_texture_metadata: Option<PaintColorTextureMetadata>,
|
||||||
/// The base color that the color texture gets mixed into.
|
/// The base color that the color texture gets mixed into.
|
||||||
pub base_color: ColorU,
|
pub base_color: ColorU,
|
||||||
|
pub blend_mode: BlendMode,
|
||||||
/// True if this paint is fully opaque.
|
/// True if this paint is fully opaque.
|
||||||
pub is_opaque: bool,
|
pub is_opaque: bool,
|
||||||
}
|
}
|
||||||
|
@ -435,6 +436,8 @@ impl Palette {
|
||||||
color_texture_metadata,
|
color_texture_metadata,
|
||||||
is_opaque: paint.is_opaque(),
|
is_opaque: paint.is_opaque(),
|
||||||
base_color: paint.base_color(),
|
base_color: paint.base_color(),
|
||||||
|
// FIXME(pcwalton)
|
||||||
|
blend_mode: BlendMode::SrcOver,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +499,14 @@ impl Palette {
|
||||||
None => Transform2F::default(),
|
None => Transform2F::default(),
|
||||||
Some(ref color_texture_metadata) => color_texture_metadata.transform,
|
Some(ref color_texture_metadata) => color_texture_metadata.transform,
|
||||||
},
|
},
|
||||||
|
color_0_combine_mode: if paint_metadata.color_texture_metadata.is_some() {
|
||||||
|
ColorCombineMode::SrcIn
|
||||||
|
} else {
|
||||||
|
ColorCombineMode::None
|
||||||
|
},
|
||||||
base_color: paint_metadata.base_color,
|
base_color: paint_metadata.base_color,
|
||||||
|
filter: paint_metadata.filter(),
|
||||||
|
blend_mode: paint_metadata.blend_mode,
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
let mut render_commands = vec![RenderCommand::UploadTextureMetadata(texture_metadata)];
|
let mut render_commands = vec![RenderCommand::UploadTextureMetadata(texture_metadata)];
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
use crate::builder::SceneBuilder;
|
use crate::builder::SceneBuilder;
|
||||||
use crate::concurrent::executor::Executor;
|
use crate::concurrent::executor::Executor;
|
||||||
|
use crate::gpu::options::RendererLevel;
|
||||||
use crate::options::{BuildOptions, PreparedBuildOptions};
|
use crate::options::{BuildOptions, PreparedBuildOptions};
|
||||||
use crate::options::{PreparedRenderTransform, RenderCommandListener};
|
use crate::options::{PreparedRenderTransform, RenderCommandListener};
|
||||||
use crate::paint::{MergedPaletteInfo, Paint, PaintId, PaintInfo, Palette};
|
use crate::paint::{MergedPaletteInfo, Paint, PaintId, PaintInfo, Palette};
|
||||||
|
@ -22,19 +23,22 @@ use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2f};
|
use pathfinder_geometry::vector::{Vector2I, vec2f};
|
||||||
|
use std::ops::Range;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::u64;
|
||||||
|
|
||||||
static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0);
|
static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
pub(crate) display_list: Vec<DisplayItem>,
|
display_list: Vec<DisplayItem>,
|
||||||
pub(crate) paths: Vec<DrawPath>,
|
draw_paths: Vec<DrawPath>,
|
||||||
pub(crate) clip_paths: Vec<ClipPath>,
|
clip_paths: Vec<ClipPath>,
|
||||||
palette: Palette,
|
palette: Palette,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
view_box: RectF,
|
view_box: RectF,
|
||||||
id: SceneId,
|
id: SceneId,
|
||||||
|
epoch: SceneEpoch,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -46,47 +50,47 @@ impl Scene {
|
||||||
let scene_id = SceneId(NEXT_SCENE_ID.fetch_add(1, Ordering::Relaxed) as u32);
|
let scene_id = SceneId(NEXT_SCENE_ID.fetch_add(1, Ordering::Relaxed) as u32);
|
||||||
Scene {
|
Scene {
|
||||||
display_list: vec![],
|
display_list: vec![],
|
||||||
paths: vec![],
|
draw_paths: vec![],
|
||||||
clip_paths: vec![],
|
clip_paths: vec![],
|
||||||
palette: Palette::new(scene_id),
|
palette: Palette::new(scene_id),
|
||||||
bounds: RectF::default(),
|
bounds: RectF::default(),
|
||||||
view_box: RectF::default(),
|
view_box: RectF::default(),
|
||||||
id: scene_id,
|
id: scene_id,
|
||||||
|
epoch: SceneEpoch::new(0, 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_path(&mut self, path: DrawPath) {
|
pub fn push_draw_path(&mut self, draw_path: DrawPath) {
|
||||||
let path_index = self.paths.len() as u32;
|
let draw_path_index = DrawPathId(self.draw_paths.len() as u32);
|
||||||
self.paths.push(path);
|
self.draw_paths.push(draw_path);
|
||||||
self.push_path_with_index(path_index);
|
self.push_draw_path_with_index(draw_path_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_path_with_index(&mut self, path_index: u32) {
|
fn push_draw_path_with_index(&mut self, draw_path_id: DrawPathId) {
|
||||||
self.bounds = self.bounds.union_rect(self.paths[path_index as usize].outline.bounds());
|
let new_path_bounds = self.draw_paths[draw_path_id.0 as usize].outline.bounds();
|
||||||
|
self.bounds = self.bounds.union_rect(new_path_bounds);
|
||||||
|
|
||||||
if let Some(DisplayItem::DrawPaths {
|
let end_path_id = DrawPathId(draw_path_id.0 + 1);
|
||||||
start_index: _,
|
match self.display_list.last_mut() {
|
||||||
ref mut end_index
|
Some(DisplayItem::DrawPaths(ref mut range)) => range.end = end_path_id,
|
||||||
}) = self.display_list.last_mut() {
|
_ => self.display_list.push(DisplayItem::DrawPaths(draw_path_id..end_path_id)),
|
||||||
*end_index = path_index + 1;
|
|
||||||
} else {
|
|
||||||
self.display_list.push(DisplayItem::DrawPaths {
|
|
||||||
start_index: path_index,
|
|
||||||
end_index: path_index + 1,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.epoch.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_clip_path(&mut self, clip_path: ClipPath) -> ClipPathId {
|
pub fn push_clip_path(&mut self, clip_path: ClipPath) -> ClipPathId {
|
||||||
self.bounds = self.bounds.union_rect(clip_path.outline.bounds());
|
self.bounds = self.bounds.union_rect(clip_path.outline.bounds());
|
||||||
let clip_path_id = ClipPathId(self.clip_paths.len() as u32);
|
let clip_path_id = ClipPathId(self.clip_paths.len() as u32);
|
||||||
self.clip_paths.push(clip_path);
|
self.clip_paths.push(clip_path);
|
||||||
|
self.epoch.next();
|
||||||
clip_path_id
|
clip_path_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
pub fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
||||||
let render_target_id = self.palette.push_render_target(render_target);
|
let render_target_id = self.palette.push_render_target(render_target);
|
||||||
self.display_list.push(DisplayItem::PushRenderTarget(render_target_id));
|
self.display_list.push(DisplayItem::PushRenderTarget(render_target_id));
|
||||||
|
self.epoch.next();
|
||||||
render_target_id
|
render_target_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,10 +112,10 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge draw paths.
|
// Merge draw paths.
|
||||||
let mut draw_path_mapping = Vec::with_capacity(scene.paths.len());
|
let mut draw_path_mapping = Vec::with_capacity(scene.draw_paths.len());
|
||||||
for draw_path in scene.paths {
|
for draw_path in scene.draw_paths {
|
||||||
draw_path_mapping.push(self.paths.len() as u32);
|
draw_path_mapping.push(self.draw_paths.len() as u32);
|
||||||
self.paths.push(DrawPath {
|
self.draw_paths.push(DrawPath {
|
||||||
outline: draw_path.outline,
|
outline: draw_path.outline,
|
||||||
paint: paint_mapping[&draw_path.paint],
|
paint: paint_mapping[&draw_path.paint],
|
||||||
clip_path: draw_path.clip_path.map(|clip_path_id| {
|
clip_path: draw_path.clip_path.map(|clip_path_id| {
|
||||||
|
@ -133,16 +137,17 @@ impl Scene {
|
||||||
DisplayItem::PopRenderTarget => {
|
DisplayItem::PopRenderTarget => {
|
||||||
self.display_list.push(DisplayItem::PopRenderTarget);
|
self.display_list.push(DisplayItem::PopRenderTarget);
|
||||||
}
|
}
|
||||||
DisplayItem::DrawPaths {
|
DisplayItem::DrawPaths(range) => {
|
||||||
start_index: old_start_path_index,
|
for old_path_index in (range.start.0 as usize)..(range.end.0 as usize) {
|
||||||
end_index: old_end_path_index,
|
let old_draw_path_id = DrawPathId(draw_path_mapping[old_path_index]);
|
||||||
} => {
|
self.push_draw_path_with_index(old_draw_path_id);
|
||||||
for old_path_index in old_start_path_index..old_end_path_index {
|
|
||||||
self.push_path_with_index(draw_path_mapping[old_path_index as usize])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bump epoch.
|
||||||
|
self.epoch.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -152,12 +157,9 @@ impl Scene {
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
pub fn push_paint(&mut self, paint: &Paint) -> PaintId {
|
pub fn push_paint(&mut self, paint: &Paint) -> PaintId {
|
||||||
self.palette.push_paint(paint)
|
let paint_id = self.palette.push_paint(paint);
|
||||||
}
|
self.epoch.next();
|
||||||
|
paint_id
|
||||||
#[inline]
|
|
||||||
pub fn path_count(&self) -> usize {
|
|
||||||
self.paths.len()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -168,6 +170,7 @@ impl Scene {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_bounds(&mut self, new_bounds: RectF) {
|
pub fn set_bounds(&mut self, new_bounds: RectF) {
|
||||||
self.bounds = new_bounds;
|
self.bounds = new_bounds;
|
||||||
|
self.epoch.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -178,13 +181,13 @@ impl Scene {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_view_box(&mut self, new_view_box: RectF) {
|
pub fn set_view_box(&mut self, new_view_box: RectF) {
|
||||||
self.view_box = new_view_box;
|
self.view_box = new_view_box;
|
||||||
|
self.epoch.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn apply_render_options(
|
pub(crate) fn apply_render_options(&self,
|
||||||
&self,
|
|
||||||
original_outline: &Outline,
|
original_outline: &Outline,
|
||||||
options: &PreparedBuildOptions,
|
options: &PreparedBuildOptions)
|
||||||
) -> Outline {
|
-> Outline {
|
||||||
let mut outline;
|
let mut outline;
|
||||||
match options.transform {
|
match options.transform {
|
||||||
PreparedRenderTransform::Perspective {
|
PreparedRenderTransform::Perspective {
|
||||||
|
@ -238,63 +241,131 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build<'a, E>(&mut self,
|
pub fn build<'a, 'b, E>(&mut self,
|
||||||
options: BuildOptions,
|
options: BuildOptions,
|
||||||
listener: Box<dyn RenderCommandListener + 'a>,
|
sink: &'b mut SceneSink<'a>,
|
||||||
executor: &E)
|
executor: &E)
|
||||||
where E: Executor {
|
where E: Executor {
|
||||||
let prepared_options = options.prepare(self.bounds);
|
let prepared_options = options.prepare(self.bounds);
|
||||||
SceneBuilder::new(self, &prepared_options, listener).build(executor)
|
SceneBuilder::new(self, &prepared_options, sink).build(executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paths<'a>(&'a self) -> PathIter {
|
#[inline]
|
||||||
PathIter {
|
pub fn display_list(&self) -> &[DisplayItem] {
|
||||||
scene: self,
|
&self.display_list
|
||||||
pos: 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn draw_paths(&self) -> &[DrawPath] {
|
||||||
|
&self.draw_paths
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn clip_paths(&self) -> &[ClipPath] {
|
||||||
|
&self.clip_paths
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_draw_path(&self, draw_path_id: DrawPathId) -> &DrawPath {
|
||||||
|
&self.draw_paths[draw_path_id.0 as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_clip_path(&self, clip_path_id: ClipPathId) -> &ClipPath {
|
||||||
|
&self.clip_paths[clip_path_id.0 as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn palette(&self) -> &Palette {
|
||||||
|
&self.palette
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn id(&self) -> SceneId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn epoch(&self) -> SceneEpoch {
|
||||||
|
self.epoch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PathIter<'a> {
|
pub struct SceneSink<'a> {
|
||||||
scene: &'a Scene,
|
pub(crate) listener: RenderCommandListener<'a>,
|
||||||
pos: usize
|
pub(crate) renderer_level: RendererLevel,
|
||||||
|
pub(crate) last_scene: Option<LastSceneInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for PathIter<'a> {
|
pub(crate) struct LastSceneInfo {
|
||||||
type Item = (&'a Paint, &'a Outline, &'a str);
|
pub(crate) scene_id: SceneId,
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
pub(crate) scene_epoch: SceneEpoch,
|
||||||
let item = self.scene.paths.get(self.pos).map(|path_object| {
|
pub(crate) draw_segment_ranges: Vec<Range<u32>>,
|
||||||
(
|
pub(crate) clip_segment_ranges: Vec<Range<u32>>,
|
||||||
self.scene.palette.paints.get(path_object.paint.0 as usize).unwrap(),
|
}
|
||||||
&path_object.outline,
|
|
||||||
&*path_object.name
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
)
|
pub struct SceneEpoch {
|
||||||
});
|
pub hi: u64,
|
||||||
self.pos += 1;
|
pub lo: u64,
|
||||||
item
|
}
|
||||||
|
|
||||||
|
impl SceneEpoch {
|
||||||
|
#[inline]
|
||||||
|
fn new(hi: u64, lo: u64) -> SceneEpoch {
|
||||||
|
SceneEpoch { hi, lo }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn successor(&self) -> SceneEpoch {
|
||||||
|
if self.lo == u64::MAX {
|
||||||
|
SceneEpoch { hi: self.hi + 1, lo: 0 }
|
||||||
|
} else {
|
||||||
|
SceneEpoch { hi: self.hi, lo: self.lo + 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) {
|
||||||
|
*self = self.successor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SceneSink<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(listener: RenderCommandListener<'a>, renderer_level: RendererLevel)
|
||||||
|
-> SceneSink<'a> {
|
||||||
|
SceneSink { listener, renderer_level, last_scene: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DrawPath {
|
pub struct DrawPath {
|
||||||
outline: Outline,
|
pub outline: Outline,
|
||||||
paint: PaintId,
|
pub paint: PaintId,
|
||||||
clip_path: Option<ClipPathId>,
|
pub clip_path: Option<ClipPathId>,
|
||||||
fill_rule: FillRule,
|
pub fill_rule: FillRule,
|
||||||
blend_mode: BlendMode,
|
pub blend_mode: BlendMode,
|
||||||
name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ClipPath {
|
pub struct ClipPath {
|
||||||
outline: Outline,
|
pub outline: Outline,
|
||||||
fill_rule: FillRule,
|
pub fill_rule: FillRule,
|
||||||
name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct DrawPathId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
pub struct ClipPathId(pub u32);
|
pub struct ClipPathId(pub u32);
|
||||||
|
|
||||||
|
/// Either a draw path ID or a clip path ID, depending on context.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct PathId(pub u32);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RenderTarget {
|
pub struct RenderTarget {
|
||||||
size: Vector2I,
|
size: Vector2I,
|
||||||
|
@ -305,7 +376,7 @@ pub struct RenderTarget {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DisplayItem {
|
pub enum DisplayItem {
|
||||||
/// Draws paths to the render target on top of the stack.
|
/// Draws paths to the render target on top of the stack.
|
||||||
DrawPaths { start_index: u32, end_index: u32 },
|
DrawPaths(Range<DrawPathId>),
|
||||||
|
|
||||||
/// Pushes a render target onto the top of the stack.
|
/// Pushes a render target onto the top of the stack.
|
||||||
PushRenderTarget(RenderTargetId),
|
PushRenderTarget(RenderTargetId),
|
||||||
|
@ -411,3 +482,29 @@ impl RenderTarget {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DrawPathId {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_path_id(self) -> PathId {
|
||||||
|
PathId(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClipPathId {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_path_id(self) -> PathId {
|
||||||
|
PathId(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathId {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_clip_path_id(self) -> ClipPathId {
|
||||||
|
ClipPathId(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_draw_path_id(self) -> DrawPathId {
|
||||||
|
DrawPathId(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,35 +11,23 @@
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DenseTileMap<T> {
|
pub struct DenseTileMap<T> where T: Clone + Copy {
|
||||||
pub data: Vec<T>,
|
pub data: Vec<T>,
|
||||||
pub rect: RectI,
|
pub rect: RectI,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DenseTileMap<T> {
|
impl<T> DenseTileMap<T> where T: Clone + Copy {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(rect: RectI) -> DenseTileMap<T>
|
pub fn from_builder<F>(mut build: F, rect: RectI) -> DenseTileMap<T>
|
||||||
where
|
where F: FnMut(Vector2I) -> T {
|
||||||
T: Copy + Clone + Default,
|
let mut data = Vec::with_capacity(rect.size().x() as usize * rect.size().y() as usize);
|
||||||
{
|
for y in rect.min_y()..rect.max_y() {
|
||||||
let length = rect.size().x() as usize * rect.size().y() as usize;
|
for x in rect.min_x()..rect.max_x() {
|
||||||
DenseTileMap {
|
data.push(build(vec2i(x, y)));
|
||||||
data: vec![T::default(); length],
|
|
||||||
rect,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DenseTileMap { data, rect }
|
||||||
#[inline]
|
|
||||||
pub fn from_builder<F>(build: F, rect: RectI) -> DenseTileMap<T>
|
|
||||||
where
|
|
||||||
F: FnMut(usize) -> T,
|
|
||||||
{
|
|
||||||
let length = rect.size().x() as usize * rect.size().y() as usize;
|
|
||||||
DenseTileMap {
|
|
||||||
data: (0..length).map(build).collect(),
|
|
||||||
rect,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -47,6 +35,14 @@ impl<T> DenseTileMap<T> {
|
||||||
self.coords_to_index(coords).and_then(|index| self.data.get(index))
|
self.coords_to_index(coords).and_then(|index| self.data.get(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mut(&mut self, coords: Vector2I) -> Option<&mut T> {
|
||||||
|
match self.coords_to_index(coords) {
|
||||||
|
None => None,
|
||||||
|
Some(index) => self.data.get_mut(index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn coords_to_index(&self, coords: Vector2I) -> Option<usize> {
|
pub fn coords_to_index(&self, coords: Vector2I) -> Option<usize> {
|
||||||
if self.rect.contains_point(coords) {
|
if self.rect.contains_point(coords) {
|
||||||
|
|
|
@ -11,8 +11,12 @@
|
||||||
//! Implements the fast lattice-clipping algorithm from Nehab and Hoppe, "Random-Access Rendering
|
//! Implements the fast lattice-clipping algorithm from Nehab and Hoppe, "Random-Access Rendering
|
||||||
//! of General Vector Graphics" 2006.
|
//! of General Vector Graphics" 2006.
|
||||||
|
|
||||||
use crate::builder::{ObjectBuilder, Occluder, SceneBuilder, SolidTiles};
|
use crate::builder::{BuiltPath, BuiltPathBinCPUData, BuiltPathData, ObjectBuilder, SceneBuilder};
|
||||||
use crate::tiles::{PackedTile, TILE_HEIGHT, TILE_WIDTH, TileType, TilingPathInfo};
|
use crate::gpu::options::RendererLevel;
|
||||||
|
use crate::gpu_data::AlphaTileId;
|
||||||
|
use crate::options::PrepareMode;
|
||||||
|
use crate::scene::PathId;
|
||||||
|
use crate::tiles::{DrawTilingPathInfo, TILE_HEIGHT, TILE_WIDTH, TilingPathInfo};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
||||||
use pathfinder_content::segment::Segment;
|
use pathfinder_content::segment::Segment;
|
||||||
|
@ -23,102 +27,172 @@ use pathfinder_simd::default::{F32x2, U32x2};
|
||||||
|
|
||||||
const FLATTENING_TOLERANCE: f32 = 0.25;
|
const FLATTENING_TOLERANCE: f32 = 0.25;
|
||||||
|
|
||||||
pub(crate) struct Tiler<'a, 'b> {
|
pub(crate) struct Tiler<'a, 'b, 'c, 'd> {
|
||||||
scene_builder: &'a SceneBuilder<'b, 'a>,
|
scene_builder: &'a SceneBuilder<'b, 'a, 'c, 'd>,
|
||||||
pub(crate) object_builder: ObjectBuilder,
|
pub(crate) object_builder: ObjectBuilder,
|
||||||
outline: &'a Outline,
|
outline: &'a Outline,
|
||||||
path_info: TilingPathInfo<'a>,
|
clip_path: Option<&'a BuiltPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Tiler<'a, 'b> {
|
impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
pub(crate) fn new(scene_builder: &'a SceneBuilder<'b, 'a>,
|
pub(crate) fn new(scene_builder: &'a SceneBuilder<'b, 'a, 'c, 'd>,
|
||||||
|
path_id: PathId,
|
||||||
outline: &'a Outline,
|
outline: &'a Outline,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
view_box: RectF,
|
view_box: RectF,
|
||||||
path_info: TilingPathInfo<'a>)
|
prepare_mode: &PrepareMode,
|
||||||
-> Tiler<'a, 'b> {
|
built_clip_paths: &'a [BuiltPath],
|
||||||
|
path_info: TilingPathInfo)
|
||||||
|
-> Tiler<'a, 'b, 'c, 'd> {
|
||||||
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF::default());
|
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF::default());
|
||||||
let object_builder = ObjectBuilder::new(bounds, view_box, fill_rule, &path_info);
|
|
||||||
Tiler { scene_builder, object_builder, outline, path_info }
|
let clip_path = match path_info {
|
||||||
|
TilingPathInfo::Draw(DrawTilingPathInfo { clip_path_id: Some(clip_path_id), .. }) => {
|
||||||
|
Some(&built_clip_paths[clip_path_id.0 as usize])
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let object_builder = ObjectBuilder::new(path_id,
|
||||||
|
bounds,
|
||||||
|
view_box,
|
||||||
|
fill_rule,
|
||||||
|
prepare_mode,
|
||||||
|
&path_info);
|
||||||
|
|
||||||
|
Tiler { scene_builder, object_builder, outline, clip_path }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generate_tiles(&mut self) {
|
pub(crate) fn generate_tiles(&mut self) {
|
||||||
|
match self.object_builder.built_path.data {
|
||||||
|
BuiltPathData::CPU(_) => {
|
||||||
|
self.generate_fills();
|
||||||
|
self.prepare_tiles();
|
||||||
|
}
|
||||||
|
BuiltPathData::TransformCPUBinGPU(ref mut data) => {
|
||||||
|
data.outline = (*self.outline).clone();
|
||||||
|
}
|
||||||
|
BuiltPathData::GPU => {
|
||||||
|
panic!("Shouldn't have generated a tiler at all if we're transforming on GPU!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_fills(&mut self) {
|
||||||
|
debug_assert_eq!(self.scene_builder.sink.renderer_level, RendererLevel::D3D9);
|
||||||
|
|
||||||
for contour in self.outline.contours() {
|
for contour in self.outline.contours() {
|
||||||
for segment in contour.iter(ContourIterFlags::empty()) {
|
for segment in contour.iter(ContourIterFlags::empty()) {
|
||||||
process_segment(&segment, self.scene_builder, &mut self.object_builder);
|
process_segment(&segment, self.scene_builder, &mut self.object_builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.propagate_backdrops();
|
|
||||||
self.pack_and_cull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_backdrops(&mut self) {
|
fn prepare_tiles(&mut self) {
|
||||||
let tiles_across = self.object_builder.built_path.tiles.rect.width() as usize;
|
// Don't do this here if the GPU will do it.
|
||||||
for (draw_tile_index, draw_tile) in self.object_builder
|
let (backdrops, tiles, clips) = match self.object_builder.built_path.data {
|
||||||
.built_path
|
BuiltPathData::CPU(ref mut tiled_data) => {
|
||||||
.tiles
|
(&mut tiled_data.backdrops, &mut tiled_data.tiles, &mut tiled_data.clip_tiles)
|
||||||
.data
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate() {
|
|
||||||
let column = draw_tile_index % tiles_across;
|
|
||||||
let delta = draw_tile.backdrop;
|
|
||||||
draw_tile.backdrop = self.object_builder.current_backdrops[column];
|
|
||||||
self.object_builder.current_backdrops[column] += delta;
|
|
||||||
}
|
}
|
||||||
|
BuiltPathData::TransformCPUBinGPU(_) | BuiltPathData::GPU => {
|
||||||
|
panic!("We shouldn't be preparing tiles on CPU!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_and_cull(&mut self) {
|
|
||||||
let draw_tiling_path_info = match self.path_info {
|
|
||||||
TilingPathInfo::Clip => return,
|
|
||||||
TilingPathInfo::Draw(draw_tiling_path_info) => draw_tiling_path_info,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let blend_mode_is_destructive = draw_tiling_path_info.blend_mode.is_destructive();
|
// Propagate backdrops.
|
||||||
|
let tiles_across = tiles.rect.width() as usize;
|
||||||
|
for (draw_tile_index, draw_tile) in tiles.data.iter_mut().enumerate() {
|
||||||
|
let tile_coords = vec2i(draw_tile.tile_x as i32, draw_tile.tile_y as i32);
|
||||||
|
let column = draw_tile_index % tiles_across;
|
||||||
|
let delta = draw_tile.backdrop as i32;
|
||||||
|
|
||||||
for (draw_tile_index, draw_tile) in self.object_builder
|
let mut draw_alpha_tile_id = draw_tile.alpha_tile_id;
|
||||||
|
let mut draw_tile_backdrop = backdrops[column] as i8;
|
||||||
|
|
||||||
|
if let Some(built_clip_path) = self.clip_path {
|
||||||
|
let clip_tiles = match built_clip_path.data {
|
||||||
|
BuiltPathData::CPU(BuiltPathBinCPUData { ref tiles, .. }) => tiles,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
match clip_tiles.get(tile_coords) {
|
||||||
|
Some(clip_tile) => {
|
||||||
|
if clip_tile.alpha_tile_id != AlphaTileId(!0) &&
|
||||||
|
draw_alpha_tile_id != AlphaTileId(!0) {
|
||||||
|
// Hard case: We have an alpha tile and a clip tile with masks. Add a
|
||||||
|
// job to combine the two masks. Because the mask combining step
|
||||||
|
// applies the backdrops, zero out the backdrop in the draw tile itself
|
||||||
|
// so that we don't double-count it.
|
||||||
|
let clip = clips.as_mut()
|
||||||
|
.expect("Where are the clips?")
|
||||||
|
.get_mut(tile_coords)
|
||||||
|
.unwrap();
|
||||||
|
clip.dest_tile_id = draw_tile.alpha_tile_id;
|
||||||
|
clip.dest_backdrop = draw_tile_backdrop as i32;
|
||||||
|
clip.src_tile_id = clip_tile.alpha_tile_id;
|
||||||
|
clip.src_backdrop = clip_tile.backdrop as i32;
|
||||||
|
draw_tile_backdrop = 0;
|
||||||
|
} else if clip_tile.alpha_tile_id != AlphaTileId(!0) &&
|
||||||
|
draw_alpha_tile_id == AlphaTileId(!0) &&
|
||||||
|
draw_tile_backdrop != 0 {
|
||||||
|
// This is a solid draw tile, but there's a clip applied. Replace it
|
||||||
|
// with an alpha tile pointing directly to the clip mask.
|
||||||
|
draw_alpha_tile_id = clip_tile.alpha_tile_id;
|
||||||
|
draw_tile_backdrop = clip_tile.backdrop;
|
||||||
|
} else if clip_tile.alpha_tile_id == AlphaTileId(!0) &&
|
||||||
|
clip_tile.backdrop == 0 {
|
||||||
|
// This is a blank clip tile. Cull the draw tile entirely.
|
||||||
|
draw_alpha_tile_id = AlphaTileId(!0);
|
||||||
|
draw_tile_backdrop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// This draw tile is outside the clip path rect. Cull the tile.
|
||||||
|
draw_alpha_tile_id = AlphaTileId(!0);
|
||||||
|
draw_tile_backdrop = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_tile.alpha_tile_id = draw_alpha_tile_id;
|
||||||
|
draw_tile.backdrop = draw_tile_backdrop;
|
||||||
|
|
||||||
|
backdrops[column] += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
// Calculate clips.
|
||||||
|
let built_clip_path = match self.path_info {
|
||||||
|
TilingPathInfo::Draw(DrawTilingPathInfo {
|
||||||
|
built_clip_path: Some(built_clip_path),
|
||||||
|
..
|
||||||
|
}) => built_clip_path,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let clip_tiles = self.object_builder
|
||||||
.built_path
|
.built_path
|
||||||
.tiles
|
.clip_tiles
|
||||||
.data
|
.as_mut()
|
||||||
.iter()
|
.expect("Where are the clip tiles?");
|
||||||
.enumerate() {
|
|
||||||
let packed_tile = PackedTile::new(draw_tile_index as u32,
|
|
||||||
draw_tile,
|
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.object_builder);
|
|
||||||
|
|
||||||
match packed_tile.tile_type {
|
for draw_tile in &mut self.object_builder.built_path.tiles.data {
|
||||||
TileType::Solid => {
|
let tile_coords = vec2i(draw_tile.tile_x as i32, draw_tile.tile_y as i32);
|
||||||
match self.object_builder.built_path.solid_tiles {
|
let built_clip_tile = match built_clip_path.tiles.get(tile_coords) {
|
||||||
SolidTiles::Occluders(ref mut occluders) => {
|
None => {
|
||||||
occluders.push(Occluder::new(packed_tile.tile_coords));
|
draw_tile.alpha_tile_id = AlphaTileId(!0);
|
||||||
}
|
continue;
|
||||||
SolidTiles::Regular(ref mut solid_tiles) => {
|
|
||||||
packed_tile.add_to(solid_tiles,
|
|
||||||
&mut self.object_builder.built_path.clip_tiles,
|
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.scene_builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TileType::SingleMask => {
|
|
||||||
debug_assert_ne!(packed_tile.draw_tile.alpha_tile_id.page(), !0);
|
|
||||||
packed_tile.add_to(&mut self.object_builder.built_path.single_mask_tiles,
|
|
||||||
&mut self.object_builder.built_path.clip_tiles,
|
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.scene_builder);
|
|
||||||
}
|
|
||||||
TileType::Empty if blend_mode_is_destructive => {
|
|
||||||
packed_tile.add_to(&mut self.object_builder.built_path.empty_tiles,
|
|
||||||
&mut self.object_builder.built_path.clip_tiles,
|
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.scene_builder);
|
|
||||||
}
|
|
||||||
TileType::Empty => {
|
|
||||||
// Just cull.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Some(built_clip_tile) => built_clip_tile,
|
||||||
|
};
|
||||||
|
|
||||||
|
let clip_tile = clip_tiles.get_mut(tile_coords).unwrap();
|
||||||
|
clip_tile.dest_tile_id = draw_tile.alpha_tile_id;
|
||||||
|
clip_tile.dest_backdrop = draw_tile.backdrop as i32;
|
||||||
|
clip_tile.src_tile_id = built_clip_tile.alpha_tile_id;
|
||||||
|
clip_tile.src_backdrop = built_clip_tile.backdrop as i32;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +239,8 @@ fn process_line_segment(line_segment: LineSegment2F,
|
||||||
// Compute `step = vec2f(vector.x < 0 ? -1 : 1, vector.y < 0 ? -1 : 1)`.
|
// Compute `step = vec2f(vector.x < 0 ? -1 : 1, vector.y < 0 ? -1 : 1)`.
|
||||||
let step = Vector2I((vector_is_negative | U32x2::splat(1)).to_i32x2());
|
let step = Vector2I((vector_is_negative | U32x2::splat(1)).to_i32x2());
|
||||||
|
|
||||||
// Compute `first_tile_crossing = (from_tile_coords + vec2i(vector.x > 0 ? 1 : 0,
|
// Compute `first_tile_crossing = (from_tile_coords + vec2i(vector.x >= 0 ? 1 : 0,
|
||||||
// vector.y > 0 ? 1 : 0)) * tile_size`.
|
// vector.y >= 0 ? 1 : 0)) * tile_size`.
|
||||||
let first_tile_crossing = (from_tile_coords +
|
let first_tile_crossing = (from_tile_coords +
|
||||||
Vector2I((!vector_is_negative & U32x2::splat(1)).to_i32x2())).to_f32() * tile_size;
|
Vector2I((!vector_is_negative & U32x2::splat(1)).to_i32x2())).to_f32() * tile_size;
|
||||||
|
|
||||||
|
|
|
@ -8,33 +8,33 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::builder::{BuiltPath, ObjectBuilder};
|
use crate::gpu_data::{TILE_CTRL_MASK_0_SHIFT, TILE_CTRL_MASK_EVEN_ODD};
|
||||||
use crate::gpu_data::{AlphaTileId, TileObjectPrimitive};
|
use crate::gpu_data::{TILE_CTRL_MASK_WINDING, TileObjectPrimitive};
|
||||||
use crate::paint::{PaintId, PaintMetadata};
|
use crate::paint::PaintId;
|
||||||
|
use crate::scene::ClipPathId;
|
||||||
use pathfinder_content::effects::BlendMode;
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_geometry::rect::{RectF, RectI};
|
use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2f};
|
use pathfinder_geometry::vector::vec2f;
|
||||||
|
|
||||||
pub const TILE_WIDTH: u32 = 16;
|
pub const TILE_WIDTH: u32 = 16;
|
||||||
pub const TILE_HEIGHT: u32 = 16;
|
pub const TILE_HEIGHT: u32 = 16;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) enum TilingPathInfo<'a> {
|
pub(crate) enum TilingPathInfo {
|
||||||
Clip,
|
Clip,
|
||||||
Draw(DrawTilingPathInfo<'a>),
|
Draw(DrawTilingPathInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) struct DrawTilingPathInfo<'a> {
|
pub(crate) struct DrawTilingPathInfo {
|
||||||
pub(crate) paint_id: PaintId,
|
pub(crate) paint_id: PaintId,
|
||||||
pub(crate) paint_metadata: &'a PaintMetadata,
|
|
||||||
pub(crate) blend_mode: BlendMode,
|
pub(crate) blend_mode: BlendMode,
|
||||||
pub(crate) built_clip_path: Option<&'a BuiltPath>,
|
|
||||||
pub(crate) fill_rule: FillRule,
|
pub(crate) fill_rule: FillRule,
|
||||||
|
pub(crate) clip_path_id: Option<ClipPathId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TilingPathInfo<'a> {
|
impl TilingPathInfo {
|
||||||
pub(crate) fn has_destructive_blend_mode(&self) -> bool {
|
pub(crate) fn has_destructive_blend_mode(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
|
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
|
||||||
|
@ -43,126 +43,23 @@ impl<'a> TilingPathInfo<'a> {
|
||||||
TilingPathInfo::Clip => false,
|
TilingPathInfo::Clip => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct PackedTile<'a> {
|
pub(crate) fn to_ctrl(&self) -> u8 {
|
||||||
pub(crate) tile_type: TileType,
|
let mut ctrl = 0;
|
||||||
pub(crate) tile_coords: Vector2I,
|
match *self {
|
||||||
pub(crate) draw_tile: &'a TileObjectPrimitive,
|
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
|
||||||
pub(crate) clip_tile: Option<&'a TileObjectPrimitive>,
|
match draw_tiling_path_info.fill_rule {
|
||||||
|
FillRule::EvenOdd => {
|
||||||
|
ctrl |= (TILE_CTRL_MASK_EVEN_ODD << TILE_CTRL_MASK_0_SHIFT) as u8
|
||||||
}
|
}
|
||||||
|
FillRule::Winding => {
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
ctrl |= (TILE_CTRL_MASK_WINDING << TILE_CTRL_MASK_0_SHIFT) as u8
|
||||||
pub(crate) enum TileType {
|
|
||||||
Solid,
|
|
||||||
Empty,
|
|
||||||
SingleMask,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PackedTile<'a> {
|
|
||||||
pub(crate) fn new(draw_tile_index: u32,
|
|
||||||
draw_tile: &'a TileObjectPrimitive,
|
|
||||||
draw_tiling_path_info: &DrawTilingPathInfo<'a>,
|
|
||||||
object_builder: &ObjectBuilder)
|
|
||||||
-> PackedTile<'a> {
|
|
||||||
let tile_coords = object_builder.local_tile_index_to_coords(draw_tile_index as u32);
|
|
||||||
|
|
||||||
// First, if the draw tile is empty, cull it regardless of clip.
|
|
||||||
if draw_tile.is_solid() {
|
|
||||||
match (object_builder.built_path.fill_rule, draw_tile.backdrop) {
|
|
||||||
(FillRule::Winding, 0) => {
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(FillRule::Winding, _) => {}
|
|
||||||
(FillRule::EvenOdd, backdrop) if backdrop % 2 == 0 => {
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(FillRule::EvenOdd, _) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out what clip tile we need, if any.
|
|
||||||
let clip_tile = match draw_tiling_path_info.built_clip_path {
|
|
||||||
None => None,
|
|
||||||
Some(built_clip_path) => {
|
|
||||||
match built_clip_path.tiles.get(tile_coords) {
|
|
||||||
None => {
|
|
||||||
// This tile is outside of the bounds of the clip path entirely. We can
|
|
||||||
// cull it.
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Some(clip_tile) if clip_tile.is_solid() => {
|
|
||||||
if clip_tile.backdrop != 0 {
|
|
||||||
// The clip tile is fully opaque, so this tile isn't clipped at
|
|
||||||
// all.
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// This tile is completely clipped out. Cull it.
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(clip_tile) => Some(clip_tile),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Choose a tile type.
|
|
||||||
match clip_tile {
|
|
||||||
None if draw_tile.is_solid() => {
|
|
||||||
// This is a solid tile that completely occludes the background.
|
|
||||||
PackedTile { tile_type: TileType::Solid, tile_coords, draw_tile, clip_tile }
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// We have a draw tile and no clip tile.
|
|
||||||
PackedTile {
|
|
||||||
tile_type: TileType::SingleMask,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(clip_tile) if draw_tile.is_solid() => {
|
|
||||||
// We have a solid draw tile and a clip tile. This is effectively the same as
|
|
||||||
// having a draw tile and no clip tile.
|
|
||||||
//
|
|
||||||
// FIXME(pcwalton): This doesn't preserve the fill rule of the clip path!
|
|
||||||
PackedTile {
|
|
||||||
tile_type: TileType::SingleMask,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile: clip_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(clip_tile) => {
|
|
||||||
// We have both a draw and clip mask. Composite them together.
|
|
||||||
PackedTile {
|
|
||||||
tile_type: TileType::SingleMask,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: Some(clip_tile),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TilingPathInfo::Clip => {}
|
||||||
|
}
|
||||||
|
ctrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,13 +67,6 @@ pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI {
|
||||||
(rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32()
|
(rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TileObjectPrimitive {
|
|
||||||
#[inline]
|
|
||||||
fn default() -> TileObjectPrimitive {
|
|
||||||
TileObjectPrimitive { backdrop: 0, alpha_tile_id: AlphaTileId::invalid() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TileObjectPrimitive {
|
impl TileObjectPrimitive {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_solid(&self) -> bool { !self.alpha_tile_id.is_valid() }
|
pub fn is_solid(&self) -> bool { !self.alpha_tile_id.is_valid() }
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
// pathfinder/renderer/src/z_buffer.rs
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
//! Software occlusion culling.
|
|
||||||
|
|
||||||
use crate::builder::Occluder;
|
|
||||||
use crate::gpu_data::{Tile, TileBatch};
|
|
||||||
use crate::paint::{PaintId, PaintMetadata};
|
|
||||||
use crate::tile_map::DenseTileMap;
|
|
||||||
use crate::tiles;
|
|
||||||
use pathfinder_content::effects::BlendMode;
|
|
||||||
use pathfinder_geometry::rect::RectF;
|
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
|
||||||
use vec_map::VecMap;
|
|
||||||
|
|
||||||
pub(crate) struct ZBuffer {
|
|
||||||
buffer: DenseTileMap<u32>,
|
|
||||||
depth_metadata: VecMap<DepthMetadata>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct SolidTiles {
|
|
||||||
pub(crate) batches: Vec<TileBatch>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub(crate) struct DepthMetadata {
|
|
||||||
pub(crate) paint_id: PaintId,
|
|
||||||
}
|
|
||||||
impl ZBuffer {
|
|
||||||
pub(crate) fn new(view_box: RectF) -> ZBuffer {
|
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
|
||||||
ZBuffer {
|
|
||||||
buffer: DenseTileMap::from_builder(|_| 0, tile_rect),
|
|
||||||
depth_metadata: VecMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn test(&self, coords: Vector2I, depth: u32) -> bool {
|
|
||||||
let tile_index = self.buffer.coords_to_index_unchecked(coords);
|
|
||||||
self.buffer.data[tile_index as usize] < depth
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn update(&mut self,
|
|
||||||
solid_tiles: &[Occluder],
|
|
||||||
depth: u32,
|
|
||||||
metadata: DepthMetadata) {
|
|
||||||
self.depth_metadata.insert(depth as usize, metadata);
|
|
||||||
for solid_tile in solid_tiles {
|
|
||||||
let tile_index = self.buffer.coords_to_index_unchecked(solid_tile.coords);
|
|
||||||
let z_dest = &mut self.buffer.data[tile_index as usize];
|
|
||||||
*z_dest = u32::max(*z_dest, depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn build_solid_tiles(&self, paint_metadata: &[PaintMetadata]) -> SolidTiles {
|
|
||||||
let mut solid_tiles = SolidTiles { batches: vec![] };
|
|
||||||
|
|
||||||
for tile_index in 0..self.buffer.data.len() {
|
|
||||||
let depth = self.buffer.data[tile_index];
|
|
||||||
if depth == 0 {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tile_coords = self.buffer.index_to_coords(tile_index);
|
|
||||||
|
|
||||||
let depth_metadata = self.depth_metadata[depth as usize];
|
|
||||||
let paint_id = depth_metadata.paint_id;
|
|
||||||
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
|
||||||
|
|
||||||
let tile_position = tile_coords + self.buffer.rect.origin();
|
|
||||||
|
|
||||||
// Create a batch if necessary.
|
|
||||||
let paint_tile_batch_texture = paint_metadata.tile_batch_texture();
|
|
||||||
let paint_filter = paint_metadata.filter();
|
|
||||||
match solid_tiles.batches.last() {
|
|
||||||
Some(TileBatch { color_texture: tile_batch_texture, filter: tile_filter, .. }) if
|
|
||||||
*tile_batch_texture == paint_tile_batch_texture &&
|
|
||||||
*tile_filter == paint_filter => {}
|
|
||||||
_ => {
|
|
||||||
// Batch break.
|
|
||||||
//
|
|
||||||
// TODO(pcwalton): We could be more aggressive with batching here, since we
|
|
||||||
// know there are no overlaps.
|
|
||||||
solid_tiles.batches.push(TileBatch {
|
|
||||||
color_texture: paint_tile_batch_texture,
|
|
||||||
tiles: vec![],
|
|
||||||
filter: paint_filter,
|
|
||||||
blend_mode: BlendMode::default(),
|
|
||||||
tile_page: !0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let batch = solid_tiles.batches.last_mut().unwrap();
|
|
||||||
batch.tiles.push(Tile::new_solid_from_paint_id(tile_position, paint_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
solid_tiles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tile {
|
|
||||||
pub(crate) fn new_solid_from_paint_id(tile_origin: Vector2I, paint_id: PaintId) -> Tile {
|
|
||||||
Tile {
|
|
||||||
tile_x: tile_origin.x() as i16,
|
|
||||||
tile_y: tile_origin.y() as i16,
|
|
||||||
mask_0_backdrop: 0,
|
|
||||||
mask_0_u: 0,
|
|
||||||
mask_0_v: 0,
|
|
||||||
ctrl: 0,
|
|
||||||
pad: 0,
|
|
||||||
color: paint_id.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,69 +7,88 @@ shaders/gl3/blit.fs.glsl
|
||||||
shaders/gl3/blit.vs.glsl
|
shaders/gl3/blit.vs.glsl
|
||||||
shaders/gl3/clear.fs.glsl
|
shaders/gl3/clear.fs.glsl
|
||||||
shaders/gl3/clear.vs.glsl
|
shaders/gl3/clear.vs.glsl
|
||||||
shaders/gl3/debug_solid.fs.glsl
|
shaders/gl3/d3d9/fill.fs.glsl
|
||||||
shaders/gl3/debug_solid.vs.glsl
|
shaders/gl3/d3d9/fill.vs.glsl
|
||||||
shaders/gl3/debug_texture.fs.glsl
|
shaders/gl3/d3d9/tile.fs.glsl
|
||||||
shaders/gl3/debug_texture.vs.glsl
|
shaders/gl3/d3d9/tile.vs.glsl
|
||||||
|
shaders/gl3/d3d9/tile_clip_combine.fs.glsl
|
||||||
|
shaders/gl3/d3d9/tile_clip_combine.vs.glsl
|
||||||
|
shaders/gl3/d3d9/tile_clip_copy.fs.glsl
|
||||||
|
shaders/gl3/d3d9/tile_clip_copy.vs.glsl
|
||||||
|
shaders/gl3/d3d9/tile_copy.fs.glsl
|
||||||
|
shaders/gl3/d3d9/tile_copy.vs.glsl
|
||||||
|
shaders/gl3/debug/solid.fs.glsl
|
||||||
|
shaders/gl3/debug/solid.vs.glsl
|
||||||
|
shaders/gl3/debug/texture.fs.glsl
|
||||||
|
shaders/gl3/debug/texture.vs.glsl
|
||||||
shaders/gl3/demo_ground.fs.glsl
|
shaders/gl3/demo_ground.fs.glsl
|
||||||
shaders/gl3/demo_ground.vs.glsl
|
shaders/gl3/demo_ground.vs.glsl
|
||||||
shaders/gl3/fill.fs.glsl
|
|
||||||
shaders/gl3/fill.vs.glsl
|
|
||||||
shaders/gl3/reproject.fs.glsl
|
shaders/gl3/reproject.fs.glsl
|
||||||
shaders/gl3/reproject.vs.glsl
|
shaders/gl3/reproject.vs.glsl
|
||||||
shaders/gl3/stencil.fs.glsl
|
shaders/gl3/stencil.fs.glsl
|
||||||
shaders/gl3/stencil.vs.glsl
|
shaders/gl3/stencil.vs.glsl
|
||||||
shaders/gl3/tile.fs.glsl
|
|
||||||
shaders/gl3/tile.vs.glsl
|
|
||||||
shaders/gl3/tile_clip.fs.glsl
|
|
||||||
shaders/gl3/tile_clip.vs.glsl
|
|
||||||
shaders/gl3/tile_copy.fs.glsl
|
|
||||||
shaders/gl3/tile_copy.vs.glsl
|
|
||||||
shaders/gl4/blit.fs.glsl
|
shaders/gl4/blit.fs.glsl
|
||||||
shaders/gl4/blit.vs.glsl
|
shaders/gl4/blit.vs.glsl
|
||||||
shaders/gl4/clear.fs.glsl
|
shaders/gl4/clear.fs.glsl
|
||||||
shaders/gl4/clear.vs.glsl
|
shaders/gl4/clear.vs.glsl
|
||||||
shaders/gl4/debug_solid.fs.glsl
|
shaders/gl4/d3d11/bin.cs.glsl
|
||||||
shaders/gl4/debug_solid.vs.glsl
|
shaders/gl4/d3d11/bound.cs.glsl
|
||||||
shaders/gl4/debug_texture.fs.glsl
|
shaders/gl4/d3d11/dice.cs.glsl
|
||||||
shaders/gl4/debug_texture.vs.glsl
|
shaders/gl4/d3d11/fill.cs.glsl
|
||||||
|
shaders/gl4/d3d11/propagate.cs.glsl
|
||||||
|
shaders/gl4/d3d11/sort.cs.glsl
|
||||||
|
shaders/gl4/d3d11/tile.cs.glsl
|
||||||
|
shaders/gl4/d3d9/fill.fs.glsl
|
||||||
|
shaders/gl4/d3d9/fill.vs.glsl
|
||||||
|
shaders/gl4/d3d9/tile.fs.glsl
|
||||||
|
shaders/gl4/d3d9/tile.vs.glsl
|
||||||
|
shaders/gl4/d3d9/tile_clip_combine.fs.glsl
|
||||||
|
shaders/gl4/d3d9/tile_clip_combine.vs.glsl
|
||||||
|
shaders/gl4/d3d9/tile_clip_copy.fs.glsl
|
||||||
|
shaders/gl4/d3d9/tile_clip_copy.vs.glsl
|
||||||
|
shaders/gl4/d3d9/tile_copy.fs.glsl
|
||||||
|
shaders/gl4/d3d9/tile_copy.vs.glsl
|
||||||
|
shaders/gl4/debug/solid.fs.glsl
|
||||||
|
shaders/gl4/debug/solid.vs.glsl
|
||||||
|
shaders/gl4/debug/texture.fs.glsl
|
||||||
|
shaders/gl4/debug/texture.vs.glsl
|
||||||
shaders/gl4/demo_ground.fs.glsl
|
shaders/gl4/demo_ground.fs.glsl
|
||||||
shaders/gl4/demo_ground.vs.glsl
|
shaders/gl4/demo_ground.vs.glsl
|
||||||
shaders/gl4/fill.fs.glsl
|
|
||||||
shaders/gl4/fill.vs.glsl
|
|
||||||
shaders/gl4/reproject.fs.glsl
|
shaders/gl4/reproject.fs.glsl
|
||||||
shaders/gl4/reproject.vs.glsl
|
shaders/gl4/reproject.vs.glsl
|
||||||
shaders/gl4/stencil.fs.glsl
|
shaders/gl4/stencil.fs.glsl
|
||||||
shaders/gl4/stencil.vs.glsl
|
shaders/gl4/stencil.vs.glsl
|
||||||
shaders/gl4/tile.fs.glsl
|
|
||||||
shaders/gl4/tile.vs.glsl
|
|
||||||
shaders/gl4/tile_clip.fs.glsl
|
|
||||||
shaders/gl4/tile_clip.vs.glsl
|
|
||||||
shaders/gl4/tile_copy.fs.glsl
|
|
||||||
shaders/gl4/tile_copy.vs.glsl
|
|
||||||
shaders/metal/blit.fs.metal
|
shaders/metal/blit.fs.metal
|
||||||
shaders/metal/blit.vs.metal
|
shaders/metal/blit.vs.metal
|
||||||
shaders/metal/clear.fs.metal
|
shaders/metal/clear.fs.metal
|
||||||
shaders/metal/clear.vs.metal
|
shaders/metal/clear.vs.metal
|
||||||
shaders/metal/debug_solid.fs.metal
|
shaders/metal/d3d11/bin.cs.metal
|
||||||
shaders/metal/debug_solid.vs.metal
|
shaders/metal/d3d11/bound.cs.metal
|
||||||
shaders/metal/debug_texture.fs.metal
|
shaders/metal/d3d11/dice.cs.metal
|
||||||
shaders/metal/debug_texture.vs.metal
|
shaders/metal/d3d11/fill.cs.metal
|
||||||
|
shaders/metal/d3d11/propagate.cs.metal
|
||||||
|
shaders/metal/d3d11/sort.cs.metal
|
||||||
|
shaders/metal/d3d11/tile.cs.metal
|
||||||
|
shaders/metal/d3d9/fill.fs.metal
|
||||||
|
shaders/metal/d3d9/fill.vs.metal
|
||||||
|
shaders/metal/d3d9/tile.fs.metal
|
||||||
|
shaders/metal/d3d9/tile.vs.metal
|
||||||
|
shaders/metal/d3d9/tile_clip_combine.fs.metal
|
||||||
|
shaders/metal/d3d9/tile_clip_combine.vs.metal
|
||||||
|
shaders/metal/d3d9/tile_clip_copy.fs.metal
|
||||||
|
shaders/metal/d3d9/tile_clip_copy.vs.metal
|
||||||
|
shaders/metal/d3d9/tile_copy.fs.metal
|
||||||
|
shaders/metal/d3d9/tile_copy.vs.metal
|
||||||
|
shaders/metal/debug/solid.fs.metal
|
||||||
|
shaders/metal/debug/solid.vs.metal
|
||||||
|
shaders/metal/debug/texture.fs.metal
|
||||||
|
shaders/metal/debug/texture.vs.metal
|
||||||
shaders/metal/demo_ground.fs.metal
|
shaders/metal/demo_ground.fs.metal
|
||||||
shaders/metal/demo_ground.vs.metal
|
shaders/metal/demo_ground.vs.metal
|
||||||
shaders/metal/fill.cs.metal
|
|
||||||
shaders/metal/fill.fs.metal
|
|
||||||
shaders/metal/fill.vs.metal
|
|
||||||
shaders/metal/reproject.fs.metal
|
shaders/metal/reproject.fs.metal
|
||||||
shaders/metal/reproject.vs.metal
|
shaders/metal/reproject.vs.metal
|
||||||
shaders/metal/stencil.fs.metal
|
shaders/metal/stencil.fs.metal
|
||||||
shaders/metal/stencil.vs.metal
|
shaders/metal/stencil.vs.metal
|
||||||
shaders/metal/tile.fs.metal
|
|
||||||
shaders/metal/tile.vs.metal
|
|
||||||
shaders/metal/tile_clip.fs.metal
|
|
||||||
shaders/metal/tile_clip.vs.metal
|
|
||||||
shaders/metal/tile_copy.fs.metal
|
|
||||||
shaders/metal/tile_copy.vs.metal
|
|
||||||
textures/area-lut.png
|
textures/area-lut.png
|
||||||
textures/debug-corner-fill.png
|
textures/debug-corner-fill.png
|
||||||
textures/debug-corner-outline.png
|
textures/debug-corner-outline.png
|
||||||
|
|
|
@ -26,6 +26,6 @@ out vec4 oFragColor;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
vec4 color = texture(uSrc, vTexCoord);
|
vec4 color = texture(uSrc, vTexCoord);
|
||||||
oFragColor = vec4(color . rgb * color . a, color . a);
|
oFragColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,16 +18,17 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec4 uDestRect;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
in ivec2 aPosition;
|
in ivec2 aPosition;
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
|
vec2 position = mix(uDestRect . xy, uDestRect . zw, vec2(aPosition))/ uFramebufferSize;
|
||||||
vec2 texCoord = vec2(aPosition);
|
vec2 texCoord = vec2(aPosition);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vTexCoord = texCoord;
|
vTexCoord = texCoord;
|
||||||
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0);
|
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), position), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
|
||||||
|
in uvec2 aTessCoord;
|
||||||
|
in uvec4 aLineSegment;
|
||||||
|
in int aTileIndex;
|
||||||
|
|
||||||
|
out vec2 vFrom;
|
||||||
|
out vec2 vTo;
|
||||||
|
|
||||||
|
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth, vec2 tileSize){
|
||||||
|
uint tilesPerRow = uint(stencilTextureWidth / tileSize . x);
|
||||||
|
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
||||||
|
return vec2(tileOffset)* tileSize * vec2(1.0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 computeVertexPosition(uint tileIndex,
|
||||||
|
uvec2 tessCoord,
|
||||||
|
uvec4 packedLineSegment,
|
||||||
|
vec2 tileSize,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
out vec2 outFrom,
|
||||||
|
out vec2 outTo){
|
||||||
|
vec2 tileOrigin = computeTileOffset(uint(tileIndex), framebufferSize . x, tileSize);
|
||||||
|
|
||||||
|
vec4 lineSegment = vec4(packedLineSegment)/ 256.0;
|
||||||
|
vec2 from = lineSegment . xy, to = lineSegment . zw;
|
||||||
|
|
||||||
|
vec2 position;
|
||||||
|
if(tessCoord . x == 0u)
|
||||||
|
position . x = floor(min(from . x, to . x));
|
||||||
|
else
|
||||||
|
position . x = ceil(max(from . x, to . x));
|
||||||
|
if(tessCoord . y == 0u)
|
||||||
|
position . y = floor(min(from . y, to . y));
|
||||||
|
else
|
||||||
|
position . y = tileSize . y;
|
||||||
|
position . y = floor(position . y * 0.25);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec2 offset = vec2(0.0, 1.5)- position * vec2(1.0, 4.0);
|
||||||
|
outFrom = from + offset;
|
||||||
|
outTo = to + offset;
|
||||||
|
|
||||||
|
vec2 globalPosition =(tileOrigin + position)/ framebufferSize * 2.0 - 1.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return vec4(globalPosition, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
gl_Position = computeVertexPosition(uint(aTileIndex),
|
||||||
|
aTessCoord,
|
||||||
|
aLineSegment,
|
||||||
|
uTileSize,
|
||||||
|
uFramebufferSize,
|
||||||
|
vFrom,
|
||||||
|
vTo);
|
||||||
|
}
|
||||||
|
|
|
@ -12,27 +12,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
@ -83,24 +62,37 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform sampler2D uColorTexture0;
|
|
||||||
uniform sampler2D uMaskTexture0;
|
|
||||||
uniform sampler2D uDestTexture;
|
|
||||||
uniform sampler2D uGammaLUT;
|
|
||||||
uniform vec2 uColorTextureSize0;
|
|
||||||
uniform vec2 uMaskTextureSize0;
|
|
||||||
uniform vec4 uFilterParams0;
|
|
||||||
uniform vec4 uFilterParams1;
|
|
||||||
uniform vec4 uFilterParams2;
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform int uCtrl;
|
|
||||||
|
|
||||||
in vec3 vMaskTexCoord0;
|
|
||||||
in vec2 vColorTexCoord0;
|
|
||||||
in vec4 vBaseColor;
|
|
||||||
in float vTileCtrl;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -567,27 +559,42 @@ float sampleMask(float maskAlpha,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void calculateColor(int tileCtrl, int ctrl){
|
vec4 calculateColor(vec2 fragCoord,
|
||||||
|
sampler2D colorTexture0,
|
||||||
|
sampler2D maskTexture0,
|
||||||
|
sampler2D destTexture,
|
||||||
|
sampler2D gammaLUT,
|
||||||
|
vec2 colorTextureSize0,
|
||||||
|
vec2 maskTextureSize0,
|
||||||
|
vec4 filterParams0,
|
||||||
|
vec4 filterParams1,
|
||||||
|
vec4 filterParams2,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
int ctrl,
|
||||||
|
vec3 maskTexCoord0,
|
||||||
|
vec2 colorTexCoord0,
|
||||||
|
vec4 baseColor,
|
||||||
|
int tileCtrl){
|
||||||
|
|
||||||
int maskCtrl0 =(tileCtrl >> 0)& 0x3;
|
int maskCtrl0 =(tileCtrl >> 0)& 0x3;
|
||||||
float maskAlpha = 1.0;
|
float maskAlpha = 1.0;
|
||||||
maskAlpha = sampleMask(maskAlpha, uMaskTexture0, uMaskTextureSize0, vMaskTexCoord0, maskCtrl0);
|
maskAlpha = sampleMask(maskAlpha, maskTexture0, maskTextureSize0, maskTexCoord0, maskCtrl0);
|
||||||
|
|
||||||
|
|
||||||
vec4 color = vBaseColor;
|
vec4 color = baseColor;
|
||||||
int color0Combine =(ctrl >> 6)&
|
int color0Combine =(ctrl >> 6)&
|
||||||
0x3;
|
0x3;
|
||||||
if(color0Combine != 0){
|
if(color0Combine != 0){
|
||||||
int color0Filter =(ctrl >> 4)& 0x3;
|
int color0Filter =(ctrl >> 4)& 0x3;
|
||||||
vec4 color0 = filterColor(vColorTexCoord0,
|
vec4 color0 = filterColor(colorTexCoord0,
|
||||||
uColorTexture0,
|
colorTexture0,
|
||||||
uGammaLUT,
|
gammaLUT,
|
||||||
uColorTextureSize0,
|
colorTextureSize0,
|
||||||
gl_FragCoord . xy,
|
fragCoord,
|
||||||
uFramebufferSize,
|
framebufferSize,
|
||||||
uFilterParams0,
|
filterParams0,
|
||||||
uFilterParams1,
|
filterParams1,
|
||||||
uFilterParams2,
|
filterParams2,
|
||||||
color0Filter);
|
color0Filter);
|
||||||
color = combineColor0(color, color0, color0Combine);
|
color = combineColor0(color, color0, color0Combine);
|
||||||
}
|
}
|
||||||
|
@ -597,18 +604,53 @@ void calculateColor(int tileCtrl, int ctrl){
|
||||||
|
|
||||||
|
|
||||||
int compositeOp =(ctrl >> 8)& 0xf;
|
int compositeOp =(ctrl >> 8)& 0xf;
|
||||||
color = composite(color, uDestTexture, uFramebufferSize, gl_FragCoord . xy, compositeOp);
|
color = composite(color, destTexture, framebufferSize, fragCoord, compositeOp);
|
||||||
|
|
||||||
|
|
||||||
color . rgb *= color . a;
|
color . rgb *= color . a;
|
||||||
oFragColor = color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uniform sampler2D uColorTexture0;
|
||||||
|
uniform sampler2D uMaskTexture0;
|
||||||
|
uniform sampler2D uDestTexture;
|
||||||
|
uniform sampler2D uGammaLUT;
|
||||||
|
uniform vec2 uColorTextureSize0;
|
||||||
|
uniform vec2 uMaskTextureSize0;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in vec3 vMaskTexCoord0;
|
||||||
|
in vec2 vColorTexCoord0;
|
||||||
|
in vec4 vBaseColor;
|
||||||
|
in float vTileCtrl;
|
||||||
|
in vec4 vFilterParams0;
|
||||||
|
in vec4 vFilterParams1;
|
||||||
|
in vec4 vFilterParams2;
|
||||||
|
in float vCtrl;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
calculateColor(int(vTileCtrl), uCtrl);
|
oFragColor = calculateColor(gl_FragCoord . xy,
|
||||||
|
uColorTexture0,
|
||||||
|
uMaskTexture0,
|
||||||
|
uDestTexture,
|
||||||
|
uGammaLUT,
|
||||||
|
uColorTextureSize0,
|
||||||
|
uMaskTextureSize0,
|
||||||
|
vFilterParams0,
|
||||||
|
vFilterParams1,
|
||||||
|
vFilterParams2,
|
||||||
|
uFramebufferSize,
|
||||||
|
int(vCtrl),
|
||||||
|
vMaskTexCoord0,
|
||||||
|
vColorTexCoord0,
|
||||||
|
vBaseColor,
|
||||||
|
int(vTileCtrl));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 fetchUnscaled(sampler2D srcTexture, vec2 scale, vec2 originCoord, int entry){
|
||||||
|
return texture(srcTexture,(originCoord + vec2(0.5)+ vec2(entry, 0))* scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeTileVaryings(vec2 position,
|
||||||
|
int colorEntry,
|
||||||
|
sampler2D textureMetadata,
|
||||||
|
ivec2 textureMetadataSize,
|
||||||
|
out vec2 outColorTexCoord0,
|
||||||
|
out vec4 outBaseColor,
|
||||||
|
out vec4 outFilterParams0,
|
||||||
|
out vec4 outFilterParams1,
|
||||||
|
out vec4 outFilterParams2,
|
||||||
|
out int outCtrl){
|
||||||
|
vec2 metadataScale = vec2(1.0)/ vec2(textureMetadataSize);
|
||||||
|
vec2 metadataEntryCoord = vec2(colorEntry % 128 * 8, colorEntry / 128);
|
||||||
|
vec4 colorTexMatrix0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 0);
|
||||||
|
vec4 colorTexOffsets = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 1);
|
||||||
|
vec4 baseColor = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 2);
|
||||||
|
vec4 filterParams0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 3);
|
||||||
|
vec4 filterParams1 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 4);
|
||||||
|
vec4 filterParams2 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 5);
|
||||||
|
vec4 extra = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 6);
|
||||||
|
outColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
|
||||||
|
outBaseColor = baseColor;
|
||||||
|
outFilterParams0 = filterParams0;
|
||||||
|
outFilterParams1 = filterParams1;
|
||||||
|
outFilterParams2 = filterParams2;
|
||||||
|
outCtrl = int(extra . x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uniform mat4 uTransform;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
uniform sampler2D uTextureMetadata;
|
||||||
|
uniform ivec2 uTextureMetadataSize;
|
||||||
|
uniform sampler2D uZBuffer;
|
||||||
|
uniform ivec2 uZBufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in ivec2 aTileOrigin;
|
||||||
|
in uvec4 aMaskTexCoord0;
|
||||||
|
in ivec2 aCtrlBackdrop;
|
||||||
|
in int aPathIndex;
|
||||||
|
in int aColor;
|
||||||
|
|
||||||
|
out vec3 vMaskTexCoord0;
|
||||||
|
out vec2 vColorTexCoord0;
|
||||||
|
out vec4 vBaseColor;
|
||||||
|
out float vTileCtrl;
|
||||||
|
out vec4 vFilterParams0;
|
||||||
|
out vec4 vFilterParams1;
|
||||||
|
out vec4 vFilterParams2;
|
||||||
|
out float vCtrl;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
||||||
|
vec2 position =(tileOrigin + tileOffset)* uTileSize;
|
||||||
|
|
||||||
|
ivec4 zValue = ivec4(texture(uZBuffer,(tileOrigin + vec2(0.5))/ vec2(uZBufferSize))* 255.0);
|
||||||
|
if(aPathIndex <(zValue . x |(zValue . y << 8)|(zValue . z << 16)|(zValue . w << 24))){
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uvec2 maskTileCoord = uvec2(aMaskTexCoord0 . x, aMaskTexCoord0 . y + 256u * aMaskTexCoord0 . z);
|
||||||
|
vec2 maskTexCoord0 =(vec2(maskTileCoord)+ tileOffset)* uTileSize;
|
||||||
|
if(aCtrlBackdrop . y == 0 && aMaskTexCoord0 . w != 0u){
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctrl;
|
||||||
|
computeTileVaryings(position,
|
||||||
|
aColor,
|
||||||
|
uTextureMetadata,
|
||||||
|
uTextureMetadataSize,
|
||||||
|
vColorTexCoord0,
|
||||||
|
vBaseColor,
|
||||||
|
vFilterParams0,
|
||||||
|
vFilterParams1,
|
||||||
|
vFilterParams2,
|
||||||
|
ctrl);
|
||||||
|
|
||||||
|
vTileCtrl = float(aCtrlBackdrop . x);
|
||||||
|
vCtrl = float(ctrl);
|
||||||
|
vMaskTexCoord0 = vec3(maskTexCoord0, float(aCtrlBackdrop . y));
|
||||||
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
|
in vec2 vTexCoord0;
|
||||||
|
in float vBackdrop0;
|
||||||
|
in vec2 vTexCoord1;
|
||||||
|
in float vBackdrop1;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
oFragColor = min(abs(texture(uSrc, vTexCoord0)+ vBackdrop0),
|
||||||
|
abs(texture(uSrc, vTexCoord1)+ vBackdrop1));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in int aDestTileIndex;
|
||||||
|
in int aDestBackdrop;
|
||||||
|
in int aSrcTileIndex;
|
||||||
|
in int aSrcBackdrop;
|
||||||
|
|
||||||
|
out vec2 vTexCoord0;
|
||||||
|
out float vBackdrop0;
|
||||||
|
out vec2 vTexCoord1;
|
||||||
|
out float vBackdrop1;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 destPosition = vec2(ivec2(aDestTileIndex % 256, aDestTileIndex / 256)+ aTileOffset);
|
||||||
|
vec2 srcPosition = vec2(ivec2(aSrcTileIndex % 256, aSrcTileIndex / 256)+ aTileOffset);
|
||||||
|
destPosition *= vec2(16.0, 4.0)/ uFramebufferSize;
|
||||||
|
srcPosition *= vec2(16.0, 4.0)/ uFramebufferSize;
|
||||||
|
|
||||||
|
vTexCoord0 = destPosition;
|
||||||
|
vTexCoord1 = srcPosition;
|
||||||
|
|
||||||
|
vBackdrop0 = float(aDestBackdrop);
|
||||||
|
vBackdrop1 = float(aSrcBackdrop);
|
||||||
|
|
||||||
|
if(aDestTileIndex < 0)
|
||||||
|
destPosition = vec2(0.0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), destPosition), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -21,11 +21,10 @@ precision highp float;
|
||||||
uniform sampler2D uSrc;
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
in float vBackdrop;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
oFragColor = clamp(abs(texture(uSrc, vTexCoord)+ vBackdrop), 0.0, 1.0);
|
oFragColor = texture(uSrc, vTexCoord);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in int aTileIndex;
|
||||||
|
|
||||||
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 position = vec2(ivec2(aTileIndex % 256, aTileIndex / 256)+ aTileOffset);
|
||||||
|
position *= vec2(16.0, 4.0)/ uFramebufferSize;
|
||||||
|
|
||||||
|
vTexCoord = position;
|
||||||
|
|
||||||
|
if(aTileIndex < 0)
|
||||||
|
position = vec2(0.0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), position), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
|
||||||
in uint aFromPx;
|
|
||||||
in uint aToPx;
|
|
||||||
in vec2 aFromSubpx;
|
|
||||||
in vec2 aToSubpx;
|
|
||||||
in uint aTileIndex;
|
|
||||||
|
|
||||||
out vec2 vFrom;
|
|
||||||
out vec2 vTo;
|
|
||||||
|
|
||||||
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
|
|
||||||
uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x);
|
|
||||||
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
|
||||||
return vec2(tileOffset)* uTileSize * vec2(1.0, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 tileOrigin = computeTileOffset(aTileIndex, uFramebufferSize . x);
|
|
||||||
|
|
||||||
vec2 from = vec2(aFromPx & 15u, aFromPx >> 4u)+ aFromSubpx;
|
|
||||||
vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx;
|
|
||||||
|
|
||||||
vec2 position;
|
|
||||||
if(aTessCoord . x == 0u)
|
|
||||||
position . x = floor(min(from . x, to . x));
|
|
||||||
else
|
|
||||||
position . x = ceil(max(from . x, to . x));
|
|
||||||
if(aTessCoord . y == 0u)
|
|
||||||
position . y = floor(min(from . y, to . y));
|
|
||||||
else
|
|
||||||
position . y = uTileSize . y;
|
|
||||||
position . y = floor(position . y * 0.25);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec2 offset = vec2(0.0, 1.5)- position * vec2(1.0, 4.0);
|
|
||||||
vFrom = from + offset;
|
|
||||||
vTo = to + offset;
|
|
||||||
|
|
||||||
vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gl_Position = vec4(globalPosition, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
uniform sampler2D uTextureMetadata;
|
|
||||||
uniform ivec2 uTextureMetadataSize;
|
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
|
||||||
in ivec2 aTileOrigin;
|
|
||||||
in uvec2 aMaskTexCoord0;
|
|
||||||
in ivec2 aMaskBackdrop;
|
|
||||||
in int aColor;
|
|
||||||
in int aTileCtrl;
|
|
||||||
|
|
||||||
out vec3 vMaskTexCoord0;
|
|
||||||
out vec2 vColorTexCoord0;
|
|
||||||
out vec4 vBaseColor;
|
|
||||||
out float vTileCtrl;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
|
||||||
vec2 position =(tileOrigin + tileOffset)* uTileSize;
|
|
||||||
|
|
||||||
vec2 maskTexCoord0 =(vec2(aMaskTexCoord0)+ tileOffset)* uTileSize;
|
|
||||||
|
|
||||||
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
|
|
||||||
vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128);
|
|
||||||
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
|
|
||||||
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
|
|
||||||
vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale;
|
|
||||||
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
|
|
||||||
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
|
|
||||||
vec4 baseColor = texture(uTextureMetadata, baseColorCoord);
|
|
||||||
|
|
||||||
vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
|
|
||||||
vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop . x));
|
|
||||||
vBaseColor = baseColor;
|
|
||||||
vTileCtrl = float(aTileCtrl);
|
|
||||||
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
|
||||||
in ivec2 aDestTileOrigin;
|
|
||||||
in ivec2 aSrcTileOrigin;
|
|
||||||
in int aSrcBackdrop;
|
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
|
||||||
out float vBackdrop;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 destPosition = vec2(aDestTileOrigin + aTileOffset)/ vec2(256.0);
|
|
||||||
vec2 srcPosition = vec2(aSrcTileOrigin + aTileOffset)/ vec2(256.0);
|
|
||||||
vTexCoord = srcPosition;
|
|
||||||
vBackdrop = float(aSrcBackdrop);
|
|
||||||
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), destPosition), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -26,6 +26,6 @@ out vec4 oFragColor;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
vec4 color = texture(uSrc, vTexCoord);
|
vec4 color = texture(uSrc, vTexCoord);
|
||||||
oFragColor = vec4(color . rgb * color . a, color . a);
|
oFragColor = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,16 +18,17 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec4 uDestRect;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
in ivec2 aPosition;
|
in ivec2 aPosition;
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
|
vec2 position = mix(uDestRect . xy, uDestRect . zw, vec2(aPosition))/ uFramebufferSize;
|
||||||
vec2 texCoord = vec2(aPosition);
|
vec2 texCoord = vec2(aPosition);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vTexCoord = texCoord;
|
vTexCoord = texCoord;
|
||||||
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0);
|
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), position), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,259 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(local_size_x = 64)in;
|
||||||
|
|
||||||
|
uniform int uMicrolineCount;
|
||||||
|
|
||||||
|
uniform int uMaxFillCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bMicrolines {
|
||||||
|
restrict readonly uvec4 iMicrolines[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bMetadata {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly ivec4 iMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(std430, binding = 2)buffer bIndirectDrawParams {
|
||||||
|
restrict uint iIndirectDrawParams[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3)buffer bFills {
|
||||||
|
restrict writeonly uint iFills[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 4)buffer bTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 5)buffer bBackdrops {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iBackdrops[];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint computeTileIndexNoCheck(ivec2 tileCoords, ivec4 pathTileRect, uint pathTileOffset){
|
||||||
|
ivec2 offsetCoords = tileCoords - pathTileRect . xy;
|
||||||
|
return pathTileOffset + offsetCoords . x + offsetCoords . y *(pathTileRect . z - pathTileRect . x);
|
||||||
|
}
|
||||||
|
|
||||||
|
bvec4 computeTileOutcodes(ivec2 tileCoords, ivec4 pathTileRect){
|
||||||
|
return bvec4(lessThan(tileCoords, pathTileRect . xy),
|
||||||
|
greaterThanEqual(tileCoords, pathTileRect . zw));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool computeTileIndex(ivec2 tileCoords,
|
||||||
|
ivec4 pathTileRect,
|
||||||
|
uint pathTileOffset,
|
||||||
|
out uint outTileIndex){
|
||||||
|
outTileIndex = computeTileIndexNoCheck(tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
return ! any(computeTileOutcodes(tileCoords, pathTileRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFill(vec4 lineSegment, ivec2 tileCoords, ivec4 pathTileRect, uint pathTileOffset){
|
||||||
|
|
||||||
|
uint tileIndex;
|
||||||
|
if(! computeTileIndex(tileCoords, pathTileRect, pathTileOffset, tileIndex)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uvec4 scaledLocalLine = uvec4((lineSegment - vec4(tileCoords . xyxy * ivec4(16)))* vec4(256.0));
|
||||||
|
if(scaledLocalLine . x == scaledLocalLine . z)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
uint fillIndex = atomicAdd(iIndirectDrawParams[1], 1);
|
||||||
|
|
||||||
|
|
||||||
|
uint fillLink = atomicExchange(iTiles[tileIndex * 4 + 1],
|
||||||
|
int(fillIndex));
|
||||||
|
|
||||||
|
|
||||||
|
if(fillIndex < uMaxFillCount){
|
||||||
|
iFills[fillIndex * 3 + 0]= scaledLocalLine . x |(scaledLocalLine . y << 16);
|
||||||
|
iFills[fillIndex * 3 + 1]= scaledLocalLine . z |(scaledLocalLine . w << 16);
|
||||||
|
iFills[fillIndex * 3 + 2]= fillLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjustBackdrop(int backdropDelta,
|
||||||
|
ivec2 tileCoords,
|
||||||
|
ivec4 pathTileRect,
|
||||||
|
uint pathTileOffset,
|
||||||
|
uint pathBackdropOffset){
|
||||||
|
bvec4 outcodes = computeTileOutcodes(tileCoords, pathTileRect);
|
||||||
|
if(any(outcodes)){
|
||||||
|
if(! outcodes . x && outcodes . y && ! outcodes . z){
|
||||||
|
uint backdropIndex = pathBackdropOffset + uint(tileCoords . x - pathTileRect . x);
|
||||||
|
atomicAdd(iBackdrops[backdropIndex * 3], backdropDelta);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint tileIndex = computeTileIndexNoCheck(tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
atomicAdd(iTiles[tileIndex * 4 + 2],
|
||||||
|
uint(backdropDelta)<< 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 unpackMicroline(uvec4 packedMicroline, out uint outPathIndex){
|
||||||
|
outPathIndex = packedMicroline . w;
|
||||||
|
ivec4 signedMicroline = ivec4(packedMicroline);
|
||||||
|
return vec4((signedMicroline . x << 16)>> 16, signedMicroline . x >> 16,
|
||||||
|
(signedMicroline . y << 16)>> 16, signedMicroline . y >> 16)+
|
||||||
|
vec4(signedMicroline . z & 0xff,(signedMicroline . z >> 8)& 0xff,
|
||||||
|
(signedMicroline . z >> 16)& 0xff,(signedMicroline . z >> 24)& 0xff)/ 256.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
uint segmentIndex = gl_GlobalInvocationID . x;
|
||||||
|
if(segmentIndex >= uMicrolineCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint pathIndex;
|
||||||
|
vec4 lineSegment = unpackMicroline(iMicrolines[segmentIndex], pathIndex);
|
||||||
|
|
||||||
|
ivec4 pathTileRect = iMetadata[pathIndex * 3 + 0];
|
||||||
|
uint pathTileOffset = uint(iMetadata[pathIndex * 3 + 1]. x);
|
||||||
|
uint pathBackdropOffset = uint(iMetadata[pathIndex * 3 + 2]. x);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ivec2 tileSize = ivec2(16);
|
||||||
|
|
||||||
|
ivec4 tileLineSegment = ivec4(floor(lineSegment / vec4(tileSize . xyxy)));
|
||||||
|
ivec2 fromTileCoords = tileLineSegment . xy, toTileCoords = tileLineSegment . zw;
|
||||||
|
|
||||||
|
vec2 vector = lineSegment . zw - lineSegment . xy;
|
||||||
|
vec2 vectorIsNegative = vec2(vector . x < 0.0 ? - 1.0 : 0.0, vector . y < 0.0 ? - 1.0 : 0.0);
|
||||||
|
ivec2 tileStep = ivec2(vector . x < 0.0 ? - 1 : 1, vector . y < 0.0 ? - 1 : 1);
|
||||||
|
|
||||||
|
vec2 firstTileCrossing = vec2((fromTileCoords + ivec2(vector . x >= 0.0 ? 1 : 0,
|
||||||
|
vector . y >= 0.0 ? 1 : 0))* tileSize);
|
||||||
|
|
||||||
|
vec2 tMax =(firstTileCrossing - lineSegment . xy)/ vector;
|
||||||
|
vec2 tDelta = abs(tileSize / vector);
|
||||||
|
|
||||||
|
vec2 currentPosition = lineSegment . xy;
|
||||||
|
ivec2 tileCoords = fromTileCoords;
|
||||||
|
int lastStepDirection = 0;
|
||||||
|
uint iteration = 0;
|
||||||
|
|
||||||
|
while(iteration < 1024u){
|
||||||
|
int nextStepDirection;
|
||||||
|
if(tMax . x < tMax . y)
|
||||||
|
nextStepDirection = 1;
|
||||||
|
else if(tMax . x > tMax . y)
|
||||||
|
nextStepDirection = 2;
|
||||||
|
else if(tileStep . x > 0.0)
|
||||||
|
nextStepDirection = 1;
|
||||||
|
else
|
||||||
|
nextStepDirection = 2;
|
||||||
|
|
||||||
|
float nextT = min(nextStepDirection == 1 ? tMax . x : tMax . y, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
if(tileCoords == toTileCoords)
|
||||||
|
nextStepDirection = 0;
|
||||||
|
|
||||||
|
vec2 nextPosition = mix(lineSegment . xy, lineSegment . zw, nextT);
|
||||||
|
vec4 clippedLineSegment = vec4(currentPosition, nextPosition);
|
||||||
|
addFill(clippedLineSegment, tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
|
||||||
|
|
||||||
|
vec4 auxiliarySegment;
|
||||||
|
bool haveAuxiliarySegment = false;
|
||||||
|
if(tileStep . y < 0 && nextStepDirection == 2){
|
||||||
|
auxiliarySegment = vec4(clippedLineSegment . zw, vec2(tileCoords * tileSize));
|
||||||
|
haveAuxiliarySegment = true;
|
||||||
|
} else if(tileStep . y > 0 && lastStepDirection == 2){
|
||||||
|
auxiliarySegment = vec4(vec2(tileCoords * tileSize), clippedLineSegment . xy);
|
||||||
|
haveAuxiliarySegment = true;
|
||||||
|
}
|
||||||
|
if(haveAuxiliarySegment)
|
||||||
|
addFill(auxiliarySegment, tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(tileStep . x < 0 && lastStepDirection == 1){
|
||||||
|
adjustBackdrop(1,
|
||||||
|
tileCoords,
|
||||||
|
pathTileRect,
|
||||||
|
pathTileOffset,
|
||||||
|
pathBackdropOffset);
|
||||||
|
} else if(tileStep . x > 0 && nextStepDirection == 1){
|
||||||
|
adjustBackdrop(- 1,
|
||||||
|
tileCoords,
|
||||||
|
pathTileRect,
|
||||||
|
pathTileOffset,
|
||||||
|
pathBackdropOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(nextStepDirection == 1){
|
||||||
|
tMax . x += tDelta . x;
|
||||||
|
tileCoords . x += tileStep . x;
|
||||||
|
} else if(nextStepDirection == 2){
|
||||||
|
tMax . y += tDelta . y;
|
||||||
|
tileCoords . y += tileStep . y;
|
||||||
|
} else if(nextStepDirection == 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPosition = nextPosition;
|
||||||
|
lastStepDirection = nextStepDirection;
|
||||||
|
|
||||||
|
iteration ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(local_size_x = 64)in;
|
||||||
|
|
||||||
|
uniform int uPathCount;
|
||||||
|
uniform int uTileCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bTilePathInfo {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly uvec4 iTilePathInfo[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
uint tileIndex = gl_GlobalInvocationID . x;
|
||||||
|
if(tileIndex >= uint(uTileCount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint lowPathIndex = 0, highPathIndex = uint(uPathCount);
|
||||||
|
int iteration = 0;
|
||||||
|
while(iteration < 1024 && lowPathIndex + 1 < highPathIndex){
|
||||||
|
uint midPathIndex = lowPathIndex +(highPathIndex - lowPathIndex)/ 2;
|
||||||
|
uint midTileIndex = iTilePathInfo[midPathIndex]. z;
|
||||||
|
if(tileIndex < midTileIndex){
|
||||||
|
highPathIndex = midPathIndex;
|
||||||
|
} else {
|
||||||
|
lowPathIndex = midPathIndex;
|
||||||
|
if(tileIndex == midTileIndex)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iteration ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint pathIndex = lowPathIndex;
|
||||||
|
uvec4 pathInfo = iTilePathInfo[pathIndex];
|
||||||
|
|
||||||
|
ivec2 packedTileRect = ivec2(pathInfo . xy);
|
||||||
|
ivec4 tileRect = ivec4((packedTileRect . x << 16)>> 16, packedTileRect . x >> 16,
|
||||||
|
(packedTileRect . y << 16)>> 16, packedTileRect . y >> 16);
|
||||||
|
|
||||||
|
uint tileOffset = tileIndex - pathInfo . z;
|
||||||
|
uint tileWidth = uint(tileRect . z - tileRect . x);
|
||||||
|
ivec2 tileCoords = tileRect . xy + ivec2(tileOffset % tileWidth, tileOffset / tileWidth);
|
||||||
|
|
||||||
|
iTiles[tileIndex * 4 + 0]= ~ 0u;
|
||||||
|
iTiles[tileIndex * 4 + 1]= ~ 0u;
|
||||||
|
iTiles[tileIndex * 4 + 2]= 0x00ffffffu;
|
||||||
|
iTiles[tileIndex * 4 + 3]= pathInfo . w;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(local_size_x = 64)in;
|
||||||
|
|
||||||
|
uniform mat2 uTransform;
|
||||||
|
uniform vec2 uTranslation;
|
||||||
|
uniform int uPathCount;
|
||||||
|
uniform int uLastBatchSegmentIndex;
|
||||||
|
uniform int uMaxMicrolineCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bComputeIndirectParams {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iComputeIndirectParams[];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bDiceMetadata {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly uvec4 iDiceMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2)buffer bPoints {
|
||||||
|
restrict readonly vec2 iPoints[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3)buffer bInputIndices {
|
||||||
|
restrict readonly uvec2 iInputIndices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 4)buffer bMicrolines {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uvec4 iMicrolines[];
|
||||||
|
};
|
||||||
|
|
||||||
|
void emitMicroline(vec4 microlineSegment, uint pathIndex, uint outputMicrolineIndex){
|
||||||
|
if(outputMicrolineIndex >= uMaxMicrolineCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ivec4 microlineSubpixels = ivec4(round(clamp(microlineSegment, - 32768.0, 32767.0)* 256.0));
|
||||||
|
ivec4 microlinePixels = ivec4(floor(vec4(microlineSubpixels)/ 256.0));
|
||||||
|
ivec4 microlineFractPixels = microlineSubpixels - microlinePixels * 256;
|
||||||
|
|
||||||
|
iMicrolines[outputMicrolineIndex]=
|
||||||
|
uvec4((uint(microlinePixels . x)& 0xffff)|(uint(microlinePixels . y)<< 16),
|
||||||
|
(uint(microlinePixels . z)& 0xffff)|(uint(microlinePixels . w)<< 16),
|
||||||
|
uint(microlineFractPixels . x)|(uint(microlineFractPixels . y)<< 8)|
|
||||||
|
(uint(microlineFractPixels . z)<< 16)|(uint(microlineFractPixels . w)<< 24),
|
||||||
|
pathIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool curveIsFlat(vec4 baseline, vec4 ctrl){
|
||||||
|
vec4 uv = vec4(3.0)* ctrl - vec4(2.0)* baseline - baseline . zwxy;
|
||||||
|
uv *= uv;
|
||||||
|
uv = max(uv, uv . zwxy);
|
||||||
|
return uv . x + uv . y <= 16.0 * 0.25 * 0.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subdivideCurve(vec4 baseline,
|
||||||
|
vec4 ctrl,
|
||||||
|
float t,
|
||||||
|
out vec4 prevBaseline,
|
||||||
|
out vec4 prevCtrl,
|
||||||
|
out vec4 nextBaseline,
|
||||||
|
out vec4 nextCtrl){
|
||||||
|
vec2 p0 = baseline . xy, p1 = ctrl . xy, p2 = ctrl . zw, p3 = baseline . zw;
|
||||||
|
vec2 p0p1 = mix(p0, p1, t), p1p2 = mix(p1, p2, t), p2p3 = mix(p2, p3, t);
|
||||||
|
vec2 p0p1p2 = mix(p0p1, p1p2, t), p1p2p3 = mix(p1p2, p2p3, t);
|
||||||
|
vec2 p0p1p2p3 = mix(p0p1p2, p1p2p3, t);
|
||||||
|
prevBaseline = vec4(p0, p0p1p2p3);
|
||||||
|
prevCtrl = vec4(p0p1, p0p1p2);
|
||||||
|
nextBaseline = vec4(p0p1p2p3, p3);
|
||||||
|
nextCtrl = vec4(p1p2p3, p2p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 sampleCurve(vec4 baseline, vec4 ctrl, float t){
|
||||||
|
vec2 p0 = baseline . xy, p1 = ctrl . xy, p2 = ctrl . zw, p3 = baseline . zw;
|
||||||
|
vec2 p0p1 = mix(p0, p1, t), p1p2 = mix(p1, p2, t), p2p3 = mix(p2, p3, t);
|
||||||
|
vec2 p0p1p2 = mix(p0p1, p1p2, t), p1p2p3 = mix(p1p2, p2p3, t);
|
||||||
|
return mix(p0p1p2, p1p2p3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 sampleLine(vec4 line, float t){
|
||||||
|
return mix(line . xy, line . zw, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getPoint(uint pointIndex){
|
||||||
|
return uTransform * iPoints[pointIndex]+ uTranslation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
uint batchSegmentIndex = gl_GlobalInvocationID . x;
|
||||||
|
if(batchSegmentIndex >= uLastBatchSegmentIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
uint lowPathIndex = 0, highPathIndex = uint(uPathCount);
|
||||||
|
int iteration = 0;
|
||||||
|
while(iteration < 1024 && lowPathIndex + 1 < highPathIndex){
|
||||||
|
uint midPathIndex = lowPathIndex +(highPathIndex - lowPathIndex)/ 2;
|
||||||
|
uint midBatchSegmentIndex = iDiceMetadata[midPathIndex]. z;
|
||||||
|
if(batchSegmentIndex < midBatchSegmentIndex){
|
||||||
|
highPathIndex = midPathIndex;
|
||||||
|
} else {
|
||||||
|
lowPathIndex = midPathIndex;
|
||||||
|
if(batchSegmentIndex == midBatchSegmentIndex)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iteration ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint batchPathIndex = lowPathIndex;
|
||||||
|
uvec4 diceMetadata = iDiceMetadata[batchPathIndex];
|
||||||
|
uint firstGlobalSegmentIndexInPath = diceMetadata . y;
|
||||||
|
uint firstBatchSegmentIndexInPath = diceMetadata . z;
|
||||||
|
uint globalSegmentIndex = batchSegmentIndex - firstBatchSegmentIndexInPath +
|
||||||
|
firstGlobalSegmentIndexInPath;
|
||||||
|
|
||||||
|
uvec2 inputIndices = iInputIndices[globalSegmentIndex];
|
||||||
|
uint fromPointIndex = inputIndices . x, flagsPathIndex = inputIndices . y;
|
||||||
|
|
||||||
|
uint toPointIndex = fromPointIndex;
|
||||||
|
if((flagsPathIndex & 0x40000000u)!= 0u)
|
||||||
|
toPointIndex += 3;
|
||||||
|
else if((flagsPathIndex & 0x80000000u)!= 0u)
|
||||||
|
toPointIndex += 2;
|
||||||
|
else
|
||||||
|
toPointIndex += 1;
|
||||||
|
|
||||||
|
vec4 baseline = vec4(getPoint(fromPointIndex), getPoint(toPointIndex));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 ctrl = vec4(0.0);
|
||||||
|
float segmentCountF;
|
||||||
|
bool isCurve =(flagsPathIndex &(0x40000000u |
|
||||||
|
0x80000000u))!= 0;
|
||||||
|
if(isCurve){
|
||||||
|
vec2 ctrl0 = getPoint(fromPointIndex + 1);
|
||||||
|
if((flagsPathIndex & 0x80000000u)!= 0){
|
||||||
|
vec2 ctrl0_2 = ctrl0 * vec2(2.0);
|
||||||
|
ctrl =(baseline +(ctrl0 * vec2(2.0)). xyxy)* vec4(1.0 / 3.0);
|
||||||
|
} else {
|
||||||
|
ctrl = vec4(ctrl0, getPoint(fromPointIndex + 2));
|
||||||
|
}
|
||||||
|
vec2 bound = vec2(6.0)* max(abs(ctrl . zw - 2.0 * ctrl . xy + baseline . xy),
|
||||||
|
abs(baseline . zw - 2.0 * ctrl . zw + ctrl . xy));
|
||||||
|
segmentCountF = sqrt(length(bound)/(8.0 * 0.25));
|
||||||
|
} else {
|
||||||
|
segmentCountF = length(baseline . zw - baseline . xy)/ 16.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int segmentCount = max(int(ceil(segmentCountF)), 1);
|
||||||
|
uint firstOutputMicrolineIndex =
|
||||||
|
atomicAdd(iComputeIndirectParams[3],
|
||||||
|
segmentCount);
|
||||||
|
|
||||||
|
float prevT = 0.0;
|
||||||
|
vec2 prevPoint = baseline . xy;
|
||||||
|
for(int segmentIndex = 0;segmentIndex < segmentCount;segmentIndex ++){
|
||||||
|
float nextT = float(segmentIndex + 1)/ float(segmentCount);
|
||||||
|
vec2 nextPoint;
|
||||||
|
if(isCurve)
|
||||||
|
nextPoint = sampleCurve(baseline, ctrl, nextT);
|
||||||
|
else
|
||||||
|
nextPoint = sampleLine(baseline, nextT);
|
||||||
|
emitMicroline(vec4(prevPoint, nextPoint),
|
||||||
|
batchPathIndex,
|
||||||
|
firstOutputMicrolineIndex + segmentIndex);
|
||||||
|
prevT = nextT;
|
||||||
|
prevPoint = nextPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
|
||||||
|
|
||||||
|
vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from;
|
||||||
|
|
||||||
|
|
||||||
|
vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5);
|
||||||
|
float offset = mix(window . x, window . y, 0.5)- left . x;
|
||||||
|
float t = offset /(right . x - left . x);
|
||||||
|
|
||||||
|
|
||||||
|
float y = mix(left . y, right . y, t);
|
||||||
|
float d =(right . y - left . y)/(right . x - left . x);
|
||||||
|
|
||||||
|
|
||||||
|
float dX = window . x - window . y;
|
||||||
|
return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
layout(local_size_x = 16, local_size_y = 4)in;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(rgba8)uniform image2D uDest;
|
||||||
|
uniform sampler2D uAreaLUT;
|
||||||
|
uniform ivec2 uAlphaTileRange;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bFills {
|
||||||
|
restrict readonly uint iFills[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2)buffer bAlphaTiles {
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly uint iAlphaTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 accumulateCoverageForFillList(int fillIndex, ivec2 tileSubCoord){
|
||||||
|
vec2 tileFragCoord = vec2(tileSubCoord)+ vec2(0.5);
|
||||||
|
vec4 coverages = vec4(0.0);
|
||||||
|
int iteration = 0;
|
||||||
|
do {
|
||||||
|
uint fillFrom = iFills[fillIndex * 3 + 0], fillTo = iFills[fillIndex * 3 + 1];
|
||||||
|
vec4 lineSegment = vec4(fillFrom & 0xffff, fillFrom >> 16,
|
||||||
|
fillTo & 0xffff, fillTo >> 16)/ 256.0;
|
||||||
|
lineSegment -= tileFragCoord . xyxy;
|
||||||
|
coverages += computeCoverage(lineSegment . xy, lineSegment . zw, uAreaLUT);
|
||||||
|
fillIndex = int(iFills[fillIndex * 3 + 2]);
|
||||||
|
iteration ++;
|
||||||
|
} while(fillIndex >= 0 && iteration < 1024);
|
||||||
|
return coverages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ivec2 computeTileCoord(uint alphaTileIndex){
|
||||||
|
uint x = alphaTileIndex & 0xff;
|
||||||
|
uint y =(alphaTileIndex >> 8u)& 0xff +(((alphaTileIndex >> 16u)& 0xff)<< 8u);
|
||||||
|
return ivec2(16, 4)* ivec2(x, y)+ ivec2(gl_LocalInvocationID . xy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
ivec2 tileSubCoord = ivec2(gl_LocalInvocationID . xy)* ivec2(1, 4);
|
||||||
|
|
||||||
|
|
||||||
|
uint batchAlphaTileIndex =(gl_WorkGroupID . x |(gl_WorkGroupID . y << 15));
|
||||||
|
uint alphaTileIndex = batchAlphaTileIndex + uint(uAlphaTileRange . x);
|
||||||
|
if(alphaTileIndex >= uint(uAlphaTileRange . y))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint tileIndex = iAlphaTiles[batchAlphaTileIndex * 2 + 0];
|
||||||
|
if((int(iTiles[tileIndex * 4 + 2]<< 8)>> 8)< 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int fillIndex = int(iTiles[tileIndex * 4 + 1]);
|
||||||
|
int backdrop = int(iTiles[tileIndex * 4 + 3])>> 24;
|
||||||
|
|
||||||
|
|
||||||
|
vec4 coverages = vec4(backdrop);
|
||||||
|
coverages += accumulateCoverageForFillList(fillIndex, tileSubCoord);
|
||||||
|
coverages = clamp(abs(coverages), 0.0, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
int clipTileIndex = int(iAlphaTiles[batchAlphaTileIndex * 2 + 1]);
|
||||||
|
if(clipTileIndex >= 0)
|
||||||
|
coverages = min(coverages, imageLoad(uDest, computeTileCoord(clipTileIndex)));
|
||||||
|
|
||||||
|
imageStore(uDest, computeTileCoord(alphaTileIndex), coverages);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
layout(local_size_x = 64)in;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform ivec2 uFramebufferTileSize;
|
||||||
|
uniform int uColumnCount;
|
||||||
|
uniform int uFirstAlphaTileIndex;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bDrawMetadata {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly uvec4 iDrawMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bClipMetadata {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly uvec4 iClipMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2)buffer bBackdrops {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly int iBackdrops[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3)buffer bDrawTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iDrawTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 4)buffer bClipTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iClipTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 5)buffer bZBuffer {
|
||||||
|
restrict int iZBuffer[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 6)buffer bFirstTileMap {
|
||||||
|
restrict int iFirstTileMap[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 7)buffer bIndirectDrawParams {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iIndirectDrawParams[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 8)buffer bAlphaTiles {
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iAlphaTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint calculateTileIndex(uint bufferOffset, uvec4 tileRect, uvec2 tileCoord){
|
||||||
|
return bufferOffset + tileCoord . y *(tileRect . z - tileRect . x)+ tileCoord . x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
uint columnIndex = gl_GlobalInvocationID . x;
|
||||||
|
if(int(columnIndex)>= uColumnCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int currentBackdrop = iBackdrops[columnIndex * 3 + 0];
|
||||||
|
int tileX = iBackdrops[columnIndex * 3 + 1];
|
||||||
|
uint drawPathIndex = uint(iBackdrops[columnIndex * 3 + 2]);
|
||||||
|
|
||||||
|
uvec4 drawTileRect = iDrawMetadata[drawPathIndex * 3 + 0];
|
||||||
|
uvec4 drawOffsets = iDrawMetadata[drawPathIndex * 3 + 1];
|
||||||
|
uvec2 drawTileSize = drawTileRect . zw - drawTileRect . xy;
|
||||||
|
uint drawTileBufferOffset = drawOffsets . x;
|
||||||
|
bool zWrite = drawOffsets . z != 0;
|
||||||
|
|
||||||
|
int clipPathIndex = int(drawOffsets . w);
|
||||||
|
uvec4 clipTileRect = uvec4(0u), clipOffsets = uvec4(0u);
|
||||||
|
if(clipPathIndex >= 0){
|
||||||
|
clipTileRect = iClipMetadata[clipPathIndex * 2 + 0];
|
||||||
|
clipOffsets = iClipMetadata[clipPathIndex * 2 + 1];
|
||||||
|
}
|
||||||
|
uint clipTileBufferOffset = clipOffsets . x, clipBackdropOffset = clipOffsets . y;
|
||||||
|
|
||||||
|
for(uint tileY = 0;tileY < drawTileSize . y;tileY ++){
|
||||||
|
uvec2 drawTileCoord = uvec2(tileX, tileY);
|
||||||
|
uint drawTileIndex = calculateTileIndex(drawTileBufferOffset, drawTileRect, drawTileCoord);
|
||||||
|
|
||||||
|
int drawAlphaTileIndex = - 1;
|
||||||
|
int clipAlphaTileIndex = - 1;
|
||||||
|
int drawFirstFillIndex = int(iDrawTiles[drawTileIndex * 4 + 1]);
|
||||||
|
int drawBackdropDelta =
|
||||||
|
int(iDrawTiles[drawTileIndex * 4 + 2])>> 24;
|
||||||
|
uint drawTileWord = iDrawTiles[drawTileIndex * 4 + 3]& 0x00ffffff;
|
||||||
|
|
||||||
|
int drawTileBackdrop = currentBackdrop;
|
||||||
|
bool haveDrawAlphaMask = drawFirstFillIndex >= 0;
|
||||||
|
bool needNewAlphaTile = haveDrawAlphaMask;
|
||||||
|
|
||||||
|
|
||||||
|
if(clipPathIndex >= 0){
|
||||||
|
uvec2 tileCoord = drawTileCoord + drawTileRect . xy;
|
||||||
|
if(all(bvec4(greaterThanEqual(tileCoord, clipTileRect . xy),
|
||||||
|
lessThan(tileCoord, clipTileRect . zw)))){
|
||||||
|
uvec2 clipTileCoord = tileCoord - clipTileRect . xy;
|
||||||
|
uint clipTileIndex = calculateTileIndex(clipTileBufferOffset,
|
||||||
|
clipTileRect,
|
||||||
|
clipTileCoord);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int thisClipAlphaTileIndex =
|
||||||
|
int(iClipTiles[clipTileIndex * 4 +
|
||||||
|
2]<< 8)>> 8;
|
||||||
|
|
||||||
|
uint clipTileWord = iClipTiles[clipTileIndex * 4 + 3];
|
||||||
|
int clipTileBackdrop = int(clipTileWord)>> 24;
|
||||||
|
|
||||||
|
if(thisClipAlphaTileIndex >= 0){
|
||||||
|
if(haveDrawAlphaMask){
|
||||||
|
clipAlphaTileIndex = thisClipAlphaTileIndex;
|
||||||
|
needNewAlphaTile = true;
|
||||||
|
} else {
|
||||||
|
if(drawTileBackdrop != 0){
|
||||||
|
|
||||||
|
|
||||||
|
drawAlphaTileIndex = thisClipAlphaTileIndex;
|
||||||
|
clipAlphaTileIndex = - 1;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
drawAlphaTileIndex = - 1;
|
||||||
|
clipAlphaTileIndex = - 1;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(clipTileBackdrop == 0){
|
||||||
|
|
||||||
|
drawTileBackdrop = 0;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
} else {
|
||||||
|
needNewAlphaTile = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
drawTileBackdrop = 0;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(needNewAlphaTile){
|
||||||
|
uint drawBatchAlphaTileIndex = atomicAdd(iIndirectDrawParams[4], 1);
|
||||||
|
iAlphaTiles[drawBatchAlphaTileIndex * 2 + 0]= drawTileIndex;
|
||||||
|
iAlphaTiles[drawBatchAlphaTileIndex * 2 + 1]= clipAlphaTileIndex;
|
||||||
|
drawAlphaTileIndex = int(drawBatchAlphaTileIndex)+ uFirstAlphaTileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
iDrawTiles[drawTileIndex * 4 + 2]=
|
||||||
|
(uint(drawAlphaTileIndex)& 0x00ffffffu)|(uint(drawBackdropDelta)<< 24);
|
||||||
|
iDrawTiles[drawTileIndex * 4 + 3]=
|
||||||
|
drawTileWord |(uint(drawTileBackdrop)<< 24);
|
||||||
|
|
||||||
|
|
||||||
|
ivec2 tileCoord = ivec2(tileX, tileY)+ ivec2(drawTileRect . xy);
|
||||||
|
int tileMapIndex = tileCoord . y * uFramebufferTileSize . x + tileCoord . x;
|
||||||
|
if(zWrite && drawTileBackdrop != 0 && drawAlphaTileIndex < 0)
|
||||||
|
atomicMax(iZBuffer[tileMapIndex], int(drawTileIndex));
|
||||||
|
|
||||||
|
|
||||||
|
if(drawTileBackdrop != 0 || drawAlphaTileIndex >= 0){
|
||||||
|
int nextTileIndex = atomicExchange(iFirstTileMap[tileMapIndex], int(drawTileIndex));
|
||||||
|
iDrawTiles[drawTileIndex * 4 + 0]= nextTileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBackdrop += drawBackdropDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform int uTileCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bFirstTileMap {
|
||||||
|
restrict int iFirstTileMap[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2)buffer bZBuffer {
|
||||||
|
restrict readonly int iZBuffer[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(local_size_x = 64)in;
|
||||||
|
|
||||||
|
int getFirst(uint globalTileIndex){
|
||||||
|
return iFirstTileMap[globalTileIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNextTile(int tileIndex){
|
||||||
|
return int(iTiles[tileIndex * 4 + 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNextTile(int tileIndex, int newNextTileIndex){
|
||||||
|
iTiles[tileIndex * 4 + 0]= uint(newNextTileIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
uint globalTileIndex = gl_GlobalInvocationID . x;
|
||||||
|
if(globalTileIndex >= uint(uTileCount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int zValue = iZBuffer[globalTileIndex];
|
||||||
|
|
||||||
|
int unsortedFirstTileIndex = getFirst(globalTileIndex);
|
||||||
|
int sortedFirstTileIndex = - 1;
|
||||||
|
|
||||||
|
while(unsortedFirstTileIndex >= 0){
|
||||||
|
int currentTileIndex = unsortedFirstTileIndex;
|
||||||
|
unsortedFirstTileIndex = getNextTile(currentTileIndex);
|
||||||
|
|
||||||
|
if(currentTileIndex >= zValue){
|
||||||
|
int prevTrialTileIndex = - 1;
|
||||||
|
int trialTileIndex = sortedFirstTileIndex;
|
||||||
|
while(true){
|
||||||
|
if(trialTileIndex < 0 || currentTileIndex < trialTileIndex){
|
||||||
|
if(prevTrialTileIndex < 0){
|
||||||
|
setNextTile(currentTileIndex, sortedFirstTileIndex);
|
||||||
|
sortedFirstTileIndex = currentTileIndex;
|
||||||
|
} else {
|
||||||
|
setNextTile(currentTileIndex, trialTileIndex);
|
||||||
|
setNextTile(prevTrialTileIndex, currentTileIndex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevTrialTileIndex = trialTileIndex;
|
||||||
|
trialTileIndex = getNextTile(trialTileIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iFirstTileMap[globalTileIndex]= sortedFirstTileIndex;
|
||||||
|
}
|
||||||
|
|
|
@ -15,48 +15,13 @@
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
precision highp sampler2D;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
layout(local_size_x = 16, local_size_y = 4)in;
|
layout(local_size_x = 16, local_size_y = 4)in;
|
||||||
|
|
||||||
layout(rgba8)uniform image2D uDestImage;
|
|
||||||
uniform sampler2D uTextureMetadata;
|
|
||||||
uniform ivec2 uTextureMetadataSize;
|
|
||||||
uniform sampler2D uColorTexture0;
|
|
||||||
uniform sampler2D uMaskTexture0;
|
|
||||||
uniform sampler2D uGammaLUT;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
uniform vec4 uFilterParams0;
|
|
||||||
uniform vec4 uFilterParams1;
|
|
||||||
uniform vec4 uFilterParams2;
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform vec2 uColorTextureSize0;
|
|
||||||
uniform int uCtrl;
|
|
||||||
uniform sampler2D uAreaLUT;
|
|
||||||
|
|
||||||
layout(std430, binding = 0)buffer bFills {
|
|
||||||
restrict readonly uvec2 iFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 1)buffer bNextFills {
|
|
||||||
restrict readonly int iNextFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 2)buffer bFillTileMap {
|
|
||||||
restrict readonly int iFillTileMap[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 3)buffer bTiles {
|
|
||||||
restrict readonly uint iTiles[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 4)buffer bNextTiles {
|
|
||||||
restrict readonly int iNextTiles[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 5)buffer bFirstTiles {
|
|
||||||
restrict readonly int iFirstTiles[];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,23 +34,6 @@ layout(std430, binding = 5)buffer bFirstTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
|
|
||||||
|
|
||||||
vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from;
|
|
||||||
|
|
||||||
|
|
||||||
vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5);
|
|
||||||
float offset = mix(window . x, window . y, 0.5)- left . x;
|
|
||||||
float t = offset /(right . x - left . x);
|
|
||||||
|
|
||||||
|
|
||||||
float y = mix(left . y, right . y, t);
|
|
||||||
float d =(right . y - left . y)/(right . x - left . x);
|
|
||||||
|
|
||||||
|
|
||||||
float dX = window . x - window . y;
|
|
||||||
return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,41 +46,6 @@ vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT);
|
|
||||||
|
|
||||||
ivec2 calculateTileOrigin(uint tileIndex){
|
|
||||||
return ivec2(tileIndex & 0xff,(tileIndex >> 8u)& 0xff)* 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 calculateFillAlpha(ivec2 tileSubCoord, uint tileIndex){
|
|
||||||
int fillIndex = iFillTileMap[tileIndex];
|
|
||||||
if(fillIndex < 0)
|
|
||||||
return vec4(0.0);
|
|
||||||
|
|
||||||
vec4 coverages = vec4(0.0);
|
|
||||||
do {
|
|
||||||
uvec2 fill = iFills[fillIndex];
|
|
||||||
vec2 from = vec2(fill . y & 0xf,(fill . y >> 4u)& 0xf)+
|
|
||||||
vec2(fill . x & 0xff,(fill . x >> 8u)& 0xff)/ 256.0;
|
|
||||||
vec2 to = vec2((fill . y >> 8u)& 0xf,(fill . y >> 12u)& 0xf)+
|
|
||||||
vec2((fill . x >> 16u)& 0xff,(fill . x >> 24u)& 0xff)/ 256.0;
|
|
||||||
|
|
||||||
coverages += computeCoverage(from -(vec2(tileSubCoord)+ vec2(0.5)),
|
|
||||||
to -(vec2(tileSubCoord)+ vec2(0.5)),
|
|
||||||
uAreaLUT);
|
|
||||||
|
|
||||||
fillIndex = iNextFills[fillIndex];
|
|
||||||
} while(fillIndex >= 0);
|
|
||||||
|
|
||||||
return coverages;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -648,11 +561,27 @@ float sampleMask(float maskAlpha,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 calculateColorWithMaskAlpha(float maskAlpha,
|
vec4 calculateColor(vec2 fragCoord,
|
||||||
vec4 baseColor,
|
sampler2D colorTexture0,
|
||||||
|
sampler2D maskTexture0,
|
||||||
|
sampler2D destTexture,
|
||||||
|
sampler2D gammaLUT,
|
||||||
|
vec2 colorTextureSize0,
|
||||||
|
vec2 maskTextureSize0,
|
||||||
|
vec4 filterParams0,
|
||||||
|
vec4 filterParams1,
|
||||||
|
vec4 filterParams2,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
int ctrl,
|
||||||
|
vec3 maskTexCoord0,
|
||||||
vec2 colorTexCoord0,
|
vec2 colorTexCoord0,
|
||||||
vec2 fragCoord,
|
vec4 baseColor,
|
||||||
int ctrl){
|
int tileCtrl){
|
||||||
|
|
||||||
|
int maskCtrl0 =(tileCtrl >> 0)& 0x3;
|
||||||
|
float maskAlpha = 1.0;
|
||||||
|
maskAlpha = sampleMask(maskAlpha, maskTexture0, maskTextureSize0, maskTexCoord0, maskCtrl0);
|
||||||
|
|
||||||
|
|
||||||
vec4 color = baseColor;
|
vec4 color = baseColor;
|
||||||
int color0Combine =(ctrl >> 6)&
|
int color0Combine =(ctrl >> 6)&
|
||||||
|
@ -660,14 +589,14 @@ vec4 calculateColorWithMaskAlpha(float maskAlpha,
|
||||||
if(color0Combine != 0){
|
if(color0Combine != 0){
|
||||||
int color0Filter =(ctrl >> 4)& 0x3;
|
int color0Filter =(ctrl >> 4)& 0x3;
|
||||||
vec4 color0 = filterColor(colorTexCoord0,
|
vec4 color0 = filterColor(colorTexCoord0,
|
||||||
uColorTexture0,
|
colorTexture0,
|
||||||
uGammaLUT,
|
gammaLUT,
|
||||||
uColorTextureSize0,
|
colorTextureSize0,
|
||||||
fragCoord,
|
fragCoord,
|
||||||
uFramebufferSize,
|
framebufferSize,
|
||||||
uFilterParams0,
|
filterParams0,
|
||||||
uFilterParams1,
|
filterParams1,
|
||||||
uFilterParams2,
|
filterParams2,
|
||||||
color0Filter);
|
color0Filter);
|
||||||
color = combineColor0(color, color0, color0Combine);
|
color = combineColor0(color, color0, color0Combine);
|
||||||
}
|
}
|
||||||
|
@ -676,11 +605,8 @@ vec4 calculateColorWithMaskAlpha(float maskAlpha,
|
||||||
color . a *= maskAlpha;
|
color . a *= maskAlpha;
|
||||||
|
|
||||||
|
|
||||||
|
int compositeOp =(ctrl >> 8)& 0xf;
|
||||||
|
color = composite(color, destTexture, framebufferSize, fragCoord, compositeOp);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
color . rgb *= color . a;
|
color . rgb *= color . a;
|
||||||
|
@ -698,85 +624,168 @@ vec4 calculateColorWithMaskAlpha(float maskAlpha,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void lookupTextureMetadata(int color,
|
vec4 fetchUnscaled(sampler2D srcTexture, vec2 scale, vec2 originCoord, int entry){
|
||||||
out mat2 outColorTexMatrix0,
|
return texture(srcTexture,(originCoord + vec2(0.5)+ vec2(entry, 0))* scale);
|
||||||
out vec4 outColorTexOffsets,
|
}
|
||||||
out vec4 outBaseColor){
|
|
||||||
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
|
void computeTileVaryings(vec2 position,
|
||||||
vec2 metadataEntryCoord = vec2(color % 128 * 4, color / 128);
|
int colorEntry,
|
||||||
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
|
sampler2D textureMetadata,
|
||||||
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
|
ivec2 textureMetadataSize,
|
||||||
vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale;
|
out vec2 outColorTexCoord0,
|
||||||
outColorTexMatrix0 = mat2(texture(uTextureMetadata, colorTexMatrix0Coord));
|
out vec4 outBaseColor,
|
||||||
outColorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
|
out vec4 outFilterParams0,
|
||||||
outBaseColor = texture(uTextureMetadata, baseColorCoord);
|
out vec4 outFilterParams1,
|
||||||
|
out vec4 outFilterParams2,
|
||||||
|
out int outCtrl){
|
||||||
|
vec2 metadataScale = vec2(1.0)/ vec2(textureMetadataSize);
|
||||||
|
vec2 metadataEntryCoord = vec2(colorEntry % 128 * 8, colorEntry / 128);
|
||||||
|
vec4 colorTexMatrix0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 0);
|
||||||
|
vec4 colorTexOffsets = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 1);
|
||||||
|
vec4 baseColor = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 2);
|
||||||
|
vec4 filterParams0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 3);
|
||||||
|
vec4 filterParams1 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 4);
|
||||||
|
vec4 filterParams2 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 5);
|
||||||
|
vec4 extra = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 6);
|
||||||
|
outColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
|
||||||
|
outBaseColor = baseColor;
|
||||||
|
outFilterParams0 = filterParams0;
|
||||||
|
outFilterParams1 = filterParams1;
|
||||||
|
outFilterParams2 = filterParams2;
|
||||||
|
outCtrl = int(extra . x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform int uLoadAction;
|
||||||
|
uniform vec4 uClearColor;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
uniform sampler2D uTextureMetadata;
|
||||||
|
uniform ivec2 uTextureMetadataSize;
|
||||||
|
uniform sampler2D uZBuffer;
|
||||||
|
uniform ivec2 uZBufferSize;
|
||||||
|
uniform sampler2D uColorTexture0;
|
||||||
|
uniform sampler2D uMaskTexture0;
|
||||||
|
uniform sampler2D uDestTexture;
|
||||||
|
uniform sampler2D uGammaLUT;
|
||||||
|
uniform vec2 uColorTextureSize0;
|
||||||
|
uniform vec2 uMaskTextureSize0;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
uniform ivec2 uFramebufferTileSize;
|
||||||
|
layout(rgba8)uniform image2D uDestImage;
|
||||||
|
|
||||||
|
layout(std430, binding = 0)buffer bTiles {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
restrict readonly uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1)buffer bFirstTileMap {
|
||||||
|
restrict readonly int iFirstTileMap[];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint calculateTileIndex(uint bufferOffset, uvec4 tileRect, uvec2 tileCoord){
|
||||||
|
return bufferOffset + tileCoord . y *(tileRect . z - tileRect . x)+ tileCoord . x;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec2 toImageCoords(ivec2 coords){
|
||||||
|
return ivec2(coords . x, uFramebufferSize . y - coords . y);
|
||||||
|
}
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
int maskCtrl0 =(uCtrl >> 0)& 0x1;
|
ivec2 tileCoord = ivec2(gl_WorkGroupID . xy);
|
||||||
|
ivec2 firstTileSubCoord = ivec2(gl_LocalInvocationID . xy)* ivec2(1, 4);
|
||||||
|
ivec2 firstFragCoord = tileCoord * ivec2(uTileSize)+ firstTileSubCoord;
|
||||||
|
|
||||||
vec4 colors[4]= { vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)};
|
|
||||||
ivec2 tileSubCoord = ivec2(gl_LocalInvocationID . xy)* ivec2(1, 4);
|
|
||||||
ivec2 tileOrigin = ivec2(0);
|
|
||||||
|
|
||||||
int tileIndex = iFirstTiles[gl_WorkGroupID . z];
|
int tileIndex = iFirstTileMap[tileCoord . x + uFramebufferTileSize . x * tileCoord . y];
|
||||||
int overlapCount = 0;
|
if(tileIndex < 0 && uLoadAction != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mat4 destColors;
|
||||||
|
for(int subY = 0;subY < 4;subY ++){
|
||||||
|
if(uLoadAction == 0){
|
||||||
|
destColors[subY]= uClearColor;
|
||||||
|
} else {
|
||||||
|
ivec2 imageCoords = toImageCoords(firstFragCoord + ivec2(0, subY));
|
||||||
|
destColors[subY]= imageLoad(uDestImage, imageCoords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while(tileIndex >= 0){
|
while(tileIndex >= 0){
|
||||||
overlapCount ++;
|
for(int subY = 0;subY < 4;subY ++){
|
||||||
|
ivec2 tileSubCoord = firstTileSubCoord + ivec2(0, subY);
|
||||||
|
vec2 fragCoord = vec2(firstFragCoord + ivec2(0, subY))+ vec2(0.5);
|
||||||
|
|
||||||
uint tileCoord = iTiles[tileIndex * 3 + 0];
|
int alphaTileIndex =
|
||||||
uint maskTexCoord = iTiles[tileIndex * 3 + 1];
|
int(iTiles[tileIndex * 4 + 2]<< 8)>> 8;
|
||||||
uint colorCtrl = iTiles[tileIndex * 3 + 2];
|
uint tileControlWord = iTiles[tileIndex * 4 + 3];
|
||||||
|
uint colorEntry = tileControlWord & 0xffff;
|
||||||
|
int tileCtrl = int((tileControlWord >> 16)& 0xff);
|
||||||
|
|
||||||
tileOrigin = ivec2(int(tileCoord & 0xffff), int(tileCoord >> 16));
|
int backdrop;
|
||||||
|
uvec2 maskTileCoord;
|
||||||
|
if(alphaTileIndex >= 0){
|
||||||
|
backdrop = 0;
|
||||||
|
maskTileCoord = uvec2(alphaTileIndex & 0xff, alphaTileIndex >> 8)*
|
||||||
|
uvec2(uTileSize);
|
||||||
|
} else {
|
||||||
|
|
||||||
int ctrl = int(uCtrl);
|
backdrop = int(tileControlWord)>> 24;
|
||||||
int tileColor = int(colorCtrl & 0xffff);
|
maskTileCoord = uvec2(0u);
|
||||||
int tileCtrl = int(colorCtrl >> 16);
|
tileCtrl &= ~(0x3 << 0);
|
||||||
|
|
||||||
mat2 colorTexMatrix0;
|
|
||||||
vec4 colorTexOffsets;
|
|
||||||
vec4 baseColor;
|
|
||||||
lookupTextureMetadata(tileColor, colorTexMatrix0, colorTexOffsets, baseColor);
|
|
||||||
|
|
||||||
int maskTileCtrl0 =(tileCtrl >> 0)& 0x3;
|
|
||||||
|
|
||||||
vec4 maskAlphas = vec4(1.0);
|
|
||||||
if(maskCtrl0 != 0 && maskTileCtrl0 != 0){
|
|
||||||
uint maskTileIndex0 = maskTexCoord & 0xffff;
|
|
||||||
int maskTileBackdrop0 = int(maskTexCoord << 8)>> 24;
|
|
||||||
maskAlphas = clamp(abs(calculateFillAlpha(tileSubCoord, maskTileIndex0)+
|
|
||||||
float(maskTileBackdrop0)), 0.0, 1.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int yOffset = 0;yOffset < 4;yOffset ++){
|
vec3 maskTexCoord0 = vec3(vec2(ivec2(maskTileCoord)+ tileSubCoord), backdrop);
|
||||||
|
|
||||||
ivec2 fragCoordI = tileOrigin * ivec2(uTileSize)+ tileSubCoord + ivec2(0, yOffset);
|
vec2 colorTexCoord0;
|
||||||
vec2 fragCoord = vec2(fragCoordI)+ vec2(0.5);
|
vec4 baseColor, filterParams0, filterParams1, filterParams2;
|
||||||
vec2 colorTexCoord0 = colorTexMatrix0 * fragCoord + colorTexOffsets . xy;
|
int ctrl;
|
||||||
vec4 color = calculateColorWithMaskAlpha(maskAlphas[yOffset],
|
computeTileVaryings(fragCoord,
|
||||||
baseColor,
|
int(colorEntry),
|
||||||
|
uTextureMetadata,
|
||||||
|
uTextureMetadataSize,
|
||||||
colorTexCoord0,
|
colorTexCoord0,
|
||||||
fragCoord,
|
baseColor,
|
||||||
|
filterParams0,
|
||||||
|
filterParams1,
|
||||||
|
filterParams2,
|
||||||
ctrl);
|
ctrl);
|
||||||
colors[yOffset]= colors[yOffset]*(1.0 - color . a)+ color;
|
|
||||||
|
vec4 srcColor = calculateColor(fragCoord,
|
||||||
|
uColorTexture0,
|
||||||
|
uMaskTexture0,
|
||||||
|
uDestTexture,
|
||||||
|
uGammaLUT,
|
||||||
|
uColorTextureSize0,
|
||||||
|
uMaskTextureSize0,
|
||||||
|
filterParams0,
|
||||||
|
filterParams1,
|
||||||
|
filterParams2,
|
||||||
|
uFramebufferSize,
|
||||||
|
ctrl,
|
||||||
|
maskTexCoord0,
|
||||||
|
colorTexCoord0,
|
||||||
|
baseColor,
|
||||||
|
tileCtrl);
|
||||||
|
|
||||||
|
destColors[subY]= destColors[subY]*(1.0 - srcColor . a)+ srcColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
tileIndex = iNextTiles[tileIndex];
|
tileIndex = int(iTiles[tileIndex * 4 + 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int yOffset = 0;yOffset < 4;yOffset ++){
|
for(int subY = 0;subY < 4;subY ++)
|
||||||
ivec2 fragCoord = tileOrigin * ivec2(uTileSize)+ tileSubCoord + ivec2(0, yOffset);
|
imageStore(uDestImage, toImageCoords(firstFragCoord + ivec2(0, subY)), destColors[subY]);
|
||||||
|
|
||||||
|
|
||||||
vec4 color = colors[yOffset];
|
|
||||||
if(color . a < 1.0)
|
|
||||||
color = imageLoad(uDestImage, fragCoord)*(1.0 - color . a)+ color;
|
|
||||||
imageStore(uDestImage, fragCoord, color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
|
||||||
|
in uvec2 aTessCoord;
|
||||||
|
in uvec4 aLineSegment;
|
||||||
|
in int aTileIndex;
|
||||||
|
|
||||||
|
out vec2 vFrom;
|
||||||
|
out vec2 vTo;
|
||||||
|
|
||||||
|
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth, vec2 tileSize){
|
||||||
|
uint tilesPerRow = uint(stencilTextureWidth / tileSize . x);
|
||||||
|
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
||||||
|
return vec2(tileOffset)* tileSize * vec2(1.0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 computeVertexPosition(uint tileIndex,
|
||||||
|
uvec2 tessCoord,
|
||||||
|
uvec4 packedLineSegment,
|
||||||
|
vec2 tileSize,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
out vec2 outFrom,
|
||||||
|
out vec2 outTo){
|
||||||
|
vec2 tileOrigin = computeTileOffset(uint(tileIndex), framebufferSize . x, tileSize);
|
||||||
|
|
||||||
|
vec4 lineSegment = vec4(packedLineSegment)/ 256.0;
|
||||||
|
vec2 from = lineSegment . xy, to = lineSegment . zw;
|
||||||
|
|
||||||
|
vec2 position;
|
||||||
|
if(tessCoord . x == 0u)
|
||||||
|
position . x = floor(min(from . x, to . x));
|
||||||
|
else
|
||||||
|
position . x = ceil(max(from . x, to . x));
|
||||||
|
if(tessCoord . y == 0u)
|
||||||
|
position . y = floor(min(from . y, to . y));
|
||||||
|
else
|
||||||
|
position . y = tileSize . y;
|
||||||
|
position . y = floor(position . y * 0.25);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec2 offset = vec2(0.0, 1.5)- position * vec2(1.0, 4.0);
|
||||||
|
outFrom = from + offset;
|
||||||
|
outTo = to + offset;
|
||||||
|
|
||||||
|
vec2 globalPosition =(tileOrigin + position)/ framebufferSize * 2.0 - 1.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return vec4(globalPosition, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
gl_Position = computeVertexPosition(uint(aTileIndex),
|
||||||
|
aTessCoord,
|
||||||
|
aLineSegment,
|
||||||
|
uTileSize,
|
||||||
|
uFramebufferSize,
|
||||||
|
vFrom,
|
||||||
|
vTo);
|
||||||
|
}
|
||||||
|
|
|
@ -12,27 +12,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
@ -83,24 +62,37 @@ precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform sampler2D uColorTexture0;
|
|
||||||
uniform sampler2D uMaskTexture0;
|
|
||||||
uniform sampler2D uDestTexture;
|
|
||||||
uniform sampler2D uGammaLUT;
|
|
||||||
uniform vec2 uColorTextureSize0;
|
|
||||||
uniform vec2 uMaskTextureSize0;
|
|
||||||
uniform vec4 uFilterParams0;
|
|
||||||
uniform vec4 uFilterParams1;
|
|
||||||
uniform vec4 uFilterParams2;
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform int uCtrl;
|
|
||||||
|
|
||||||
in vec3 vMaskTexCoord0;
|
|
||||||
in vec2 vColorTexCoord0;
|
|
||||||
in vec4 vBaseColor;
|
|
||||||
in float vTileCtrl;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -567,27 +559,42 @@ float sampleMask(float maskAlpha,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void calculateColor(int tileCtrl, int ctrl){
|
vec4 calculateColor(vec2 fragCoord,
|
||||||
|
sampler2D colorTexture0,
|
||||||
|
sampler2D maskTexture0,
|
||||||
|
sampler2D destTexture,
|
||||||
|
sampler2D gammaLUT,
|
||||||
|
vec2 colorTextureSize0,
|
||||||
|
vec2 maskTextureSize0,
|
||||||
|
vec4 filterParams0,
|
||||||
|
vec4 filterParams1,
|
||||||
|
vec4 filterParams2,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
int ctrl,
|
||||||
|
vec3 maskTexCoord0,
|
||||||
|
vec2 colorTexCoord0,
|
||||||
|
vec4 baseColor,
|
||||||
|
int tileCtrl){
|
||||||
|
|
||||||
int maskCtrl0 =(tileCtrl >> 0)& 0x3;
|
int maskCtrl0 =(tileCtrl >> 0)& 0x3;
|
||||||
float maskAlpha = 1.0;
|
float maskAlpha = 1.0;
|
||||||
maskAlpha = sampleMask(maskAlpha, uMaskTexture0, uMaskTextureSize0, vMaskTexCoord0, maskCtrl0);
|
maskAlpha = sampleMask(maskAlpha, maskTexture0, maskTextureSize0, maskTexCoord0, maskCtrl0);
|
||||||
|
|
||||||
|
|
||||||
vec4 color = vBaseColor;
|
vec4 color = baseColor;
|
||||||
int color0Combine =(ctrl >> 6)&
|
int color0Combine =(ctrl >> 6)&
|
||||||
0x3;
|
0x3;
|
||||||
if(color0Combine != 0){
|
if(color0Combine != 0){
|
||||||
int color0Filter =(ctrl >> 4)& 0x3;
|
int color0Filter =(ctrl >> 4)& 0x3;
|
||||||
vec4 color0 = filterColor(vColorTexCoord0,
|
vec4 color0 = filterColor(colorTexCoord0,
|
||||||
uColorTexture0,
|
colorTexture0,
|
||||||
uGammaLUT,
|
gammaLUT,
|
||||||
uColorTextureSize0,
|
colorTextureSize0,
|
||||||
gl_FragCoord . xy,
|
fragCoord,
|
||||||
uFramebufferSize,
|
framebufferSize,
|
||||||
uFilterParams0,
|
filterParams0,
|
||||||
uFilterParams1,
|
filterParams1,
|
||||||
uFilterParams2,
|
filterParams2,
|
||||||
color0Filter);
|
color0Filter);
|
||||||
color = combineColor0(color, color0, color0Combine);
|
color = combineColor0(color, color0, color0Combine);
|
||||||
}
|
}
|
||||||
|
@ -597,18 +604,53 @@ void calculateColor(int tileCtrl, int ctrl){
|
||||||
|
|
||||||
|
|
||||||
int compositeOp =(ctrl >> 8)& 0xf;
|
int compositeOp =(ctrl >> 8)& 0xf;
|
||||||
color = composite(color, uDestTexture, uFramebufferSize, gl_FragCoord . xy, compositeOp);
|
color = composite(color, destTexture, framebufferSize, fragCoord, compositeOp);
|
||||||
|
|
||||||
|
|
||||||
color . rgb *= color . a;
|
color . rgb *= color . a;
|
||||||
oFragColor = color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uniform sampler2D uColorTexture0;
|
||||||
|
uniform sampler2D uMaskTexture0;
|
||||||
|
uniform sampler2D uDestTexture;
|
||||||
|
uniform sampler2D uGammaLUT;
|
||||||
|
uniform vec2 uColorTextureSize0;
|
||||||
|
uniform vec2 uMaskTextureSize0;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in vec3 vMaskTexCoord0;
|
||||||
|
in vec2 vColorTexCoord0;
|
||||||
|
in vec4 vBaseColor;
|
||||||
|
in float vTileCtrl;
|
||||||
|
in vec4 vFilterParams0;
|
||||||
|
in vec4 vFilterParams1;
|
||||||
|
in vec4 vFilterParams2;
|
||||||
|
in float vCtrl;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
calculateColor(int(vTileCtrl), uCtrl);
|
oFragColor = calculateColor(gl_FragCoord . xy,
|
||||||
|
uColorTexture0,
|
||||||
|
uMaskTexture0,
|
||||||
|
uDestTexture,
|
||||||
|
uGammaLUT,
|
||||||
|
uColorTextureSize0,
|
||||||
|
uMaskTextureSize0,
|
||||||
|
vFilterParams0,
|
||||||
|
vFilterParams1,
|
||||||
|
vFilterParams2,
|
||||||
|
uFramebufferSize,
|
||||||
|
int(vCtrl),
|
||||||
|
vMaskTexCoord0,
|
||||||
|
vColorTexCoord0,
|
||||||
|
vBaseColor,
|
||||||
|
int(vTileCtrl));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 fetchUnscaled(sampler2D srcTexture, vec2 scale, vec2 originCoord, int entry){
|
||||||
|
return texture(srcTexture,(originCoord + vec2(0.5)+ vec2(entry, 0))* scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeTileVaryings(vec2 position,
|
||||||
|
int colorEntry,
|
||||||
|
sampler2D textureMetadata,
|
||||||
|
ivec2 textureMetadataSize,
|
||||||
|
out vec2 outColorTexCoord0,
|
||||||
|
out vec4 outBaseColor,
|
||||||
|
out vec4 outFilterParams0,
|
||||||
|
out vec4 outFilterParams1,
|
||||||
|
out vec4 outFilterParams2,
|
||||||
|
out int outCtrl){
|
||||||
|
vec2 metadataScale = vec2(1.0)/ vec2(textureMetadataSize);
|
||||||
|
vec2 metadataEntryCoord = vec2(colorEntry % 128 * 8, colorEntry / 128);
|
||||||
|
vec4 colorTexMatrix0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 0);
|
||||||
|
vec4 colorTexOffsets = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 1);
|
||||||
|
vec4 baseColor = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 2);
|
||||||
|
vec4 filterParams0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 3);
|
||||||
|
vec4 filterParams1 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 4);
|
||||||
|
vec4 filterParams2 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 5);
|
||||||
|
vec4 extra = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 6);
|
||||||
|
outColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
|
||||||
|
outBaseColor = baseColor;
|
||||||
|
outFilterParams0 = filterParams0;
|
||||||
|
outFilterParams1 = filterParams1;
|
||||||
|
outFilterParams2 = filterParams2;
|
||||||
|
outCtrl = int(extra . x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uniform mat4 uTransform;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
uniform sampler2D uTextureMetadata;
|
||||||
|
uniform ivec2 uTextureMetadataSize;
|
||||||
|
uniform sampler2D uZBuffer;
|
||||||
|
uniform ivec2 uZBufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in ivec2 aTileOrigin;
|
||||||
|
in uvec4 aMaskTexCoord0;
|
||||||
|
in ivec2 aCtrlBackdrop;
|
||||||
|
in int aPathIndex;
|
||||||
|
in int aColor;
|
||||||
|
|
||||||
|
out vec3 vMaskTexCoord0;
|
||||||
|
out vec2 vColorTexCoord0;
|
||||||
|
out vec4 vBaseColor;
|
||||||
|
out float vTileCtrl;
|
||||||
|
out vec4 vFilterParams0;
|
||||||
|
out vec4 vFilterParams1;
|
||||||
|
out vec4 vFilterParams2;
|
||||||
|
out float vCtrl;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
||||||
|
vec2 position =(tileOrigin + tileOffset)* uTileSize;
|
||||||
|
|
||||||
|
ivec4 zValue = ivec4(texture(uZBuffer,(tileOrigin + vec2(0.5))/ vec2(uZBufferSize))* 255.0);
|
||||||
|
if(aPathIndex <(zValue . x |(zValue . y << 8)|(zValue . z << 16)|(zValue . w << 24))){
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uvec2 maskTileCoord = uvec2(aMaskTexCoord0 . x, aMaskTexCoord0 . y + 256u * aMaskTexCoord0 . z);
|
||||||
|
vec2 maskTexCoord0 =(vec2(maskTileCoord)+ tileOffset)* uTileSize;
|
||||||
|
if(aCtrlBackdrop . y == 0 && aMaskTexCoord0 . w != 0u){
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctrl;
|
||||||
|
computeTileVaryings(position,
|
||||||
|
aColor,
|
||||||
|
uTextureMetadata,
|
||||||
|
uTextureMetadataSize,
|
||||||
|
vColorTexCoord0,
|
||||||
|
vBaseColor,
|
||||||
|
vFilterParams0,
|
||||||
|
vFilterParams1,
|
||||||
|
vFilterParams2,
|
||||||
|
ctrl);
|
||||||
|
|
||||||
|
vTileCtrl = float(aCtrlBackdrop . x);
|
||||||
|
vCtrl = float(ctrl);
|
||||||
|
vMaskTexCoord0 = vec3(maskTexCoord0, float(aCtrlBackdrop . y));
|
||||||
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
|
in vec2 vTexCoord0;
|
||||||
|
in float vBackdrop0;
|
||||||
|
in vec2 vTexCoord1;
|
||||||
|
in float vBackdrop1;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
oFragColor = min(abs(texture(uSrc, vTexCoord0)+ vBackdrop0),
|
||||||
|
abs(texture(uSrc, vTexCoord1)+ vBackdrop1));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in int aDestTileIndex;
|
||||||
|
in int aDestBackdrop;
|
||||||
|
in int aSrcTileIndex;
|
||||||
|
in int aSrcBackdrop;
|
||||||
|
|
||||||
|
out vec2 vTexCoord0;
|
||||||
|
out float vBackdrop0;
|
||||||
|
out vec2 vTexCoord1;
|
||||||
|
out float vBackdrop1;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 destPosition = vec2(ivec2(aDestTileIndex % 256, aDestTileIndex / 256)+ aTileOffset);
|
||||||
|
vec2 srcPosition = vec2(ivec2(aSrcTileIndex % 256, aSrcTileIndex / 256)+ aTileOffset);
|
||||||
|
destPosition *= vec2(16.0, 4.0)/ uFramebufferSize;
|
||||||
|
srcPosition *= vec2(16.0, 4.0)/ uFramebufferSize;
|
||||||
|
|
||||||
|
vTexCoord0 = destPosition;
|
||||||
|
vTexCoord1 = srcPosition;
|
||||||
|
|
||||||
|
vBackdrop0 = float(aDestBackdrop);
|
||||||
|
vBackdrop1 = float(aSrcBackdrop);
|
||||||
|
|
||||||
|
if(aDestTileIndex < 0)
|
||||||
|
destPosition = vec2(0.0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), destPosition), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -21,11 +21,10 @@ precision highp float;
|
||||||
uniform sampler2D uSrc;
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
in float vBackdrop;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
oFragColor = clamp(abs(texture(uSrc, vTexCoord)+ vBackdrop), 0.0, 1.0);
|
oFragColor = texture(uSrc, vTexCoord);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#version {{version}}
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in int aTileIndex;
|
||||||
|
|
||||||
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec2 position = vec2(ivec2(aTileIndex % 256, aTileIndex / 256)+ aTileOffset);
|
||||||
|
position *= vec2(16.0, 4.0)/ uFramebufferSize;
|
||||||
|
|
||||||
|
vTexCoord = position;
|
||||||
|
|
||||||
|
if(aTileIndex < 0)
|
||||||
|
position = vec2(0.0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), position), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
|
|
||||||
|
|
||||||
vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from;
|
|
||||||
|
|
||||||
|
|
||||||
vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5);
|
|
||||||
float offset = mix(window . x, window . y, 0.5)- left . x;
|
|
||||||
float t = offset /(right . x - left . x);
|
|
||||||
|
|
||||||
|
|
||||||
float y = mix(left . y, right . y, t);
|
|
||||||
float d =(right . y - left . y)/(right . x - left . x);
|
|
||||||
|
|
||||||
|
|
||||||
float dX = window . x - window . y;
|
|
||||||
return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
layout(local_size_x = 16, local_size_y = 4)in;
|
|
||||||
|
|
||||||
uniform writeonly image2D uDest;
|
|
||||||
uniform sampler2D uAreaLUT;
|
|
||||||
uniform int uFirstTileIndex;
|
|
||||||
|
|
||||||
layout(std430, binding = 0)buffer bFills {
|
|
||||||
restrict readonly uvec2 iFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 1)buffer bNextFills {
|
|
||||||
restrict readonly int iNextFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 2)buffer bFillTileMap {
|
|
||||||
restrict readonly int iFillTileMap[];
|
|
||||||
};
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
ivec2 tileSubCoord = ivec2(gl_LocalInvocationID . xy)* ivec2(1, 4);
|
|
||||||
uint tileIndexOffset = gl_WorkGroupID . z;
|
|
||||||
|
|
||||||
uint tileIndex = tileIndexOffset + uint(uFirstTileIndex);
|
|
||||||
|
|
||||||
int fillIndex = iFillTileMap[tileIndex];
|
|
||||||
if(fillIndex < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vec4 coverages = vec4(0.0);
|
|
||||||
do {
|
|
||||||
uvec2 fill = iFills[fillIndex];
|
|
||||||
vec2 from = vec2(fill . y & 0xf,(fill . y >> 4u)& 0xf)+
|
|
||||||
vec2(fill . x & 0xff,(fill . x >> 8u)& 0xff)/ 256.0;
|
|
||||||
vec2 to = vec2((fill . y >> 8u)& 0xf,(fill . y >> 12u)& 0xf)+
|
|
||||||
vec2((fill . x >> 16u)& 0xff,(fill . x >> 24u)& 0xff)/ 256.0;
|
|
||||||
|
|
||||||
coverages += computeCoverage(from -(vec2(tileSubCoord)+ vec2(0.5)),
|
|
||||||
to -(vec2(tileSubCoord)+ vec2(0.5)),
|
|
||||||
uAreaLUT);
|
|
||||||
|
|
||||||
fillIndex = iNextFills[fillIndex];
|
|
||||||
} while(fillIndex >= 0);
|
|
||||||
|
|
||||||
ivec2 tileOrigin = ivec2(tileIndex & 0xff,(tileIndex >> 8u)& 0xff)* ivec2(16, 4);
|
|
||||||
ivec2 destCoord = tileOrigin + ivec2(gl_LocalInvocationID . xy);
|
|
||||||
imageStore(uDest, destCoord, coverages);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
|
||||||
in uint aFromPx;
|
|
||||||
in uint aToPx;
|
|
||||||
in vec2 aFromSubpx;
|
|
||||||
in vec2 aToSubpx;
|
|
||||||
in uint aTileIndex;
|
|
||||||
|
|
||||||
out vec2 vFrom;
|
|
||||||
out vec2 vTo;
|
|
||||||
|
|
||||||
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
|
|
||||||
uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x);
|
|
||||||
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
|
||||||
return vec2(tileOffset)* uTileSize * vec2(1.0, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 tileOrigin = computeTileOffset(aTileIndex, uFramebufferSize . x);
|
|
||||||
|
|
||||||
vec2 from = vec2(aFromPx & 15u, aFromPx >> 4u)+ aFromSubpx;
|
|
||||||
vec2 to = vec2(aToPx & 15u, aToPx >> 4u)+ aToSubpx;
|
|
||||||
|
|
||||||
vec2 position;
|
|
||||||
if(aTessCoord . x == 0u)
|
|
||||||
position . x = floor(min(from . x, to . x));
|
|
||||||
else
|
|
||||||
position . x = ceil(max(from . x, to . x));
|
|
||||||
if(aTessCoord . y == 0u)
|
|
||||||
position . y = floor(min(from . y, to . y));
|
|
||||||
else
|
|
||||||
position . y = uTileSize . y;
|
|
||||||
position . y = floor(position . y * 0.25);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec2 offset = vec2(0.0, 1.5)- position * vec2(1.0, 4.0);
|
|
||||||
vFrom = from + offset;
|
|
||||||
vTo = to + offset;
|
|
||||||
|
|
||||||
vec2 globalPosition =(tileOrigin + position)/ uFramebufferSize * 2.0 - 1.0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gl_Position = vec4(globalPosition, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
uniform sampler2D uTextureMetadata;
|
|
||||||
uniform ivec2 uTextureMetadataSize;
|
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
|
||||||
in ivec2 aTileOrigin;
|
|
||||||
in uvec2 aMaskTexCoord0;
|
|
||||||
in ivec2 aMaskBackdrop;
|
|
||||||
in int aColor;
|
|
||||||
in int aTileCtrl;
|
|
||||||
|
|
||||||
out vec3 vMaskTexCoord0;
|
|
||||||
out vec2 vColorTexCoord0;
|
|
||||||
out vec4 vBaseColor;
|
|
||||||
out float vTileCtrl;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
|
||||||
vec2 position =(tileOrigin + tileOffset)* uTileSize;
|
|
||||||
|
|
||||||
vec2 maskTexCoord0 =(vec2(aMaskTexCoord0)+ tileOffset)* uTileSize;
|
|
||||||
|
|
||||||
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
|
|
||||||
vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128);
|
|
||||||
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
|
|
||||||
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
|
|
||||||
vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale;
|
|
||||||
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
|
|
||||||
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
|
|
||||||
vec4 baseColor = texture(uTextureMetadata, baseColorCoord);
|
|
||||||
|
|
||||||
vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
|
|
||||||
vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop . x));
|
|
||||||
vBaseColor = baseColor;
|
|
||||||
vTileCtrl = float(aTileCtrl);
|
|
||||||
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
|
||||||
in ivec2 aDestTileOrigin;
|
|
||||||
in ivec2 aSrcTileOrigin;
|
|
||||||
in int aSrcBackdrop;
|
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
|
||||||
out float vBackdrop;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 destPosition = vec2(aDestTileOrigin + aTileOffset)/ vec2(256.0);
|
|
||||||
vec2 srcPosition = vec2(aSrcTileOrigin + aTileOffset)/ vec2(256.0);
|
|
||||||
vTexCoord = srcPosition;
|
|
||||||
vBackdrop = float(aSrcBackdrop);
|
|
||||||
gl_Position = vec4(mix(vec2(- 1.0), vec2(1.0), destPosition), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,708 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
precision highp sampler2D;
|
|
||||||
|
|
||||||
uniform sampler2D uColorTexture0;
|
|
||||||
uniform sampler2D uMaskTexture0;
|
|
||||||
uniform sampler2D uDestTexture;
|
|
||||||
uniform sampler2D uGammaLUT;
|
|
||||||
uniform vec4 uFilterParams0;
|
|
||||||
uniform vec4 uFilterParams1;
|
|
||||||
uniform vec4 uFilterParams2;
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform vec2 uColorTextureSize0;
|
|
||||||
uniform int uCtrl;
|
|
||||||
uniform sampler2D uAreaLUT;
|
|
||||||
|
|
||||||
layout(std430, binding = 0)buffer bFills {
|
|
||||||
restrict readonly uvec2 iFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 1)buffer bNextFills {
|
|
||||||
restrict readonly int iNextFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 2)buffer bFillTileMap {
|
|
||||||
restrict readonly int iFillTileMap[];
|
|
||||||
};
|
|
||||||
|
|
||||||
in vec2 vTileSubCoord;
|
|
||||||
flat in uint vMaskTileIndex0;
|
|
||||||
flat in int vMaskTileBackdrop0;
|
|
||||||
in vec2 vColorTexCoord0;
|
|
||||||
in vec4 vBaseColor;
|
|
||||||
in float vTileCtrl;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
|
|
||||||
|
|
||||||
vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from;
|
|
||||||
|
|
||||||
|
|
||||||
vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5);
|
|
||||||
float offset = mix(window . x, window . y, 0.5)- left . x;
|
|
||||||
float t = offset /(right . x - left . x);
|
|
||||||
|
|
||||||
|
|
||||||
float y = mix(left . y, right . y, t);
|
|
||||||
float d =(right . y - left . y)/(right . x - left . x);
|
|
||||||
|
|
||||||
|
|
||||||
float dX = window . x - window . y;
|
|
||||||
return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT);
|
|
||||||
|
|
||||||
ivec2 calculateTileOrigin(uint tileIndex){
|
|
||||||
return ivec2(tileIndex & 0xff,(tileIndex >> 8u)& 0xff)* 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 calculateFillAlpha(ivec2 tileSubCoord, uint tileIndex){
|
|
||||||
int fillIndex = iFillTileMap[tileIndex];
|
|
||||||
if(fillIndex < 0)
|
|
||||||
return vec4(0.0);
|
|
||||||
|
|
||||||
vec4 coverages = vec4(0.0);
|
|
||||||
do {
|
|
||||||
uvec2 fill = iFills[fillIndex];
|
|
||||||
vec2 from = vec2(fill . y & 0xf,(fill . y >> 4u)& 0xf)+
|
|
||||||
vec2(fill . x & 0xff,(fill . x >> 8u)& 0xff)/ 256.0;
|
|
||||||
vec2 to = vec2((fill . y >> 8u)& 0xf,(fill . y >> 12u)& 0xf)+
|
|
||||||
vec2((fill . x >> 16u)& 0xff,(fill . x >> 24u)& 0xff)/ 256.0;
|
|
||||||
|
|
||||||
coverages += computeCoverage(from -(vec2(tileSubCoord)+ vec2(0.5)),
|
|
||||||
to -(vec2(tileSubCoord)+ vec2(0.5)),
|
|
||||||
uAreaLUT);
|
|
||||||
|
|
||||||
fillIndex = iNextFills[fillIndex];
|
|
||||||
} while(fillIndex >= 0);
|
|
||||||
|
|
||||||
return coverages;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord){
|
|
||||||
return texture(colorTexture, colorTexCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 combineColor0(vec4 destColor, vec4 srcColor, int op){
|
|
||||||
switch(op){
|
|
||||||
case 0x1 :
|
|
||||||
return vec4(srcColor . rgb, srcColor . a * destColor . a);
|
|
||||||
case 0x2 :
|
|
||||||
return vec4(destColor . rgb, srcColor . a * destColor . a);
|
|
||||||
}
|
|
||||||
return destColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float filterTextSample1Tap(float offset, sampler2D colorTexture, vec2 colorTexCoord){
|
|
||||||
return texture(colorTexture, colorTexCoord + vec2(offset, 0.0)). r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void filterTextSample9Tap(out vec4 outAlphaLeft,
|
|
||||||
out float outAlphaCenter,
|
|
||||||
out vec4 outAlphaRight,
|
|
||||||
sampler2D colorTexture,
|
|
||||||
vec2 colorTexCoord,
|
|
||||||
vec4 kernel,
|
|
||||||
float onePixel){
|
|
||||||
bool wide = kernel . x > 0.0;
|
|
||||||
outAlphaLeft =
|
|
||||||
vec4(wide ? filterTextSample1Tap(- 4.0 * onePixel, colorTexture, colorTexCoord): 0.0,
|
|
||||||
filterTextSample1Tap(- 3.0 * onePixel, colorTexture, colorTexCoord),
|
|
||||||
filterTextSample1Tap(- 2.0 * onePixel, colorTexture, colorTexCoord),
|
|
||||||
filterTextSample1Tap(- 1.0 * onePixel, colorTexture, colorTexCoord));
|
|
||||||
outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord);
|
|
||||||
outAlphaRight =
|
|
||||||
vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord),
|
|
||||||
filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord),
|
|
||||||
filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord),
|
|
||||||
wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord): 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel){
|
|
||||||
return dot(alpha0, kernel)+ dot(alpha1, kernel . zyx);
|
|
||||||
}
|
|
||||||
|
|
||||||
float filterTextGammaCorrectChannel(float bgColor, float fgColor, sampler2D gammaLUT){
|
|
||||||
return texture(gammaLUT, vec2(fgColor, 1.0 - bgColor)). r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, sampler2D gammaLUT){
|
|
||||||
return vec3(filterTextGammaCorrectChannel(bgColor . r, fgColor . r, gammaLUT),
|
|
||||||
filterTextGammaCorrectChannel(bgColor . g, fgColor . g, gammaLUT),
|
|
||||||
filterTextGammaCorrectChannel(bgColor . b, fgColor . b, gammaLUT));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 filterText(vec2 colorTexCoord,
|
|
||||||
sampler2D colorTexture,
|
|
||||||
sampler2D gammaLUT,
|
|
||||||
vec2 colorTextureSize,
|
|
||||||
vec4 filterParams0,
|
|
||||||
vec4 filterParams1,
|
|
||||||
vec4 filterParams2){
|
|
||||||
|
|
||||||
vec4 kernel = filterParams0;
|
|
||||||
vec3 bgColor = filterParams1 . rgb;
|
|
||||||
vec3 fgColor = filterParams2 . rgb;
|
|
||||||
bool gammaCorrectionEnabled = filterParams2 . a != 0.0;
|
|
||||||
|
|
||||||
|
|
||||||
vec3 alpha;
|
|
||||||
if(kernel . w == 0.0){
|
|
||||||
alpha = texture(colorTexture, colorTexCoord). rrr;
|
|
||||||
} else {
|
|
||||||
vec4 alphaLeft, alphaRight;
|
|
||||||
float alphaCenter;
|
|
||||||
filterTextSample9Tap(alphaLeft,
|
|
||||||
alphaCenter,
|
|
||||||
alphaRight,
|
|
||||||
colorTexture,
|
|
||||||
colorTexCoord,
|
|
||||||
kernel,
|
|
||||||
1.0 / colorTextureSize . x);
|
|
||||||
|
|
||||||
float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight . xy), kernel);
|
|
||||||
float g = filterTextConvolve7Tap(vec4(alphaLeft . yzw, alphaCenter), alphaRight . xyz, kernel);
|
|
||||||
float b = filterTextConvolve7Tap(vec4(alphaLeft . zw, alphaCenter, alphaRight . x),
|
|
||||||
alphaRight . yzw,
|
|
||||||
kernel);
|
|
||||||
|
|
||||||
alpha = vec3(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(gammaCorrectionEnabled)
|
|
||||||
alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT);
|
|
||||||
|
|
||||||
|
|
||||||
return vec4(mix(bgColor, fgColor, alpha), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 filterRadialGradient(vec2 colorTexCoord,
|
|
||||||
sampler2D colorTexture,
|
|
||||||
vec2 colorTextureSize,
|
|
||||||
vec2 fragCoord,
|
|
||||||
vec2 framebufferSize,
|
|
||||||
vec4 filterParams0,
|
|
||||||
vec4 filterParams1){
|
|
||||||
vec2 lineFrom = filterParams0 . xy, lineVector = filterParams0 . zw;
|
|
||||||
vec2 radii = filterParams1 . xy, uvOrigin = filterParams1 . zw;
|
|
||||||
|
|
||||||
vec2 dP = colorTexCoord - lineFrom, dC = lineVector;
|
|
||||||
float dR = radii . y - radii . x;
|
|
||||||
|
|
||||||
float a = dot(dC, dC)- dR * dR;
|
|
||||||
float b = dot(dP, dC)+ radii . x * dR;
|
|
||||||
float c = dot(dP, dP)- radii . x * radii . x;
|
|
||||||
float discrim = b * b - a * c;
|
|
||||||
|
|
||||||
vec4 color = vec4(0.0);
|
|
||||||
if(abs(discrim)>= 0.00001){
|
|
||||||
vec2 ts = vec2(sqrt(discrim)* vec2(1.0, - 1.0)+ vec2(b))/ vec2(a);
|
|
||||||
if(ts . x > ts . y)
|
|
||||||
ts = ts . yx;
|
|
||||||
float t = ts . x >= 0.0 ? ts . x : ts . y;
|
|
||||||
color = texture(colorTexture, uvOrigin + vec2(clamp(t, 0.0, 1.0), 0.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 filterBlur(vec2 colorTexCoord,
|
|
||||||
sampler2D colorTexture,
|
|
||||||
vec2 colorTextureSize,
|
|
||||||
vec4 filterParams0,
|
|
||||||
vec4 filterParams1){
|
|
||||||
|
|
||||||
vec2 srcOffsetScale = filterParams0 . xy / colorTextureSize;
|
|
||||||
int support = int(filterParams0 . z);
|
|
||||||
vec3 gaussCoeff = filterParams1 . xyz;
|
|
||||||
|
|
||||||
|
|
||||||
float gaussSum = gaussCoeff . x;
|
|
||||||
vec4 color = texture(colorTexture, colorTexCoord)* gaussCoeff . x;
|
|
||||||
gaussCoeff . xy *= gaussCoeff . yz;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 1;i <= support;i += 2){
|
|
||||||
float gaussPartialSum = gaussCoeff . x;
|
|
||||||
gaussCoeff . xy *= gaussCoeff . yz;
|
|
||||||
gaussPartialSum += gaussCoeff . x;
|
|
||||||
|
|
||||||
vec2 srcOffset = srcOffsetScale *(float(i)+ gaussCoeff . x / gaussPartialSum);
|
|
||||||
color +=(texture(colorTexture, colorTexCoord - srcOffset)+
|
|
||||||
texture(colorTexture, colorTexCoord + srcOffset))* gaussPartialSum;
|
|
||||||
|
|
||||||
gaussSum += 2.0 * gaussPartialSum;
|
|
||||||
gaussCoeff . xy *= gaussCoeff . yz;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return color / gaussSum;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture){
|
|
||||||
return sampleColor(colorTexture, colorTexCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 filterColor(vec2 colorTexCoord,
|
|
||||||
sampler2D colorTexture,
|
|
||||||
sampler2D gammaLUT,
|
|
||||||
vec2 colorTextureSize,
|
|
||||||
vec2 fragCoord,
|
|
||||||
vec2 framebufferSize,
|
|
||||||
vec4 filterParams0,
|
|
||||||
vec4 filterParams1,
|
|
||||||
vec4 filterParams2,
|
|
||||||
int colorFilter){
|
|
||||||
switch(colorFilter){
|
|
||||||
case 0x1 :
|
|
||||||
return filterRadialGradient(colorTexCoord,
|
|
||||||
colorTexture,
|
|
||||||
colorTextureSize,
|
|
||||||
fragCoord,
|
|
||||||
framebufferSize,
|
|
||||||
filterParams0,
|
|
||||||
filterParams1);
|
|
||||||
case 0x3 :
|
|
||||||
return filterBlur(colorTexCoord,
|
|
||||||
colorTexture,
|
|
||||||
colorTextureSize,
|
|
||||||
filterParams0,
|
|
||||||
filterParams1);
|
|
||||||
case 0x2 :
|
|
||||||
return filterText(colorTexCoord,
|
|
||||||
colorTexture,
|
|
||||||
gammaLUT,
|
|
||||||
colorTextureSize,
|
|
||||||
filterParams0,
|
|
||||||
filterParams1,
|
|
||||||
filterParams2);
|
|
||||||
}
|
|
||||||
return filterNone(colorTexCoord, colorTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse){
|
|
||||||
return vec3(cond . x ? ifTrue . x : ifFalse . x,
|
|
||||||
cond . y ? ifTrue . y : ifFalse . y,
|
|
||||||
cond . z ? ifTrue . z : ifFalse . z);
|
|
||||||
}
|
|
||||||
|
|
||||||
float compositeDivide(float num, float denom){
|
|
||||||
return denom != 0.0 ? num / denom : 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 compositeColorDodge(vec3 destColor, vec3 srcColor){
|
|
||||||
bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0));
|
|
||||||
return compositeSelect(destZero,
|
|
||||||
vec3(0.0),
|
|
||||||
compositeSelect(srcOne, vec3(1.0), destColor /(vec3(1.0)- srcColor)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec3 compositeHSLToRGB(vec3 hsl){
|
|
||||||
float a = hsl . y * min(hsl . z, 1.0 - hsl . z);
|
|
||||||
vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0);
|
|
||||||
return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec3 compositeRGBToHSL(vec3 rgb){
|
|
||||||
float v = max(max(rgb . r, rgb . g), rgb . b), xMin = min(min(rgb . r, rgb . g), rgb . b);
|
|
||||||
float c = v - xMin, l = mix(xMin, v, 0.5);
|
|
||||||
vec3 terms = rgb . r == v ? vec3(0.0, rgb . gb):
|
|
||||||
rgb . g == v ? vec3(2.0, rgb . br):
|
|
||||||
vec3(4.0, rgb . rg);
|
|
||||||
float h = 1.0471975511965976 * compositeDivide(terms . x * c + terms . y - terms . z, c);
|
|
||||||
float s = compositeDivide(c, v);
|
|
||||||
return vec3(h, s, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 compositeScreen(vec3 destColor, vec3 srcColor){
|
|
||||||
return destColor + srcColor - destColor * srcColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 compositeHardLight(vec3 destColor, vec3 srcColor){
|
|
||||||
return compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
|
|
||||||
destColor * vec3(2.0)* srcColor,
|
|
||||||
compositeScreen(destColor, vec3(2.0)* srcColor - vec3(1.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 compositeSoftLight(vec3 destColor, vec3 srcColor){
|
|
||||||
vec3 darkenedDestColor =
|
|
||||||
compositeSelect(lessThanEqual(destColor, vec3(0.25)),
|
|
||||||
((vec3(16.0)* destColor - 12.0)* destColor + 4.0)* destColor,
|
|
||||||
sqrt(destColor));
|
|
||||||
vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
|
|
||||||
destColor *(vec3(1.0)- destColor),
|
|
||||||
darkenedDestColor - destColor);
|
|
||||||
return destColor +(srcColor * 2.0 - 1.0)* factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op){
|
|
||||||
switch(op){
|
|
||||||
case 0xc :
|
|
||||||
return vec3(srcColor . x, destColor . y, destColor . z);
|
|
||||||
case 0xd :
|
|
||||||
return vec3(destColor . x, srcColor . y, destColor . z);
|
|
||||||
case 0xe :
|
|
||||||
return vec3(srcColor . x, srcColor . y, destColor . z);
|
|
||||||
default :
|
|
||||||
return vec3(destColor . x, destColor . y, srcColor . z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op){
|
|
||||||
switch(op){
|
|
||||||
case 0x1 :
|
|
||||||
return destColor * srcColor;
|
|
||||||
case 0x2 :
|
|
||||||
return compositeScreen(destColor, srcColor);
|
|
||||||
case 0x3 :
|
|
||||||
return compositeHardLight(srcColor, destColor);
|
|
||||||
case 0x4 :
|
|
||||||
return min(destColor, srcColor);
|
|
||||||
case 0x5 :
|
|
||||||
return max(destColor, srcColor);
|
|
||||||
case 0x6 :
|
|
||||||
return compositeColorDodge(destColor, srcColor);
|
|
||||||
case 0x7 :
|
|
||||||
return vec3(1.0)- compositeColorDodge(vec3(1.0)- destColor, vec3(1.0)- srcColor);
|
|
||||||
case 0x8 :
|
|
||||||
return compositeHardLight(destColor, srcColor);
|
|
||||||
case 0x9 :
|
|
||||||
return compositeSoftLight(destColor, srcColor);
|
|
||||||
case 0xa :
|
|
||||||
return abs(destColor - srcColor);
|
|
||||||
case 0xb :
|
|
||||||
return destColor + srcColor - vec3(2.0)* destColor * srcColor;
|
|
||||||
case 0xc :
|
|
||||||
case 0xd :
|
|
||||||
case 0xe :
|
|
||||||
case 0xf :
|
|
||||||
return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor),
|
|
||||||
compositeRGBToHSL(srcColor),
|
|
||||||
op));
|
|
||||||
}
|
|
||||||
return srcColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 composite(vec4 srcColor,
|
|
||||||
sampler2D destTexture,
|
|
||||||
vec2 destTextureSize,
|
|
||||||
vec2 fragCoord,
|
|
||||||
int op){
|
|
||||||
if(op == 0x0)
|
|
||||||
return srcColor;
|
|
||||||
|
|
||||||
|
|
||||||
vec2 destTexCoord = fragCoord / destTextureSize;
|
|
||||||
vec4 destColor = texture(destTexture, destTexCoord);
|
|
||||||
vec3 blendedRGB = compositeRGB(destColor . rgb, srcColor . rgb, op);
|
|
||||||
return vec4(srcColor . a *(1.0 - destColor . a)* srcColor . rgb +
|
|
||||||
srcColor . a * destColor . a * blendedRGB +
|
|
||||||
(1.0 - srcColor . a)* destColor . rgb,
|
|
||||||
1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float sampleMask(float maskAlpha,
|
|
||||||
sampler2D maskTexture,
|
|
||||||
vec2 maskTextureSize,
|
|
||||||
vec3 maskTexCoord,
|
|
||||||
int maskCtrl){
|
|
||||||
if(maskCtrl == 0)
|
|
||||||
return maskAlpha;
|
|
||||||
|
|
||||||
ivec2 maskTexCoordI = ivec2(floor(maskTexCoord . xy));
|
|
||||||
vec4 texel = texture(maskTexture,(vec2(maskTexCoordI / ivec2(1, 4))+ 0.5)/ maskTextureSize);
|
|
||||||
float coverage = texel[maskTexCoordI . y % 4]+ maskTexCoord . z;
|
|
||||||
|
|
||||||
if((maskCtrl & 0x1)!= 0)
|
|
||||||
coverage = abs(coverage);
|
|
||||||
else
|
|
||||||
coverage = 1.0 - abs(1.0 - mod(coverage, 2.0));
|
|
||||||
return min(maskAlpha, coverage);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 calculateColorWithMaskAlpha(float maskAlpha,
|
|
||||||
vec4 baseColor,
|
|
||||||
vec2 colorTexCoord0,
|
|
||||||
vec2 fragCoord,
|
|
||||||
int ctrl){
|
|
||||||
|
|
||||||
vec4 color = baseColor;
|
|
||||||
int color0Combine =(ctrl >> 6)&
|
|
||||||
0x3;
|
|
||||||
if(color0Combine != 0){
|
|
||||||
int color0Filter =(ctrl >> 4)& 0x3;
|
|
||||||
vec4 color0 = filterColor(colorTexCoord0,
|
|
||||||
uColorTexture0,
|
|
||||||
uGammaLUT,
|
|
||||||
uColorTextureSize0,
|
|
||||||
fragCoord,
|
|
||||||
uFramebufferSize,
|
|
||||||
uFilterParams0,
|
|
||||||
uFilterParams1,
|
|
||||||
uFilterParams2,
|
|
||||||
color0Filter);
|
|
||||||
color = combineColor0(color, color0, color0Combine);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
color . a *= maskAlpha;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
color . rgb *= color . a;
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec4 calculateColor(int tileCtrl, int ctrl){
|
|
||||||
float maskAlpha = 1.0;
|
|
||||||
int maskCtrl0 =(ctrl >> 0)& 0x1;
|
|
||||||
int maskTileCtrl0 =(tileCtrl >> 0)& 0x3;
|
|
||||||
uint maskTileIndex0 = vMaskTileIndex0;
|
|
||||||
if(maskCtrl0 != 0 && maskTileCtrl0 != 0){
|
|
||||||
ivec2 tileSubCoord = ivec2(floor(vTileSubCoord));
|
|
||||||
vec4 alphas = calculateFillAlpha(tileSubCoord, maskTileIndex0)+ float(vMaskTileBackdrop0);
|
|
||||||
maskAlpha = alphas . x;
|
|
||||||
}
|
|
||||||
return calculateColorWithMaskAlpha(maskAlpha,
|
|
||||||
vBaseColor,
|
|
||||||
vColorTexCoord0,
|
|
||||||
gl_FragCoord . xy,
|
|
||||||
ctrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
oFragColor = calculateColor(int(vTileCtrl), uCtrl);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
#version {{version}}
|
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
precision highp sampler2D;
|
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
uniform sampler2D uTextureMetadata;
|
|
||||||
uniform ivec2 uTextureMetadataSize;
|
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
|
||||||
in ivec2 aTileOrigin;
|
|
||||||
in uint aMaskTileIndex0;
|
|
||||||
in ivec2 aMaskBackdrop;
|
|
||||||
in int aColor;
|
|
||||||
in int aTileCtrl;
|
|
||||||
|
|
||||||
out vec2 vTileSubCoord;
|
|
||||||
flat out uint vMaskTileIndex0;
|
|
||||||
flat out int vMaskTileBackdrop0;
|
|
||||||
out vec2 vColorTexCoord0;
|
|
||||||
out vec4 vBaseColor;
|
|
||||||
out float vTileCtrl;
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
|
||||||
vec2 position =(tileOrigin + tileOffset)* uTileSize;
|
|
||||||
|
|
||||||
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
|
|
||||||
vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128);
|
|
||||||
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
|
|
||||||
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
|
|
||||||
vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale;
|
|
||||||
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
|
|
||||||
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
|
|
||||||
vec4 baseColor = texture(uTextureMetadata, baseColorCoord);
|
|
||||||
|
|
||||||
vTileSubCoord = tileOffset * vec2(16.0);
|
|
||||||
vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
|
|
||||||
vMaskTileIndex0 = aMaskTileIndex0;
|
|
||||||
vMaskTileBackdrop0 = aMaskBackdrop . x;
|
|
||||||
vBaseColor = baseColor;
|
|
||||||
vTileCtrl = float(aTileCtrl);
|
|
||||||
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uSrc [[textu
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
float4 color = uSrc.sample(uSrcSmplr, in.vTexCoord);
|
float4 color = uSrc.sample(uSrcSmplr, in.vTexCoord);
|
||||||
out.oFragColor = float4(color.xyz * color.w, color.w);
|
out.oFragColor = color;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,13 @@ struct main0_in
|
||||||
int2 aPosition [[attribute(0)]];
|
int2 aPosition [[attribute(0)]];
|
||||||
};
|
};
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]])
|
vertex main0_out main0(main0_in in [[stage_in]], constant float4& uDestRect [[buffer(0)]], constant float2& uFramebufferSize [[buffer(1)]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
|
float2 position = mix(uDestRect.xy, uDestRect.zw, float2(in.aPosition)) / uFramebufferSize;
|
||||||
float2 texCoord = float2(in.aPosition);
|
float2 texCoord = float2(in.aPosition);
|
||||||
texCoord.y = 1.0 - texCoord.y;
|
|
||||||
out.vTexCoord = texCoord;
|
out.vTexCoord = texCoord;
|
||||||
out.gl_Position = float4(mix(float2(-1.0), float2(1.0), float2(in.aPosition)), 0.0, 1.0);
|
out.gl_Position = float4(mix(float2(-1.0), float2(1.0), position), 0.0, 1.0);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,284 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
#include <metal_atomic>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bIndirectDrawParams
|
||||||
|
{
|
||||||
|
uint iIndirectDrawParams[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bTiles
|
||||||
|
{
|
||||||
|
uint iTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bFills
|
||||||
|
{
|
||||||
|
uint iFills[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bBackdrops
|
||||||
|
{
|
||||||
|
uint iBackdrops[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bMicrolines
|
||||||
|
{
|
||||||
|
uint4 iMicrolines[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bMetadata
|
||||||
|
{
|
||||||
|
int4 iMetadata[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(64u, 1u, 1u);
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 unpackMicroline(thread const uint4& packedMicroline, thread uint& outPathIndex)
|
||||||
|
{
|
||||||
|
outPathIndex = packedMicroline.w;
|
||||||
|
int4 signedMicroline = int4(packedMicroline);
|
||||||
|
return float4(float((signedMicroline.x << 16) >> 16), float(signedMicroline.x >> 16), float((signedMicroline.y << 16) >> 16), float(signedMicroline.y >> 16)) + (float4(float(signedMicroline.z & 255), float((signedMicroline.z >> 8) & 255), float((signedMicroline.z >> 16) & 255), float((signedMicroline.z >> 24) & 255)) / float4(256.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
uint computeTileIndexNoCheck(thread const int2& tileCoords, thread const int4& pathTileRect, thread const uint& pathTileOffset)
|
||||||
|
{
|
||||||
|
int2 offsetCoords = tileCoords - pathTileRect.xy;
|
||||||
|
return (pathTileOffset + uint(offsetCoords.x)) + uint(offsetCoords.y * (pathTileRect.z - pathTileRect.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
bool4 computeTileOutcodes(thread const int2& tileCoords, thread const int4& pathTileRect)
|
||||||
|
{
|
||||||
|
return bool4(tileCoords < pathTileRect.xy, tileCoords >= pathTileRect.zw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
bool computeTileIndex(thread const int2& tileCoords, thread const int4& pathTileRect, thread const uint& pathTileOffset, thread uint& outTileIndex)
|
||||||
|
{
|
||||||
|
int2 param = tileCoords;
|
||||||
|
int4 param_1 = pathTileRect;
|
||||||
|
uint param_2 = pathTileOffset;
|
||||||
|
outTileIndex = computeTileIndexNoCheck(param, param_1, param_2);
|
||||||
|
int2 param_3 = tileCoords;
|
||||||
|
int4 param_4 = pathTileRect;
|
||||||
|
return !any(computeTileOutcodes(param_3, param_4));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void addFill(thread const float4& lineSegment, thread const int2& tileCoords, thread const int4& pathTileRect, thread const uint& pathTileOffset, device bIndirectDrawParams& v_155, device bTiles& v_165, thread int uMaxFillCount, device bFills& v_186)
|
||||||
|
{
|
||||||
|
int2 param = tileCoords;
|
||||||
|
int4 param_1 = pathTileRect;
|
||||||
|
uint param_2 = pathTileOffset;
|
||||||
|
uint param_3;
|
||||||
|
bool _124 = computeTileIndex(param, param_1, param_2, param_3);
|
||||||
|
uint tileIndex = param_3;
|
||||||
|
if (!_124)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint4 scaledLocalLine = uint4((lineSegment - float4(tileCoords.xyxy * int4(16))) * float4(256.0));
|
||||||
|
if (scaledLocalLine.x == scaledLocalLine.z)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint _160 = atomic_fetch_add_explicit((device atomic_uint*)&v_155.iIndirectDrawParams[1], 1u, memory_order_relaxed);
|
||||||
|
uint fillIndex = _160;
|
||||||
|
uint _174 = atomic_exchange_explicit((device atomic_uint*)&v_165.iTiles[(tileIndex * 4u) + 1u], uint(int(fillIndex)), memory_order_relaxed);
|
||||||
|
uint fillLink = _174;
|
||||||
|
if (fillIndex < uint(uMaxFillCount))
|
||||||
|
{
|
||||||
|
v_186.iFills[(fillIndex * 3u) + 0u] = scaledLocalLine.x | (scaledLocalLine.y << uint(16));
|
||||||
|
v_186.iFills[(fillIndex * 3u) + 1u] = scaledLocalLine.z | (scaledLocalLine.w << uint(16));
|
||||||
|
v_186.iFills[(fillIndex * 3u) + 2u] = fillLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void adjustBackdrop(thread const int& backdropDelta, thread const int2& tileCoords, thread const int4& pathTileRect, thread const uint& pathTileOffset, thread const uint& pathBackdropOffset, device bTiles& v_165, device bBackdrops& v_251)
|
||||||
|
{
|
||||||
|
int2 param = tileCoords;
|
||||||
|
int4 param_1 = pathTileRect;
|
||||||
|
bool4 outcodes = computeTileOutcodes(param, param_1);
|
||||||
|
if (any(outcodes))
|
||||||
|
{
|
||||||
|
bool _230 = (!outcodes.x) && outcodes.y;
|
||||||
|
bool _236;
|
||||||
|
if (_230)
|
||||||
|
{
|
||||||
|
_236 = !outcodes.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_236 = _230;
|
||||||
|
}
|
||||||
|
if (_236)
|
||||||
|
{
|
||||||
|
uint backdropIndex = pathBackdropOffset + uint(tileCoords.x - pathTileRect.x);
|
||||||
|
uint _257 = atomic_fetch_add_explicit((device atomic_uint*)&v_251.iBackdrops[backdropIndex * 3u], uint(backdropDelta), memory_order_relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int2 param_2 = tileCoords;
|
||||||
|
int4 param_3 = pathTileRect;
|
||||||
|
uint param_4 = pathTileOffset;
|
||||||
|
uint tileIndex = computeTileIndexNoCheck(param_2, param_3, param_4);
|
||||||
|
uint _275 = atomic_fetch_add_explicit((device atomic_uint*)&v_165.iTiles[(tileIndex * 4u) + 2u], uint(backdropDelta) << uint(24), memory_order_relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void main0(constant int& uMaxFillCount [[buffer(2)]], constant int& uMicrolineCount [[buffer(5)]], device bIndirectDrawParams& v_155 [[buffer(0)]], device bTiles& v_165 [[buffer(1)]], device bFills& v_186 [[buffer(3)]], device bBackdrops& v_251 [[buffer(4)]], const device bMicrolines& _346 [[buffer(6)]], const device bMetadata& _360 [[buffer(7)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]])
|
||||||
|
{
|
||||||
|
uint segmentIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (segmentIndex >= uint(uMicrolineCount))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint4 param = _346.iMicrolines[segmentIndex];
|
||||||
|
uint param_1;
|
||||||
|
float4 _354 = unpackMicroline(param, param_1);
|
||||||
|
uint pathIndex = param_1;
|
||||||
|
float4 lineSegment = _354;
|
||||||
|
int4 pathTileRect = _360.iMetadata[(pathIndex * 3u) + 0u];
|
||||||
|
uint pathTileOffset = uint(_360.iMetadata[(pathIndex * 3u) + 1u].x);
|
||||||
|
uint pathBackdropOffset = uint(_360.iMetadata[(pathIndex * 3u) + 2u].x);
|
||||||
|
int2 tileSize = int2(16);
|
||||||
|
int4 tileLineSegment = int4(floor(lineSegment / float4(tileSize.xyxy)));
|
||||||
|
int2 fromTileCoords = tileLineSegment.xy;
|
||||||
|
int2 toTileCoords = tileLineSegment.zw;
|
||||||
|
float2 vector = lineSegment.zw - lineSegment.xy;
|
||||||
|
float2 vectorIsNegative = float2((vector.x < 0.0) ? (-1.0) : 0.0, (vector.y < 0.0) ? (-1.0) : 0.0);
|
||||||
|
int2 tileStep = int2((vector.x < 0.0) ? (-1) : 1, (vector.y < 0.0) ? (-1) : 1);
|
||||||
|
float2 firstTileCrossing = float2((fromTileCoords + int2(int(vector.x >= 0.0), int(vector.y >= 0.0))) * tileSize);
|
||||||
|
float2 tMax = (firstTileCrossing - lineSegment.xy) / vector;
|
||||||
|
float2 tDelta = abs(float2(tileSize) / vector);
|
||||||
|
float2 currentPosition = lineSegment.xy;
|
||||||
|
int2 tileCoords = fromTileCoords;
|
||||||
|
int lastStepDirection = 0;
|
||||||
|
uint iteration = 0u;
|
||||||
|
int nextStepDirection;
|
||||||
|
float _501;
|
||||||
|
float4 auxiliarySegment;
|
||||||
|
while (iteration < 1024u)
|
||||||
|
{
|
||||||
|
if (tMax.x < tMax.y)
|
||||||
|
{
|
||||||
|
nextStepDirection = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tMax.x > tMax.y)
|
||||||
|
{
|
||||||
|
nextStepDirection = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (float(tileStep.x) > 0.0)
|
||||||
|
{
|
||||||
|
nextStepDirection = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextStepDirection = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextStepDirection == 1)
|
||||||
|
{
|
||||||
|
_501 = tMax.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_501 = tMax.y;
|
||||||
|
}
|
||||||
|
float nextT = fast::min(_501, 1.0);
|
||||||
|
if (all(tileCoords == toTileCoords))
|
||||||
|
{
|
||||||
|
nextStepDirection = 0;
|
||||||
|
}
|
||||||
|
float2 nextPosition = mix(lineSegment.xy, lineSegment.zw, float2(nextT));
|
||||||
|
float4 clippedLineSegment = float4(currentPosition, nextPosition);
|
||||||
|
float4 param_2 = clippedLineSegment;
|
||||||
|
int2 param_3 = tileCoords;
|
||||||
|
int4 param_4 = pathTileRect;
|
||||||
|
uint param_5 = pathTileOffset;
|
||||||
|
addFill(param_2, param_3, param_4, param_5, v_155, v_165, uMaxFillCount, v_186);
|
||||||
|
bool haveAuxiliarySegment = false;
|
||||||
|
if ((tileStep.y < 0) && (nextStepDirection == 2))
|
||||||
|
{
|
||||||
|
auxiliarySegment = float4(clippedLineSegment.zw, float2(tileCoords * tileSize));
|
||||||
|
haveAuxiliarySegment = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((tileStep.y > 0) && (lastStepDirection == 2))
|
||||||
|
{
|
||||||
|
auxiliarySegment = float4(float2(tileCoords * tileSize), clippedLineSegment.xy);
|
||||||
|
haveAuxiliarySegment = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (haveAuxiliarySegment)
|
||||||
|
{
|
||||||
|
float4 param_6 = auxiliarySegment;
|
||||||
|
int2 param_7 = tileCoords;
|
||||||
|
int4 param_8 = pathTileRect;
|
||||||
|
uint param_9 = pathTileOffset;
|
||||||
|
addFill(param_6, param_7, param_8, param_9, v_155, v_165, uMaxFillCount, v_186);
|
||||||
|
}
|
||||||
|
if ((tileStep.x < 0) && (lastStepDirection == 1))
|
||||||
|
{
|
||||||
|
int param_10 = 1;
|
||||||
|
int2 param_11 = tileCoords;
|
||||||
|
int4 param_12 = pathTileRect;
|
||||||
|
uint param_13 = pathTileOffset;
|
||||||
|
uint param_14 = pathBackdropOffset;
|
||||||
|
adjustBackdrop(param_10, param_11, param_12, param_13, param_14, v_165, v_251);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((tileStep.x > 0) && (nextStepDirection == 1))
|
||||||
|
{
|
||||||
|
int param_15 = -1;
|
||||||
|
int2 param_16 = tileCoords;
|
||||||
|
int4 param_17 = pathTileRect;
|
||||||
|
uint param_18 = pathTileOffset;
|
||||||
|
uint param_19 = pathBackdropOffset;
|
||||||
|
adjustBackdrop(param_15, param_16, param_17, param_18, param_19, v_165, v_251);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextStepDirection == 1)
|
||||||
|
{
|
||||||
|
tMax.x += tDelta.x;
|
||||||
|
tileCoords.x += tileStep.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nextStepDirection == 2)
|
||||||
|
{
|
||||||
|
tMax.y += tDelta.y;
|
||||||
|
tileCoords.y += tileStep.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (nextStepDirection == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentPosition = nextPosition;
|
||||||
|
lastStepDirection = nextStepDirection;
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bTilePathInfo
|
||||||
|
{
|
||||||
|
uint4 iTilePathInfo[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bTiles
|
||||||
|
{
|
||||||
|
uint iTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(64u, 1u, 1u);
|
||||||
|
|
||||||
|
kernel void main0(constant int& uTileCount [[buffer(0)]], constant int& uPathCount [[buffer(1)]], const device bTilePathInfo& _64 [[buffer(2)]], device bTiles& _148 [[buffer(3)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]])
|
||||||
|
{
|
||||||
|
uint tileIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (tileIndex >= uint(uTileCount))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint lowPathIndex = 0u;
|
||||||
|
uint highPathIndex = uint(uPathCount);
|
||||||
|
int iteration = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
bool _42 = iteration < 1024;
|
||||||
|
bool _50;
|
||||||
|
if (_42)
|
||||||
|
{
|
||||||
|
_50 = (lowPathIndex + 1u) < highPathIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_50 = _42;
|
||||||
|
}
|
||||||
|
if (_50)
|
||||||
|
{
|
||||||
|
uint midPathIndex = lowPathIndex + ((highPathIndex - lowPathIndex) / 2u);
|
||||||
|
uint midTileIndex = _64.iTilePathInfo[midPathIndex].z;
|
||||||
|
if (tileIndex < midTileIndex)
|
||||||
|
{
|
||||||
|
highPathIndex = midPathIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lowPathIndex = midPathIndex;
|
||||||
|
if (tileIndex == midTileIndex)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iteration++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint pathIndex = lowPathIndex;
|
||||||
|
uint4 pathInfo = _64.iTilePathInfo[pathIndex];
|
||||||
|
int2 packedTileRect = int2(pathInfo.xy);
|
||||||
|
int4 tileRect = int4((packedTileRect.x << 16) >> 16, packedTileRect.x >> 16, (packedTileRect.y << 16) >> 16, packedTileRect.y >> 16);
|
||||||
|
uint tileOffset = tileIndex - pathInfo.z;
|
||||||
|
uint tileWidth = uint(tileRect.z - tileRect.x);
|
||||||
|
int2 tileCoords = tileRect.xy + int2(int(tileOffset % tileWidth), int(tileOffset / tileWidth));
|
||||||
|
_148.iTiles[(tileIndex * 4u) + 0u] = 4294967295u;
|
||||||
|
_148.iTiles[(tileIndex * 4u) + 1u] = 4294967295u;
|
||||||
|
_148.iTiles[(tileIndex * 4u) + 2u] = 16777215u;
|
||||||
|
_148.iTiles[(tileIndex * 4u) + 3u] = pathInfo.w;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
#include <metal_atomic>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bMicrolines
|
||||||
|
{
|
||||||
|
uint4 iMicrolines[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bPoints
|
||||||
|
{
|
||||||
|
float2 iPoints[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bDiceMetadata
|
||||||
|
{
|
||||||
|
uint4 iDiceMetadata[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bInputIndices
|
||||||
|
{
|
||||||
|
uint2 iInputIndices[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bComputeIndirectParams
|
||||||
|
{
|
||||||
|
uint iComputeIndirectParams[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(64u, 1u, 1u);
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float2 getPoint(thread const uint& pointIndex, thread float2x2 uTransform, const device bPoints& v_194, thread float2 uTranslation)
|
||||||
|
{
|
||||||
|
return (uTransform * v_194.iPoints[pointIndex]) + uTranslation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float2 sampleCurve(thread const float4& baseline, thread const float4& ctrl, thread const float& t)
|
||||||
|
{
|
||||||
|
float2 p0 = baseline.xy;
|
||||||
|
float2 p1 = ctrl.xy;
|
||||||
|
float2 p2 = ctrl.zw;
|
||||||
|
float2 p3 = baseline.zw;
|
||||||
|
float2 p0p1 = mix(p0, p1, float2(t));
|
||||||
|
float2 p1p2 = mix(p1, p2, float2(t));
|
||||||
|
float2 p2p3 = mix(p2, p3, float2(t));
|
||||||
|
float2 p0p1p2 = mix(p0p1, p1p2, float2(t));
|
||||||
|
float2 p1p2p3 = mix(p1p2, p2p3, float2(t));
|
||||||
|
return mix(p0p1p2, p1p2p3, float2(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float2 sampleLine(thread const float4& line, thread const float& t)
|
||||||
|
{
|
||||||
|
return mix(line.xy, line.zw, float2(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void emitMicroline(thread const float4& microlineSegment, thread const uint& pathIndex, thread const uint& outputMicrolineIndex, thread int uMaxMicrolineCount, device bMicrolines& v_76)
|
||||||
|
{
|
||||||
|
if (outputMicrolineIndex >= uint(uMaxMicrolineCount))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int4 microlineSubpixels = int4(round(fast::clamp(microlineSegment, float4(-32768.0), float4(32767.0)) * 256.0));
|
||||||
|
int4 microlinePixels = int4(floor(float4(microlineSubpixels) / float4(256.0)));
|
||||||
|
int4 microlineFractPixels = microlineSubpixels - (microlinePixels * int4(256));
|
||||||
|
v_76.iMicrolines[outputMicrolineIndex] = uint4((uint(microlinePixels.x) & 65535u) | (uint(microlinePixels.y) << uint(16)), (uint(microlinePixels.z) & 65535u) | (uint(microlinePixels.w) << uint(16)), ((uint(microlineFractPixels.x) | (uint(microlineFractPixels.y) << uint(8))) | (uint(microlineFractPixels.z) << uint(16))) | (uint(microlineFractPixels.w) << uint(24)), pathIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void main0(constant int& uMaxMicrolineCount [[buffer(0)]], constant int& uLastBatchSegmentIndex [[buffer(5)]], constant int& uPathCount [[buffer(6)]], constant float2x2& uTransform [[buffer(2)]], constant float2& uTranslation [[buffer(4)]], device bMicrolines& v_76 [[buffer(1)]], const device bPoints& v_194 [[buffer(3)]], const device bDiceMetadata& _253 [[buffer(7)]], const device bInputIndices& _300 [[buffer(8)]], device bComputeIndirectParams& _439 [[buffer(9)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]])
|
||||||
|
{
|
||||||
|
uint batchSegmentIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (batchSegmentIndex >= uint(uLastBatchSegmentIndex))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint lowPathIndex = 0u;
|
||||||
|
uint highPathIndex = uint(uPathCount);
|
||||||
|
int iteration = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
bool _234 = iteration < 1024;
|
||||||
|
bool _241;
|
||||||
|
if (_234)
|
||||||
|
{
|
||||||
|
_241 = (lowPathIndex + 1u) < highPathIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_241 = _234;
|
||||||
|
}
|
||||||
|
if (_241)
|
||||||
|
{
|
||||||
|
uint midPathIndex = lowPathIndex + ((highPathIndex - lowPathIndex) / 2u);
|
||||||
|
uint midBatchSegmentIndex = _253.iDiceMetadata[midPathIndex].z;
|
||||||
|
if (batchSegmentIndex < midBatchSegmentIndex)
|
||||||
|
{
|
||||||
|
highPathIndex = midPathIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lowPathIndex = midPathIndex;
|
||||||
|
if (batchSegmentIndex == midBatchSegmentIndex)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iteration++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint batchPathIndex = lowPathIndex;
|
||||||
|
uint4 diceMetadata = _253.iDiceMetadata[batchPathIndex];
|
||||||
|
uint firstGlobalSegmentIndexInPath = diceMetadata.y;
|
||||||
|
uint firstBatchSegmentIndexInPath = diceMetadata.z;
|
||||||
|
uint globalSegmentIndex = (batchSegmentIndex - firstBatchSegmentIndexInPath) + firstGlobalSegmentIndexInPath;
|
||||||
|
uint2 inputIndices = _300.iInputIndices[globalSegmentIndex];
|
||||||
|
uint fromPointIndex = inputIndices.x;
|
||||||
|
uint flagsPathIndex = inputIndices.y;
|
||||||
|
uint toPointIndex = fromPointIndex;
|
||||||
|
if ((flagsPathIndex & 1073741824u) != 0u)
|
||||||
|
{
|
||||||
|
toPointIndex += 3u;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((flagsPathIndex & 2147483648u) != 0u)
|
||||||
|
{
|
||||||
|
toPointIndex += 2u;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toPointIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint param = fromPointIndex;
|
||||||
|
uint param_1 = toPointIndex;
|
||||||
|
float4 baseline = float4(getPoint(param, uTransform, v_194, uTranslation), getPoint(param_1, uTransform, v_194, uTranslation));
|
||||||
|
float4 ctrl = float4(0.0);
|
||||||
|
bool isCurve = (flagsPathIndex & 3221225472u) != 0u;
|
||||||
|
float segmentCountF;
|
||||||
|
if (isCurve)
|
||||||
|
{
|
||||||
|
uint param_2 = fromPointIndex + 1u;
|
||||||
|
float2 ctrl0 = getPoint(param_2, uTransform, v_194, uTranslation);
|
||||||
|
if ((flagsPathIndex & 2147483648u) != 0u)
|
||||||
|
{
|
||||||
|
float2 ctrl0_2 = ctrl0 * float2(2.0);
|
||||||
|
ctrl = (baseline + (ctrl0 * float2(2.0)).xyxy) * float4(0.3333333432674407958984375);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint param_3 = fromPointIndex + 2u;
|
||||||
|
ctrl = float4(ctrl0, getPoint(param_3, uTransform, v_194, uTranslation));
|
||||||
|
}
|
||||||
|
float2 bound = float2(6.0) * fast::max(abs((ctrl.zw - (ctrl.xy * 2.0)) + baseline.xy), abs((baseline.zw - (ctrl.zw * 2.0)) + ctrl.xy));
|
||||||
|
segmentCountF = sqrt(length(bound) / 2.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segmentCountF = length(baseline.zw - baseline.xy) / 16.0;
|
||||||
|
}
|
||||||
|
int segmentCount = max(int(ceil(segmentCountF)), 1);
|
||||||
|
uint _444 = atomic_fetch_add_explicit((device atomic_uint*)&_439.iComputeIndirectParams[3], uint(segmentCount), memory_order_relaxed);
|
||||||
|
uint firstOutputMicrolineIndex = _444;
|
||||||
|
float prevT = 0.0;
|
||||||
|
float2 prevPoint = baseline.xy;
|
||||||
|
float2 nextPoint;
|
||||||
|
for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
|
||||||
|
{
|
||||||
|
float nextT = float(segmentIndex + 1) / float(segmentCount);
|
||||||
|
if (isCurve)
|
||||||
|
{
|
||||||
|
float4 param_4 = baseline;
|
||||||
|
float4 param_5 = ctrl;
|
||||||
|
float param_6 = nextT;
|
||||||
|
nextPoint = sampleCurve(param_4, param_5, param_6);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float4 param_7 = baseline;
|
||||||
|
float param_8 = nextT;
|
||||||
|
nextPoint = sampleLine(param_7, param_8);
|
||||||
|
}
|
||||||
|
float4 param_9 = float4(prevPoint, nextPoint);
|
||||||
|
uint param_10 = batchPathIndex;
|
||||||
|
uint param_11 = firstOutputMicrolineIndex + uint(segmentIndex);
|
||||||
|
emitMicroline(param_9, param_10, param_11, uMaxMicrolineCount, v_76);
|
||||||
|
prevT = nextT;
|
||||||
|
prevPoint = nextPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bFills
|
||||||
|
{
|
||||||
|
uint iFills[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bAlphaTiles
|
||||||
|
{
|
||||||
|
uint iAlphaTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bTiles
|
||||||
|
{
|
||||||
|
uint iTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(16u, 4u, 1u);
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 computeCoverage(thread const float2& from, thread const float2& to, thread const texture2d<float> areaLUT, thread const sampler areaLUTSmplr)
|
||||||
|
{
|
||||||
|
float2 left = select(to, from, bool2(from.x < to.x));
|
||||||
|
float2 right = select(from, to, bool2(from.x < to.x));
|
||||||
|
float2 window = fast::clamp(float2(from.x, to.x), float2(-0.5), float2(0.5));
|
||||||
|
float offset = mix(window.x, window.y, 0.5) - left.x;
|
||||||
|
float t = offset / (right.x - left.x);
|
||||||
|
float y = mix(left.y, right.y, t);
|
||||||
|
float d = (right.y - left.y) / (right.x - left.x);
|
||||||
|
float dX = window.x - window.y;
|
||||||
|
return areaLUT.sample(areaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0)), level(0.0)) * dX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 accumulateCoverageForFillList(thread int& fillIndex, thread const int2& tileSubCoord, const device bFills& v_148, thread texture2d<float> uAreaLUT, thread const sampler uAreaLUTSmplr)
|
||||||
|
{
|
||||||
|
float2 tileFragCoord = float2(tileSubCoord) + float2(0.5);
|
||||||
|
float4 coverages = float4(0.0);
|
||||||
|
int iteration = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint fillFrom = v_148.iFills[(fillIndex * 3) + 0];
|
||||||
|
uint fillTo = v_148.iFills[(fillIndex * 3) + 1];
|
||||||
|
float4 lineSegment = float4(float(fillFrom & 65535u), float(fillFrom >> uint(16)), float(fillTo & 65535u), float(fillTo >> uint(16))) / float4(256.0);
|
||||||
|
lineSegment -= tileFragCoord.xyxy;
|
||||||
|
float2 param = lineSegment.xy;
|
||||||
|
float2 param_1 = lineSegment.zw;
|
||||||
|
coverages += computeCoverage(param, param_1, uAreaLUT, uAreaLUTSmplr);
|
||||||
|
fillIndex = int(v_148.iFills[(fillIndex * 3) + 2]);
|
||||||
|
iteration++;
|
||||||
|
} while ((fillIndex >= 0) && (iteration < 1024));
|
||||||
|
return coverages;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
int2 computeTileCoord(thread const uint& alphaTileIndex, thread uint3& gl_LocalInvocationID)
|
||||||
|
{
|
||||||
|
uint x = alphaTileIndex & 255u;
|
||||||
|
uint y = (alphaTileIndex >> 8u) & (255u + (((alphaTileIndex >> 16u) & 255u) << 8u));
|
||||||
|
return (int2(16, 4) * int2(int(x), int(y))) + int2(gl_LocalInvocationID.xy);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void main0(constant int2& uAlphaTileRange [[buffer(1)]], const device bFills& v_148 [[buffer(0)]], const device bAlphaTiles& _284 [[buffer(2)]], device bTiles& _294 [[buffer(3)]], texture2d<float> uAreaLUT [[texture(0)]], texture2d<float, access::read_write> uDest [[texture(1)]], sampler uAreaLUTSmplr [[sampler(0)]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]])
|
||||||
|
{
|
||||||
|
int2 tileSubCoord = int2(gl_LocalInvocationID.xy) * int2(1, 4);
|
||||||
|
uint batchAlphaTileIndex = gl_WorkGroupID.x | (gl_WorkGroupID.y << uint(15));
|
||||||
|
uint alphaTileIndex = batchAlphaTileIndex + uint(uAlphaTileRange.x);
|
||||||
|
if (alphaTileIndex >= uint(uAlphaTileRange.y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint tileIndex = _284.iAlphaTiles[(batchAlphaTileIndex * 2u) + 0u];
|
||||||
|
if ((int(_294.iTiles[(tileIndex * 4u) + 2u] << uint(8)) >> 8) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int fillIndex = int(_294.iTiles[(tileIndex * 4u) + 1u]);
|
||||||
|
int backdrop = int(_294.iTiles[(tileIndex * 4u) + 3u]) >> 24;
|
||||||
|
float4 coverages = float4(float(backdrop));
|
||||||
|
int param = fillIndex;
|
||||||
|
int2 param_1 = tileSubCoord;
|
||||||
|
float4 _334 = accumulateCoverageForFillList(param, param_1, v_148, uAreaLUT, uAreaLUTSmplr);
|
||||||
|
coverages += _334;
|
||||||
|
coverages = fast::clamp(abs(coverages), float4(0.0), float4(1.0));
|
||||||
|
int clipTileIndex = int(_284.iAlphaTiles[(batchAlphaTileIndex * 2u) + 1u]);
|
||||||
|
if (clipTileIndex >= 0)
|
||||||
|
{
|
||||||
|
uint param_2 = uint(clipTileIndex);
|
||||||
|
coverages = fast::min(coverages, uDest.read(uint2(computeTileCoord(param_2, gl_LocalInvocationID))));
|
||||||
|
}
|
||||||
|
uint param_3 = alphaTileIndex;
|
||||||
|
uDest.write(coverages, uint2(computeTileCoord(param_3, gl_LocalInvocationID)));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
#include <metal_atomic>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bBackdrops
|
||||||
|
{
|
||||||
|
int iBackdrops[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bDrawMetadata
|
||||||
|
{
|
||||||
|
uint4 iDrawMetadata[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bClipMetadata
|
||||||
|
{
|
||||||
|
uint4 iClipMetadata[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bDrawTiles
|
||||||
|
{
|
||||||
|
uint iDrawTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bClipTiles
|
||||||
|
{
|
||||||
|
uint iClipTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bIndirectDrawParams
|
||||||
|
{
|
||||||
|
uint iIndirectDrawParams[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bAlphaTiles
|
||||||
|
{
|
||||||
|
uint iAlphaTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bZBuffer
|
||||||
|
{
|
||||||
|
int iZBuffer[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bFirstTileMap
|
||||||
|
{
|
||||||
|
int iFirstTileMap[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(64u, 1u, 1u);
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
uint calculateTileIndex(thread const uint& bufferOffset, thread const uint4& tileRect, thread const uint2& tileCoord)
|
||||||
|
{
|
||||||
|
return (bufferOffset + (tileCoord.y * (tileRect.z - tileRect.x))) + tileCoord.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void main0(constant int& uColumnCount [[buffer(0)]], constant int& uFirstAlphaTileIndex [[buffer(8)]], constant int2& uFramebufferTileSize [[buffer(9)]], const device bBackdrops& _59 [[buffer(1)]], const device bDrawMetadata& _85 [[buffer(2)]], const device bClipMetadata& _126 [[buffer(3)]], device bDrawTiles& _175 [[buffer(4)]], device bClipTiles& _252 [[buffer(5)]], device bIndirectDrawParams& _303 [[buffer(6)]], device bAlphaTiles& _310 [[buffer(7)]], device bZBuffer& _381 [[buffer(10)]], device bFirstTileMap& _398 [[buffer(11)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]])
|
||||||
|
{
|
||||||
|
uint columnIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (int(columnIndex) >= uColumnCount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int currentBackdrop = _59.iBackdrops[(columnIndex * 3u) + 0u];
|
||||||
|
int tileX = _59.iBackdrops[(columnIndex * 3u) + 1u];
|
||||||
|
uint drawPathIndex = uint(_59.iBackdrops[(columnIndex * 3u) + 2u]);
|
||||||
|
uint4 drawTileRect = _85.iDrawMetadata[(drawPathIndex * 3u) + 0u];
|
||||||
|
uint4 drawOffsets = _85.iDrawMetadata[(drawPathIndex * 3u) + 1u];
|
||||||
|
uint2 drawTileSize = drawTileRect.zw - drawTileRect.xy;
|
||||||
|
uint drawTileBufferOffset = drawOffsets.x;
|
||||||
|
bool zWrite = drawOffsets.z != 0u;
|
||||||
|
int clipPathIndex = int(drawOffsets.w);
|
||||||
|
uint4 clipTileRect = uint4(0u);
|
||||||
|
uint4 clipOffsets = uint4(0u);
|
||||||
|
if (clipPathIndex >= 0)
|
||||||
|
{
|
||||||
|
clipTileRect = _126.iClipMetadata[(clipPathIndex * 2) + 0];
|
||||||
|
clipOffsets = _126.iClipMetadata[(clipPathIndex * 2) + 1];
|
||||||
|
}
|
||||||
|
uint clipTileBufferOffset = clipOffsets.x;
|
||||||
|
uint clipBackdropOffset = clipOffsets.y;
|
||||||
|
for (uint tileY = 0u; tileY < drawTileSize.y; tileY++)
|
||||||
|
{
|
||||||
|
uint2 drawTileCoord = uint2(uint(tileX), tileY);
|
||||||
|
uint param = drawTileBufferOffset;
|
||||||
|
uint4 param_1 = drawTileRect;
|
||||||
|
uint2 param_2 = drawTileCoord;
|
||||||
|
uint drawTileIndex = calculateTileIndex(param, param_1, param_2);
|
||||||
|
int drawAlphaTileIndex = -1;
|
||||||
|
int clipAlphaTileIndex = -1;
|
||||||
|
int drawFirstFillIndex = int(_175.iDrawTiles[(drawTileIndex * 4u) + 1u]);
|
||||||
|
int drawBackdropDelta = int(_175.iDrawTiles[(drawTileIndex * 4u) + 2u]) >> 24;
|
||||||
|
uint drawTileWord = _175.iDrawTiles[(drawTileIndex * 4u) + 3u] & 16777215u;
|
||||||
|
int drawTileBackdrop = currentBackdrop;
|
||||||
|
bool haveDrawAlphaMask = drawFirstFillIndex >= 0;
|
||||||
|
bool needNewAlphaTile = haveDrawAlphaMask;
|
||||||
|
if (clipPathIndex >= 0)
|
||||||
|
{
|
||||||
|
uint2 tileCoord = drawTileCoord + drawTileRect.xy;
|
||||||
|
if (all(bool4(tileCoord >= clipTileRect.xy, tileCoord < clipTileRect.zw)))
|
||||||
|
{
|
||||||
|
uint2 clipTileCoord = tileCoord - clipTileRect.xy;
|
||||||
|
uint param_3 = clipTileBufferOffset;
|
||||||
|
uint4 param_4 = clipTileRect;
|
||||||
|
uint2 param_5 = clipTileCoord;
|
||||||
|
uint clipTileIndex = calculateTileIndex(param_3, param_4, param_5);
|
||||||
|
int thisClipAlphaTileIndex = int(_252.iClipTiles[(clipTileIndex * 4u) + 2u] << uint(8)) >> 8;
|
||||||
|
uint clipTileWord = _252.iClipTiles[(clipTileIndex * 4u) + 3u];
|
||||||
|
int clipTileBackdrop = int(clipTileWord) >> 24;
|
||||||
|
if (thisClipAlphaTileIndex >= 0)
|
||||||
|
{
|
||||||
|
if (haveDrawAlphaMask)
|
||||||
|
{
|
||||||
|
clipAlphaTileIndex = thisClipAlphaTileIndex;
|
||||||
|
needNewAlphaTile = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (drawTileBackdrop != 0)
|
||||||
|
{
|
||||||
|
drawAlphaTileIndex = thisClipAlphaTileIndex;
|
||||||
|
clipAlphaTileIndex = -1;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drawAlphaTileIndex = -1;
|
||||||
|
clipAlphaTileIndex = -1;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (clipTileBackdrop == 0)
|
||||||
|
{
|
||||||
|
drawTileBackdrop = 0;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
needNewAlphaTile = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drawTileBackdrop = 0;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needNewAlphaTile)
|
||||||
|
{
|
||||||
|
uint _306 = atomic_fetch_add_explicit((device atomic_uint*)&_303.iIndirectDrawParams[4], 1u, memory_order_relaxed);
|
||||||
|
uint drawBatchAlphaTileIndex = _306;
|
||||||
|
_310.iAlphaTiles[(drawBatchAlphaTileIndex * 2u) + 0u] = drawTileIndex;
|
||||||
|
_310.iAlphaTiles[(drawBatchAlphaTileIndex * 2u) + 1u] = uint(clipAlphaTileIndex);
|
||||||
|
drawAlphaTileIndex = int(drawBatchAlphaTileIndex) + uFirstAlphaTileIndex;
|
||||||
|
}
|
||||||
|
_175.iDrawTiles[(drawTileIndex * 4u) + 2u] = (uint(drawAlphaTileIndex) & 16777215u) | (uint(drawBackdropDelta) << uint(24));
|
||||||
|
_175.iDrawTiles[(drawTileIndex * 4u) + 3u] = drawTileWord | (uint(drawTileBackdrop) << uint(24));
|
||||||
|
int2 tileCoord_1 = int2(tileX, int(tileY)) + int2(drawTileRect.xy);
|
||||||
|
int tileMapIndex = (tileCoord_1.y * uFramebufferTileSize.x) + tileCoord_1.x;
|
||||||
|
if ((zWrite && (drawTileBackdrop != 0)) && (drawAlphaTileIndex < 0))
|
||||||
|
{
|
||||||
|
int _386 = atomic_fetch_max_explicit((device atomic_int*)&_381.iZBuffer[tileMapIndex], int(drawTileIndex), memory_order_relaxed);
|
||||||
|
}
|
||||||
|
if ((drawTileBackdrop != 0) || (drawAlphaTileIndex >= 0))
|
||||||
|
{
|
||||||
|
int _403 = atomic_exchange_explicit((device atomic_int*)&_398.iFirstTileMap[tileMapIndex], int(drawTileIndex), memory_order_relaxed);
|
||||||
|
int nextTileIndex = _403;
|
||||||
|
_175.iDrawTiles[(drawTileIndex * 4u) + 0u] = uint(nextTileIndex);
|
||||||
|
}
|
||||||
|
currentBackdrop += drawBackdropDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bFirstTileMap
|
||||||
|
{
|
||||||
|
int iFirstTileMap[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bTiles
|
||||||
|
{
|
||||||
|
uint iTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bZBuffer
|
||||||
|
{
|
||||||
|
int iZBuffer[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(64u, 1u, 1u);
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
int getFirst(thread const uint& globalTileIndex, device bFirstTileMap& v_26)
|
||||||
|
{
|
||||||
|
return v_26.iFirstTileMap[globalTileIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
int getNextTile(thread const int& tileIndex, device bTiles& v_37)
|
||||||
|
{
|
||||||
|
return int(v_37.iTiles[(tileIndex * 4) + 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void setNextTile(thread const int& tileIndex, thread const int& newNextTileIndex, device bTiles& v_37)
|
||||||
|
{
|
||||||
|
v_37.iTiles[(tileIndex * 4) + 0] = uint(newNextTileIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void main0(constant int& uTileCount [[buffer(2)]], device bFirstTileMap& v_26 [[buffer(0)]], device bTiles& v_37 [[buffer(1)]], const device bZBuffer& _76 [[buffer(3)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]])
|
||||||
|
{
|
||||||
|
uint globalTileIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (globalTileIndex >= uint(uTileCount))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int zValue = _76.iZBuffer[globalTileIndex];
|
||||||
|
uint param = globalTileIndex;
|
||||||
|
int unsortedFirstTileIndex = getFirst(param, v_26);
|
||||||
|
int sortedFirstTileIndex = -1;
|
||||||
|
while (unsortedFirstTileIndex >= 0)
|
||||||
|
{
|
||||||
|
int currentTileIndex = unsortedFirstTileIndex;
|
||||||
|
int param_1 = currentTileIndex;
|
||||||
|
unsortedFirstTileIndex = getNextTile(param_1, v_37);
|
||||||
|
if (currentTileIndex >= zValue)
|
||||||
|
{
|
||||||
|
int prevTrialTileIndex = -1;
|
||||||
|
int trialTileIndex = sortedFirstTileIndex;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if ((trialTileIndex < 0) || (currentTileIndex < trialTileIndex))
|
||||||
|
{
|
||||||
|
if (prevTrialTileIndex < 0)
|
||||||
|
{
|
||||||
|
int param_2 = currentTileIndex;
|
||||||
|
int param_3 = sortedFirstTileIndex;
|
||||||
|
setNextTile(param_2, param_3, v_37);
|
||||||
|
sortedFirstTileIndex = currentTileIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int param_4 = currentTileIndex;
|
||||||
|
int param_5 = trialTileIndex;
|
||||||
|
setNextTile(param_4, param_5, v_37);
|
||||||
|
int param_6 = prevTrialTileIndex;
|
||||||
|
int param_7 = currentTileIndex;
|
||||||
|
setNextTile(param_6, param_7, v_37);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevTrialTileIndex = trialTileIndex;
|
||||||
|
int param_8 = trialTileIndex;
|
||||||
|
trialTileIndex = getNextTile(param_8, v_37);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v_26.iFirstTileMap[globalTileIndex] = sortedFirstTileIndex;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,737 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct bFirstTileMap
|
||||||
|
{
|
||||||
|
int iFirstTileMap[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bTiles
|
||||||
|
{
|
||||||
|
uint iTiles[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(16u, 4u, 1u);
|
||||||
|
|
||||||
|
constant float3 _1082 = {};
|
||||||
|
|
||||||
|
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
|
||||||
|
template<typename Tx, typename Ty>
|
||||||
|
inline Tx mod(Tx x, Ty y)
|
||||||
|
{
|
||||||
|
return x - y * floor(x / y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
int2 toImageCoords(thread const int2& coords, thread float2 uFramebufferSize)
|
||||||
|
{
|
||||||
|
return int2(coords.x, int(uFramebufferSize.y - float(coords.y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 fetchUnscaled(thread const texture2d<float> srcTexture, thread const sampler srcTextureSmplr, thread const float2& scale, thread const float2& originCoord, thread const int& entry)
|
||||||
|
{
|
||||||
|
return srcTexture.sample(srcTextureSmplr, (((originCoord + float2(0.5)) + float2(float(entry), 0.0)) * scale), level(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void computeTileVaryings(thread const float2& position, thread const int& colorEntry, thread const texture2d<float> textureMetadata, thread const sampler textureMetadataSmplr, thread const int2& textureMetadataSize, thread float2& outColorTexCoord0, thread float4& outBaseColor, thread float4& outFilterParams0, thread float4& outFilterParams1, thread float4& outFilterParams2, thread int& outCtrl)
|
||||||
|
{
|
||||||
|
float2 metadataScale = float2(1.0) / float2(textureMetadataSize);
|
||||||
|
float2 metadataEntryCoord = float2(float((colorEntry % 128) * 8), float(colorEntry / 128));
|
||||||
|
float2 param = metadataScale;
|
||||||
|
float2 param_1 = metadataEntryCoord;
|
||||||
|
int param_2 = 0;
|
||||||
|
float4 colorTexMatrix0 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param, param_1, param_2);
|
||||||
|
float2 param_3 = metadataScale;
|
||||||
|
float2 param_4 = metadataEntryCoord;
|
||||||
|
int param_5 = 1;
|
||||||
|
float4 colorTexOffsets = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_3, param_4, param_5);
|
||||||
|
float2 param_6 = metadataScale;
|
||||||
|
float2 param_7 = metadataEntryCoord;
|
||||||
|
int param_8 = 2;
|
||||||
|
float4 baseColor = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_6, param_7, param_8);
|
||||||
|
float2 param_9 = metadataScale;
|
||||||
|
float2 param_10 = metadataEntryCoord;
|
||||||
|
int param_11 = 3;
|
||||||
|
float4 filterParams0 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_9, param_10, param_11);
|
||||||
|
float2 param_12 = metadataScale;
|
||||||
|
float2 param_13 = metadataEntryCoord;
|
||||||
|
int param_14 = 4;
|
||||||
|
float4 filterParams1 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_12, param_13, param_14);
|
||||||
|
float2 param_15 = metadataScale;
|
||||||
|
float2 param_16 = metadataEntryCoord;
|
||||||
|
int param_17 = 5;
|
||||||
|
float4 filterParams2 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_15, param_16, param_17);
|
||||||
|
float2 param_18 = metadataScale;
|
||||||
|
float2 param_19 = metadataEntryCoord;
|
||||||
|
int param_20 = 6;
|
||||||
|
float4 extra = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_18, param_19, param_20);
|
||||||
|
outColorTexCoord0 = (float2x2(float2(colorTexMatrix0.xy), float2(colorTexMatrix0.zw)) * position) + colorTexOffsets.xy;
|
||||||
|
outBaseColor = baseColor;
|
||||||
|
outFilterParams0 = filterParams0;
|
||||||
|
outFilterParams1 = filterParams1;
|
||||||
|
outFilterParams2 = filterParams2;
|
||||||
|
outCtrl = int(extra.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float sampleMask(thread const float& maskAlpha, thread const texture2d<float> maskTexture, thread const sampler maskTextureSmplr, thread const float2& maskTextureSize, thread const float3& maskTexCoord, thread const int& maskCtrl)
|
||||||
|
{
|
||||||
|
if (maskCtrl == 0)
|
||||||
|
{
|
||||||
|
return maskAlpha;
|
||||||
|
}
|
||||||
|
int2 maskTexCoordI = int2(floor(maskTexCoord.xy));
|
||||||
|
float4 texel = maskTexture.sample(maskTextureSmplr, ((float2(maskTexCoordI / int2(1, 4)) + float2(0.5)) / maskTextureSize), level(0.0));
|
||||||
|
float coverage = texel[maskTexCoordI.y % 4] + maskTexCoord.z;
|
||||||
|
if ((maskCtrl & 1) != 0)
|
||||||
|
{
|
||||||
|
coverage = abs(coverage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coverage = 1.0 - abs(1.0 - mod(coverage, 2.0));
|
||||||
|
}
|
||||||
|
return fast::min(maskAlpha, coverage);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 filterRadialGradient(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTextureSize, thread const float2& fragCoord, thread const float2& framebufferSize, thread const float4& filterParams0, thread const float4& filterParams1)
|
||||||
|
{
|
||||||
|
float2 lineFrom = filterParams0.xy;
|
||||||
|
float2 lineVector = filterParams0.zw;
|
||||||
|
float2 radii = filterParams1.xy;
|
||||||
|
float2 uvOrigin = filterParams1.zw;
|
||||||
|
float2 dP = colorTexCoord - lineFrom;
|
||||||
|
float2 dC = lineVector;
|
||||||
|
float dR = radii.y - radii.x;
|
||||||
|
float a = dot(dC, dC) - (dR * dR);
|
||||||
|
float b = dot(dP, dC) + (radii.x * dR);
|
||||||
|
float c = dot(dP, dP) - (radii.x * radii.x);
|
||||||
|
float discrim = (b * b) - (a * c);
|
||||||
|
float4 color = float4(0.0);
|
||||||
|
if (abs(discrim) >= 9.9999997473787516355514526367188e-06)
|
||||||
|
{
|
||||||
|
float2 ts = float2((float2(1.0, -1.0) * sqrt(discrim)) + float2(b)) / float2(a);
|
||||||
|
if (ts.x > ts.y)
|
||||||
|
{
|
||||||
|
ts = ts.yx;
|
||||||
|
}
|
||||||
|
float _595;
|
||||||
|
if (ts.x >= 0.0)
|
||||||
|
{
|
||||||
|
_595 = ts.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_595 = ts.y;
|
||||||
|
}
|
||||||
|
float t = _595;
|
||||||
|
color = colorTexture.sample(colorTextureSmplr, (uvOrigin + float2(fast::clamp(t, 0.0, 1.0), 0.0)), level(0.0));
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 filterBlur(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1)
|
||||||
|
{
|
||||||
|
float2 srcOffsetScale = filterParams0.xy / colorTextureSize;
|
||||||
|
int support = int(filterParams0.z);
|
||||||
|
float3 gaussCoeff = filterParams1.xyz;
|
||||||
|
float gaussSum = gaussCoeff.x;
|
||||||
|
float4 color = colorTexture.sample(colorTextureSmplr, colorTexCoord, level(0.0)) * gaussCoeff.x;
|
||||||
|
float2 _640 = gaussCoeff.xy * gaussCoeff.yz;
|
||||||
|
gaussCoeff = float3(_640.x, _640.y, gaussCoeff.z);
|
||||||
|
for (int i = 1; i <= support; i += 2)
|
||||||
|
{
|
||||||
|
float gaussPartialSum = gaussCoeff.x;
|
||||||
|
float2 _660 = gaussCoeff.xy * gaussCoeff.yz;
|
||||||
|
gaussCoeff = float3(_660.x, _660.y, gaussCoeff.z);
|
||||||
|
gaussPartialSum += gaussCoeff.x;
|
||||||
|
float2 srcOffset = srcOffsetScale * (float(i) + (gaussCoeff.x / gaussPartialSum));
|
||||||
|
color += ((colorTexture.sample(colorTextureSmplr, (colorTexCoord - srcOffset), level(0.0)) + colorTexture.sample(colorTextureSmplr, (colorTexCoord + srcOffset), level(0.0))) * gaussPartialSum);
|
||||||
|
gaussSum += (2.0 * gaussPartialSum);
|
||||||
|
float2 _700 = gaussCoeff.xy * gaussCoeff.yz;
|
||||||
|
gaussCoeff = float3(_700.x, _700.y, gaussCoeff.z);
|
||||||
|
}
|
||||||
|
return color / float4(gaussSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float filterTextSample1Tap(thread const float& offset, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord)
|
||||||
|
{
|
||||||
|
return colorTexture.sample(colorTextureSmplr, (colorTexCoord + float2(offset, 0.0)), level(0.0)).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord, thread const float4& kernel0, thread const float& onePixel)
|
||||||
|
{
|
||||||
|
bool wide = kernel0.x > 0.0;
|
||||||
|
float _276;
|
||||||
|
if (wide)
|
||||||
|
{
|
||||||
|
float param = (-4.0) * onePixel;
|
||||||
|
float2 param_1 = colorTexCoord;
|
||||||
|
_276 = filterTextSample1Tap(param, colorTexture, colorTextureSmplr, param_1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_276 = 0.0;
|
||||||
|
}
|
||||||
|
float param_2 = (-3.0) * onePixel;
|
||||||
|
float2 param_3 = colorTexCoord;
|
||||||
|
float param_4 = (-2.0) * onePixel;
|
||||||
|
float2 param_5 = colorTexCoord;
|
||||||
|
float param_6 = (-1.0) * onePixel;
|
||||||
|
float2 param_7 = colorTexCoord;
|
||||||
|
outAlphaLeft = float4(_276, filterTextSample1Tap(param_2, colorTexture, colorTextureSmplr, param_3), filterTextSample1Tap(param_4, colorTexture, colorTextureSmplr, param_5), filterTextSample1Tap(param_6, colorTexture, colorTextureSmplr, param_7));
|
||||||
|
float param_8 = 0.0;
|
||||||
|
float2 param_9 = colorTexCoord;
|
||||||
|
outAlphaCenter = filterTextSample1Tap(param_8, colorTexture, colorTextureSmplr, param_9);
|
||||||
|
float param_10 = 1.0 * onePixel;
|
||||||
|
float2 param_11 = colorTexCoord;
|
||||||
|
float param_12 = 2.0 * onePixel;
|
||||||
|
float2 param_13 = colorTexCoord;
|
||||||
|
float param_14 = 3.0 * onePixel;
|
||||||
|
float2 param_15 = colorTexCoord;
|
||||||
|
float _336;
|
||||||
|
if (wide)
|
||||||
|
{
|
||||||
|
float param_16 = 4.0 * onePixel;
|
||||||
|
float2 param_17 = colorTexCoord;
|
||||||
|
_336 = filterTextSample1Tap(param_16, colorTexture, colorTextureSmplr, param_17);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_336 = 0.0;
|
||||||
|
}
|
||||||
|
outAlphaRight = float4(filterTextSample1Tap(param_10, colorTexture, colorTextureSmplr, param_11), filterTextSample1Tap(param_12, colorTexture, colorTextureSmplr, param_13), filterTextSample1Tap(param_14, colorTexture, colorTextureSmplr, param_15), _336);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float filterTextConvolve7Tap(thread const float4& alpha0, thread const float3& alpha1, thread const float4& kernel0)
|
||||||
|
{
|
||||||
|
return dot(alpha0, kernel0) + dot(alpha1, kernel0.zyx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float filterTextGammaCorrectChannel(thread const float& bgColor, thread const float& fgColor, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr)
|
||||||
|
{
|
||||||
|
return gammaLUT.sample(gammaLUTSmplr, float2(fgColor, 1.0 - bgColor), level(0.0)).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 filterTextGammaCorrect(thread const float3& bgColor, thread const float3& fgColor, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr)
|
||||||
|
{
|
||||||
|
float param = bgColor.x;
|
||||||
|
float param_1 = fgColor.x;
|
||||||
|
float param_2 = bgColor.y;
|
||||||
|
float param_3 = fgColor.y;
|
||||||
|
float param_4 = bgColor.z;
|
||||||
|
float param_5 = fgColor.z;
|
||||||
|
return float3(filterTextGammaCorrectChannel(param, param_1, gammaLUT, gammaLUTSmplr), filterTextGammaCorrectChannel(param_2, param_3, gammaLUT, gammaLUTSmplr), filterTextGammaCorrectChannel(param_4, param_5, gammaLUT, gammaLUTSmplr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 filterText(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2)
|
||||||
|
{
|
||||||
|
float4 kernel0 = filterParams0;
|
||||||
|
float3 bgColor = filterParams1.xyz;
|
||||||
|
float3 fgColor = filterParams2.xyz;
|
||||||
|
bool gammaCorrectionEnabled = filterParams2.w != 0.0;
|
||||||
|
float3 alpha;
|
||||||
|
if (kernel0.w == 0.0)
|
||||||
|
{
|
||||||
|
alpha = colorTexture.sample(colorTextureSmplr, colorTexCoord, level(0.0)).xxx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float2 param_3 = colorTexCoord;
|
||||||
|
float4 param_4 = kernel0;
|
||||||
|
float param_5 = 1.0 / colorTextureSize.x;
|
||||||
|
float4 param;
|
||||||
|
float param_1;
|
||||||
|
float4 param_2;
|
||||||
|
filterTextSample9Tap(param, param_1, param_2, colorTexture, colorTextureSmplr, param_3, param_4, param_5);
|
||||||
|
float4 alphaLeft = param;
|
||||||
|
float alphaCenter = param_1;
|
||||||
|
float4 alphaRight = param_2;
|
||||||
|
float4 param_6 = alphaLeft;
|
||||||
|
float3 param_7 = float3(alphaCenter, alphaRight.xy);
|
||||||
|
float4 param_8 = kernel0;
|
||||||
|
float r = filterTextConvolve7Tap(param_6, param_7, param_8);
|
||||||
|
float4 param_9 = float4(alphaLeft.yzw, alphaCenter);
|
||||||
|
float3 param_10 = alphaRight.xyz;
|
||||||
|
float4 param_11 = kernel0;
|
||||||
|
float g = filterTextConvolve7Tap(param_9, param_10, param_11);
|
||||||
|
float4 param_12 = float4(alphaLeft.zw, alphaCenter, alphaRight.x);
|
||||||
|
float3 param_13 = alphaRight.yzw;
|
||||||
|
float4 param_14 = kernel0;
|
||||||
|
float b = filterTextConvolve7Tap(param_12, param_13, param_14);
|
||||||
|
alpha = float3(r, g, b);
|
||||||
|
}
|
||||||
|
if (gammaCorrectionEnabled)
|
||||||
|
{
|
||||||
|
float3 param_15 = bgColor;
|
||||||
|
float3 param_16 = alpha;
|
||||||
|
alpha = filterTextGammaCorrect(param_15, param_16, gammaLUT, gammaLUTSmplr);
|
||||||
|
}
|
||||||
|
return float4(mix(bgColor, fgColor, alpha), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 sampleColor(thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord)
|
||||||
|
{
|
||||||
|
return colorTexture.sample(colorTextureSmplr, colorTexCoord, level(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 filterNone(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr)
|
||||||
|
{
|
||||||
|
float2 param = colorTexCoord;
|
||||||
|
return sampleColor(colorTexture, colorTextureSmplr, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 filterColor(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize, thread const float2& fragCoord, thread const float2& framebufferSize, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2, thread const int& colorFilter)
|
||||||
|
{
|
||||||
|
switch (colorFilter)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
float2 param = colorTexCoord;
|
||||||
|
float2 param_1 = colorTextureSize;
|
||||||
|
float2 param_2 = fragCoord;
|
||||||
|
float2 param_3 = framebufferSize;
|
||||||
|
float4 param_4 = filterParams0;
|
||||||
|
float4 param_5 = filterParams1;
|
||||||
|
return filterRadialGradient(param, colorTexture, colorTextureSmplr, param_1, param_2, param_3, param_4, param_5);
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
float2 param_6 = colorTexCoord;
|
||||||
|
float2 param_7 = colorTextureSize;
|
||||||
|
float4 param_8 = filterParams0;
|
||||||
|
float4 param_9 = filterParams1;
|
||||||
|
return filterBlur(param_6, colorTexture, colorTextureSmplr, param_7, param_8, param_9);
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
float2 param_10 = colorTexCoord;
|
||||||
|
float2 param_11 = colorTextureSize;
|
||||||
|
float4 param_12 = filterParams0;
|
||||||
|
float4 param_13 = filterParams1;
|
||||||
|
float4 param_14 = filterParams2;
|
||||||
|
return filterText(param_10, colorTexture, colorTextureSmplr, gammaLUT, gammaLUTSmplr, param_11, param_12, param_13, param_14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float2 param_15 = colorTexCoord;
|
||||||
|
return filterNone(param_15, colorTexture, colorTextureSmplr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 combineColor0(thread const float4& destColor, thread const float4& srcColor, thread const int& op)
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
return float4(srcColor.xyz, srcColor.w * destColor.w);
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
return float4(destColor.xyz, srcColor.w * destColor.w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return destColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeScreen(thread const float3& destColor, thread const float3& srcColor)
|
||||||
|
{
|
||||||
|
return (destColor + srcColor) - (destColor * srcColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeSelect(thread const bool3& cond, thread const float3& ifTrue, thread const float3& ifFalse)
|
||||||
|
{
|
||||||
|
float _766;
|
||||||
|
if (cond.x)
|
||||||
|
{
|
||||||
|
_766 = ifTrue.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_766 = ifFalse.x;
|
||||||
|
}
|
||||||
|
float _777;
|
||||||
|
if (cond.y)
|
||||||
|
{
|
||||||
|
_777 = ifTrue.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_777 = ifFalse.y;
|
||||||
|
}
|
||||||
|
float _788;
|
||||||
|
if (cond.z)
|
||||||
|
{
|
||||||
|
_788 = ifTrue.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_788 = ifFalse.z;
|
||||||
|
}
|
||||||
|
return float3(_766, _777, _788);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeHardLight(thread const float3& destColor, thread const float3& srcColor)
|
||||||
|
{
|
||||||
|
float3 param = destColor;
|
||||||
|
float3 param_1 = (float3(2.0) * srcColor) - float3(1.0);
|
||||||
|
bool3 param_2 = srcColor <= float3(0.5);
|
||||||
|
float3 param_3 = (destColor * float3(2.0)) * srcColor;
|
||||||
|
float3 param_4 = compositeScreen(param, param_1);
|
||||||
|
return compositeSelect(param_2, param_3, param_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeColorDodge(thread const float3& destColor, thread const float3& srcColor)
|
||||||
|
{
|
||||||
|
bool3 destZero = destColor == float3(0.0);
|
||||||
|
bool3 srcOne = srcColor == float3(1.0);
|
||||||
|
bool3 param = srcOne;
|
||||||
|
float3 param_1 = float3(1.0);
|
||||||
|
float3 param_2 = destColor / (float3(1.0) - srcColor);
|
||||||
|
bool3 param_3 = destZero;
|
||||||
|
float3 param_4 = float3(0.0);
|
||||||
|
float3 param_5 = compositeSelect(param, param_1, param_2);
|
||||||
|
return compositeSelect(param_3, param_4, param_5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeSoftLight(thread const float3& destColor, thread const float3& srcColor)
|
||||||
|
{
|
||||||
|
bool3 param = destColor <= float3(0.25);
|
||||||
|
float3 param_1 = ((((float3(16.0) * destColor) - float3(12.0)) * destColor) + float3(4.0)) * destColor;
|
||||||
|
float3 param_2 = sqrt(destColor);
|
||||||
|
float3 darkenedDestColor = compositeSelect(param, param_1, param_2);
|
||||||
|
bool3 param_3 = srcColor <= float3(0.5);
|
||||||
|
float3 param_4 = destColor * (float3(1.0) - destColor);
|
||||||
|
float3 param_5 = darkenedDestColor - destColor;
|
||||||
|
float3 factor = compositeSelect(param_3, param_4, param_5);
|
||||||
|
return destColor + (((srcColor * 2.0) - float3(1.0)) * factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float compositeDivide(thread const float& num, thread const float& denom)
|
||||||
|
{
|
||||||
|
float _802;
|
||||||
|
if (denom != 0.0)
|
||||||
|
{
|
||||||
|
_802 = num / denom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_802 = 0.0;
|
||||||
|
}
|
||||||
|
return _802;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeRGBToHSL(thread const float3& rgb)
|
||||||
|
{
|
||||||
|
float v = fast::max(fast::max(rgb.x, rgb.y), rgb.z);
|
||||||
|
float xMin = fast::min(fast::min(rgb.x, rgb.y), rgb.z);
|
||||||
|
float c = v - xMin;
|
||||||
|
float l = mix(xMin, v, 0.5);
|
||||||
|
float3 _908;
|
||||||
|
if (rgb.x == v)
|
||||||
|
{
|
||||||
|
_908 = float3(0.0, rgb.yz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float3 _921;
|
||||||
|
if (rgb.y == v)
|
||||||
|
{
|
||||||
|
_921 = float3(2.0, rgb.zx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_921 = float3(4.0, rgb.xy);
|
||||||
|
}
|
||||||
|
_908 = _921;
|
||||||
|
}
|
||||||
|
float3 terms = _908;
|
||||||
|
float param = ((terms.x * c) + terms.y) - terms.z;
|
||||||
|
float param_1 = c;
|
||||||
|
float h = 1.0471975803375244140625 * compositeDivide(param, param_1);
|
||||||
|
float param_2 = c;
|
||||||
|
float param_3 = v;
|
||||||
|
float s = compositeDivide(param_2, param_3);
|
||||||
|
return float3(h, s, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeHSL(thread const float3& destColor, thread const float3& srcColor, thread const int& op)
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case 12:
|
||||||
|
{
|
||||||
|
return float3(srcColor.x, destColor.y, destColor.z);
|
||||||
|
}
|
||||||
|
case 13:
|
||||||
|
{
|
||||||
|
return float3(destColor.x, srcColor.y, destColor.z);
|
||||||
|
}
|
||||||
|
case 14:
|
||||||
|
{
|
||||||
|
return float3(srcColor.x, srcColor.y, destColor.z);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return float3(destColor.x, destColor.y, srcColor.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeHSLToRGB(thread const float3& hsl)
|
||||||
|
{
|
||||||
|
float a = hsl.y * fast::min(hsl.z, 1.0 - hsl.z);
|
||||||
|
float3 ks = mod(float3(0.0, 8.0, 4.0) + float3(hsl.x * 1.90985929965972900390625), float3(12.0));
|
||||||
|
return hsl.zzz - (fast::clamp(fast::min(ks - float3(3.0), float3(9.0) - ks), float3(-1.0), float3(1.0)) * a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float3 compositeRGB(thread const float3& destColor, thread const float3& srcColor, thread const int& op)
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
return destColor * srcColor;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
float3 param = destColor;
|
||||||
|
float3 param_1 = srcColor;
|
||||||
|
return compositeScreen(param, param_1);
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
float3 param_2 = srcColor;
|
||||||
|
float3 param_3 = destColor;
|
||||||
|
return compositeHardLight(param_2, param_3);
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
return fast::min(destColor, srcColor);
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
{
|
||||||
|
return fast::max(destColor, srcColor);
|
||||||
|
}
|
||||||
|
case 6:
|
||||||
|
{
|
||||||
|
float3 param_4 = destColor;
|
||||||
|
float3 param_5 = srcColor;
|
||||||
|
return compositeColorDodge(param_4, param_5);
|
||||||
|
}
|
||||||
|
case 7:
|
||||||
|
{
|
||||||
|
float3 param_6 = float3(1.0) - destColor;
|
||||||
|
float3 param_7 = float3(1.0) - srcColor;
|
||||||
|
return float3(1.0) - compositeColorDodge(param_6, param_7);
|
||||||
|
}
|
||||||
|
case 8:
|
||||||
|
{
|
||||||
|
float3 param_8 = destColor;
|
||||||
|
float3 param_9 = srcColor;
|
||||||
|
return compositeHardLight(param_8, param_9);
|
||||||
|
}
|
||||||
|
case 9:
|
||||||
|
{
|
||||||
|
float3 param_10 = destColor;
|
||||||
|
float3 param_11 = srcColor;
|
||||||
|
return compositeSoftLight(param_10, param_11);
|
||||||
|
}
|
||||||
|
case 10:
|
||||||
|
{
|
||||||
|
return abs(destColor - srcColor);
|
||||||
|
}
|
||||||
|
case 11:
|
||||||
|
{
|
||||||
|
return (destColor + srcColor) - ((float3(2.0) * destColor) * srcColor);
|
||||||
|
}
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
case 14:
|
||||||
|
case 15:
|
||||||
|
{
|
||||||
|
float3 param_12 = destColor;
|
||||||
|
float3 param_13 = srcColor;
|
||||||
|
float3 param_14 = compositeRGBToHSL(param_12);
|
||||||
|
float3 param_15 = compositeRGBToHSL(param_13);
|
||||||
|
int param_16 = op;
|
||||||
|
float3 param_17 = compositeHSL(param_14, param_15, param_16);
|
||||||
|
return compositeHSLToRGB(param_17);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return srcColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 composite(thread const float4& srcColor, thread const texture2d<float> destTexture, thread const sampler destTextureSmplr, thread const float2& destTextureSize, thread const float2& fragCoord, thread const int& op)
|
||||||
|
{
|
||||||
|
if (op == 0)
|
||||||
|
{
|
||||||
|
return srcColor;
|
||||||
|
}
|
||||||
|
float2 destTexCoord = fragCoord / destTextureSize;
|
||||||
|
float4 destColor = destTexture.sample(destTextureSmplr, destTexCoord, level(0.0));
|
||||||
|
float3 param = destColor.xyz;
|
||||||
|
float3 param_1 = srcColor.xyz;
|
||||||
|
int param_2 = op;
|
||||||
|
float3 blendedRGB = compositeRGB(param, param_1, param_2);
|
||||||
|
return float4(((srcColor.xyz * (srcColor.w * (1.0 - destColor.w))) + (blendedRGB * (srcColor.w * destColor.w))) + (destColor.xyz * (1.0 - srcColor.w)), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 calculateColor(thread const float2& fragCoord, thread const texture2d<float> colorTexture0, thread const sampler colorTexture0Smplr, thread const texture2d<float> maskTexture0, thread const sampler maskTexture0Smplr, thread const texture2d<float> destTexture, thread const sampler destTextureSmplr, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize0, thread const float2& maskTextureSize0, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2, thread const float2& framebufferSize, thread const int& ctrl, thread const float3& maskTexCoord0, thread const float2& colorTexCoord0, thread const float4& baseColor, thread const int& tileCtrl)
|
||||||
|
{
|
||||||
|
int maskCtrl0 = (tileCtrl >> 0) & 3;
|
||||||
|
float maskAlpha = 1.0;
|
||||||
|
float param = maskAlpha;
|
||||||
|
float2 param_1 = maskTextureSize0;
|
||||||
|
float3 param_2 = maskTexCoord0;
|
||||||
|
int param_3 = maskCtrl0;
|
||||||
|
maskAlpha = sampleMask(param, maskTexture0, maskTexture0Smplr, param_1, param_2, param_3);
|
||||||
|
float4 color = baseColor;
|
||||||
|
int color0Combine = (ctrl >> 6) & 3;
|
||||||
|
if (color0Combine != 0)
|
||||||
|
{
|
||||||
|
int color0Filter = (ctrl >> 4) & 3;
|
||||||
|
float2 param_4 = colorTexCoord0;
|
||||||
|
float2 param_5 = colorTextureSize0;
|
||||||
|
float2 param_6 = fragCoord;
|
||||||
|
float2 param_7 = framebufferSize;
|
||||||
|
float4 param_8 = filterParams0;
|
||||||
|
float4 param_9 = filterParams1;
|
||||||
|
float4 param_10 = filterParams2;
|
||||||
|
int param_11 = color0Filter;
|
||||||
|
float4 color0 = filterColor(param_4, colorTexture0, colorTexture0Smplr, gammaLUT, gammaLUTSmplr, param_5, param_6, param_7, param_8, param_9, param_10, param_11);
|
||||||
|
float4 param_12 = color;
|
||||||
|
float4 param_13 = color0;
|
||||||
|
int param_14 = color0Combine;
|
||||||
|
color = combineColor0(param_12, param_13, param_14);
|
||||||
|
}
|
||||||
|
color.w *= maskAlpha;
|
||||||
|
int compositeOp = (ctrl >> 8) & 15;
|
||||||
|
float4 param_15 = color;
|
||||||
|
float2 param_16 = framebufferSize;
|
||||||
|
float2 param_17 = fragCoord;
|
||||||
|
int param_18 = compositeOp;
|
||||||
|
color = composite(param_15, destTexture, destTextureSmplr, param_16, param_17, param_18);
|
||||||
|
float3 _1364 = color.xyz * color.w;
|
||||||
|
color = float4(_1364.x, _1364.y, _1364.z, color.w);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel void main0(constant int2& uFramebufferTileSize [[buffer(3)]], constant int& uLoadAction [[buffer(4)]], constant int2& uTextureMetadataSize [[buffer(7)]], constant float2& uFramebufferSize [[buffer(0)]], constant float2& uTileSize [[buffer(1)]], constant float4& uClearColor [[buffer(5)]], constant float2& uColorTextureSize0 [[buffer(8)]], constant float2& uMaskTextureSize0 [[buffer(9)]], const device bFirstTileMap& _1510 [[buffer(2)]], const device bTiles& _1603 [[buffer(6)]], texture2d<float, access::read_write> uDestImage [[texture(0)]], texture2d<float> uTextureMetadata [[texture(1)]], texture2d<float> uColorTexture0 [[texture(2)]], texture2d<float> uMaskTexture0 [[texture(3)]], texture2d<float> uDestTexture [[texture(4)]], texture2d<float> uGammaLUT [[texture(5)]], sampler uTextureMetadataSmplr [[sampler(0)]], sampler uColorTexture0Smplr [[sampler(1)]], sampler uMaskTexture0Smplr [[sampler(2)]], sampler uDestTextureSmplr [[sampler(3)]], sampler uGammaLUTSmplr [[sampler(4)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]])
|
||||||
|
{
|
||||||
|
int2 tileCoord = int2(gl_WorkGroupID.xy);
|
||||||
|
int2 firstTileSubCoord = int2(gl_LocalInvocationID.xy) * int2(1, 4);
|
||||||
|
int2 firstFragCoord = (tileCoord * int2(uTileSize)) + firstTileSubCoord;
|
||||||
|
int tileIndex = _1510.iFirstTileMap[tileCoord.x + (uFramebufferTileSize.x * tileCoord.y)];
|
||||||
|
if ((tileIndex < 0) && (uLoadAction != 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float4x4 destColors;
|
||||||
|
for (int subY = 0; subY < 4; subY++)
|
||||||
|
{
|
||||||
|
if (uLoadAction == 0)
|
||||||
|
{
|
||||||
|
destColors[subY] = uClearColor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int2 param = firstFragCoord + int2(0, subY);
|
||||||
|
int2 imageCoords = toImageCoords(param, uFramebufferSize);
|
||||||
|
destColors[subY] = uDestImage.read(uint2(imageCoords));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int backdrop;
|
||||||
|
uint2 maskTileCoord;
|
||||||
|
float2 param_4;
|
||||||
|
float4 param_5;
|
||||||
|
float4 param_6;
|
||||||
|
float4 param_7;
|
||||||
|
float4 param_8;
|
||||||
|
int param_9;
|
||||||
|
while (tileIndex >= 0)
|
||||||
|
{
|
||||||
|
for (int subY_1 = 0; subY_1 < 4; subY_1++)
|
||||||
|
{
|
||||||
|
int2 tileSubCoord = firstTileSubCoord + int2(0, subY_1);
|
||||||
|
float2 fragCoord = float2(firstFragCoord + int2(0, subY_1)) + float2(0.5);
|
||||||
|
int alphaTileIndex = int(_1603.iTiles[(tileIndex * 4) + 2] << uint(8)) >> 8;
|
||||||
|
uint tileControlWord = _1603.iTiles[(tileIndex * 4) + 3];
|
||||||
|
uint colorEntry = tileControlWord & 65535u;
|
||||||
|
int tileCtrl = int((tileControlWord >> uint(16)) & 255u);
|
||||||
|
if (alphaTileIndex >= 0)
|
||||||
|
{
|
||||||
|
backdrop = 0;
|
||||||
|
maskTileCoord = uint2(uint(alphaTileIndex & 255), uint(alphaTileIndex >> 8)) * uint2(uTileSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backdrop = int(tileControlWord) >> 24;
|
||||||
|
maskTileCoord = uint2(0u);
|
||||||
|
tileCtrl &= (-4);
|
||||||
|
}
|
||||||
|
float3 maskTexCoord0 = float3(float2(int2(maskTileCoord) + tileSubCoord), float(backdrop));
|
||||||
|
float2 param_1 = fragCoord;
|
||||||
|
int param_2 = int(colorEntry);
|
||||||
|
int2 param_3 = uTextureMetadataSize;
|
||||||
|
computeTileVaryings(param_1, param_2, uTextureMetadata, uTextureMetadataSmplr, param_3, param_4, param_5, param_6, param_7, param_8, param_9);
|
||||||
|
float2 colorTexCoord0 = param_4;
|
||||||
|
float4 baseColor = param_5;
|
||||||
|
float4 filterParams0 = param_6;
|
||||||
|
float4 filterParams1 = param_7;
|
||||||
|
float4 filterParams2 = param_8;
|
||||||
|
int ctrl = param_9;
|
||||||
|
float2 param_10 = fragCoord;
|
||||||
|
float2 param_11 = uColorTextureSize0;
|
||||||
|
float2 param_12 = uMaskTextureSize0;
|
||||||
|
float4 param_13 = filterParams0;
|
||||||
|
float4 param_14 = filterParams1;
|
||||||
|
float4 param_15 = filterParams2;
|
||||||
|
float2 param_16 = uFramebufferSize;
|
||||||
|
int param_17 = ctrl;
|
||||||
|
float3 param_18 = maskTexCoord0;
|
||||||
|
float2 param_19 = colorTexCoord0;
|
||||||
|
float4 param_20 = baseColor;
|
||||||
|
int param_21 = tileCtrl;
|
||||||
|
float4 srcColor = calculateColor(param_10, uColorTexture0, uColorTexture0Smplr, uMaskTexture0, uMaskTexture0Smplr, uDestTexture, uDestTextureSmplr, uGammaLUT, uGammaLUTSmplr, param_11, param_12, param_13, param_14, param_15, param_16, param_17, param_18, param_19, param_20, param_21);
|
||||||
|
destColors[subY_1] = (destColors[subY_1] * (1.0 - srcColor.w)) + srcColor;
|
||||||
|
}
|
||||||
|
tileIndex = int(_1603.iTiles[(tileIndex * 4) + 0]);
|
||||||
|
}
|
||||||
|
for (int subY_2 = 0; subY_2 < 4; subY_2++)
|
||||||
|
{
|
||||||
|
int2 param_22 = firstFragCoord + int2(0, subY_2);
|
||||||
|
uDestImage.write(destColors[subY_2], uint2(toImageCoords(param_22, uFramebufferSize)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float2 vFrom [[user(locn0)]];
|
||||||
|
float2 vTo [[user(locn1)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
uint2 aTessCoord [[attribute(0)]];
|
||||||
|
uint4 aLineSegment [[attribute(1)]];
|
||||||
|
int aTileIndex [[attribute(2)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread const float2& tileSize)
|
||||||
|
{
|
||||||
|
uint tilesPerRow = uint(stencilTextureWidth / tileSize.x);
|
||||||
|
uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
||||||
|
return (float2(tileOffset) * tileSize) * float2(1.0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 computeVertexPosition(thread const uint& tileIndex, thread const uint2& tessCoord, thread const uint4& packedLineSegment, thread const float2& tileSize, thread const float2& framebufferSize, thread float2& outFrom, thread float2& outTo)
|
||||||
|
{
|
||||||
|
uint param = tileIndex;
|
||||||
|
float param_1 = framebufferSize.x;
|
||||||
|
float2 param_2 = tileSize;
|
||||||
|
float2 tileOrigin = computeTileOffset(param, param_1, param_2);
|
||||||
|
float4 lineSegment = float4(packedLineSegment) / float4(256.0);
|
||||||
|
float2 from = lineSegment.xy;
|
||||||
|
float2 to = lineSegment.zw;
|
||||||
|
float2 position;
|
||||||
|
if (tessCoord.x == 0u)
|
||||||
|
{
|
||||||
|
position.x = floor(fast::min(from.x, to.x));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position.x = ceil(fast::max(from.x, to.x));
|
||||||
|
}
|
||||||
|
if (tessCoord.y == 0u)
|
||||||
|
{
|
||||||
|
position.y = floor(fast::min(from.y, to.y));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position.y = tileSize.y;
|
||||||
|
}
|
||||||
|
position.y = floor(position.y * 0.25);
|
||||||
|
float2 offset = float2(0.0, 1.5) - (position * float2(1.0, 4.0));
|
||||||
|
outFrom = from + offset;
|
||||||
|
outTo = to + offset;
|
||||||
|
float2 globalPosition = (((tileOrigin + position) / framebufferSize) * 2.0) - float2(1.0);
|
||||||
|
globalPosition.y = -globalPosition.y;
|
||||||
|
return float4(globalPosition, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant float2& uTileSize [[buffer(0)]], constant float2& uFramebufferSize [[buffer(1)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
uint param = uint(in.aTileIndex);
|
||||||
|
uint2 param_1 = in.aTessCoord;
|
||||||
|
uint4 param_2 = in.aLineSegment;
|
||||||
|
float2 param_3 = uTileSize;
|
||||||
|
float2 param_4 = uFramebufferSize;
|
||||||
|
float2 param_5;
|
||||||
|
float2 param_6;
|
||||||
|
float4 _190 = computeVertexPosition(param, param_1, param_2, param_3, param_4, param_5, param_6);
|
||||||
|
out.vFrom = param_5;
|
||||||
|
out.vTo = param_6;
|
||||||
|
out.gl_Position = _190;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
constant float3 _1042 = {};
|
constant float3 _1056 = {};
|
||||||
|
|
||||||
struct main0_out
|
struct main0_out
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,10 @@ struct main0_in
|
||||||
float2 vColorTexCoord0 [[user(locn1)]];
|
float2 vColorTexCoord0 [[user(locn1)]];
|
||||||
float4 vBaseColor [[user(locn2)]];
|
float4 vBaseColor [[user(locn2)]];
|
||||||
float vTileCtrl [[user(locn3)]];
|
float vTileCtrl [[user(locn3)]];
|
||||||
|
float4 vFilterParams0 [[user(locn4)]];
|
||||||
|
float4 vFilterParams1 [[user(locn5)]];
|
||||||
|
float4 vFilterParams2 [[user(locn6)]];
|
||||||
|
float vCtrl [[user(locn7)]];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
|
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
|
||||||
|
@ -71,16 +75,16 @@ float4 filterRadialGradient(thread const float2& colorTexCoord, thread const tex
|
||||||
{
|
{
|
||||||
ts = ts.yx;
|
ts = ts.yx;
|
||||||
}
|
}
|
||||||
float _555;
|
float _569;
|
||||||
if (ts.x >= 0.0)
|
if (ts.x >= 0.0)
|
||||||
{
|
{
|
||||||
_555 = ts.x;
|
_569 = ts.x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_555 = ts.y;
|
_569 = ts.y;
|
||||||
}
|
}
|
||||||
float t = _555;
|
float t = _569;
|
||||||
color = colorTexture.sample(colorTextureSmplr, (uvOrigin + float2(fast::clamp(t, 0.0, 1.0), 0.0)));
|
color = colorTexture.sample(colorTextureSmplr, (uvOrigin + float2(fast::clamp(t, 0.0, 1.0), 0.0)));
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
|
@ -94,19 +98,19 @@ float4 filterBlur(thread const float2& colorTexCoord, thread const texture2d<flo
|
||||||
float3 gaussCoeff = filterParams1.xyz;
|
float3 gaussCoeff = filterParams1.xyz;
|
||||||
float gaussSum = gaussCoeff.x;
|
float gaussSum = gaussCoeff.x;
|
||||||
float4 color = colorTexture.sample(colorTextureSmplr, colorTexCoord) * gaussCoeff.x;
|
float4 color = colorTexture.sample(colorTextureSmplr, colorTexCoord) * gaussCoeff.x;
|
||||||
float2 _600 = gaussCoeff.xy * gaussCoeff.yz;
|
float2 _614 = gaussCoeff.xy * gaussCoeff.yz;
|
||||||
gaussCoeff = float3(_600.x, _600.y, gaussCoeff.z);
|
gaussCoeff = float3(_614.x, _614.y, gaussCoeff.z);
|
||||||
for (int i = 1; i <= support; i += 2)
|
for (int i = 1; i <= support; i += 2)
|
||||||
{
|
{
|
||||||
float gaussPartialSum = gaussCoeff.x;
|
float gaussPartialSum = gaussCoeff.x;
|
||||||
float2 _620 = gaussCoeff.xy * gaussCoeff.yz;
|
float2 _634 = gaussCoeff.xy * gaussCoeff.yz;
|
||||||
gaussCoeff = float3(_620.x, _620.y, gaussCoeff.z);
|
gaussCoeff = float3(_634.x, _634.y, gaussCoeff.z);
|
||||||
gaussPartialSum += gaussCoeff.x;
|
gaussPartialSum += gaussCoeff.x;
|
||||||
float2 srcOffset = srcOffsetScale * (float(i) + (gaussCoeff.x / gaussPartialSum));
|
float2 srcOffset = srcOffsetScale * (float(i) + (gaussCoeff.x / gaussPartialSum));
|
||||||
color += ((colorTexture.sample(colorTextureSmplr, (colorTexCoord - srcOffset)) + colorTexture.sample(colorTextureSmplr, (colorTexCoord + srcOffset))) * gaussPartialSum);
|
color += ((colorTexture.sample(colorTextureSmplr, (colorTexCoord - srcOffset)) + colorTexture.sample(colorTextureSmplr, (colorTexCoord + srcOffset))) * gaussPartialSum);
|
||||||
gaussSum += (2.0 * gaussPartialSum);
|
gaussSum += (2.0 * gaussPartialSum);
|
||||||
float2 _660 = gaussCoeff.xy * gaussCoeff.yz;
|
float2 _674 = gaussCoeff.xy * gaussCoeff.yz;
|
||||||
gaussCoeff = float3(_660.x, _660.y, gaussCoeff.z);
|
gaussCoeff = float3(_674.x, _674.y, gaussCoeff.z);
|
||||||
}
|
}
|
||||||
return color / float4(gaussSum);
|
return color / float4(gaussSum);
|
||||||
}
|
}
|
||||||
|
@ -121,16 +125,16 @@ static inline __attribute__((always_inline))
|
||||||
void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord, thread const float4& kernel0, thread const float& onePixel)
|
void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord, thread const float4& kernel0, thread const float& onePixel)
|
||||||
{
|
{
|
||||||
bool wide = kernel0.x > 0.0;
|
bool wide = kernel0.x > 0.0;
|
||||||
float _236;
|
float _250;
|
||||||
if (wide)
|
if (wide)
|
||||||
{
|
{
|
||||||
float param = (-4.0) * onePixel;
|
float param = (-4.0) * onePixel;
|
||||||
float2 param_1 = colorTexCoord;
|
float2 param_1 = colorTexCoord;
|
||||||
_236 = filterTextSample1Tap(param, colorTexture, colorTextureSmplr, param_1);
|
_250 = filterTextSample1Tap(param, colorTexture, colorTextureSmplr, param_1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_236 = 0.0;
|
_250 = 0.0;
|
||||||
}
|
}
|
||||||
float param_2 = (-3.0) * onePixel;
|
float param_2 = (-3.0) * onePixel;
|
||||||
float2 param_3 = colorTexCoord;
|
float2 param_3 = colorTexCoord;
|
||||||
|
@ -138,7 +142,7 @@ void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCen
|
||||||
float2 param_5 = colorTexCoord;
|
float2 param_5 = colorTexCoord;
|
||||||
float param_6 = (-1.0) * onePixel;
|
float param_6 = (-1.0) * onePixel;
|
||||||
float2 param_7 = colorTexCoord;
|
float2 param_7 = colorTexCoord;
|
||||||
outAlphaLeft = float4(_236, filterTextSample1Tap(param_2, colorTexture, colorTextureSmplr, param_3), filterTextSample1Tap(param_4, colorTexture, colorTextureSmplr, param_5), filterTextSample1Tap(param_6, colorTexture, colorTextureSmplr, param_7));
|
outAlphaLeft = float4(_250, filterTextSample1Tap(param_2, colorTexture, colorTextureSmplr, param_3), filterTextSample1Tap(param_4, colorTexture, colorTextureSmplr, param_5), filterTextSample1Tap(param_6, colorTexture, colorTextureSmplr, param_7));
|
||||||
float param_8 = 0.0;
|
float param_8 = 0.0;
|
||||||
float2 param_9 = colorTexCoord;
|
float2 param_9 = colorTexCoord;
|
||||||
outAlphaCenter = filterTextSample1Tap(param_8, colorTexture, colorTextureSmplr, param_9);
|
outAlphaCenter = filterTextSample1Tap(param_8, colorTexture, colorTextureSmplr, param_9);
|
||||||
|
@ -148,18 +152,18 @@ void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCen
|
||||||
float2 param_13 = colorTexCoord;
|
float2 param_13 = colorTexCoord;
|
||||||
float param_14 = 3.0 * onePixel;
|
float param_14 = 3.0 * onePixel;
|
||||||
float2 param_15 = colorTexCoord;
|
float2 param_15 = colorTexCoord;
|
||||||
float _296;
|
float _310;
|
||||||
if (wide)
|
if (wide)
|
||||||
{
|
{
|
||||||
float param_16 = 4.0 * onePixel;
|
float param_16 = 4.0 * onePixel;
|
||||||
float2 param_17 = colorTexCoord;
|
float2 param_17 = colorTexCoord;
|
||||||
_296 = filterTextSample1Tap(param_16, colorTexture, colorTextureSmplr, param_17);
|
_310 = filterTextSample1Tap(param_16, colorTexture, colorTextureSmplr, param_17);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_296 = 0.0;
|
_310 = 0.0;
|
||||||
}
|
}
|
||||||
outAlphaRight = float4(filterTextSample1Tap(param_10, colorTexture, colorTextureSmplr, param_11), filterTextSample1Tap(param_12, colorTexture, colorTextureSmplr, param_13), filterTextSample1Tap(param_14, colorTexture, colorTextureSmplr, param_15), _296);
|
outAlphaRight = float4(filterTextSample1Tap(param_10, colorTexture, colorTextureSmplr, param_11), filterTextSample1Tap(param_12, colorTexture, colorTextureSmplr, param_13), filterTextSample1Tap(param_14, colorTexture, colorTextureSmplr, param_15), _310);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
|
@ -309,34 +313,34 @@ float3 compositeScreen(thread const float3& destColor, thread const float3& srcC
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
float3 compositeSelect(thread const bool3& cond, thread const float3& ifTrue, thread const float3& ifFalse)
|
float3 compositeSelect(thread const bool3& cond, thread const float3& ifTrue, thread const float3& ifFalse)
|
||||||
{
|
{
|
||||||
float _726;
|
float _740;
|
||||||
if (cond.x)
|
if (cond.x)
|
||||||
{
|
{
|
||||||
_726 = ifTrue.x;
|
_740 = ifTrue.x;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_726 = ifFalse.x;
|
_740 = ifFalse.x;
|
||||||
}
|
}
|
||||||
float _737;
|
float _751;
|
||||||
if (cond.y)
|
if (cond.y)
|
||||||
{
|
{
|
||||||
_737 = ifTrue.y;
|
_751 = ifTrue.y;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_737 = ifFalse.y;
|
_751 = ifFalse.y;
|
||||||
}
|
}
|
||||||
float _748;
|
float _762;
|
||||||
if (cond.z)
|
if (cond.z)
|
||||||
{
|
{
|
||||||
_748 = ifTrue.z;
|
_762 = ifTrue.z;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_748 = ifFalse.z;
|
_762 = ifFalse.z;
|
||||||
}
|
}
|
||||||
return float3(_726, _737, _748);
|
return float3(_740, _751, _762);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
|
@ -381,16 +385,16 @@ float3 compositeSoftLight(thread const float3& destColor, thread const float3& s
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
float compositeDivide(thread const float& num, thread const float& denom)
|
float compositeDivide(thread const float& num, thread const float& denom)
|
||||||
{
|
{
|
||||||
float _762;
|
float _776;
|
||||||
if (denom != 0.0)
|
if (denom != 0.0)
|
||||||
{
|
{
|
||||||
_762 = num / denom;
|
_776 = num / denom;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_762 = 0.0;
|
_776 = 0.0;
|
||||||
}
|
}
|
||||||
return _762;
|
return _776;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
|
@ -400,25 +404,25 @@ float3 compositeRGBToHSL(thread const float3& rgb)
|
||||||
float xMin = fast::min(fast::min(rgb.x, rgb.y), rgb.z);
|
float xMin = fast::min(fast::min(rgb.x, rgb.y), rgb.z);
|
||||||
float c = v - xMin;
|
float c = v - xMin;
|
||||||
float l = mix(xMin, v, 0.5);
|
float l = mix(xMin, v, 0.5);
|
||||||
float3 _868;
|
float3 _882;
|
||||||
if (rgb.x == v)
|
if (rgb.x == v)
|
||||||
{
|
{
|
||||||
_868 = float3(0.0, rgb.yz);
|
_882 = float3(0.0, rgb.yz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float3 _881;
|
float3 _895;
|
||||||
if (rgb.y == v)
|
if (rgb.y == v)
|
||||||
{
|
{
|
||||||
_881 = float3(2.0, rgb.zx);
|
_895 = float3(2.0, rgb.zx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_881 = float3(4.0, rgb.xy);
|
_895 = float3(4.0, rgb.xy);
|
||||||
}
|
}
|
||||||
_868 = _881;
|
_882 = _895;
|
||||||
}
|
}
|
||||||
float3 terms = _868;
|
float3 terms = _882;
|
||||||
float param = ((terms.x * c) + terms.y) - terms.z;
|
float param = ((terms.x * c) + terms.y) - terms.z;
|
||||||
float param_1 = c;
|
float param_1 = c;
|
||||||
float h = 1.0471975803375244140625 * compositeDivide(param, param_1);
|
float h = 1.0471975803375244140625 * compositeDivide(param, param_1);
|
||||||
|
@ -555,29 +559,29 @@ float4 composite(thread const float4& srcColor, thread const texture2d<float> de
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
static inline __attribute__((always_inline))
|
||||||
void calculateColor(thread const int& tileCtrl, thread const int& ctrl, thread texture2d<float> uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float2 uMaskTextureSize0, thread float3& vMaskTexCoord0, thread float4& vBaseColor, thread float2& vColorTexCoord0, thread texture2d<float> uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d<float> uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTextureSize0, thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread texture2d<float> uDestTexture, thread const sampler uDestTextureSmplr, thread float4& oFragColor)
|
float4 calculateColor(thread const float2& fragCoord, thread const texture2d<float> colorTexture0, thread const sampler colorTexture0Smplr, thread const texture2d<float> maskTexture0, thread const sampler maskTexture0Smplr, thread const texture2d<float> destTexture, thread const sampler destTextureSmplr, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize0, thread const float2& maskTextureSize0, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2, thread const float2& framebufferSize, thread const int& ctrl, thread const float3& maskTexCoord0, thread const float2& colorTexCoord0, thread const float4& baseColor, thread const int& tileCtrl)
|
||||||
{
|
{
|
||||||
int maskCtrl0 = (tileCtrl >> 0) & 3;
|
int maskCtrl0 = (tileCtrl >> 0) & 3;
|
||||||
float maskAlpha = 1.0;
|
float maskAlpha = 1.0;
|
||||||
float param = maskAlpha;
|
float param = maskAlpha;
|
||||||
float2 param_1 = uMaskTextureSize0;
|
float2 param_1 = maskTextureSize0;
|
||||||
float3 param_2 = vMaskTexCoord0;
|
float3 param_2 = maskTexCoord0;
|
||||||
int param_3 = maskCtrl0;
|
int param_3 = maskCtrl0;
|
||||||
maskAlpha = sampleMask(param, uMaskTexture0, uMaskTexture0Smplr, param_1, param_2, param_3);
|
maskAlpha = sampleMask(param, maskTexture0, maskTexture0Smplr, param_1, param_2, param_3);
|
||||||
float4 color = vBaseColor;
|
float4 color = baseColor;
|
||||||
int color0Combine = (ctrl >> 6) & 3;
|
int color0Combine = (ctrl >> 6) & 3;
|
||||||
if (color0Combine != 0)
|
if (color0Combine != 0)
|
||||||
{
|
{
|
||||||
int color0Filter = (ctrl >> 4) & 3;
|
int color0Filter = (ctrl >> 4) & 3;
|
||||||
float2 param_4 = vColorTexCoord0;
|
float2 param_4 = colorTexCoord0;
|
||||||
float2 param_5 = uColorTextureSize0;
|
float2 param_5 = colorTextureSize0;
|
||||||
float2 param_6 = gl_FragCoord.xy;
|
float2 param_6 = fragCoord;
|
||||||
float2 param_7 = uFramebufferSize;
|
float2 param_7 = framebufferSize;
|
||||||
float4 param_8 = uFilterParams0;
|
float4 param_8 = filterParams0;
|
||||||
float4 param_9 = uFilterParams1;
|
float4 param_9 = filterParams1;
|
||||||
float4 param_10 = uFilterParams2;
|
float4 param_10 = filterParams2;
|
||||||
int param_11 = color0Filter;
|
int param_11 = color0Filter;
|
||||||
float4 color0 = filterColor(param_4, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, param_5, param_6, param_7, param_8, param_9, param_10, param_11);
|
float4 color0 = filterColor(param_4, colorTexture0, colorTexture0Smplr, gammaLUT, gammaLUTSmplr, param_5, param_6, param_7, param_8, param_9, param_10, param_11);
|
||||||
float4 param_12 = color;
|
float4 param_12 = color;
|
||||||
float4 param_13 = color0;
|
float4 param_13 = color0;
|
||||||
int param_14 = color0Combine;
|
int param_14 = color0Combine;
|
||||||
|
@ -586,21 +590,31 @@ void calculateColor(thread const int& tileCtrl, thread const int& ctrl, thread t
|
||||||
color.w *= maskAlpha;
|
color.w *= maskAlpha;
|
||||||
int compositeOp = (ctrl >> 8) & 15;
|
int compositeOp = (ctrl >> 8) & 15;
|
||||||
float4 param_15 = color;
|
float4 param_15 = color;
|
||||||
float2 param_16 = uFramebufferSize;
|
float2 param_16 = framebufferSize;
|
||||||
float2 param_17 = gl_FragCoord.xy;
|
float2 param_17 = fragCoord;
|
||||||
int param_18 = compositeOp;
|
int param_18 = compositeOp;
|
||||||
color = composite(param_15, uDestTexture, uDestTextureSmplr, param_16, param_17, param_18);
|
color = composite(param_15, destTexture, destTextureSmplr, param_16, param_17, param_18);
|
||||||
float3 _1347 = color.xyz * color.w;
|
float3 _1340 = color.xyz * color.w;
|
||||||
color = float4(_1347.x, _1347.y, _1347.z, color.w);
|
color = float4(_1340.x, _1340.y, _1340.z, color.w);
|
||||||
oFragColor = color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment main0_out main0(main0_in in [[stage_in]], constant int& uCtrl [[buffer(6)]], constant float2& uMaskTextureSize0 [[buffer(0)]], constant float2& uColorTextureSize0 [[buffer(1)]], constant float2& uFramebufferSize [[buffer(2)]], constant float4& uFilterParams0 [[buffer(3)]], constant float4& uFilterParams1 [[buffer(4)]], constant float4& uFilterParams2 [[buffer(5)]], texture2d<float> uMaskTexture0 [[texture(0)]], texture2d<float> uColorTexture0 [[texture(1)]], texture2d<float> uGammaLUT [[texture(2)]], texture2d<float> uDestTexture [[texture(3)]], sampler uMaskTexture0Smplr [[sampler(0)]], sampler uColorTexture0Smplr [[sampler(1)]], sampler uGammaLUTSmplr [[sampler(2)]], sampler uDestTextureSmplr [[sampler(3)]], float4 gl_FragCoord [[position]])
|
fragment main0_out main0(main0_in in [[stage_in]], constant float2& uColorTextureSize0 [[buffer(0)]], constant float2& uMaskTextureSize0 [[buffer(1)]], constant float2& uFramebufferSize [[buffer(2)]], texture2d<float> uColorTexture0 [[texture(0)]], texture2d<float> uMaskTexture0 [[texture(1)]], texture2d<float> uDestTexture [[texture(2)]], texture2d<float> uGammaLUT [[texture(3)]], sampler uColorTexture0Smplr [[sampler(0)]], sampler uMaskTexture0Smplr [[sampler(1)]], sampler uDestTextureSmplr [[sampler(2)]], sampler uGammaLUTSmplr [[sampler(3)]], float4 gl_FragCoord [[position]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
int param = int(in.vTileCtrl);
|
float2 param = gl_FragCoord.xy;
|
||||||
int param_1 = uCtrl;
|
float2 param_1 = uColorTextureSize0;
|
||||||
calculateColor(param, param_1, uMaskTexture0, uMaskTexture0Smplr, uMaskTextureSize0, in.vMaskTexCoord0, in.vBaseColor, in.vColorTexCoord0, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, uColorTextureSize0, gl_FragCoord, uFramebufferSize, uFilterParams0, uFilterParams1, uFilterParams2, uDestTexture, uDestTextureSmplr, out.oFragColor);
|
float2 param_2 = uMaskTextureSize0;
|
||||||
|
float4 param_3 = in.vFilterParams0;
|
||||||
|
float4 param_4 = in.vFilterParams1;
|
||||||
|
float4 param_5 = in.vFilterParams2;
|
||||||
|
float2 param_6 = uFramebufferSize;
|
||||||
|
int param_7 = int(in.vCtrl);
|
||||||
|
float3 param_8 = in.vMaskTexCoord0;
|
||||||
|
float2 param_9 = in.vColorTexCoord0;
|
||||||
|
float4 param_10 = in.vBaseColor;
|
||||||
|
int param_11 = int(in.vTileCtrl);
|
||||||
|
out.oFragColor = calculateColor(param, uColorTexture0, uColorTexture0Smplr, uMaskTexture0, uMaskTexture0Smplr, uDestTexture, uDestTextureSmplr, uGammaLUT, uGammaLUTSmplr, param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10, param_11);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float3 vMaskTexCoord0 [[user(locn0)]];
|
||||||
|
float2 vColorTexCoord0 [[user(locn1)]];
|
||||||
|
float4 vBaseColor [[user(locn2)]];
|
||||||
|
float vTileCtrl [[user(locn3)]];
|
||||||
|
float4 vFilterParams0 [[user(locn4)]];
|
||||||
|
float4 vFilterParams1 [[user(locn5)]];
|
||||||
|
float4 vFilterParams2 [[user(locn6)]];
|
||||||
|
float vCtrl [[user(locn7)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
int2 aTileOffset [[attribute(0)]];
|
||||||
|
int2 aTileOrigin [[attribute(1)]];
|
||||||
|
uint4 aMaskTexCoord0 [[attribute(2)]];
|
||||||
|
int2 aCtrlBackdrop [[attribute(3)]];
|
||||||
|
int aPathIndex [[attribute(4)]];
|
||||||
|
int aColor [[attribute(5)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
float4 fetchUnscaled(thread const texture2d<float> srcTexture, thread const sampler srcTextureSmplr, thread const float2& scale, thread const float2& originCoord, thread const int& entry)
|
||||||
|
{
|
||||||
|
return srcTexture.sample(srcTextureSmplr, (((originCoord + float2(0.5)) + float2(float(entry), 0.0)) * scale), level(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __attribute__((always_inline))
|
||||||
|
void computeTileVaryings(thread const float2& position, thread const int& colorEntry, thread const texture2d<float> textureMetadata, thread const sampler textureMetadataSmplr, thread const int2& textureMetadataSize, thread float2& outColorTexCoord0, thread float4& outBaseColor, thread float4& outFilterParams0, thread float4& outFilterParams1, thread float4& outFilterParams2, thread int& outCtrl)
|
||||||
|
{
|
||||||
|
float2 metadataScale = float2(1.0) / float2(textureMetadataSize);
|
||||||
|
float2 metadataEntryCoord = float2(float((colorEntry % 128) * 8), float(colorEntry / 128));
|
||||||
|
float2 param = metadataScale;
|
||||||
|
float2 param_1 = metadataEntryCoord;
|
||||||
|
int param_2 = 0;
|
||||||
|
float4 colorTexMatrix0 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param, param_1, param_2);
|
||||||
|
float2 param_3 = metadataScale;
|
||||||
|
float2 param_4 = metadataEntryCoord;
|
||||||
|
int param_5 = 1;
|
||||||
|
float4 colorTexOffsets = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_3, param_4, param_5);
|
||||||
|
float2 param_6 = metadataScale;
|
||||||
|
float2 param_7 = metadataEntryCoord;
|
||||||
|
int param_8 = 2;
|
||||||
|
float4 baseColor = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_6, param_7, param_8);
|
||||||
|
float2 param_9 = metadataScale;
|
||||||
|
float2 param_10 = metadataEntryCoord;
|
||||||
|
int param_11 = 3;
|
||||||
|
float4 filterParams0 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_9, param_10, param_11);
|
||||||
|
float2 param_12 = metadataScale;
|
||||||
|
float2 param_13 = metadataEntryCoord;
|
||||||
|
int param_14 = 4;
|
||||||
|
float4 filterParams1 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_12, param_13, param_14);
|
||||||
|
float2 param_15 = metadataScale;
|
||||||
|
float2 param_16 = metadataEntryCoord;
|
||||||
|
int param_17 = 5;
|
||||||
|
float4 filterParams2 = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_15, param_16, param_17);
|
||||||
|
float2 param_18 = metadataScale;
|
||||||
|
float2 param_19 = metadataEntryCoord;
|
||||||
|
int param_20 = 6;
|
||||||
|
float4 extra = fetchUnscaled(textureMetadata, textureMetadataSmplr, param_18, param_19, param_20);
|
||||||
|
outColorTexCoord0 = (float2x2(float2(colorTexMatrix0.xy), float2(colorTexMatrix0.zw)) * position) + colorTexOffsets.xy;
|
||||||
|
outBaseColor = baseColor;
|
||||||
|
outFilterParams0 = filterParams0;
|
||||||
|
outFilterParams1 = filterParams1;
|
||||||
|
outFilterParams2 = filterParams2;
|
||||||
|
outCtrl = int(extra.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant int2& uZBufferSize [[buffer(1)]], constant int2& uTextureMetadataSize [[buffer(2)]], constant float2& uTileSize [[buffer(0)]], constant float4x4& uTransform [[buffer(3)]], texture2d<float> uZBuffer [[texture(0)]], texture2d<float> uTextureMetadata [[texture(1)]], sampler uZBufferSmplr [[sampler(0)]], sampler uTextureMetadataSmplr [[sampler(1)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 tileOrigin = float2(in.aTileOrigin);
|
||||||
|
float2 tileOffset = float2(in.aTileOffset);
|
||||||
|
float2 position = (tileOrigin + tileOffset) * uTileSize;
|
||||||
|
int4 zValue = int4(uZBuffer.sample(uZBufferSmplr, ((tileOrigin + float2(0.5)) / float2(uZBufferSize)), level(0.0)) * 255.0);
|
||||||
|
if (in.aPathIndex < (((zValue.x | (zValue.y << 8)) | (zValue.z << 16)) | (zValue.w << 24)))
|
||||||
|
{
|
||||||
|
out.gl_Position = float4(0.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
uint2 maskTileCoord = uint2(in.aMaskTexCoord0.x, in.aMaskTexCoord0.y + (256u * in.aMaskTexCoord0.z));
|
||||||
|
float2 maskTexCoord0 = (float2(maskTileCoord) + tileOffset) * uTileSize;
|
||||||
|
bool _244 = in.aCtrlBackdrop.y == 0;
|
||||||
|
bool _250;
|
||||||
|
if (_244)
|
||||||
|
{
|
||||||
|
_250 = in.aMaskTexCoord0.w != 0u;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_250 = _244;
|
||||||
|
}
|
||||||
|
if (_250)
|
||||||
|
{
|
||||||
|
out.gl_Position = float4(0.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
float2 param = position;
|
||||||
|
int param_1 = in.aColor;
|
||||||
|
int2 param_2 = uTextureMetadataSize;
|
||||||
|
float2 param_3;
|
||||||
|
float4 param_4;
|
||||||
|
float4 param_5;
|
||||||
|
float4 param_6;
|
||||||
|
float4 param_7;
|
||||||
|
int param_8;
|
||||||
|
computeTileVaryings(param, param_1, uTextureMetadata, uTextureMetadataSmplr, param_2, param_3, param_4, param_5, param_6, param_7, param_8);
|
||||||
|
out.vColorTexCoord0 = param_3;
|
||||||
|
out.vBaseColor = param_4;
|
||||||
|
out.vFilterParams0 = param_5;
|
||||||
|
out.vFilterParams1 = param_6;
|
||||||
|
out.vFilterParams2 = param_7;
|
||||||
|
int ctrl = param_8;
|
||||||
|
out.vTileCtrl = float(in.aCtrlBackdrop.x);
|
||||||
|
out.vCtrl = float(ctrl);
|
||||||
|
out.vMaskTexCoord0 = float3(maskTexCoord0, float(in.aCtrlBackdrop.y));
|
||||||
|
out.gl_Position = uTransform * float4(position, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 oFragColor [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float2 vTexCoord0 [[user(locn0)]];
|
||||||
|
float vBackdrop0 [[user(locn1)]];
|
||||||
|
float2 vTexCoord1 [[user(locn2)]];
|
||||||
|
float vBackdrop1 [[user(locn3)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uSrc [[texture(0)]], sampler uSrcSmplr [[sampler(0)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
out.oFragColor = fast::min(abs(uSrc.sample(uSrcSmplr, in.vTexCoord0) + float4(in.vBackdrop0)), abs(uSrc.sample(uSrcSmplr, in.vTexCoord1) + float4(in.vBackdrop1)));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float2 vTexCoord0 [[user(locn0)]];
|
||||||
|
float vBackdrop0 [[user(locn1)]];
|
||||||
|
float2 vTexCoord1 [[user(locn2)]];
|
||||||
|
float vBackdrop1 [[user(locn3)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
int2 aTileOffset [[attribute(0)]];
|
||||||
|
int aDestTileIndex [[attribute(1)]];
|
||||||
|
int aDestBackdrop [[attribute(2)]];
|
||||||
|
int aSrcTileIndex [[attribute(3)]];
|
||||||
|
int aSrcBackdrop [[attribute(4)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant float2& uFramebufferSize [[buffer(0)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 destPosition = float2(int2(in.aDestTileIndex % 256, in.aDestTileIndex / 256) + in.aTileOffset);
|
||||||
|
float2 srcPosition = float2(int2(in.aSrcTileIndex % 256, in.aSrcTileIndex / 256) + in.aTileOffset);
|
||||||
|
destPosition *= (float2(16.0, 4.0) / uFramebufferSize);
|
||||||
|
srcPosition *= (float2(16.0, 4.0) / uFramebufferSize);
|
||||||
|
out.vTexCoord0 = destPosition;
|
||||||
|
out.vTexCoord1 = srcPosition;
|
||||||
|
out.vBackdrop0 = float(in.aDestBackdrop);
|
||||||
|
out.vBackdrop1 = float(in.aSrcBackdrop);
|
||||||
|
if (in.aDestTileIndex < 0)
|
||||||
|
{
|
||||||
|
destPosition = float2(0.0);
|
||||||
|
}
|
||||||
|
destPosition.y = 1.0 - destPosition.y;
|
||||||
|
out.gl_Position = float4(mix(float2(-1.0), float2(1.0), destPosition), 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -12,13 +12,12 @@ struct main0_out
|
||||||
struct main0_in
|
struct main0_in
|
||||||
{
|
{
|
||||||
float2 vTexCoord [[user(locn0)]];
|
float2 vTexCoord [[user(locn0)]];
|
||||||
float vBackdrop [[user(locn1)]];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uSrc [[texture(0)]], sampler uSrcSmplr [[sampler(0)]])
|
fragment main0_out main0(main0_in in [[stage_in]], texture2d<float> uSrc [[texture(0)]], sampler uSrcSmplr [[sampler(0)]])
|
||||||
{
|
{
|
||||||
main0_out out = {};
|
main0_out out = {};
|
||||||
out.oFragColor = fast::clamp(abs(uSrc.sample(uSrcSmplr, in.vTexCoord) + float4(in.vBackdrop)), float4(0.0), float4(1.0));
|
out.oFragColor = uSrc.sample(uSrcSmplr, in.vTexCoord);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float2 vTexCoord [[user(locn0)]];
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
int2 aTileOffset [[attribute(0)]];
|
||||||
|
int aTileIndex [[attribute(1)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant float2& uFramebufferSize [[buffer(0)]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 position = float2(int2(in.aTileIndex % 256, in.aTileIndex / 256) + in.aTileOffset);
|
||||||
|
position *= (float2(16.0, 4.0) / uFramebufferSize);
|
||||||
|
out.vTexCoord = position;
|
||||||
|
if (in.aTileIndex < 0)
|
||||||
|
{
|
||||||
|
position = float2(0.0);
|
||||||
|
}
|
||||||
|
position.y = 1.0 - position.y;
|
||||||
|
out.gl_Position = float4(mix(float2(-1.0), float2(1.0), position), 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
|
||||||
|
|
||||||
#include <metal_stdlib>
|
|
||||||
#include <simd/simd.h>
|
|
||||||
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
struct bFillTileMap
|
|
||||||
{
|
|
||||||
int iFillTileMap[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bFills
|
|
||||||
{
|
|
||||||
uint2 iFills[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bNextFills
|
|
||||||
{
|
|
||||||
int iNextFills[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(16u, 4u, 1u);
|
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
|
||||||
float4 computeCoverage(thread const float2& from, thread const float2& to, thread const texture2d<float> areaLUT, thread const sampler areaLUTSmplr)
|
|
||||||
{
|
|
||||||
float2 left = select(to, from, bool2(from.x < to.x));
|
|
||||||
float2 right = select(from, to, bool2(from.x < to.x));
|
|
||||||
float2 window = fast::clamp(float2(from.x, to.x), float2(-0.5), float2(0.5));
|
|
||||||
float offset = mix(window.x, window.y, 0.5) - left.x;
|
|
||||||
float t = offset / (right.x - left.x);
|
|
||||||
float y = mix(left.y, right.y, t);
|
|
||||||
float d = (right.y - left.y) / (right.x - left.x);
|
|
||||||
float dX = window.x - window.y;
|
|
||||||
return areaLUT.sample(areaLUTSmplr, (float2(y + 8.0, abs(d * dX)) / float2(16.0)), level(0.0)) * dX;
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel void main0(constant int& uFirstTileIndex [[buffer(0)]], const device bFillTileMap& _150 [[buffer(1)]], const device bFills& _173 [[buffer(2)]], const device bNextFills& _256 [[buffer(3)]], texture2d<float> uAreaLUT [[texture(0)]], texture2d<float, access::write> uDest [[texture(1)]], sampler uAreaLUTSmplr [[sampler(0)]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]])
|
|
||||||
{
|
|
||||||
int2 tileSubCoord = int2(gl_LocalInvocationID.xy) * int2(1, 4);
|
|
||||||
uint tileIndexOffset = gl_WorkGroupID.z;
|
|
||||||
uint tileIndex = tileIndexOffset + uint(uFirstTileIndex);
|
|
||||||
int fillIndex = _150.iFillTileMap[tileIndex];
|
|
||||||
if (fillIndex < 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float4 coverages = float4(0.0);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint2 fill = _173.iFills[fillIndex];
|
|
||||||
float2 from = float2(float(fill.y & 15u), float((fill.y >> 4u) & 15u)) + (float2(float(fill.x & 255u), float((fill.x >> 8u) & 255u)) / float2(256.0));
|
|
||||||
float2 to = float2(float((fill.y >> 8u) & 15u), float((fill.y >> 12u) & 15u)) + (float2(float((fill.x >> 16u) & 255u), float((fill.x >> 24u) & 255u)) / float2(256.0));
|
|
||||||
float2 param = from - (float2(tileSubCoord) + float2(0.5));
|
|
||||||
float2 param_1 = to - (float2(tileSubCoord) + float2(0.5));
|
|
||||||
coverages += computeCoverage(param, param_1, uAreaLUT, uAreaLUTSmplr);
|
|
||||||
fillIndex = _256.iNextFills[fillIndex];
|
|
||||||
} while (fillIndex >= 0);
|
|
||||||
int2 tileOrigin = int2(int(tileIndex & 255u), int((tileIndex >> 8u) & 255u)) * int2(16, 4);
|
|
||||||
int2 destCoord = tileOrigin + int2(gl_LocalInvocationID.xy);
|
|
||||||
uDest.write(coverages, uint2(destCoord));
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
|
||||||
|
|
||||||
#include <metal_stdlib>
|
|
||||||
#include <simd/simd.h>
|
|
||||||
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
struct main0_out
|
|
||||||
{
|
|
||||||
float2 vFrom [[user(locn0)]];
|
|
||||||
float2 vTo [[user(locn1)]];
|
|
||||||
float4 gl_Position [[position]];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct main0_in
|
|
||||||
{
|
|
||||||
uint2 aTessCoord [[attribute(0)]];
|
|
||||||
uint aFromPx [[attribute(1)]];
|
|
||||||
uint aToPx [[attribute(2)]];
|
|
||||||
float2 aFromSubpx [[attribute(3)]];
|
|
||||||
float2 aToSubpx [[attribute(4)]];
|
|
||||||
uint aTileIndex [[attribute(5)]];
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline __attribute__((always_inline))
|
|
||||||
float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize)
|
|
||||||
{
|
|
||||||
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
|
|
||||||
uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
|
||||||
return (float2(tileOffset) * uTileSize) * float2(1.0, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]], constant float2& uTileSize [[buffer(0)]], constant float2& uFramebufferSize [[buffer(1)]])
|
|
||||||
{
|
|
||||||
main0_out out = {};
|
|
||||||
uint param = in.aTileIndex;
|
|
||||||
float param_1 = uFramebufferSize.x;
|
|
||||||
float2 tileOrigin = computeTileOffset(param, param_1, uTileSize);
|
|
||||||
float2 from = float2(float(in.aFromPx & 15u), float(in.aFromPx >> 4u)) + in.aFromSubpx;
|
|
||||||
float2 to = float2(float(in.aToPx & 15u), float(in.aToPx >> 4u)) + in.aToSubpx;
|
|
||||||
float2 position;
|
|
||||||
if (in.aTessCoord.x == 0u)
|
|
||||||
{
|
|
||||||
position.x = floor(fast::min(from.x, to.x));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
position.x = ceil(fast::max(from.x, to.x));
|
|
||||||
}
|
|
||||||
if (in.aTessCoord.y == 0u)
|
|
||||||
{
|
|
||||||
position.y = floor(fast::min(from.y, to.y));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
position.y = uTileSize.y;
|
|
||||||
}
|
|
||||||
position.y = floor(position.y * 0.25);
|
|
||||||
float2 offset = float2(0.0, 1.5) - (position * float2(1.0, 4.0));
|
|
||||||
out.vFrom = from + offset;
|
|
||||||
out.vTo = to + offset;
|
|
||||||
float2 globalPosition = (((tileOrigin + position) / uFramebufferSize) * 2.0) - float2(1.0);
|
|
||||||
globalPosition.y = -globalPosition.y;
|
|
||||||
out.gl_Position = float4(globalPosition, 0.0, 1.0);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
#include <metal_stdlib>
|
|
||||||
#include <simd/simd.h>
|
|
||||||
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
struct main0_out
|
|
||||||
{
|
|
||||||
float3 vMaskTexCoord0 [[user(locn0)]];
|
|
||||||
float2 vColorTexCoord0 [[user(locn1)]];
|
|
||||||
float4 vBaseColor [[user(locn2)]];
|
|
||||||
float vTileCtrl [[user(locn3)]];
|
|
||||||
float4 gl_Position [[position]];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct main0_in
|
|
||||||
{
|
|
||||||
int2 aTileOffset [[attribute(0)]];
|
|
||||||
int2 aTileOrigin [[attribute(1)]];
|
|
||||||
uint2 aMaskTexCoord0 [[attribute(2)]];
|
|
||||||
int2 aMaskBackdrop [[attribute(3)]];
|
|
||||||
int aColor [[attribute(4)]];
|
|
||||||
int aTileCtrl [[attribute(5)]];
|
|
||||||
};
|
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]], constant int2& uTextureMetadataSize [[buffer(1)]], constant float2& uTileSize [[buffer(0)]], constant float4x4& uTransform [[buffer(2)]], texture2d<float> uTextureMetadata [[texture(0)]], sampler uTextureMetadataSmplr [[sampler(0)]])
|
|
||||||
{
|
|
||||||
main0_out out = {};
|
|
||||||
float2 tileOrigin = float2(in.aTileOrigin);
|
|
||||||
float2 tileOffset = float2(in.aTileOffset);
|
|
||||||
float2 position = (tileOrigin + tileOffset) * uTileSize;
|
|
||||||
float2 maskTexCoord0 = (float2(in.aMaskTexCoord0) + tileOffset) * uTileSize;
|
|
||||||
float2 textureMetadataScale = float2(1.0) / float2(uTextureMetadataSize);
|
|
||||||
float2 metadataEntryCoord = float2(float((in.aColor % 128) * 4), float(in.aColor / 128));
|
|
||||||
float2 colorTexMatrix0Coord = (metadataEntryCoord + float2(0.5)) * textureMetadataScale;
|
|
||||||
float2 colorTexOffsetsCoord = (metadataEntryCoord + float2(1.5, 0.5)) * textureMetadataScale;
|
|
||||||
float2 baseColorCoord = (metadataEntryCoord + float2(2.5, 0.5)) * textureMetadataScale;
|
|
||||||
float4 colorTexMatrix0 = uTextureMetadata.sample(uTextureMetadataSmplr, colorTexMatrix0Coord, level(0.0));
|
|
||||||
float4 colorTexOffsets = uTextureMetadata.sample(uTextureMetadataSmplr, colorTexOffsetsCoord, level(0.0));
|
|
||||||
float4 baseColor = uTextureMetadata.sample(uTextureMetadataSmplr, baseColorCoord, level(0.0));
|
|
||||||
out.vColorTexCoord0 = (float2x2(float2(colorTexMatrix0.xy), float2(colorTexMatrix0.zw)) * position) + colorTexOffsets.xy;
|
|
||||||
out.vMaskTexCoord0 = float3(maskTexCoord0, float(in.aMaskBackdrop.x));
|
|
||||||
out.vBaseColor = baseColor;
|
|
||||||
out.vTileCtrl = float(in.aTileCtrl);
|
|
||||||
out.gl_Position = uTransform * float4(position, 0.0, 1.0);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
||||||
#include <metal_stdlib>
|
|
||||||
#include <simd/simd.h>
|
|
||||||
|
|
||||||
using namespace metal;
|
|
||||||
|
|
||||||
struct main0_out
|
|
||||||
{
|
|
||||||
float2 vTexCoord [[user(locn0)]];
|
|
||||||
float vBackdrop [[user(locn1)]];
|
|
||||||
float4 gl_Position [[position]];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct main0_in
|
|
||||||
{
|
|
||||||
int2 aTileOffset [[attribute(0)]];
|
|
||||||
int2 aDestTileOrigin [[attribute(1)]];
|
|
||||||
int2 aSrcTileOrigin [[attribute(2)]];
|
|
||||||
int aSrcBackdrop [[attribute(3)]];
|
|
||||||
};
|
|
||||||
|
|
||||||
vertex main0_out main0(main0_in in [[stage_in]])
|
|
||||||
{
|
|
||||||
main0_out out = {};
|
|
||||||
float2 destPosition = float2(in.aDestTileOrigin + in.aTileOffset) / float2(256.0);
|
|
||||||
float2 srcPosition = float2(in.aSrcTileOrigin + in.aTileOffset) / float2(256.0);
|
|
||||||
out.vTexCoord = srcPosition;
|
|
||||||
out.vBackdrop = float(in.aSrcBackdrop);
|
|
||||||
out.gl_Position = float4(mix(float2(-1.0), float2(1.0), destPosition), 0.0, 1.0);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,36 +3,47 @@ TARGET_DIR?=../resources/shaders
|
||||||
EMPTY=
|
EMPTY=
|
||||||
|
|
||||||
SHADERS=\
|
SHADERS=\
|
||||||
|
d3d9/fill.fs.glsl \
|
||||||
|
d3d9/fill.vs.glsl \
|
||||||
|
d3d9/tile.fs.glsl \
|
||||||
|
d3d9/tile.vs.glsl \
|
||||||
|
d3d9/tile_clip_combine.fs.glsl \
|
||||||
|
d3d9/tile_clip_combine.vs.glsl \
|
||||||
|
d3d9/tile_clip_copy.fs.glsl \
|
||||||
|
d3d9/tile_clip_copy.vs.glsl \
|
||||||
|
d3d9/tile_copy.fs.glsl \
|
||||||
|
d3d9/tile_copy.vs.glsl \
|
||||||
|
debug/solid.fs.glsl \
|
||||||
|
debug/solid.vs.glsl \
|
||||||
|
debug/texture.fs.glsl \
|
||||||
|
debug/texture.vs.glsl \
|
||||||
blit.fs.glsl \
|
blit.fs.glsl \
|
||||||
blit.vs.glsl \
|
blit.vs.glsl \
|
||||||
clear.fs.glsl \
|
clear.fs.glsl \
|
||||||
clear.vs.glsl \
|
clear.vs.glsl \
|
||||||
debug_solid.fs.glsl \
|
|
||||||
debug_solid.vs.glsl \
|
|
||||||
debug_texture.fs.glsl \
|
|
||||||
debug_texture.vs.glsl \
|
|
||||||
demo_ground.fs.glsl \
|
demo_ground.fs.glsl \
|
||||||
demo_ground.vs.glsl \
|
demo_ground.vs.glsl \
|
||||||
fill.fs.glsl \
|
|
||||||
fill.vs.glsl \
|
|
||||||
reproject.fs.glsl \
|
reproject.fs.glsl \
|
||||||
reproject.vs.glsl \
|
reproject.vs.glsl \
|
||||||
stencil.fs.glsl \
|
stencil.fs.glsl \
|
||||||
stencil.vs.glsl \
|
stencil.vs.glsl \
|
||||||
tile.fs.glsl \
|
|
||||||
tile.vs.glsl \
|
|
||||||
tile_clip.fs.glsl \
|
|
||||||
tile_clip.vs.glsl \
|
|
||||||
tile_copy.fs.glsl \
|
|
||||||
tile_copy.vs.glsl \
|
|
||||||
$(EMPTY)
|
$(EMPTY)
|
||||||
|
|
||||||
COMPUTE_SHADERS=\
|
COMPUTE_SHADERS=\
|
||||||
fill.cs.glsl \
|
d3d11/bin.cs.glsl \
|
||||||
|
d3d11/bound.cs.glsl \
|
||||||
|
d3d11/dice.cs.glsl \
|
||||||
|
d3d11/fill.cs.glsl \
|
||||||
|
d3d11/propagate.cs.glsl \
|
||||||
|
d3d11/sort.cs.glsl \
|
||||||
|
d3d11/tile.cs.glsl \
|
||||||
$(EMPTY)
|
$(EMPTY)
|
||||||
|
|
||||||
INCLUDES=\
|
INCLUDES=\
|
||||||
fill.inc.glsl \
|
d3d11/fill_compute.inc.glsl \
|
||||||
|
fill_area.inc.glsl \
|
||||||
|
tile_fragment.inc.glsl \
|
||||||
|
tile_vertex.inc.glsl \
|
||||||
$(EMPTY)
|
$(EMPTY)
|
||||||
|
|
||||||
OUT=\
|
OUT=\
|
||||||
|
@ -58,6 +69,10 @@ HEADER="// Automatically generated from files in pathfinder/shaders/. Do not edi
|
||||||
|
|
||||||
GLSL_SED_ARGS=-e "s/\#version .*//" -e "s/\#line.*$$//"
|
GLSL_SED_ARGS=-e "s/\#version .*//" -e "s/\#line.*$$//"
|
||||||
|
|
||||||
|
GLSL_SHADER_TYPE.fs=frag
|
||||||
|
GLSL_SHADER_TYPE.vs=vert
|
||||||
|
GLSL_SHADER_TYPE.cs=comp
|
||||||
|
|
||||||
all: $(OUT)
|
all: $(OUT)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -65,29 +80,14 @@ all: $(OUT)
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OUT)
|
rm -f $(OUT)
|
||||||
|
|
||||||
build/metal/%.fs.spv: %.fs.glsl $(INCLUDES)
|
build/metal/%.spv: %.glsl $(INCLUDES)
|
||||||
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S frag -o $@ $<
|
mkdir -p $(dir $@) && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S $(GLSL_SHADER_TYPE$(suffix $(basename $(notdir $<)))) -o $@ $<
|
||||||
|
|
||||||
$(TARGET_DIR)/gl3/%.fs.glsl: %.fs.glsl $(INCLUDES)
|
$(TARGET_DIR)/gl3/%.glsl: %.glsl $(INCLUDES)
|
||||||
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
mkdir -p $(dir $@) && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S $(GLSL_SHADER_TYPE$(suffix $(basename $(notdir $<)))) -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
||||||
|
|
||||||
$(TARGET_DIR)/gl4/%.fs.glsl: %.fs.glsl $(INCLUDES)
|
$(TARGET_DIR)/gl4/%.glsl: %.glsl $(INCLUDES)
|
||||||
mkdir -p $(TARGET_DIR)/gl4 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
mkdir -p $(dir $@) && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S $(GLSL_SHADER_TYPE$(suffix $(basename $(notdir $<)))) -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
||||||
|
|
||||||
build/metal/%.vs.spv: %.vs.glsl $(INCLUDES)
|
|
||||||
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S vert -o $@ $<
|
|
||||||
|
|
||||||
$(TARGET_DIR)/gl3/%.vs.glsl: %.vs.glsl $(INCLUDES)
|
|
||||||
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
|
||||||
|
|
||||||
$(TARGET_DIR)/gl4/%.vs.glsl: %.vs.glsl $(INCLUDES)
|
|
||||||
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
|
||||||
|
|
||||||
build/metal/%.cs.spv: %.cs.glsl $(INCLUDES)
|
|
||||||
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_COMPUTE_VERSION) -S comp -o $@ $<
|
|
||||||
|
|
||||||
$(TARGET_DIR)/gl4/%.cs.glsl: %.cs.glsl $(INCLUDES)
|
|
||||||
mkdir -p $(TARGET_DIR)/gl4 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
|
|
||||||
|
|
||||||
$(TARGET_DIR)/metal/%.metal: build/metal/%.spv
|
$(TARGET_DIR)/metal/%.metal: build/metal/%.spv
|
||||||
mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< >> $@ ) || ( rm $@ && exit 1 )
|
mkdir -p $(dir $@) && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< >> $@ ) || ( rm $@ && exit 1 )
|
||||||
|
|
|
@ -24,5 +24,5 @@ out vec4 oFragColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 color = texture(uSrc, vTexCoord);
|
vec4 color = texture(uSrc, vTexCoord);
|
||||||
oFragColor = vec4(color.rgb * color.a, color.a);
|
oFragColor = color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,16 @@ precision highp float;
|
||||||
precision highp sampler2D;
|
precision highp sampler2D;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uniform vec4 uDestRect;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
in ivec2 aPosition;
|
in ivec2 aPosition;
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
vec2 position = mix(uDestRect.xy, uDestRect.zw, vec2(aPosition)) / uFramebufferSize;
|
||||||
vec2 texCoord = vec2(aPosition);
|
vec2 texCoord = vec2(aPosition);
|
||||||
#ifdef PF_ORIGIN_UPPER_LEFT
|
|
||||||
texCoord.y = 1.0 - texCoord.y;
|
|
||||||
#endif
|
|
||||||
vTexCoord = texCoord;
|
vTexCoord = texCoord;
|
||||||
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), vec2(aPosition)), 0.0, 1.0);
|
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), position), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/bin.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
// Assigns microlines to tiles.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
#define MAX_ITERATIONS 1024u
|
||||||
|
|
||||||
|
#define STEP_DIRECTION_NONE 0
|
||||||
|
#define STEP_DIRECTION_X 1
|
||||||
|
#define STEP_DIRECTION_Y 2
|
||||||
|
|
||||||
|
#define TILE_FIELD_NEXT_TILE_ID 0
|
||||||
|
#define TILE_FIELD_FIRST_FILL_ID 1
|
||||||
|
#define TILE_FIELD_BACKDROP_ALPHA_TILE_ID 2
|
||||||
|
#define TILE_FIELD_CONTROL 3
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
layout(local_size_x = 64) in;
|
||||||
|
|
||||||
|
uniform int uMicrolineCount;
|
||||||
|
// How many slots we have allocated for fills.
|
||||||
|
uniform int uMaxFillCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bMicrolines {
|
||||||
|
restrict readonly uvec4 iMicrolines[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer bMetadata {
|
||||||
|
// [0]: tile rect
|
||||||
|
// [1].x: tile offset
|
||||||
|
// [1].y: path ID
|
||||||
|
// [1].z: z write flag
|
||||||
|
// [1].w: clip path ID
|
||||||
|
// [2].x: backdrop offset
|
||||||
|
restrict readonly ivec4 iMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// [0]: vertexCount (6)
|
||||||
|
// [1]: instanceCount (of fills)
|
||||||
|
// [2]: vertexStart (0)
|
||||||
|
// [3]: baseInstance (0)
|
||||||
|
// [4]: alpha tile count
|
||||||
|
layout(std430, binding = 2) buffer bIndirectDrawParams {
|
||||||
|
restrict uint iIndirectDrawParams[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) buffer bFills {
|
||||||
|
restrict writeonly uint iFills[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 4) buffer bTiles {
|
||||||
|
// [0]: next tile ID (initialized to -1)
|
||||||
|
// [1]: first fill ID (initialized to -1)
|
||||||
|
// [2]: backdrop delta upper 8 bits, alpha tile ID lower 24 (initialized to 0, -1 respectively)
|
||||||
|
// [3]: color/ctrl/backdrop word
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 5) buffer bBackdrops {
|
||||||
|
// [0]: backdrop
|
||||||
|
// [1]: tile X offset
|
||||||
|
// [2]: path ID
|
||||||
|
restrict uint iBackdrops[];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint computeTileIndexNoCheck(ivec2 tileCoords, ivec4 pathTileRect, uint pathTileOffset) {
|
||||||
|
ivec2 offsetCoords = tileCoords - pathTileRect.xy;
|
||||||
|
return pathTileOffset + offsetCoords.x + offsetCoords.y * (pathTileRect.z - pathTileRect.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
bvec4 computeTileOutcodes(ivec2 tileCoords, ivec4 pathTileRect) {
|
||||||
|
return bvec4(lessThan(tileCoords, pathTileRect.xy),
|
||||||
|
greaterThanEqual(tileCoords, pathTileRect.zw));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool computeTileIndex(ivec2 tileCoords,
|
||||||
|
ivec4 pathTileRect,
|
||||||
|
uint pathTileOffset,
|
||||||
|
out uint outTileIndex) {
|
||||||
|
outTileIndex = computeTileIndexNoCheck(tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
return !any(computeTileOutcodes(tileCoords, pathTileRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFill(vec4 lineSegment, ivec2 tileCoords, ivec4 pathTileRect, uint pathTileOffset) {
|
||||||
|
// Compute tile offset. If out of bounds, cull.
|
||||||
|
uint tileIndex;
|
||||||
|
if (!computeTileIndex(tileCoords, pathTileRect, pathTileOffset, tileIndex)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clip line. If too narrow, cull.
|
||||||
|
uvec4 scaledLocalLine = uvec4((lineSegment - vec4(tileCoords.xyxy * ivec4(16))) * vec4(256.0));
|
||||||
|
if (scaledLocalLine.x == scaledLocalLine.z)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Bump instance count.
|
||||||
|
uint fillIndex = atomicAdd(iIndirectDrawParams[1], 1);
|
||||||
|
|
||||||
|
// Fill out the link field, inserting into the linked list.
|
||||||
|
uint fillLink = atomicExchange(iTiles[tileIndex * 4 + TILE_FIELD_FIRST_FILL_ID],
|
||||||
|
int(fillIndex));
|
||||||
|
|
||||||
|
// Write fill.
|
||||||
|
if (fillIndex < uMaxFillCount) {
|
||||||
|
iFills[fillIndex * 3 + 0] = scaledLocalLine.x | (scaledLocalLine.y << 16);
|
||||||
|
iFills[fillIndex * 3 + 1] = scaledLocalLine.z | (scaledLocalLine.w << 16);
|
||||||
|
iFills[fillIndex * 3 + 2] = fillLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjustBackdrop(int backdropDelta,
|
||||||
|
ivec2 tileCoords,
|
||||||
|
ivec4 pathTileRect,
|
||||||
|
uint pathTileOffset,
|
||||||
|
uint pathBackdropOffset) {
|
||||||
|
bvec4 outcodes = computeTileOutcodes(tileCoords, pathTileRect);
|
||||||
|
if (any(outcodes)) {
|
||||||
|
if (!outcodes.x && outcodes.y && !outcodes.z) {
|
||||||
|
uint backdropIndex = pathBackdropOffset + uint(tileCoords.x - pathTileRect.x);
|
||||||
|
atomicAdd(iBackdrops[backdropIndex * 3], backdropDelta);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint tileIndex = computeTileIndexNoCheck(tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
atomicAdd(iTiles[tileIndex * 4 + TILE_FIELD_BACKDROP_ALPHA_TILE_ID],
|
||||||
|
uint(backdropDelta) << 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 unpackMicroline(uvec4 packedMicroline, out uint outPathIndex) {
|
||||||
|
outPathIndex = packedMicroline.w;
|
||||||
|
ivec4 signedMicroline = ivec4(packedMicroline);
|
||||||
|
return vec4((signedMicroline.x << 16) >> 16, signedMicroline.x >> 16,
|
||||||
|
(signedMicroline.y << 16) >> 16, signedMicroline.y >> 16) +
|
||||||
|
vec4(signedMicroline.z & 0xff, (signedMicroline.z >> 8) & 0xff,
|
||||||
|
(signedMicroline.z >> 16) & 0xff, (signedMicroline.z >> 24) & 0xff) / 256.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
uint segmentIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (segmentIndex >= uMicrolineCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint pathIndex;
|
||||||
|
vec4 lineSegment = unpackMicroline(iMicrolines[segmentIndex], pathIndex);
|
||||||
|
|
||||||
|
ivec4 pathTileRect = iMetadata[pathIndex * 3 + 0];
|
||||||
|
uint pathTileOffset = uint(iMetadata[pathIndex * 3 + 1].x);
|
||||||
|
uint pathBackdropOffset = uint(iMetadata[pathIndex * 3 + 2].x);
|
||||||
|
|
||||||
|
// Following is a straight port of `process_line_segment()`:
|
||||||
|
|
||||||
|
ivec2 tileSize = ivec2(16);
|
||||||
|
|
||||||
|
ivec4 tileLineSegment = ivec4(floor(lineSegment / vec4(tileSize.xyxy)));
|
||||||
|
ivec2 fromTileCoords = tileLineSegment.xy, toTileCoords = tileLineSegment.zw;
|
||||||
|
|
||||||
|
vec2 vector = lineSegment.zw - lineSegment.xy;
|
||||||
|
vec2 vectorIsNegative = vec2(vector.x < 0.0 ? -1.0 : 0.0, vector.y < 0.0 ? -1.0 : 0.0);
|
||||||
|
ivec2 tileStep = ivec2(vector.x < 0.0 ? -1 : 1, vector.y < 0.0 ? -1 : 1);
|
||||||
|
|
||||||
|
vec2 firstTileCrossing = vec2((fromTileCoords + ivec2(vector.x >= 0.0 ? 1 : 0,
|
||||||
|
vector.y >= 0.0 ? 1 : 0)) * tileSize);
|
||||||
|
|
||||||
|
vec2 tMax = (firstTileCrossing - lineSegment.xy) / vector;
|
||||||
|
vec2 tDelta = abs(tileSize / vector);
|
||||||
|
|
||||||
|
vec2 currentPosition = lineSegment.xy;
|
||||||
|
ivec2 tileCoords = fromTileCoords;
|
||||||
|
int lastStepDirection = STEP_DIRECTION_NONE;
|
||||||
|
uint iteration = 0;
|
||||||
|
|
||||||
|
while (iteration < MAX_ITERATIONS) {
|
||||||
|
int nextStepDirection;
|
||||||
|
if (tMax.x < tMax.y)
|
||||||
|
nextStepDirection = STEP_DIRECTION_X;
|
||||||
|
else if (tMax.x > tMax.y)
|
||||||
|
nextStepDirection = STEP_DIRECTION_Y;
|
||||||
|
else if (tileStep.x > 0.0)
|
||||||
|
nextStepDirection = STEP_DIRECTION_X;
|
||||||
|
else
|
||||||
|
nextStepDirection = STEP_DIRECTION_Y;
|
||||||
|
|
||||||
|
float nextT = min(nextStepDirection == STEP_DIRECTION_X ? tMax.x : tMax.y, 1.0);
|
||||||
|
|
||||||
|
// If we've reached the end tile, don't step at all.
|
||||||
|
if (tileCoords == toTileCoords)
|
||||||
|
nextStepDirection = STEP_DIRECTION_NONE;
|
||||||
|
|
||||||
|
vec2 nextPosition = mix(lineSegment.xy, lineSegment.zw, nextT);
|
||||||
|
vec4 clippedLineSegment = vec4(currentPosition, nextPosition);
|
||||||
|
addFill(clippedLineSegment, tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
|
||||||
|
// Add extra fills if necessary.
|
||||||
|
vec4 auxiliarySegment;
|
||||||
|
bool haveAuxiliarySegment = false;
|
||||||
|
if (tileStep.y < 0 && nextStepDirection == STEP_DIRECTION_Y) {
|
||||||
|
auxiliarySegment = vec4(clippedLineSegment.zw, vec2(tileCoords * tileSize));
|
||||||
|
haveAuxiliarySegment = true;
|
||||||
|
} else if (tileStep.y > 0 && lastStepDirection == STEP_DIRECTION_Y) {
|
||||||
|
auxiliarySegment = vec4(vec2(tileCoords * tileSize), clippedLineSegment.xy);
|
||||||
|
haveAuxiliarySegment = true;
|
||||||
|
}
|
||||||
|
if (haveAuxiliarySegment)
|
||||||
|
addFill(auxiliarySegment, tileCoords, pathTileRect, pathTileOffset);
|
||||||
|
|
||||||
|
// Adjust backdrop if necessary.
|
||||||
|
//
|
||||||
|
// NB: Do not refactor the calls below. This exact code sequence is needed to avoid a
|
||||||
|
// miscompilation on the Radeon Metal compiler.
|
||||||
|
if (tileStep.x < 0 && lastStepDirection == STEP_DIRECTION_X) {
|
||||||
|
adjustBackdrop(1,
|
||||||
|
tileCoords,
|
||||||
|
pathTileRect,
|
||||||
|
pathTileOffset,
|
||||||
|
pathBackdropOffset);
|
||||||
|
} else if (tileStep.x > 0 && nextStepDirection == STEP_DIRECTION_X) {
|
||||||
|
adjustBackdrop(-1,
|
||||||
|
tileCoords,
|
||||||
|
pathTileRect,
|
||||||
|
pathTileOffset,
|
||||||
|
pathBackdropOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a step.
|
||||||
|
if (nextStepDirection == STEP_DIRECTION_X) {
|
||||||
|
tMax.x += tDelta.x;
|
||||||
|
tileCoords.x += tileStep.x;
|
||||||
|
} else if (nextStepDirection == STEP_DIRECTION_Y) {
|
||||||
|
tMax.y += tDelta.y;
|
||||||
|
tileCoords.y += tileStep.y;
|
||||||
|
} else if (nextStepDirection == STEP_DIRECTION_NONE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPosition = nextPosition;
|
||||||
|
lastStepDirection = nextStepDirection;
|
||||||
|
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/bound.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
// Initializes the tile maps.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TILE_FIELD_NEXT_TILE_ID 0
|
||||||
|
#define TILE_FIELD_FIRST_FILL_ID 1
|
||||||
|
#define TILE_FIELD_BACKDROP_ALPHA_TILE_ID 2
|
||||||
|
#define TILE_FIELD_CONTROL 3
|
||||||
|
|
||||||
|
layout(local_size_x = 64) in;
|
||||||
|
|
||||||
|
uniform int uPathCount;
|
||||||
|
uniform int uTileCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bTilePathInfo {
|
||||||
|
// x: tile upper left, 16-bit packed x/y
|
||||||
|
// y: tile lower right, 16-bit packed x/y
|
||||||
|
// z: first tile index in this path
|
||||||
|
// w: color/ctrl/backdrop word
|
||||||
|
restrict readonly uvec4 iTilePathInfo[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer bTiles {
|
||||||
|
// [0]: next tile ID (initialized to -1)
|
||||||
|
// [1]: first fill ID (initialized to -1)
|
||||||
|
// [2]: backdrop delta upper 8 bits, alpha tile ID lower 24 (initialized to 0, -1 respectively)
|
||||||
|
// [3]: color/ctrl/backdrop word
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
uint tileIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (tileIndex >= uint(uTileCount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint lowPathIndex = 0, highPathIndex = uint(uPathCount);
|
||||||
|
int iteration = 0;
|
||||||
|
while (iteration < 1024 && lowPathIndex + 1 < highPathIndex) {
|
||||||
|
uint midPathIndex = lowPathIndex + (highPathIndex - lowPathIndex) / 2;
|
||||||
|
uint midTileIndex = iTilePathInfo[midPathIndex].z;
|
||||||
|
if (tileIndex < midTileIndex) {
|
||||||
|
highPathIndex = midPathIndex;
|
||||||
|
} else {
|
||||||
|
lowPathIndex = midPathIndex;
|
||||||
|
if (tileIndex == midTileIndex)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint pathIndex = lowPathIndex;
|
||||||
|
uvec4 pathInfo = iTilePathInfo[pathIndex];
|
||||||
|
|
||||||
|
ivec2 packedTileRect = ivec2(pathInfo.xy);
|
||||||
|
ivec4 tileRect = ivec4((packedTileRect.x << 16) >> 16, packedTileRect.x >> 16,
|
||||||
|
(packedTileRect.y << 16) >> 16, packedTileRect.y >> 16);
|
||||||
|
|
||||||
|
uint tileOffset = tileIndex - pathInfo.z;
|
||||||
|
uint tileWidth = uint(tileRect.z - tileRect.x);
|
||||||
|
ivec2 tileCoords = tileRect.xy + ivec2(tileOffset % tileWidth, tileOffset / tileWidth);
|
||||||
|
|
||||||
|
iTiles[tileIndex * 4 + TILE_FIELD_NEXT_TILE_ID] = ~0u;
|
||||||
|
iTiles[tileIndex * 4 + TILE_FIELD_FIRST_FILL_ID] = ~0u;
|
||||||
|
iTiles[tileIndex * 4 + TILE_FIELD_BACKDROP_ALPHA_TILE_ID] = 0x00ffffffu;
|
||||||
|
iTiles[tileIndex * 4 + TILE_FIELD_CONTROL] = pathInfo.w;
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/dice.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
// Chops lines and curves into microlines.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
#define BIN_WORKGROUP_SIZE 64
|
||||||
|
|
||||||
|
#define MAX_CURVE_STACK_SIZE 32
|
||||||
|
|
||||||
|
#define FLAGS_PATH_INDEX_CURVE_IS_QUADRATIC 0x80000000u
|
||||||
|
#define FLAGS_PATH_INDEX_CURVE_IS_CUBIC 0x40000000u
|
||||||
|
|
||||||
|
#define BIN_INDIRECT_DRAW_PARAMS_MICROLINE_COUNT_INDEX 3
|
||||||
|
|
||||||
|
#define TOLERANCE 0.25
|
||||||
|
#define MICROLINE_LENGTH 16.0
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
layout(local_size_x = 64) in;
|
||||||
|
|
||||||
|
uniform mat2 uTransform;
|
||||||
|
uniform vec2 uTranslation;
|
||||||
|
uniform int uPathCount;
|
||||||
|
uniform int uLastBatchSegmentIndex;
|
||||||
|
uniform int uMaxMicrolineCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bComputeIndirectParams {
|
||||||
|
// [0]: number of x workgroups
|
||||||
|
// [1]: number of y workgroups (always 1)
|
||||||
|
// [2]: number of z workgroups (always 1)
|
||||||
|
// [3]: number of output microlines
|
||||||
|
restrict uint iComputeIndirectParams[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Indexed by batch path index.
|
||||||
|
layout(std430, binding = 1) buffer bDiceMetadata {
|
||||||
|
// x: global path ID
|
||||||
|
// y: first global segment index
|
||||||
|
// z: first batch segment index
|
||||||
|
// w: unused
|
||||||
|
restrict readonly uvec4 iDiceMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) buffer bPoints {
|
||||||
|
restrict readonly vec2 iPoints[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) buffer bInputIndices {
|
||||||
|
restrict readonly uvec2 iInputIndices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 4) buffer bMicrolines {
|
||||||
|
// x: from (X, Y) whole pixels, packed signed 16-bit
|
||||||
|
// y: to (X, Y) whole pixels, packed signed 16-bit
|
||||||
|
// z: (from X, from Y, to X, to Y) fractional pixels, packed unsigned 8-bit (0.8 fixed point)
|
||||||
|
// w: path ID
|
||||||
|
restrict uvec4 iMicrolines[];
|
||||||
|
};
|
||||||
|
|
||||||
|
void emitMicroline(vec4 microlineSegment, uint pathIndex, uint outputMicrolineIndex) {
|
||||||
|
if (outputMicrolineIndex >= uMaxMicrolineCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ivec4 microlineSubpixels = ivec4(round(clamp(microlineSegment, -32768.0, 32767.0) * 256.0));
|
||||||
|
ivec4 microlinePixels = ivec4(floor(vec4(microlineSubpixels) / 256.0));
|
||||||
|
ivec4 microlineFractPixels = microlineSubpixels - microlinePixels * 256;
|
||||||
|
|
||||||
|
iMicrolines[outputMicrolineIndex] =
|
||||||
|
uvec4((uint(microlinePixels.x) & 0xffff) | (uint(microlinePixels.y) << 16),
|
||||||
|
(uint(microlinePixels.z) & 0xffff) | (uint(microlinePixels.w) << 16),
|
||||||
|
uint(microlineFractPixels.x) | (uint(microlineFractPixels.y) << 8) |
|
||||||
|
(uint(microlineFractPixels.z) << 16) | (uint(microlineFractPixels.w) << 24),
|
||||||
|
pathIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See Kaspar Fischer, "Piecewise Linear Approximation of Bézier Curves", 2000.
|
||||||
|
bool curveIsFlat(vec4 baseline, vec4 ctrl) {
|
||||||
|
vec4 uv = vec4(3.0) * ctrl - vec4(2.0) * baseline - baseline.zwxy;
|
||||||
|
uv *= uv;
|
||||||
|
uv = max(uv, uv.zwxy);
|
||||||
|
return uv.x + uv.y <= 16.0 * TOLERANCE * TOLERANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subdivideCurve(vec4 baseline,
|
||||||
|
vec4 ctrl,
|
||||||
|
float t,
|
||||||
|
out vec4 prevBaseline,
|
||||||
|
out vec4 prevCtrl,
|
||||||
|
out vec4 nextBaseline,
|
||||||
|
out vec4 nextCtrl) {
|
||||||
|
vec2 p0 = baseline.xy, p1 = ctrl.xy, p2 = ctrl.zw, p3 = baseline.zw;
|
||||||
|
vec2 p0p1 = mix(p0, p1, t), p1p2 = mix(p1, p2, t), p2p3 = mix(p2, p3, t);
|
||||||
|
vec2 p0p1p2 = mix(p0p1, p1p2, t), p1p2p3 = mix(p1p2, p2p3, t);
|
||||||
|
vec2 p0p1p2p3 = mix(p0p1p2, p1p2p3, t);
|
||||||
|
prevBaseline = vec4(p0, p0p1p2p3);
|
||||||
|
prevCtrl = vec4(p0p1, p0p1p2);
|
||||||
|
nextBaseline = vec4(p0p1p2p3, p3);
|
||||||
|
nextCtrl = vec4(p1p2p3, p2p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 sampleCurve(vec4 baseline, vec4 ctrl, float t) {
|
||||||
|
vec2 p0 = baseline.xy, p1 = ctrl.xy, p2 = ctrl.zw, p3 = baseline.zw;
|
||||||
|
vec2 p0p1 = mix(p0, p1, t), p1p2 = mix(p1, p2, t), p2p3 = mix(p2, p3, t);
|
||||||
|
vec2 p0p1p2 = mix(p0p1, p1p2, t), p1p2p3 = mix(p1p2, p2p3, t);
|
||||||
|
return mix(p0p1p2, p1p2p3, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 sampleLine(vec4 line, float t) {
|
||||||
|
return mix(line.xy, line.zw, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getPoint(uint pointIndex) {
|
||||||
|
return uTransform * iPoints[pointIndex] + uTranslation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
uint batchSegmentIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (batchSegmentIndex >= uLastBatchSegmentIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Find the path index.
|
||||||
|
uint lowPathIndex = 0, highPathIndex = uint(uPathCount);
|
||||||
|
int iteration = 0;
|
||||||
|
while (iteration < 1024 && lowPathIndex + 1 < highPathIndex) {
|
||||||
|
uint midPathIndex = lowPathIndex + (highPathIndex - lowPathIndex) / 2;
|
||||||
|
uint midBatchSegmentIndex = iDiceMetadata[midPathIndex].z;
|
||||||
|
if (batchSegmentIndex < midBatchSegmentIndex) {
|
||||||
|
highPathIndex = midPathIndex;
|
||||||
|
} else {
|
||||||
|
lowPathIndex = midPathIndex;
|
||||||
|
if (batchSegmentIndex == midBatchSegmentIndex)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint batchPathIndex = lowPathIndex;
|
||||||
|
uvec4 diceMetadata = iDiceMetadata[batchPathIndex];
|
||||||
|
uint firstGlobalSegmentIndexInPath = diceMetadata.y;
|
||||||
|
uint firstBatchSegmentIndexInPath = diceMetadata.z;
|
||||||
|
uint globalSegmentIndex = batchSegmentIndex - firstBatchSegmentIndexInPath +
|
||||||
|
firstGlobalSegmentIndexInPath;
|
||||||
|
|
||||||
|
uvec2 inputIndices = iInputIndices[globalSegmentIndex];
|
||||||
|
uint fromPointIndex = inputIndices.x, flagsPathIndex = inputIndices.y;
|
||||||
|
|
||||||
|
uint toPointIndex = fromPointIndex;
|
||||||
|
if ((flagsPathIndex & FLAGS_PATH_INDEX_CURVE_IS_CUBIC) != 0u)
|
||||||
|
toPointIndex += 3;
|
||||||
|
else if ((flagsPathIndex & FLAGS_PATH_INDEX_CURVE_IS_QUADRATIC) != 0u)
|
||||||
|
toPointIndex += 2;
|
||||||
|
else
|
||||||
|
toPointIndex += 1;
|
||||||
|
|
||||||
|
vec4 baseline = vec4(getPoint(fromPointIndex), getPoint(toPointIndex));
|
||||||
|
|
||||||
|
// Read control points if applicable, and calculate number of segments.
|
||||||
|
//
|
||||||
|
// The technique is from Thomas Sederberg, "Computer-Aided Geometric Design" notes, section
|
||||||
|
// 10.6 "Error Bounds".
|
||||||
|
vec4 ctrl = vec4(0.0);
|
||||||
|
float segmentCountF;
|
||||||
|
bool isCurve = (flagsPathIndex & (FLAGS_PATH_INDEX_CURVE_IS_CUBIC |
|
||||||
|
FLAGS_PATH_INDEX_CURVE_IS_QUADRATIC)) != 0;
|
||||||
|
if (isCurve) {
|
||||||
|
vec2 ctrl0 = getPoint(fromPointIndex + 1);
|
||||||
|
if ((flagsPathIndex & FLAGS_PATH_INDEX_CURVE_IS_QUADRATIC) != 0) {
|
||||||
|
vec2 ctrl0_2 = ctrl0 * vec2(2.0);
|
||||||
|
ctrl = (baseline + (ctrl0 * vec2(2.0)).xyxy) * vec4(1.0 / 3.0);
|
||||||
|
} else {
|
||||||
|
ctrl = vec4(ctrl0, getPoint(fromPointIndex + 2));
|
||||||
|
}
|
||||||
|
vec2 bound = vec2(6.0) * max(abs(ctrl.zw - 2.0 * ctrl.xy + baseline.xy),
|
||||||
|
abs(baseline.zw - 2.0 * ctrl.zw + ctrl.xy));
|
||||||
|
segmentCountF = sqrt(length(bound) / (8.0 * TOLERANCE));
|
||||||
|
} else {
|
||||||
|
segmentCountF = length(baseline.zw - baseline.xy) / MICROLINE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate space.
|
||||||
|
int segmentCount = max(int(ceil(segmentCountF)), 1);
|
||||||
|
uint firstOutputMicrolineIndex =
|
||||||
|
atomicAdd(iComputeIndirectParams[BIN_INDIRECT_DRAW_PARAMS_MICROLINE_COUNT_INDEX],
|
||||||
|
segmentCount);
|
||||||
|
|
||||||
|
float prevT = 0.0;
|
||||||
|
vec2 prevPoint = baseline.xy;
|
||||||
|
for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++) {
|
||||||
|
float nextT = float(segmentIndex + 1) / float(segmentCount);
|
||||||
|
vec2 nextPoint;
|
||||||
|
if (isCurve)
|
||||||
|
nextPoint = sampleCurve(baseline, ctrl, nextT);
|
||||||
|
else
|
||||||
|
nextPoint = sampleLine(baseline, nextT);
|
||||||
|
emitMicroline(vec4(prevPoint, nextPoint),
|
||||||
|
batchPathIndex,
|
||||||
|
firstOutputMicrolineIndex + segmentIndex);
|
||||||
|
prevT = nextT;
|
||||||
|
prevPoint = nextPoint;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/fill.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "fill_area.inc.glsl"
|
||||||
|
|
||||||
|
layout(local_size_x = 16, local_size_y = 4) in;
|
||||||
|
|
||||||
|
#define TILE_FIELD_NEXT_TILE_ID 0
|
||||||
|
#define TILE_FIELD_FIRST_FILL_ID 1
|
||||||
|
#define TILE_FIELD_BACKDROP_ALPHA_TILE_ID 2
|
||||||
|
#define TILE_FIELD_CONTROL 3
|
||||||
|
|
||||||
|
layout(rgba8) uniform image2D uDest;
|
||||||
|
uniform sampler2D uAreaLUT;
|
||||||
|
uniform ivec2 uAlphaTileRange;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bFills {
|
||||||
|
restrict readonly uint iFills[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer bTiles {
|
||||||
|
// [0]: path ID
|
||||||
|
// [1]: next tile ID
|
||||||
|
// [2]: first fill ID
|
||||||
|
// [3]: backdrop delta upper 8 bits, alpha tile ID lower 24 bits
|
||||||
|
// [4]: color/ctrl/backdrop word
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) buffer bAlphaTiles {
|
||||||
|
// [0]: alpha tile index
|
||||||
|
// [1]: clip tile index
|
||||||
|
restrict readonly uint iAlphaTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "fill_compute.inc.glsl"
|
||||||
|
|
||||||
|
ivec2 computeTileCoord(uint alphaTileIndex) {
|
||||||
|
uint x = alphaTileIndex & 0xff;
|
||||||
|
uint y = (alphaTileIndex >> 8u) & 0xff + (((alphaTileIndex >> 16u) & 0xff) << 8u);
|
||||||
|
return ivec2(16, 4) * ivec2(x, y) + ivec2(gl_LocalInvocationID.xy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec2 tileSubCoord = ivec2(gl_LocalInvocationID.xy) * ivec2(1, 4);
|
||||||
|
|
||||||
|
// This is a workaround for the 64K workgroup dispatch limit in OpenGL.
|
||||||
|
uint batchAlphaTileIndex = (gl_WorkGroupID.x | (gl_WorkGroupID.y << 15));
|
||||||
|
uint alphaTileIndex = batchAlphaTileIndex + uint(uAlphaTileRange.x);
|
||||||
|
if (alphaTileIndex >= uint(uAlphaTileRange.y))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint tileIndex = iAlphaTiles[batchAlphaTileIndex * 2 + 0];
|
||||||
|
if ((int(iTiles[tileIndex * 4 + TILE_FIELD_BACKDROP_ALPHA_TILE_ID] << 8) >> 8) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int fillIndex = int(iTiles[tileIndex * 4 + TILE_FIELD_FIRST_FILL_ID]);
|
||||||
|
int backdrop = int(iTiles[tileIndex * 4 + TILE_FIELD_CONTROL]) >> 24;
|
||||||
|
|
||||||
|
// TODO(pcwalton): Handle even-odd fill rule.
|
||||||
|
vec4 coverages = vec4(backdrop);
|
||||||
|
coverages += accumulateCoverageForFillList(fillIndex, tileSubCoord);
|
||||||
|
coverages = clamp(abs(coverages), 0.0, 1.0);
|
||||||
|
|
||||||
|
// Handle clip if necessary.
|
||||||
|
int clipTileIndex = int(iAlphaTiles[batchAlphaTileIndex * 2 + 1]);
|
||||||
|
if (clipTileIndex >= 0)
|
||||||
|
coverages = min(coverages, imageLoad(uDest, computeTileCoord(clipTileIndex)));
|
||||||
|
|
||||||
|
imageStore(uDest, computeTileCoord(alphaTileIndex), coverages);
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// pathfinder/shaders/fill_compute.inc.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
vec4 accumulateCoverageForFillList(int fillIndex, ivec2 tileSubCoord) {
|
||||||
|
vec2 tileFragCoord = vec2(tileSubCoord) + vec2(0.5);
|
||||||
|
vec4 coverages = vec4(0.0);
|
||||||
|
int iteration = 0;
|
||||||
|
do {
|
||||||
|
uint fillFrom = iFills[fillIndex * 3 + 0], fillTo = iFills[fillIndex * 3 + 1];
|
||||||
|
vec4 lineSegment = vec4(fillFrom & 0xffff, fillFrom >> 16,
|
||||||
|
fillTo & 0xffff, fillTo >> 16) / 256.0;
|
||||||
|
lineSegment -= tileFragCoord.xyxy;
|
||||||
|
coverages += computeCoverage(lineSegment.xy, lineSegment.zw, uAreaLUT);
|
||||||
|
fillIndex = int(iFills[fillIndex * 3 + 2]);
|
||||||
|
iteration++;
|
||||||
|
} while (fillIndex >= 0 && iteration < 1024);
|
||||||
|
return coverages;
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/propagate.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
// Sum up backdrops to propagate fills across tiles, and allocate alpha tiles.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
layout(local_size_x = 64) in;
|
||||||
|
|
||||||
|
#define TILE_FIELD_NEXT_TILE_ID 0
|
||||||
|
#define TILE_FIELD_FIRST_FILL_ID 1
|
||||||
|
#define TILE_FIELD_BACKDROP_ALPHA_TILE_ID 2
|
||||||
|
#define TILE_FIELD_CONTROL 3
|
||||||
|
|
||||||
|
uniform ivec2 uFramebufferTileSize;
|
||||||
|
uniform int uColumnCount;
|
||||||
|
uniform int uFirstAlphaTileIndex;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bDrawMetadata {
|
||||||
|
// [0]: tile rect
|
||||||
|
// [1].x: tile offset
|
||||||
|
// [1].y: path ID
|
||||||
|
// [1].z: Z write enabled?
|
||||||
|
// [1].w: clip path ID, or ~0
|
||||||
|
// [2].x: backdrop column offset
|
||||||
|
restrict readonly uvec4 iDrawMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer bClipMetadata {
|
||||||
|
// [0]: tile rect
|
||||||
|
// [1].x: tile offset
|
||||||
|
// [1].y: unused
|
||||||
|
// [1].z: unused
|
||||||
|
// [1].w: unused
|
||||||
|
restrict readonly uvec4 iClipMetadata[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) buffer bBackdrops {
|
||||||
|
// [0]: backdrop
|
||||||
|
// [1]: tile X offset
|
||||||
|
// [2]: path ID
|
||||||
|
restrict readonly int iBackdrops[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) buffer bDrawTiles {
|
||||||
|
// [0]: next tile ID
|
||||||
|
// [1]: first fill ID
|
||||||
|
// [2]: backdrop delta upper 8 bits, alpha tile ID lower 24
|
||||||
|
// [3]: color/ctrl/backdrop word
|
||||||
|
restrict uint iDrawTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 4) buffer bClipTiles {
|
||||||
|
// [0]: next tile ID
|
||||||
|
// [1]: first fill ID
|
||||||
|
// [2]: backdrop delta upper 8 bits, alpha tile ID lower 24
|
||||||
|
// [3]: color/ctrl/backdrop word
|
||||||
|
restrict uint iClipTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 5) buffer bZBuffer {
|
||||||
|
restrict int iZBuffer[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 6) buffer bFirstTileMap {
|
||||||
|
restrict int iFirstTileMap[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 7) buffer bIndirectDrawParams {
|
||||||
|
// [0]: vertexCount (6)
|
||||||
|
// [1]: instanceCount (of fills)
|
||||||
|
// [2]: vertexStart (0)
|
||||||
|
// [3]: baseInstance (0)
|
||||||
|
// [4]: alpha tile count
|
||||||
|
restrict uint iIndirectDrawParams[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 8) buffer bAlphaTiles {
|
||||||
|
// [0]: alpha tile index
|
||||||
|
// [1]: clip tile index
|
||||||
|
restrict uint iAlphaTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint calculateTileIndex(uint bufferOffset, uvec4 tileRect, uvec2 tileCoord) {
|
||||||
|
return bufferOffset + tileCoord.y * (tileRect.z - tileRect.x) + tileCoord.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
uint columnIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (int(columnIndex) >= uColumnCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int currentBackdrop = iBackdrops[columnIndex * 3 + 0];
|
||||||
|
int tileX = iBackdrops[columnIndex * 3 + 1];
|
||||||
|
uint drawPathIndex = uint(iBackdrops[columnIndex * 3 + 2]);
|
||||||
|
|
||||||
|
uvec4 drawTileRect = iDrawMetadata[drawPathIndex * 3 + 0];
|
||||||
|
uvec4 drawOffsets = iDrawMetadata[drawPathIndex * 3 + 1];
|
||||||
|
uvec2 drawTileSize = drawTileRect.zw - drawTileRect.xy;
|
||||||
|
uint drawTileBufferOffset = drawOffsets.x;
|
||||||
|
bool zWrite = drawOffsets.z != 0;
|
||||||
|
|
||||||
|
int clipPathIndex = int(drawOffsets.w);
|
||||||
|
uvec4 clipTileRect = uvec4(0u), clipOffsets = uvec4(0u);
|
||||||
|
if (clipPathIndex >= 0) {
|
||||||
|
clipTileRect = iClipMetadata[clipPathIndex * 2 + 0];
|
||||||
|
clipOffsets = iClipMetadata[clipPathIndex * 2 + 1];
|
||||||
|
}
|
||||||
|
uint clipTileBufferOffset = clipOffsets.x, clipBackdropOffset = clipOffsets.y;
|
||||||
|
|
||||||
|
for (uint tileY = 0; tileY < drawTileSize.y; tileY++) {
|
||||||
|
uvec2 drawTileCoord = uvec2(tileX, tileY);
|
||||||
|
uint drawTileIndex = calculateTileIndex(drawTileBufferOffset, drawTileRect, drawTileCoord);
|
||||||
|
|
||||||
|
int drawAlphaTileIndex = -1;
|
||||||
|
int clipAlphaTileIndex = -1;
|
||||||
|
int drawFirstFillIndex = int(iDrawTiles[drawTileIndex * 4 + TILE_FIELD_FIRST_FILL_ID]);
|
||||||
|
int drawBackdropDelta =
|
||||||
|
int(iDrawTiles[drawTileIndex * 4 + TILE_FIELD_BACKDROP_ALPHA_TILE_ID]) >> 24;
|
||||||
|
uint drawTileWord = iDrawTiles[drawTileIndex * 4 + TILE_FIELD_CONTROL] & 0x00ffffff;
|
||||||
|
|
||||||
|
int drawTileBackdrop = currentBackdrop;
|
||||||
|
bool haveDrawAlphaMask = drawFirstFillIndex >= 0;
|
||||||
|
bool needNewAlphaTile = haveDrawAlphaMask;
|
||||||
|
|
||||||
|
// Handle clip if necessary.
|
||||||
|
if (clipPathIndex >= 0) {
|
||||||
|
uvec2 tileCoord = drawTileCoord + drawTileRect.xy;
|
||||||
|
if (all(bvec4(greaterThanEqual(tileCoord, clipTileRect.xy),
|
||||||
|
lessThan (tileCoord, clipTileRect.zw)))) {
|
||||||
|
uvec2 clipTileCoord = tileCoord - clipTileRect.xy;
|
||||||
|
uint clipTileIndex = calculateTileIndex(clipTileBufferOffset,
|
||||||
|
clipTileRect,
|
||||||
|
clipTileCoord);
|
||||||
|
|
||||||
|
/*
|
||||||
|
clipAlphaTileIndex =
|
||||||
|
int(iClipTiles[clipTileIndex * 4 +
|
||||||
|
TILE_FIELD_BACKDROP_ALPHA_TILE_ID] << 8) >> 8;
|
||||||
|
*/
|
||||||
|
int thisClipAlphaTileIndex =
|
||||||
|
int(iClipTiles[clipTileIndex * 4 +
|
||||||
|
TILE_FIELD_BACKDROP_ALPHA_TILE_ID] << 8) >> 8;
|
||||||
|
|
||||||
|
uint clipTileWord = iClipTiles[clipTileIndex * 4 + TILE_FIELD_CONTROL];
|
||||||
|
int clipTileBackdrop = int(clipTileWord) >> 24;
|
||||||
|
|
||||||
|
if (thisClipAlphaTileIndex >= 0) {
|
||||||
|
if (haveDrawAlphaMask) {
|
||||||
|
clipAlphaTileIndex = thisClipAlphaTileIndex;
|
||||||
|
needNewAlphaTile = true;
|
||||||
|
} else {
|
||||||
|
if (drawTileBackdrop != 0) {
|
||||||
|
// This is a solid draw tile, but there's a clip applied. Replace it with an
|
||||||
|
// alpha tile pointing directly to the clip mask.
|
||||||
|
drawAlphaTileIndex = thisClipAlphaTileIndex;
|
||||||
|
clipAlphaTileIndex = -1;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
} else {
|
||||||
|
// No draw alpha tile index, no clip alpha tile index.
|
||||||
|
drawAlphaTileIndex = -1;
|
||||||
|
clipAlphaTileIndex = -1;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No clip tile.
|
||||||
|
if (clipTileBackdrop == 0) {
|
||||||
|
// This is a blank clip tile. Cull the draw tile entirely.
|
||||||
|
drawTileBackdrop = 0;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
} else {
|
||||||
|
needNewAlphaTile = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This draw tile is outside the clip path bounding rect. Cull the draw tile.
|
||||||
|
drawTileBackdrop = 0;
|
||||||
|
needNewAlphaTile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needNewAlphaTile) {
|
||||||
|
uint drawBatchAlphaTileIndex = atomicAdd(iIndirectDrawParams[4], 1);
|
||||||
|
iAlphaTiles[drawBatchAlphaTileIndex * 2 + 0] = drawTileIndex;
|
||||||
|
iAlphaTiles[drawBatchAlphaTileIndex * 2 + 1] = clipAlphaTileIndex;
|
||||||
|
drawAlphaTileIndex = int(drawBatchAlphaTileIndex) + uFirstAlphaTileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
iDrawTiles[drawTileIndex * 4 + TILE_FIELD_BACKDROP_ALPHA_TILE_ID] =
|
||||||
|
(uint(drawAlphaTileIndex) & 0x00ffffffu) | (uint(drawBackdropDelta) << 24);
|
||||||
|
iDrawTiles[drawTileIndex * 4 + TILE_FIELD_CONTROL] =
|
||||||
|
drawTileWord | (uint(drawTileBackdrop) << 24);
|
||||||
|
|
||||||
|
// Write to Z-buffer if necessary.
|
||||||
|
ivec2 tileCoord = ivec2(tileX, tileY) + ivec2(drawTileRect.xy);
|
||||||
|
int tileMapIndex = tileCoord.y * uFramebufferTileSize.x + tileCoord.x;
|
||||||
|
if (zWrite && drawTileBackdrop != 0 && drawAlphaTileIndex < 0)
|
||||||
|
atomicMax(iZBuffer[tileMapIndex], int(drawTileIndex));
|
||||||
|
|
||||||
|
// Stitch into the linked list if necessary.
|
||||||
|
if (drawTileBackdrop != 0 || drawAlphaTileIndex >= 0) {
|
||||||
|
int nextTileIndex = atomicExchange(iFirstTileMap[tileMapIndex], int(drawTileIndex));
|
||||||
|
iDrawTiles[drawTileIndex * 4 + TILE_FIELD_NEXT_TILE_ID] = nextTileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBackdrop += drawBackdropDelta;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/sort.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TILE_FIELD_NEXT_TILE_ID 0
|
||||||
|
#define TILE_FIELD_FIRST_FILL_ID 1
|
||||||
|
#define TILE_FIELD_BACKDROP_ALPHA_TILE_ID 2
|
||||||
|
#define TILE_FIELD_CONTROL 3
|
||||||
|
|
||||||
|
uniform int uTileCount;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bTiles {
|
||||||
|
// [0]: next tile ID
|
||||||
|
// [1]: first fill ID
|
||||||
|
// [2]: backdrop delta upper 8 bits, alpha tile ID lower 24
|
||||||
|
// [3]: color/ctrl/backdrop word
|
||||||
|
restrict uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer bFirstTileMap {
|
||||||
|
restrict int iFirstTileMap[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) buffer bZBuffer {
|
||||||
|
restrict readonly int iZBuffer[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(local_size_x = 64) in;
|
||||||
|
|
||||||
|
int getFirst(uint globalTileIndex) {
|
||||||
|
return iFirstTileMap[globalTileIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNextTile(int tileIndex) {
|
||||||
|
return int(iTiles[tileIndex * 4 + TILE_FIELD_NEXT_TILE_ID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNextTile(int tileIndex, int newNextTileIndex) {
|
||||||
|
iTiles[tileIndex * 4 + TILE_FIELD_NEXT_TILE_ID] = uint(newNextTileIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
uint globalTileIndex = gl_GlobalInvocationID.x;
|
||||||
|
if (globalTileIndex >= uint(uTileCount))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int zValue = iZBuffer[globalTileIndex];
|
||||||
|
|
||||||
|
int unsortedFirstTileIndex = getFirst(globalTileIndex);
|
||||||
|
int sortedFirstTileIndex = -1;
|
||||||
|
|
||||||
|
while (unsortedFirstTileIndex >= 0) {
|
||||||
|
int currentTileIndex = unsortedFirstTileIndex;
|
||||||
|
unsortedFirstTileIndex = getNextTile(currentTileIndex);
|
||||||
|
|
||||||
|
if (currentTileIndex >= zValue) {
|
||||||
|
int prevTrialTileIndex = -1;
|
||||||
|
int trialTileIndex = sortedFirstTileIndex;
|
||||||
|
while (true) {
|
||||||
|
if (trialTileIndex < 0 || currentTileIndex < trialTileIndex) {
|
||||||
|
if (prevTrialTileIndex < 0) {
|
||||||
|
setNextTile(currentTileIndex, sortedFirstTileIndex);
|
||||||
|
sortedFirstTileIndex = currentTileIndex;
|
||||||
|
} else {
|
||||||
|
setNextTile(currentTileIndex, trialTileIndex);
|
||||||
|
setNextTile(prevTrialTileIndex, currentTileIndex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prevTrialTileIndex = trialTileIndex;
|
||||||
|
trialTileIndex = getNextTile(trialTileIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iFirstTileMap[globalTileIndex] = sortedFirstTileIndex;
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile.cs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
layout(local_size_x = 16, local_size_y = 4) in;
|
||||||
|
|
||||||
|
#include "tile_fragment.inc.glsl"
|
||||||
|
#include "tile_vertex.inc.glsl"
|
||||||
|
|
||||||
|
#define LOAD_ACTION_CLEAR 0
|
||||||
|
#define LOAD_ACTION_LOAD 1
|
||||||
|
|
||||||
|
#define TILE_FIELD_NEXT_TILE_ID 0
|
||||||
|
#define TILE_FIELD_FIRST_FILL_ID 1
|
||||||
|
#define TILE_FIELD_BACKDROP_ALPHA_TILE_ID 2
|
||||||
|
#define TILE_FIELD_CONTROL 3
|
||||||
|
|
||||||
|
uniform int uLoadAction;
|
||||||
|
uniform vec4 uClearColor;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
uniform sampler2D uTextureMetadata;
|
||||||
|
uniform ivec2 uTextureMetadataSize;
|
||||||
|
uniform sampler2D uZBuffer;
|
||||||
|
uniform ivec2 uZBufferSize;
|
||||||
|
uniform sampler2D uColorTexture0;
|
||||||
|
uniform sampler2D uMaskTexture0;
|
||||||
|
uniform sampler2D uDestTexture;
|
||||||
|
uniform sampler2D uGammaLUT;
|
||||||
|
uniform vec2 uColorTextureSize0;
|
||||||
|
uniform vec2 uMaskTextureSize0;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
uniform ivec2 uFramebufferTileSize;
|
||||||
|
layout(rgba8) uniform image2D uDestImage;
|
||||||
|
|
||||||
|
layout(std430, binding = 0) buffer bTiles {
|
||||||
|
// [0]: path ID
|
||||||
|
// [1]: next tile ID
|
||||||
|
// [2]: first fill ID
|
||||||
|
// [3]: backdrop delta upper 8 bits, alpha tile ID lower 24 bits
|
||||||
|
// [4]: color/ctrl/backdrop word
|
||||||
|
restrict readonly uint iTiles[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 1) buffer bFirstTileMap {
|
||||||
|
restrict readonly int iFirstTileMap[];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint calculateTileIndex(uint bufferOffset, uvec4 tileRect, uvec2 tileCoord) {
|
||||||
|
return bufferOffset + tileCoord.y * (tileRect.z - tileRect.x) + tileCoord.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec2 toImageCoords(ivec2 coords) {
|
||||||
|
return ivec2(coords.x, uFramebufferSize.y - coords.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec2 tileCoord = ivec2(gl_WorkGroupID.xy);
|
||||||
|
ivec2 firstTileSubCoord = ivec2(gl_LocalInvocationID.xy) * ivec2(1, 4);
|
||||||
|
ivec2 firstFragCoord = tileCoord * ivec2(uTileSize) + firstTileSubCoord;
|
||||||
|
|
||||||
|
// Quick exit if this is guaranteed to be empty.
|
||||||
|
int tileIndex = iFirstTileMap[tileCoord.x + uFramebufferTileSize.x * tileCoord.y];
|
||||||
|
if (tileIndex < 0 && uLoadAction != LOAD_ACTION_CLEAR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mat4 destColors;
|
||||||
|
for (int subY = 0; subY < 4; subY++) {
|
||||||
|
if (uLoadAction == LOAD_ACTION_CLEAR) {
|
||||||
|
destColors[subY] = uClearColor;
|
||||||
|
} else {
|
||||||
|
ivec2 imageCoords = toImageCoords(firstFragCoord + ivec2(0, subY));
|
||||||
|
destColors[subY] = imageLoad(uDestImage, imageCoords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (tileIndex >= 0) {
|
||||||
|
for (int subY = 0; subY < 4; subY++) {
|
||||||
|
ivec2 tileSubCoord = firstTileSubCoord + ivec2(0, subY);
|
||||||
|
vec2 fragCoord = vec2(firstFragCoord + ivec2(0, subY)) + vec2(0.5);
|
||||||
|
|
||||||
|
int alphaTileIndex =
|
||||||
|
int(iTiles[tileIndex * 4 + TILE_FIELD_BACKDROP_ALPHA_TILE_ID] << 8) >> 8;
|
||||||
|
uint tileControlWord = iTiles[tileIndex * 4 + TILE_FIELD_CONTROL];
|
||||||
|
uint colorEntry = tileControlWord & 0xffff;
|
||||||
|
int tileCtrl = int((tileControlWord >> 16) & 0xff);
|
||||||
|
|
||||||
|
int backdrop;
|
||||||
|
uvec2 maskTileCoord;
|
||||||
|
if (alphaTileIndex >= 0) {
|
||||||
|
backdrop = 0;
|
||||||
|
maskTileCoord = uvec2(alphaTileIndex & 0xff, alphaTileIndex >> 8) *
|
||||||
|
uvec2(uTileSize);
|
||||||
|
} else {
|
||||||
|
// We have no alpha mask. Clear the mask bits so we don't try to look one up.
|
||||||
|
backdrop = int(tileControlWord) >> 24;
|
||||||
|
maskTileCoord = uvec2(0u);
|
||||||
|
tileCtrl &= ~(TILE_CTRL_MASK_MASK << TILE_CTRL_MASK_0_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 maskTexCoord0 = vec3(vec2(ivec2(maskTileCoord) + tileSubCoord), backdrop);
|
||||||
|
|
||||||
|
vec2 colorTexCoord0;
|
||||||
|
vec4 baseColor, filterParams0, filterParams1, filterParams2;
|
||||||
|
int ctrl;
|
||||||
|
computeTileVaryings(fragCoord,
|
||||||
|
int(colorEntry),
|
||||||
|
uTextureMetadata,
|
||||||
|
uTextureMetadataSize,
|
||||||
|
colorTexCoord0,
|
||||||
|
baseColor,
|
||||||
|
filterParams0,
|
||||||
|
filterParams1,
|
||||||
|
filterParams2,
|
||||||
|
ctrl);
|
||||||
|
|
||||||
|
vec4 srcColor = calculateColor(fragCoord,
|
||||||
|
uColorTexture0,
|
||||||
|
uMaskTexture0,
|
||||||
|
uDestTexture,
|
||||||
|
uGammaLUT,
|
||||||
|
uColorTextureSize0,
|
||||||
|
uMaskTextureSize0,
|
||||||
|
filterParams0,
|
||||||
|
filterParams1,
|
||||||
|
filterParams2,
|
||||||
|
uFramebufferSize,
|
||||||
|
ctrl,
|
||||||
|
maskTexCoord0,
|
||||||
|
colorTexCoord0,
|
||||||
|
baseColor,
|
||||||
|
tileCtrl);
|
||||||
|
|
||||||
|
destColors[subY] = destColors[subY] * (1.0 - srcColor.a) + srcColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
tileIndex = int(iTiles[tileIndex * 4 + TILE_FIELD_NEXT_TILE_ID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int subY = 0; subY < 4; subY++)
|
||||||
|
imageStore(uDestImage, toImageCoords(firstFragCoord + ivec2(0, subY)), destColors[subY]);
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ precision highp float;
|
||||||
precision highp sampler2D;
|
precision highp sampler2D;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "fill.inc.glsl"
|
#include "fill_area.inc.glsl"
|
||||||
|
|
||||||
uniform sampler2D uAreaLUT;
|
uniform sampler2D uAreaLUT;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
#ifdef GL_ES
|
#ifdef GL_ES
|
||||||
|
@ -20,36 +22,39 @@ uniform vec2 uFramebufferSize;
|
||||||
uniform vec2 uTileSize;
|
uniform vec2 uTileSize;
|
||||||
|
|
||||||
in uvec2 aTessCoord;
|
in uvec2 aTessCoord;
|
||||||
in uint aFromPx;
|
in uvec4 aLineSegment;
|
||||||
in uint aToPx;
|
in int aTileIndex;
|
||||||
in vec2 aFromSubpx;
|
|
||||||
in vec2 aToSubpx;
|
|
||||||
in uint aTileIndex;
|
|
||||||
|
|
||||||
out vec2 vFrom;
|
out vec2 vFrom;
|
||||||
out vec2 vTo;
|
out vec2 vTo;
|
||||||
|
|
||||||
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth, vec2 tileSize) {
|
||||||
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
|
uint tilesPerRow = uint(stencilTextureWidth / tileSize.x);
|
||||||
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
|
||||||
return vec2(tileOffset) * uTileSize * vec2(1.0, 0.25);
|
return vec2(tileOffset) * tileSize * vec2(1.0, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
vec4 computeVertexPosition(uint tileIndex,
|
||||||
vec2 tileOrigin = computeTileOffset(aTileIndex, uFramebufferSize.x);
|
uvec2 tessCoord,
|
||||||
|
uvec4 packedLineSegment,
|
||||||
|
vec2 tileSize,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
out vec2 outFrom,
|
||||||
|
out vec2 outTo) {
|
||||||
|
vec2 tileOrigin = computeTileOffset(uint(tileIndex), framebufferSize.x, tileSize);
|
||||||
|
|
||||||
vec2 from = vec2(aFromPx & 15u, aFromPx >> 4u) + aFromSubpx;
|
vec4 lineSegment = vec4(packedLineSegment) / 256.0;
|
||||||
vec2 to = vec2(aToPx & 15u, aToPx >> 4u) + aToSubpx;
|
vec2 from = lineSegment.xy, to = lineSegment.zw;
|
||||||
|
|
||||||
vec2 position;
|
vec2 position;
|
||||||
if (aTessCoord.x == 0u)
|
if (tessCoord.x == 0u)
|
||||||
position.x = floor(min(from.x, to.x));
|
position.x = floor(min(from.x, to.x));
|
||||||
else
|
else
|
||||||
position.x = ceil(max(from.x, to.x));
|
position.x = ceil(max(from.x, to.x));
|
||||||
if (aTessCoord.y == 0u)
|
if (tessCoord.y == 0u)
|
||||||
position.y = floor(min(from.y, to.y));
|
position.y = floor(min(from.y, to.y));
|
||||||
else
|
else
|
||||||
position.y = uTileSize.y;
|
position.y = tileSize.y;
|
||||||
position.y = floor(position.y * 0.25);
|
position.y = floor(position.y * 0.25);
|
||||||
|
|
||||||
// Since each fragment corresponds to 4 pixels on a scanline, the varying interpolation will
|
// Since each fragment corresponds to 4 pixels on a scanline, the varying interpolation will
|
||||||
|
@ -57,12 +62,22 @@ void main() {
|
||||||
// do our coverage calculation on the center of the first pixel in the strip instead, at pixel
|
// do our coverage calculation on the center of the first pixel in the strip instead, at pixel
|
||||||
// offset 0.5. This adjustment of 1.5 accomplishes that.
|
// offset 0.5. This adjustment of 1.5 accomplishes that.
|
||||||
vec2 offset = vec2(0.0, 1.5) - position * vec2(1.0, 4.0);
|
vec2 offset = vec2(0.0, 1.5) - position * vec2(1.0, 4.0);
|
||||||
vFrom = from + offset;
|
outFrom = from + offset;
|
||||||
vTo = to + offset;
|
outTo = to + offset;
|
||||||
|
|
||||||
vec2 globalPosition = (tileOrigin + position) / uFramebufferSize * 2.0 - 1.0;
|
vec2 globalPosition = (tileOrigin + position) / framebufferSize * 2.0 - 1.0;
|
||||||
#ifdef PF_ORIGIN_UPPER_LEFT
|
#ifdef PF_ORIGIN_UPPER_LEFT
|
||||||
globalPosition.y = -globalPosition.y;
|
globalPosition.y = -globalPosition.y;
|
||||||
#endif
|
#endif
|
||||||
gl_Position = vec4(globalPosition, 0.0, 1.0);
|
return vec4(globalPosition, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = computeVertexPosition(uint(aTileIndex),
|
||||||
|
aTessCoord,
|
||||||
|
aLineSegment,
|
||||||
|
uTileSize,
|
||||||
|
uFramebufferSize,
|
||||||
|
vFrom,
|
||||||
|
vTo);
|
||||||
}
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile.fs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tile_fragment.inc.glsl"
|
||||||
|
|
||||||
|
uniform sampler2D uColorTexture0;
|
||||||
|
uniform sampler2D uMaskTexture0;
|
||||||
|
uniform sampler2D uDestTexture;
|
||||||
|
uniform sampler2D uGammaLUT;
|
||||||
|
uniform vec2 uColorTextureSize0;
|
||||||
|
uniform vec2 uMaskTextureSize0;
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in vec3 vMaskTexCoord0;
|
||||||
|
in vec2 vColorTexCoord0;
|
||||||
|
in vec4 vBaseColor;
|
||||||
|
in float vTileCtrl;
|
||||||
|
in vec4 vFilterParams0;
|
||||||
|
in vec4 vFilterParams1;
|
||||||
|
in vec4 vFilterParams2;
|
||||||
|
in float vCtrl;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
// Entry point
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): Generate this dynamically.
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
oFragColor = calculateColor(gl_FragCoord.xy,
|
||||||
|
uColorTexture0,
|
||||||
|
uMaskTexture0,
|
||||||
|
uDestTexture,
|
||||||
|
uGammaLUT,
|
||||||
|
uColorTextureSize0,
|
||||||
|
uMaskTextureSize0,
|
||||||
|
vFilterParams0,
|
||||||
|
vFilterParams1,
|
||||||
|
vFilterParams2,
|
||||||
|
uFramebufferSize,
|
||||||
|
int(vCtrl),
|
||||||
|
vMaskTexCoord0,
|
||||||
|
vColorTexCoord0,
|
||||||
|
vBaseColor,
|
||||||
|
int(vTileCtrl));
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile.vs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : enable
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tile_vertex.inc.glsl"
|
||||||
|
|
||||||
|
uniform mat4 uTransform;
|
||||||
|
uniform vec2 uTileSize;
|
||||||
|
uniform sampler2D uTextureMetadata;
|
||||||
|
uniform ivec2 uTextureMetadataSize;
|
||||||
|
uniform sampler2D uZBuffer;
|
||||||
|
uniform ivec2 uZBufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in ivec2 aTileOrigin;
|
||||||
|
in uvec4 aMaskTexCoord0;
|
||||||
|
in ivec2 aCtrlBackdrop;
|
||||||
|
in int aPathIndex;
|
||||||
|
in int aColor;
|
||||||
|
|
||||||
|
out vec3 vMaskTexCoord0;
|
||||||
|
out vec2 vColorTexCoord0;
|
||||||
|
out vec4 vBaseColor;
|
||||||
|
out float vTileCtrl;
|
||||||
|
out vec4 vFilterParams0;
|
||||||
|
out vec4 vFilterParams1;
|
||||||
|
out vec4 vFilterParams2;
|
||||||
|
out float vCtrl;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
||||||
|
vec2 position = (tileOrigin + tileOffset) * uTileSize;
|
||||||
|
|
||||||
|
ivec4 zValue = ivec4(texture(uZBuffer, (tileOrigin + vec2(0.5)) / vec2(uZBufferSize)) * 255.0);
|
||||||
|
if (aPathIndex < (zValue.x | (zValue.y << 8) | (zValue.z << 16) | (zValue.w << 24))) {
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uvec2 maskTileCoord = uvec2(aMaskTexCoord0.x, aMaskTexCoord0.y + 256u * aMaskTexCoord0.z);
|
||||||
|
vec2 maskTexCoord0 = (vec2(maskTileCoord) + tileOffset) * uTileSize;
|
||||||
|
if (aCtrlBackdrop.y == 0 && aMaskTexCoord0.w != 0u) {
|
||||||
|
gl_Position = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ctrl;
|
||||||
|
computeTileVaryings(position,
|
||||||
|
aColor,
|
||||||
|
uTextureMetadata,
|
||||||
|
uTextureMetadataSize,
|
||||||
|
vColorTexCoord0,
|
||||||
|
vBaseColor,
|
||||||
|
vFilterParams0,
|
||||||
|
vFilterParams1,
|
||||||
|
vFilterParams2,
|
||||||
|
ctrl);
|
||||||
|
|
||||||
|
vTileCtrl = float(aCtrlBackdrop.x);
|
||||||
|
vCtrl = float(ctrl);
|
||||||
|
vMaskTexCoord0 = vec3(maskTexCoord0, float(aCtrlBackdrop.y));
|
||||||
|
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile_clip_combine.fs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
|
in vec2 vTexCoord0;
|
||||||
|
in float vBackdrop0;
|
||||||
|
in vec2 vTexCoord1;
|
||||||
|
in float vBackdrop1;
|
||||||
|
|
||||||
|
out vec4 oFragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
oFragColor = min(abs(texture(uSrc, vTexCoord0) + vBackdrop0),
|
||||||
|
abs(texture(uSrc, vTexCoord1) + vBackdrop1));
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
// pathfinder/shaders/tile_clip_combine.vs.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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;
|
||||||
|
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision highp sampler2D;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
|
in ivec2 aTileOffset;
|
||||||
|
in int aDestTileIndex;
|
||||||
|
in int aDestBackdrop;
|
||||||
|
in int aSrcTileIndex;
|
||||||
|
in int aSrcBackdrop;
|
||||||
|
|
||||||
|
out vec2 vTexCoord0;
|
||||||
|
out float vBackdrop0;
|
||||||
|
out vec2 vTexCoord1;
|
||||||
|
out float vBackdrop1;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 destPosition = vec2(ivec2(aDestTileIndex % 256, aDestTileIndex / 256) + aTileOffset);
|
||||||
|
vec2 srcPosition = vec2(ivec2(aSrcTileIndex % 256, aSrcTileIndex / 256) + aTileOffset);
|
||||||
|
destPosition *= vec2(16.0, 4.0) / uFramebufferSize;
|
||||||
|
srcPosition *= vec2(16.0, 4.0) / uFramebufferSize;
|
||||||
|
|
||||||
|
vTexCoord0 = destPosition;
|
||||||
|
vTexCoord1 = srcPosition;
|
||||||
|
|
||||||
|
vBackdrop0 = float(aDestBackdrop);
|
||||||
|
vBackdrop1 = float(aSrcBackdrop);
|
||||||
|
|
||||||
|
if (aDestTileIndex < 0)
|
||||||
|
destPosition = vec2(0.0);
|
||||||
|
|
||||||
|
#ifdef PF_ORIGIN_UPPER_LEFT
|
||||||
|
destPosition.y = 1.0 - destPosition.y;
|
||||||
|
#endif
|
||||||
|
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), destPosition), 0.0, 1.0);
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// pathfinder/shaders/tile_clip.fs.glsl
|
// pathfinder/shaders/tile_clip_copy.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2020 The Pathfinder Project Developers.
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -19,10 +19,9 @@ precision highp sampler2D;
|
||||||
uniform sampler2D uSrc;
|
uniform sampler2D uSrc;
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
in float vBackdrop;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
out vec4 oFragColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
oFragColor = clamp(abs(texture(uSrc, vTexCoord) + vBackdrop), 0.0, 1.0);
|
oFragColor = texture(uSrc, vTexCoord);
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// pathfinder/shaders/tile_clip.vs.glsl
|
// pathfinder/shaders/tile_clip_copy.vs.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2020 The Pathfinder Project Developers.
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -16,18 +16,24 @@ precision highp float;
|
||||||
precision highp sampler2D;
|
precision highp sampler2D;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uniform vec2 uFramebufferSize;
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
in ivec2 aTileOffset;
|
||||||
in ivec2 aDestTileOrigin;
|
in int aTileIndex;
|
||||||
in ivec2 aSrcTileOrigin;
|
|
||||||
in int aSrcBackdrop;
|
|
||||||
|
|
||||||
out vec2 vTexCoord;
|
out vec2 vTexCoord;
|
||||||
out float vBackdrop;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 destPosition = vec2(aDestTileOrigin + aTileOffset) / vec2(256.0);
|
vec2 position = vec2(ivec2(aTileIndex % 256, aTileIndex / 256) + aTileOffset);
|
||||||
vec2 srcPosition = vec2(aSrcTileOrigin + aTileOffset) / vec2(256.0);
|
position *= vec2(16.0, 4.0) / uFramebufferSize;
|
||||||
vTexCoord = srcPosition;
|
|
||||||
vBackdrop = float(aSrcBackdrop);
|
vTexCoord = position;
|
||||||
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), destPosition), 0.0, 1.0);
|
|
||||||
|
if (aTileIndex < 0)
|
||||||
|
position = vec2(0.0);
|
||||||
|
|
||||||
|
#ifdef PF_ORIGIN_UPPER_LEFT
|
||||||
|
position.y = 1.0 - position.y;
|
||||||
|
#endif
|
||||||
|
gl_Position = vec4(mix(vec2(-1.0), vec2(1.0), position), 0.0, 1.0);
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// pathfinder/shaders/debug_solid.fs.glsl
|
// pathfinder/shaders/debug/solid.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -1,6 +1,6 @@
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// pathfinder/shaders/debug_solid.vs.glsl
|
// pathfinder/shaders/debug/solid.vs.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -1,6 +1,6 @@
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// pathfinder/shaders/debug_texture.fs.glsl
|
// pathfinder/shaders/debug/texture.fs.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -1,6 +1,6 @@
|
||||||
#version 330
|
#version 330
|
||||||
|
|
||||||
// pathfinder/shaders/debug_texture.vs.glsl
|
// pathfinder/shaders/debug/texture.vs.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -1,69 +0,0 @@
|
||||||
#version 430
|
|
||||||
|
|
||||||
// pathfinder/shaders/fill.cs.glsl
|
|
||||||
//
|
|
||||||
// Copyright © 2020 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.
|
|
||||||
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision highp sampler2D;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "fill.inc.glsl"
|
|
||||||
|
|
||||||
layout(local_size_x = 16, local_size_y = 4) in;
|
|
||||||
|
|
||||||
uniform writeonly image2D uDest;
|
|
||||||
uniform sampler2D uAreaLUT;
|
|
||||||
uniform int uFirstTileIndex;
|
|
||||||
|
|
||||||
layout(std430, binding = 0) buffer bFills {
|
|
||||||
restrict readonly uvec2 iFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 1) buffer bNextFills {
|
|
||||||
restrict readonly int iNextFills[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 2) buffer bFillTileMap {
|
|
||||||
restrict readonly int iFillTileMap[];
|
|
||||||
};
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
ivec2 tileSubCoord = ivec2(gl_LocalInvocationID.xy) * ivec2(1, 4);
|
|
||||||
uint tileIndexOffset = gl_WorkGroupID.z;
|
|
||||||
|
|
||||||
uint tileIndex = tileIndexOffset + uint(uFirstTileIndex);
|
|
||||||
|
|
||||||
int fillIndex = iFillTileMap[tileIndex];
|
|
||||||
if (fillIndex < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
vec4 coverages = vec4(0.0);
|
|
||||||
do {
|
|
||||||
uvec2 fill = iFills[fillIndex];
|
|
||||||
vec2 from = vec2(fill.y & 0xf, (fill.y >> 4u) & 0xf) +
|
|
||||||
vec2(fill.x & 0xff, (fill.x >> 8u) & 0xff) / 256.0;
|
|
||||||
vec2 to = vec2((fill.y >> 8u) & 0xf, (fill.y >> 12u) & 0xf) +
|
|
||||||
vec2((fill.x >> 16u) & 0xff, (fill.x >> 24u) & 0xff) / 256.0;
|
|
||||||
|
|
||||||
coverages += computeCoverage(from - (vec2(tileSubCoord) + vec2(0.5)),
|
|
||||||
to - (vec2(tileSubCoord) + vec2(0.5)),
|
|
||||||
uAreaLUT);
|
|
||||||
|
|
||||||
fillIndex = iNextFills[fillIndex];
|
|
||||||
} while (fillIndex >= 0);
|
|
||||||
|
|
||||||
ivec2 tileOrigin = ivec2(tileIndex & 0xff, (tileIndex >> 8u) & 0xff) * ivec2(16, 4);
|
|
||||||
ivec2 destCoord = tileOrigin + ivec2(gl_LocalInvocationID.xy);
|
|
||||||
imageStore(uDest, destCoord, coverages);
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/shaders/fill.inc.glsl
|
// pathfinder/shaders/fill_area.inc.glsl
|
||||||
//
|
//
|
||||||
// Copyright © 2020 The Pathfinder Project Developers.
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
//
|
//
|
|
@ -1,56 +0,0 @@
|
||||||
#version 330
|
|
||||||
|
|
||||||
// pathfinder/shaders/tile.vs.glsl
|
|
||||||
//
|
|
||||||
// Copyright © 2020 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;
|
|
||||||
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision highp sampler2D;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uniform mat4 uTransform;
|
|
||||||
uniform vec2 uTileSize;
|
|
||||||
uniform sampler2D uTextureMetadata;
|
|
||||||
uniform ivec2 uTextureMetadataSize;
|
|
||||||
|
|
||||||
in ivec2 aTileOffset;
|
|
||||||
in ivec2 aTileOrigin;
|
|
||||||
in uvec2 aMaskTexCoord0;
|
|
||||||
in ivec2 aMaskBackdrop;
|
|
||||||
in int aColor;
|
|
||||||
in int aTileCtrl;
|
|
||||||
|
|
||||||
out vec3 vMaskTexCoord0;
|
|
||||||
out vec2 vColorTexCoord0;
|
|
||||||
out vec4 vBaseColor;
|
|
||||||
out float vTileCtrl;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
|
|
||||||
vec2 position = (tileOrigin + tileOffset) * uTileSize;
|
|
||||||
|
|
||||||
vec2 maskTexCoord0 = (vec2(aMaskTexCoord0) + tileOffset) * uTileSize;
|
|
||||||
|
|
||||||
vec2 textureMetadataScale = vec2(1.0) / vec2(uTextureMetadataSize);
|
|
||||||
vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128);
|
|
||||||
vec2 colorTexMatrix0Coord = (metadataEntryCoord + vec2(0.5, 0.5)) * textureMetadataScale;
|
|
||||||
vec2 colorTexOffsetsCoord = (metadataEntryCoord + vec2(1.5, 0.5)) * textureMetadataScale;
|
|
||||||
vec2 baseColorCoord = (metadataEntryCoord + vec2(2.5, 0.5)) * textureMetadataScale;
|
|
||||||
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
|
|
||||||
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
|
|
||||||
vec4 baseColor = texture(uTextureMetadata, baseColorCoord);
|
|
||||||
|
|
||||||
vColorTexCoord0 = mat2(colorTexMatrix0) * position + colorTexOffsets.xy;
|
|
||||||
vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop.x));
|
|
||||||
vBaseColor = baseColor;
|
|
||||||
vTileCtrl = float(aTileCtrl);
|
|
||||||
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
|
||||||
}
|
|
|
@ -1,6 +1,4 @@
|
||||||
#version 330
|
// pathfinder/shaders/tile_fragment.inc.glsl
|
||||||
|
|
||||||
// pathfinder/shaders/tile.fs.glsl
|
|
||||||
//
|
//
|
||||||
// Copyright © 2020 The Pathfinder Project Developers.
|
// Copyright © 2020 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -31,14 +29,6 @@
|
||||||
// + +
|
// + +
|
||||||
// Color UV 0 Color UV 1
|
// Color UV 0 Color UV 1
|
||||||
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
|
|
||||||
#ifdef GL_ES
|
|
||||||
precision highp sampler2D;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EPSILON 0.00001
|
#define EPSILON 0.00001
|
||||||
|
|
||||||
#define FRAC_6_PI 1.9098593171027443
|
#define FRAC_6_PI 1.9098593171027443
|
||||||
|
@ -81,25 +71,6 @@ precision highp sampler2D;
|
||||||
#define COMBINER_CTRL_COLOR_COMBINE_SHIFT 6
|
#define COMBINER_CTRL_COLOR_COMBINE_SHIFT 6
|
||||||
#define COMBINER_CTRL_COMPOSITE_SHIFT 8
|
#define COMBINER_CTRL_COMPOSITE_SHIFT 8
|
||||||
|
|
||||||
uniform sampler2D uColorTexture0;
|
|
||||||
uniform sampler2D uMaskTexture0;
|
|
||||||
uniform sampler2D uDestTexture;
|
|
||||||
uniform sampler2D uGammaLUT;
|
|
||||||
uniform vec2 uColorTextureSize0;
|
|
||||||
uniform vec2 uMaskTextureSize0;
|
|
||||||
uniform vec4 uFilterParams0;
|
|
||||||
uniform vec4 uFilterParams1;
|
|
||||||
uniform vec4 uFilterParams2;
|
|
||||||
uniform vec2 uFramebufferSize;
|
|
||||||
uniform int uCtrl;
|
|
||||||
|
|
||||||
in vec3 vMaskTexCoord0;
|
|
||||||
in vec2 vColorTexCoord0;
|
|
||||||
in vec4 vBaseColor;
|
|
||||||
in float vTileCtrl;
|
|
||||||
|
|
||||||
out vec4 oFragColor;
|
|
||||||
|
|
||||||
// Color sampling
|
// Color sampling
|
||||||
|
|
||||||
vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord) {
|
vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord) {
|
||||||
|
@ -565,27 +536,42 @@ float sampleMask(float maskAlpha,
|
||||||
|
|
||||||
// Main function
|
// Main function
|
||||||
|
|
||||||
void calculateColor(int tileCtrl, int ctrl) {
|
vec4 calculateColor(vec2 fragCoord,
|
||||||
|
sampler2D colorTexture0,
|
||||||
|
sampler2D maskTexture0,
|
||||||
|
sampler2D destTexture,
|
||||||
|
sampler2D gammaLUT,
|
||||||
|
vec2 colorTextureSize0,
|
||||||
|
vec2 maskTextureSize0,
|
||||||
|
vec4 filterParams0,
|
||||||
|
vec4 filterParams1,
|
||||||
|
vec4 filterParams2,
|
||||||
|
vec2 framebufferSize,
|
||||||
|
int ctrl,
|
||||||
|
vec3 maskTexCoord0,
|
||||||
|
vec2 colorTexCoord0,
|
||||||
|
vec4 baseColor,
|
||||||
|
int tileCtrl) {
|
||||||
// Sample mask.
|
// Sample mask.
|
||||||
int maskCtrl0 = (tileCtrl >> TILE_CTRL_MASK_0_SHIFT) & TILE_CTRL_MASK_MASK;
|
int maskCtrl0 = (tileCtrl >> TILE_CTRL_MASK_0_SHIFT) & TILE_CTRL_MASK_MASK;
|
||||||
float maskAlpha = 1.0;
|
float maskAlpha = 1.0;
|
||||||
maskAlpha = sampleMask(maskAlpha, uMaskTexture0, uMaskTextureSize0, vMaskTexCoord0, maskCtrl0);
|
maskAlpha = sampleMask(maskAlpha, maskTexture0, maskTextureSize0, maskTexCoord0, maskCtrl0);
|
||||||
|
|
||||||
// Sample color.
|
// Sample color.
|
||||||
vec4 color = vBaseColor;
|
vec4 color = baseColor;
|
||||||
int color0Combine = (ctrl >> COMBINER_CTRL_COLOR_COMBINE_SHIFT) &
|
int color0Combine = (ctrl >> COMBINER_CTRL_COLOR_COMBINE_SHIFT) &
|
||||||
COMBINER_CTRL_COLOR_COMBINE_MASK;
|
COMBINER_CTRL_COLOR_COMBINE_MASK;
|
||||||
if (color0Combine != 0) {
|
if (color0Combine != 0) {
|
||||||
int color0Filter = (ctrl >> COMBINER_CTRL_COLOR_FILTER_SHIFT) & COMBINER_CTRL_FILTER_MASK;
|
int color0Filter = (ctrl >> COMBINER_CTRL_COLOR_FILTER_SHIFT) & COMBINER_CTRL_FILTER_MASK;
|
||||||
vec4 color0 = filterColor(vColorTexCoord0,
|
vec4 color0 = filterColor(colorTexCoord0,
|
||||||
uColorTexture0,
|
colorTexture0,
|
||||||
uGammaLUT,
|
gammaLUT,
|
||||||
uColorTextureSize0,
|
colorTextureSize0,
|
||||||
gl_FragCoord.xy,
|
fragCoord,
|
||||||
uFramebufferSize,
|
framebufferSize,
|
||||||
uFilterParams0,
|
filterParams0,
|
||||||
uFilterParams1,
|
filterParams1,
|
||||||
uFilterParams2,
|
filterParams2,
|
||||||
color0Filter);
|
color0Filter);
|
||||||
color = combineColor0(color, color0, color0Combine);
|
color = combineColor0(color, color0, color0Combine);
|
||||||
}
|
}
|
||||||
|
@ -595,17 +581,9 @@ void calculateColor(int tileCtrl, int ctrl) {
|
||||||
|
|
||||||
// Apply composite.
|
// Apply composite.
|
||||||
int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK;
|
int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK;
|
||||||
color = composite(color, uDestTexture, uFramebufferSize, gl_FragCoord.xy, compositeOp);
|
color = composite(color, destTexture, framebufferSize, fragCoord, compositeOp);
|
||||||
|
|
||||||
// Premultiply alpha.
|
// Premultiply alpha.
|
||||||
color.rgb *= color.a;
|
color.rgb *= color.a;
|
||||||
oFragColor = color;
|
return color;
|
||||||
}
|
|
||||||
|
|
||||||
// Entry point
|
|
||||||
//
|
|
||||||
// TODO(pcwalton): Generate this dynamically.
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
calculateColor(int(vTileCtrl), uCtrl);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
// pathfinder/shaders/tile_vertex.inc.glsl
|
||||||
|
//
|
||||||
|
// Copyright © 2020 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.
|
||||||
|
|
||||||
|
vec4 fetchUnscaled(sampler2D srcTexture, vec2 scale, vec2 originCoord, int entry) {
|
||||||
|
return texture(srcTexture, (originCoord + vec2(0.5) + vec2(entry, 0)) * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeTileVaryings(vec2 position,
|
||||||
|
int colorEntry,
|
||||||
|
sampler2D textureMetadata,
|
||||||
|
ivec2 textureMetadataSize,
|
||||||
|
out vec2 outColorTexCoord0,
|
||||||
|
out vec4 outBaseColor,
|
||||||
|
out vec4 outFilterParams0,
|
||||||
|
out vec4 outFilterParams1,
|
||||||
|
out vec4 outFilterParams2,
|
||||||
|
out int outCtrl) {
|
||||||
|
vec2 metadataScale = vec2(1.0) / vec2(textureMetadataSize);
|
||||||
|
vec2 metadataEntryCoord = vec2(colorEntry % 128 * 8, colorEntry / 128);
|
||||||
|
vec4 colorTexMatrix0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 0);
|
||||||
|
vec4 colorTexOffsets = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 1);
|
||||||
|
vec4 baseColor = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 2);
|
||||||
|
vec4 filterParams0 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 3);
|
||||||
|
vec4 filterParams1 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 4);
|
||||||
|
vec4 filterParams2 = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 5);
|
||||||
|
vec4 extra = fetchUnscaled(textureMetadata, metadataScale, metadataEntryCoord, 6);
|
||||||
|
outColorTexCoord0 = mat2(colorTexMatrix0) * position + colorTexOffsets.xy;
|
||||||
|
outBaseColor = baseColor;
|
||||||
|
outFilterParams0 = filterParams0;
|
||||||
|
outFilterParams1 = filterParams1;
|
||||||
|
outFilterParams2 = filterParams2;
|
||||||
|
outCtrl = int(extra.x);
|
||||||
|
}
|
|
@ -280,7 +280,7 @@ impl BuiltSVG {
|
||||||
path.set_clip_path(state.clip_path);
|
path.set_clip_path(state.clip_path);
|
||||||
path.set_fill_rule(fill_rule);
|
path.set_fill_rule(fill_rule);
|
||||||
path.set_name(name);
|
path.set_name(name);
|
||||||
self.scene.push_path(path);
|
self.scene.push_draw_path(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
|
||||||
|
|
||||||
let mut path = DrawPath::new(path, paint_id);
|
let mut path = DrawPath::new(path, paint_id);
|
||||||
path.set_fill_rule(FillRule::EvenOdd);
|
path.set_fill_rule(FillRule::EvenOdd);
|
||||||
scene.push_path(path);
|
scene.push_draw_path(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ impl<F> FontContext<F> where F: Loader {
|
||||||
path.set_clip_path(render_options.clip_path);
|
path.set_clip_path(render_options.clip_path);
|
||||||
path.set_blend_mode(render_options.blend_mode);
|
path.set_blend_mode(render_options.blend_mode);
|
||||||
|
|
||||||
scene.push_path(path);
|
scene.push_draw_path(path);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
228
ui/src/lib.rs
228
ui/src/lib.rs
|
@ -20,9 +20,10 @@ use hashbrown::HashMap;
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2i};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2i};
|
||||||
use pathfinder_gpu::{BlendFactor, BlendState, BufferData, BufferTarget, BufferUploadMode, Device};
|
use pathfinder_gpu::allocator::{BufferTag, GPUMemoryAllocator};
|
||||||
use pathfinder_gpu::{Primitive, RenderOptions, RenderState, RenderTarget, TextureFormat};
|
use pathfinder_gpu::{BlendFactor, BlendState, BufferTarget, Device, Primitive, RenderOptions};
|
||||||
use pathfinder_gpu::{UniformData, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
use pathfinder_gpu::{RenderState, RenderTarget, TextureFormat, UniformData, VertexAttrClass};
|
||||||
|
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::F32x4;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
@ -71,9 +72,7 @@ pub struct UIPresenter<D> where D: Device {
|
||||||
framebuffer_size: Vector2I,
|
framebuffer_size: Vector2I,
|
||||||
|
|
||||||
texture_program: DebugTextureProgram<D>,
|
texture_program: DebugTextureProgram<D>,
|
||||||
texture_vertex_array: DebugTextureVertexArray<D>,
|
|
||||||
solid_program: DebugSolidProgram<D>,
|
solid_program: DebugSolidProgram<D>,
|
||||||
solid_vertex_array: DebugSolidVertexArray<D>,
|
|
||||||
font: DebugFont,
|
font: DebugFont,
|
||||||
|
|
||||||
font_texture: D::Texture,
|
font_texture: D::Texture,
|
||||||
|
@ -85,11 +84,9 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
pub fn new(device: &D, resources: &dyn ResourceLoader, framebuffer_size: Vector2I)
|
pub fn new(device: &D, resources: &dyn ResourceLoader, framebuffer_size: Vector2I)
|
||||||
-> UIPresenter<D> {
|
-> UIPresenter<D> {
|
||||||
let texture_program = DebugTextureProgram::new(device, resources);
|
let texture_program = DebugTextureProgram::new(device, resources);
|
||||||
let texture_vertex_array = DebugTextureVertexArray::new(device, &texture_program);
|
|
||||||
let font = DebugFont::load(resources);
|
let font = DebugFont::load(resources);
|
||||||
|
|
||||||
let solid_program = DebugSolidProgram::new(device, resources);
|
let solid_program = DebugSolidProgram::new(device, resources);
|
||||||
let solid_vertex_array = DebugSolidVertexArray::new(device, &solid_program);
|
|
||||||
|
|
||||||
let font_texture = device.create_texture_from_png(resources,
|
let font_texture = device.create_texture_from_png(resources,
|
||||||
FONT_PNG_NAME,
|
FONT_PNG_NAME,
|
||||||
|
@ -108,10 +105,8 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
framebuffer_size,
|
framebuffer_size,
|
||||||
|
|
||||||
texture_program,
|
texture_program,
|
||||||
texture_vertex_array,
|
|
||||||
font,
|
font,
|
||||||
solid_program,
|
solid_program,
|
||||||
solid_vertex_array,
|
|
||||||
|
|
||||||
font_texture,
|
font_texture,
|
||||||
corner_fill_texture,
|
corner_fill_texture,
|
||||||
|
@ -128,16 +123,25 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn draw_solid_rect(&self, device: &D, rect: RectI, color: ColorU) {
|
pub fn draw_solid_rect(&self,
|
||||||
self.draw_rect(device, rect, color, true);
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
rect: RectI,
|
||||||
|
color: ColorU) {
|
||||||
|
self.draw_rect(device, allocator, rect, color, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_rect_outline(&self, device: &D, rect: RectI, color: ColorU) {
|
pub fn draw_rect_outline(&self,
|
||||||
self.draw_rect(device, rect, color, false);
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
rect: RectI,
|
||||||
|
color: ColorU) {
|
||||||
|
self.draw_rect(device, allocator, rect, color, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_rect(&self,
|
fn draw_rect(&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
rect: RectI,
|
rect: RectI,
|
||||||
color: ColorU,
|
color: ColorU,
|
||||||
filled: bool) {
|
filled: bool) {
|
||||||
|
@ -150,12 +154,14 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
if filled {
|
if filled {
|
||||||
self.draw_solid_rects_with_vertex_data(device,
|
self.draw_solid_rects_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
&vertex_data,
|
&vertex_data,
|
||||||
&QUAD_INDICES,
|
&QUAD_INDICES,
|
||||||
color,
|
color,
|
||||||
true);
|
true);
|
||||||
} else {
|
} else {
|
||||||
self.draw_solid_rects_with_vertex_data(device,
|
self.draw_solid_rects_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
&vertex_data,
|
&vertex_data,
|
||||||
&RECT_LINE_INDICES,
|
&RECT_LINE_INDICES,
|
||||||
color,
|
color,
|
||||||
|
@ -165,22 +171,33 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
fn draw_solid_rects_with_vertex_data(&self,
|
fn draw_solid_rects_with_vertex_data(&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
vertex_data: &[DebugSolidVertex],
|
vertex_data: &[DebugSolidVertex],
|
||||||
index_data: &[u32],
|
index_data: &[u32],
|
||||||
color: ColorU,
|
color: ColorU,
|
||||||
filled: bool) {
|
filled: bool) {
|
||||||
device.allocate_buffer(&self.solid_vertex_array.vertex_buffer,
|
let vertex_buffer_id =
|
||||||
BufferData::Memory(vertex_data),
|
allocator.allocate_buffer::<DebugSolidVertex>(device,
|
||||||
BufferTarget::Vertex);
|
vertex_data.len() as u64,
|
||||||
device.allocate_buffer(&self.solid_vertex_array.index_buffer,
|
BufferTag("SolidVertexDebug"));
|
||||||
BufferData::Memory(index_data),
|
let index_buffer_id = allocator.allocate_buffer::<u32>(device,
|
||||||
BufferTarget::Index);
|
index_data.len() as u64,
|
||||||
|
BufferTag("SolidIndexDebug"));
|
||||||
|
{
|
||||||
|
let vertex_buffer = allocator.get_buffer(vertex_buffer_id);
|
||||||
|
let index_buffer = allocator.get_buffer(index_buffer_id);
|
||||||
|
device.upload_to_buffer(&vertex_buffer, 0, vertex_data, BufferTarget::Vertex);
|
||||||
|
device.upload_to_buffer(&index_buffer, 0, index_data, BufferTarget::Index);
|
||||||
|
let solid_vertex_array = DebugSolidVertexArray::new(device,
|
||||||
|
&self.solid_program,
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer);
|
||||||
|
|
||||||
let primitive = if filled { Primitive::Triangles } else { Primitive::Lines };
|
let primitive = if filled { Primitive::Triangles } else { Primitive::Lines };
|
||||||
device.draw_elements(index_data.len() as u32, &RenderState {
|
device.draw_elements(index_data.len() as u32, &RenderState {
|
||||||
target: &RenderTarget::Default,
|
target: &RenderTarget::Default,
|
||||||
program: &self.solid_program.program,
|
program: &self.solid_program.program,
|
||||||
vertex_array: &self.solid_vertex_array.vertex_array,
|
vertex_array: &solid_vertex_array.vertex_array,
|
||||||
primitive,
|
primitive,
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.solid_program.framebuffer_size_uniform,
|
(&self.solid_program.framebuffer_size_uniform,
|
||||||
|
@ -189,6 +206,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
],
|
],
|
||||||
textures: &[],
|
textures: &[],
|
||||||
images: &[],
|
images: &[],
|
||||||
|
storage_buffers: &[],
|
||||||
viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
|
viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: Some(alpha_blend_state()),
|
blend: Some(alpha_blend_state()),
|
||||||
|
@ -197,7 +215,16 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_text(&self, device: &D, string: &str, origin: Vector2I, invert: bool) {
|
allocator.free_buffer(index_buffer_id);
|
||||||
|
allocator.free_buffer(vertex_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_text(&self,
|
||||||
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
string: &str,
|
||||||
|
origin: Vector2I,
|
||||||
|
invert: bool) {
|
||||||
let mut next = origin;
|
let mut next = origin;
|
||||||
let char_count = string.chars().count();
|
let char_count = string.chars().count();
|
||||||
let mut vertex_data = Vec::with_capacity(char_count * 4);
|
let mut vertex_data = Vec::with_capacity(char_count * 4);
|
||||||
|
@ -227,6 +254,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR };
|
let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR };
|
||||||
self.draw_texture_with_vertex_data(device,
|
self.draw_texture_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
&vertex_data,
|
&vertex_data,
|
||||||
&index_data,
|
&index_data,
|
||||||
&self.font_texture,
|
&self.font_texture,
|
||||||
|
@ -235,6 +263,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
pub fn draw_texture(&self,
|
pub fn draw_texture(&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
origin: Vector2I,
|
origin: Vector2I,
|
||||||
texture: &D::Texture,
|
texture: &D::Texture,
|
||||||
color: ColorU) {
|
color: ColorU) {
|
||||||
|
@ -247,7 +276,12 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
||||||
];
|
];
|
||||||
|
|
||||||
self.draw_texture_with_vertex_data(device, &vertex_data, &QUAD_INDICES, texture, color);
|
self.draw_texture_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
|
&vertex_data,
|
||||||
|
&QUAD_INDICES,
|
||||||
|
texture,
|
||||||
|
color);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn measure_text(&self, string: &str) -> i32 {
|
pub fn measure_text(&self, string: &str) -> i32 {
|
||||||
|
@ -268,10 +302,14 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
SEGMENT_SIZE * segment_count as i32 + (segment_count - 1) as i32
|
SEGMENT_SIZE * segment_count as i32 + (segment_count - 1) as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_solid_rounded_rect(&self, device: &D, rect: RectI, color: ColorU) {
|
pub fn draw_solid_rounded_rect(&self,
|
||||||
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
rect: RectI,
|
||||||
|
color: ColorU) {
|
||||||
let corner_texture = self.corner_texture(true);
|
let corner_texture = self.corner_texture(true);
|
||||||
let corner_rects = CornerRects::new(device, rect, corner_texture);
|
let corner_rects = CornerRects::new(device, rect, corner_texture);
|
||||||
self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects);
|
self.draw_rounded_rect_corners(device, allocator, color, corner_texture, &corner_rects);
|
||||||
|
|
||||||
let solid_rect_mid = RectI::from_points(corner_rects.upper_left.upper_right(),
|
let solid_rect_mid = RectI::from_points(corner_rects.upper_left.upper_right(),
|
||||||
corner_rects.lower_right.lower_left());
|
corner_rects.lower_right.lower_left());
|
||||||
|
@ -302,16 +340,21 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
|
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
|
||||||
|
|
||||||
self.draw_solid_rects_with_vertex_data(device,
|
self.draw_solid_rects_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
&vertex_data,
|
&vertex_data,
|
||||||
&index_data[0..18],
|
&index_data[0..18],
|
||||||
color,
|
color,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_rounded_rect_outline(&self, device: &D, rect: RectI, color: ColorU) {
|
pub fn draw_rounded_rect_outline(&self,
|
||||||
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
rect: RectI,
|
||||||
|
color: ColorU) {
|
||||||
let corner_texture = self.corner_texture(false);
|
let corner_texture = self.corner_texture(false);
|
||||||
let corner_rects = CornerRects::new(device, rect, corner_texture);
|
let corner_rects = CornerRects::new(device, rect, corner_texture);
|
||||||
self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects);
|
self.draw_rounded_rect_corners(device, allocator, color, corner_texture, &corner_rects);
|
||||||
|
|
||||||
let vertex_data = vec![
|
let vertex_data = vec![
|
||||||
DebugSolidVertex::new(corner_rects.upper_left.upper_right()),
|
DebugSolidVertex::new(corner_rects.upper_left.upper_right()),
|
||||||
|
@ -325,18 +368,34 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
];
|
];
|
||||||
|
|
||||||
let index_data = &OUTLINE_RECT_LINE_INDICES;
|
let index_data = &OUTLINE_RECT_LINE_INDICES;
|
||||||
self.draw_solid_rects_with_vertex_data(device, &vertex_data, index_data, color, false);
|
self.draw_solid_rects_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
|
&vertex_data,
|
||||||
|
index_data,
|
||||||
|
color,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): `LineSegment2I`.
|
// TODO(pcwalton): `LineSegment2I`.
|
||||||
fn draw_line(&self, device: &D, from: Vector2I, to: Vector2I, color: ColorU) {
|
fn draw_line(&self,
|
||||||
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
from: Vector2I,
|
||||||
|
to: Vector2I,
|
||||||
|
color: ColorU) {
|
||||||
let vertex_data = vec![DebugSolidVertex::new(from), DebugSolidVertex::new(to)];
|
let vertex_data = vec![DebugSolidVertex::new(from), DebugSolidVertex::new(to)];
|
||||||
self.draw_solid_rects_with_vertex_data(device, &vertex_data, &[0, 1], color, false);
|
self.draw_solid_rects_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
|
&vertex_data,
|
||||||
|
&[0, 1],
|
||||||
|
color,
|
||||||
|
false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_rounded_rect_corners(&self,
|
fn draw_rounded_rect_corners(&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
color: ColorU,
|
color: ColorU,
|
||||||
texture: &D::Texture,
|
texture: &D::Texture,
|
||||||
corner_rects: &CornerRects) {
|
corner_rects: &CornerRects) {
|
||||||
|
@ -387,7 +446,12 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
|
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 12));
|
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 12));
|
||||||
|
|
||||||
self.draw_texture_with_vertex_data(device, &vertex_data, &index_data, texture, color);
|
self.draw_texture_with_vertex_data(device,
|
||||||
|
allocator,
|
||||||
|
&vertex_data,
|
||||||
|
&index_data,
|
||||||
|
texture,
|
||||||
|
color);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn corner_texture(&self, filled: bool) -> &D::Texture {
|
fn corner_texture(&self, filled: bool) -> &D::Texture {
|
||||||
|
@ -396,24 +460,37 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
fn draw_texture_with_vertex_data(&self,
|
fn draw_texture_with_vertex_data(&self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
vertex_data: &[DebugTextureVertex],
|
vertex_data: &[DebugTextureVertex],
|
||||||
index_data: &[u32],
|
index_data: &[u32],
|
||||||
texture: &D::Texture,
|
texture: &D::Texture,
|
||||||
color: ColorU) {
|
color: ColorU) {
|
||||||
device.allocate_buffer(&self.texture_vertex_array.vertex_buffer,
|
let vertex_buffer_id =
|
||||||
BufferData::Memory(vertex_data),
|
allocator.allocate_buffer::<DebugTextureVertex>(device,
|
||||||
BufferTarget::Vertex);
|
vertex_data.len() as u64,
|
||||||
device.allocate_buffer(&self.texture_vertex_array.index_buffer,
|
BufferTag("TextureVertexDebug"));
|
||||||
BufferData::Memory(index_data),
|
let index_buffer_id = allocator.allocate_buffer::<u32>(device,
|
||||||
BufferTarget::Index);
|
index_data.len() as u64,
|
||||||
|
BufferTag("TextureIndexDebug"));
|
||||||
|
{
|
||||||
|
let vertex_buffer = allocator.get_buffer(vertex_buffer_id);
|
||||||
|
let index_buffer = allocator.get_buffer(index_buffer_id);
|
||||||
|
device.upload_to_buffer(&vertex_buffer, 0, vertex_data, BufferTarget::Vertex);
|
||||||
|
device.upload_to_buffer(&index_buffer, 0, index_data, BufferTarget::Index);
|
||||||
|
|
||||||
|
let texture_vertex_array = DebugTextureVertexArray::new(device,
|
||||||
|
&self.texture_program,
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer);
|
||||||
|
|
||||||
device.draw_elements(index_data.len() as u32, &RenderState {
|
device.draw_elements(index_data.len() as u32, &RenderState {
|
||||||
target: &RenderTarget::Default,
|
target: &RenderTarget::Default,
|
||||||
program: &self.texture_program.program,
|
program: &self.texture_program.program,
|
||||||
vertex_array: &self.texture_vertex_array.vertex_array,
|
vertex_array: &texture_vertex_array.vertex_array,
|
||||||
primitive: Primitive::Triangles,
|
primitive: Primitive::Triangles,
|
||||||
textures: &[(&self.texture_program.texture, &texture)],
|
textures: &[(&self.texture_program.texture, &texture)],
|
||||||
images: &[],
|
images: &[],
|
||||||
|
storage_buffers: &[],
|
||||||
uniforms: &[
|
uniforms: &[
|
||||||
(&self.texture_program.framebuffer_size_uniform,
|
(&self.texture_program.framebuffer_size_uniform,
|
||||||
UniformData::Vec2(self.framebuffer_size.0.to_f32x2())),
|
UniformData::Vec2(self.framebuffer_size.0.to_f32x2())),
|
||||||
|
@ -429,11 +506,20 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_button(&mut self, device: &D, origin: Vector2I, texture: &D::Texture) -> bool {
|
allocator.free_buffer(index_buffer_id);
|
||||||
|
allocator.free_buffer(vertex_buffer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_button(&mut self,
|
||||||
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
origin: Vector2I,
|
||||||
|
texture: &D::Texture) -> bool {
|
||||||
let button_rect = RectI::new(origin, vec2i(BUTTON_WIDTH, BUTTON_HEIGHT));
|
let button_rect = RectI::new(origin, vec2i(BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||||
self.draw_solid_rounded_rect(device, button_rect, WINDOW_COLOR);
|
self.draw_solid_rounded_rect(device, allocator, button_rect, WINDOW_COLOR);
|
||||||
self.draw_rounded_rect_outline(device, button_rect, OUTLINE_COLOR);
|
self.draw_rounded_rect_outline(device, allocator, button_rect, OUTLINE_COLOR);
|
||||||
self.draw_texture(device,
|
self.draw_texture(device,
|
||||||
|
allocator,
|
||||||
origin + vec2i(PADDING, PADDING),
|
origin + vec2i(PADDING, PADDING),
|
||||||
texture,
|
texture,
|
||||||
BUTTON_ICON_COLOR);
|
BUTTON_ICON_COLOR);
|
||||||
|
@ -442,11 +528,13 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
pub fn draw_text_switch(&mut self,
|
pub fn draw_text_switch(&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
mut origin: Vector2I,
|
mut origin: Vector2I,
|
||||||
segment_labels: &[&str],
|
segment_labels: &[&str],
|
||||||
mut value: u8)
|
mut value: u8)
|
||||||
-> u8 {
|
-> u8 {
|
||||||
if let Some(new_value) = self.draw_segmented_control(device,
|
if let Some(new_value) = self.draw_segmented_control(device,
|
||||||
|
allocator,
|
||||||
origin,
|
origin,
|
||||||
Some(value),
|
Some(value),
|
||||||
segment_labels.len() as u8) {
|
segment_labels.len() as u8) {
|
||||||
|
@ -458,6 +546,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
let label_width = self.measure_text(segment_label);
|
let label_width = self.measure_text(segment_label);
|
||||||
let offset = SEGMENT_SIZE / 2 - label_width / 2;
|
let offset = SEGMENT_SIZE / 2 - label_width / 2;
|
||||||
self.draw_text(device,
|
self.draw_text(device,
|
||||||
|
allocator,
|
||||||
segment_label,
|
segment_label,
|
||||||
origin + vec2i(offset, 0),
|
origin + vec2i(offset, 0),
|
||||||
segment_index as u8 == value);
|
segment_index as u8 == value);
|
||||||
|
@ -469,12 +558,14 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
pub fn draw_image_segmented_control(&mut self,
|
pub fn draw_image_segmented_control(&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
mut origin: Vector2I,
|
mut origin: Vector2I,
|
||||||
segment_textures: &[&D::Texture],
|
segment_textures: &[&D::Texture],
|
||||||
mut value: Option<u8>)
|
mut value: Option<u8>)
|
||||||
-> Option<u8> {
|
-> Option<u8> {
|
||||||
let mut clicked_segment = None;
|
let mut clicked_segment = None;
|
||||||
if let Some(segment_index) = self.draw_segmented_control(device,
|
if let Some(segment_index) = self.draw_segmented_control(device,
|
||||||
|
allocator,
|
||||||
origin,
|
origin,
|
||||||
value,
|
value,
|
||||||
segment_textures.len() as u8) {
|
segment_textures.len() as u8) {
|
||||||
|
@ -493,7 +584,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
TEXT_COLOR
|
TEXT_COLOR
|
||||||
};
|
};
|
||||||
|
|
||||||
self.draw_texture(device, origin + offset, segment_texture, color);
|
self.draw_texture(device, allocator, origin + offset, segment_texture, color);
|
||||||
origin += vec2i(SEGMENT_SIZE + 1, 0);
|
origin += vec2i(SEGMENT_SIZE + 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,6 +593,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
|
|
||||||
fn draw_segmented_control(&mut self,
|
fn draw_segmented_control(&mut self,
|
||||||
device: &D,
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
origin: Vector2I,
|
origin: Vector2I,
|
||||||
mut value: Option<u8>,
|
mut value: Option<u8>,
|
||||||
segment_count: u8)
|
segment_count: u8)
|
||||||
|
@ -518,13 +610,14 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
clicked_segment = Some(segment);
|
clicked_segment = Some(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw_solid_rounded_rect(device, widget_rect, WINDOW_COLOR);
|
self.draw_solid_rounded_rect(device, allocator, widget_rect, WINDOW_COLOR);
|
||||||
self.draw_rounded_rect_outline(device, widget_rect, OUTLINE_COLOR);
|
self.draw_rounded_rect_outline(device, allocator, widget_rect, OUTLINE_COLOR);
|
||||||
|
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
let highlight_size = vec2i(SEGMENT_SIZE, BUTTON_HEIGHT);
|
let highlight_size = vec2i(SEGMENT_SIZE, BUTTON_HEIGHT);
|
||||||
let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1);
|
let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1);
|
||||||
self.draw_solid_rounded_rect(device,
|
self.draw_solid_rounded_rect(device,
|
||||||
|
allocator,
|
||||||
RectI::new(origin + vec2i(x_offset, 0), highlight_size),
|
RectI::new(origin + vec2i(x_offset, 0), highlight_size),
|
||||||
TEXT_COLOR);
|
TEXT_COLOR);
|
||||||
}
|
}
|
||||||
|
@ -536,6 +629,7 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
Some(value) if value == prev_segment_index || value == next_segment_index => {}
|
Some(value) if value == prev_segment_index || value == next_segment_index => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.draw_line(device,
|
self.draw_line(device,
|
||||||
|
allocator,
|
||||||
segment_origin,
|
segment_origin,
|
||||||
segment_origin + vec2i(0, BUTTON_HEIGHT),
|
segment_origin + vec2i(0, BUTTON_HEIGHT),
|
||||||
TEXT_COLOR);
|
TEXT_COLOR);
|
||||||
|
@ -547,7 +641,11 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
clicked_segment
|
clicked_segment
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_tooltip(&self, device: &D, string: &str, rect: RectI) {
|
pub fn draw_tooltip(&self,
|
||||||
|
device: &D,
|
||||||
|
allocator: &mut GPUMemoryAllocator<D>,
|
||||||
|
string: &str,
|
||||||
|
rect: RectI) {
|
||||||
if !rect.to_f32().contains_point(self.mouse_position) {
|
if !rect.to_f32().contains_point(self.mouse_position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -556,8 +654,15 @@ impl<D> UIPresenter<D> where D: Device {
|
||||||
let window_size = vec2i(text_size + PADDING * 2, TOOLTIP_HEIGHT);
|
let window_size = vec2i(text_size + PADDING * 2, TOOLTIP_HEIGHT);
|
||||||
let origin = rect.origin() - vec2i(0, window_size.y() + PADDING);
|
let origin = rect.origin() - vec2i(0, window_size.y() + PADDING);
|
||||||
|
|
||||||
self.draw_solid_rounded_rect(device, RectI::new(origin, window_size), WINDOW_COLOR);
|
self.draw_solid_rounded_rect(device,
|
||||||
self.draw_text(device, string, origin + vec2i(PADDING, PADDING + FONT_ASCENT), false);
|
allocator,
|
||||||
|
RectI::new(origin, window_size),
|
||||||
|
WINDOW_COLOR);
|
||||||
|
self.draw_text(device,
|
||||||
|
allocator,
|
||||||
|
string,
|
||||||
|
origin + vec2i(PADDING, PADDING + FONT_ASCENT),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,7 +676,7 @@ struct DebugTextureProgram<D> where D: Device {
|
||||||
|
|
||||||
impl<D> DebugTextureProgram<D> where D: Device {
|
impl<D> DebugTextureProgram<D> where D: Device {
|
||||||
fn new(device: &D, resources: &dyn ResourceLoader) -> DebugTextureProgram<D> {
|
fn new(device: &D, resources: &dyn ResourceLoader) -> DebugTextureProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "debug_texture");
|
let program = device.create_raster_program(resources, "debug/texture");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let texture_size_uniform = device.get_uniform(&program, "TextureSize");
|
let texture_size_uniform = device.get_uniform(&program, "TextureSize");
|
||||||
let color_uniform = device.get_uniform(&program, "Color");
|
let color_uniform = device.get_uniform(&program, "Color");
|
||||||
|
@ -588,15 +693,14 @@ impl<D> DebugTextureProgram<D> where D: Device {
|
||||||
|
|
||||||
struct DebugTextureVertexArray<D> where D: Device {
|
struct DebugTextureVertexArray<D> where D: Device {
|
||||||
vertex_array: D::VertexArray,
|
vertex_array: D::VertexArray,
|
||||||
vertex_buffer: D::Buffer,
|
|
||||||
index_buffer: D::Buffer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DebugTextureVertexArray<D> where D: Device {
|
impl<D> DebugTextureVertexArray<D> where D: Device {
|
||||||
fn new(device: &D, debug_texture_program: &DebugTextureProgram<D>)
|
fn new(device: &D,
|
||||||
|
debug_texture_program: &DebugTextureProgram<D>,
|
||||||
|
vertex_buffer: &D::Buffer,
|
||||||
|
index_buffer: &D::Buffer)
|
||||||
-> DebugTextureVertexArray<D> {
|
-> DebugTextureVertexArray<D> {
|
||||||
let vertex_buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
|
||||||
let index_buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position")
|
let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position")
|
||||||
|
@ -604,8 +708,8 @@ impl<D> DebugTextureVertexArray<D> where D: Device {
|
||||||
let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord")
|
let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
|
device.bind_buffer(&vertex_array, vertex_buffer, BufferTarget::Vertex);
|
||||||
device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index);
|
device.bind_buffer(&vertex_array, index_buffer, BufferTarget::Index);
|
||||||
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
|
||||||
size: 2,
|
size: 2,
|
||||||
class: VertexAttrClass::Int,
|
class: VertexAttrClass::Int,
|
||||||
|
@ -625,20 +729,20 @@ impl<D> DebugTextureVertexArray<D> where D: Device {
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer }
|
DebugTextureVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DebugSolidVertexArray<D> where D: Device {
|
struct DebugSolidVertexArray<D> where D: Device {
|
||||||
vertex_array: D::VertexArray,
|
vertex_array: D::VertexArray,
|
||||||
vertex_buffer: D::Buffer,
|
|
||||||
index_buffer: D::Buffer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> DebugSolidVertexArray<D> where D: Device {
|
impl<D> DebugSolidVertexArray<D> where D: Device {
|
||||||
fn new(device: &D, debug_solid_program: &DebugSolidProgram<D>) -> DebugSolidVertexArray<D> {
|
fn new(device: &D,
|
||||||
let vertex_buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
debug_solid_program: &DebugSolidProgram<D>,
|
||||||
let index_buffer = device.create_buffer(BufferUploadMode::Dynamic);
|
vertex_buffer: &D::Buffer,
|
||||||
|
index_buffer: &D::Buffer)
|
||||||
|
-> DebugSolidVertexArray<D> {
|
||||||
let vertex_array = device.create_vertex_array();
|
let vertex_array = device.create_vertex_array();
|
||||||
|
|
||||||
let position_attr =
|
let position_attr =
|
||||||
|
@ -655,7 +759,7 @@ impl<D> DebugSolidVertexArray<D> where D: Device {
|
||||||
buffer_index: 0,
|
buffer_index: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer }
|
DebugSolidVertexArray { vertex_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +771,7 @@ struct DebugSolidProgram<D> where D: Device {
|
||||||
|
|
||||||
impl<D> DebugSolidProgram<D> where D: Device {
|
impl<D> DebugSolidProgram<D> where D: Device {
|
||||||
fn new(device: &D, resources: &dyn ResourceLoader) -> DebugSolidProgram<D> {
|
fn new(device: &D, resources: &dyn ResourceLoader) -> DebugSolidProgram<D> {
|
||||||
let program = device.create_raster_program(resources, "debug_solid");
|
let program = device.create_raster_program(resources, "debug/solid");
|
||||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||||
let color_uniform = device.get_uniform(&program, "Color");
|
let color_uniform = device.get_uniform(&program, "Color");
|
||||||
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
use js_sys::{Uint8Array, Uint16Array, Float32Array, Object};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps};
|
||||||
|
@ -24,11 +25,11 @@ use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
|
||||||
use pathfinder_resources::ResourceLoader;
|
use pathfinder_resources::ResourceLoader;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::ops::Range;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::WebGl2RenderingContext as WebGl;
|
use web_sys::WebGl2RenderingContext as WebGl;
|
||||||
use js_sys::{Uint8Array, Uint16Array, Float32Array, Object};
|
|
||||||
|
|
||||||
pub struct WebGlDevice {
|
pub struct WebGlDevice {
|
||||||
context: web_sys::WebGl2RenderingContext,
|
context: web_sys::WebGl2RenderingContext,
|
||||||
|
@ -426,6 +427,7 @@ unsafe fn check_and_extract_data(
|
||||||
|
|
||||||
impl Device for WebGlDevice {
|
impl Device for WebGlDevice {
|
||||||
type Buffer = WebGlBuffer;
|
type Buffer = WebGlBuffer;
|
||||||
|
type BufferDataReceiver = ();
|
||||||
type Fence = ();
|
type Fence = ();
|
||||||
type Framebuffer = WebGlFramebuffer;
|
type Framebuffer = WebGlFramebuffer;
|
||||||
type ImageParameter = ();
|
type ImageParameter = ();
|
||||||
|
@ -943,9 +945,23 @@ impl Device for WebGlDevice {
|
||||||
fn recv_timer_query(&self, _query: &WebGlTimerQuery) -> Duration {
|
fn recv_timer_query(&self, _query: &WebGlTimerQuery) -> Duration {
|
||||||
Duration::from_millis(0)
|
Duration::from_millis(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_recv_buffer(&self, _: &()) -> Option<Vec<u8>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_buffer(&self, _: &()) -> Vec<u8> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_buffer(&self, _: &Self::Buffer, _: BufferTarget, _: Range<usize>) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn try_recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> Option<TextureData> {
|
fn try_recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> Option<TextureData> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> TextureData {
|
fn recv_texture_data(&self, _receiver: &Self::TextureDataReceiver) -> TextureData {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -1175,6 +1191,7 @@ impl VertexAttrTypeExt for VertexAttrType {
|
||||||
fn to_gl_type(self) -> u32 {
|
fn to_gl_type(self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
VertexAttrType::F32 => WebGl::FLOAT,
|
VertexAttrType::F32 => WebGl::FLOAT,
|
||||||
|
VertexAttrType::I32 => WebGl::INT,
|
||||||
VertexAttrType::I16 => WebGl::SHORT,
|
VertexAttrType::I16 => WebGl::SHORT,
|
||||||
VertexAttrType::I8 => WebGl::BYTE,
|
VertexAttrType::I8 => WebGl::BYTE,
|
||||||
VertexAttrType::U16 => WebGl::UNSIGNED_SHORT,
|
VertexAttrType::U16 => WebGl::UNSIGNED_SHORT,
|
||||||
|
|
Loading…
Reference in New Issue