mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-09 12:21:31 +11:00
commit
f5a721d92b
399
Cargo.lock
generated
399
Cargo.lock
generated
|
@ -29,9 +29,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
@ -48,7 +48,7 @@ version = "0.33.3+1.2.191"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219"
|
||||
dependencies = [
|
||||
"libloading 0.7.1",
|
||||
"libloading 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -58,7 +58,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "12f91ce4c6be1a2ba99d3d6cd57d5bae9ac6d6f903b5ae53d6b1dee2edf872af"
|
||||
dependencies = [
|
||||
"ash",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.3.4",
|
||||
"raw-window-metal",
|
||||
]
|
||||
|
||||
|
@ -75,9 +75,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
|
@ -93,18 +93,18 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
|||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.7.2"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
|
||||
checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54"
|
||||
checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -128,10 +128,29 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.72"
|
||||
name = "cbindgen"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
checksum = "51e3973b165dc0f435831a9e426de67e894de532754ff7a3f307c03ee5dec7dc"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -147,9 +166,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
|
@ -169,7 +188,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"core-foundation 0.9.2",
|
||||
"core-foundation 0.9.3",
|
||||
"core-graphics 0.22.3",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -184,7 +203,7 @@ checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"block",
|
||||
"core-foundation 0.9.2",
|
||||
"core-foundation 0.9.3",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -203,9 +222,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys 0.8.3",
|
||||
"libc",
|
||||
|
@ -242,7 +261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation 0.9.2",
|
||||
"core-foundation 0.9.3",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -255,7 +274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation 0.9.2",
|
||||
"core-foundation 0.9.3",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
]
|
||||
|
@ -275,9 +294,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
@ -298,9 +317,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
|
@ -319,10 +338,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.5"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
|
||||
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
|
@ -332,9 +352,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.2"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
|
||||
checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
|
@ -342,14 +362,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.5"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cty"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
|
@ -395,31 +421,20 @@ dependencies = [
|
|||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "3.0.2"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
|
@ -447,7 +462,7 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
|
||||
dependencies = [
|
||||
"libloading 0.7.1",
|
||||
"libloading 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -456,6 +471,15 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -490,9 +514,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
|
@ -505,6 +529,21 @@ version = "1.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
@ -520,6 +559,16 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
|
@ -529,6 +578,12 @@ dependencies = [
|
|||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
|
@ -552,9 +607,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.107"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
|
||||
checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -568,9 +623,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.1"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0"
|
||||
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi",
|
||||
|
@ -578,18 +633,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
version = "0.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
@ -611,9 +667,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
|
@ -626,9 +682,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -677,9 +733,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio-misc"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ddf05411bb159cdb5801bb10002afb66cb4572be656044315e363460ce69dc2"
|
||||
checksum = "b47412f3a52115b936ff2a229b803498c7b4d332adeb87c2f1498c9da54c398c"
|
||||
dependencies = [
|
||||
"crossbeam",
|
||||
"crossbeam-queue",
|
||||
|
@ -696,6 +752,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moscato"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8372f6cdc8b2c431750a9c4edbc8d9c511ef1a68472aaa02500493414a407c64"
|
||||
dependencies = [
|
||||
"pinot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.3.0"
|
||||
|
@ -737,9 +802,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
|
||||
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
|
@ -767,41 +832,39 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
version = "7.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
|
||||
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.4"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f"
|
||||
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
|
||||
dependencies = [
|
||||
"derivative",
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.4"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9"
|
||||
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.1.0",
|
||||
"proc-macro-crate 1.1.3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
|
@ -828,9 +891,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
|
@ -872,6 +935,19 @@ version = "2.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
|
||||
[[package]]
|
||||
name = "pgpu-render"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"cocoa",
|
||||
"metal",
|
||||
"objc",
|
||||
"piet-gpu",
|
||||
"piet-gpu-hal",
|
||||
"piet-scene",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "piet"
|
||||
version = "0.2.0"
|
||||
|
@ -896,7 +972,7 @@ dependencies = [
|
|||
"piet-gpu-types",
|
||||
"png",
|
||||
"rand",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.3.4",
|
||||
"roxmltree",
|
||||
"swash",
|
||||
"winit",
|
||||
|
@ -924,7 +1000,7 @@ dependencies = [
|
|||
"foreign-types",
|
||||
"metal",
|
||||
"objc",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.3.4",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
"wio",
|
||||
|
@ -951,10 +1027,26 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
name = "piet-scene"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"moscato",
|
||||
"pinot",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pinot"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
checksum = "6ba3013ff85036c414a4a3cf826135db204de2bd80d684728550e7130421809a"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
|
@ -970,9 +1062,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
|
@ -985,9 +1077,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.1.0"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83"
|
||||
checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"toml",
|
||||
|
@ -995,18 +1087,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -1054,11 +1146,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211"
|
||||
checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"raw-window-handle 0.4.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
|
||||
dependencies = [
|
||||
"cty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1070,26 +1172,36 @@ dependencies = [
|
|||
"cocoa",
|
||||
"core-graphics 0.22.3",
|
||||
"objc",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.0"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.3",
|
||||
"getrandom 0.2.6",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1111,6 +1223,12 @@ dependencies = [
|
|||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
@ -1134,15 +1252,40 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
version = "1.0.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
|
@ -1187,15 +1330,29 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||
checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
|
@ -1207,18 +1364,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.30"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1227,9 +1384,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
@ -1291,6 +1448,12 @@ dependencies = [
|
|||
"unic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
|
@ -1309,12 +1472,6 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
|
@ -1450,7 +1607,7 @@ checksum = "79610794594d5e86be473ef7763f604f2159cbac8c94debd00df8fb41e86c2f8"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"cocoa",
|
||||
"core-foundation 0.9.2",
|
||||
"core-foundation 0.9.3",
|
||||
"core-graphics 0.22.3",
|
||||
"core-video-sys",
|
||||
"dispatch",
|
||||
|
@ -1466,7 +1623,7 @@ dependencies = [
|
|||
"objc",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"raw-window-handle 0.3.4",
|
||||
"scopeguard",
|
||||
"smithay-client-toolkit",
|
||||
"wayland-client",
|
||||
|
@ -1505,9 +1662,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a23fe958c70412687039c86f578938b4a0bb50ec788e96bce4d6ab00ddd5803"
|
||||
checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
]
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
[workspace]
|
||||
|
||||
members = [
|
||||
"pgpu-render",
|
||||
"piet-gpu",
|
||||
"piet-gpu-derive",
|
||||
"piet-gpu-hal",
|
||||
"piet-gpu-types",
|
||||
"piet-scene",
|
||||
"tests"
|
||||
]
|
||||
|
|
21
pgpu-render/Cargo.toml
Normal file
21
pgpu-render/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "pgpu-render"
|
||||
version = "0.1.0"
|
||||
description = "C interface for glyph rendering using piet-gpu."
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
piet-gpu = { path = "../piet-gpu" }
|
||||
piet-gpu-hal = { path = "../piet-gpu-hal" }
|
||||
piet-scene = { path = "../piet-scene" }
|
||||
|
||||
metal = "0.22"
|
||||
cocoa = "0.24.0"
|
||||
objc = "0.2.5"
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.20.0"
|
29
pgpu-render/build.rs
Normal file
29
pgpu-render/build.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
extern crate cbindgen;
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
cbindgen::Builder::new()
|
||||
.with_crate(crate_dir)
|
||||
.with_header("/** Automatically generated from pgpu-render/src/lib.rs with cbindgen. **/")
|
||||
.generate()
|
||||
.expect("Unable to generate bindings")
|
||||
.write_to_file("pgpu.h");
|
||||
}
|
142
pgpu-render/pgpu.h
Normal file
142
pgpu-render/pgpu.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/** Automatically generated from pgpu-render/src/lib.rs with cbindgen. **/
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <new>
|
||||
|
||||
/// Encoded (possibly color) outline for a glyph.
|
||||
struct PgpuGlyph;
|
||||
|
||||
/// Context for loading and scaling glyphs.
|
||||
struct PgpuGlyphContext;
|
||||
|
||||
/// Context for loading a scaling glyphs from a specific font.
|
||||
struct PgpuGlyphProvider;
|
||||
|
||||
/// State and resources for rendering a scene.
|
||||
struct PgpuRenderer;
|
||||
|
||||
/// Encoded streams and resources describing a vector graphics scene.
|
||||
struct PgpuScene;
|
||||
|
||||
/// Builder for constructing an encoded scene.
|
||||
struct PgpuSceneBuilder;
|
||||
|
||||
/// Tag and value for a font variation axis.
|
||||
struct PgpuFontVariation {
|
||||
/// Tag that specifies the axis.
|
||||
uint32_t tag;
|
||||
/// Requested setting for the axis.
|
||||
float value;
|
||||
};
|
||||
|
||||
/// Description of a font.
|
||||
struct PgpuFontDesc {
|
||||
/// Pointer to the context of the font file.
|
||||
const uint8_t *data;
|
||||
/// Size of the font file data in bytes.
|
||||
uintptr_t data_len;
|
||||
/// Index of the requested font in the font file.
|
||||
uint32_t index;
|
||||
/// Unique identifier for the font.
|
||||
uint64_t unique_id;
|
||||
/// Requested size in pixels per em unit. Set to 0.0 for
|
||||
/// unscaled outlines.
|
||||
float ppem;
|
||||
/// Pointer to array of font variation settings.
|
||||
const PgpuFontVariation *variations;
|
||||
/// Number of font variation settings.
|
||||
uintptr_t variations_len;
|
||||
};
|
||||
|
||||
/// Rectangle defined by minimum and maximum points.
|
||||
struct PgpuRect {
|
||||
float x0;
|
||||
float y0;
|
||||
float x1;
|
||||
float y1;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
/// Creates a new piet-gpu renderer for the specified Metal device and
|
||||
/// command queue.
|
||||
///
|
||||
/// device: MTLDevice*
|
||||
/// queue: MTLCommandQueue*
|
||||
PgpuRenderer *pgpu_renderer_new(void *device, void *queue);
|
||||
|
||||
/// Renders a prepared scene into a texture target. Commands for rendering are
|
||||
/// recorded into the specified command buffer. Returns an id representing
|
||||
/// resources that may have been allocated during this process. After the
|
||||
/// command buffer has been retired, call `pgpu_renderer_release` with this id
|
||||
/// to drop any associated resources.
|
||||
///
|
||||
/// target: MTLTexture*
|
||||
/// cmdbuf: MTLCommandBuffer*
|
||||
uint32_t pgpu_renderer_render(PgpuRenderer *renderer,
|
||||
const PgpuScene *scene,
|
||||
void *target,
|
||||
void *cmdbuf);
|
||||
|
||||
/// Releases the internal resources associated with the specified id from a
|
||||
/// previous render operation.
|
||||
void pgpu_renderer_release(PgpuRenderer *renderer, uint32_t id);
|
||||
|
||||
/// Destroys the piet-gpu renderer.
|
||||
void pgpu_renderer_destroy(PgpuRenderer *renderer);
|
||||
|
||||
/// Creates a new, empty piet-gpu scene.
|
||||
PgpuScene *pgpu_scene_new();
|
||||
|
||||
/// Destroys the piet-gpu scene.
|
||||
void pgpu_scene_destroy(PgpuScene *scene);
|
||||
|
||||
/// Creates a new builder for filling a piet-gpu scene. The specified scene
|
||||
/// should not be accessed while the builder is live.
|
||||
PgpuSceneBuilder *pgpu_scene_builder_new(PgpuScene *scene);
|
||||
|
||||
/// Adds a glyph with the specified transform to the underlying scene.
|
||||
void pgpu_scene_builder_add_glyph(PgpuSceneBuilder *builder,
|
||||
const PgpuGlyph *glyph,
|
||||
const float (*transform)[6]);
|
||||
|
||||
/// Finalizes the scene builder, making the underlying scene ready for
|
||||
/// rendering. This takes ownership and consumes the builder.
|
||||
void pgpu_scene_builder_finish(PgpuSceneBuilder *builder);
|
||||
|
||||
/// Creates a new context for loading glyph outlines.
|
||||
PgpuGlyphContext *pgpu_glyph_context_new();
|
||||
|
||||
/// Destroys the glyph context.
|
||||
void pgpu_glyph_context_destroy(PgpuGlyphContext *gcx);
|
||||
|
||||
/// Creates a new glyph provider for the specified glyph context and font
|
||||
/// descriptor. May return nullptr if the font data is invalid. Only one glyph
|
||||
/// provider may be live for a glyph context.
|
||||
PgpuGlyphProvider *pgpu_glyph_provider_new(PgpuGlyphContext *gcx, const PgpuFontDesc *font);
|
||||
|
||||
/// Returns an encoded outline for the specified glyph provider and glyph id.
|
||||
/// May return nullptr if the requested glyph is not available.
|
||||
PgpuGlyph *pgpu_glyph_provider_get(PgpuGlyphProvider *provider, uint16_t gid);
|
||||
|
||||
/// Returns an encoded color outline for the specified glyph provider, color
|
||||
/// palette index and glyph id. May return nullptr if the requested glyph is
|
||||
/// not available.
|
||||
PgpuGlyph *pgpu_glyph_provider_get_color(PgpuGlyphProvider *provider,
|
||||
uint16_t palette_index,
|
||||
uint16_t gid);
|
||||
|
||||
/// Destroys the glyph provider.
|
||||
void pgpu_glyph_provider_destroy(PgpuGlyphProvider *provider);
|
||||
|
||||
/// Computes the bounding box for the glyph after applying the specified
|
||||
/// transform.
|
||||
PgpuRect pgpu_glyph_bbox(const PgpuGlyph *glyph, const float (*transform)[6]);
|
||||
|
||||
/// Destroys the glyph.
|
||||
void pgpu_glyph_destroy(PgpuGlyph *glyph);
|
||||
|
||||
} // extern "C"
|
233
pgpu-render/src/lib.rs
Normal file
233
pgpu-render/src/lib.rs
Normal file
|
@ -0,0 +1,233 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
mod render;
|
||||
|
||||
use render::*;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::transmute;
|
||||
|
||||
/// Creates a new piet-gpu renderer for the specified Metal device and
|
||||
/// command queue.
|
||||
///
|
||||
/// device: MTLDevice*
|
||||
/// queue: MTLCommandQueue*
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_renderer_new(
|
||||
device: *mut c_void,
|
||||
queue: *mut c_void,
|
||||
) -> *mut PgpuRenderer {
|
||||
let device: &metal::DeviceRef = transmute(device);
|
||||
let queue: &metal::CommandQueueRef = transmute(queue);
|
||||
Box::into_raw(Box::new(PgpuRenderer::new(device, queue)))
|
||||
}
|
||||
|
||||
/// Renders a prepared scene into a texture target. Commands for rendering are
|
||||
/// recorded into the specified command buffer. Returns an id representing
|
||||
/// resources that may have been allocated during this process. After the
|
||||
/// command buffer has been retired, call `pgpu_renderer_release` with this id
|
||||
/// to drop any associated resources.
|
||||
///
|
||||
/// target: MTLTexture*
|
||||
/// cmdbuf: MTLCommandBuffer*
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_renderer_render(
|
||||
renderer: *mut PgpuRenderer,
|
||||
scene: *const PgpuScene,
|
||||
target: *mut c_void,
|
||||
cmdbuf: *mut c_void,
|
||||
) -> u32 {
|
||||
let cmdbuf: &metal::CommandBufferRef = transmute(cmdbuf);
|
||||
let target: &metal::TextureRef = transmute(target);
|
||||
(*renderer).render(&*scene, cmdbuf, target)
|
||||
}
|
||||
|
||||
/// Releases the internal resources associated with the specified id from a
|
||||
/// previous render operation.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_renderer_release(renderer: *mut PgpuRenderer, id: u32) {
|
||||
(*renderer).release(id);
|
||||
}
|
||||
|
||||
/// Destroys the piet-gpu renderer.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_renderer_destroy(renderer: *mut PgpuRenderer) {
|
||||
Box::from_raw(renderer);
|
||||
}
|
||||
|
||||
/// Creates a new, empty piet-gpu scene.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_scene_new() -> *mut PgpuScene {
|
||||
Box::into_raw(Box::new(PgpuScene::new()))
|
||||
}
|
||||
|
||||
/// Destroys the piet-gpu scene.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_scene_destroy(scene: *mut PgpuScene) {
|
||||
Box::from_raw(scene);
|
||||
}
|
||||
|
||||
/// Creates a new builder for filling a piet-gpu scene. The specified scene
|
||||
/// should not be accessed while the builder is live.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_scene_builder_new(
|
||||
scene: *mut PgpuScene,
|
||||
) -> *mut PgpuSceneBuilder<'static> {
|
||||
Box::into_raw(Box::new((*scene).build()))
|
||||
}
|
||||
|
||||
/// Adds a glyph with the specified transform to the underlying scene.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_scene_builder_add_glyph(
|
||||
builder: *mut PgpuSceneBuilder<'static>,
|
||||
glyph: *const PgpuGlyph,
|
||||
transform: &[f32; 6],
|
||||
) {
|
||||
let transform = piet_scene::geometry::Affine::new(transform);
|
||||
(*builder).add_glyph(&*glyph, &transform);
|
||||
}
|
||||
|
||||
/// Finalizes the scene builder, making the underlying scene ready for
|
||||
/// rendering. This takes ownership and consumes the builder.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_scene_builder_finish(builder: *mut PgpuSceneBuilder<'static>) {
|
||||
let builder = Box::from_raw(builder);
|
||||
builder.finish();
|
||||
}
|
||||
|
||||
/// Creates a new context for loading glyph outlines.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_context_new() -> *mut PgpuGlyphContext {
|
||||
Box::into_raw(Box::new(PgpuGlyphContext::new()))
|
||||
}
|
||||
|
||||
/// Destroys the glyph context.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_context_destroy(gcx: *mut PgpuGlyphContext) {
|
||||
Box::from_raw(gcx);
|
||||
}
|
||||
|
||||
/// Description of a font.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct PgpuFontDesc {
|
||||
/// Pointer to the context of the font file.
|
||||
data: *const u8,
|
||||
/// Size of the font file data in bytes.
|
||||
data_len: usize,
|
||||
/// Index of the requested font in the font file.
|
||||
index: u32,
|
||||
/// Unique identifier for the font.
|
||||
unique_id: u64,
|
||||
/// Requested size in pixels per em unit. Set to 0.0 for
|
||||
/// unscaled outlines.
|
||||
ppem: f32,
|
||||
/// Pointer to array of font variation settings.
|
||||
variations: *const PgpuFontVariation,
|
||||
/// Number of font variation settings.
|
||||
variations_len: usize,
|
||||
}
|
||||
|
||||
/// Creates a new glyph provider for the specified glyph context and font
|
||||
/// descriptor. May return nullptr if the font data is invalid. Only one glyph
|
||||
/// provider may be live for a glyph context.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_provider_new(
|
||||
gcx: *mut PgpuGlyphContext,
|
||||
font: *const PgpuFontDesc,
|
||||
) -> *mut PgpuGlyphProvider<'static> {
|
||||
let font = &*font;
|
||||
let font_data = std::slice::from_raw_parts(font.data, font.data_len);
|
||||
let variations = std::slice::from_raw_parts(font.variations, font.variations_len);
|
||||
if let Some(provider) = (*gcx).new_provider(
|
||||
font_data,
|
||||
font.index,
|
||||
font.unique_id,
|
||||
font.ppem,
|
||||
false,
|
||||
variations,
|
||||
) {
|
||||
Box::into_raw(Box::new(provider))
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an encoded outline for the specified glyph provider and glyph id.
|
||||
/// May return nullptr if the requested glyph is not available.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_provider_get(
|
||||
provider: *mut PgpuGlyphProvider,
|
||||
gid: u16,
|
||||
) -> *mut PgpuGlyph {
|
||||
if let Some(glyph) = (*provider).get(gid) {
|
||||
Box::into_raw(Box::new(glyph))
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an encoded color outline for the specified glyph provider, color
|
||||
/// palette index and glyph id. May return nullptr if the requested glyph is
|
||||
/// not available.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_provider_get_color(
|
||||
provider: *mut PgpuGlyphProvider,
|
||||
palette_index: u16,
|
||||
gid: u16,
|
||||
) -> *mut PgpuGlyph {
|
||||
if let Some(glyph) = (*provider).get_color(palette_index, gid) {
|
||||
Box::into_raw(Box::new(glyph))
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys the glyph provider.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_provider_destroy(provider: *mut PgpuGlyphProvider) {
|
||||
Box::from_raw(provider);
|
||||
}
|
||||
|
||||
/// Rectangle defined by minimum and maximum points.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
#[repr(C)]
|
||||
pub struct PgpuRect {
|
||||
pub x0: f32,
|
||||
pub y0: f32,
|
||||
pub x1: f32,
|
||||
pub y1: f32,
|
||||
}
|
||||
|
||||
/// Computes the bounding box for the glyph after applying the specified
|
||||
/// transform.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_bbox(glyph: *const PgpuGlyph, transform: &[f32; 6]) -> PgpuRect {
|
||||
let transform = piet_scene::geometry::Affine::new(transform);
|
||||
let rect = (*glyph).bbox(Some(transform));
|
||||
PgpuRect {
|
||||
x0: rect.min.x,
|
||||
y0: rect.min.y,
|
||||
x1: rect.max.x,
|
||||
y1: rect.max.y,
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys the glyph.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pgpu_glyph_destroy(glyph: *mut PgpuGlyph) {
|
||||
Box::from_raw(glyph);
|
||||
}
|
222
pgpu-render/src/render.rs
Normal file
222
pgpu-render/src/render.rs
Normal file
|
@ -0,0 +1,222 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use piet_gpu::{EncodedSceneRef, PixelFormat, RenderConfig};
|
||||
use piet_gpu_hal::{QueryPool, Session};
|
||||
use piet_scene::glyph::pinot::{types::Tag, FontDataRef};
|
||||
use piet_scene::geometry::{Affine, Rect};
|
||||
use piet_scene::glyph::{GlyphContext, GlyphProvider};
|
||||
use piet_scene::resource::ResourceContext;
|
||||
use piet_scene::scene::{Fragment, Scene};
|
||||
|
||||
/// State and resources for rendering a scene.
|
||||
pub struct PgpuRenderer {
|
||||
session: Session,
|
||||
pgpu_renderer: Option<piet_gpu::Renderer>,
|
||||
query_pool: QueryPool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
is_color: bool,
|
||||
}
|
||||
|
||||
impl PgpuRenderer {
|
||||
pub fn new(device: &metal::DeviceRef, queue: &metal::CommandQueueRef) -> Self {
|
||||
let piet_device = piet_gpu_hal::Device::new_from_raw_mtl(device, &queue);
|
||||
let session = Session::new(piet_device);
|
||||
let query_pool = session.create_query_pool(12).unwrap();
|
||||
Self {
|
||||
session,
|
||||
pgpu_renderer: None,
|
||||
query_pool,
|
||||
width: 0,
|
||||
height: 0,
|
||||
is_color: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&mut self,
|
||||
scene: &PgpuScene,
|
||||
cmdbuf: &metal::CommandBufferRef,
|
||||
target: &metal::TextureRef,
|
||||
) -> u32 {
|
||||
let is_color = target.pixel_format() != metal::MTLPixelFormat::A8Unorm;
|
||||
let width = target.width() as u32;
|
||||
let height = target.height() as u32;
|
||||
if self.pgpu_renderer.is_none()
|
||||
|| self.width != width
|
||||
|| self.height != height
|
||||
|| self.is_color != is_color
|
||||
{
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.is_color = is_color;
|
||||
let format = if is_color {
|
||||
PixelFormat::Rgba8
|
||||
} else {
|
||||
PixelFormat::A8
|
||||
};
|
||||
let config = RenderConfig::new(width as usize, height as usize).pixel_format(format);
|
||||
unsafe {
|
||||
self.pgpu_renderer =
|
||||
piet_gpu::Renderer::new_from_config(&self.session, config, 1).ok();
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
let mut cmd_buf = self.session.cmd_buf_from_raw_mtl(cmdbuf);
|
||||
let dst_image = self
|
||||
.session
|
||||
.image_from_raw_mtl(target, self.width, self.height);
|
||||
if let Some(renderer) = &mut self.pgpu_renderer {
|
||||
renderer.upload_scene(&scene.encoded_scene(), 0).unwrap();
|
||||
renderer.record(&mut cmd_buf, &self.query_pool, 0);
|
||||
// TODO later: we can bind the destination image and avoid the copy.
|
||||
cmd_buf.blit_image(&renderer.image_dev, &dst_image);
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
pub fn release(&mut self, _id: u32) {
|
||||
// TODO: worry about freeing resources / managing overlapping submits
|
||||
}
|
||||
}
|
||||
|
||||
/// Encoded streams and resources describing a vector graphics scene.
|
||||
pub struct PgpuScene {
|
||||
scene: Scene,
|
||||
rcx: ResourceContext,
|
||||
}
|
||||
|
||||
impl PgpuScene {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
scene: Scene::default(),
|
||||
rcx: ResourceContext::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&mut self) -> PgpuSceneBuilder {
|
||||
self.rcx.advance();
|
||||
PgpuSceneBuilder(piet_scene::scene::build_scene(
|
||||
&mut self.scene,
|
||||
&mut self.rcx,
|
||||
))
|
||||
}
|
||||
|
||||
fn encoded_scene<'a>(&'a self) -> EncodedSceneRef<'a, piet_scene::geometry::Affine> {
|
||||
let d = self.scene.data();
|
||||
EncodedSceneRef {
|
||||
transform_stream: &d.transform_stream,
|
||||
tag_stream: &d.tag_stream,
|
||||
pathseg_stream: &d.pathseg_stream,
|
||||
linewidth_stream: &d.linewidth_stream,
|
||||
drawtag_stream: &d.drawtag_stream,
|
||||
drawdata_stream: &d.drawdata_stream,
|
||||
n_path: d.n_path,
|
||||
n_pathseg: d.n_pathseg,
|
||||
n_clip: d.n_clip,
|
||||
ramp_data: self.rcx.ramp_data(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for constructing an encoded scene.
|
||||
pub struct PgpuSceneBuilder<'a>(piet_scene::scene::Builder<'a>);
|
||||
|
||||
impl<'a> PgpuSceneBuilder<'a> {
|
||||
pub fn add_glyph(&mut self, glyph: &PgpuGlyph, transform: &piet_scene::geometry::Affine) {
|
||||
self.0.push_transform(*transform);
|
||||
self.0.append(&glyph.fragment);
|
||||
self.0.pop_transform();
|
||||
}
|
||||
|
||||
pub fn finish(self) {
|
||||
self.0.finish();
|
||||
}
|
||||
}
|
||||
|
||||
/// Tag and value for a font variation axis.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct PgpuFontVariation {
|
||||
/// Tag that specifies the axis.
|
||||
pub tag: u32,
|
||||
/// Requested setting for the axis.
|
||||
pub value: f32,
|
||||
}
|
||||
|
||||
/// Context for loading and scaling glyphs.
|
||||
pub struct PgpuGlyphContext(GlyphContext);
|
||||
|
||||
impl PgpuGlyphContext {
|
||||
pub fn new() -> Self {
|
||||
Self(GlyphContext::new())
|
||||
}
|
||||
|
||||
pub fn new_provider<'a>(
|
||||
&'a mut self,
|
||||
font_data: &'a [u8],
|
||||
font_index: u32,
|
||||
font_id: u64,
|
||||
ppem: f32,
|
||||
hint: bool,
|
||||
variations: &[PgpuFontVariation],
|
||||
) -> Option<PgpuGlyphProvider> {
|
||||
let font = FontDataRef::new(font_data).and_then(|f| f.get(font_index))?;
|
||||
Some(PgpuGlyphProvider(
|
||||
self.0.new_provider(
|
||||
&font,
|
||||
Some(font_id),
|
||||
ppem,
|
||||
hint,
|
||||
variations
|
||||
.iter()
|
||||
.map(|variation| (Tag(variation.tag), variation.value)),
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Context for loading a scaling glyphs from a specific font.
|
||||
pub struct PgpuGlyphProvider<'a>(GlyphProvider<'a>);
|
||||
|
||||
impl<'a> PgpuGlyphProvider<'a> {
|
||||
pub fn get(&mut self, gid: u16) -> Option<PgpuGlyph> {
|
||||
let fragment = self.0.get(gid)?;
|
||||
Some(PgpuGlyph { fragment })
|
||||
}
|
||||
|
||||
pub fn get_color(&mut self, palette_index: u16, gid: u16) -> Option<PgpuGlyph> {
|
||||
let fragment = self.0.get_color(palette_index, gid)?;
|
||||
Some(PgpuGlyph { fragment })
|
||||
}
|
||||
}
|
||||
|
||||
/// Encoded (possibly color) outline for a glyph.
|
||||
pub struct PgpuGlyph {
|
||||
fragment: Fragment,
|
||||
}
|
||||
|
||||
impl PgpuGlyph {
|
||||
pub fn bbox(&self, transform: Option<Affine>) -> Rect {
|
||||
if let Some(transform) = &transform {
|
||||
Rect::from_points(self.fragment.points().iter().map(|p| p.transform(transform)))
|
||||
} else {
|
||||
Rect::from_points(self.fragment.points())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -350,7 +350,7 @@ impl crate::backend::Device for MtlDevice {
|
|||
//desc.set_mipmap_level_count(1);
|
||||
let mtl_format = match format {
|
||||
ImageFormat::A8 => metal::MTLPixelFormat::R8Unorm,
|
||||
ImageFormat::Rgba8 => metal::MTLPixelFormat::RGBA8Unorm,
|
||||
ImageFormat::Rgba8 => metal::MTLPixelFormat::BGRA8Unorm,
|
||||
};
|
||||
desc.set_pixel_format(mtl_format);
|
||||
desc.set_usage(metal::MTLTextureUsage::ShaderRead | metal::MTLTextureUsage::ShaderWrite);
|
||||
|
|
|
@ -37,6 +37,147 @@ pub struct Encoder {
|
|||
n_clip: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct EncodedSceneRef<'a, T: Copy + Pod> {
|
||||
pub transform_stream: &'a [T],
|
||||
pub tag_stream: &'a [u8],
|
||||
pub pathseg_stream: &'a [u8],
|
||||
pub linewidth_stream: &'a [f32],
|
||||
pub drawtag_stream: &'a [u32],
|
||||
pub drawdata_stream: &'a [u8],
|
||||
pub n_path: u32,
|
||||
pub n_pathseg: u32,
|
||||
pub n_clip: u32,
|
||||
pub ramp_data: &'a [u32],
|
||||
}
|
||||
|
||||
impl<'a, T: Copy + Pod> EncodedSceneRef<'a, T> {
|
||||
/// Return a config for the element processing pipeline.
|
||||
///
|
||||
/// This does not include further pipeline processing. Also returns the
|
||||
/// beginning of free memory.
|
||||
pub fn stage_config(&self) -> (Config, usize) {
|
||||
// Layout of scene buffer
|
||||
let drawtag_offset = 0;
|
||||
let n_drawobj = self.n_drawobj();
|
||||
let n_drawobj_padded = align_up(n_drawobj, DRAW_PART_SIZE as usize);
|
||||
let drawdata_offset = drawtag_offset + n_drawobj_padded * DRAWTAG_SIZE;
|
||||
let trans_offset = drawdata_offset + self.drawdata_stream.len();
|
||||
let n_trans = self.transform_stream.len();
|
||||
let n_trans_padded = align_up(n_trans, TRANSFORM_PART_SIZE as usize);
|
||||
let linewidth_offset = trans_offset + n_trans_padded * TRANSFORM_SIZE;
|
||||
let n_linewidth = self.linewidth_stream.len();
|
||||
let pathtag_offset = linewidth_offset + n_linewidth * LINEWIDTH_SIZE;
|
||||
let n_pathtag = self.tag_stream.len();
|
||||
let n_pathtag_padded = align_up(n_pathtag, PATHSEG_PART_SIZE as usize);
|
||||
let pathseg_offset = pathtag_offset + n_pathtag_padded;
|
||||
|
||||
// Layout of memory
|
||||
let mut alloc = 0;
|
||||
let trans_alloc = alloc;
|
||||
alloc += trans_alloc + n_trans_padded * TRANSFORM_SIZE;
|
||||
let pathseg_alloc = alloc;
|
||||
alloc += pathseg_alloc + self.n_pathseg as usize * PATHSEG_SIZE;
|
||||
let path_bbox_alloc = alloc;
|
||||
let n_path = self.n_path as usize;
|
||||
alloc += path_bbox_alloc + n_path * PATH_BBOX_SIZE;
|
||||
let drawmonoid_alloc = alloc;
|
||||
alloc += n_drawobj_padded * DRAWMONOID_SIZE;
|
||||
let anno_alloc = alloc;
|
||||
alloc += n_drawobj * ANNOTATED_SIZE;
|
||||
let clip_alloc = alloc;
|
||||
let n_clip = self.n_clip as usize;
|
||||
const CLIP_SIZE: usize = 4;
|
||||
alloc += n_clip * CLIP_SIZE;
|
||||
let clip_bic_alloc = alloc;
|
||||
const CLIP_BIC_SIZE: usize = 8;
|
||||
// This can round down, as we only reduce the prefix
|
||||
alloc += (n_clip / CLIP_PART_SIZE as usize) * CLIP_BIC_SIZE;
|
||||
let clip_stack_alloc = alloc;
|
||||
const CLIP_EL_SIZE: usize = 20;
|
||||
alloc += n_clip * CLIP_EL_SIZE;
|
||||
let clip_bbox_alloc = alloc;
|
||||
const CLIP_BBOX_SIZE: usize = 16;
|
||||
alloc += align_up(n_clip as usize, CLIP_PART_SIZE as usize) * CLIP_BBOX_SIZE;
|
||||
let draw_bbox_alloc = alloc;
|
||||
alloc += n_drawobj * DRAW_BBOX_SIZE;
|
||||
let drawinfo_alloc = alloc;
|
||||
// TODO: not optimized; it can be accumulated during encoding or summed from drawtags
|
||||
const MAX_DRAWINFO_SIZE: usize = 44;
|
||||
alloc += n_drawobj * MAX_DRAWINFO_SIZE;
|
||||
|
||||
let config = Config {
|
||||
n_elements: n_drawobj as u32,
|
||||
n_pathseg: self.n_pathseg,
|
||||
pathseg_alloc: pathseg_alloc as u32,
|
||||
anno_alloc: anno_alloc as u32,
|
||||
trans_alloc: trans_alloc as u32,
|
||||
path_bbox_alloc: path_bbox_alloc as u32,
|
||||
drawmonoid_alloc: drawmonoid_alloc as u32,
|
||||
clip_alloc: clip_alloc as u32,
|
||||
clip_bic_alloc: clip_bic_alloc as u32,
|
||||
clip_stack_alloc: clip_stack_alloc as u32,
|
||||
clip_bbox_alloc: clip_bbox_alloc as u32,
|
||||
draw_bbox_alloc: draw_bbox_alloc as u32,
|
||||
drawinfo_alloc: drawinfo_alloc as u32,
|
||||
n_trans: n_trans as u32,
|
||||
n_path: self.n_path,
|
||||
n_clip: self.n_clip,
|
||||
trans_offset: trans_offset as u32,
|
||||
linewidth_offset: linewidth_offset as u32,
|
||||
pathtag_offset: pathtag_offset as u32,
|
||||
pathseg_offset: pathseg_offset as u32,
|
||||
drawtag_offset: drawtag_offset as u32,
|
||||
drawdata_offset: drawdata_offset as u32,
|
||||
..Default::default()
|
||||
};
|
||||
(config, alloc)
|
||||
}
|
||||
|
||||
pub fn write_scene(&self, buf: &mut BufWrite) {
|
||||
buf.extend_slice(&self.drawtag_stream);
|
||||
let n_drawobj = self.drawtag_stream.len();
|
||||
buf.fill_zero(padding(n_drawobj, DRAW_PART_SIZE as usize) * DRAWTAG_SIZE);
|
||||
buf.extend_slice(&self.drawdata_stream);
|
||||
buf.extend_slice(&self.transform_stream);
|
||||
let n_trans = self.transform_stream.len();
|
||||
buf.fill_zero(padding(n_trans, TRANSFORM_PART_SIZE as usize) * TRANSFORM_SIZE);
|
||||
buf.extend_slice(&self.linewidth_stream);
|
||||
buf.extend_slice(&self.tag_stream);
|
||||
let n_pathtag = self.tag_stream.len();
|
||||
buf.fill_zero(padding(n_pathtag, PATHSEG_PART_SIZE as usize));
|
||||
buf.extend_slice(&self.pathseg_stream);
|
||||
}
|
||||
|
||||
/// The number of draw objects in the draw object stream.
|
||||
pub(crate) fn n_drawobj(&self) -> usize {
|
||||
self.drawtag_stream.len()
|
||||
}
|
||||
|
||||
/// The number of paths.
|
||||
pub(crate) fn n_path(&self) -> u32 {
|
||||
self.n_path
|
||||
}
|
||||
|
||||
/// The number of path segments.
|
||||
pub(crate) fn n_pathseg(&self) -> u32 {
|
||||
self.n_pathseg
|
||||
}
|
||||
|
||||
pub(crate) fn n_transform(&self) -> usize {
|
||||
self.transform_stream.len()
|
||||
}
|
||||
|
||||
/// The number of tags in the path stream.
|
||||
pub(crate) fn n_pathtag(&self) -> usize {
|
||||
self.tag_stream.len()
|
||||
}
|
||||
|
||||
pub(crate) fn n_clip(&self) -> u32 {
|
||||
self.n_clip
|
||||
}
|
||||
}
|
||||
|
||||
/// A scene fragment encoding a glyph.
|
||||
///
|
||||
/// This is a reduced version of the full encoder.
|
||||
|
|
|
@ -8,9 +8,11 @@ pub mod stages;
|
|||
pub mod test_scenes;
|
||||
mod text;
|
||||
|
||||
use bytemuck::Pod;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub use blend::{Blend, BlendMode, CompositionMode};
|
||||
pub use encoder::EncodedSceneRef;
|
||||
pub use render_ctx::PietGpuRenderContext;
|
||||
pub use gradient::Colrv1RadialGradient;
|
||||
|
||||
|
@ -406,6 +408,61 @@ impl Renderer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn upload_scene<T: Copy + Pod>(
|
||||
&mut self,
|
||||
scene: &EncodedSceneRef<T>,
|
||||
buf_ix: usize,
|
||||
) -> Result<(), Error> {
|
||||
let (mut config, mut alloc) = scene.stage_config();
|
||||
let n_drawobj = scene.n_drawobj();
|
||||
// TODO: be more consistent in size types
|
||||
let n_path = scene.n_path() as usize;
|
||||
self.n_paths = n_path;
|
||||
self.n_transform = scene.n_transform();
|
||||
self.n_drawobj = scene.n_drawobj();
|
||||
self.n_pathseg = scene.n_pathseg() as usize;
|
||||
self.n_pathtag = scene.n_pathtag();
|
||||
self.n_clip = scene.n_clip();
|
||||
|
||||
// These constants depend on encoding and may need to be updated.
|
||||
// Perhaps we can plumb these from piet-gpu-derive?
|
||||
const PATH_SIZE: usize = 12;
|
||||
const BIN_SIZE: usize = 8;
|
||||
let width_in_tiles = self.width / TILE_W;
|
||||
let height_in_tiles = self.height / TILE_H;
|
||||
let tile_base = alloc;
|
||||
alloc += ((n_path + 3) & !3) * PATH_SIZE;
|
||||
let bin_base = alloc;
|
||||
alloc += ((n_drawobj + 255) & !255) * BIN_SIZE;
|
||||
let ptcl_base = alloc;
|
||||
alloc += width_in_tiles * height_in_tiles * PTCL_INITIAL_ALLOC;
|
||||
|
||||
config.width_in_tiles = width_in_tiles as u32;
|
||||
config.height_in_tiles = height_in_tiles as u32;
|
||||
config.tile_alloc = tile_base as u32;
|
||||
config.bin_alloc = bin_base as u32;
|
||||
config.ptcl_alloc = ptcl_base as u32;
|
||||
unsafe {
|
||||
// TODO: reallocate scene buffer if size is inadequate
|
||||
{
|
||||
let mut mapped_scene = self.scene_bufs[buf_ix].map_write(..)?;
|
||||
scene.write_scene(&mut mapped_scene);
|
||||
}
|
||||
self.config_bufs[buf_ix].write(&[config])?;
|
||||
self.memory_buf_host[buf_ix].write(&[alloc as u32, 0 /* Overflow flag */])?;
|
||||
|
||||
// Upload gradient data.
|
||||
if !scene.ramp_data.is_empty() {
|
||||
assert!(
|
||||
self.gradient_bufs[buf_ix].size() as usize
|
||||
>= std::mem::size_of_val(&*scene.ramp_data)
|
||||
);
|
||||
self.gradient_bufs[buf_ix].write(scene.ramp_data)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn record(&self, cmd_buf: &mut CmdBuf, query_pool: &QueryPool, buf_ix: usize) {
|
||||
cmd_buf.copy_buffer(&self.config_bufs[buf_ix], &self.config_buf);
|
||||
cmd_buf.copy_buffer(&self.memory_buf_host[buf_ix], &self.memory_buf_dev);
|
||||
|
|
11
piet-scene/Cargo.toml
Normal file
11
piet-scene/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "piet-scene"
|
||||
version = "0.1.0"
|
||||
license = "MIT/Apache-2.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bytemuck = { version = "1.7.2", features = ["derive"] }
|
||||
smallvec = "1.8.0"
|
||||
pinot = "0.1.5"
|
||||
moscato = "0.1.2"
|
41
piet-scene/src/brush/color.rs
Normal file
41
piet-scene/src/brush/color.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
|
||||
pub struct Color {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
pub a: u8,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub const fn rgb8(r: u8, g: u8, b: u8) -> Self {
|
||||
Self { r, g, b, a: 255 }
|
||||
}
|
||||
|
||||
pub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Self { r, g, b, a }
|
||||
}
|
||||
|
||||
pub fn to_premul_u32(self) -> u32 {
|
||||
let a = self.a as f64 * (1.0 / 255.0);
|
||||
let r = (self.r as f64 * a).round() as u32;
|
||||
let g = (self.g as f64 * a).round() as u32;
|
||||
let b = (self.b as f64 * a).round() as u32;
|
||||
(r << 24) | (g << 16) | (b << 8) | self.a as u32
|
||||
}
|
||||
}
|
78
piet-scene/src/brush/gradient.rs
Normal file
78
piet-scene/src/brush/gradient.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use super::color::Color;
|
||||
use crate::geometry::Point;
|
||||
use smallvec::SmallVec;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
#[derive(Copy, Clone, PartialOrd, Default, Debug)]
|
||||
pub struct Stop {
|
||||
pub offset: f32,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
impl Hash for Stop {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.offset.to_bits().hash(state);
|
||||
self.color.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
// Override PartialEq to use to_bits for the offset to match with the Hash impl
|
||||
impl std::cmp::PartialEq for Stop {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.offset.to_bits() == other.offset.to_bits() && self.color == other.color
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::Eq for Stop {}
|
||||
|
||||
pub type StopVec = SmallVec<[Stop; 4]>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Extend {
|
||||
Pad,
|
||||
Repeat,
|
||||
Reflect,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LinearGradient {
|
||||
pub start: Point,
|
||||
pub end: Point,
|
||||
pub stops: StopVec,
|
||||
pub extend: Extend,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RadialGradient {
|
||||
pub center0: Point,
|
||||
pub radius0: f32,
|
||||
pub center1: Point,
|
||||
pub radius1: f32,
|
||||
pub stops: StopVec,
|
||||
pub extend: Extend,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SweepGradient {
|
||||
pub center: Point,
|
||||
pub start_angle: f32,
|
||||
pub end_angle: f32,
|
||||
pub stops: StopVec,
|
||||
pub extend: Extend,
|
||||
}
|
96
piet-scene/src/brush/image.rs
Normal file
96
piet-scene/src/brush/image.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use std::result::Result;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Format {
|
||||
A8,
|
||||
Rgba8,
|
||||
}
|
||||
|
||||
impl Format {
|
||||
pub fn data_size(self, width: u32, height: u32) -> Option<usize> {
|
||||
(width as usize)
|
||||
.checked_mul(height as usize)
|
||||
.and_then(|size| {
|
||||
size.checked_mul(match self {
|
||||
Self::A8 => 1,
|
||||
Self::Rgba8 => 4,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Image(Arc<Inner>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Inner {
|
||||
id: u64,
|
||||
format: Format,
|
||||
width: u32,
|
||||
height: u32,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub fn new(
|
||||
format: Format,
|
||||
width: u32,
|
||||
height: u32,
|
||||
mut data: Vec<u8>,
|
||||
) -> Result<Self, DataSizeError> {
|
||||
let data_size = format.data_size(width, height).ok_or(DataSizeError)?;
|
||||
if data.len() < data_size {
|
||||
return Err(DataSizeError);
|
||||
}
|
||||
data.truncate(data_size);
|
||||
static ID: AtomicU64 = AtomicU64::new(1);
|
||||
Ok(Self(Arc::new(Inner {
|
||||
id: ID.fetch_add(1, Ordering::Relaxed),
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u64 {
|
||||
self.0.id
|
||||
}
|
||||
|
||||
pub fn format(&self) -> Format {
|
||||
self.0.format
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.0.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.0.height
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.0.data
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DataSizeError;
|
35
piet-scene/src/brush/mod.rs
Normal file
35
piet-scene/src/brush/mod.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
mod color;
|
||||
mod gradient;
|
||||
mod image;
|
||||
|
||||
pub use color::Color;
|
||||
pub use gradient::*;
|
||||
pub use image::*;
|
||||
|
||||
use crate::resource::PersistentBrush;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Brush {
|
||||
Solid(Color),
|
||||
LinearGradient(LinearGradient),
|
||||
RadialGradient(RadialGradient),
|
||||
SweepGradient(SweepGradient),
|
||||
Image(Image),
|
||||
Persistent(PersistentBrush),
|
||||
}
|
227
piet-scene/src/geometry.rs
Normal file
227
piet-scene/src/geometry.rs
Normal file
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
// This module is based in part on kurbo (https://github.com/linebender/kurbo)
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use core::borrow::Borrow;
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
/// Two dimensional point.
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Default, Debug, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct Point {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl Hash for Point {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.x.to_bits().hash(state);
|
||||
self.y.to_bits().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub const fn new(x: f32, y: f32) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
|
||||
pub fn transform(&self, affine: &Affine) -> Self {
|
||||
Self {
|
||||
x: self.x * affine.xx + self.y * affine.yx + affine.dx,
|
||||
y: self.y * affine.yy + self.y * affine.xy + affine.dy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 2]> for Point {
|
||||
fn from(value: [f32; 2]) -> Self {
|
||||
Self::new(value[0], value[1])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(f32, f32)> for Point {
|
||||
fn from(value: (f32, f32)) -> Self {
|
||||
Self::new(value.0, value.1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Affine transformation matrix.
|
||||
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct Affine {
|
||||
pub xx: f32,
|
||||
pub yx: f32,
|
||||
pub xy: f32,
|
||||
pub yy: f32,
|
||||
pub dx: f32,
|
||||
pub dy: f32,
|
||||
}
|
||||
|
||||
impl Affine {
|
||||
pub const IDENTITY: Self = Self {
|
||||
xx: 1.0,
|
||||
yx: 0.0,
|
||||
xy: 0.0,
|
||||
yy: 1.0,
|
||||
dx: 0.0,
|
||||
dy: 0.0,
|
||||
};
|
||||
|
||||
pub const fn new(elements: &[f32; 6]) -> Self {
|
||||
Self {
|
||||
xx: elements[0],
|
||||
yx: elements[1],
|
||||
xy: elements[2],
|
||||
yy: elements[3],
|
||||
dx: elements[4],
|
||||
dy: elements[5],
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new affine transform representing the specified scale along the
|
||||
/// x and y axes.
|
||||
pub fn scale(x: f32, y: f32) -> Self {
|
||||
Self::new(&[x, 0., 0., y, 0., 0.])
|
||||
}
|
||||
|
||||
/// Creates a new affine transform representing the specified translation.
|
||||
pub fn translate(x: f32, y: f32) -> Self {
|
||||
Self::new(&[1., 0., 0., 1., x, y])
|
||||
}
|
||||
|
||||
/// Creates a new affine transform representing a counter-clockwise
|
||||
/// rotation for the specified angle in radians.
|
||||
pub fn rotate(th: f32) -> Self {
|
||||
let (s, c) = th.sin_cos();
|
||||
Self::new(&[c, s, -s, c, 0., 0.])
|
||||
}
|
||||
|
||||
/// Creates a new skew transform
|
||||
pub fn skew(x: f32, y: f32) -> Self {
|
||||
Self::new(&[1., x.tan(), y.tan(), 1., 0., 0.])
|
||||
}
|
||||
|
||||
pub fn around_center(&self, x: f32, y: f32) -> Self {
|
||||
Self::translate(x, y) * *self * Self::translate(-x, -y)
|
||||
}
|
||||
|
||||
/// Transforms the specified point.
|
||||
pub fn transform_point(&self, point: Point) -> Point {
|
||||
Point {
|
||||
x: point.x * self.xx + point.y * self.yx + self.dx,
|
||||
y: point.y * self.yy + point.y * self.xy + self.dy,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the determinant of this transform.
|
||||
pub fn determinant(self) -> f32 {
|
||||
self.xx * self.yy - self.yx * self.xy
|
||||
}
|
||||
|
||||
/// Compute the inverse transform.
|
||||
///
|
||||
/// Produces NaN values when the determinant is zero.
|
||||
pub fn inverse(self) -> Self {
|
||||
let inv_det = self.determinant().recip();
|
||||
Self::new(&[
|
||||
inv_det * self.yy,
|
||||
-inv_det * self.yx,
|
||||
-inv_det * self.xy,
|
||||
inv_det * self.xx,
|
||||
inv_det * (self.xy * self.dy - self.yy * self.dx),
|
||||
inv_det * (self.yx * self.dx - self.xx * self.dy),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Affine {
|
||||
fn default() -> Self {
|
||||
Self::IDENTITY
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Mul for Affine {
|
||||
type Output = Self;
|
||||
fn mul(self, other: Self) -> Self {
|
||||
Self::new(&[
|
||||
self.xx * other.xx + self.xy * other.yx,
|
||||
self.yx * other.xx + self.yy * other.yx,
|
||||
self.xx * other.xy + self.xy * other.yy,
|
||||
self.yx * other.xy + self.yy * other.yy,
|
||||
self.xx * other.dx + self.xy * other.dy + self.dx,
|
||||
self.yx * other.dx + self.yy * other.dy + self.dy,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
/// Axis-aligned rectangle represented as minimum and maximum points.
|
||||
#[derive(Copy, Clone, Default, Debug, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct Rect {
|
||||
pub min: Point,
|
||||
pub max: Point,
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
/// Creates a new rectangle that encloses the specified collection of
|
||||
/// points.
|
||||
pub fn from_points<I>(points: I) -> Self
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Borrow<Point>,
|
||||
{
|
||||
let mut rect = Self {
|
||||
min: Point::new(f32::MAX, f32::MAX),
|
||||
max: Point::new(f32::MIN, f32::MIN),
|
||||
};
|
||||
let mut count = 0;
|
||||
for point in points {
|
||||
rect.add(*point.borrow());
|
||||
count += 1;
|
||||
}
|
||||
if count != 0 {
|
||||
rect
|
||||
} else {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the width of the rectangle.
|
||||
pub fn width(&self) -> f32 {
|
||||
self.max.x - self.min.x
|
||||
}
|
||||
|
||||
/// Returns the height of the rectangle.
|
||||
pub fn height(&self) -> f32 {
|
||||
self.max.y - self.min.y
|
||||
}
|
||||
|
||||
/// Extends the rectangle to include the specified point.
|
||||
pub fn add(&mut self, point: Point) {
|
||||
self.min.x = self.min.x.min(point.x);
|
||||
self.min.y = self.min.y.min(point.y);
|
||||
self.max.x = self.max.x.max(point.x);
|
||||
self.max.y = self.max.y.max(point.y);
|
||||
}
|
||||
|
||||
/// Returns a new rectangle that encloses the minimum and maximum points
|
||||
/// of this rectangle after applying the specified transform to each.
|
||||
pub fn transform(&self, affine: &Affine) -> Self {
|
||||
Self::from_points([self.min.transform(affine), self.max.transform(affine)])
|
||||
}
|
||||
}
|
322
piet-scene/src/glyph/mod.rs
Normal file
322
piet-scene/src/glyph/mod.rs
Normal file
|
@ -0,0 +1,322 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
pub use pinot;
|
||||
|
||||
use crate::brush::{Brush, Color};
|
||||
use crate::geometry::Affine;
|
||||
use crate::path::Element;
|
||||
use crate::scene::{build_fragment, Fill, Fragment};
|
||||
|
||||
use moscato::{Context, Scaler};
|
||||
use pinot::{types::Tag, FontRef};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// General context for creating scene fragments for glyph outlines.
|
||||
pub struct GlyphContext {
|
||||
ctx: Context,
|
||||
}
|
||||
|
||||
impl GlyphContext {
|
||||
/// Creates a new context.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ctx: Context::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new provider for generating scene fragments for glyphs from
|
||||
/// the specified font and settings.
|
||||
pub fn new_provider<'a, V>(
|
||||
&'a mut self,
|
||||
font: &FontRef<'a>,
|
||||
font_id: Option<u64>,
|
||||
ppem: f32,
|
||||
hint: bool,
|
||||
variations: V,
|
||||
) -> GlyphProvider<'a>
|
||||
where
|
||||
V: IntoIterator,
|
||||
V::Item: Into<(Tag, f32)>,
|
||||
{
|
||||
let scaler = if let Some(font_id) = font_id {
|
||||
self.ctx
|
||||
.new_scaler_with_id(font, font_id)
|
||||
.size(ppem)
|
||||
.hint(hint)
|
||||
.variations(variations)
|
||||
.build()
|
||||
} else {
|
||||
self.ctx
|
||||
.new_scaler(font)
|
||||
.size(ppem)
|
||||
.hint(hint)
|
||||
.variations(variations)
|
||||
.build()
|
||||
};
|
||||
GlyphProvider { scaler }
|
||||
}
|
||||
}
|
||||
|
||||
/// Generator for scene fragments containing glyph outlines for a specific
|
||||
/// font.
|
||||
pub struct GlyphProvider<'a> {
|
||||
scaler: Scaler<'a>,
|
||||
}
|
||||
|
||||
impl<'a> GlyphProvider<'a> {
|
||||
/// Returns a scene fragment containing the commands to render the
|
||||
/// specified glyph.
|
||||
pub fn get(&mut self, gid: u16) -> Option<Fragment> {
|
||||
let glyph = self.scaler.glyph(gid)?;
|
||||
let path = glyph.path(0)?;
|
||||
let mut fragment = Fragment::default();
|
||||
let mut builder = build_fragment(&mut fragment);
|
||||
builder.fill(
|
||||
Fill::NonZero,
|
||||
&Brush::Solid(Color::rgb8(255, 255, 255)),
|
||||
None,
|
||||
convert_path(path.elements()),
|
||||
);
|
||||
Some(fragment)
|
||||
}
|
||||
|
||||
/// Returns a scene fragment containing the commands and resources to
|
||||
/// render the specified color glyph.
|
||||
pub fn get_color(&mut self, palette_index: u16, gid: u16) -> Option<Fragment> {
|
||||
use crate::geometry::*;
|
||||
use moscato::Command;
|
||||
let glyph = self.scaler.color_glyph(palette_index, gid)?;
|
||||
let mut fragment = Fragment::default();
|
||||
let mut builder = build_fragment(&mut fragment);
|
||||
let mut xform_stack: SmallVec<[Affine; 8]> = SmallVec::new();
|
||||
for command in glyph.commands() {
|
||||
match command {
|
||||
Command::PushTransform(xform) => {
|
||||
let xform = if let Some(parent) = xform_stack.last() {
|
||||
convert_transform(xform) * *parent
|
||||
} else {
|
||||
convert_transform(xform)
|
||||
};
|
||||
xform_stack.push(xform);
|
||||
}
|
||||
Command::PopTransform => { xform_stack.pop(); },
|
||||
Command::PushClip(path_index) => {
|
||||
let path = glyph.path(*path_index)?;
|
||||
if let Some(xform) = xform_stack.last() {
|
||||
builder.push_layer(
|
||||
Default::default(),
|
||||
convert_transformed_path(path.elements(), xform),
|
||||
);
|
||||
} else {
|
||||
builder.push_layer(Default::default(), convert_path(path.elements()));
|
||||
}
|
||||
}
|
||||
Command::PopClip => builder.pop_layer(),
|
||||
Command::PushLayer(bounds) => {
|
||||
let mut rect = Rect {
|
||||
min: Point::new(bounds.min.x, bounds.min.y),
|
||||
max: Point::new(bounds.max.x, bounds.max.y),
|
||||
};
|
||||
if let Some(xform) = xform_stack.last() {
|
||||
rect = rect.transform(xform);
|
||||
}
|
||||
builder.push_layer(Default::default(), rect.elements());
|
||||
}
|
||||
Command::PopLayer => builder.pop_layer(),
|
||||
Command::BeginBlend(bounds, mode) => {
|
||||
let mut rect = Rect {
|
||||
min: Point::new(bounds.min.x, bounds.min.y),
|
||||
max: Point::new(bounds.max.x, bounds.max.y),
|
||||
};
|
||||
if let Some(xform) = xform_stack.last() {
|
||||
rect = rect.transform(xform);
|
||||
}
|
||||
builder.push_layer(convert_blend(*mode), rect.elements())
|
||||
}
|
||||
Command::EndBlend => builder.pop_layer(),
|
||||
Command::SimpleFill(path_index, brush, brush_xform) => {
|
||||
let path = glyph.path(*path_index)?;
|
||||
let brush = convert_brush(brush);
|
||||
let brush_xform = brush_xform.map(|xform| convert_transform(&xform));
|
||||
if let Some(xform) = xform_stack.last() {
|
||||
builder.fill(
|
||||
Fill::NonZero,
|
||||
&brush,
|
||||
brush_xform.map(|x| x * *xform),
|
||||
convert_transformed_path(path.elements(), xform),
|
||||
);
|
||||
} else {
|
||||
builder.fill(
|
||||
Fill::NonZero,
|
||||
&brush,
|
||||
brush_xform,
|
||||
convert_path(path.elements()),
|
||||
);
|
||||
}
|
||||
}
|
||||
Command::Fill(brush, brush_xform) => {
|
||||
// TODO: this needs to compute a bounding box for
|
||||
// the parent clips
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(fragment)
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_path(
|
||||
path: impl Iterator<Item = moscato::Element> + Clone,
|
||||
) -> impl Iterator<Item = Element> + Clone {
|
||||
use crate::geometry::Point;
|
||||
path.map(|el| match el {
|
||||
moscato::Element::MoveTo(p0) => Element::MoveTo(Point::new(p0.x, p0.y)),
|
||||
moscato::Element::LineTo(p0) => Element::LineTo(Point::new(p0.x, p0.y)),
|
||||
moscato::Element::QuadTo(p0, p1) => {
|
||||
Element::QuadTo(Point::new(p0.x, p0.y), Point::new(p1.x, p1.y))
|
||||
}
|
||||
moscato::Element::CurveTo(p0, p1, p2) => Element::CurveTo(
|
||||
Point::new(p0.x, p0.y),
|
||||
Point::new(p1.x, p1.y),
|
||||
Point::new(p2.x, p2.y),
|
||||
),
|
||||
moscato::Element::Close => Element::Close,
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_transformed_path(
|
||||
path: impl Iterator<Item = moscato::Element> + Clone,
|
||||
xform: &Affine,
|
||||
) -> impl Iterator<Item = Element> + Clone {
|
||||
use crate::geometry::Point;
|
||||
let xform = *xform;
|
||||
path.map(move |el| match el {
|
||||
moscato::Element::MoveTo(p0) => Element::MoveTo(Point::new(p0.x, p0.y).transform(&xform)),
|
||||
moscato::Element::LineTo(p0) => Element::LineTo(Point::new(p0.x, p0.y).transform(&xform)),
|
||||
moscato::Element::QuadTo(p0, p1) => Element::QuadTo(
|
||||
Point::new(p0.x, p0.y).transform(&xform),
|
||||
Point::new(p1.x, p1.y).transform(&xform),
|
||||
),
|
||||
moscato::Element::CurveTo(p0, p1, p2) => Element::CurveTo(
|
||||
Point::new(p0.x, p0.y).transform(&xform),
|
||||
Point::new(p1.x, p1.y).transform(&xform),
|
||||
Point::new(p2.x, p2.y).transform(&xform),
|
||||
),
|
||||
moscato::Element::Close => Element::Close,
|
||||
})
|
||||
}
|
||||
|
||||
fn convert_blend(mode: moscato::CompositeMode) -> crate::scene::Blend {
|
||||
use crate::scene::{Blend, Compose, Mix};
|
||||
use moscato::CompositeMode;
|
||||
let mut mix = Mix::Normal;
|
||||
let mut compose = Compose::SrcOver;
|
||||
match mode {
|
||||
CompositeMode::Clear => compose = Compose::Clear,
|
||||
CompositeMode::Src => compose = Compose::Copy,
|
||||
CompositeMode::Dest => compose = Compose::Dest,
|
||||
CompositeMode::SrcOver => {}
|
||||
CompositeMode::DestOver => compose = Compose::DestOver,
|
||||
CompositeMode::SrcIn => compose = Compose::SrcIn,
|
||||
CompositeMode::DestIn => compose = Compose::DestIn,
|
||||
CompositeMode::SrcOut => compose = Compose::SrcOut,
|
||||
CompositeMode::DestOut => compose = Compose::DestOut,
|
||||
CompositeMode::SrcAtop => compose = Compose::SrcAtop,
|
||||
CompositeMode::DestAtop => compose = Compose::DestAtop,
|
||||
CompositeMode::Xor => compose = Compose::Xor,
|
||||
CompositeMode::Plus => compose = Compose::Plus,
|
||||
CompositeMode::Screen => mix = Mix::Screen,
|
||||
CompositeMode::Overlay => mix = Mix::Overlay,
|
||||
CompositeMode::Darken => mix = Mix::Darken,
|
||||
CompositeMode::Lighten => mix = Mix::Lighten,
|
||||
CompositeMode::ColorDodge => mix = Mix::ColorDodge,
|
||||
CompositeMode::ColorBurn => mix = Mix::ColorBurn,
|
||||
CompositeMode::HardLight => mix = Mix::HardLight,
|
||||
CompositeMode::SoftLight => mix = Mix::SoftLight,
|
||||
CompositeMode::Difference => mix = Mix::Difference,
|
||||
CompositeMode::Exclusion => mix = Mix::Exclusion,
|
||||
CompositeMode::Multiply => mix = Mix::Multiply,
|
||||
CompositeMode::HslHue => mix = Mix::Hue,
|
||||
CompositeMode::HslSaturation => mix = Mix::Saturation,
|
||||
CompositeMode::HslColor => mix = Mix::Color,
|
||||
CompositeMode::HslLuminosity => mix = Mix::Luminosity,
|
||||
}
|
||||
Blend { mix, compose }
|
||||
}
|
||||
|
||||
fn convert_transform(xform: &moscato::Transform) -> crate::geometry::Affine {
|
||||
crate::geometry::Affine {
|
||||
xx: xform.xx,
|
||||
yx: xform.yx,
|
||||
xy: xform.xy,
|
||||
yy: xform.yy,
|
||||
dx: xform.dx,
|
||||
dy: xform.dy,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_brush(brush: &moscato::Brush) -> crate::brush::Brush {
|
||||
use crate::brush::*;
|
||||
use crate::geometry::*;
|
||||
match brush {
|
||||
moscato::Brush::Solid(color) => Brush::Solid(Color {
|
||||
r: color.r,
|
||||
g: color.g,
|
||||
b: color.b,
|
||||
a: color.a,
|
||||
}),
|
||||
moscato::Brush::LinearGradient(grad) => Brush::LinearGradient(LinearGradient {
|
||||
start: Point::new(grad.start.x, grad.start.y),
|
||||
end: Point::new(grad.end.x, grad.end.y),
|
||||
stops: convert_stops(&grad.stops),
|
||||
extend: convert_extend(grad.extend),
|
||||
}),
|
||||
moscato::Brush::RadialGradient(grad) => Brush::RadialGradient(RadialGradient {
|
||||
center0: Point::new(grad.center0.x, grad.center0.y),
|
||||
center1: Point::new(grad.center1.x, grad.center1.y),
|
||||
radius0: grad.radius0,
|
||||
radius1: grad.radius1,
|
||||
stops: convert_stops(&grad.stops),
|
||||
extend: convert_extend(grad.extend),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_stops(stops: &[moscato::ColorStop]) -> crate::brush::StopVec {
|
||||
use crate::brush::Stop;
|
||||
stops
|
||||
.iter()
|
||||
.map(|stop| Stop {
|
||||
offset: stop.offset,
|
||||
color: Color {
|
||||
r: stop.color.r,
|
||||
g: stop.color.g,
|
||||
b: stop.color.b,
|
||||
a: stop.color.a,
|
||||
},
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn convert_extend(extend: moscato::ExtendMode) -> crate::brush::Extend {
|
||||
use crate::brush::Extend::*;
|
||||
match extend {
|
||||
moscato::ExtendMode::Pad => Pad,
|
||||
moscato::ExtendMode::Repeat => Repeat,
|
||||
moscato::ExtendMode::Reflect => Reflect,
|
||||
}
|
||||
}
|
22
piet-scene/src/lib.rs
Normal file
22
piet-scene/src/lib.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
pub mod brush;
|
||||
pub mod geometry;
|
||||
pub mod glyph;
|
||||
pub mod path;
|
||||
pub mod resource;
|
||||
pub mod scene;
|
63
piet-scene/src/path.rs
Normal file
63
piet-scene/src/path.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use super::geometry::{Point, Rect};
|
||||
|
||||
/// Action of a path element.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Verb {
|
||||
MoveTo,
|
||||
LineTo,
|
||||
QuadTo,
|
||||
CurveTo,
|
||||
Close,
|
||||
}
|
||||
|
||||
/// Element of a path represented by a verb and its associated points.
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Element {
|
||||
MoveTo(Point),
|
||||
LineTo(Point),
|
||||
QuadTo(Point, Point),
|
||||
CurveTo(Point, Point, Point),
|
||||
Close,
|
||||
}
|
||||
|
||||
impl Element {
|
||||
/// Returns the verb that describes the action of the path element.
|
||||
pub fn verb(&self) -> Verb {
|
||||
match self {
|
||||
Self::MoveTo(..) => Verb::MoveTo,
|
||||
Self::LineTo(..) => Verb::LineTo,
|
||||
Self::QuadTo(..) => Verb::QuadTo,
|
||||
Self::CurveTo(..) => Verb::CurveTo,
|
||||
Self::Close => Verb::Close,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn elements(&self) -> impl Iterator<Item = Element> + Clone {
|
||||
let elements = [
|
||||
Element::MoveTo((self.min.x, self.min.y).into()),
|
||||
Element::LineTo((self.max.x, self.min.y).into()),
|
||||
Element::LineTo((self.max.x, self.max.y).into()),
|
||||
Element::LineTo((self.min.x, self.max.y).into()),
|
||||
Element::Close,
|
||||
];
|
||||
(0..5).map(move |i| elements[i])
|
||||
}
|
||||
}
|
138
piet-scene/src/resource/gradient.rs
Normal file
138
piet-scene/src/resource/gradient.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
use crate::brush::{Color, Stop, StopVec};
|
||||
use std::collections::HashMap;
|
||||
|
||||
const N_SAMPLES: usize = 512;
|
||||
const RETAINED_COUNT: usize = 64;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RampCache {
|
||||
epoch: u64,
|
||||
map: HashMap<StopVec, (u32, u64)>,
|
||||
data: Vec<u32>,
|
||||
}
|
||||
|
||||
impl RampCache {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn advance(&mut self) {
|
||||
self.epoch += 1;
|
||||
if self.map.len() > RETAINED_COUNT {
|
||||
self.map
|
||||
.retain(|_key, value| value.0 < RETAINED_COUNT as u32);
|
||||
self.data.truncate(RETAINED_COUNT * N_SAMPLES);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.epoch = 0;
|
||||
self.map.clear();
|
||||
self.data.clear();
|
||||
}
|
||||
|
||||
pub fn add(&mut self, stops: &[Stop]) -> u32 {
|
||||
if let Some(entry) = self.map.get_mut(stops) {
|
||||
entry.1 = self.epoch;
|
||||
entry.0
|
||||
} else if self.map.len() < RETAINED_COUNT {
|
||||
let id = (self.data.len() / N_SAMPLES) as u32;
|
||||
self.data.extend(make_ramp(stops));
|
||||
self.map.insert(stops.into(), (id, self.epoch));
|
||||
id
|
||||
} else {
|
||||
let mut reuse = None;
|
||||
for (stops, (id, epoch)) in &self.map {
|
||||
if *epoch + 2 < self.epoch {
|
||||
reuse = Some((stops.to_owned(), *id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some((old_stops, id)) = reuse {
|
||||
self.map.remove(&old_stops);
|
||||
let start = id as usize * N_SAMPLES;
|
||||
for (dst, src) in self.data[start..start + N_SAMPLES]
|
||||
.iter_mut()
|
||||
.zip(make_ramp(stops))
|
||||
{
|
||||
*dst = src;
|
||||
}
|
||||
self.map.insert(stops.into(), (id, self.epoch));
|
||||
id
|
||||
} else {
|
||||
let id = (self.data.len() / N_SAMPLES) as u32;
|
||||
self.data.extend(make_ramp(stops));
|
||||
self.map.insert(stops.into(), (id, self.epoch));
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u32] {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
fn make_ramp<'a>(stops: &'a [Stop]) -> impl Iterator<Item = u32> + 'a {
|
||||
let mut last_u = 0.0;
|
||||
let mut last_c = ColorF64::from_color(stops[0].color);
|
||||
let mut this_u = last_u;
|
||||
let mut this_c = last_c;
|
||||
let mut j = 0;
|
||||
(0..N_SAMPLES).map(move |i| {
|
||||
let u = (i as f64) / (N_SAMPLES - 1) as f64;
|
||||
while u > this_u {
|
||||
last_u = this_u;
|
||||
last_c = this_c;
|
||||
if let Some(s) = stops.get(j + 1) {
|
||||
this_u = s.offset as f64;
|
||||
this_c = ColorF64::from_color(s.color);
|
||||
j += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let du = this_u - last_u;
|
||||
let c = if du < 1e-9 {
|
||||
this_c
|
||||
} else {
|
||||
last_c.lerp(&this_c, (u - last_u) / du)
|
||||
};
|
||||
c.to_premul_u32()
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct ColorF64([f64; 4]);
|
||||
|
||||
impl ColorF64 {
|
||||
fn from_color(color: Color) -> Self {
|
||||
Self([
|
||||
color.r as f64 / 255.0,
|
||||
color.g as f64 / 255.0,
|
||||
color.b as f64 / 255.0,
|
||||
color.a as f64 / 255.0,
|
||||
])
|
||||
}
|
||||
|
||||
fn lerp(&self, other: &Self, a: f64) -> Self {
|
||||
fn l(x: f64, y: f64, a: f64) -> f64 {
|
||||
x * (1.0 - a) + y * a
|
||||
}
|
||||
Self([
|
||||
l(self.0[0], other.0[0], a),
|
||||
l(self.0[1], other.0[1], a),
|
||||
l(self.0[2], other.0[2], a),
|
||||
l(self.0[3], other.0[3], a),
|
||||
])
|
||||
}
|
||||
|
||||
fn to_premul_u32(&self) -> u32 {
|
||||
let a = self.0[3].min(1.0).max(0.0);
|
||||
let r = ((self.0[0] * a).min(1.0).max(0.0) * 255.0) as u32;
|
||||
let g = ((self.0[1] * a).min(1.0).max(0.0) * 255.0) as u32;
|
||||
let b = ((self.0[2] * a).min(1.0).max(0.0) * 255.0) as u32;
|
||||
let a = (a * 255.0) as u32;
|
||||
b | (g << 8) | (r << 16) | (a << 24)
|
||||
}
|
||||
}
|
56
piet-scene/src/resource/mod.rs
Normal file
56
piet-scene/src/resource/mod.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
mod gradient;
|
||||
|
||||
use crate::brush::{Brush, Stop};
|
||||
use gradient::RampCache;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Context for caching resources across rendering operations.
|
||||
#[derive(Default)]
|
||||
pub struct ResourceContext {
|
||||
ramps: RampCache,
|
||||
persistent_map: HashMap<u64, PersistentBrushData>,
|
||||
}
|
||||
|
||||
impl ResourceContext {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn advance(&mut self) {
|
||||
self.ramps.advance();
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.ramps.clear();
|
||||
self.persistent_map.clear();
|
||||
}
|
||||
|
||||
pub fn add_ramp(&mut self, stops: &[Stop]) -> u32 {
|
||||
self.ramps.add(stops)
|
||||
}
|
||||
|
||||
pub fn create_brush(&mut self, brush: &Brush) -> PersistentBrush {
|
||||
match brush {
|
||||
Brush::Persistent(dup) => return *dup,
|
||||
_ => {}
|
||||
}
|
||||
PersistentBrush { kind: 0, id: 0 }
|
||||
}
|
||||
|
||||
pub fn destroy_brush(&mut self, brush: PersistentBrush) {}
|
||||
|
||||
pub fn ramp_data(&self) -> &[u32] {
|
||||
&self.ramps.data()
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle for a brush that is managed by the resource context.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct PersistentBrush {
|
||||
kind: u8,
|
||||
id: u64,
|
||||
}
|
||||
|
||||
struct PersistentBrushData {
|
||||
brush: Brush,
|
||||
}
|
102
piet-scene/src/scene/blend.rs
Normal file
102
piet-scene/src/scene/blend.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
/// Defines the color mixing function for a blend operation.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[repr(C)]
|
||||
pub enum Mix {
|
||||
Normal = 0,
|
||||
Multiply = 1,
|
||||
Screen = 2,
|
||||
Overlay = 3,
|
||||
Darken = 4,
|
||||
Lighten = 5,
|
||||
ColorDodge = 6,
|
||||
ColorBurn = 7,
|
||||
HardLight = 8,
|
||||
SoftLight = 9,
|
||||
Difference = 10,
|
||||
Exclusion = 11,
|
||||
Hue = 12,
|
||||
Saturation = 13,
|
||||
Color = 14,
|
||||
Luminosity = 15,
|
||||
}
|
||||
|
||||
/// Defines the layer composition function for a blend operation.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[repr(C)]
|
||||
pub enum Compose {
|
||||
Clear = 0,
|
||||
Copy = 1,
|
||||
Dest = 2,
|
||||
SrcOver = 3,
|
||||
DestOver = 4,
|
||||
SrcIn = 5,
|
||||
DestIn = 6,
|
||||
SrcOut = 7,
|
||||
DestOut = 8,
|
||||
SrcAtop = 9,
|
||||
DestAtop = 10,
|
||||
Xor = 11,
|
||||
Plus = 12,
|
||||
PlusDarker = 13,
|
||||
PlusLighter = 14,
|
||||
}
|
||||
|
||||
/// Blend mode consisting of mixing and composition functions.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Blend {
|
||||
pub mix: Mix,
|
||||
pub compose: Compose,
|
||||
}
|
||||
|
||||
impl Blend {
|
||||
pub fn new(mix: Mix, compose: Compose) -> Self {
|
||||
Self { mix, compose }
|
||||
}
|
||||
|
||||
pub fn pack(&self) -> u32 {
|
||||
(self.mix as u32) << 8 | self.compose as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Blend {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mix: Mix::Normal,
|
||||
compose: Compose::SrcOver,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Mix> for Blend {
|
||||
fn from(mix: Mix) -> Self {
|
||||
Self {
|
||||
mix,
|
||||
compose: Compose::SrcOver,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Compose> for Blend {
|
||||
fn from(compose: Compose) -> Self {
|
||||
Self {
|
||||
mix: Mix::Normal,
|
||||
compose,
|
||||
}
|
||||
}
|
||||
}
|
554
piet-scene/src/scene/builder.rs
Normal file
554
piet-scene/src/scene/builder.rs
Normal file
|
@ -0,0 +1,554 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use super::style::{Fill, Stroke};
|
||||
use super::{Affine, Blend, Element, Fragment, FragmentResources, ResourcePatch, Scene, SceneData};
|
||||
use crate::brush::*;
|
||||
use crate::resource::ResourceContext;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use core::borrow::Borrow;
|
||||
|
||||
const MAX_BLEND_STACK: usize = 256;
|
||||
|
||||
/// Creates a new builder for constructing a scene.
|
||||
pub fn build_scene<'a>(scene: &'a mut Scene, resources: &'a mut ResourceContext) -> Builder<'a> {
|
||||
Builder::new(&mut scene.data, ResourceData::Scene(resources))
|
||||
}
|
||||
|
||||
/// Creates a new builder for construction a scene fragment.
|
||||
pub fn build_fragment<'a>(fragment: &'a mut Fragment) -> Builder<'a> {
|
||||
Builder::new(
|
||||
&mut fragment.data,
|
||||
ResourceData::Fragment(&mut fragment.resources),
|
||||
)
|
||||
}
|
||||
|
||||
/// Builder for constructing a scene or scene fragment.
|
||||
pub struct Builder<'a> {
|
||||
scene: &'a mut SceneData,
|
||||
resources: ResourceData<'a>,
|
||||
layers: Vec<Blend>,
|
||||
transforms: Vec<Affine>,
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
/// Creates a new builder for constructing a scene.
|
||||
fn new(scene: &'a mut SceneData, mut resources: ResourceData<'a>) -> Self {
|
||||
let is_fragment = match resources {
|
||||
ResourceData::Fragment(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
scene.reset(is_fragment);
|
||||
resources.clear();
|
||||
Self {
|
||||
scene,
|
||||
resources,
|
||||
layers: vec![],
|
||||
transforms: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a transform matrix onto the stack.
|
||||
pub fn push_transform(&mut self, transform: Affine) {
|
||||
self.transform(transform);
|
||||
self.transforms.push(transform);
|
||||
}
|
||||
|
||||
/// Pops the current transform matrix.
|
||||
pub fn pop_transform(&mut self) {
|
||||
if let Some(transform) = self.transforms.pop() {
|
||||
self.transform(transform.inverse());
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes a new layer bound by the specifed shape and composed with
|
||||
/// previous layers using the specified blend mode.
|
||||
pub fn push_layer<'s, E>(&mut self, blend: Blend, elements: E)
|
||||
where
|
||||
E: IntoIterator,
|
||||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
self.linewidth(-1.0);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, true);
|
||||
self.begin_clip(Some(blend));
|
||||
if self.layers.len() >= MAX_BLEND_STACK {
|
||||
panic!("Maximum clip/blend stack size {} exceeded", MAX_BLEND_STACK);
|
||||
}
|
||||
self.layers.push(blend);
|
||||
}
|
||||
|
||||
/// Pops the current layer.
|
||||
pub fn pop_layer(&mut self) {
|
||||
if let Some(layer) = self.layers.pop() {
|
||||
self.end_clip(Some(layer));
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills a shape using the specified style and brush.
|
||||
pub fn fill<'s, E>(
|
||||
&mut self,
|
||||
style: Fill,
|
||||
brush: &Brush,
|
||||
brush_transform: Option<Affine>,
|
||||
elements: E,
|
||||
) where
|
||||
E: IntoIterator,
|
||||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
self.linewidth(-1.0);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, true);
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
self.transform(brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.transform(brush_transform.inverse());
|
||||
} else {
|
||||
self.encode_brush(brush);
|
||||
}
|
||||
}
|
||||
|
||||
/// Strokes a shape using the specified style and brush.
|
||||
pub fn stroke<'s, D, E>(
|
||||
&mut self,
|
||||
style: &Stroke<D>,
|
||||
brush: &Brush,
|
||||
brush_transform: Option<Affine>,
|
||||
elements: E,
|
||||
) where
|
||||
D: Borrow<[f32]>,
|
||||
E: IntoIterator,
|
||||
E::IntoIter: Clone,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
self.linewidth(style.width);
|
||||
let elements = elements.into_iter();
|
||||
self.encode_path(elements, false);
|
||||
if let Some(brush_transform) = brush_transform {
|
||||
self.transform(brush_transform);
|
||||
self.swap_last_tags();
|
||||
self.encode_brush(brush);
|
||||
self.transform(brush_transform.inverse());
|
||||
} else {
|
||||
self.encode_brush(brush);
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends a fragment to the scene.
|
||||
pub fn append(&mut self, fragment: &Fragment) {
|
||||
let drawdata_base = self.scene.drawdata_stream.len();
|
||||
self.scene.append(&fragment.data);
|
||||
match &mut self.resources {
|
||||
ResourceData::Scene(res) => {
|
||||
for patch in &fragment.resources.patches {
|
||||
match patch {
|
||||
ResourcePatch::Ramp {
|
||||
drawdata_offset,
|
||||
stops,
|
||||
} => {
|
||||
let stops = &fragment.resources.stops[stops.clone()];
|
||||
let ramp_id = res.add_ramp(stops);
|
||||
let patch_base = *drawdata_offset + drawdata_base;
|
||||
(&mut self.scene.drawdata_stream[patch_base..patch_base + 4])
|
||||
.copy_from_slice(bytemuck::bytes_of(&ramp_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ResourceData::Fragment(res) => {
|
||||
let stops_base = res.stops.len();
|
||||
res.stops.extend_from_slice(&fragment.resources.stops);
|
||||
res.patches.extend(fragment.resources.patches.iter().map(
|
||||
|pending| match pending {
|
||||
ResourcePatch::Ramp {
|
||||
drawdata_offset,
|
||||
stops,
|
||||
} => ResourcePatch::Ramp {
|
||||
drawdata_offset: drawdata_offset + drawdata_base,
|
||||
stops: stops.start + stops_base..stops.end + stops_base,
|
||||
},
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Completes construction and finalizes the underlying scene.
|
||||
pub fn finish(mut self) {
|
||||
while let Some(layer) = self.layers.pop() {
|
||||
self.end_clip(Some(layer));
|
||||
}
|
||||
match self.resources {
|
||||
ResourceData::Fragment(_) => {
|
||||
// Make sure the transform state is invariant for fragments
|
||||
while !self.transforms.is_empty() {
|
||||
self.pop_transform();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
fn encode_path<E>(&mut self, elements: E, is_fill: bool)
|
||||
where
|
||||
E: Iterator,
|
||||
E::Item: Borrow<Element>,
|
||||
{
|
||||
if is_fill {
|
||||
self.encode_path_inner(
|
||||
elements
|
||||
.map(|el| *el.borrow())
|
||||
.flat_map(|el| {
|
||||
match el {
|
||||
Element::MoveTo(..) => Some(Element::Close),
|
||||
_ => None,
|
||||
}
|
||||
.into_iter()
|
||||
.chain(Some(el))
|
||||
})
|
||||
.chain(Some(Element::Close)),
|
||||
)
|
||||
} else {
|
||||
self.encode_path_inner(elements.map(|el| *el.borrow()))
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_path_inner(&mut self, elements: impl Iterator<Item = Element>) {
|
||||
let mut b = PathBuilder::new(&mut self.scene.tag_stream, &mut self.scene.pathseg_stream);
|
||||
for el in elements {
|
||||
match el {
|
||||
Element::MoveTo(p0) => b.move_to(p0.x, p0.y),
|
||||
Element::LineTo(p0) => b.line_to(p0.x, p0.y),
|
||||
Element::QuadTo(p0, p1) => b.quad_to(p0.x, p0.y, p1.x, p1.y),
|
||||
Element::CurveTo(p0, p1, p2) => b.cubic_to(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y),
|
||||
Element::Close => b.close_path(),
|
||||
}
|
||||
}
|
||||
b.path();
|
||||
let n_pathseg = b.n_pathseg();
|
||||
self.scene.n_path += 1;
|
||||
self.scene.n_pathseg += n_pathseg;
|
||||
}
|
||||
|
||||
fn transform(&mut self, transform: Affine) {
|
||||
self.scene.tag_stream.push(0x20);
|
||||
self.scene.transform_stream.push(transform);
|
||||
}
|
||||
|
||||
// Swap the last two tags in the tag stream; used for transformed
|
||||
// gradients.
|
||||
fn swap_last_tags(&mut self) {
|
||||
let len = self.scene.tag_stream.len();
|
||||
self.scene.tag_stream.swap(len - 1, len - 2);
|
||||
}
|
||||
|
||||
// -1.0 means "fill"
|
||||
fn linewidth(&mut self, linewidth: f32) {
|
||||
self.scene.tag_stream.push(0x40);
|
||||
self.scene.linewidth_stream.push(linewidth);
|
||||
}
|
||||
|
||||
fn encode_brush(&mut self, brush: &Brush) {
|
||||
match brush {
|
||||
Brush::Solid(color) => {
|
||||
self.scene.drawtag_stream.push(DRAWTAG_FILLCOLOR);
|
||||
let rgba_color = color.to_premul_u32();
|
||||
self.scene
|
||||
.drawdata_stream
|
||||
.extend(bytemuck::bytes_of(&FillColor { rgba_color }));
|
||||
}
|
||||
Brush::LinearGradient(gradient) => {
|
||||
let index = self.add_ramp(&gradient.stops);
|
||||
self.scene.drawtag_stream.push(DRAWTAG_FILLLINGRADIENT);
|
||||
self.scene
|
||||
.drawdata_stream
|
||||
.extend(bytemuck::bytes_of(&FillLinGradient {
|
||||
index,
|
||||
p0: [gradient.start.x, gradient.start.y],
|
||||
p1: [gradient.end.x, gradient.end.y],
|
||||
}));
|
||||
}
|
||||
Brush::RadialGradient(gradient) => {
|
||||
let index = self.add_ramp(&gradient.stops);
|
||||
self.scene.drawtag_stream.push(DRAWTAG_FILLRADGRADIENT);
|
||||
self.scene
|
||||
.drawdata_stream
|
||||
.extend(bytemuck::bytes_of(&FillRadGradient {
|
||||
index,
|
||||
p0: [gradient.center0.x, gradient.center0.y],
|
||||
p1: [gradient.center1.x, gradient.center1.y],
|
||||
r0: gradient.radius0,
|
||||
r1: gradient.radius1,
|
||||
}));
|
||||
}
|
||||
Brush::SweepGradient(_gradient) => todo!("sweep gradients aren't done yet!"),
|
||||
Brush::Image(_image) => todo!("images aren't done yet!"),
|
||||
Brush::Persistent(_) => todo!("persistent brushes aren't done yet!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_ramp(&mut self, stops: &[Stop]) -> u32 {
|
||||
match &mut self.resources {
|
||||
ResourceData::Scene(res) => res.add_ramp(stops),
|
||||
ResourceData::Fragment(res) => {
|
||||
let stops_start = res.stops.len();
|
||||
res.stops.extend_from_slice(stops);
|
||||
let id = res.patches.len() as u32;
|
||||
res.patches.push(ResourcePatch::Ramp {
|
||||
drawdata_offset: self.scene.drawdata_stream.len(),
|
||||
stops: stops_start..stops_start + stops.len(),
|
||||
});
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a clip.
|
||||
fn begin_clip(&mut self, blend: Option<Blend>) {
|
||||
self.scene.drawtag_stream.push(DRAWTAG_BEGINCLIP);
|
||||
let element = Clip {
|
||||
blend: blend.unwrap_or(Blend::default()).pack(),
|
||||
};
|
||||
self.scene
|
||||
.drawdata_stream
|
||||
.extend(bytemuck::bytes_of(&element));
|
||||
self.scene.n_clip += 1;
|
||||
}
|
||||
|
||||
fn end_clip(&mut self, blend: Option<Blend>) {
|
||||
self.scene.drawtag_stream.push(DRAWTAG_ENDCLIP);
|
||||
let element = Clip {
|
||||
blend: blend.unwrap_or(Blend::default()).pack(),
|
||||
};
|
||||
self.scene
|
||||
.drawdata_stream
|
||||
.extend(bytemuck::bytes_of(&element));
|
||||
// This is a dummy path, and will go away with the new clip impl.
|
||||
self.scene.tag_stream.push(0x10);
|
||||
self.scene.n_path += 1;
|
||||
self.scene.n_clip += 1;
|
||||
}
|
||||
}
|
||||
|
||||
enum ResourceData<'a> {
|
||||
Fragment(&'a mut FragmentResources),
|
||||
Scene(&'a mut ResourceContext),
|
||||
}
|
||||
|
||||
impl ResourceData<'_> {
|
||||
fn clear(&mut self) {
|
||||
match self {
|
||||
Self::Fragment(res) => {
|
||||
res.patches.clear();
|
||||
res.stops.clear();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tags for draw objects. See shader/drawtag.h for the authoritative source.
|
||||
const DRAWTAG_FILLCOLOR: u32 = 0x44;
|
||||
const DRAWTAG_FILLLINGRADIENT: u32 = 0x114;
|
||||
const DRAWTAG_FILLRADGRADIENT: u32 = 0x2dc;
|
||||
const DRAWTAG_BEGINCLIP: u32 = 0x05;
|
||||
const DRAWTAG_ENDCLIP: u32 = 0x25;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||
pub struct FillColor {
|
||||
rgba_color: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||
pub struct FillLinGradient {
|
||||
index: u32,
|
||||
p0: [f32; 2],
|
||||
p1: [f32; 2],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||
pub struct FillRadGradient {
|
||||
index: u32,
|
||||
p0: [f32; 2],
|
||||
p1: [f32; 2],
|
||||
r0: f32,
|
||||
r1: f32,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||
pub struct FillImage {
|
||||
index: u32,
|
||||
// [i16; 2]
|
||||
offset: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||
pub struct Clip {
|
||||
blend: u32,
|
||||
}
|
||||
|
||||
struct PathBuilder<'a> {
|
||||
tag_stream: &'a mut Vec<u8>,
|
||||
// If we're never going to use the i16 encoding, it might be
|
||||
// slightly faster to store this as Vec<u32>, we'd get aligned
|
||||
// stores on ARM etc.
|
||||
pathseg_stream: &'a mut Vec<u8>,
|
||||
first_pt: [f32; 2],
|
||||
state: PathState,
|
||||
n_pathseg: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum PathState {
|
||||
Start,
|
||||
MoveTo,
|
||||
NonemptySubpath,
|
||||
}
|
||||
|
||||
impl<'a> PathBuilder<'a> {
|
||||
pub fn new(tags: &'a mut Vec<u8>, pathsegs: &'a mut Vec<u8>) -> PathBuilder<'a> {
|
||||
PathBuilder {
|
||||
tag_stream: tags,
|
||||
pathseg_stream: pathsegs,
|
||||
first_pt: [0.0, 0.0],
|
||||
state: PathState::Start,
|
||||
n_pathseg: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_to(&mut self, x: f32, y: f32) {
|
||||
let buf = [x, y];
|
||||
let bytes = bytemuck::bytes_of(&buf);
|
||||
self.first_pt = buf;
|
||||
if self.state == PathState::MoveTo {
|
||||
let new_len = self.pathseg_stream.len() - 8;
|
||||
self.pathseg_stream.truncate(new_len);
|
||||
}
|
||||
if self.state == PathState::NonemptySubpath {
|
||||
if let Some(tag) = self.tag_stream.last_mut() {
|
||||
*tag |= 4;
|
||||
}
|
||||
}
|
||||
self.pathseg_stream.extend_from_slice(bytes);
|
||||
self.state = PathState::MoveTo;
|
||||
}
|
||||
|
||||
pub fn line_to(&mut self, x: f32, y: f32) {
|
||||
if self.state == PathState::Start {
|
||||
// should warn or error
|
||||
return;
|
||||
}
|
||||
let buf = [x, y];
|
||||
let bytes = bytemuck::bytes_of(&buf);
|
||||
self.pathseg_stream.extend_from_slice(bytes);
|
||||
self.tag_stream.push(9);
|
||||
self.state = PathState::NonemptySubpath;
|
||||
self.n_pathseg += 1;
|
||||
}
|
||||
|
||||
pub fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
|
||||
if self.state == PathState::Start {
|
||||
return;
|
||||
}
|
||||
let buf = [x1, y1, x2, y2];
|
||||
let bytes = bytemuck::bytes_of(&buf);
|
||||
self.pathseg_stream.extend_from_slice(bytes);
|
||||
self.tag_stream.push(10);
|
||||
self.state = PathState::NonemptySubpath;
|
||||
self.n_pathseg += 1;
|
||||
}
|
||||
|
||||
pub fn cubic_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
|
||||
if self.state == PathState::Start {
|
||||
return;
|
||||
}
|
||||
let buf = [x1, y1, x2, y2, x3, y3];
|
||||
let bytes = bytemuck::bytes_of(&buf);
|
||||
self.pathseg_stream.extend_from_slice(bytes);
|
||||
self.tag_stream.push(11);
|
||||
self.state = PathState::NonemptySubpath;
|
||||
self.n_pathseg += 1;
|
||||
}
|
||||
|
||||
pub fn close_path(&mut self) {
|
||||
match self.state {
|
||||
PathState::Start => return,
|
||||
PathState::MoveTo => {
|
||||
let new_len = self.pathseg_stream.len() - 8;
|
||||
self.pathseg_stream.truncate(new_len);
|
||||
self.state = PathState::Start;
|
||||
return;
|
||||
}
|
||||
PathState::NonemptySubpath => (),
|
||||
}
|
||||
let len = self.pathseg_stream.len();
|
||||
if len < 8 {
|
||||
// can't happen
|
||||
return;
|
||||
}
|
||||
let first_bytes = bytemuck::bytes_of(&self.first_pt);
|
||||
if &self.pathseg_stream[len - 8..len] != first_bytes {
|
||||
self.pathseg_stream.extend_from_slice(first_bytes);
|
||||
self.tag_stream.push(13);
|
||||
self.n_pathseg += 1;
|
||||
} else {
|
||||
if let Some(tag) = self.tag_stream.last_mut() {
|
||||
*tag |= 4;
|
||||
}
|
||||
}
|
||||
self.state = PathState::Start;
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
if self.state == PathState::MoveTo {
|
||||
let new_len = self.pathseg_stream.len() - 8;
|
||||
self.pathseg_stream.truncate(new_len);
|
||||
}
|
||||
if let Some(tag) = self.tag_stream.last_mut() {
|
||||
*tag |= 4;
|
||||
}
|
||||
}
|
||||
|
||||
/// Finish encoding a path.
|
||||
///
|
||||
/// Encode this after encoding path segments.
|
||||
pub fn path(&mut self) {
|
||||
self.finish();
|
||||
// maybe don't encode if path is empty? might throw off sync though
|
||||
self.tag_stream.push(0x10);
|
||||
}
|
||||
|
||||
/// Get the number of path segments.
|
||||
///
|
||||
/// This is the number of path segments that will be written by the
|
||||
/// path stage; use this for allocating the output buffer.
|
||||
///
|
||||
/// Also note: it takes `self` for lifetime reasons.
|
||||
pub fn n_pathseg(self) -> u32 {
|
||||
self.n_pathseg
|
||||
}
|
||||
}
|
115
piet-scene/src/scene/mod.rs
Normal file
115
piet-scene/src/scene/mod.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
mod blend;
|
||||
mod builder;
|
||||
mod style;
|
||||
|
||||
pub use blend::{Blend, Compose, Mix};
|
||||
pub use builder::{build_fragment, build_scene, Builder};
|
||||
pub use style::*;
|
||||
|
||||
use super::brush::*;
|
||||
use super::geometry::{Affine, Point, Rect};
|
||||
use super::path::Element;
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SceneData {
|
||||
pub transform_stream: Vec<Affine>,
|
||||
pub tag_stream: Vec<u8>,
|
||||
pub pathseg_stream: Vec<u8>,
|
||||
pub linewidth_stream: Vec<f32>,
|
||||
pub drawtag_stream: Vec<u32>,
|
||||
pub drawdata_stream: Vec<u8>,
|
||||
pub n_path: u32,
|
||||
pub n_pathseg: u32,
|
||||
pub n_clip: u32,
|
||||
}
|
||||
|
||||
impl SceneData {
|
||||
fn reset(&mut self, is_fragment: bool) {
|
||||
self.transform_stream.clear();
|
||||
self.tag_stream.clear();
|
||||
self.pathseg_stream.clear();
|
||||
self.linewidth_stream.clear();
|
||||
self.drawtag_stream.clear();
|
||||
self.drawdata_stream.clear();
|
||||
self.n_path = 0;
|
||||
self.n_pathseg = 0;
|
||||
self.n_clip = 0;
|
||||
if !is_fragment {
|
||||
self.transform_stream
|
||||
.push(Affine::new(&[1.0, 0.0, 0.0, 1.0, 0.0, 0.0]));
|
||||
self.linewidth_stream.push(-1.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn append(&mut self, other: &SceneData) {
|
||||
self.transform_stream
|
||||
.extend_from_slice(&other.transform_stream);
|
||||
self.tag_stream.extend_from_slice(&other.tag_stream);
|
||||
self.pathseg_stream.extend_from_slice(&other.pathseg_stream);
|
||||
self.linewidth_stream
|
||||
.extend_from_slice(&other.linewidth_stream);
|
||||
self.drawtag_stream.extend_from_slice(&other.drawtag_stream);
|
||||
self.drawdata_stream
|
||||
.extend_from_slice(&other.drawdata_stream);
|
||||
self.n_path += other.n_path;
|
||||
self.n_pathseg += other.n_pathseg;
|
||||
self.n_clip += other.n_clip;
|
||||
}
|
||||
}
|
||||
|
||||
/// Encoded definition of a scene that is ready for rendering when paired with
|
||||
/// an associated resource context.
|
||||
#[derive(Default)]
|
||||
pub struct Scene {
|
||||
data: SceneData,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn data(&self) -> &SceneData {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
/// Encoded definition of a scene fragment and associated resources.
|
||||
#[derive(Default)]
|
||||
pub struct Fragment {
|
||||
data: SceneData,
|
||||
resources: FragmentResources,
|
||||
}
|
||||
|
||||
impl Fragment {
|
||||
pub fn points(&self) -> &[Point] {
|
||||
bytemuck::cast_slice(&self.data.pathseg_stream)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FragmentResources {
|
||||
patches: Vec<ResourcePatch>,
|
||||
stops: Vec<Stop>,
|
||||
}
|
||||
|
||||
enum ResourcePatch {
|
||||
Ramp {
|
||||
drawdata_offset: usize,
|
||||
stops: Range<usize>,
|
||||
},
|
||||
}
|
71
piet-scene/src/scene/style.rs
Normal file
71
piet-scene/src/scene/style.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2022 The piet-gpu authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Also licensed under MIT license, at your choice.
|
||||
|
||||
use core::borrow::Borrow;
|
||||
|
||||
/// Describes the winding rule that determines the interior portion of a path.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Fill {
|
||||
NonZero,
|
||||
EvenOdd,
|
||||
}
|
||||
|
||||
/// Defines the connection between two segments of a stroke.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Join {
|
||||
/// A straight line connecting the segments.
|
||||
Bevel,
|
||||
/// The segments are extended to their natural intersection point.
|
||||
Miter,
|
||||
/// An arc between the segments.
|
||||
Round,
|
||||
}
|
||||
|
||||
/// Defines the shape to be drawn at the ends of a stroke.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Cap {
|
||||
/// Flat cap.
|
||||
Butt,
|
||||
/// Square cap with dimensions equal to half the stroke width.
|
||||
Square,
|
||||
/// Rounded cap with radius equal to half the stroke width.
|
||||
Round,
|
||||
}
|
||||
|
||||
/// Describes the visual style of a stroke.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Stroke<D>
|
||||
where
|
||||
D: Borrow<[f32]>,
|
||||
{
|
||||
/// Width of the stroke.
|
||||
pub width: f32,
|
||||
/// Style for connecting segments of the stroke.
|
||||
pub join: Join,
|
||||
/// Limit for miter joins.
|
||||
pub miter_limit: f32,
|
||||
/// Style for capping the beginning of an open subpath.
|
||||
pub start_cap: Cap,
|
||||
/// Style for capping the end of an open subpath.
|
||||
pub end_cap: Cap,
|
||||
/// Lengths of dashes in alternating on/off order.
|
||||
pub dash_pattern: D,
|
||||
/// Offset of the first dash.
|
||||
pub dash_offset: f32,
|
||||
/// True if the stroke width should be affected by the scale of a
|
||||
/// transform.
|
||||
pub scale: bool,
|
||||
}
|
Loading…
Reference in a new issue