8 Commits

17 changed files with 647 additions and 390 deletions

View File

@@ -2,7 +2,7 @@ name: Rust
on:
push:
branches: [ master ]
branches: [ master, testing ]
env:
CARGO_TERM_COLOR: always

258
Cargo.lock generated
View File

@@ -53,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b"
dependencies = [
"alsa-sys",
"bitflags",
"bitflags 1.3.2",
"libc",
"nix 0.23.1",
]
@@ -124,7 +124,7 @@ checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -176,21 +176,22 @@ dependencies = [
[[package]]
name = "bindgen"
version = "0.59.2"
version = "0.69.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
dependencies = [
"bitflags",
"bitflags 2.5.0",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.66",
]
[[package]]
@@ -214,6 +215,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "block"
version = "0.1.6"
@@ -271,7 +278,7 @@ checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -383,7 +390,7 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"block",
"cocoa-foundation",
"core-foundation 0.9.3",
@@ -399,7 +406,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"block",
"core-foundation 0.9.3",
"core-graphics-types",
@@ -494,7 +501,7 @@ version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation 0.7.0",
"foreign-types",
"libc",
@@ -506,7 +513,7 @@ version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation 0.9.3",
"core-graphics-types",
"foreign-types",
@@ -519,7 +526,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation 0.9.3",
"foreign-types",
"libc",
@@ -544,15 +551,15 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"coreaudio-sys",
]
[[package]]
name = "coreaudio-sys"
version = "0.2.10"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dff444d80630d7073077d38d40b4501fd518bd2b922c2a55edcc8b0f7be57e6"
checksum = "7f01585027057ff5f0a5bf276174ae4c1594a2c5bde93d5f46a016d76270f5a9"
dependencies = [
"bindgen",
]
@@ -783,7 +790,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "827914e1f53b1e0e025ecd3d967a7836b7bcb54520f90e21ef8df7b4d88a2759"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libloading",
"winapi 0.3.9",
]
@@ -809,7 +816,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -820,7 +827,7 @@ checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
dependencies = [
"darling_core",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -1032,7 +1039,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"fsevent-sys",
]
@@ -1051,7 +1058,7 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"fuchsia-zircon-sys",
]
@@ -1117,7 +1124,7 @@ checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -1177,7 +1184,7 @@ checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
@@ -1215,7 +1222,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"gpu-alloc-types",
]
@@ -1225,7 +1232,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@@ -1234,7 +1241,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"gpu-descriptor-types",
"hashbrown",
]
@@ -1245,7 +1252,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@@ -1283,7 +1290,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d"
dependencies = [
"base64",
"bitflags",
"bitflags 1.3.2",
"bytes",
"headers-core",
"http",
@@ -1438,7 +1445,7 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"inotify-sys",
"libc",
]
@@ -1588,9 +1595,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "libc"
version = "0.2.126"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libloading"
@@ -1690,7 +1697,7 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"block",
"core-graphics-types",
"foreign-types",
@@ -1763,7 +1770,7 @@ dependencies = [
"kernel32-sys",
"libc",
"log",
"miow 0.2.2",
"miow",
"net2",
"slab",
"winapi 0.2.8",
@@ -1771,15 +1778,14 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.0"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"miow 0.3.7",
"ntapi",
"winapi 0.3.9",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
]
[[package]]
@@ -1806,15 +1812,6 @@ dependencies = [
"ws2_32-sys",
]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "more-asserts"
version = "0.2.2"
@@ -1846,7 +1843,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f50357e1167a3ab92d6b3c7f4bf5f7fd13fde3f4b28bf0d5ea07b5100fdb6c0"
dependencies = [
"bit-set",
"bitflags",
"bitflags 1.3.2",
"codespan-reporting",
"hexf-parse",
"indexmap",
@@ -1865,7 +1862,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"jni-sys",
"ndk-sys 0.2.2",
"num_enum",
@@ -1878,7 +1875,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"jni-sys",
"ndk-sys 0.3.0",
"num_enum",
@@ -1931,7 +1928,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -1966,7 +1963,7 @@ version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cc",
"cfg-if 1.0.0",
"libc",
@@ -1979,7 +1976,7 @@ version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cc",
"cfg-if 1.0.0",
"libc",
@@ -2002,7 +1999,7 @@ version = "4.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"filetime",
"fsevent",
"fsevent-sys",
@@ -2014,15 +2011,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "ntapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "num-complex"
version = "0.4.0"
@@ -2040,7 +2028,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -2090,7 +2078,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -2226,12 +2214,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -2261,7 +2243,7 @@ checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -2321,9 +2303,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.40"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
@@ -2351,9 +2333,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.15"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
@@ -2463,7 +2445,7 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@@ -2511,7 +2493,7 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libc",
"mach",
"winapi 0.3.9",
@@ -2576,7 +2558,7 @@ version = "0.33.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
@@ -2632,7 +2614,7 @@ version = "0.34.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deecbc3fa9460acff5a1e563e05cb5f31bba0aa0c214bb49a43db8159176d54b"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"lazy_static",
"libc",
"raw-window-handle 0.3.4",
@@ -2671,7 +2653,7 @@ checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -2773,7 +2755,7 @@ version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"calloop",
"dlib",
"lazy_static",
@@ -2802,7 +2784,7 @@ version = "0.2.0+1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"num-traits",
]
@@ -2841,6 +2823,17 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tar"
version = "0.4.38"
@@ -2898,7 +2891,7 @@ checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -2944,7 +2937,7 @@ dependencies = [
"bytes",
"libc",
"memchr",
"mio 0.8.0",
"mio 0.8.11",
"pin-project-lite",
"socket2",
"winapi 0.3.9",
@@ -3165,12 +3158,14 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uw8"
version = "0.2.0"
version = "0.2.1"
dependencies = [
"ansi_term",
"anyhow",
"cpal",
"curlywas",
"env_logger 0.9.0",
"log",
"notify",
"pico-args",
"rubato",
@@ -3207,6 +3202,7 @@ dependencies = [
"env_logger 0.9.0",
"log",
"minifb",
"pico-args",
"pollster",
"wgpu",
"winapi 0.3.9",
@@ -3259,7 +3255,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
]
[[package]]
@@ -3308,6 +3304,12 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.81"
@@ -3329,7 +3331,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
"wasm-bindgen-shared",
]
@@ -3363,7 +3365,7 @@ checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.98",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -3639,7 +3641,7 @@ version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"downcast-rs",
"libc",
"nix 0.22.3",
@@ -3678,7 +3680,7 @@ version = "0.29.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"wayland-client",
"wayland-commons",
"wayland-scanner",
@@ -3759,7 +3761,7 @@ checksum = "266ca6be6004fd1b2a768023b1cb0afbf7af0cbffaba19af25c5792d44e74784"
dependencies = [
"arrayvec",
"bit-vec",
"bitflags",
"bitflags 1.3.2",
"cfg_aliases",
"codespan-reporting",
"copyless",
@@ -3786,7 +3788,7 @@ dependencies = [
"arrayvec",
"ash",
"bit-set",
"bitflags",
"bitflags 1.3.2",
"block",
"core-graphics-types",
"d3d12",
@@ -3821,7 +3823,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f48d691b733b9d50ea8cb18f377fd1ed927c90c55ad1ec5b90f68885471977f7"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@@ -3873,13 +3875,79 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winit"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cocoa",
"core-foundation 0.9.3",
"core-graphics 0.22.3",
@@ -3889,7 +3957,7 @@ dependencies = [
"lazy_static",
"libc",
"log",
"mio 0.8.0",
"mio 0.8.11",
"ndk 0.5.0",
"ndk-glue 0.5.1",
"ndk-sys 0.2.2",

View File

@@ -13,6 +13,8 @@ browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
[dependencies]
wasmtime = { version = "0.37.0", optional = true }
anyhow = "1"
env_logger = "0.9"
log = "0.4"
uw8-window = { path = "uw8-window", optional = true }
notify = "4"
pico-args = "0.4"

View File

@@ -43,6 +43,27 @@ Options:
-l LEVEL, --level LEVEL : Compression level (0-9). Higher compression levels are really slow.
-o FILE, --output FILE : Write the loaded and optionally packed cart back to disk.
when using the native runtime:
-m, --no-audio : Disable audio, also reduces cpu load a bit
--no-gpu : Force old cpu-only window code
--filter FILTER : Select an upscale filter at startup
--fullscreen : Start in fullscreen mode
Note that the cpu-only window does not support fullscreen nor upscale filters.
Unless --no-gpu is given, uw8 will first try to open a gpu accelerated window, falling back to the old cpu-only window if that fails.
Therefore you should rarely need to manually pass --no-gpu. If you prefer the old pixel doubling look to the now default crt filter,
you can just pass "--filter nearest" or "--filter 1".
The upscale filter options are:
1, nearest : Anti-aliased nearest filter
2, fast_crt : Very simple, cheap crt filter, not very good below a window size of 960x720
3, ss_crt : Super sampled crt filter, a little more demanding on the GPU but scales well to smaller window sizes
4, chromatic_crt : Variant of fast_crt with a slight offset of the three color dots of a pixel, still pretty cheap
5, auto_crt (default) : ss_crt below 960x720, chromatic_crt otherwise
You can switch the upscale filter at any time using the keys 1-5. You can toggle fullscreen with F.
uw8 pack [<options>] <infile> <outfile>

View File

@@ -436,6 +436,30 @@ and execution of the cart is stopped. Defaults to 30 (0.5s)
* `-l LEVEL`, `--level LEVEL`: Compression level (0-9). Higher compression levels are really slow.
* `-o FILE`, `--output FILE`: Write the loaded and optionally packed cart back to disk.
when using the native runtime:
* `-m`, `--no-audio`: Disable audio, also reduces cpu load a bit
* `--no-gpu`: Force old cpu-only window code
* `--filter FILTER`: Select an upscale filter at startup
* `--fullscreen`: Start in fullscreen mode
Note that the cpu-only window does not support fullscreen nor upscale filters.
Unless --no-gpu is given, uw8 will first try to open a gpu accelerated window, falling back to the old cpu-only window if that fails.
Therefore you should rarely need to manually pass --no-gpu. If you prefer the old pixel doubling look to the now default crt filter,
you can just pass `--filter nearest` or `--filter 1`.
The upscale filter options are:
```
1, nearest : Anti-aliased nearest filter
2, fast_crt : Very simple, cheap crt filter, not very good below a window size of 960x720
3, ss_crt : Super sampled crt filter, a little more demanding on the GPU but scales well to smaller window sizes
4, chromatic_crt : Variant of fast_crt with a slight offset of the three color dots of a pixel, still pretty cheap
5, auto_crt (default) : ss_crt below 960x720, chromatic_crt otherwise
```
You can switch the upscale filter at any time using the keys 1-5. You can toggle fullscreen with F.
## `uw8 pack`
Usage:

View File

@@ -13,6 +13,7 @@ use uw8::RunWebServer;
use uw8::Runtime;
fn main() -> Result<()> {
env_logger::Builder::from_env(env_logger::Env::default()).init();
let mut args = Arguments::from_env();
// try to enable ansi support in win10 cmd shell
@@ -35,7 +36,7 @@ fn main() -> Result<()> {
println!();
println!("Usage:");
#[cfg(any(feature = "native", feature = "browser"))]
println!(" uw8 run [-t/--timeout <frames>] [--no-gpu] [--b/--browser] [-w/--watch] [-p/--pack] [-u/--uncompressed] [-l/--level] [-o/--output <out-file>] <file>");
println!(" uw8 run [-t/--timeout <frames>] [--b/--browser] [-w/--watch] [-p/--pack] [-u/--uncompressed] [-l/--level] [-o/--output <out-file>] <file>");
println!(" uw8 pack [-u/--uncompressed] [-l/--level] <in-file> <out-file>");
println!(" uw8 unpack <in-file> <out-file>");
println!(" uw8 compile [-d/--debug] <in-file> <out-file>");
@@ -54,8 +55,6 @@ fn run(mut args: Arguments) -> Result<()> {
let watch_mode = args.contains(["-w", "--watch"]);
#[allow(unused)]
let timeout: Option<u32> = args.opt_value_from_str(["-t", "--timeout"])?;
#[allow(unused)]
let gpu = !args.contains("--no-gpu");
let mut config = Config::default();
if args.contains(["-p", "--pack"]) {
@@ -82,7 +81,16 @@ fn run(mut args: Arguments) -> Result<()> {
#[cfg(not(feature = "native"))]
let run_browser = args.contains(["-b", "--browser"]) || true;
let disable_audio = args.contains(["-m", "--disable-audio"]);
let disable_audio = args.contains(["-m", "--no-audio"]);
#[cfg(feature = "native")]
let window_config = {
let mut config = WindowConfig::default();
if !run_browser {
config.parse_arguments(&mut args);
}
config
};
let filename = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
@@ -90,12 +98,14 @@ fn run(mut args: Arguments) -> Result<()> {
use std::process::exit;
use uw8_window::WindowConfig;
let mut runtime: Box<dyn Runtime> = if !run_browser {
#[cfg(not(feature = "native"))]
unimplemented!();
#[cfg(feature = "native")]
{
let mut microw8 = MicroW8::new(timeout, gpu)?;
let mut microw8 = MicroW8::new(timeout, window_config)?;
if disable_audio {
microw8.disable_audio();
}
@@ -167,7 +177,8 @@ fn load_cart(filename: &Path, config: &Config) -> (Result<Vec<u8>>, Vec<PathBuf>
if let Some(ref pack_config) = config.pack {
cart = uw8_tool::pack(&cart, pack_config)?;
println!(
"\npacked size: {:.2} bytes",
"\npacked size: {} bytes ({:.2})",
cart.len(),
uw8_tool::compressed_size(&cart)
);
}

View File

@@ -5,23 +5,20 @@ use std::{thread, time::Instant};
use anyhow::{anyhow, Result};
use cpal::traits::*;
use rubato::Resampler;
use uw8_window::{Window, WindowConfig};
use wasmtime::{
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
};
pub struct MicroW8 {
tx: mpsc::SyncSender<Option<UW8Instance>>,
rx: mpsc::Receiver<UIEvent>,
window: Window,
stream: Option<cpal::Stream>,
engine: Engine,
loader_module: Module,
disable_audio: bool,
module_data: Option<Vec<u8>>,
}
enum UIEvent {
Error(Result<()>),
Reset,
timeout: u32,
instance: Option<UW8Instance>,
}
struct UW8Instance {
@@ -48,7 +45,7 @@ struct UW8WatchDog {
}
impl MicroW8 {
pub fn new(timeout: Option<u32>, gpu: bool) -> Result<MicroW8> {
pub fn new(timeout: Option<u32>, window_config: WindowConfig) -> Result<MicroW8> {
let mut config = wasmtime::Config::new();
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
if timeout.is_some() {
@@ -59,39 +56,17 @@ impl MicroW8 {
let loader_module =
wasmtime::Module::new(&engine, include_bytes!("../platform/bin/loader.wasm"))?;
let (to_ui_tx, to_ui_rx) = mpsc::sync_channel(2);
let (from_ui_tx, from_ui_rx) = mpsc::sync_channel(1);
std::thread::spawn(move || {
let mut state = State {
instance: None,
timeout: timeout.unwrap_or(0),
};
uw8_window::run(gpu, move |framebuffer, gamepad, reset| {
while let Ok(instance) = to_ui_rx.try_recv() {
state.instance = instance;
}
if reset {
from_ui_tx.send(UIEvent::Reset).unwrap();
}
state.run_frame(framebuffer, gamepad).unwrap_or_else(|err| {
from_ui_tx.send(UIEvent::Error(Err(err))).unwrap();
Instant::now()
})
});
});
let window = Window::new(window_config)?;
Ok(MicroW8 {
tx: to_ui_tx,
rx: from_ui_rx,
window,
stream: None,
engine,
loader_module,
disable_audio: false,
module_data: None,
timeout: timeout.unwrap_or(0),
instance: None,
})
}
@@ -102,12 +77,12 @@ impl MicroW8 {
impl super::Runtime for MicroW8 {
fn is_open(&self) -> bool {
true
self.window.is_open()
}
fn load(&mut self, module_data: &[u8]) -> Result<()> {
self.stream = None;
self.tx.send(None)?;
self.instance = None;
let mut store = wasmtime::Store::new(&self.engine, ());
store.set_epoch_deadline(60);
@@ -174,7 +149,7 @@ impl super::Runtime for MicroW8 {
}
};
self.tx.send(Some(UW8Instance {
self.instance = Some(UW8Instance {
store,
memory,
end_frame,
@@ -182,56 +157,36 @@ impl super::Runtime for MicroW8 {
start_time: Instant::now(),
watchdog,
sound_tx,
}))?;
});
self.stream = stream;
self.module_data = Some(module_data.into());
Ok(())
}
fn run_frame(&mut self) -> Result<()> {
if let Ok(event) = self.rx.try_recv() {
match event {
UIEvent::Error(err) => err,
UIEvent::Reset => {
let input = self.window.begin_frame();
if input.reset {
if let Some(module_data) = self.module_data.take() {
self.load(&module_data)
} else {
Ok(())
self.load(&module_data)?;
}
}
}
} else {
Ok(())
}
}
}
struct State {
instance: Option<UW8Instance>,
timeout: u32,
}
impl State {
fn run_frame(
&mut self,
framebuffer: &mut dyn uw8_window::Framebuffer,
gamepad: u32,
) -> Result<Instant> {
let now = Instant::now();
let mut result = Ok(now);
let mut result = Ok(());
if let Some(mut instance) = self.instance.take() {
let time = (now - instance.start_time).as_millis() as i32;
{
let next_frame = {
let offset = ((time as u32 as i64 * 6) % 100 - 50) / 6;
let max = now + Duration::from_millis(17);
let next_center = now + Duration::from_millis((16 - offset) as u64);
result = Ok(next_center.min(max));
}
next_center.min(max)
};
{
let mem = instance.memory.data_mut(&mut instance.store);
mem[64..68].copy_from_slice(&time.to_le_bytes());
mem[68..72].copy_from_slice(&gamepad.to_le_bytes());
mem[68..72].copy_from_slice(&input.gamepads);
}
instance.store.set_epoch_deadline(self.timeout as u64);
@@ -255,14 +210,16 @@ impl State {
let framebuffer_mem = &memory[120..(120 + 320 * 240)];
let palette_mem = &memory[0x13000..];
framebuffer.update(framebuffer_mem, palette_mem);
self.window
.end_frame(framebuffer_mem, palette_mem, next_frame);
if result.is_ok() {
self.instance = Some(instance);
}
}
Ok(result?)
result?;
Ok(())
}
}

7
uw8-window/Cargo.lock generated
View File

@@ -986,6 +986,12 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pico-args"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -1296,6 +1302,7 @@ dependencies = [
"env_logger",
"log",
"minifb",
"pico-args",
"pollster",
"wgpu",
"winapi",

View File

@@ -9,6 +9,7 @@ edition = "2021"
winit = "0.26.1"
env_logger = "0.9"
log = "0.4"
pico-args = "0.4"
wgpu = "0.13.1"
pollster = "0.2"
bytemuck = { version = "1.4", features = [ "derive" ] }

View File

@@ -1,7 +1,8 @@
use std::time::Instant;
use crate::Framebuffer;
use minifb::{Key, Window, WindowOptions};
use crate::{Input, WindowImpl};
use anyhow::Result;
use minifb::{Key, WindowOptions};
static GAMEPAD_KEYS: &[Key] = &[
Key::Up,
@@ -14,13 +15,19 @@ static GAMEPAD_KEYS: &[Key] = &[
Key::S,
];
pub fn run(mut update: Box<dyn FnMut(&mut dyn Framebuffer, u32, bool) -> Instant + 'static>) -> ! {
pub struct Window {
window: minifb::Window,
buffer: Vec<u32>,
}
impl Window {
pub fn new() -> Result<Window> {
#[cfg(target_os = "windows")]
unsafe {
winapi::um::timeapi::timeBeginPeriod(1);
}
let mut buffer: Vec<u32> = vec![0; 320 * 240];
let buffer: Vec<u32> = vec![0; 320 * 240];
let options = WindowOptions {
scale: minifb::Scale::X2,
@@ -28,44 +35,33 @@ pub fn run(mut update: Box<dyn FnMut(&mut dyn Framebuffer, u32, bool) -> Instant
resize: true,
..Default::default()
};
let mut window = Window::new("MicroW8", 320, 240, options).unwrap();
let window = minifb::Window::new("MicroW8", 320, 240, options).unwrap();
let mut next_frame = Instant::now();
while window.is_open() && !window.is_key_down(Key::Escape) {
if let Some(sleep) = next_frame.checked_duration_since(Instant::now()) {
std::thread::sleep(sleep);
Ok(Window { window, buffer })
}
}
let mut gamepad = 0;
for key in window.get_keys() {
impl WindowImpl for Window {
fn begin_frame(&mut self) -> Input {
let mut gamepads = [0u8; 4];
for key in self.window.get_keys() {
if let Some(index) = GAMEPAD_KEYS
.iter()
.enumerate()
.find(|(_, &k)| k == key)
.map(|(i, _)| i)
{
gamepad |= 1 << index;
gamepads[0] |= 1 << index;
}
}
next_frame = update(
&mut CpuFramebuffer {
buffer: &mut buffer,
},
gamepad,
window.is_key_pressed(Key::R, minifb::KeyRepeat::No),
);
window.update_with_buffer(&buffer, 320, 240).unwrap();
Input {
gamepads,
reset: self.window.is_key_pressed(Key::R, minifb::KeyRepeat::No),
}
}
std::process::exit(0);
}
struct CpuFramebuffer<'a> {
buffer: &'a mut Vec<u32>,
}
impl<'a> Framebuffer for CpuFramebuffer<'a> {
fn update(&mut self, framebuffer: &[u8], palette: &[u8]) {
fn end_frame(&mut self, framebuffer: &[u8], palette: &[u8], next_frame: Instant) {
for (i, &color_index) in framebuffer.iter().enumerate() {
let offset = color_index as usize * 4;
self.buffer[i] = 0xff000000
@@ -73,5 +69,15 @@ impl<'a> Framebuffer for CpuFramebuffer<'a> {
| ((palette[offset + 1] as u32) << 8)
| palette[offset + 2] as u32;
}
self.window
.update_with_buffer(&self.buffer, 320, 240)
.unwrap();
if let Some(sleep) = next_frame.checked_duration_since(Instant::now()) {
std::thread::sleep(sleep);
}
}
fn is_open(&self) -> bool {
self.window.is_open() && !self.window.is_key_down(Key::Escape)
}
}

View File

@@ -112,7 +112,7 @@ impl CrtFilter {
}
impl Filter for CrtFilter {
fn resize(&self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(new_size),
};

View File

@@ -15,6 +15,7 @@ impl FastCrtFilter {
screen: &wgpu::TextureView,
resolution: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
chromatic: bool,
) -> FastCrtFilter {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(resolution),
@@ -104,7 +105,11 @@ impl FastCrtFilter {
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
entry_point: if chromatic {
"fs_main_chromatic"
} else {
"fs_main"
},
targets: &[Some(wgpu::ColorTargetState {
format: surface_format,
blend: None,
@@ -126,7 +131,7 @@ impl FastCrtFilter {
}
impl Filter for FastCrtFilter {
fn resize(&self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(new_size),
};

View File

@@ -34,10 +34,9 @@ fn col_factor(offset: f32) -> f32 {
return 1.0 / (1.0 + offset * offset * 16.0);
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let base = round(in.tex_coords) - vec2<f32>(0.5);
let frac = in.tex_coords - base;
fn sample_screen(tex_coords: vec2<f32>) -> vec4<f32> {
let base = round(tex_coords) - vec2<f32>(0.5);
let frac = tex_coords - base;
let top_factor = row_factor(frac.y);
let bottom_factor = row_factor(frac.y - 1.0);
@@ -52,3 +51,16 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return textureSample(screen_texture, linear_sampler, vec2<f32>(u, v) / vec2<f32>(320.0, 240.0)) * (top_factor + bottom_factor) * (left_factor + right_factor) * 1.1;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return sample_screen(in.tex_coords);
}
@fragment
fn fs_main_chromatic(in: VertexOutput) -> @location(0) vec4<f32> {
let r = sample_screen(in.tex_coords + vec2<f32>(0.2, 0.2)).r;
let g = sample_screen(in.tex_coords + vec2<f32>(0.07, -0.27)).g;
let b = sample_screen(in.tex_coords + vec2<f32>(-0.27, 0.07)).b;
return vec4<f32>(r, g, b, 1.0);
}

View File

@@ -1,4 +1,4 @@
use crate::Framebuffer;
use crate::{Input, WindowConfig, WindowImpl};
use anyhow::{anyhow, Result};
use std::{num::NonZeroU32, time::Instant};
@@ -9,12 +9,7 @@ use winit::{
window::{Fullscreen, WindowBuilder},
};
#[cfg(target_os = "macos")]
use winit::platform::macos::EventLoopExtMacOS;
#[cfg(target_os = "linux")]
use winit::platform::unix::EventLoopExtUnix;
#[cfg(target_os = "windows")]
use winit::platform::windows::EventLoopExtWindows;
use winit::platform::run_return::EventLoopExtRunReturn;
mod crt;
mod fast_crt;
@@ -25,23 +20,35 @@ use fast_crt::FastCrtFilter;
use square::SquareFilter;
pub struct Window {
event_loop: EventLoop<()>,
window: winit::window::Window,
instance: wgpu::Instance,
_instance: wgpu::Instance,
surface: wgpu::Surface,
adapter: wgpu::Adapter,
_adapter: wgpu::Adapter,
device: wgpu::Device,
queue: wgpu::Queue,
palette_screen_mode: PaletteScreenMode,
surface_config: wgpu::SurfaceConfiguration,
filter: Box<dyn Filter>,
event_loop: EventLoop<()>,
window: winit::window::Window,
gamepads: [u8; 4],
next_frame: Instant,
is_fullscreen: bool,
is_open: bool,
}
impl Window {
pub fn new() -> Result<Window> {
async fn create() -> Result<Window> {
let event_loop = EventLoop::new_any_thread();
pub fn new(window_config: WindowConfig) -> Result<Window> {
async fn create(window_config: WindowConfig) -> Result<Window> {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(PhysicalSize::new(640u32, 480))
.with_min_inner_size(PhysicalSize::new(320u32, 240))
.with_title("MicroW8")
.with_fullscreen(if window_config.fullscreen {
Some(Fullscreen::Borderless(None))
} else {
None
})
.build(&event_loop)?;
window.set_cursor_visible(false);
@@ -61,37 +68,9 @@ impl Window {
.request_device(&wgpu::DeviceDescriptor::default(), None)
.await?;
Ok(Window {
event_loop,
window,
instance,
surface,
adapter,
device,
queue,
})
}
pollster::block_on(create())
}
pub fn run(
self,
mut update: Box<dyn FnMut(&mut dyn Framebuffer, u32, bool) -> Instant + 'static>,
) -> ! {
let Window {
event_loop,
window,
instance,
surface,
adapter,
device,
queue,
} = self;
let palette_screen_mode = PaletteScreenMode::new(&device);
let mut surface_config = wgpu::SurfaceConfiguration {
let surface_config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface.get_supported_formats(&adapter)[0],
width: window.inner_size().width,
@@ -99,32 +78,58 @@ impl Window {
present_mode: wgpu::PresentMode::AutoNoVsync,
};
let mut filter: Box<dyn Filter> = Box::new(CrtFilter::new(
let filter: Box<dyn Filter> = create_filter(
&device,
&palette_screen_mode.screen_view,
window.inner_size(),
surface_config.format,
));
window_config.filter,
);
surface.configure(&device, &surface_config);
Ok(Window {
event_loop,
window,
_instance: instance,
surface,
_adapter: adapter,
device,
queue,
palette_screen_mode,
surface_config,
filter,
gamepads: [0; 4],
next_frame: Instant::now(),
is_fullscreen: window_config.fullscreen,
is_open: true,
})
}
pollster::block_on(create(window_config))
}
}
impl WindowImpl for Window {
fn begin_frame(&mut self) -> Input {
let mut reset = false;
let mut gamepad = 0;
event_loop.run(move |event, _, control_flow| {
let _ = (&window, &instance, &surface, &adapter, &device);
self.event_loop.run_return(|event, _, control_flow| {
*control_flow = ControlFlow::WaitUntil(self.next_frame);
let mut new_filter = None;
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::Resized(new_size) => {
surface_config.width = new_size.width;
surface_config.height = new_size.height;
surface.configure(&device, &surface_config);
filter.resize(&queue, new_size);
self.surface_config.width = new_size.width;
self.surface_config.height = new_size.height;
self.surface.configure(&self.device, &self.surface_config);
self.filter.resize(&self.queue, new_size);
}
WindowEvent::CloseRequested => {
self.is_open = false;
*control_flow = ControlFlow::Exit;
}
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::KeyboardInput { input, .. } => {
fn gamepad_button(input: &winit::event::KeyboardInput) -> u32 {
fn gamepad_button(input: &winit::event::KeyboardInput) -> u8 {
match input.scancode {
44 => 16,
45 => 32,
@@ -141,78 +146,79 @@ impl Window {
}
if input.state == winit::event::ElementState::Pressed {
match input.virtual_keycode {
Some(VirtualKeyCode::Escape) => *control_flow = ControlFlow::Exit,
Some(VirtualKeyCode::Escape) => {
self.is_open = false;
*control_flow = ControlFlow::Exit;
}
Some(VirtualKeyCode::F) => {
window.set_fullscreen(if window.fullscreen().is_some() {
let fullscreen = if self.window.fullscreen().is_some() {
None
} else {
Some(Fullscreen::Borderless(None))
});
};
self.is_fullscreen = fullscreen.is_some();
self.window.set_fullscreen(fullscreen);
}
Some(VirtualKeyCode::R) => reset = true,
Some(VirtualKeyCode::Key1) => {
filter = Box::new(SquareFilter::new(
&device,
&palette_screen_mode.screen_view,
window.inner_size(),
surface_config.format,
))
}
Some(VirtualKeyCode::Key2) => {
filter = Box::new(FastCrtFilter::new(
&device,
&palette_screen_mode.screen_view,
window.inner_size(),
surface_config.format,
))
}
Some(VirtualKeyCode::Key3) => {
filter = Box::new(CrtFilter::new(
&device,
&palette_screen_mode.screen_view,
window.inner_size(),
surface_config.format,
))
}
Some(VirtualKeyCode::Key1) => new_filter = Some(1),
Some(VirtualKeyCode::Key2) => new_filter = Some(2),
Some(VirtualKeyCode::Key3) => new_filter = Some(3),
Some(VirtualKeyCode::Key4) => new_filter = Some(4),
Some(VirtualKeyCode::Key5) => new_filter = Some(5),
_ => (),
}
gamepad |= gamepad_button(&input);
self.gamepads[0] |= gamepad_button(&input);
} else {
gamepad &= !gamepad_button(&input);
self.gamepads[0] &= !gamepad_button(&input);
}
}
_ => (),
},
Event::MainEventsCleared => {
if let ControlFlow::WaitUntil(t) = *control_flow {
if Instant::now() < t {
return;
Event::RedrawEventsCleared => {
if Instant::now() >= self.next_frame
// workaround needed on Wayland until the next winit release
&& self.window.fullscreen().is_some() == self.is_fullscreen
{
*control_flow = ControlFlow::Exit
}
}
let next_frame = update(
&mut GpuFramebuffer {
queue: &queue,
framebuffer: &palette_screen_mode,
},
gamepad,
reset,
_ => (),
}
if let Some(new_filter) = new_filter {
self.filter = create_filter(
&self.device,
&self.palette_screen_mode.screen_view,
self.window.inner_size(),
self.surface_config.format,
new_filter,
);
reset = false;
*control_flow = ControlFlow::WaitUntil(next_frame);
}
});
Input {
gamepads: self.gamepads,
reset,
}
}
let output = surface.get_current_texture().unwrap();
fn end_frame(&mut self, framebuffer: &[u8], palette: &[u8], next_frame: Instant) {
self.next_frame = next_frame;
self.palette_screen_mode
.write_framebuffer(&self.queue, framebuffer);
self.palette_screen_mode.write_palette(&self.queue, palette);
let output = self.surface.get_current_texture().unwrap();
let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = device
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
palette_screen_mode.resolve_screen(&mut encoder);
self.palette_screen_mode.resolve_screen(&mut encoder);
{
let mut render_pass =
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
@@ -230,35 +236,105 @@ impl Window {
depth_stencil_attachment: None,
});
filter.render(&mut render_pass);
self.filter.render(&mut render_pass);
}
queue.submit(std::iter::once(encoder.finish()));
self.queue.submit(std::iter::once(encoder.finish()));
output.present();
}
_ => (),
}
});
fn is_open(&self) -> bool {
self.is_open
}
}
struct GpuFramebuffer<'a> {
framebuffer: &'a PaletteScreenMode,
queue: &'a wgpu::Queue,
}
impl<'a> Framebuffer for GpuFramebuffer<'a> {
fn update(&mut self, pixels: &[u8], palette: &[u8]) {
self.framebuffer.write_framebuffer(self.queue, pixels);
self.framebuffer.write_palette(self.queue, palette);
fn create_filter(
device: &wgpu::Device,
screen_texture: &wgpu::TextureView,
window_size: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
filter: u32,
) -> Box<dyn Filter> {
match filter {
1 => Box::new(SquareFilter::new(
device,
screen_texture,
window_size,
surface_format,
)),
2 => Box::new(FastCrtFilter::new(
device,
screen_texture,
window_size,
surface_format,
false,
)),
3 => Box::new(CrtFilter::new(
device,
screen_texture,
window_size,
surface_format,
)),
4 => Box::new(FastCrtFilter::new(
device,
screen_texture,
window_size,
surface_format,
true,
)),
_ => Box::new(AutoCrtFilter::new(
device,
screen_texture,
window_size,
surface_format,
)),
}
}
trait Filter {
fn resize(&self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>);
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>);
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>);
}
struct AutoCrtFilter {
small: CrtFilter,
large: FastCrtFilter,
resolution: PhysicalSize<u32>,
}
impl AutoCrtFilter {
fn new(
device: &wgpu::Device,
screen: &wgpu::TextureView,
resolution: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
) -> AutoCrtFilter {
let small = CrtFilter::new(device, screen, resolution, surface_format);
let large = FastCrtFilter::new(device, screen, resolution, surface_format, true);
AutoCrtFilter {
small,
large,
resolution,
}
}
}
impl Filter for AutoCrtFilter {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
self.small.resize(queue, new_size);
self.large.resize(queue, new_size);
self.resolution = new_size;
}
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
if self.resolution.width < 960 || self.resolution.height < 720 {
self.small.render(render_pass);
} else {
self.large.render(render_pass);
}
}
}
struct PaletteScreenMode {
framebuffer: wgpu::Texture,
palette: wgpu::Texture,

View File

@@ -126,7 +126,7 @@ impl SquareFilter {
}
impl Filter for SquareFilter {
fn resize(&self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(new_size),
};

View File

@@ -1,24 +1,81 @@
use anyhow::Result;
use std::time::Instant;
mod cpu;
mod gpu;
pub fn run<F: 'static + FnMut(&mut dyn Framebuffer, u32, bool) -> Instant>(
gpu: bool,
update: F,
) -> ! {
if gpu {
match gpu::Window::new() {
Ok(window) => window.run(Box::new(update)),
pub struct Window(Box<dyn WindowImpl>);
impl Window {
pub fn new(config: WindowConfig) -> Result<Window> {
if config.enable_gpu {
match gpu::Window::new(config) {
Ok(window) => return Ok(Window(Box::new(window))),
Err(err) => eprintln!(
"Failed to create gpu window: {}\nFalling back to cpu window",
"Failed to create gpu window: {}\nFalling back tp cpu window",
err
),
}
}
cpu::run(Box::new(update));
cpu::Window::new().map(|window| Window(Box::new(window)))
}
pub fn begin_frame(&mut self) -> Input {
self.0.begin_frame()
}
pub fn end_frame(&mut self, framebuffer: &[u8], palette: &[u8], next_frame: Instant) {
self.0.end_frame(framebuffer, palette, next_frame)
}
pub fn is_open(&self) -> bool {
self.0.is_open()
}
}
pub trait Framebuffer {
fn update(&mut self, pixels: &[u8], palette: &[u8]);
#[derive(Debug)]
pub struct WindowConfig {
enable_gpu: bool,
filter: u32,
fullscreen: bool,
}
impl Default for WindowConfig {
fn default() -> WindowConfig {
WindowConfig {
enable_gpu: true,
filter: 5,
fullscreen: false,
}
}
}
impl WindowConfig {
pub fn parse_arguments(&mut self, args: &mut pico_args::Arguments) {
self.enable_gpu = !args.contains("--no-gpu");
if let Some(filter) = args.opt_value_from_str::<_, String>("--filter").unwrap() {
self.filter = match filter.as_str() {
"1" | "nearest" => 1,
"2" | "fast_crt" => 2,
"3" | "ss_crt" => 3,
"4" | "chromatic" => 4,
"5" | "auto_crt" => 5,
o => {
println!("Unknown --filter '{}'", o);
std::process::exit(1);
}
}
}
self.fullscreen = args.contains("--fullscreen");
}
}
pub struct Input {
pub gamepads: [u8; 4],
pub reset: bool,
}
trait WindowImpl {
fn begin_frame(&mut self) -> Input;
fn end_frame(&mut self, framebuffer: &[u8], palette: &[u8], next_frame: Instant);
fn is_open(&self) -> bool;
}

View File

@@ -1,10 +1,13 @@
use std::time::Instant;
use uw8_window::WindowConfig;
fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let mut args = pico_args::Arguments::from_env();
let mut framebuffer = vec![0u8; 320 * 240];
let start_time = Instant::now();
let mut start_time = Instant::now();
let mut palette = vec![0u32; 256];
for i in 0..256 {
@@ -18,11 +21,19 @@ fn main() {
let mut fps_start = Instant::now();
let mut fps_counter = 0;
uw8_window::run(true, move |gpu_framebuffer, _gamepads, _reset| {
for _ in 0..1 {
draw_frame(&mut framebuffer, start_time.elapsed().as_secs_f32());
let mut window_config = WindowConfig::default();
window_config.parse_arguments(&mut args);
let mut window = uw8_window::Window::new(window_config).unwrap();
while window.is_open() {
let input = window.begin_frame();
if input.reset {
start_time = Instant::now();
}
gpu_framebuffer.update(&framebuffer, bytemuck::cast_slice(&palette));
draw_frame(&mut framebuffer, start_time.elapsed().as_secs_f32());
window.end_frame(&framebuffer, bytemuck::cast_slice(&palette), Instant::now());
fps_counter += 1;
let elapsed = fps_start.elapsed().as_secs_f32();
if elapsed >= 1.0 {
@@ -30,8 +41,7 @@ fn main() {
fps_start = Instant::now();
fps_counter = 0;
}
Instant::now()
});
}
}
fn draw_frame(framebuffer: &mut [u8], time: f32) {