Merge remote-tracking branch 'origin/wlvk' into next-dash-interface
[skip ci]
This commit is contained in:
162
Cargo.lock
generated
162
Cargo.lock
generated
@@ -376,16 +376,16 @@ dependencies = [
|
|||||||
"futures-lite",
|
"futures-lite",
|
||||||
"parking",
|
"parking",
|
||||||
"polling",
|
"polling",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"slab",
|
"slab",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-lock"
|
name = "async-lock"
|
||||||
version = "3.4.1"
|
version = "3.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
|
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"event-listener-strategy",
|
"event-listener-strategy",
|
||||||
@@ -418,7 +418,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -444,7 +444,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"slab",
|
"slab",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -874,7 +874,7 @@ checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"polling",
|
"polling",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"slab",
|
"slab",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -898,16 +898,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
|
checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"calloop 0.14.3",
|
"calloop 0.14.3",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.49"
|
version = "1.2.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
|
checksum = "9f50d563227a1c37cc0a263f64eca3334388c01c5e4c4861a9def205c614383c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -1637,46 +1637,12 @@ version = "0.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "drm"
|
|
||||||
version = "0.14.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.10.0",
|
|
||||||
"bytemuck",
|
|
||||||
"drm-ffi",
|
|
||||||
"drm-fourcc",
|
|
||||||
"libc",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "drm-ffi"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d8e41459d99a9b529845f6d2c909eb9adf3b6d2f82635ae40be8de0601726e8b"
|
|
||||||
dependencies = [
|
|
||||||
"drm-sys",
|
|
||||||
"rustix 0.38.44",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drm-fourcc"
|
name = "drm-fourcc"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
|
checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "drm-sys"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys 0.6.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
@@ -2216,7 +2182,7 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2321,17 +2287,6 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gl_generator"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
|
|
||||||
dependencies = [
|
|
||||||
"khronos_api",
|
|
||||||
"log",
|
|
||||||
"xml-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glam"
|
name = "glam"
|
||||||
version = "0.30.9"
|
version = "0.30.9"
|
||||||
@@ -2974,9 +2929,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.15"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jiff"
|
name = "jiff"
|
||||||
@@ -3071,22 +3026,6 @@ dependencies = [
|
|||||||
"ucd-trie",
|
"ucd-trie",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "khronos-egl"
|
|
||||||
version = "6.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "khronos_api"
|
|
||||||
version = "3.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kurbo"
|
name = "kurbo"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
@@ -3234,12 +3173,6 @@ version = "0.4.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@@ -3530,9 +3463,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "ntapi"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
@@ -4315,7 +4248,7 @@ dependencies = [
|
|||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"hermit-abi 0.5.2",
|
"hermit-abi 0.5.2",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4541,9 +4474,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rangemap"
|
name = "rangemap"
|
||||||
version = "1.7.0"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c"
|
checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rav1e"
|
name = "rav1e"
|
||||||
@@ -4877,9 +4810,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.1.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
|
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"errno",
|
"errno",
|
||||||
@@ -4905,9 +4838,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.20"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
@@ -5005,15 +4938,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.145"
|
version = "1.0.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
|
checksum = "6af14725505314343e673e9ecb7cd7e8a36aa9791eb936235a3567cc31447ae4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
"ryu",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5221,24 +5154,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "740cea6927892bc182d5bf70c8f79806c8bc9f68f2fb96e55a30be171b63af98"
|
checksum = "740cea6927892bc182d5bf70c8f79806c8bc9f68f2fb96e55a30be171b63af98"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"appendlist",
|
"appendlist",
|
||||||
|
"ash",
|
||||||
"atomic_float",
|
"atomic_float",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"calloop 0.14.3",
|
"calloop 0.14.3",
|
||||||
"cgmath",
|
"cgmath",
|
||||||
"cursor-icon",
|
"cursor-icon",
|
||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"drm",
|
|
||||||
"drm-ffi",
|
|
||||||
"drm-fourcc",
|
"drm-fourcc",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"errno",
|
"errno",
|
||||||
"gl_generator",
|
|
||||||
"indexmap 2.12.1",
|
"indexmap 2.12.1",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading",
|
|
||||||
"profiling",
|
"profiling",
|
||||||
"rand",
|
"rand",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"sha2",
|
"sha2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -5293,7 +5223,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
@@ -5570,14 +5500,14 @@ checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.23.0"
|
version = "3.24.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
|
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.3.4",
|
"getrandom 0.3.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6275,7 +6205,7 @@ checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"wayland-sys",
|
"wayland-sys",
|
||||||
@@ -6288,7 +6218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
|
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-scanner",
|
"wayland-scanner",
|
||||||
]
|
]
|
||||||
@@ -6310,21 +6240,11 @@ version = "0.31.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
|
checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
"xcursor",
|
"xcursor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-egl"
|
|
||||||
version = "0.32.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d36232ee23ba3ea34a6835d68ca1af91d3ca3d6eddcf9c7147c4e0e66901b9fd"
|
|
||||||
dependencies = [
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols"
|
name = "wayland-protocols"
|
||||||
version = "0.32.9"
|
version = "0.32.9"
|
||||||
@@ -6411,7 +6331,7 @@ checksum = "fcbd4f3aba6c9fba70445ad2a484c0ef0356c1a9459b1e8e435bedc1971a6222"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-scanner",
|
"wayland-scanner",
|
||||||
]
|
]
|
||||||
@@ -7094,7 +7014,6 @@ dependencies = [
|
|||||||
"interprocess",
|
"interprocess",
|
||||||
"json",
|
"json",
|
||||||
"json5 1.3.0",
|
"json5 1.3.0",
|
||||||
"khronos-egl",
|
|
||||||
"libc",
|
"libc",
|
||||||
"libmonado",
|
"libmonado",
|
||||||
"log",
|
"log",
|
||||||
@@ -7123,7 +7042,6 @@ dependencies = [
|
|||||||
"vulkano",
|
"vulkano",
|
||||||
"vulkano-shaders",
|
"vulkano-shaders",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
"wayland-egl",
|
|
||||||
"wayvr-ipc",
|
"wayvr-ipc",
|
||||||
"wgui",
|
"wgui",
|
||||||
"winit",
|
"winit",
|
||||||
@@ -7162,7 +7080,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"libloading",
|
"libloading",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.1.2",
|
"rustix 1.1.3",
|
||||||
"x11rb-protocol",
|
"x11rb-protocol",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7467,6 +7385,12 @@ dependencies = [
|
|||||||
"syn 2.0.111",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e404bcd8afdaf006e529269d3e85a743f9480c3cef60034d77860d02964f3ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-core"
|
name = "zune-core"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -7484,9 +7408,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-jpeg"
|
name = "zune-jpeg"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51d915729b0e7d5fe35c2f294c5dc10b30207cc637920e5b59077bfa3da63f28"
|
checksum = "e35aee689668bf9bd6f6f3a6c60bb29ba1244b3b43adfd50edd554a371da37d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zune-core",
|
"zune-core",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -315,93 +315,16 @@ impl WayVRClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fn_wvr_display_list(
|
pub async fn fn_wvr_window_list(
|
||||||
client: WayVRClientMutex,
|
client: WayVRClientMutex,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
) -> anyhow::Result<Vec<packet_server::WvrDisplay>> {
|
|
||||||
Ok(
|
|
||||||
send_and_wait!(
|
|
||||||
client,
|
|
||||||
serial,
|
|
||||||
&PacketClient::WvrDisplayList(serial),
|
|
||||||
WvrDisplayListResponse
|
|
||||||
)
|
|
||||||
.list,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fn_wvr_display_get(
|
|
||||||
client: WayVRClientMutex,
|
|
||||||
serial: Serial,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) -> anyhow::Result<Option<packet_server::WvrDisplay>> {
|
|
||||||
Ok(send_and_wait!(
|
|
||||||
client,
|
|
||||||
serial,
|
|
||||||
&PacketClient::WvrDisplayGet(serial, handle),
|
|
||||||
WvrDisplayGetResponse
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fn_wvr_display_remove(
|
|
||||||
client: WayVRClientMutex,
|
|
||||||
serial: Serial,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
send_and_wait!(
|
|
||||||
client,
|
|
||||||
serial,
|
|
||||||
&PacketClient::WvrDisplayRemove(serial, handle),
|
|
||||||
WvrDisplayRemoveResponse
|
|
||||||
)
|
|
||||||
.map_err(|e| anyhow::anyhow!("{}", e))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fn_wvr_display_create(
|
|
||||||
client: WayVRClientMutex,
|
|
||||||
serial: Serial,
|
|
||||||
params: packet_client::WvrDisplayCreateParams,
|
|
||||||
) -> anyhow::Result<packet_server::WvrDisplayHandle> {
|
|
||||||
Ok(send_and_wait!(
|
|
||||||
client,
|
|
||||||
serial,
|
|
||||||
&PacketClient::WvrDisplayCreate(serial, params),
|
|
||||||
WvrDisplayCreateResponse
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fn_wvr_display_set_visible(
|
|
||||||
client: WayVRClientMutex,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
visible: bool,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
send_only!(client, &PacketClient::WvrDisplaySetVisible(handle, visible));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fn_wvr_display_set_layout(
|
|
||||||
client: WayVRClientMutex,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
layout: packet_server::WvrDisplayWindowLayout,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
send_only!(
|
|
||||||
client,
|
|
||||||
&PacketClient::WvrDisplaySetWindowLayout(handle, layout)
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fn_wvr_display_window_list(
|
|
||||||
client: WayVRClientMutex,
|
|
||||||
serial: Serial,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) -> anyhow::Result<Option<Vec<packet_server::WvrWindow>>> {
|
) -> anyhow::Result<Option<Vec<packet_server::WvrWindow>>> {
|
||||||
Ok(
|
Ok(
|
||||||
send_and_wait!(
|
send_and_wait!(
|
||||||
client,
|
client,
|
||||||
serial,
|
serial,
|
||||||
&PacketClient::WvrDisplayWindowList(serial, handle),
|
&PacketClient::WvrWindowList(serial),
|
||||||
WvrDisplayWindowListResponse
|
WvrWindowListResponse
|
||||||
)
|
)
|
||||||
.map(|res| res.list),
|
.map(|res| res.list),
|
||||||
)
|
)
|
||||||
@@ -478,11 +401,12 @@ impl WayVRClient {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fn_wlx_haptics(
|
pub async fn fn_wlx_device_haptics(
|
||||||
client: WayVRClientMutex,
|
client: WayVRClientMutex,
|
||||||
|
device: usize,
|
||||||
params: packet_client::WlxHapticsParams,
|
params: packet_client::WlxHapticsParams,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
send_only!(client, &PacketClient::WlxHaptics(params));
|
send_only!(client, &PacketClient::WlxDeviceHaptics(device, params));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,22 +67,13 @@ pub struct WlxModifyPanelParams {
|
|||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum PacketClient {
|
pub enum PacketClient {
|
||||||
Handshake(Handshake),
|
Handshake(Handshake),
|
||||||
WvrDisplayCreate(Serial, WvrDisplayCreateParams),
|
WvrWindowList(Serial),
|
||||||
WvrDisplayGet(Serial, packet_server::WvrDisplayHandle),
|
|
||||||
WvrDisplayList(Serial),
|
|
||||||
WvrDisplayRemove(Serial, packet_server::WvrDisplayHandle),
|
|
||||||
WvrDisplaySetVisible(packet_server::WvrDisplayHandle, bool),
|
|
||||||
WvrDisplayWindowList(Serial, packet_server::WvrDisplayHandle),
|
|
||||||
WvrDisplaySetWindowLayout(
|
|
||||||
packet_server::WvrDisplayHandle,
|
|
||||||
packet_server::WvrDisplayWindowLayout,
|
|
||||||
),
|
|
||||||
WvrWindowSetVisible(packet_server::WvrWindowHandle, bool),
|
WvrWindowSetVisible(packet_server::WvrWindowHandle, bool),
|
||||||
WvrProcessGet(Serial, packet_server::WvrProcessHandle),
|
WvrProcessGet(Serial, packet_server::WvrProcessHandle),
|
||||||
WvrProcessLaunch(Serial, WvrProcessLaunchParams),
|
WvrProcessLaunch(Serial, WvrProcessLaunchParams),
|
||||||
WvrProcessList(Serial),
|
WvrProcessList(Serial),
|
||||||
WvrProcessTerminate(packet_server::WvrProcessHandle),
|
WvrProcessTerminate(packet_server::WvrProcessHandle),
|
||||||
WlxHaptics(WlxHapticsParams),
|
|
||||||
WlxInputState(Serial),
|
WlxInputState(Serial),
|
||||||
WlxModifyPanel(WlxModifyPanelParams),
|
WlxModifyPanel(WlxModifyPanelParams),
|
||||||
|
WlxDeviceHaptics(usize, WlxHapticsParams),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,14 +48,11 @@ pub struct WvrDisplay {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct WvrWindow {
|
pub struct WvrWindow {
|
||||||
pub pos_x: i32,
|
|
||||||
pub pos_y: i32,
|
|
||||||
pub size_x: u32,
|
pub size_x: u32,
|
||||||
pub size_y: u32,
|
pub size_y: u32,
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
pub handle: WvrWindowHandle,
|
pub handle: WvrWindowHandle,
|
||||||
pub process_handle: WvrProcessHandle,
|
pub process_handle: WvrProcessHandle,
|
||||||
pub display_handle: WvrDisplayHandle,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -71,7 +68,6 @@ pub struct WvrWindowList {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct WvrProcess {
|
pub struct WvrProcess {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub display_handle: WvrDisplayHandle,
|
|
||||||
pub handle: WvrProcessHandle,
|
pub handle: WvrProcessHandle,
|
||||||
pub userdata: HashMap<String, String>,
|
pub userdata: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
@@ -103,8 +99,6 @@ pub enum WvrDisplayWindowLayout {
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub enum WvrStateChanged {
|
pub enum WvrStateChanged {
|
||||||
DisplayCreated,
|
|
||||||
DisplayRemoved,
|
|
||||||
ProcessCreated,
|
ProcessCreated,
|
||||||
ProcessRemoved,
|
ProcessRemoved,
|
||||||
WindowCreated,
|
WindowCreated,
|
||||||
@@ -132,11 +126,7 @@ pub enum PacketServer {
|
|||||||
Disconnect(Disconnect),
|
Disconnect(Disconnect),
|
||||||
HandshakeSuccess(HandshakeSuccess),
|
HandshakeSuccess(HandshakeSuccess),
|
||||||
WlxInputStateResponse(Serial, WlxInputState),
|
WlxInputStateResponse(Serial, WlxInputState),
|
||||||
WvrDisplayCreateResponse(Serial, WvrDisplayHandle),
|
WvrWindowListResponse(Serial, Option<WvrWindowList>),
|
||||||
WvrDisplayGetResponse(Serial, Option<WvrDisplay>),
|
|
||||||
WvrDisplayListResponse(Serial, WvrDisplayList),
|
|
||||||
WvrDisplayRemoveResponse(Serial, Result<(), String>),
|
|
||||||
WvrDisplayWindowListResponse(Serial, Option<WvrWindowList>),
|
|
||||||
WvrProcessGetResponse(Serial, Option<WvrProcess>),
|
WvrProcessGetResponse(Serial, Option<WvrProcess>),
|
||||||
WvrProcessLaunchResponse(Serial, Result<WvrProcessHandle, String>),
|
WvrProcessLaunchResponse(Serial, Result<WvrProcessHandle, String>),
|
||||||
WvrProcessListResponse(Serial, WvrProcessList),
|
WvrProcessListResponse(Serial, WvrProcessList),
|
||||||
@@ -149,11 +139,7 @@ impl PacketServer {
|
|||||||
PacketServer::Disconnect(_) => None,
|
PacketServer::Disconnect(_) => None,
|
||||||
PacketServer::HandshakeSuccess(_) => None,
|
PacketServer::HandshakeSuccess(_) => None,
|
||||||
PacketServer::WlxInputStateResponse(serial, _) => Some(serial),
|
PacketServer::WlxInputStateResponse(serial, _) => Some(serial),
|
||||||
PacketServer::WvrDisplayCreateResponse(serial, _) => Some(serial),
|
PacketServer::WvrWindowListResponse(serial, _) => Some(serial),
|
||||||
PacketServer::WvrDisplayGetResponse(serial, _) => Some(serial),
|
|
||||||
PacketServer::WvrDisplayListResponse(serial, _) => Some(serial),
|
|
||||||
PacketServer::WvrDisplayRemoveResponse(serial, _) => Some(serial),
|
|
||||||
PacketServer::WvrDisplayWindowListResponse(serial, _) => Some(serial),
|
|
||||||
PacketServer::WvrProcessGetResponse(serial, _) => Some(serial),
|
PacketServer::WvrProcessGetResponse(serial, _) => Some(serial),
|
||||||
PacketServer::WvrProcessLaunchResponse(serial, _) => Some(serial),
|
PacketServer::WvrProcessLaunchResponse(serial, _) => Some(serial),
|
||||||
PacketServer::WvrProcessListResponse(serial, _) => Some(serial),
|
PacketServer::WvrProcessListResponse(serial, _) => Some(serial),
|
||||||
|
|||||||
@@ -37,104 +37,18 @@ fn handle_result<T: Serialize>(pretty_print: bool, result: anyhow::Result<T>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wvr_display_create(
|
pub async fn wvr_window_list(state: &mut WayVRClientState) {
|
||||||
state: &mut WayVRClientState,
|
|
||||||
width: u16,
|
|
||||||
height: u16,
|
|
||||||
name: String,
|
|
||||||
scale: Option<f32>,
|
|
||||||
attach_to: packet_client::AttachTo,
|
|
||||||
) {
|
|
||||||
handle_result(
|
handle_result(
|
||||||
state.pretty_print,
|
state.pretty_print,
|
||||||
WayVRClient::fn_wvr_display_create(
|
WayVRClient::fn_wvr_window_list(
|
||||||
state.wayvr_client.clone(),
|
state.wayvr_client.clone(),
|
||||||
state.serial_generator.increment_get(),
|
state.serial_generator.increment_get(),
|
||||||
packet_client::WvrDisplayCreateParams {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
name,
|
|
||||||
scale,
|
|
||||||
attach_to,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.context("failed to create display"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wvr_display_list(state: &mut WayVRClientState) {
|
|
||||||
handle_result(
|
|
||||||
state.pretty_print,
|
|
||||||
WayVRClient::fn_wvr_display_list(
|
|
||||||
state.wayvr_client.clone(),
|
|
||||||
state.serial_generator.increment_get(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.context("failed to fetch displays"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wvr_display_get(
|
|
||||||
state: &mut WayVRClientState,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) {
|
|
||||||
handle_result(
|
|
||||||
state.pretty_print,
|
|
||||||
WayVRClient::fn_wvr_display_get(
|
|
||||||
state.wayvr_client.clone(),
|
|
||||||
state.serial_generator.increment_get(),
|
|
||||||
handle,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.context("failed to fetch display"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wvr_display_window_list(
|
|
||||||
state: &mut WayVRClientState,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) {
|
|
||||||
handle_result(
|
|
||||||
state.pretty_print,
|
|
||||||
WayVRClient::fn_wvr_display_window_list(
|
|
||||||
state.wayvr_client.clone(),
|
|
||||||
state.serial_generator.increment_get(),
|
|
||||||
handle,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("failed to list window displays"),
|
.context("failed to list window displays"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wvr_display_remove(
|
|
||||||
state: &mut WayVRClientState,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) {
|
|
||||||
handle_result(
|
|
||||||
state.pretty_print,
|
|
||||||
WayVRClient::fn_wvr_display_remove(
|
|
||||||
state.wayvr_client.clone(),
|
|
||||||
state.serial_generator.increment_get(),
|
|
||||||
handle,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.context("failed to remove display"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wvr_display_set_visible(
|
|
||||||
state: &mut WayVRClientState,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
visible: bool,
|
|
||||||
) {
|
|
||||||
handle_empty_result(
|
|
||||||
WayVRClient::fn_wvr_display_set_visible(state.wayvr_client.clone(), handle, visible)
|
|
||||||
.await
|
|
||||||
.context("failed to set display visibility"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wvr_window_set_visible(
|
pub async fn wvr_window_set_visible(
|
||||||
state: &mut WayVRClientState,
|
state: &mut WayVRClientState,
|
||||||
handle: packet_server::WvrWindowHandle,
|
handle: packet_server::WvrWindowHandle,
|
||||||
@@ -214,15 +128,17 @@ pub async fn wvr_process_launch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wlx_haptics(
|
pub async fn wlx_device_haptics(
|
||||||
state: &mut WayVRClientState,
|
state: &mut WayVRClientState,
|
||||||
|
device: usize,
|
||||||
intensity: f32,
|
intensity: f32,
|
||||||
duration: f32,
|
duration: f32,
|
||||||
frequency: f32,
|
frequency: f32,
|
||||||
) {
|
) {
|
||||||
handle_empty_result(
|
handle_empty_result(
|
||||||
WayVRClient::fn_wlx_haptics(
|
WayVRClient::fn_wlx_device_haptics(
|
||||||
state.wayvr_client.clone(),
|
state.wayvr_client.clone(),
|
||||||
|
device,
|
||||||
packet_client::WlxHapticsParams {
|
packet_client::WlxHapticsParams {
|
||||||
intensity,
|
intensity,
|
||||||
duration,
|
duration,
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ use env_logger::Env;
|
|||||||
use wayvr_ipc::{client::WayVRClient, ipc, packet_client};
|
use wayvr_ipc::{client::WayVRClient, ipc, packet_client};
|
||||||
|
|
||||||
use crate::helper::{
|
use crate::helper::{
|
||||||
WayVRClientState, wlx_haptics, wlx_input_state, wlx_panel_modify, wvr_display_create,
|
WayVRClientState, wlx_device_haptics, wlx_input_state, wlx_panel_modify, wvr_process_get,
|
||||||
wvr_display_get, wvr_display_list, wvr_display_remove, wvr_display_set_visible,
|
wvr_process_launch, wvr_process_list, wvr_process_terminate, wvr_window_list,
|
||||||
wvr_display_window_list, wvr_process_get, wvr_process_launch, wvr_process_list,
|
wvr_window_set_visible,
|
||||||
wvr_process_terminate, wvr_window_set_visible,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod helper;
|
mod helper;
|
||||||
@@ -76,12 +75,12 @@ async fn run_batch(state: &mut WayVRClientState, fail_fast: bool) -> anyhow::Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn parse_run_line(state: &mut WayVRClientState, line: &str) -> anyhow::Result<()> {
|
async fn parse_run_line(state: &mut WayVRClientState, line: &str) -> anyhow::Result<()> {
|
||||||
let mut argv = shell_words::split(&line).with_context(|| format!("parse error"))?;
|
let mut argv = shell_words::split(line).context("parse error")?;
|
||||||
|
|
||||||
// clap expects argv[0] to be the binary name
|
// clap expects argv[0] to be the binary name
|
||||||
argv.insert(0, env!("CARGO_PKG_NAME").to_string());
|
argv.insert(0, env!("CARGO_PKG_NAME").to_string());
|
||||||
|
|
||||||
let args = Args::try_parse_from(argv).with_context(|| format!("invalid arguments"))?;
|
let args = Args::try_parse_from(argv).context("invalid arguments")?;
|
||||||
run_once(state, args).await?;
|
run_once(state, args).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -95,43 +94,8 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()
|
|||||||
Subcommands::InputState => {
|
Subcommands::InputState => {
|
||||||
wlx_input_state(state).await;
|
wlx_input_state(state).await;
|
||||||
}
|
}
|
||||||
Subcommands::DisplayCreate {
|
Subcommands::WindowList => {
|
||||||
width,
|
wvr_window_list(state).await;
|
||||||
height,
|
|
||||||
name,
|
|
||||||
scale,
|
|
||||||
} => {
|
|
||||||
wvr_display_create(
|
|
||||||
state,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
name,
|
|
||||||
scale,
|
|
||||||
packet_client::AttachTo::None,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
Subcommands::DisplayList => {
|
|
||||||
wvr_display_list(state).await;
|
|
||||||
}
|
|
||||||
Subcommands::DisplayGet { handle } => {
|
|
||||||
let handle = serde_json::from_str(&handle).context("Invalid handle")?;
|
|
||||||
wvr_display_get(state, handle).await;
|
|
||||||
}
|
|
||||||
Subcommands::DisplayWindowList { handle } => {
|
|
||||||
let handle = serde_json::from_str(&handle).context("Invalid handle")?;
|
|
||||||
wvr_display_window_list(state, handle).await;
|
|
||||||
}
|
|
||||||
Subcommands::DisplayRemove { handle } => {
|
|
||||||
let handle = serde_json::from_str(&handle).context("Invalid handle")?;
|
|
||||||
wvr_display_remove(state, handle).await;
|
|
||||||
}
|
|
||||||
Subcommands::DisplaySetVisible {
|
|
||||||
handle,
|
|
||||||
visible_0_or_1,
|
|
||||||
} => {
|
|
||||||
let handle = serde_json::from_str(&handle).context("Invalid handle")?;
|
|
||||||
wvr_display_set_visible(state, handle, visible_0_or_1 != 0).await;
|
|
||||||
}
|
}
|
||||||
Subcommands::WindowSetVisible {
|
Subcommands::WindowSetVisible {
|
||||||
handle,
|
handle,
|
||||||
@@ -162,11 +126,12 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()
|
|||||||
wvr_process_launch(state, exec, name, env, handle, args, HashMap::new()).await;
|
wvr_process_launch(state, exec, name, env, handle, args, HashMap::new()).await;
|
||||||
}
|
}
|
||||||
Subcommands::Haptics {
|
Subcommands::Haptics {
|
||||||
|
device,
|
||||||
intensity,
|
intensity,
|
||||||
duration,
|
duration,
|
||||||
frequency,
|
frequency,
|
||||||
} => {
|
} => {
|
||||||
wlx_haptics(state, intensity, duration, frequency).await;
|
wlx_device_haptics(state, device, intensity, duration, frequency).await;
|
||||||
}
|
}
|
||||||
Subcommands::PanelModify {
|
Subcommands::PanelModify {
|
||||||
overlay,
|
overlay,
|
||||||
@@ -220,39 +185,9 @@ enum Subcommands {
|
|||||||
},
|
},
|
||||||
/// Get the positions of HMD & controllers
|
/// Get the positions of HMD & controllers
|
||||||
InputState,
|
InputState,
|
||||||
/// Create a new WayVR display
|
/// List WayVR windows
|
||||||
DisplayCreate {
|
WindowList,
|
||||||
width: u16,
|
|
||||||
height: u16,
|
|
||||||
name: String,
|
|
||||||
#[arg(short, long)]
|
|
||||||
scale: Option<f32>,
|
|
||||||
//attach_to: packet_client::AttachTo,
|
|
||||||
},
|
|
||||||
/// List WayVR displays
|
|
||||||
DisplayList,
|
|
||||||
/// Retrieve information about a single WayVR display
|
|
||||||
DisplayGet {
|
|
||||||
/// A display handle JSON returned by DisplayList or DisplayCreate
|
|
||||||
handle: String,
|
|
||||||
},
|
|
||||||
/// List windows attached to a WayVR display
|
|
||||||
DisplayWindowList {
|
|
||||||
/// A display handle JSON returned by DisplayList or DisplayCreate
|
|
||||||
handle: String,
|
|
||||||
},
|
|
||||||
/// Delete a WayVR display
|
/// Delete a WayVR display
|
||||||
DisplayRemove {
|
|
||||||
/// A display handle JSON returned by DisplayList or DisplayCreate
|
|
||||||
handle: String,
|
|
||||||
},
|
|
||||||
/// Change the visibility of a WayVR display
|
|
||||||
DisplaySetVisible {
|
|
||||||
/// A display handle JSON returned by DisplayList or DisplayCreate
|
|
||||||
handle: String,
|
|
||||||
visible_0_or_1: u8,
|
|
||||||
},
|
|
||||||
|
|
||||||
// DisplaySetLayout skipped
|
// DisplaySetLayout skipped
|
||||||
/// Change the visibility of a window on a WayVR display
|
/// Change the visibility of a window on a WayVR display
|
||||||
WindowSetVisible {
|
WindowSetVisible {
|
||||||
@@ -283,6 +218,8 @@ enum Subcommands {
|
|||||||
},
|
},
|
||||||
/// Trigger haptics on the user's controller
|
/// Trigger haptics on the user's controller
|
||||||
Haptics {
|
Haptics {
|
||||||
|
/// 0 for left, 1 for right controller
|
||||||
|
device: usize,
|
||||||
#[arg(short, long, default_value = "0.25")]
|
#[arg(short, long, default_value = "0.25")]
|
||||||
intensity: f32,
|
intensity: f32,
|
||||||
#[arg(short, long, default_value = "0.1")]
|
#[arg(short, long, default_value = "0.1")]
|
||||||
|
|||||||
@@ -1,47 +1,6 @@
|
|||||||
use std::{fmt::Display, os::fd::RawFd};
|
use std::os::fd::RawFd;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
use drm_fourcc::{DrmFormat, DrmModifier};
|
||||||
pub struct FourCC {
|
|
||||||
pub value: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for FourCC {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.value == other.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u32> for FourCC {
|
|
||||||
fn from(value: u32) -> Self {
|
|
||||||
Self { value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FourCC> for u32 {
|
|
||||||
fn from(fourcc: FourCC) -> Self {
|
|
||||||
fourcc.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for FourCC {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
for i in 0..4 {
|
|
||||||
if let Some(c) = char::from_u32((self.value >> (i * 8)) & 0xFF) {
|
|
||||||
write!(f, "{c}")?
|
|
||||||
} else {
|
|
||||||
write!(f, "?")?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const DRM_FORMAT_ARGB8888: u32 = 0x34325241; // AR24
|
|
||||||
pub const DRM_FORMAT_ABGR8888: u32 = 0x34324241; // AB24
|
|
||||||
pub const DRM_FORMAT_XRGB8888: u32 = 0x34325258; // XR24
|
|
||||||
pub const DRM_FORMAT_XBGR8888: u32 = 0x34324258; // XB24
|
|
||||||
pub const DRM_FORMAT_ABGR2101010: u32 = 0x30334241; // AB30
|
|
||||||
pub const DRM_FORMAT_XBGR2101010: u32 = 0x30334258; // XB30
|
|
||||||
|
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
@@ -73,24 +32,27 @@ pub enum Transform {
|
|||||||
Flipped270,
|
Flipped270,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct FrameFormat {
|
pub struct FrameFormat {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
pub fourcc: FourCC,
|
pub drm_format: DrmFormat,
|
||||||
pub modifier: u64,
|
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameFormat {
|
impl FrameFormat {
|
||||||
|
#[must_use]
|
||||||
pub fn get_mod_hi(&self) -> u32 {
|
pub fn get_mod_hi(&self) -> u32 {
|
||||||
(self.modifier >> 32) as _
|
let m = u64::from(self.drm_format.modifier);
|
||||||
|
(m >> 32) as _
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub fn get_mod_lo(&self) -> u32 {
|
pub fn get_mod_lo(&self) -> u32 {
|
||||||
(self.modifier & 0xFFFFFFFF) as _
|
let m = u64::from(self.drm_format.modifier);
|
||||||
|
(m & 0xFFFFFFFF) as _
|
||||||
}
|
}
|
||||||
pub fn set_mod(&mut self, mod_hi: u32, mod_low: u32) {
|
pub fn set_mod(&mut self, mod_hi: u32, mod_low: u32) {
|
||||||
self.modifier = ((mod_hi as u64) << 32) + mod_low as u64;
|
self.drm_format.modifier = DrmModifier::from(((mod_hi as u64) << 32) + mod_low as u64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,13 +63,6 @@ pub struct FramePlane {
|
|||||||
pub stride: i32,
|
pub stride: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
|
||||||
pub struct DrmFormat {
|
|
||||||
pub fourcc: FourCC,
|
|
||||||
pub modifiers: Vec<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DmabufFrame {
|
pub struct DmabufFrame {
|
||||||
pub format: FrameFormat,
|
pub format: FrameFormat,
|
||||||
pub num_planes: usize,
|
pub num_planes: usize,
|
||||||
@@ -126,7 +81,7 @@ impl DmabufFrame {
|
|||||||
0x3056, // HEIGHT
|
0x3056, // HEIGHT
|
||||||
self.format.height as _,
|
self.format.height as _,
|
||||||
0x3271, // LINUX_DRM_FOURCC_EXT,
|
0x3271, // LINUX_DRM_FOURCC_EXT,
|
||||||
self.format.fourcc.value as _,
|
self.format.drm_format.code as _,
|
||||||
];
|
];
|
||||||
|
|
||||||
for i in 0..self.num_planes {
|
for i in 0..self.num_planes {
|
||||||
@@ -162,14 +117,12 @@ impl DmabufFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct MemFdFrame {
|
pub struct MemFdFrame {
|
||||||
pub format: FrameFormat,
|
pub format: FrameFormat,
|
||||||
pub plane: FramePlane,
|
pub plane: FramePlane,
|
||||||
pub mouse: Option<MouseMeta>,
|
pub mouse: Option<MouseMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct MemPtrFrame {
|
pub struct MemPtrFrame {
|
||||||
pub format: FrameFormat,
|
pub format: FrameFormat,
|
||||||
pub ptr: usize,
|
pub ptr: usize,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![allow(clippy::expect_fun_call)]
|
#![allow(clippy::expect_fun_call)]
|
||||||
|
|
||||||
use frame::{DrmFormat, WlxFrame};
|
pub use drm_fourcc::{DrmFormat, DrmFourcc, DrmModifier};
|
||||||
|
use frame::WlxFrame;
|
||||||
|
|
||||||
pub mod frame;
|
pub mod frame;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::AtomicU32;
|
use std::sync::atomic::AtomicU32;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
@@ -12,6 +13,9 @@ use ashpd::desktop::{
|
|||||||
|
|
||||||
pub use ashpd::Error as AshpdError;
|
pub use ashpd::Error as AshpdError;
|
||||||
|
|
||||||
|
use drm_fourcc::DrmFormat;
|
||||||
|
use drm_fourcc::DrmFourcc;
|
||||||
|
use drm_fourcc::DrmModifier;
|
||||||
use pipewire as pw;
|
use pipewire as pw;
|
||||||
use pw::spa;
|
use pw::spa;
|
||||||
|
|
||||||
@@ -33,14 +37,6 @@ use spa::utils::ChoiceEnum;
|
|||||||
use spa::utils::ChoiceFlags;
|
use spa::utils::ChoiceFlags;
|
||||||
|
|
||||||
use crate::WlxCapture;
|
use crate::WlxCapture;
|
||||||
use crate::frame::DRM_FORMAT_ABGR8888;
|
|
||||||
use crate::frame::DRM_FORMAT_ABGR2101010;
|
|
||||||
use crate::frame::DRM_FORMAT_ARGB8888;
|
|
||||||
use crate::frame::DRM_FORMAT_XBGR8888;
|
|
||||||
use crate::frame::DRM_FORMAT_XBGR2101010;
|
|
||||||
use crate::frame::DRM_FORMAT_XRGB8888;
|
|
||||||
use crate::frame::DrmFormat;
|
|
||||||
use crate::frame::FourCC;
|
|
||||||
use crate::frame::FrameFormat;
|
use crate::frame::FrameFormat;
|
||||||
use crate::frame::MouseMeta;
|
use crate::frame::MouseMeta;
|
||||||
use crate::frame::Transform;
|
use crate::frame::Transform;
|
||||||
@@ -297,7 +293,15 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let _listener = stream
|
let _listener = stream
|
||||||
.add_local_listener_with_user_data(FrameFormat::default())
|
.add_local_listener_with_user_data(FrameFormat {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
drm_format: DrmFormat {
|
||||||
|
code: DrmFourcc::Argb8888,
|
||||||
|
modifier: DrmModifier::Invalid,
|
||||||
|
},
|
||||||
|
transform: Transform::Undefined,
|
||||||
|
})
|
||||||
.state_changed({
|
.state_changed({
|
||||||
let name = name.clone();
|
let name = name.clone();
|
||||||
move |_, _, old, new| {
|
move |_, _, old, new| {
|
||||||
@@ -320,10 +324,10 @@ where
|
|||||||
|
|
||||||
format.width = info.size().width;
|
format.width = info.size().width;
|
||||||
format.height = info.size().height;
|
format.height = info.size().height;
|
||||||
format.fourcc = spa_to_fourcc(info.format());
|
format.drm_format.code = spa_to_fourcc(info.format());
|
||||||
format.modifier = info.modifier();
|
format.drm_format.modifier = DrmModifier::from(info.modifier());
|
||||||
|
|
||||||
let kind = if format.modifier != 0 {
|
let kind = if info.modifier() != 0 {
|
||||||
"DMA-buf"
|
"DMA-buf"
|
||||||
} else {
|
} else {
|
||||||
"SHM"
|
"SHM"
|
||||||
@@ -425,7 +429,7 @@ where
|
|||||||
format: *format,
|
format: *format,
|
||||||
num_planes: planes.len(),
|
num_planes: planes.len(),
|
||||||
mouse: mouse_meta,
|
mouse: mouse_meta,
|
||||||
..Default::default()
|
planes: Default::default(),
|
||||||
};
|
};
|
||||||
dmabuf.planes[..planes.len()].copy_from_slice(&planes[..planes.len()]);
|
dmabuf.planes[..planes.len()].copy_from_slice(&planes[..planes.len()]);
|
||||||
|
|
||||||
@@ -494,7 +498,17 @@ where
|
|||||||
})
|
})
|
||||||
.register()?;
|
.register()?;
|
||||||
|
|
||||||
let mut format_params: Vec<Vec<u8>> = dmabuf_formats
|
let mut fourcc_mods: HashMap<DrmFourcc, Vec<DrmModifier>> = HashMap::new();
|
||||||
|
|
||||||
|
for f in dmabuf_formats.iter() {
|
||||||
|
if let Some(v) = fourcc_mods.get_mut(&f.code) {
|
||||||
|
v.push(f.modifier);
|
||||||
|
} else {
|
||||||
|
fourcc_mods.insert(f.code, vec![f.modifier]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut format_params: Vec<Vec<u8>> = fourcc_mods
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|f| obj_to_bytes(get_format_params(Some(f))).ok())
|
.filter_map(|f| obj_to_bytes(get_format_params(Some(f))).ok())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -591,7 +605,7 @@ fn get_meta_object(key: u32, size: usize) -> Object {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_format_params(fmt: Option<&DrmFormat>) -> Object {
|
fn get_format_params(fmt: Option<(&DrmFourcc, &Vec<DrmModifier>)>) -> Object {
|
||||||
let mut obj = spa::pod::object!(
|
let mut obj = spa::pod::object!(
|
||||||
spa::utils::SpaTypes::ObjectParamFormat,
|
spa::utils::SpaTypes::ObjectParamFormat,
|
||||||
spa::param::ParamType::EnumFormat,
|
spa::param::ParamType::EnumFormat,
|
||||||
@@ -638,7 +652,7 @@ fn get_format_params(fmt: Option<&DrmFormat>) -> Object {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(fmt) = fmt {
|
if let Some(fmt) = fmt {
|
||||||
let spa_fmt = fourcc_to_spa(fmt.fourcc);
|
let spa_fmt = fourcc_to_spa(*fmt.0);
|
||||||
|
|
||||||
let prop = spa::pod::property!(
|
let prop = spa::pod::property!(
|
||||||
spa::param::format::FormatProperties::VideoFormat,
|
spa::param::format::FormatProperties::VideoFormat,
|
||||||
@@ -657,8 +671,8 @@ fn get_format_params(fmt: Option<&DrmFormat>) -> Object {
|
|||||||
value: Value::Choice(ChoiceValue::Long(Choice(
|
value: Value::Choice(ChoiceValue::Long(Choice(
|
||||||
ChoiceFlags::empty(),
|
ChoiceFlags::empty(),
|
||||||
ChoiceEnum::Enum {
|
ChoiceEnum::Enum {
|
||||||
default: fmt.modifiers[0] as _,
|
default: u64::from(fmt.1[0]) as _,
|
||||||
alternatives: fmt.modifiers.iter().map(|m| *m as _).collect(),
|
alternatives: fmt.1.iter().map(|m| u64::from(*m) as _).collect(),
|
||||||
},
|
},
|
||||||
))),
|
))),
|
||||||
};
|
};
|
||||||
@@ -683,27 +697,27 @@ fn get_format_params(fmt: Option<&DrmFormat>) -> Object {
|
|||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fourcc_to_spa(fourcc: FourCC) -> VideoFormat {
|
fn fourcc_to_spa(fourcc: DrmFourcc) -> VideoFormat {
|
||||||
match fourcc.value {
|
match fourcc{
|
||||||
DRM_FORMAT_ARGB8888 => VideoFormat::BGRA,
|
DrmFourcc::Argb8888 => VideoFormat::BGRA,
|
||||||
DRM_FORMAT_ABGR8888 => VideoFormat::RGBA,
|
DrmFourcc::Abgr8888 => VideoFormat::RGBA,
|
||||||
DRM_FORMAT_XRGB8888 => VideoFormat::BGRx,
|
DrmFourcc::Xrgb8888 => VideoFormat::BGRx,
|
||||||
DRM_FORMAT_XBGR8888 => VideoFormat::RGBx,
|
DrmFourcc::Xbgr8888 => VideoFormat::RGBx,
|
||||||
DRM_FORMAT_ABGR2101010 => VideoFormat::ABGR_210LE,
|
DrmFourcc::Abgr2101010 => VideoFormat::ABGR_210LE,
|
||||||
DRM_FORMAT_XBGR2101010 => VideoFormat::xBGR_210LE,
|
DrmFourcc::Xbgr2101010 => VideoFormat::xBGR_210LE,
|
||||||
_ => panic!("Unsupported format"),
|
_ => panic!("Unsupported format"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
fn spa_to_fourcc(spa: VideoFormat) -> FourCC {
|
fn spa_to_fourcc(spa: VideoFormat) -> DrmFourcc {
|
||||||
match spa {
|
match spa {
|
||||||
VideoFormat::BGRA => DRM_FORMAT_ARGB8888.into(),
|
VideoFormat::BGRA => DrmFourcc::Argb8888,
|
||||||
VideoFormat::RGBA => DRM_FORMAT_ABGR8888.into(),
|
VideoFormat::RGBA => DrmFourcc::Abgr8888,
|
||||||
VideoFormat::BGRx => DRM_FORMAT_XRGB8888.into(),
|
VideoFormat::BGRx => DrmFourcc::Xrgb8888,
|
||||||
VideoFormat::RGBx => DRM_FORMAT_XBGR8888.into(),
|
VideoFormat::RGBx => DrmFourcc::Xbgr8888,
|
||||||
VideoFormat::ABGR_210LE => DRM_FORMAT_ABGR2101010.into(),
|
VideoFormat::ABGR_210LE => DrmFourcc::Abgr2101010,
|
||||||
VideoFormat::xBGR_210LE => DRM_FORMAT_XBGR2101010.into(),
|
VideoFormat::xBGR_210LE => DrmFourcc::Xbgr2101010,
|
||||||
_ => panic!("Unsupported format"),
|
_ => panic!("Unsupported format"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ use std::{
|
|||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use drm_fourcc::{DrmFormat, DrmFourcc, DrmModifier};
|
||||||
use smithay_client_toolkit::reexports::protocols_wlr::export_dmabuf::v1::client::zwlr_export_dmabuf_frame_v1::{self, ZwlrExportDmabufFrameV1};
|
use smithay_client_toolkit::reexports::protocols_wlr::export_dmabuf::v1::client::zwlr_export_dmabuf_frame_v1::{self, ZwlrExportDmabufFrameV1};
|
||||||
use wayland_client::{Connection, QueueHandle, Dispatch, Proxy};
|
use wayland_client::{Connection, QueueHandle, Dispatch, Proxy};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
WlxCapture,
|
WlxCapture,
|
||||||
frame::{DmabufFrame, DrmFormat, FramePlane, WlxFrame},
|
frame::{DmabufFrame, FrameFormat, FramePlane, WlxFrame},
|
||||||
wayland::WlxClient,
|
wayland::WlxClient,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,13 +169,27 @@ fn request_dmabuf_frame(
|
|||||||
num_objects,
|
num_objects,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut new_frame = DmabufFrame::default();
|
let mut new_frame = DmabufFrame {
|
||||||
new_frame.format.width = width;
|
format: FrameFormat {
|
||||||
new_frame.format.height = height;
|
width,
|
||||||
new_frame.format.fourcc.value = format;
|
height,
|
||||||
|
drm_format: DrmFormat {
|
||||||
|
code: match DrmFourcc::try_from(format) {
|
||||||
|
Ok(code) => code,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Unrecognized fourcc: {e:?}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier: DrmModifier::Invalid,
|
||||||
|
},
|
||||||
|
transform,
|
||||||
|
},
|
||||||
|
mouse: None,
|
||||||
|
num_planes: num_objects as _,
|
||||||
|
planes: Default::default(),
|
||||||
|
};
|
||||||
new_frame.format.set_mod(mod_high, mod_low);
|
new_frame.format.set_mod(mod_high, mod_low);
|
||||||
new_frame.format.transform = transform;
|
|
||||||
new_frame.num_planes = num_objects as _;
|
|
||||||
frame = Some(new_frame);
|
frame = Some(new_frame);
|
||||||
}
|
}
|
||||||
zwlr_export_dmabuf_frame_v1::Event::Object {
|
zwlr_export_dmabuf_frame_v1::Event::Object {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use drm_fourcc::{DrmFormat, DrmFourcc, DrmModifier};
|
||||||
use libc::{O_CREAT, O_RDWR, S_IRUSR, S_IWUSR};
|
use libc::{O_CREAT, O_RDWR, S_IRUSR, S_IWUSR};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
@@ -18,10 +19,7 @@ use smithay_client_toolkit::reexports::protocols_wlr::screencopy::v1::client::zw
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
WlxCapture,
|
WlxCapture,
|
||||||
frame::{
|
frame::{FrameFormat, FramePlane, MemFdFrame, WlxFrame},
|
||||||
DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DrmFormat, FourCC, FrameFormat, FramePlane,
|
|
||||||
MemFdFrame, WlxFrame,
|
|
||||||
},
|
|
||||||
wayland::WlxClient,
|
wayland::WlxClient,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,7 +42,7 @@ impl Drop for BufData {
|
|||||||
enum ScreenCopyEvent {
|
enum ScreenCopyEvent {
|
||||||
Buffer {
|
Buffer {
|
||||||
data: BufData,
|
data: BufData,
|
||||||
fourcc: FourCC,
|
drm_format: DrmFormat,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
stride: u32,
|
stride: u32,
|
||||||
@@ -213,7 +211,7 @@ where
|
|||||||
match event {
|
match event {
|
||||||
ScreenCopyEvent::Buffer {
|
ScreenCopyEvent::Buffer {
|
||||||
data,
|
data,
|
||||||
fourcc,
|
drm_format,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
stride,
|
stride,
|
||||||
@@ -222,16 +220,15 @@ where
|
|||||||
format: FrameFormat {
|
format: FrameFormat {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
fourcc,
|
drm_format,
|
||||||
transform,
|
transform,
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
plane: FramePlane {
|
plane: FramePlane {
|
||||||
fd: Some(data.fd),
|
fd: Some(data.fd),
|
||||||
offset: 0,
|
offset: 0,
|
||||||
stride: stride as _,
|
stride: stride as _,
|
||||||
},
|
},
|
||||||
..Default::default()
|
mouse: None,
|
||||||
};
|
};
|
||||||
log::trace!("{}: Received screencopy buffer, copying", name.as_ref());
|
log::trace!("{}: Received screencopy buffer, copying", name.as_ref());
|
||||||
if wait_for_damage {
|
if wait_for_damage {
|
||||||
@@ -331,7 +328,10 @@ impl Dispatch<ZwlrScreencopyFrameV1, SyncSender<ScreenCopyEvent>> for WlxClient
|
|||||||
wl_pool,
|
wl_pool,
|
||||||
fd,
|
fd,
|
||||||
},
|
},
|
||||||
fourcc,
|
drm_format: DrmFormat {
|
||||||
|
code: fourcc,
|
||||||
|
modifier: DrmModifier::Invalid,
|
||||||
|
},
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
stride,
|
stride,
|
||||||
@@ -346,12 +346,12 @@ impl Dispatch<ZwlrScreencopyFrameV1, SyncSender<ScreenCopyEvent>> for WlxClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fourcc_from_wlshm(shm_format: Format) -> Option<FourCC> {
|
fn fourcc_from_wlshm(shm_format: Format) -> Option<DrmFourcc> {
|
||||||
match shm_format {
|
match shm_format {
|
||||||
Format::Argb8888 => Some(FourCC::from(DRM_FORMAT_ARGB8888)),
|
Format::Argb8888 => Some(DrmFourcc::Argb8888),
|
||||||
Format::Xrgb8888 => Some(FourCC::from(DRM_FORMAT_XRGB8888)),
|
Format::Xrgb8888 => Some(DrmFourcc::Xrgb8888),
|
||||||
Format::Abgr8888 => Some(FourCC::from(DRM_FORMAT_ARGB8888)),
|
Format::Abgr8888 => Some(DrmFourcc::Abgr8888),
|
||||||
Format::Xbgr8888 => Some(FourCC::from(DRM_FORMAT_XRGB8888)),
|
Format::Xbgr8888 => Some(DrmFourcc::Xbgr8888),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use drm_fourcc::{DrmFormat, DrmFourcc, DrmModifier};
|
||||||
use rxscreen::monitor::Monitor;
|
use rxscreen::monitor::Monitor;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
WlxCapture,
|
WlxCapture,
|
||||||
frame::{DRM_FORMAT_XRGB8888, DrmFormat, FrameFormat, MemPtrFrame, MouseMeta, WlxFrame},
|
frame::{FrameFormat, MemPtrFrame, MouseMeta, Transform, WlxFrame},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct XshmScreen {
|
pub struct XshmScreen {
|
||||||
@@ -101,8 +102,11 @@ where
|
|||||||
format: FrameFormat {
|
format: FrameFormat {
|
||||||
width: image.width() as _,
|
width: image.width() as _,
|
||||||
height: image.height() as _,
|
height: image.height() as _,
|
||||||
fourcc: DRM_FORMAT_XRGB8888.into(),
|
drm_format: DrmFormat {
|
||||||
..Default::default()
|
code: DrmFourcc::Xrgb8888,
|
||||||
|
modifier: DrmModifier::Invalid,
|
||||||
|
},
|
||||||
|
transform: Transform::Normal,
|
||||||
},
|
},
|
||||||
ptr: unsafe { image.as_ptr() as _ },
|
ptr: unsafe { image.as_ptr() as _ },
|
||||||
size,
|
size,
|
||||||
|
|||||||
@@ -82,23 +82,18 @@ vulkano = { workspace = true }
|
|||||||
vulkano-shaders = { workspace = true }
|
vulkano-shaders = { workspace = true }
|
||||||
wgui = { path = "../wgui" }
|
wgui = { path = "../wgui" }
|
||||||
wayvr_ipc = { workspace = true }
|
wayvr_ipc = { workspace = true }
|
||||||
|
bytes = { version = "1.11.0" }
|
||||||
|
|
||||||
################################
|
################################
|
||||||
#WayVR-only deps
|
# Wayland Server deps
|
||||||
################################
|
################################
|
||||||
khronos-egl = { version = "6.0.0", features = ["static"], optional = true }
|
|
||||||
smithay = { version = "0.7.0", default-features = false, features = [
|
smithay = { version = "0.7.0", default-features = false, features = [
|
||||||
"renderer_gl",
|
"backend_vulkan",
|
||||||
"backend_egl",
|
|
||||||
"backend_drm",
|
|
||||||
"xwayland",
|
"xwayland",
|
||||||
"wayland_frontend",
|
"wayland_frontend",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
uuid = { version = "1.19.0", features = ["v4", "fast-rng"], optional = true }
|
uuid = { version = "1.19.0", features = ["v4", "fast-rng"], optional = true }
|
||||||
wayland-client = { workspace = true, optional = true }
|
wayland-client = { workspace = true, optional = true }
|
||||||
wayland-egl = { version = "0.32.8", optional = true }
|
|
||||||
bytes = { version = "1.11.0", optional = true }
|
|
||||||
wayvr-ipc = { path = "../wayvr-ipc", default-features = false, optional = true }
|
|
||||||
rust-embed = { workspace = true }
|
rust-embed = { workspace = true }
|
||||||
signal-hook = "0.3.18"
|
signal-hook = "0.3.18"
|
||||||
################################
|
################################
|
||||||
@@ -106,6 +101,7 @@ signal-hook = "0.3.18"
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
regex = { version = "1.12.2" }
|
regex = { version = "1.12.2" }
|
||||||
|
|
||||||
|
# TODO: rename "wayvr" feature to "wayland-server"
|
||||||
[features]
|
[features]
|
||||||
default = ["openvr", "openxr", "osc", "x11", "wayland", "wayvr"]
|
default = ["openvr", "openxr", "osc", "x11", "wayland", "wayvr"]
|
||||||
openvr = ["dep:ovr_overlay", "dep:json"]
|
openvr = ["dep:ovr_overlay", "dep:json"]
|
||||||
@@ -116,13 +112,5 @@ wayland = ["pipewire", "wlx-capture/wlr", "xkbcommon/wayland"]
|
|||||||
pipewire = ["wlx-capture/pipewire"]
|
pipewire = ["wlx-capture/pipewire"]
|
||||||
uidev = ["dep:winit"]
|
uidev = ["dep:winit"]
|
||||||
xcb = ["dep:xcb"]
|
xcb = ["dep:xcb"]
|
||||||
wayvr = [
|
wayvr = ["dep:smithay", "dep:uuid", "dep:wayland-client"]
|
||||||
"dep:khronos-egl",
|
|
||||||
"dep:smithay",
|
|
||||||
"dep:uuid",
|
|
||||||
"dep:wayland-client",
|
|
||||||
"dep:wayland-egl",
|
|
||||||
"dep:bytes",
|
|
||||||
"dep:wayvr-ipc",
|
|
||||||
]
|
|
||||||
as-raw-xcb-connection = []
|
as-raw-xcb-connection = []
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use smallvec::{SmallVec, smallvec};
|
|||||||
use wlx_common::common::LeftRight;
|
use wlx_common::common::LeftRight;
|
||||||
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
||||||
|
|
||||||
use crate::backend::task::OverlayTask;
|
use crate::backend::task::{InputTask, OverlayTask};
|
||||||
use crate::overlays::anchor::{ANCHOR_NAME, GRAB_HELP_NAME};
|
use crate::overlays::anchor::{ANCHOR_NAME, GRAB_HELP_NAME};
|
||||||
use crate::overlays::watch::WATCH_NAME;
|
use crate::overlays::watch::WATCH_NAME;
|
||||||
use crate::state::{AppSession, AppState};
|
use crate::state::{AppSession, AppState};
|
||||||
@@ -65,6 +65,18 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_task(&mut self, task: InputTask) {
|
||||||
|
match task {
|
||||||
|
InputTask::Haptics { device, haptics } => {
|
||||||
|
if let Some(pointer) = self.pointers.get_mut(device) {
|
||||||
|
pointer.pending_haptics = Some(haptics);
|
||||||
|
} else {
|
||||||
|
log::warn!("Can't trigger haptics on non-existing device: {device}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn pre_update(&mut self) {
|
pub const fn pre_update(&mut self) {
|
||||||
self.pointers[0].before = self.pointers[0].now;
|
self.pointers[0].before = self.pointers[0].now;
|
||||||
self.pointers[1].before = self.pointers[1].now;
|
self.pointers[1].before = self.pointers[1].now;
|
||||||
@@ -218,6 +230,7 @@ pub struct Pointer {
|
|||||||
pub now: PointerState,
|
pub now: PointerState,
|
||||||
pub before: PointerState,
|
pub before: PointerState,
|
||||||
pub last_click: Instant,
|
pub last_click: Instant,
|
||||||
|
pub pending_haptics: Option<Haptics>,
|
||||||
pub(super) interaction: InteractionState,
|
pub(super) interaction: InteractionState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +244,7 @@ impl Pointer {
|
|||||||
now: PointerState::default(),
|
now: PointerState::default(),
|
||||||
before: PointerState::default(),
|
before: PointerState::default(),
|
||||||
last_click: Instant::now(),
|
last_click: Instant::now(),
|
||||||
|
pending_haptics: None,
|
||||||
interaction: InteractionState::default(),
|
interaction: InteractionState::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,6 +354,8 @@ where
|
|||||||
{
|
{
|
||||||
// already grabbing, ignore everything else
|
// already grabbing, ignore everything else
|
||||||
let mut pointer = &mut app.input_state.pointers[idx];
|
let mut pointer = &mut app.input_state.pointers[idx];
|
||||||
|
let pending_haptics = pointer.pending_haptics.take();
|
||||||
|
|
||||||
if let Some(grab_data) = pointer.interaction.grabbed {
|
if let Some(grab_data) = pointer.interaction.grabbed {
|
||||||
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
|
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
|
||||||
handle_grabbed(idx, grabbed, app);
|
handle_grabbed(idx, grabbed, app);
|
||||||
@@ -347,13 +363,13 @@ where
|
|||||||
log::warn!("Grabbed overlay {:?} does not exist", grab_data.grabbed_id);
|
log::warn!("Grabbed overlay {:?} does not exist", grab_data.grabbed_id);
|
||||||
pointer.interaction.grabbed = None;
|
pointer.interaction.grabbed = None;
|
||||||
}
|
}
|
||||||
return (0.1, None);
|
return (0.1, pending_haptics);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hovered_id = pointer.interaction.hovered_id.take();
|
let hovered_id = pointer.interaction.hovered_id.take();
|
||||||
let (Some(mut hit), haptics) = get_nearest_hit(idx, overlays, app) else {
|
let (Some(mut hit), haptics) = get_nearest_hit(idx, overlays, app) else {
|
||||||
handle_no_hit(idx, hovered_id, overlays, app);
|
handle_no_hit(idx, hovered_id, overlays, app);
|
||||||
return (0.0, None); // no hit
|
return (0.0, pending_haptics); // no hit
|
||||||
};
|
};
|
||||||
|
|
||||||
// focus change
|
// focus change
|
||||||
@@ -378,7 +394,7 @@ where
|
|||||||
|
|
||||||
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
||||||
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
||||||
return (0.0, None); // no hit
|
return (0.0, pending_haptics); // no hit
|
||||||
};
|
};
|
||||||
pointer = &mut app.input_state.pointers[idx];
|
pointer = &mut app.input_state.pointers[idx];
|
||||||
pointer.interaction.hovered_id = Some(hit.overlay);
|
pointer.interaction.hovered_id = Some(hit.overlay);
|
||||||
@@ -447,7 +463,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(hit.dist, haptics)
|
(hit.dist, haptics.or(pending_haptics))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_no_hit<O>(
|
fn handle_no_hit<O>(
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
|
||||||
use crate::{backend::wayvr::WayVRAction, overlays::wayvr::wayvr_action};
|
|
||||||
|
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod lines;
|
pub mod lines;
|
||||||
@@ -157,37 +154,31 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
}
|
}
|
||||||
FRAME_COUNTER.fetch_add(1, Ordering::Relaxed);
|
FRAME_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
{
|
||||||
// extremely cursed
|
// extremely cursed
|
||||||
const VREVENT_QUIT: u32 = EVREventType::VREvent_Quit as u32;
|
const EV_QUIT: u32 = EVREventType::VREvent_Quit as u32;
|
||||||
const VREVENT_TRACKED_ACTIVATED: u32 = EVREventType::VREvent_TrackedDeviceActivated as u32;
|
const EV_DEV_ACTIVATED: u32 = EVREventType::VREvent_TrackedDeviceActivated as u32;
|
||||||
const VREVENT_TRACKED_DEACTIVATED: u32 =
|
const EV_DEV_DEACTIVATED: u32 = EVREventType::VREvent_TrackedDeviceDeactivated as u32;
|
||||||
EVREventType::VREvent_TrackedDeviceDeactivated as u32;
|
const EV_DEV_UPDATED: u32 = EVREventType::VREvent_TrackedDeviceUpdated as u32;
|
||||||
const VREVENT_TRACKED_UPDATED: u32 = EVREventType::VREvent_TrackedDeviceUpdated as u32;
|
const EV_SEAT_ZERO: u32 = EVREventType::VREvent_SeatedZeroPoseReset as u32;
|
||||||
const VREVENT_SEATED_ZERO: u32 = EVREventType::VREvent_SeatedZeroPoseReset as u32;
|
const EV_STAND_ZERO: u32 = EVREventType::VREvent_StandingZeroPoseReset as u32;
|
||||||
const VREVENT_STANDING_ZERO: u32 = EVREventType::VREvent_StandingZeroPoseReset as u32;
|
const EV_CHAP_CHANGED: u32 = EVREventType::VREvent_ChaperoneUniverseHasChanged as u32;
|
||||||
const VREVENT_CHAPERONE_CHANGED: u32 =
|
const EV_SCENE_CHANGED: u32 = EVREventType::VREvent_SceneApplicationChanged as u32;
|
||||||
EVREventType::VREvent_ChaperoneUniverseHasChanged as u32;
|
const EV_IPD_CHANGED: u32 = EVREventType::VREvent_IpdChanged as u32;
|
||||||
const VREVENT_SCENE_APP_CHANGED: u32 = EVREventType::VREvent_SceneApplicationChanged as u32;
|
|
||||||
const VREVENT_IPD_CHANGED: u32 = EVREventType::VREvent_IpdChanged as u32;
|
|
||||||
|
|
||||||
while let Some(event) = system_mgr.poll_next_event() {
|
while let Some(event) = system_mgr.poll_next_event() {
|
||||||
match event.event_type {
|
match event.event_type {
|
||||||
VREVENT_QUIT => {
|
EV_QUIT => {
|
||||||
log::warn!("Received quit event, shutting down.");
|
log::warn!("Received quit event, shutting down.");
|
||||||
break 'main_loop;
|
break 'main_loop;
|
||||||
}
|
}
|
||||||
VREVENT_TRACKED_ACTIVATED
|
EV_DEV_ACTIVATED | EV_DEV_DEACTIVATED | EV_DEV_UPDATED => {
|
||||||
| VREVENT_TRACKED_DEACTIVATED
|
|
||||||
| VREVENT_TRACKED_UPDATED => {
|
|
||||||
next_device_update = Instant::now();
|
next_device_update = Instant::now();
|
||||||
}
|
}
|
||||||
VREVENT_SEATED_ZERO
|
EV_SEAT_ZERO | EV_STAND_ZERO | EV_CHAP_CHANGED | EV_SCENE_CHANGED => {
|
||||||
| VREVENT_STANDING_ZERO
|
|
||||||
| VREVENT_CHAPERONE_CHANGED
|
|
||||||
| VREVENT_SCENE_APP_CHANGED => {
|
|
||||||
playspace.playspace_changed(&mut compositor_mgr, &mut chaperone_mgr);
|
playspace.playspace_changed(&mut compositor_mgr, &mut chaperone_mgr);
|
||||||
}
|
}
|
||||||
VREVENT_IPD_CHANGED => {
|
EV_IPD_CHANGED => {
|
||||||
if let Ok(ipd) = system_mgr.get_tracked_device_property::<f32>(
|
if let Ok(ipd) = system_mgr.get_tracked_device_property::<f32>(
|
||||||
TrackedDeviceIndex::HMD,
|
TrackedDeviceIndex::HMD,
|
||||||
ETrackedDeviceProperty::Prop_UserIpdMeters_Float,
|
ETrackedDeviceProperty::Prop_UserIpdMeters_Float,
|
||||||
@@ -195,7 +186,11 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
let ipd = (ipd * 1000.0).round();
|
let ipd = (ipd * 1000.0).round();
|
||||||
if (ipd - app.input_state.ipd).abs() > 0.05 {
|
if (ipd - app.input_state.ipd).abs() > 0.05 {
|
||||||
log::info!("IPD: {:.1} mm -> {:.1} mm", app.input_state.ipd, ipd);
|
log::info!("IPD: {:.1} mm -> {:.1} mm", app.input_state.ipd, ipd);
|
||||||
Toast::new(ToastTopic::IpdChange, "IPD".into(), format!("{ipd:.1} mm"))
|
Toast::new(
|
||||||
|
ToastTopic::IpdChange,
|
||||||
|
"IPD".into(),
|
||||||
|
format!("{ipd:.1} mm"),
|
||||||
|
)
|
||||||
.submit(&mut app);
|
.submit(&mut app);
|
||||||
}
|
}
|
||||||
app.input_state.ipd = ipd;
|
app.input_state.ipd = ipd;
|
||||||
@@ -204,6 +199,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if next_device_update <= Instant::now() {
|
if next_device_update <= Instant::now() {
|
||||||
let changed = input_source.update_devices(&mut system_mgr, &mut app);
|
let changed = input_source.update_devices(&mut system_mgr, &mut app);
|
||||||
@@ -220,6 +216,9 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
|
|
||||||
while let Some(task) = due_tasks.pop_front() {
|
while let Some(task) = due_tasks.pop_front() {
|
||||||
match task {
|
match task {
|
||||||
|
TaskType::Input(task) => {
|
||||||
|
app.input_state.handle_task(task);
|
||||||
|
}
|
||||||
TaskType::Overlay(task) => {
|
TaskType::Overlay(task) => {
|
||||||
overlays.handle_task(&mut app, task)?;
|
overlays.handle_task(&mut app, task)?;
|
||||||
}
|
}
|
||||||
@@ -232,9 +231,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
TaskType::WayVR(action) => {
|
TaskType::WayVR(_action) => { /* TODO */ }
|
||||||
wayvr_action(&mut app, &mut overlays, &action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,9 +261,7 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
.pointers
|
.pointers
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| p.now.toggle_dashboard && !p.before.toggle_dashboard)
|
.any(|p| p.now.toggle_dashboard && !p.before.toggle_dashboard)
|
||||||
{
|
{ /* TODO */ }
|
||||||
wayvr_action(&mut app, &mut overlays, &WayVRAction::ToggleDashboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
overlays
|
overlays
|
||||||
.values_mut()
|
.values_mut()
|
||||||
@@ -303,11 +298,10 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
let _ = sender.send_params(&overlays, &app.input_state.devices);
|
let _ = sender.send_params(&overlays, &app.input_state.devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut app, &mut overlays)
|
crate::ipc::events::tick_events::<OpenVrOverlayData>(&mut app, &mut overlays)
|
||||||
{
|
{
|
||||||
log::error!("WayVR tick_events failed: {e:?}");
|
log::error!("WayVR IPC tick_events failed: {e:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
log::trace!("Rendering frame");
|
log::trace!("Rendering frame");
|
||||||
@@ -335,11 +329,6 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
.values_mut()
|
.values_mut()
|
||||||
.for_each(|o| o.after_render(universe.clone(), &mut overlay_mgr, &app.gfx));
|
.for_each(|o| o.after_render(universe.clone(), &mut overlay_mgr, &app.gfx));
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
|
||||||
if let Some(wayvr) = &app.wayvr {
|
|
||||||
wayvr.borrow_mut().data.tick_finish()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// chaperone
|
// chaperone
|
||||||
} // main_loop
|
} // main_loop
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
|
||||||
use crate::{backend::wayvr::WayVRAction, overlays::wayvr::wayvr_action};
|
|
||||||
|
|
||||||
mod blocker;
|
mod blocker;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod input;
|
mod input;
|
||||||
@@ -149,8 +146,8 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
};
|
};
|
||||||
|
|
||||||
let pointer_lines = [
|
let pointer_lines = [
|
||||||
lines.allocate(&xr_state, &mut app)?,
|
lines.allocate(&xr_state, &app)?,
|
||||||
lines.allocate(&xr_state, &mut app)?,
|
lines.allocate(&xr_state, &app)?,
|
||||||
];
|
];
|
||||||
|
|
||||||
let watch_id = overlays.lookup(WATCH_NAME).unwrap(); // want panic
|
let watch_id = overlays.lookup(WATCH_NAME).unwrap(); // want panic
|
||||||
@@ -303,9 +300,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
.pointers
|
.pointers
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| p.now.toggle_dashboard && !p.before.toggle_dashboard)
|
.any(|p| p.now.toggle_dashboard && !p.before.toggle_dashboard)
|
||||||
{
|
{ /* TODO */ }
|
||||||
wayvr_action(&mut app, &mut overlays, &WayVRAction::ToggleDashboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch_fade(&mut app, overlays.mut_by_id(watch_id).unwrap()); // want panic
|
watch_fade(&mut app, overlays.mut_by_id(watch_id).unwrap()); // want panic
|
||||||
if let Some(ref mut space_mover) = playspace {
|
if let Some(ref mut space_mover) = playspace {
|
||||||
@@ -373,9 +368,9 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app, &mut overlays)
|
crate::ipc::events::tick_events::<OpenXrOverlayData>(&mut app, &mut overlays)
|
||||||
{
|
{
|
||||||
log::error!("WayVR tick_events failed: {e:?}");
|
log::error!("WayVR IPC tick_events failed: {e:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin rendering
|
// Begin rendering
|
||||||
@@ -458,11 +453,6 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
}
|
}
|
||||||
// End layer composition
|
// End layer composition
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
|
||||||
if let Some(wayvr) = &app.wayvr {
|
|
||||||
wayvr.borrow_mut().data.tick_finish()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin layer submit
|
// Begin layer submit
|
||||||
layers.sort_by(|a, b| b.0.total_cmp(&a.0));
|
layers.sort_by(|a, b| b.0.total_cmp(&a.0));
|
||||||
|
|
||||||
@@ -489,6 +479,9 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
app.tasks.retrieve_due(&mut due_tasks);
|
app.tasks.retrieve_due(&mut due_tasks);
|
||||||
while let Some(task) = due_tasks.pop_front() {
|
while let Some(task) = due_tasks.pop_front() {
|
||||||
match task {
|
match task {
|
||||||
|
TaskType::Input(task) => {
|
||||||
|
app.input_state.handle_task(task);
|
||||||
|
}
|
||||||
TaskType::Overlay(task) => {
|
TaskType::Overlay(task) => {
|
||||||
overlays.handle_task(&mut app, task)?;
|
overlays.handle_task(&mut app, task)?;
|
||||||
}
|
}
|
||||||
@@ -499,10 +492,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
TaskType::OpenVR(_) => {}
|
TaskType::OpenVR(_) => {}
|
||||||
#[cfg(feature = "wayvr")]
|
TaskType::WayVR(_action) => { /* TODO */ }
|
||||||
TaskType::WayVR(action) => {
|
|
||||||
wayvr_action(&mut app, &mut overlays, &action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::{
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::input,
|
||||||
state::AppState,
|
state::AppState,
|
||||||
windowing::{OverlaySelector, window::OverlayWindowConfig},
|
windowing::{OverlaySelector, window::OverlayWindowConfig},
|
||||||
};
|
};
|
||||||
@@ -43,6 +44,13 @@ impl Ord for AppTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum InputTask {
|
||||||
|
Haptics {
|
||||||
|
device: usize,
|
||||||
|
haptics: input::Haptics,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
pub enum OpenVrTask {
|
pub enum OpenVrTask {
|
||||||
ColorGain(ColorChannel, f32),
|
ColorGain(ColorChannel, f32),
|
||||||
@@ -87,6 +95,7 @@ pub enum OverlayTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum TaskType {
|
pub enum TaskType {
|
||||||
|
Input(InputTask),
|
||||||
Overlay(OverlayTask),
|
Overlay(OverlayTask),
|
||||||
Playspace(PlayspaceTask),
|
Playspace(PlayspaceTask),
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
|
|||||||
@@ -14,12 +14,11 @@ use crate::backend::wayvr::{ExternalProcessRequest, WayVRTask};
|
|||||||
use super::{
|
use super::{
|
||||||
ProcessWayVREnv,
|
ProcessWayVREnv,
|
||||||
comp::{self, ClientState},
|
comp::{self, ClientState},
|
||||||
display, process,
|
process,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct WayVRClient {
|
pub struct WayVRClient {
|
||||||
pub client: wayland_server::Client,
|
pub client: wayland_server::Client,
|
||||||
pub display_handle: display::DisplayHandle,
|
|
||||||
pub pid: u32,
|
pub pid: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,10 +102,13 @@ impl WayVRCompositor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cleanup_handles(&mut self) {
|
||||||
|
self.state.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
fn accept_connection(
|
fn accept_connection(
|
||||||
&mut self,
|
&mut self,
|
||||||
stream: UnixStream,
|
stream: UnixStream,
|
||||||
displays: &mut display::DisplayVec,
|
|
||||||
processes: &mut process::ProcessVec,
|
processes: &mut process::ProcessVec,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let client = self
|
let client = self
|
||||||
@@ -126,19 +128,15 @@ impl WayVRCompositor {
|
|||||||
{
|
{
|
||||||
// Find process with matching auth key
|
// Find process with matching auth key
|
||||||
if process.auth_key.as_str() == auth_key {
|
if process.auth_key.as_str() == auth_key {
|
||||||
// Check if display handle is valid
|
|
||||||
if displays.get(&process.display_handle).is_some() {
|
|
||||||
// Add client
|
// Add client
|
||||||
self.add_client(WayVRClient {
|
self.add_client(WayVRClient {
|
||||||
client,
|
client,
|
||||||
display_handle: process.display_handle,
|
|
||||||
pid: creds.pid as u32,
|
pid: creds.pid as u32,
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This is a new process which we didn't met before.
|
// This is a new process which we didn't met before.
|
||||||
// Treat external processes exclusively (spawned by the user or external program)
|
// Treat external processes exclusively (spawned by the user or external program)
|
||||||
@@ -158,13 +156,9 @@ impl WayVRCompositor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_connections(
|
fn accept_connections(&mut self, processes: &mut process::ProcessVec) -> anyhow::Result<()> {
|
||||||
&mut self,
|
|
||||||
displays: &mut display::DisplayVec,
|
|
||||||
processes: &mut process::ProcessVec,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
if let Some(stream) = self.listener.accept()?
|
if let Some(stream) = self.listener.accept()?
|
||||||
&& let Err(e) = self.accept_connection(stream, displays, processes)
|
&& let Err(e) = self.accept_connection(stream, processes)
|
||||||
{
|
{
|
||||||
log::error!("Failed to accept connection: {e}");
|
log::error!("Failed to accept connection: {e}");
|
||||||
}
|
}
|
||||||
@@ -172,12 +166,8 @@ impl WayVRCompositor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_wayland(
|
pub fn tick_wayland(&mut self, processes: &mut process::ProcessVec) -> anyhow::Result<()> {
|
||||||
&mut self,
|
if let Err(e) = self.accept_connections(processes) {
|
||||||
displays: &mut display::DisplayVec,
|
|
||||||
processes: &mut process::ProcessVec,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
if let Err(e) = self.accept_connections(displays, processes) {
|
|
||||||
log::error!("accept_connections failed: {e}");
|
log::error!("accept_connections failed: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
use smithay::backend::allocator::dmabuf::Dmabuf;
|
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||||
use smithay::backend::renderer::ImportDma;
|
use smithay::backend::renderer::{BufferType, buffer_type};
|
||||||
use smithay::backend::renderer::gles::GlesRenderer;
|
|
||||||
use smithay::backend::renderer::utils::on_commit_buffer_handler;
|
|
||||||
use smithay::input::{Seat, SeatHandler, SeatState};
|
use smithay::input::{Seat, SeatHandler, SeatState};
|
||||||
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
|
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel;
|
||||||
use smithay::reexports::wayland_server;
|
use smithay::reexports::wayland_server;
|
||||||
use smithay::reexports::wayland_server::Resource;
|
use smithay::reexports::wayland_server::Resource;
|
||||||
use smithay::reexports::wayland_server::protocol::{wl_buffer, wl_seat, wl_surface};
|
use smithay::reexports::wayland_server::protocol::{wl_buffer, wl_output, wl_seat, wl_surface};
|
||||||
use smithay::wayland::buffer::BufferHandler;
|
use smithay::wayland::buffer::BufferHandler;
|
||||||
use smithay::wayland::dmabuf::{
|
use smithay::wayland::dmabuf::{
|
||||||
DmabufFeedback, DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier,
|
DmabufFeedback, DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier, get_dmabuf,
|
||||||
};
|
};
|
||||||
use smithay::wayland::output::OutputHandler;
|
use smithay::wayland::output::OutputHandler;
|
||||||
use smithay::wayland::shm::{ShmHandler, ShmState};
|
use smithay::wayland::shm::{ShmHandler, ShmState, with_buffer_contents};
|
||||||
|
use smithay::wayland::single_pixel_buffer::get_single_pixel_buffer;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
delegate_compositor, delegate_data_device, delegate_dmabuf, delegate_output, delegate_seat,
|
delegate_compositor, delegate_data_device, delegate_dmabuf, delegate_output, delegate_seat,
|
||||||
delegate_shm, delegate_xdg_shell,
|
delegate_shm, delegate_xdg_shell,
|
||||||
@@ -23,7 +22,7 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
use smithay::utils::Serial;
|
use smithay::utils::Serial;
|
||||||
use smithay::wayland::compositor::{
|
use smithay::wayland::compositor::{
|
||||||
self, SurfaceAttributes, TraversalAction, with_surface_tree_downward,
|
self, BufferAssignment, SurfaceAttributes, TraversalAction, with_surface_tree_downward,
|
||||||
};
|
};
|
||||||
|
|
||||||
use smithay::wayland::selection::SelectionHandler;
|
use smithay::wayland::selection::SelectionHandler;
|
||||||
@@ -37,11 +36,14 @@ use wayland_server::Client;
|
|||||||
use wayland_server::backend::{ClientData, ClientId, DisconnectReason};
|
use wayland_server::backend::{ClientData, ClientId, DisconnectReason};
|
||||||
use wayland_server::protocol::wl_surface::WlSurface;
|
use wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
|
||||||
|
use crate::backend::wayvr::SurfaceBufWithImage;
|
||||||
|
use crate::backend::wayvr::image_importer::ImageImporter;
|
||||||
|
use crate::ipc::event_queue::SyncEventQueue;
|
||||||
|
|
||||||
use super::WayVRTask;
|
use super::WayVRTask;
|
||||||
use super::event_queue::SyncEventQueue;
|
|
||||||
|
|
||||||
pub struct Application {
|
pub struct Application {
|
||||||
pub gles_renderer: GlesRenderer,
|
pub image_importer: ImageImporter,
|
||||||
pub dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
pub dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
||||||
pub compositor: compositor::CompositorState,
|
pub compositor: compositor::CompositorState,
|
||||||
pub xdg_shell: XdgShellState,
|
pub xdg_shell: XdgShellState,
|
||||||
@@ -56,6 +58,10 @@ impl Application {
|
|||||||
pub fn check_redraw(&mut self, surface: &WlSurface) -> bool {
|
pub fn check_redraw(&mut self, surface: &WlSurface) -> bool {
|
||||||
self.redraw_requests.remove(&surface.id())
|
self.redraw_requests.remove(&surface.id())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cleanup(&mut self) {
|
||||||
|
self.image_importer.cleanup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl compositor::CompositorHandler for Application {
|
impl compositor::CompositorHandler for Application {
|
||||||
@@ -71,7 +77,74 @@ impl compositor::CompositorHandler for Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn commit(&mut self, surface: &WlSurface) {
|
fn commit(&mut self, surface: &WlSurface) {
|
||||||
on_commit_buffer_handler::<Self>(surface);
|
smithay::wayland::compositor::with_states(surface, |states| {
|
||||||
|
let mut guard = states.cached_state.get::<SurfaceAttributes>();
|
||||||
|
let attrs = guard.current();
|
||||||
|
|
||||||
|
match attrs.buffer.take() {
|
||||||
|
Some(BufferAssignment::NewBuffer(buffer)) => {
|
||||||
|
let current = SurfaceBufWithImage::get_from_surface(states);
|
||||||
|
|
||||||
|
if current.is_none_or(|c| c.buffer != buffer) {
|
||||||
|
match buffer_type(&buffer) {
|
||||||
|
Some(BufferType::Dma) => {
|
||||||
|
let dmabuf = get_dmabuf(&buffer).unwrap(); // always Ok due to buffer_type
|
||||||
|
if let Ok(image) =
|
||||||
|
self.image_importer.get_or_import_dmabuf(dmabuf.clone())
|
||||||
|
{
|
||||||
|
let sbwi = SurfaceBufWithImage {
|
||||||
|
image,
|
||||||
|
buffer,
|
||||||
|
transform: wl_transform_to_frame_transform(
|
||||||
|
attrs.buffer_transform,
|
||||||
|
),
|
||||||
|
scale: attrs.buffer_scale,
|
||||||
|
};
|
||||||
|
sbwi.apply_to_surface(states);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(BufferType::Shm) => {
|
||||||
|
with_buffer_contents(&buffer, |data, size, buf| {
|
||||||
|
if let Ok(image) =
|
||||||
|
self.image_importer.import_shm(data, size, buf)
|
||||||
|
{
|
||||||
|
let sbwi = SurfaceBufWithImage {
|
||||||
|
image,
|
||||||
|
buffer: buffer.clone(),
|
||||||
|
transform: wl_transform_to_frame_transform(
|
||||||
|
attrs.buffer_transform,
|
||||||
|
),
|
||||||
|
scale: attrs.buffer_scale,
|
||||||
|
};
|
||||||
|
sbwi.apply_to_surface(states);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(BufferType::SinglePixel) => {
|
||||||
|
let spb = get_single_pixel_buffer(&buffer).unwrap(); // always Ok
|
||||||
|
if let Ok(image) = self.image_importer.import_spb(spb) {
|
||||||
|
let sbwi = SurfaceBufWithImage {
|
||||||
|
image,
|
||||||
|
buffer,
|
||||||
|
transform: wl_transform_to_frame_transform(
|
||||||
|
// does this even matter
|
||||||
|
attrs.buffer_transform,
|
||||||
|
),
|
||||||
|
scale: attrs.buffer_scale,
|
||||||
|
};
|
||||||
|
sbwi.apply_to_surface(states);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(other) => log::warn!("Unsupported wl_buffer format: {other:?}"),
|
||||||
|
None => { /* don't draw anything */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(BufferAssignment::Removed) => {}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
self.redraw_requests.insert(surface.id());
|
self.redraw_requests.insert(surface.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +270,7 @@ impl DmabufHandler for Application {
|
|||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
notifier: ImportNotifier,
|
notifier: ImportNotifier,
|
||||||
) {
|
) {
|
||||||
if self.gles_renderer.import_dmabuf(&dmabuf, None).is_ok() {
|
if self.image_importer.get_or_import_dmabuf(dmabuf).is_ok() {
|
||||||
let _ = notifier.successful::<Self>();
|
let _ = notifier.successful::<Self>();
|
||||||
} else {
|
} else {
|
||||||
notifier.failed();
|
notifier.failed();
|
||||||
@@ -234,3 +307,19 @@ pub fn send_frames_surface_tree(surface: &wl_surface::WlSurface, time: u32) {
|
|||||||
|_, _, &()| true,
|
|_, _, &()| true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wl_transform_to_frame_transform(
|
||||||
|
transform: wl_output::Transform,
|
||||||
|
) -> wlx_capture::frame::Transform {
|
||||||
|
match transform {
|
||||||
|
wl_output::Transform::Normal => wlx_capture::frame::Transform::Normal,
|
||||||
|
wl_output::Transform::_90 => wlx_capture::frame::Transform::Rotated90,
|
||||||
|
wl_output::Transform::_180 => wlx_capture::frame::Transform::Rotated180,
|
||||||
|
wl_output::Transform::_270 => wlx_capture::frame::Transform::Rotated270,
|
||||||
|
wl_output::Transform::Flipped => wlx_capture::frame::Transform::Flipped,
|
||||||
|
wl_output::Transform::Flipped90 => wlx_capture::frame::Transform::Flipped90,
|
||||||
|
wl_output::Transform::Flipped180 => wlx_capture::frame::Transform::Flipped180,
|
||||||
|
wl_output::Transform::Flipped270 => wlx_capture::frame::Transform::Flipped270,
|
||||||
|
_ => wlx_capture::frame::Transform::Undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,605 +0,0 @@
|
|||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
|
||||||
|
|
||||||
use smithay::{
|
|
||||||
backend::renderer::{
|
|
||||||
Bind, Color32F, Frame, Renderer,
|
|
||||||
element::{
|
|
||||||
Kind,
|
|
||||||
surface::{WaylandSurfaceRenderElement, render_elements_from_surface_tree},
|
|
||||||
},
|
|
||||||
gles::{GlesRenderer, GlesTexture, ffi},
|
|
||||||
utils::draw_render_elements,
|
|
||||||
},
|
|
||||||
input,
|
|
||||||
utils::{Logical, Point, Rectangle, Size, Transform},
|
|
||||||
wayland::shell::xdg::ToplevelSurface,
|
|
||||||
};
|
|
||||||
use wayvr_ipc::packet_server;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::wayvr::time::get_millis, gen_id, subsystem::hid::WheelDelta, windowing::OverlayID,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
BlitMethod, WayVRSignal, client::WayVRCompositor, comp::send_frames_surface_tree, egl_data,
|
|
||||||
event_queue::SyncEventQueue, process, smithay_wrapper, time, window,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn generate_auth_key() -> String {
|
|
||||||
let uuid = uuid::Uuid::new_v4();
|
|
||||||
uuid.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DisplayWindow {
|
|
||||||
pub window_handle: window::WindowHandle,
|
|
||||||
pub toplevel: ToplevelSurface,
|
|
||||||
pub process_handle: process::ProcessHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SpawnProcessResult {
|
|
||||||
pub auth_key: String,
|
|
||||||
pub child: std::process::Child,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum DisplayTask {
|
|
||||||
ProcessCleanup(process::ProcessHandle),
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_DISPLAY_SIZE: u16 = 8192;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Display {
|
|
||||||
// Display info stuff
|
|
||||||
pub width: u16,
|
|
||||||
pub height: u16,
|
|
||||||
pub name: String,
|
|
||||||
pub visible: bool,
|
|
||||||
pub layout: packet_server::WvrDisplayWindowLayout,
|
|
||||||
pub overlay_id: Option<OverlayID>,
|
|
||||||
pub wants_redraw: bool,
|
|
||||||
pub rendered_frame_count: u32,
|
|
||||||
pub primary: bool,
|
|
||||||
pub wm: Rc<RefCell<window::WindowManager>>,
|
|
||||||
pub displayed_windows: Vec<DisplayWindow>,
|
|
||||||
wayland_env: super::WaylandEnv,
|
|
||||||
last_pressed_time_ms: u64,
|
|
||||||
pub no_windows_since: Option<u64>,
|
|
||||||
|
|
||||||
// Render data stuff
|
|
||||||
gles_texture: GlesTexture, // TODO: drop texture
|
|
||||||
egl_image: khronos_egl::Image,
|
|
||||||
egl_data: Rc<egl_data::EGLData>,
|
|
||||||
|
|
||||||
pub render_data: egl_data::RenderData,
|
|
||||||
|
|
||||||
pub tasks: SyncEventQueue<DisplayTask>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Display {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = self
|
|
||||||
.egl_data
|
|
||||||
.egl
|
|
||||||
.destroy_image(self.egl_data.display, self.egl_image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DisplayInitParams<'a> {
|
|
||||||
pub wm: Rc<RefCell<window::WindowManager>>,
|
|
||||||
pub config: &'a super::Config,
|
|
||||||
pub renderer: &'a mut GlesRenderer,
|
|
||||||
pub egl_data: Rc<egl_data::EGLData>,
|
|
||||||
pub wayland_env: super::WaylandEnv,
|
|
||||||
pub width: u16,
|
|
||||||
pub height: u16,
|
|
||||||
pub name: &'a str,
|
|
||||||
pub primary: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display {
|
|
||||||
pub fn new(params: DisplayInitParams) -> anyhow::Result<Self> {
|
|
||||||
if params.width > MAX_DISPLAY_SIZE {
|
|
||||||
anyhow::bail!(
|
|
||||||
"display width ({}) is larger than {}",
|
|
||||||
params.width,
|
|
||||||
MAX_DISPLAY_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if params.height > MAX_DISPLAY_SIZE {
|
|
||||||
anyhow::bail!(
|
|
||||||
"display height ({}) is larger than {}",
|
|
||||||
params.height,
|
|
||||||
MAX_DISPLAY_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tex_format = ffi::RGBA;
|
|
||||||
let internal_format = ffi::RGBA8;
|
|
||||||
|
|
||||||
let tex_id = params.renderer.with_context(|gl| {
|
|
||||||
smithay_wrapper::create_framebuffer_texture(
|
|
||||||
gl,
|
|
||||||
u32::from(params.width),
|
|
||||||
u32::from(params.height),
|
|
||||||
tex_format,
|
|
||||||
internal_format,
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let egl_image = params.egl_data.create_egl_image(tex_id)?;
|
|
||||||
|
|
||||||
let render_data = match params.config.blit_method {
|
|
||||||
BlitMethod::Dmabuf => match params.egl_data.create_dmabuf_data(&egl_image) {
|
|
||||||
Ok(dmabuf_data) => egl_data::RenderData::Dmabuf(dmabuf_data),
|
|
||||||
Err(e) => {
|
|
||||||
log::error!(
|
|
||||||
"create_dmabuf_data failed: {e:?}. Using software blitting (This will be slow!)"
|
|
||||||
);
|
|
||||||
egl_data::RenderData::Software(None)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
BlitMethod::Software => egl_data::RenderData::Software(None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let opaque = false;
|
|
||||||
let size = (i32::from(params.width), i32::from(params.height)).into();
|
|
||||||
let gles_texture = unsafe {
|
|
||||||
GlesTexture::from_raw(params.renderer, Some(tex_format), opaque, tex_id, size)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
egl_data: params.egl_data,
|
|
||||||
width: params.width,
|
|
||||||
height: params.height,
|
|
||||||
name: String::from(params.name),
|
|
||||||
primary: params.primary,
|
|
||||||
wayland_env: params.wayland_env,
|
|
||||||
wm: params.wm,
|
|
||||||
displayed_windows: Vec::new(),
|
|
||||||
render_data,
|
|
||||||
egl_image,
|
|
||||||
gles_texture,
|
|
||||||
last_pressed_time_ms: 0,
|
|
||||||
no_windows_since: None,
|
|
||||||
overlay_id: None,
|
|
||||||
tasks: SyncEventQueue::new(),
|
|
||||||
visible: true,
|
|
||||||
wants_redraw: true,
|
|
||||||
rendered_frame_count: 0,
|
|
||||||
layout: packet_server::WvrDisplayWindowLayout::Tiling,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_packet(&self, handle: DisplayHandle) -> packet_server::WvrDisplay {
|
|
||||||
packet_server::WvrDisplay {
|
|
||||||
width: self.width,
|
|
||||||
height: self.height,
|
|
||||||
name: self.name.clone(),
|
|
||||||
visible: self.visible,
|
|
||||||
handle: handle.as_packet(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_window(
|
|
||||||
&mut self,
|
|
||||||
window_handle: window::WindowHandle,
|
|
||||||
process_handle: process::ProcessHandle,
|
|
||||||
toplevel: &ToplevelSurface,
|
|
||||||
) {
|
|
||||||
log::debug!("Attaching toplevel surface into display");
|
|
||||||
self.displayed_windows.push(DisplayWindow {
|
|
||||||
window_handle,
|
|
||||||
process_handle,
|
|
||||||
toplevel: toplevel.clone(),
|
|
||||||
});
|
|
||||||
self.reposition_windows();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_window(&mut self, window_handle: window::WindowHandle) {
|
|
||||||
self.displayed_windows
|
|
||||||
.retain(|disp| disp.window_handle != window_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reposition_windows(&mut self) {
|
|
||||||
let window_count = self.displayed_windows.len();
|
|
||||||
|
|
||||||
match &self.layout {
|
|
||||||
packet_server::WvrDisplayWindowLayout::Tiling => {
|
|
||||||
let mut i = 0;
|
|
||||||
for win in &mut self.displayed_windows {
|
|
||||||
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
|
|
||||||
if !window.visible {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let d_cur = i as f32 / window_count as f32;
|
|
||||||
let d_next = (i + 1) as f32 / window_count as f32;
|
|
||||||
|
|
||||||
let left = (d_cur * f32::from(self.width)) as i32;
|
|
||||||
let right = (d_next * f32::from(self.width)) as i32;
|
|
||||||
|
|
||||||
window.set_pos(left, 0);
|
|
||||||
window.set_size((right - left) as u32, u32::from(self.height));
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packet_server::WvrDisplayWindowLayout::Stacking(opts) => {
|
|
||||||
let do_margins = |margins: &packet_server::Margins, window: &mut window::Window| {
|
|
||||||
let top = i32::from(margins.top);
|
|
||||||
let bottom = i32::from(self.height) - i32::from(margins.bottom);
|
|
||||||
let left = i32::from(margins.left);
|
|
||||||
let right = i32::from(self.width) - i32::from(margins.right);
|
|
||||||
let width = right - left;
|
|
||||||
let height = bottom - top;
|
|
||||||
if width < 0 || height < 0 {
|
|
||||||
return; // wrong parameters, do nothing!
|
|
||||||
}
|
|
||||||
|
|
||||||
window.set_pos(left, top);
|
|
||||||
window.set_size(width as u32, height as u32);
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
for win in &mut self.displayed_windows {
|
|
||||||
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
|
|
||||||
if !window.visible {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
do_margins(
|
|
||||||
if i == 0 {
|
|
||||||
&opts.margins_first
|
|
||||||
} else {
|
|
||||||
&opts.margins_rest
|
|
||||||
},
|
|
||||||
window,
|
|
||||||
);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick(
|
|
||||||
&mut self,
|
|
||||||
config: &super::Config,
|
|
||||||
handle: &DisplayHandle,
|
|
||||||
signals: &mut SyncEventQueue<WayVRSignal>,
|
|
||||||
) {
|
|
||||||
if self.visible {
|
|
||||||
if !self.displayed_windows.is_empty() {
|
|
||||||
self.no_windows_since = None;
|
|
||||||
} else if let Some(auto_hide_delay) = config.auto_hide_delay
|
|
||||||
&& let Some(s) = self.no_windows_since
|
|
||||||
&& s + u64::from(auto_hide_delay) < get_millis()
|
|
||||||
{
|
|
||||||
// Auto-hide after specific time
|
|
||||||
signals.send(WayVRSignal::DisplayVisibility(*handle, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(task) = self.tasks.read() {
|
|
||||||
match task {
|
|
||||||
DisplayTask::ProcessCleanup(process_handle) => {
|
|
||||||
let count = self.displayed_windows.len();
|
|
||||||
self.displayed_windows
|
|
||||||
.retain(|win| win.process_handle != process_handle);
|
|
||||||
log::info!(
|
|
||||||
"Cleanup finished for display \"{}\". Current window count: {}",
|
|
||||||
self.name,
|
|
||||||
self.displayed_windows.len()
|
|
||||||
);
|
|
||||||
self.no_windows_since = Some(get_millis());
|
|
||||||
|
|
||||||
if count != self.displayed_windows.len() {
|
|
||||||
signals.send(WayVRSignal::BroadcastStateChanged(
|
|
||||||
packet_server::WvrStateChanged::WindowRemoved,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.reposition_windows();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::significant_drop_tightening)]
|
|
||||||
pub fn tick_render(&mut self, renderer: &mut GlesRenderer, time_ms: u64) -> anyhow::Result<()> {
|
|
||||||
let mut gles_texture = self.gles_texture.clone();
|
|
||||||
let mut target = renderer.bind(&mut gles_texture)?;
|
|
||||||
|
|
||||||
let size = Size::from((i32::from(self.width), i32::from(self.height)));
|
|
||||||
let damage: Rectangle<i32, smithay::utils::Physical> = Rectangle::from_size(size);
|
|
||||||
|
|
||||||
let elements: Vec<WaylandSurfaceRenderElement<GlesRenderer>> = self
|
|
||||||
.displayed_windows
|
|
||||||
.iter()
|
|
||||||
.flat_map(|display_window| {
|
|
||||||
let wm = self.wm.borrow_mut();
|
|
||||||
if let Some(window) = wm.windows.get(&display_window.window_handle) {
|
|
||||||
if !window.visible {
|
|
||||||
return vec![];
|
|
||||||
}
|
|
||||||
render_elements_from_surface_tree(
|
|
||||||
renderer,
|
|
||||||
display_window.toplevel.wl_surface(),
|
|
||||||
(window.pos_x, window.pos_y),
|
|
||||||
1.0,
|
|
||||||
1.0,
|
|
||||||
Kind::Unspecified,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Failed to fetch window
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut frame = renderer.render(&mut target, size, Transform::Normal)?;
|
|
||||||
|
|
||||||
let clear_color = if self.displayed_windows.is_empty() {
|
|
||||||
Color32F::new(0.5, 0.5, 0.5, 0.5)
|
|
||||||
} else {
|
|
||||||
Color32F::new(0.0, 0.0, 0.0, 0.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.clear(clear_color, &[damage])?;
|
|
||||||
|
|
||||||
draw_render_elements(&mut frame, 1.0, &elements, &[damage])?;
|
|
||||||
|
|
||||||
let _sync_point = frame.finish()?;
|
|
||||||
|
|
||||||
for window in &self.displayed_windows {
|
|
||||||
send_frames_surface_tree(window.toplevel.wl_surface(), time_ms as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let egl_data::RenderData::Software(_) = &self.render_data {
|
|
||||||
// Read OpenGL texture into memory. Slow!
|
|
||||||
let pixel_data = renderer.with_context(|gl| unsafe {
|
|
||||||
gl.BindTexture(ffi::TEXTURE_2D, self.gles_texture.tex_id());
|
|
||||||
|
|
||||||
let len = self.width as usize * self.height as usize * 4;
|
|
||||||
let mut data: Box<[u8]> = Box::new_uninit_slice(len).assume_init();
|
|
||||||
gl.ReadPixels(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
i32::from(self.width),
|
|
||||||
i32::from(self.height),
|
|
||||||
ffi::RGBA,
|
|
||||||
ffi::UNSIGNED_BYTE,
|
|
||||||
data.as_mut_ptr().cast(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let data: Arc<[u8]> = Arc::from(data);
|
|
||||||
data
|
|
||||||
})?;
|
|
||||||
|
|
||||||
self.render_data =
|
|
||||||
egl_data::RenderData::Software(Some(egl_data::RenderSoftwarePixelsData {
|
|
||||||
data: pixel_data,
|
|
||||||
width: self.width,
|
|
||||||
height: self.height,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.rendered_frame_count += 1;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_hovered_window(&self, cursor_x: u32, cursor_y: u32) -> Option<window::WindowHandle> {
|
|
||||||
let wm = self.wm.borrow();
|
|
||||||
|
|
||||||
for cell in self.displayed_windows.iter().rev() {
|
|
||||||
if let Some(window) = wm.windows.get(&cell.window_handle) {
|
|
||||||
if !window.visible {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor_x as i32) >= window.pos_x
|
|
||||||
&& (cursor_x as i32) < window.pos_x + window.size_x as i32
|
|
||||||
&& (cursor_y as i32) >= window.pos_y
|
|
||||||
&& (cursor_y as i32) < window.pos_y + window.size_y as i32
|
|
||||||
{
|
|
||||||
return Some(cell.window_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn trigger_rerender(&mut self) {
|
|
||||||
self.wants_redraw = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_visible(&mut self, visible: bool) {
|
|
||||||
log::info!("Display \"{}\" visible: {}", self.name.as_str(), visible);
|
|
||||||
if self.visible == visible {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.visible = visible;
|
|
||||||
if visible {
|
|
||||||
self.no_windows_since = None;
|
|
||||||
self.trigger_rerender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_layout(&mut self, layout: packet_server::WvrDisplayWindowLayout) {
|
|
||||||
log::info!("Display \"{}\" layout: {:?}", self.name.as_str(), layout);
|
|
||||||
if self.layout == layout {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.layout = layout;
|
|
||||||
self.trigger_rerender();
|
|
||||||
self.reposition_windows();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_mouse_move(
|
|
||||||
&self,
|
|
||||||
config: &super::Config,
|
|
||||||
manager: &mut WayVRCompositor,
|
|
||||||
x: u32,
|
|
||||||
y: u32,
|
|
||||||
) {
|
|
||||||
let current_ms = time::get_millis();
|
|
||||||
if self.last_pressed_time_ms + u64::from(config.click_freeze_time_ms) > current_ms {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(window_handle) = self.get_hovered_window(x, y) {
|
|
||||||
let wm = self.wm.borrow();
|
|
||||||
if let Some(window) = wm.windows.get(&window_handle) {
|
|
||||||
let surf = window.toplevel.wl_surface().clone();
|
|
||||||
let point = Point::<f64, Logical>::from((
|
|
||||||
f64::from(x as i32 - window.pos_x),
|
|
||||||
f64::from(y as i32 - window.pos_y),
|
|
||||||
));
|
|
||||||
|
|
||||||
manager.seat_pointer.motion(
|
|
||||||
&mut manager.state,
|
|
||||||
Some((surf, Point::from((0.0, 0.0)))),
|
|
||||||
&input::pointer::MotionEvent {
|
|
||||||
serial: manager.serial_counter.next_serial(),
|
|
||||||
time: 0,
|
|
||||||
location: point,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
manager.seat_pointer.frame(&mut manager.state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn get_mouse_index_number(index: super::MouseIndex) -> u32 {
|
|
||||||
match index {
|
|
||||||
super::MouseIndex::Left => 0x110, /* BTN_LEFT */
|
|
||||||
super::MouseIndex::Center => 0x112, /* BTN_MIDDLE */
|
|
||||||
super::MouseIndex::Right => 0x111, /* BTN_RIGHT */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_mouse_down(&mut self, manager: &mut WayVRCompositor, index: super::MouseIndex) {
|
|
||||||
// Change keyboard focus to pressed window
|
|
||||||
let loc = manager.seat_pointer.current_location();
|
|
||||||
|
|
||||||
self.last_pressed_time_ms = time::get_millis();
|
|
||||||
|
|
||||||
if let Some(window_handle) =
|
|
||||||
self.get_hovered_window(loc.x.max(0.0) as u32, loc.y.max(0.0) as u32)
|
|
||||||
{
|
|
||||||
let wm = self.wm.borrow();
|
|
||||||
if let Some(window) = wm.windows.get(&window_handle) {
|
|
||||||
let surf = window.toplevel.wl_surface().clone();
|
|
||||||
|
|
||||||
manager.seat_keyboard.set_focus(
|
|
||||||
&mut manager.state,
|
|
||||||
Some(surf),
|
|
||||||
manager.serial_counter.next_serial(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
manager.seat_pointer.button(
|
|
||||||
&mut manager.state,
|
|
||||||
&input::pointer::ButtonEvent {
|
|
||||||
button: Self::get_mouse_index_number(index),
|
|
||||||
serial: manager.serial_counter.next_serial(),
|
|
||||||
time: 0,
|
|
||||||
state: smithay::backend::input::ButtonState::Pressed,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
manager.seat_pointer.frame(&mut manager.state);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_mouse_up(manager: &mut WayVRCompositor, index: super::MouseIndex) {
|
|
||||||
manager.seat_pointer.button(
|
|
||||||
&mut manager.state,
|
|
||||||
&input::pointer::ButtonEvent {
|
|
||||||
button: Self::get_mouse_index_number(index),
|
|
||||||
serial: manager.serial_counter.next_serial(),
|
|
||||||
time: 0,
|
|
||||||
state: smithay::backend::input::ButtonState::Released,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
manager.seat_pointer.frame(&mut manager.state);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_mouse_scroll(manager: &mut WayVRCompositor, delta: WheelDelta) {
|
|
||||||
manager.seat_pointer.axis(
|
|
||||||
&mut manager.state,
|
|
||||||
input::pointer::AxisFrame {
|
|
||||||
source: None,
|
|
||||||
relative_direction: (
|
|
||||||
smithay::backend::input::AxisRelativeDirection::Identical,
|
|
||||||
smithay::backend::input::AxisRelativeDirection::Identical,
|
|
||||||
),
|
|
||||||
time: 0,
|
|
||||||
axis: (f64::from(delta.x), f64::from(-delta.y)),
|
|
||||||
v120: Some((0, (delta.y * -64.0) as i32)),
|
|
||||||
stop: (false, false),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
manager.seat_pointer.frame(&mut manager.state);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_env(&self, cmd: &mut std::process::Command, auth_key: &str) {
|
|
||||||
cmd.env_remove("DISPLAY"); // Goodbye X11
|
|
||||||
cmd.env("WAYLAND_DISPLAY", self.wayland_env.display_num_string());
|
|
||||||
cmd.env("WAYVR_DISPLAY_AUTH", auth_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn_process(
|
|
||||||
&mut self,
|
|
||||||
exec_path: &str,
|
|
||||||
args: &[&str],
|
|
||||||
env: &[(&str, &str)],
|
|
||||||
working_dir: Option<&str>,
|
|
||||||
) -> anyhow::Result<SpawnProcessResult> {
|
|
||||||
log::info!("Spawning subprocess with exec path \"{exec_path}\"");
|
|
||||||
|
|
||||||
let auth_key = generate_auth_key();
|
|
||||||
|
|
||||||
let mut cmd = std::process::Command::new(exec_path);
|
|
||||||
self.configure_env(&mut cmd, auth_key.as_str());
|
|
||||||
cmd.args(args);
|
|
||||||
if let Some(working_dir) = working_dir {
|
|
||||||
cmd.current_dir(working_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
for e in env {
|
|
||||||
cmd.env(e.0, e.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
match cmd.spawn() {
|
|
||||||
Ok(child) => Ok(SpawnProcessResult { auth_key, child }),
|
|
||||||
Err(e) => {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Failed to launch process with path \"{exec_path}\": {e}. Make sure your exec path exists."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_id!(DisplayVec, Display, DisplayCell, DisplayHandle);
|
|
||||||
|
|
||||||
impl DisplayHandle {
|
|
||||||
pub const fn from_packet(handle: packet_server::WvrDisplayHandle) -> Self {
|
|
||||||
Self {
|
|
||||||
generation: handle.generation,
|
|
||||||
idx: handle.idx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn as_packet(&self) -> packet_server::WvrDisplayHandle {
|
|
||||||
packet_server::WvrDisplayHandle {
|
|
||||||
idx: self.idx,
|
|
||||||
generation: self.generation,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,315 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::backend::wayvr::egl_ex::{
|
|
||||||
PFNEGLGETPLATFORMDISPLAYEXTPROC, PFNEGLQUERYDMABUFFORMATSEXTPROC,
|
|
||||||
PFNEGLQUERYDMABUFMODIFIERSEXTPROC,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::egl_ex;
|
|
||||||
use anyhow::Context;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EGLData {
|
|
||||||
pub egl: khronos_egl::Instance<khronos_egl::Static>,
|
|
||||||
pub display: khronos_egl::Display,
|
|
||||||
pub config: khronos_egl::Config,
|
|
||||||
pub context: khronos_egl::Context,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! bind_egl_function {
|
|
||||||
($func_type:ident, $func:expr) => {
|
|
||||||
std::mem::transmute_copy::<_, $func_type>($func).unwrap()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DMAbufModifierInfo {
|
|
||||||
pub modifiers: Vec<u64>,
|
|
||||||
pub fourcc: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RenderDMAbufData {
|
|
||||||
pub fd: i32,
|
|
||||||
pub stride: i32,
|
|
||||||
pub offset: i32,
|
|
||||||
pub mod_info: DMAbufModifierInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RenderSoftwarePixelsData {
|
|
||||||
pub data: Arc<[u8]>,
|
|
||||||
pub width: u16,
|
|
||||||
pub height: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum RenderData {
|
|
||||||
Dmabuf(RenderDMAbufData),
|
|
||||||
Software(Option<RenderSoftwarePixelsData>), // will be set if the next image data is available
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_egl_func(
|
|
||||||
egl: &khronos_egl::Instance<khronos_egl::Static>,
|
|
||||||
func_name: &str,
|
|
||||||
) -> anyhow::Result<extern "system" fn()> {
|
|
||||||
let raw_fn = egl
|
|
||||||
.get_proc_address(func_name)
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("Required EGL function {func_name} not found"))?;
|
|
||||||
Ok(raw_fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_disp(
|
|
||||||
egl: &khronos_egl::Instance<khronos_egl::Static>,
|
|
||||||
) -> anyhow::Result<khronos_egl::Display> {
|
|
||||||
unsafe {
|
|
||||||
if let Ok(func) = load_egl_func(egl, "eglGetPlatformDisplayEXT") {
|
|
||||||
let egl_get_platform_display_ext =
|
|
||||||
bind_egl_function!(PFNEGLGETPLATFORMDISPLAYEXTPROC, &func);
|
|
||||||
|
|
||||||
let display_ext = egl_get_platform_display_ext(
|
|
||||||
egl_ex::EGL_PLATFORM_WAYLAND_EXT, // platform
|
|
||||||
std::ptr::null_mut(), // void *native_display
|
|
||||||
std::ptr::null_mut(), // EGLint *attrib_list
|
|
||||||
);
|
|
||||||
|
|
||||||
if display_ext.is_null() {
|
|
||||||
log::warn!("eglGetPlatformDisplayEXT failed, using eglGetDisplay instead");
|
|
||||||
} else {
|
|
||||||
return Ok(khronos_egl::Display::from_ptr(display_ext));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
egl
|
|
||||||
.get_display(khronos_egl::DEFAULT_DISPLAY)
|
|
||||||
.context(
|
|
||||||
"Both eglGetPlatformDisplayEXT and eglGetDisplay failed. This shouldn't happen unless you don't have any display manager running. Cannot continue, check your EGL installation."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EGLData {
|
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
|
||||||
let egl = khronos_egl::Instance::new(khronos_egl::Static);
|
|
||||||
let display = get_disp(&egl)?;
|
|
||||||
|
|
||||||
let (major, minor) = egl.initialize(display)?;
|
|
||||||
log::debug!("EGL version: {major}.{minor}");
|
|
||||||
|
|
||||||
let attrib_list = [
|
|
||||||
khronos_egl::RED_SIZE,
|
|
||||||
8,
|
|
||||||
khronos_egl::GREEN_SIZE,
|
|
||||||
8,
|
|
||||||
khronos_egl::BLUE_SIZE,
|
|
||||||
8,
|
|
||||||
khronos_egl::SURFACE_TYPE,
|
|
||||||
khronos_egl::WINDOW_BIT,
|
|
||||||
khronos_egl::RENDERABLE_TYPE,
|
|
||||||
khronos_egl::OPENGL_BIT,
|
|
||||||
khronos_egl::NONE,
|
|
||||||
];
|
|
||||||
|
|
||||||
let config = egl
|
|
||||||
.choose_first_config(display, &attrib_list)?
|
|
||||||
.context("Failed to get EGL config")?;
|
|
||||||
|
|
||||||
egl.bind_api(khronos_egl::OPENGL_ES_API)?;
|
|
||||||
|
|
||||||
log::debug!("eglCreateContext");
|
|
||||||
|
|
||||||
// Require OpenGL ES 3.0
|
|
||||||
let context_attrib_list = [
|
|
||||||
khronos_egl::CONTEXT_MAJOR_VERSION,
|
|
||||||
3,
|
|
||||||
khronos_egl::CONTEXT_MINOR_VERSION,
|
|
||||||
0,
|
|
||||||
khronos_egl::NONE,
|
|
||||||
];
|
|
||||||
|
|
||||||
let context = egl.create_context(display, config, None, &context_attrib_list)?;
|
|
||||||
|
|
||||||
log::debug!("eglMakeCurrent");
|
|
||||||
|
|
||||||
egl.make_current(display, None, None, Some(context))?;
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
egl,
|
|
||||||
display,
|
|
||||||
config,
|
|
||||||
context,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query_dmabuf_mod_info(&self) -> anyhow::Result<DMAbufModifierInfo> {
|
|
||||||
let target_fourcc = 0x3432_4258; //XB24
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let egl_query_dmabuf_formats_ext = bind_egl_function!(
|
|
||||||
PFNEGLQUERYDMABUFFORMATSEXTPROC,
|
|
||||||
&load_egl_func(&self.egl, "eglQueryDmaBufFormatsEXT")?
|
|
||||||
);
|
|
||||||
|
|
||||||
// Query format count
|
|
||||||
let mut num_formats: khronos_egl::Int = 0;
|
|
||||||
egl_query_dmabuf_formats_ext(
|
|
||||||
self.display.as_ptr(),
|
|
||||||
0,
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
&raw mut num_formats,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Retrieve format list
|
|
||||||
let mut formats: Vec<i32> = vec![0; num_formats as usize];
|
|
||||||
egl_query_dmabuf_formats_ext(
|
|
||||||
self.display.as_ptr(),
|
|
||||||
num_formats,
|
|
||||||
formats.as_mut_ptr(),
|
|
||||||
&raw mut num_formats,
|
|
||||||
);
|
|
||||||
|
|
||||||
/*for (idx, format) in formats.iter().enumerate() {
|
|
||||||
let bytes = format.to_le_bytes();
|
|
||||||
log::trace!(
|
|
||||||
"idx {}, format {}{}{}{} (hex {:#x})",
|
|
||||||
idx,
|
|
||||||
bytes[0] as char,
|
|
||||||
bytes[1] as char,
|
|
||||||
bytes[2] as char,
|
|
||||||
bytes[3] as char,
|
|
||||||
format
|
|
||||||
);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let egl_query_dmabuf_modifiers_ext = bind_egl_function!(
|
|
||||||
PFNEGLQUERYDMABUFMODIFIERSEXTPROC,
|
|
||||||
&load_egl_func(&self.egl, "eglQueryDmaBufModifiersEXT")?
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut num_mods: khronos_egl::Int = 0;
|
|
||||||
|
|
||||||
// Query modifier count
|
|
||||||
egl_query_dmabuf_modifiers_ext(
|
|
||||||
self.display.as_ptr(),
|
|
||||||
target_fourcc,
|
|
||||||
0,
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
&raw mut num_mods,
|
|
||||||
);
|
|
||||||
|
|
||||||
if num_mods == 0 {
|
|
||||||
anyhow::bail!("eglQueryDmaBufModifiersEXT modifier count is zero");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut mods: Vec<u64> = vec![0; num_mods as usize];
|
|
||||||
egl_query_dmabuf_modifiers_ext(
|
|
||||||
self.display.as_ptr(),
|
|
||||||
target_fourcc,
|
|
||||||
num_mods,
|
|
||||||
mods.as_mut_ptr(),
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
&raw mut num_mods,
|
|
||||||
);
|
|
||||||
|
|
||||||
if mods[0] == 0xFFFF_FFFF_FFFF_FFFF {
|
|
||||||
anyhow::bail!("modifier is -1")
|
|
||||||
}
|
|
||||||
|
|
||||||
log::trace!("Modifier list:");
|
|
||||||
for modifier in &mods {
|
|
||||||
log::trace!("{modifier:#x}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should not change these modifier values. Passing all of them to the Vulkan dmabuf
|
|
||||||
// texture system causes significant graphical corruption due to invalid memory layout and
|
|
||||||
// tiling on this specific GPU model (very probably others also have the same issue).
|
|
||||||
// It is not guaranteed that this modifier will be present in other models.
|
|
||||||
// If not, the full list of modifiers will be passed. Further testing is required.
|
|
||||||
// For now, it looks like only NAVI32-based gpus have this problem.
|
|
||||||
let mod_whitelist: [u64; 2] = [
|
|
||||||
0x200_0000_2086_bf04, /* AMD RX 7800 XT, Navi32 */
|
|
||||||
0x200_0000_1866_bf04, /* AMD RX 7600 XT, Navi33 */
|
|
||||||
];
|
|
||||||
|
|
||||||
for modifier in &mod_whitelist {
|
|
||||||
if mods.contains(modifier) {
|
|
||||||
log::warn!("Using whitelisted dmabuf tiling modifier: {modifier:#x}");
|
|
||||||
mods = vec![*modifier, 0x0 /* also important (???) */];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(DMAbufModifierInfo {
|
|
||||||
modifiers: mods,
|
|
||||||
fourcc: target_fourcc as u32,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_dmabuf_data(
|
|
||||||
&self,
|
|
||||||
egl_image: &khronos_egl::Image,
|
|
||||||
) -> anyhow::Result<RenderDMAbufData> {
|
|
||||||
use egl_ex::PFNEGLEXPORTDMABUFIMAGEMESAPROC as FUNC;
|
|
||||||
unsafe {
|
|
||||||
let egl_export_dmabuf_image_mesa =
|
|
||||||
bind_egl_function!(FUNC, &load_egl_func(&self.egl, "eglExportDMABUFImageMESA")?);
|
|
||||||
|
|
||||||
let mut fds: [i32; 3] = [0; 3];
|
|
||||||
let mut strides: [i32; 3] = [0; 3];
|
|
||||||
let mut offsets: [i32; 3] = [0; 3];
|
|
||||||
|
|
||||||
let ret = egl_export_dmabuf_image_mesa(
|
|
||||||
self.display.as_ptr(),
|
|
||||||
egl_image.as_ptr(),
|
|
||||||
fds.as_mut_ptr(),
|
|
||||||
strides.as_mut_ptr(),
|
|
||||||
offsets.as_mut_ptr(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if ret != khronos_egl::TRUE {
|
|
||||||
anyhow::bail!("eglExportDMABUFImageMESA failed with return code {ret}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if fds[0] <= 0 {
|
|
||||||
anyhow::bail!("fd is <=0 (got {})", fds[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// many planes in RGB data?
|
|
||||||
if fds[1] != 0 || strides[1] != 0 || offsets[1] != 0 {
|
|
||||||
anyhow::bail!("multi-planar data received, packed RGB expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
if strides[0] < 0 {
|
|
||||||
anyhow::bail!("strides is < 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if offsets[0] < 0 {
|
|
||||||
anyhow::bail!("offsets is < 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mod_info = self.query_dmabuf_mod_info()?;
|
|
||||||
|
|
||||||
Ok(RenderDMAbufData {
|
|
||||||
fd: fds[0],
|
|
||||||
stride: strides[0],
|
|
||||||
offset: offsets[0],
|
|
||||||
mod_info,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_egl_image(&self, gl_tex_id: u32) -> anyhow::Result<khronos_egl::Image> {
|
|
||||||
unsafe {
|
|
||||||
Ok(self.egl.create_image(
|
|
||||||
self.display,
|
|
||||||
self.context,
|
|
||||||
khronos_egl::GL_TEXTURE_2D as std::ffi::c_uint,
|
|
||||||
khronos_egl::ClientBuffer::from_ptr(gl_tex_id as *mut std::ffi::c_void),
|
|
||||||
&[khronos_egl::ATTRIB_NONE],
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#![allow(clippy::all)]
|
|
||||||
|
|
||||||
pub const EGL_PLATFORM_WAYLAND_EXT: khronos_egl::Enum = 0x31D8;
|
|
||||||
|
|
||||||
// eglGetPlatformDisplayEXT
|
|
||||||
// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_platform_base.txt
|
|
||||||
pub type PFNEGLGETPLATFORMDISPLAYEXTPROC = Option<
|
|
||||||
unsafe extern "C" fn(
|
|
||||||
platform: khronos_egl::Enum,
|
|
||||||
native_display: *mut std::ffi::c_void,
|
|
||||||
attrib_list: *mut khronos_egl::Enum,
|
|
||||||
) -> khronos_egl::EGLDisplay,
|
|
||||||
>;
|
|
||||||
|
|
||||||
// eglExportDMABUFImageMESA
|
|
||||||
// https://registry.khronos.org/EGL/extensions/MESA/EGL_MESA_image_dma_buf_export.txt
|
|
||||||
pub type PFNEGLEXPORTDMABUFIMAGEMESAPROC = Option<
|
|
||||||
unsafe extern "C" fn(
|
|
||||||
dpy: khronos_egl::EGLDisplay,
|
|
||||||
image: khronos_egl::EGLImage,
|
|
||||||
fds: *mut i32,
|
|
||||||
strides: *mut khronos_egl::Int,
|
|
||||||
offsets: *mut khronos_egl::Int,
|
|
||||||
) -> khronos_egl::Boolean,
|
|
||||||
>;
|
|
||||||
|
|
||||||
// eglQueryDmaBufModifiersEXT
|
|
||||||
// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt
|
|
||||||
pub type PFNEGLQUERYDMABUFMODIFIERSEXTPROC = Option<
|
|
||||||
unsafe extern "C" fn(
|
|
||||||
dpy: khronos_egl::EGLDisplay,
|
|
||||||
format: khronos_egl::Int,
|
|
||||||
max_modifiers: khronos_egl::Int,
|
|
||||||
modifiers: *mut u64,
|
|
||||||
external_only: *mut khronos_egl::Boolean,
|
|
||||||
num_modifiers: *mut khronos_egl::Int,
|
|
||||||
) -> khronos_egl::Boolean,
|
|
||||||
>;
|
|
||||||
|
|
||||||
// eglQueryDmaBufFormatsEXT
|
|
||||||
// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt
|
|
||||||
pub type PFNEGLQUERYDMABUFFORMATSEXTPROC = Option<
|
|
||||||
unsafe extern "C" fn(
|
|
||||||
dpy: khronos_egl::EGLDisplay,
|
|
||||||
max_formats: khronos_egl::Int,
|
|
||||||
formats: *mut khronos_egl::Int,
|
|
||||||
num_formats: *mut khronos_egl::Int,
|
|
||||||
) -> khronos_egl::Boolean,
|
|
||||||
>;
|
|
||||||
111
wlx-overlay-s/src/backend/wayvr/image_importer.rs
Normal file
111
wlx-overlay-s/src/backend/wayvr/image_importer.rs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
use std::{collections::HashMap, os::fd::AsRawFd, sync::Arc};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use smithay::{
|
||||||
|
backend::allocator::{
|
||||||
|
Buffer,
|
||||||
|
dmabuf::{Dmabuf, WeakDmabuf},
|
||||||
|
},
|
||||||
|
wayland::{
|
||||||
|
shm::{BufferData, shm_format_to_fourcc},
|
||||||
|
single_pixel_buffer::SinglePixelBufferUserData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use vulkano::{format::Format, image::view::ImageView};
|
||||||
|
use wgui::gfx::WGfx;
|
||||||
|
use wlx_capture::frame::{DmabufFrame, FrameFormat, Transform};
|
||||||
|
|
||||||
|
use crate::graphics::dmabuf::{WGfxDmabuf, fourcc_to_vk};
|
||||||
|
|
||||||
|
pub struct ImageImporter {
|
||||||
|
gfx: Arc<WGfx>,
|
||||||
|
dmabufs: HashMap<WeakDmabuf, Arc<ImageView>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageImporter {
|
||||||
|
pub fn new(gfx: Arc<WGfx>) -> Self {
|
||||||
|
Self {
|
||||||
|
gfx,
|
||||||
|
dmabufs: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn import_spb(
|
||||||
|
&mut self,
|
||||||
|
spb: &SinglePixelBufferUserData,
|
||||||
|
) -> anyhow::Result<Arc<ImageView>> {
|
||||||
|
let mut cmd_buf = self.gfx.create_xfer_command_buffer(
|
||||||
|
vulkano::command_buffer::CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let rgba = spb.rgba8888();
|
||||||
|
let image = cmd_buf.upload_image(1, 1, Format::R8G8B8A8_UNORM, &rgba)?;
|
||||||
|
|
||||||
|
cmd_buf.build_and_execute_now()?; //TODO: async
|
||||||
|
|
||||||
|
let image_view = ImageView::new_default(image)?;
|
||||||
|
Ok(image_view)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn import_shm(
|
||||||
|
&mut self,
|
||||||
|
data: *const u8,
|
||||||
|
size: usize,
|
||||||
|
bd: BufferData,
|
||||||
|
) -> anyhow::Result<Arc<ImageView>> {
|
||||||
|
let mut cmd_buf = self.gfx.create_xfer_command_buffer(
|
||||||
|
vulkano::command_buffer::CommandBufferUsage::OneTimeSubmit,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let fourcc = shm_format_to_fourcc(bd.format)
|
||||||
|
.with_context(|| format!("Could not conver {:?} to fourcc", bd.format))?;
|
||||||
|
|
||||||
|
let format = fourcc_to_vk(fourcc)
|
||||||
|
.with_context(|| format!("Could not convert {fourcc} to vkFormat"))?;
|
||||||
|
|
||||||
|
let data = unsafe { std::slice::from_raw_parts(data, size) };
|
||||||
|
let image = cmd_buf.upload_image(bd.width as _, bd.height as _, format, data)?;
|
||||||
|
|
||||||
|
cmd_buf.build_and_execute_now()?; //TODO: async
|
||||||
|
|
||||||
|
let image_view = ImageView::new_default(image)?;
|
||||||
|
Ok(image_view)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_or_import_dmabuf(&mut self, dmabuf: Dmabuf) -> anyhow::Result<Arc<ImageView>> {
|
||||||
|
let mut frame = DmabufFrame {
|
||||||
|
format: FrameFormat {
|
||||||
|
width: dmabuf.width(),
|
||||||
|
height: dmabuf.height(),
|
||||||
|
drm_format: dmabuf.format(),
|
||||||
|
transform: Transform::Undefined,
|
||||||
|
},
|
||||||
|
num_planes: dmabuf.num_planes(),
|
||||||
|
planes: Default::default(),
|
||||||
|
mouse: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i, handle) in dmabuf.handles().enumerate() {
|
||||||
|
// even if the original OwnedFd is dropped, the vkImage will hold reference on the DMA-buf
|
||||||
|
frame.planes[i].fd = Some(handle.as_raw_fd());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, offset) in dmabuf.offsets().enumerate() {
|
||||||
|
frame.planes[i].offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, stride) in dmabuf.strides().enumerate() {
|
||||||
|
frame.planes[i].stride = stride as _;
|
||||||
|
}
|
||||||
|
|
||||||
|
let image = self.gfx.dmabuf_texture(frame)?;
|
||||||
|
let image_view = ImageView::new_default(image)?;
|
||||||
|
self.dmabufs.insert(dmabuf.weak(), image_view.clone());
|
||||||
|
|
||||||
|
Ok(image_view)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup(&mut self) {
|
||||||
|
self.dmabufs.retain(|k, _| !k.is_gone());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,22 @@
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
mod comp;
|
mod comp;
|
||||||
pub mod display;
|
|
||||||
pub mod egl_data;
|
|
||||||
mod egl_ex;
|
|
||||||
pub mod event_queue;
|
|
||||||
mod handle;
|
mod handle;
|
||||||
mod process;
|
mod image_importer;
|
||||||
pub mod server_ipc;
|
pub mod process;
|
||||||
mod smithay_wrapper;
|
|
||||||
mod time;
|
mod time;
|
||||||
mod window;
|
pub mod window;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use comp::Application;
|
use comp::Application;
|
||||||
use display::{Display, DisplayInitParams, DisplayVec};
|
|
||||||
use event_queue::SyncEventQueue;
|
|
||||||
use process::ProcessVec;
|
use process::ProcessVec;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use server_ipc::WayVRServer;
|
use slotmap::SecondaryMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
|
||||||
egl,
|
|
||||||
renderer::{ImportDma, gles::GlesRenderer},
|
|
||||||
},
|
|
||||||
input::{SeatState, keyboard::XkbConfig},
|
input::{SeatState, keyboard::XkbConfig},
|
||||||
output::{Mode, Output},
|
output::{Mode, Output},
|
||||||
reexports::wayland_server::{self, backend::ClientId},
|
reexports::wayland_server::{self, backend::ClientId, protocol::wl_buffer},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor,
|
compositor::{self, SurfaceData},
|
||||||
dmabuf::{DmabufFeedbackBuilder, DmabufState},
|
dmabuf::{DmabufFeedbackBuilder, DmabufState},
|
||||||
selection::data_device::DataDeviceState,
|
selection::data_device::DataDeviceState,
|
||||||
shell::xdg::{ToplevelSurface, XdgShellState},
|
shell::xdg::{ToplevelSurface, XdgShellState},
|
||||||
@@ -37,19 +26,28 @@ use smithay::{
|
|||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
mem::MaybeUninit,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use time::get_millis;
|
use time::get_millis;
|
||||||
use wayvr_ipc::{
|
use vulkano::image::view::ImageView;
|
||||||
packet_client::{self},
|
use wayvr_ipc::packet_server;
|
||||||
packet_server,
|
use wgui::gfx::WGfx;
|
||||||
};
|
use wlx_capture::frame::Transform;
|
||||||
use xkbcommon::xkb;
|
use xkbcommon::xkb;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::{
|
||||||
|
task::{OverlayTask, TaskType},
|
||||||
|
wayvr::{image_importer::ImageImporter, window::Window},
|
||||||
|
},
|
||||||
|
graphics::WGfxExtras,
|
||||||
|
ipc::{event_queue::SyncEventQueue, ipc_server, signal::WayVRSignal},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::{MODS_TO_KEYS, WheelDelta},
|
subsystem::hid::{MODS_TO_KEYS, WheelDelta},
|
||||||
|
windowing::{OverlayID, OverlaySelector},
|
||||||
};
|
};
|
||||||
|
|
||||||
const STR_INVALID_HANDLE_DISP: &str = "Invalid display handle";
|
const STR_INVALID_HANDLE_DISP: &str = "Invalid display handle";
|
||||||
@@ -87,19 +85,6 @@ pub enum WayVRTask {
|
|||||||
ProcessTerminationRequest(process::ProcessHandle),
|
ProcessTerminationRequest(process::ProcessHandle),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum WayVRSignal {
|
|
||||||
DisplayVisibility(display::DisplayHandle, bool),
|
|
||||||
DisplayWindowLayout(
|
|
||||||
display::DisplayHandle,
|
|
||||||
packet_server::WvrDisplayWindowLayout,
|
|
||||||
),
|
|
||||||
BroadcastStateChanged(packet_server::WvrStateChanged),
|
|
||||||
DropOverlay(crate::windowing::OverlayID),
|
|
||||||
Haptics(super::input::Haptics),
|
|
||||||
CustomTask(crate::backend::task::ModifyPanelTask),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum BlitMethod {
|
pub enum BlitMethod {
|
||||||
Dmabuf,
|
Dmabuf,
|
||||||
Software,
|
Software,
|
||||||
@@ -125,22 +110,21 @@ pub struct Config {
|
|||||||
|
|
||||||
pub struct WayVRState {
|
pub struct WayVRState {
|
||||||
time_start: u64,
|
time_start: u64,
|
||||||
pub displays: display::DisplayVec,
|
|
||||||
pub manager: client::WayVRCompositor,
|
pub manager: client::WayVRCompositor,
|
||||||
wm: Rc<RefCell<window::WindowManager>>,
|
pub wm: Rc<RefCell<window::WindowManager>>,
|
||||||
egl_data: Rc<egl_data::EGLData>,
|
|
||||||
pub processes: process::ProcessVec,
|
pub processes: process::ProcessVec,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
dashboard_display: Option<display::DisplayHandle>,
|
|
||||||
pub tasks: SyncEventQueue<WayVRTask>,
|
pub tasks: SyncEventQueue<WayVRTask>,
|
||||||
pub signals: SyncEventQueue<WayVRSignal>,
|
|
||||||
ticks: u64,
|
ticks: u64,
|
||||||
cur_modifiers: u8,
|
cur_modifiers: u8,
|
||||||
|
signals: SyncEventQueue<WayVRSignal>,
|
||||||
|
mouse_freeze: Instant,
|
||||||
|
window_to_overlay: HashMap<window::WindowHandle, OverlayID>,
|
||||||
|
overlay_to_window: SecondaryMap<OverlayID, window::WindowHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WayVR {
|
pub struct WayVR {
|
||||||
pub state: WayVRState,
|
pub state: WayVRState,
|
||||||
pub ipc_server: WayVRServer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MouseIndex {
|
pub enum MouseIndex {
|
||||||
@@ -151,15 +135,16 @@ pub enum MouseIndex {
|
|||||||
|
|
||||||
pub enum TickTask {
|
pub enum TickTask {
|
||||||
NewExternalProcess(ExternalProcessRequest), // Call WayVRCompositor::add_client after receiving this message
|
NewExternalProcess(ExternalProcessRequest), // Call WayVRCompositor::add_client after receiving this message
|
||||||
NewDisplay(
|
|
||||||
packet_client::WvrDisplayCreateParams,
|
|
||||||
Option<display::DisplayHandle>, /* existing handle? */
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WayVR {
|
impl WayVR {
|
||||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn new(config: Config) -> anyhow::Result<Self> {
|
pub fn new(
|
||||||
|
gfx: Arc<WGfx>,
|
||||||
|
gfx_extras: &WGfxExtras,
|
||||||
|
config: Config,
|
||||||
|
signals: SyncEventQueue<WayVRSignal>,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
log::info!("Initializing WayVR");
|
log::info!("Initializing WayVR");
|
||||||
let display: wayland_server::Display<Application> = wayland_server::Display::new()?;
|
let display: wayland_server::Display<Application> = wayland_server::Display::new()?;
|
||||||
let dh = display.handle();
|
let dh = display.handle();
|
||||||
@@ -170,8 +155,8 @@ impl WayVR {
|
|||||||
let data_device = DataDeviceState::new::<Application>(&dh);
|
let data_device = DataDeviceState::new::<Application>(&dh);
|
||||||
let mut seat = seat_state.new_wl_seat(&dh, "wayvr");
|
let mut seat = seat_state.new_wl_seat(&dh, "wayvr");
|
||||||
|
|
||||||
let dummy_width = 1280;
|
let dummy_width = 1920;
|
||||||
let dummy_height = 720;
|
let dummy_height = 1080;
|
||||||
let dummy_milli_hz = 60000; /* refresh rate in millihertz */
|
let dummy_milli_hz = 60000; /* refresh rate in millihertz */
|
||||||
|
|
||||||
let output = Output::new(
|
let output = Output::new(
|
||||||
@@ -193,41 +178,26 @@ impl WayVR {
|
|||||||
output.change_current_state(Some(mode), None, None, None);
|
output.change_current_state(Some(mode), None, None, None);
|
||||||
output.set_preferred(mode);
|
output.set_preferred(mode);
|
||||||
|
|
||||||
let egl_data = egl_data::EGLData::new()?;
|
let main_device = {
|
||||||
|
let (major, minor) = gfx_extras.drm_device.as_ref().context("No DRM device!")?;
|
||||||
let smithay_display = smithay_wrapper::get_egl_display(&egl_data)?;
|
libc::makedev(*major as _, *minor as _)
|
||||||
let smithay_context = smithay_wrapper::get_egl_context(&egl_data, &smithay_display)?;
|
|
||||||
|
|
||||||
let render_node = egl::EGLDevice::device_for_display(&smithay_display)
|
|
||||||
.and_then(|device| device.try_get_render_node());
|
|
||||||
|
|
||||||
let gles_renderer = unsafe { GlesRenderer::new(smithay_context)? };
|
|
||||||
|
|
||||||
let dmabuf_default_feedback = match render_node {
|
|
||||||
Ok(Some(node)) => {
|
|
||||||
let dmabuf_formats = gles_renderer.dmabuf_formats();
|
|
||||||
let dmabuf_default_feedback =
|
|
||||||
DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
Some(dmabuf_default_feedback)
|
|
||||||
}
|
|
||||||
Ok(None) => {
|
|
||||||
log::warn!("dmabuf: Failed to query render node");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
log::warn!("dmabuf: Failed to get egl device for display: {err}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let dmabuf_state = dmabuf_default_feedback.map_or_else(
|
// this will throw a compile-time error if smithay's drm-fourcc is out of sync with wlx-capture's
|
||||||
|| {
|
let mut formats: Vec<smithay::backend::allocator::Format> = vec![];
|
||||||
let dmabuf_formats = gles_renderer.dmabuf_formats();
|
|
||||||
|
for f in gfx_extras.drm_formats.iter() {
|
||||||
|
formats.push(f.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let dmabuf_state = DmabufFeedbackBuilder::new(main_device, formats.clone())
|
||||||
|
.build()
|
||||||
|
.map_or_else(
|
||||||
|
|_| {
|
||||||
|
log::info!("Falling back to zwp_linux_dmabuf_v1 version 3.");
|
||||||
let mut dmabuf_state = DmabufState::new();
|
let mut dmabuf_state = DmabufState::new();
|
||||||
let dmabuf_global =
|
let dmabuf_global =
|
||||||
dmabuf_state.create_global::<Application>(&display.handle(), dmabuf_formats);
|
dmabuf_state.create_global::<Application>(&display.handle(), formats);
|
||||||
(dmabuf_state, dmabuf_global, None)
|
(dmabuf_state, dmabuf_global, None)
|
||||||
},
|
},
|
||||||
|default_feedback| {
|
|default_feedback| {
|
||||||
@@ -250,7 +220,10 @@ impl WayVR {
|
|||||||
|
|
||||||
let tasks = SyncEventQueue::new();
|
let tasks = SyncEventQueue::new();
|
||||||
|
|
||||||
|
let dma_importer = ImageImporter::new(gfx);
|
||||||
|
|
||||||
let state = Application {
|
let state = Application {
|
||||||
|
image_importer: dma_importer,
|
||||||
compositor,
|
compositor,
|
||||||
xdg_shell,
|
xdg_shell,
|
||||||
seat_state,
|
seat_state,
|
||||||
@@ -259,109 +232,54 @@ impl WayVR {
|
|||||||
wayvr_tasks: tasks.clone(),
|
wayvr_tasks: tasks.clone(),
|
||||||
redraw_requests: HashSet::new(),
|
redraw_requests: HashSet::new(),
|
||||||
dmabuf_state,
|
dmabuf_state,
|
||||||
gles_renderer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let time_start = get_millis();
|
let time_start = get_millis();
|
||||||
|
|
||||||
let ipc_server = WayVRServer::new()?;
|
|
||||||
|
|
||||||
let state = WayVRState {
|
let state = WayVRState {
|
||||||
time_start,
|
time_start,
|
||||||
manager: client::WayVRCompositor::new(state, display, seat_keyboard, seat_pointer)?,
|
manager: client::WayVRCompositor::new(state, display, seat_keyboard, seat_pointer)?,
|
||||||
displays: DisplayVec::new(),
|
|
||||||
processes: ProcessVec::new(),
|
processes: ProcessVec::new(),
|
||||||
egl_data: Rc::new(egl_data),
|
|
||||||
wm: Rc::new(RefCell::new(window::WindowManager::new())),
|
wm: Rc::new(RefCell::new(window::WindowManager::new())),
|
||||||
config,
|
config,
|
||||||
dashboard_display: None,
|
|
||||||
ticks: 0,
|
ticks: 0,
|
||||||
tasks,
|
tasks,
|
||||||
signals: SyncEventQueue::new(),
|
|
||||||
cur_modifiers: 0,
|
cur_modifiers: 0,
|
||||||
|
signals,
|
||||||
|
mouse_freeze: Instant::now(),
|
||||||
|
window_to_overlay: HashMap::new(),
|
||||||
|
overlay_to_window: SecondaryMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self { state, ipc_server })
|
Ok(Self { state })
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_display(&mut self, display: display::DisplayHandle) -> anyhow::Result<bool> {
|
|
||||||
let display = self
|
|
||||||
.state
|
|
||||||
.displays
|
|
||||||
.get_mut(&display)
|
|
||||||
.context(STR_INVALID_HANDLE_DISP)?;
|
|
||||||
|
|
||||||
/* Buffer warm-up is required, always two first calls of this function are always rendered */
|
|
||||||
if !display.wants_redraw && display.rendered_frame_count >= 2 {
|
|
||||||
// Nothing changed, do not render
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !display.visible {
|
|
||||||
// Display is invisible, do not render
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// millis since the start of wayvr
|
|
||||||
let time_ms = get_millis() - self.state.time_start;
|
|
||||||
|
|
||||||
display.tick_render(&mut self.state.manager.state.gles_renderer, time_ms)?;
|
|
||||||
display.wants_redraw = false;
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn tick_events(&mut self, app: &AppState) -> anyhow::Result<Vec<TickTask>> {
|
pub fn tick_events(&mut self, app: &mut AppState) -> anyhow::Result<Vec<TickTask>> {
|
||||||
let mut tasks: Vec<TickTask> = Vec::new();
|
let mut tasks: Vec<TickTask> = Vec::new();
|
||||||
|
|
||||||
self.ipc_server.tick(&mut server_ipc::TickParams {
|
app.ipc_server.tick(&mut ipc_server::TickParams {
|
||||||
state: &mut self.state,
|
wayland_state: &mut self.state,
|
||||||
|
input_state: &app.input_state,
|
||||||
tasks: &mut tasks,
|
tasks: &mut tasks,
|
||||||
app,
|
signals: &app.wayvr_signals,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for redraw events
|
|
||||||
for (_, disp) in self.state.displays.iter_mut() {
|
|
||||||
for disp_window in &disp.displayed_windows {
|
|
||||||
if self
|
|
||||||
.state
|
|
||||||
.manager
|
|
||||||
.state
|
|
||||||
.check_redraw(disp_window.toplevel.wl_surface())
|
|
||||||
{
|
|
||||||
disp.wants_redraw = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tick all child processes
|
// Tick all child processes
|
||||||
let mut to_remove: SmallVec<[(process::ProcessHandle, display::DisplayHandle); 2]> =
|
let mut to_remove: SmallVec<[process::ProcessHandle; 2]> = SmallVec::new();
|
||||||
SmallVec::new();
|
|
||||||
|
|
||||||
for (handle, process) in self.state.processes.iter_mut() {
|
for (handle, process) in self.state.processes.iter_mut() {
|
||||||
if !process.is_running() {
|
if !process.is_running() {
|
||||||
to_remove.push((handle, process.display_handle()));
|
to_remove.push(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p_handle, disp_handle) in &to_remove {
|
for p_handle in &to_remove {
|
||||||
self.state.processes.remove(p_handle);
|
self.state.processes.remove(p_handle);
|
||||||
|
|
||||||
if let Some(display) = self.state.displays.get_mut(disp_handle) {
|
|
||||||
display
|
|
||||||
.tasks
|
|
||||||
.send(display::DisplayTask::ProcessCleanup(*p_handle));
|
|
||||||
display.wants_redraw = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (handle, display) in self.state.displays.iter_mut() {
|
|
||||||
display.tick(&self.state.config, &handle, &mut self.state.signals);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !to_remove.is_empty() {
|
if !to_remove.is_empty() {
|
||||||
self.state.signals.send(WayVRSignal::BroadcastStateChanged(
|
app.wayvr_signals.send(WayVRSignal::BroadcastStateChanged(
|
||||||
packet_server::WvrStateChanged::ProcessRemoved,
|
packet_server::WvrStateChanged::ProcessRemoved,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -392,17 +310,11 @@ impl WayVR {
|
|||||||
.state
|
.state
|
||||||
.wm
|
.wm
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.create_window(client.display_handle, &toplevel);
|
.create_window(&toplevel, process_handle);
|
||||||
|
|
||||||
let Some(display) = self.state.displays.get_mut(&client.display_handle)
|
//TODO: create overlay
|
||||||
else {
|
|
||||||
// This shouldn't happen, scream if it does
|
|
||||||
log::error!("Could not attach window handle into display");
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
display.add_window(window_handle, process_handle, &toplevel);
|
app.wayvr_signals.send(WayVRSignal::BroadcastStateChanged(
|
||||||
self.state.signals.send(WayVRSignal::BroadcastStateChanged(
|
|
||||||
packet_server::WvrStateChanged::WindowCreated,
|
packet_server::WvrStateChanged::WindowCreated,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -419,18 +331,15 @@ impl WayVR {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(display) = self.state.displays.get_mut(&client.display_handle)
|
if let Some(oid) = self.state.window_to_overlay.get(&window_handle) {
|
||||||
else {
|
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Drop(
|
||||||
log::warn!("DropToplevel: Couldn't find matching display");
|
OverlaySelector::Id(*oid),
|
||||||
continue;
|
)));
|
||||||
};
|
}
|
||||||
|
|
||||||
display.remove_window(window_handle);
|
|
||||||
wm.remove_window(window_handle);
|
wm.remove_window(window_handle);
|
||||||
|
|
||||||
drop(wm);
|
drop(wm);
|
||||||
|
|
||||||
display.reposition_windows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WayVRTask::ProcessTerminationRequest(process_handle) => {
|
WayVRTask::ProcessTerminationRequest(process_handle) => {
|
||||||
@@ -441,12 +350,11 @@ impl WayVR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state
|
self.state.manager.tick_wayland(&mut self.state.processes)?;
|
||||||
.manager
|
|
||||||
.tick_wayland(&mut self.state.displays, &mut self.state.processes)?;
|
|
||||||
|
|
||||||
if self.state.ticks.is_multiple_of(200) {
|
if self.state.ticks.is_multiple_of(200) {
|
||||||
self.state.manager.cleanup_clients();
|
self.state.manager.cleanup_clients();
|
||||||
|
self.state.manager.cleanup_handles();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state.ticks += 1;
|
self.state.ticks += 1;
|
||||||
@@ -454,44 +362,6 @@ impl WayVR {
|
|||||||
Ok(tasks)
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_finish(&mut self) -> anyhow::Result<()> {
|
|
||||||
self.state
|
|
||||||
.manager
|
|
||||||
.state
|
|
||||||
.gles_renderer
|
|
||||||
.with_context(|gl| unsafe {
|
|
||||||
gl.Flush();
|
|
||||||
gl.Finish();
|
|
||||||
})?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn get_primary_display(displays: &DisplayVec) -> Option<display::DisplayHandle> {
|
|
||||||
for (idx, cell) in displays.vec.iter().enumerate() {
|
|
||||||
if let Some(cell) = cell
|
|
||||||
&& cell.obj.primary
|
|
||||||
{
|
|
||||||
return Some(DisplayVec::get_handle(cell, idx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_display_by_name(
|
|
||||||
displays: &DisplayVec,
|
|
||||||
name: &str,
|
|
||||||
) -> Option<display::DisplayHandle> {
|
|
||||||
for (idx, cell) in displays.vec.iter().enumerate() {
|
|
||||||
if let Some(cell) = cell
|
|
||||||
&& cell.obj.name == name
|
|
||||||
{
|
|
||||||
return Some(DisplayVec::get_handle(cell, idx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn terminate_process(&mut self, process_handle: process::ProcessHandle) {
|
pub fn terminate_process(&mut self, process_handle: process::ProcessHandle) {
|
||||||
self.state
|
self.state
|
||||||
.tasks
|
.tasks
|
||||||
@@ -500,24 +370,30 @@ impl WayVR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WayVRState {
|
impl WayVRState {
|
||||||
pub fn send_mouse_move(&mut self, display: display::DisplayHandle, x: u32, y: u32) {
|
pub fn send_mouse_move(&mut self, handle: window::WindowHandle, x: u32, y: u32) {
|
||||||
if let Some(display) = self.displays.get(&display) {
|
if self.mouse_freeze > Instant::now() {
|
||||||
display.send_mouse_move(&self.config, &mut self.manager, x, y);
|
return;
|
||||||
|
}
|
||||||
|
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&handle) {
|
||||||
|
window.send_mouse_move(&mut self.manager, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_down(&mut self, display: display::DisplayHandle, index: MouseIndex) {
|
pub fn send_mouse_down(&mut self, handle: window::WindowHandle, index: MouseIndex) {
|
||||||
if let Some(display) = self.displays.get_mut(&display) {
|
self.mouse_freeze =
|
||||||
display.send_mouse_down(&mut self.manager, index);
|
Instant::now() + Duration::from_millis(self.config.click_freeze_time_ms as _);
|
||||||
|
|
||||||
|
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&handle) {
|
||||||
|
window.send_mouse_down(&mut self.manager, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_up(&mut self, index: MouseIndex) {
|
pub fn send_mouse_up(&mut self, index: MouseIndex) {
|
||||||
Display::send_mouse_up(&mut self.manager, index);
|
Window::send_mouse_up(&mut self.manager, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_scroll(&mut self, delta: WheelDelta) {
|
pub fn send_mouse_scroll(&mut self, delta: WheelDelta) {
|
||||||
Display::send_mouse_scroll(&mut self.manager, delta);
|
Window::send_mouse_scroll(&mut self.manager, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_key(&mut self, virtual_key: u32, down: bool) {
|
pub fn send_key(&mut self, virtual_key: u32, down: bool) {
|
||||||
@@ -541,125 +417,9 @@ impl WayVRState {
|
|||||||
self.cur_modifiers = modifiers;
|
self.cur_modifiers = modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_display_visible(&mut self, display: display::DisplayHandle, visible: bool) {
|
|
||||||
if let Some(display) = self.displays.get_mut(&display) {
|
|
||||||
display.set_visible(visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_display_layout(
|
|
||||||
&mut self,
|
|
||||||
display: display::DisplayHandle,
|
|
||||||
layout: packet_server::WvrDisplayWindowLayout,
|
|
||||||
) {
|
|
||||||
if let Some(display) = self.displays.get_mut(&display) {
|
|
||||||
display.set_layout(layout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_render_data(
|
|
||||||
&self,
|
|
||||||
display: display::DisplayHandle,
|
|
||||||
) -> Option<&egl_data::RenderData> {
|
|
||||||
self.displays
|
|
||||||
.get(&display)
|
|
||||||
.map(|display| &display.render_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_display(
|
|
||||||
&mut self,
|
|
||||||
width: u16,
|
|
||||||
height: u16,
|
|
||||||
name: &str,
|
|
||||||
primary: bool,
|
|
||||||
) -> anyhow::Result<display::DisplayHandle> {
|
|
||||||
let display = display::Display::new(DisplayInitParams {
|
|
||||||
wm: self.wm.clone(),
|
|
||||||
egl_data: self.egl_data.clone(),
|
|
||||||
renderer: &mut self.manager.state.gles_renderer,
|
|
||||||
wayland_env: self.manager.wayland_env.clone(),
|
|
||||||
config: &self.config,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
name,
|
|
||||||
primary,
|
|
||||||
})?;
|
|
||||||
let handle = self.displays.add(display);
|
|
||||||
|
|
||||||
self.signals.send(WayVRSignal::BroadcastStateChanged(
|
|
||||||
packet_server::WvrStateChanged::DisplayCreated,
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy_display(&mut self, handle: display::DisplayHandle) -> anyhow::Result<()> {
|
|
||||||
let Some(display) = self.displays.get(&handle) else {
|
|
||||||
anyhow::bail!("Display not found");
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(overlay_id) = display.overlay_id {
|
|
||||||
self.signals.send(WayVRSignal::DropOverlay(overlay_id));
|
|
||||||
} else {
|
|
||||||
log::warn!("Destroying display without OverlayID set"); // This shouldn't happen, but log it anyways.
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut process_names = Vec::<String>::new();
|
|
||||||
|
|
||||||
for (_, process) in self.processes.iter_mut() {
|
|
||||||
if process.display_handle() == handle {
|
|
||||||
process_names.push(process.get_name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !display.displayed_windows.is_empty() || !process_names.is_empty() {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Display is not empty. Attached processes: {}",
|
|
||||||
process_names.join(", ")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.manager.cleanup_clients();
|
|
||||||
|
|
||||||
for client in &self.manager.clients {
|
|
||||||
if client.display_handle == handle {
|
|
||||||
// This shouldn't happen, but make sure we are all set to destroy this display
|
|
||||||
anyhow::bail!("Wayland client still exists");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.displays.remove(&handle);
|
|
||||||
|
|
||||||
self.signals.send(WayVRSignal::BroadcastStateChanged(
|
|
||||||
packet_server::WvrStateChanged::DisplayRemoved,
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_or_create_dashboard_display(
|
|
||||||
&mut self,
|
|
||||||
width: u16,
|
|
||||||
height: u16,
|
|
||||||
name: &str,
|
|
||||||
) -> anyhow::Result<(bool /* newly created? */, display::DisplayHandle)> {
|
|
||||||
if let Some(handle) = &self.dashboard_display {
|
|
||||||
// ensure it still exists
|
|
||||||
if self.displays.get(handle).is_some() {
|
|
||||||
return Ok((false, *handle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_disp = self.create_display(width, height, name, false)?;
|
|
||||||
self.dashboard_display = Some(new_disp);
|
|
||||||
|
|
||||||
Ok((true, new_disp))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if process with given arguments already exists
|
// Check if process with given arguments already exists
|
||||||
pub fn process_query(
|
pub fn process_query(
|
||||||
&self,
|
&self,
|
||||||
display_handle: display::DisplayHandle,
|
|
||||||
exec_path: &str,
|
exec_path: &str,
|
||||||
args: &[&str],
|
args: &[&str],
|
||||||
_env: &[(&str, &str)],
|
_env: &[(&str, &str)],
|
||||||
@@ -668,10 +428,7 @@ impl WayVRState {
|
|||||||
if let Some(cell) = &cell
|
if let Some(cell) = &cell
|
||||||
&& let process::Process::Managed(process) = &cell.obj
|
&& let process::Process::Managed(process) = &cell.obj
|
||||||
{
|
{
|
||||||
if process.display_handle != display_handle
|
if process.exec_path != exec_path || process.args != args {
|
||||||
|| process.exec_path != exec_path
|
|
||||||
|| process.args != args
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return Some(process::ProcessVec::get_handle(cell, idx));
|
return Some(process::ProcessVec::get_handle(cell, idx));
|
||||||
@@ -681,40 +438,39 @@ impl WayVRState {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_external_process(
|
pub fn add_external_process(&mut self, pid: u32) -> process::ProcessHandle {
|
||||||
&mut self,
|
|
||||||
display_handle: display::DisplayHandle,
|
|
||||||
pid: u32,
|
|
||||||
) -> process::ProcessHandle {
|
|
||||||
self.processes
|
self.processes
|
||||||
.add(process::Process::External(process::ExternalProcess {
|
.add(process::Process::External(process::ExternalProcess { pid }))
|
||||||
pid,
|
|
||||||
display_handle,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_process(
|
pub fn spawn_process(
|
||||||
&mut self,
|
&mut self,
|
||||||
display_handle: display::DisplayHandle,
|
|
||||||
exec_path: &str,
|
exec_path: &str,
|
||||||
args: &[&str],
|
args: &[&str],
|
||||||
env: &[(&str, &str)],
|
env: &[(&str, &str)],
|
||||||
working_dir: Option<&str>,
|
working_dir: Option<&str>,
|
||||||
userdata: HashMap<String, String>,
|
userdata: HashMap<String, String>,
|
||||||
) -> anyhow::Result<process::ProcessHandle> {
|
) -> anyhow::Result<process::ProcessHandle> {
|
||||||
let display = self
|
let auth_key = generate_auth_key();
|
||||||
.displays
|
|
||||||
.get_mut(&display_handle)
|
|
||||||
.context(STR_INVALID_HANDLE_DISP)?;
|
|
||||||
|
|
||||||
let res = display.spawn_process(exec_path, args, env, working_dir)?;
|
let mut cmd = std::process::Command::new(exec_path);
|
||||||
|
self.configure_env(&mut cmd, auth_key.as_str());
|
||||||
|
cmd.args(args);
|
||||||
|
if let Some(working_dir) = working_dir {
|
||||||
|
cmd.current_dir(working_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
for e in env {
|
||||||
|
cmd.env(e.0, e.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let child = cmd.spawn().context("Failed to spawn child process")?;
|
||||||
|
|
||||||
let handle = self
|
let handle = self
|
||||||
.processes
|
.processes
|
||||||
.add(process::Process::Managed(process::WayVRProcess {
|
.add(process::Process::Managed(process::WayVRProcess {
|
||||||
auth_key: res.auth_key,
|
auth_key,
|
||||||
child: res.child,
|
child,
|
||||||
display_handle,
|
|
||||||
exec_path: String::from(exec_path),
|
exec_path: String::from(exec_path),
|
||||||
userdata,
|
userdata,
|
||||||
args: args.iter().map(|x| String::from(*x)).collect(),
|
args: args.iter().map(|x| String::from(*x)).collect(),
|
||||||
@@ -731,6 +487,25 @@ impl WayVRState {
|
|||||||
|
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn configure_env(&self, cmd: &mut std::process::Command, auth_key: &str) {
|
||||||
|
cmd.env_remove("DISPLAY"); // Goodbye X11
|
||||||
|
cmd.env(
|
||||||
|
"WAYLAND_DISPLAY",
|
||||||
|
self.manager.wayland_env.display_num_string(),
|
||||||
|
);
|
||||||
|
cmd.env("WAYVR_DISPLAY_AUTH", auth_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_auth_key() -> String {
|
||||||
|
let uuid = uuid::Uuid::new_v4();
|
||||||
|
uuid.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SpawnProcessResult {
|
||||||
|
pub auth_key: String,
|
||||||
|
pub child: std::process::Child,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
@@ -751,3 +526,34 @@ pub enum WayVRAction {
|
|||||||
},
|
},
|
||||||
ToggleDashboard,
|
ToggleDashboard,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SurfaceBufWithImageContainer {
|
||||||
|
inner: RefCell<SurfaceBufWithImage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SurfaceBufWithImage {
|
||||||
|
buffer: wl_buffer::WlBuffer,
|
||||||
|
pub image: Arc<ImageView>,
|
||||||
|
pub transform: Transform,
|
||||||
|
pub scale: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SurfaceBufWithImage {
|
||||||
|
fn apply_to_surface(self, surface_data: &SurfaceData) {
|
||||||
|
let container = surface_data.data_map.get_or_insert(|| unsafe {
|
||||||
|
SurfaceBufWithImageContainer {
|
||||||
|
inner: RefCell::new(MaybeUninit::uninit().assume_init()),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
container.inner.replace(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_from_surface(surface_data: &SurfaceData) -> Option<Self> {
|
||||||
|
surface_data
|
||||||
|
.data_map
|
||||||
|
.get::<SurfaceBufWithImageContainer>()
|
||||||
|
.map(|x| x.inner.borrow().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,14 +4,11 @@ use wayvr_ipc::packet_server;
|
|||||||
|
|
||||||
use crate::gen_id;
|
use crate::gen_id;
|
||||||
|
|
||||||
use super::display;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct WayVRProcess {
|
pub struct WayVRProcess {
|
||||||
pub auth_key: String,
|
pub auth_key: String,
|
||||||
pub child: std::process::Child,
|
pub child: std::process::Child,
|
||||||
pub display_handle: display::DisplayHandle,
|
|
||||||
|
|
||||||
pub exec_path: String,
|
pub exec_path: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
@@ -24,7 +21,6 @@ pub struct WayVRProcess {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ExternalProcess {
|
pub struct ExternalProcess {
|
||||||
pub pid: u32,
|
pub pid: u32,
|
||||||
pub display_handle: display::DisplayHandle,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -34,13 +30,6 @@ pub enum Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
pub const fn display_handle(&self) -> display::DisplayHandle {
|
|
||||||
match self {
|
|
||||||
Self::Managed(p) => p.display_handle,
|
|
||||||
Self::External(p) => p.display_handle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Managed(p) => p.is_running(),
|
Self::Managed(p) => p.is_running(),
|
||||||
@@ -67,13 +56,11 @@ impl Process {
|
|||||||
Self::Managed(p) => packet_server::WvrProcess {
|
Self::Managed(p) => packet_server::WvrProcess {
|
||||||
name: p.get_name().unwrap_or_else(|| String::from("unknown")),
|
name: p.get_name().unwrap_or_else(|| String::from("unknown")),
|
||||||
userdata: p.userdata.clone(),
|
userdata: p.userdata.clone(),
|
||||||
display_handle: p.display_handle.as_packet(),
|
|
||||||
handle: handle.as_packet(),
|
handle: handle.as_packet(),
|
||||||
},
|
},
|
||||||
Self::External(p) => packet_server::WvrProcess {
|
Self::External(p) => packet_server::WvrProcess {
|
||||||
name: p.get_name().unwrap_or_else(|| String::from("unknown")),
|
name: p.get_name().unwrap_or_else(|| String::from("unknown")),
|
||||||
userdata: HashMap::default(),
|
userdata: HashMap::default(),
|
||||||
display_handle: p.display_handle.as_packet(),
|
|
||||||
handle: handle.as_packet(),
|
handle: handle.as_packet(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
use super::egl_data;
|
|
||||||
use smithay::backend::{egl as smithay_egl, renderer::gles::ffi};
|
|
||||||
|
|
||||||
pub fn get_egl_display(data: &egl_data::EGLData) -> anyhow::Result<smithay_egl::EGLDisplay> {
|
|
||||||
Ok(unsafe { smithay_egl::EGLDisplay::from_raw(data.display.as_ptr(), data.config.as_ptr())? })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_egl_context(
|
|
||||||
data: &egl_data::EGLData,
|
|
||||||
display: &smithay_egl::EGLDisplay,
|
|
||||||
) -> anyhow::Result<smithay_egl::EGLContext> {
|
|
||||||
let display_ptr = display.get_display_handle().handle;
|
|
||||||
debug_assert!(std::ptr::eq(display_ptr, data.display.as_ptr()));
|
|
||||||
let config_ptr = data.config.as_ptr();
|
|
||||||
let context_ptr = data.context.as_ptr();
|
|
||||||
Ok(unsafe { smithay_egl::EGLContext::from_raw(display_ptr, config_ptr, context_ptr)? })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_framebuffer_texture(
|
|
||||||
gl: &ffi::Gles2,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
tex_format: u32,
|
|
||||||
internal_format: u32,
|
|
||||||
) -> u32 {
|
|
||||||
unsafe {
|
|
||||||
let mut tex = 0;
|
|
||||||
gl.GenTextures(1, &raw mut tex);
|
|
||||||
gl.BindTexture(ffi::TEXTURE_2D, tex);
|
|
||||||
gl.TexParameteri(
|
|
||||||
ffi::TEXTURE_2D,
|
|
||||||
ffi::TEXTURE_MIN_FILTER,
|
|
||||||
ffi::NEAREST as i32,
|
|
||||||
);
|
|
||||||
gl.TexParameteri(
|
|
||||||
ffi::TEXTURE_2D,
|
|
||||||
ffi::TEXTURE_MAG_FILTER,
|
|
||||||
ffi::NEAREST as i32,
|
|
||||||
);
|
|
||||||
gl.TexImage2D(
|
|
||||||
ffi::TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
internal_format as i32,
|
|
||||||
width as i32,
|
|
||||||
height as i32,
|
|
||||||
0,
|
|
||||||
tex_format,
|
|
||||||
ffi::UNSIGNED_BYTE,
|
|
||||||
std::ptr::null(),
|
|
||||||
);
|
|
||||||
gl.BindTexture(ffi::TEXTURE_2D, 0);
|
|
||||||
tex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +1,36 @@
|
|||||||
use smithay::wayland::shell::xdg::ToplevelSurface;
|
use smithay::{
|
||||||
|
input,
|
||||||
|
utils::{Logical, Point},
|
||||||
|
wayland::shell::xdg::ToplevelSurface,
|
||||||
|
};
|
||||||
use wayvr_ipc::packet_server;
|
use wayvr_ipc::packet_server;
|
||||||
|
|
||||||
use crate::gen_id;
|
use crate::{
|
||||||
|
backend::wayvr::{client::WayVRCompositor, process},
|
||||||
use super::display;
|
gen_id,
|
||||||
|
subsystem::hid::WheelDelta,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub pos_x: i32,
|
|
||||||
pub pos_y: i32,
|
|
||||||
pub size_x: u32,
|
pub size_x: u32,
|
||||||
pub size_y: u32,
|
pub size_y: u32,
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
pub toplevel: ToplevelSurface,
|
pub toplevel: ToplevelSurface,
|
||||||
pub display_handle: display::DisplayHandle,
|
pub process: process::ProcessHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(display_handle: display::DisplayHandle, toplevel: &ToplevelSurface) -> Self {
|
fn new(toplevel: &ToplevelSurface, process: process::ProcessHandle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos_x: 0,
|
|
||||||
pos_y: 0,
|
|
||||||
size_x: 0,
|
size_x: 0,
|
||||||
size_y: 0,
|
size_y: 0,
|
||||||
visible: true,
|
visible: true,
|
||||||
toplevel: toplevel.clone(),
|
toplevel: toplevel.clone(),
|
||||||
display_handle,
|
process,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn set_pos(&mut self, pos_x: i32, pos_y: i32) {
|
|
||||||
self.pos_x = pos_x;
|
|
||||||
self.pos_y = pos_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_size(&mut self, size_x: u32, size_y: u32) {
|
pub fn set_size(&mut self, size_x: u32, size_y: u32) {
|
||||||
self.toplevel.with_pending_state(|state| {
|
self.toplevel.with_pending_state(|state| {
|
||||||
//state.bounds = Some((size_x as i32, size_y as i32).into());
|
//state.bounds = Some((size_x as i32, size_y as i32).into());
|
||||||
@@ -44,6 +41,86 @@ impl Window {
|
|||||||
self.size_x = size_x;
|
self.size_x = size_x;
|
||||||
self.size_y = size_y;
|
self.size_y = size_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_mouse_move(&self, manager: &mut WayVRCompositor, x: u32, y: u32) {
|
||||||
|
let surf = self.toplevel.wl_surface().clone();
|
||||||
|
let point = Point::<f64, Logical>::from((f64::from(x as i32), f64::from(y as i32)));
|
||||||
|
|
||||||
|
manager.seat_pointer.motion(
|
||||||
|
&mut manager.state,
|
||||||
|
Some((surf, Point::from((0.0, 0.0)))),
|
||||||
|
&input::pointer::MotionEvent {
|
||||||
|
serial: manager.serial_counter.next_serial(),
|
||||||
|
time: 0,
|
||||||
|
location: point,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
manager.seat_pointer.frame(&mut manager.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn get_mouse_index_number(index: super::MouseIndex) -> u32 {
|
||||||
|
match index {
|
||||||
|
super::MouseIndex::Left => 0x110, /* BTN_LEFT */
|
||||||
|
super::MouseIndex::Center => 0x112, /* BTN_MIDDLE */
|
||||||
|
super::MouseIndex::Right => 0x111, /* BTN_RIGHT */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_mouse_down(&mut self, manager: &mut WayVRCompositor, index: super::MouseIndex) {
|
||||||
|
let surf = self.toplevel.wl_surface().clone();
|
||||||
|
|
||||||
|
// Change keyboard focus to pressed window
|
||||||
|
manager.seat_keyboard.set_focus(
|
||||||
|
&mut manager.state,
|
||||||
|
Some(surf),
|
||||||
|
manager.serial_counter.next_serial(),
|
||||||
|
);
|
||||||
|
|
||||||
|
manager.seat_pointer.button(
|
||||||
|
&mut manager.state,
|
||||||
|
&input::pointer::ButtonEvent {
|
||||||
|
button: Self::get_mouse_index_number(index),
|
||||||
|
serial: manager.serial_counter.next_serial(),
|
||||||
|
time: 0,
|
||||||
|
state: smithay::backend::input::ButtonState::Pressed,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
manager.seat_pointer.frame(&mut manager.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_mouse_up(manager: &mut WayVRCompositor, index: super::MouseIndex) {
|
||||||
|
manager.seat_pointer.button(
|
||||||
|
&mut manager.state,
|
||||||
|
&input::pointer::ButtonEvent {
|
||||||
|
button: Self::get_mouse_index_number(index),
|
||||||
|
serial: manager.serial_counter.next_serial(),
|
||||||
|
time: 0,
|
||||||
|
state: smithay::backend::input::ButtonState::Released,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
manager.seat_pointer.frame(&mut manager.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_mouse_scroll(manager: &mut WayVRCompositor, delta: WheelDelta) {
|
||||||
|
manager.seat_pointer.axis(
|
||||||
|
&mut manager.state,
|
||||||
|
input::pointer::AxisFrame {
|
||||||
|
source: None,
|
||||||
|
relative_direction: (
|
||||||
|
smithay::backend::input::AxisRelativeDirection::Identical,
|
||||||
|
smithay::backend::input::AxisRelativeDirection::Identical,
|
||||||
|
),
|
||||||
|
time: 0,
|
||||||
|
axis: (f64::from(delta.x), f64::from(-delta.y)),
|
||||||
|
v120: Some((0, (delta.y * -64.0) as i32)),
|
||||||
|
stop: (false, false),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
manager.seat_pointer.frame(&mut manager.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -72,10 +149,10 @@ impl WindowManager {
|
|||||||
|
|
||||||
pub fn create_window(
|
pub fn create_window(
|
||||||
&mut self,
|
&mut self,
|
||||||
display_handle: display::DisplayHandle,
|
|
||||||
toplevel: &ToplevelSurface,
|
toplevel: &ToplevelSurface,
|
||||||
|
process: process::ProcessHandle,
|
||||||
) -> WindowHandle {
|
) -> WindowHandle {
|
||||||
self.windows.add(Window::new(display_handle, toplevel))
|
self.windows.add(Window::new(toplevel, process))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_window(&mut self, window_handle: WindowHandle) {
|
pub fn remove_window(&mut self, window_handle: WindowHandle) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use wgui::gfx::WGfx;
|
||||||
use wlx_common::{common::LeftRight, config::GeneralConfig, windowing::Positioning};
|
use wlx_common::{common::LeftRight, config::GeneralConfig, windowing::Positioning};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -19,7 +20,9 @@ use crate::{
|
|||||||
},
|
},
|
||||||
config::load_config_with_conf_d,
|
config::load_config_with_conf_d,
|
||||||
config_io,
|
config_io,
|
||||||
overlays::wayvr::{WayVRData, executable_exists_in_path},
|
graphics::WGfxExtras,
|
||||||
|
ipc::{event_queue::SyncEventQueue, signal::WayVRSignal},
|
||||||
|
overlays::wayvr::WayVRData,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flat version of RelativeTo
|
// Flat version of RelativeTo
|
||||||
@@ -135,9 +138,6 @@ pub struct WayVRDashboard {
|
|||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct WayVRConfig {
|
pub struct WayVRConfig {
|
||||||
#[serde(default = "def_true")]
|
|
||||||
pub run_compositor_at_start: bool,
|
|
||||||
|
|
||||||
#[serde(default = "Default::default")]
|
#[serde(default = "Default::default")]
|
||||||
pub catalogs: HashMap<String, WayVRCatalog>,
|
pub catalogs: HashMap<String, WayVRCatalog>,
|
||||||
|
|
||||||
@@ -201,9 +201,12 @@ impl WayVRConfig {
|
|||||||
|
|
||||||
pub fn post_load(
|
pub fn post_load(
|
||||||
&self,
|
&self,
|
||||||
|
gfx: Arc<WGfx>,
|
||||||
|
gfx_extras: &WGfxExtras,
|
||||||
config: &GeneralConfig,
|
config: &GeneralConfig,
|
||||||
tasks: &mut TaskContainer,
|
tasks: &mut TaskContainer,
|
||||||
) -> anyhow::Result<Option<Rc<RefCell<WayVRData>>>> {
|
signals: SyncEventQueue<WayVRSignal>,
|
||||||
|
) -> anyhow::Result<Rc<RefCell<WayVRData>>> {
|
||||||
let primary_count = self
|
let primary_count = self
|
||||||
.displays
|
.displays
|
||||||
.iter()
|
.iter()
|
||||||
@@ -212,10 +215,6 @@ impl WayVRConfig {
|
|||||||
|
|
||||||
if primary_count > 1 {
|
if primary_count > 1 {
|
||||||
anyhow::bail!("Number of primary displays is more than 1")
|
anyhow::bail!("Number of primary displays is more than 1")
|
||||||
} else if primary_count == 0 {
|
|
||||||
log::warn!(
|
|
||||||
"No primary display specified. External Wayland applications will not be attached."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (catalog_name, catalog) in &self.catalogs {
|
for (catalog_name, catalog) in &self.catalogs {
|
||||||
@@ -231,15 +230,12 @@ impl WayVRConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.run_compositor_at_start {
|
Ok(Rc::new(RefCell::new(WayVRData::new(
|
||||||
// Start Wayland server instantly
|
gfx,
|
||||||
Ok(Some(Rc::new(RefCell::new(WayVRData::new(
|
gfx_extras,
|
||||||
Self::get_wayvr_config(config, self)?,
|
Self::get_wayvr_config(config, self)?,
|
||||||
)?))))
|
signals,
|
||||||
} else {
|
)?)))
|
||||||
// Lazy-init WayVR later if the user requested
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,6 +254,19 @@ fn get_default_dashboard_exec() -> (
|
|||||||
(String::from("wayvr-dashboard"), None)
|
(String::from("wayvr-dashboard"), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn executable_exists_in_path(command: &str) -> bool {
|
||||||
|
let Ok(path) = std::env::var("PATH") else {
|
||||||
|
return false; // very unlikely to happen
|
||||||
|
};
|
||||||
|
for dir in path.split(':') {
|
||||||
|
let exec_path = std::path::PathBuf::from(dir).join(command);
|
||||||
|
if exec_path.exists() && exec_path.is_file() {
|
||||||
|
return true; // executable found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_wayvr() -> WayVRConfig {
|
pub fn load_wayvr() -> WayVRConfig {
|
||||||
let config_root_path = config_io::ConfigRoot::WayVR.ensure_dir();
|
let config_root_path = config_io::ConfigRoot::WayVR.ensure_dir();
|
||||||
log::info!("WayVR Config root path: {}", config_root_path.display());
|
log::info!("WayVR Config root path: {}", config_root_path.display());
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use smallvec::SmallVec;
|
use smallvec::{SmallVec, smallvec};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
VulkanError, VulkanObject,
|
VulkanError, VulkanObject,
|
||||||
device::Device,
|
device::Device,
|
||||||
@@ -19,12 +19,7 @@ use vulkano::{
|
|||||||
sync::Sharing,
|
sync::Sharing,
|
||||||
};
|
};
|
||||||
use wgui::gfx::WGfx;
|
use wgui::gfx::WGfx;
|
||||||
use wlx_capture::frame::{
|
use wlx_capture::{DrmFormat, DrmFourcc, DrmModifier, frame::DmabufFrame};
|
||||||
DRM_FORMAT_ABGR8888, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888,
|
|
||||||
DRM_FORMAT_XBGR2101010, DRM_FORMAT_XRGB8888, DmabufFrame, DrmFormat, FourCC,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const DRM_FORMAT_MOD_INVALID: u64 = 0xff_ffff_ffff_ffff;
|
|
||||||
|
|
||||||
pub trait WGfxDmabuf {
|
pub trait WGfxDmabuf {
|
||||||
fn dmabuf_texture_ex(
|
fn dmabuf_texture_ex(
|
||||||
@@ -47,7 +42,7 @@ impl WGfxDmabuf for WGfx {
|
|||||||
modifiers: &[u64],
|
modifiers: &[u64],
|
||||||
) -> anyhow::Result<Arc<Image>> {
|
) -> anyhow::Result<Arc<Image>> {
|
||||||
let extent = [frame.format.width, frame.format.height, 1];
|
let extent = [frame.format.width, frame.format.height, 1];
|
||||||
let format = fourcc_to_vk(frame.format.fourcc)?;
|
let format = fourcc_to_vk(frame.format.drm_format.code)?;
|
||||||
|
|
||||||
let image = unsafe {
|
let image = unsafe {
|
||||||
create_dmabuf_image(
|
create_dmabuf_image(
|
||||||
@@ -116,11 +111,11 @@ impl WGfxDmabuf for WGfx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result<Arc<Image>> {
|
fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result<Arc<Image>> {
|
||||||
let mut modifiers: Vec<u64> = vec![];
|
let mut modifiers: SmallVec<[u64; 4]> = smallvec![];
|
||||||
let mut tiling: ImageTiling = ImageTiling::Optimal;
|
let mut tiling: ImageTiling = ImageTiling::Optimal;
|
||||||
let mut layouts: Vec<SubresourceLayout> = vec![];
|
let mut layouts: Vec<SubresourceLayout> = vec![];
|
||||||
|
|
||||||
if frame.format.modifier != DRM_FORMAT_MOD_INVALID {
|
if !matches!(frame.format.drm_format.modifier, DrmModifier::Invalid) {
|
||||||
(0..frame.num_planes).for_each(|i| {
|
(0..frame.num_planes).for_each(|i| {
|
||||||
let plane = &frame.planes[i];
|
let plane = &frame.planes[i];
|
||||||
layouts.push(SubresourceLayout {
|
layouts.push(SubresourceLayout {
|
||||||
@@ -130,7 +125,7 @@ impl WGfxDmabuf for WGfx {
|
|||||||
array_pitch: None,
|
array_pitch: None,
|
||||||
depth_pitch: None,
|
depth_pitch: None,
|
||||||
});
|
});
|
||||||
modifiers.push(frame.format.modifier);
|
modifiers.push(frame.format.drm_format.modifier.into());
|
||||||
});
|
});
|
||||||
tiling = ImageTiling::DrmFormatModifier;
|
tiling = ImageTiling::DrmFormatModifier;
|
||||||
}
|
}
|
||||||
@@ -304,50 +299,56 @@ pub(super) unsafe fn create_dmabuf_image(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_drm_formats(device: Arc<Device>) -> Vec<DrmFormat> {
|
pub(super) fn get_drm_formats(device: Arc<Device>) -> Vec<DrmFormat> {
|
||||||
let possible_formats = [
|
let possible_formats = [
|
||||||
DRM_FORMAT_ABGR8888.into(),
|
DrmFourcc::Abgr8888,
|
||||||
DRM_FORMAT_XBGR8888.into(),
|
DrmFourcc::Xbgr8888,
|
||||||
DRM_FORMAT_ARGB8888.into(),
|
DrmFourcc::Argb8888,
|
||||||
DRM_FORMAT_XRGB8888.into(),
|
DrmFourcc::Xrgb8888,
|
||||||
DRM_FORMAT_ABGR2101010.into(),
|
DrmFourcc::Abgr2101010,
|
||||||
DRM_FORMAT_XBGR2101010.into(),
|
DrmFourcc::Xbgr2101010,
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut final_formats = vec![];
|
let mut out_formats = vec![];
|
||||||
|
|
||||||
for &f in &possible_formats {
|
for &code in &possible_formats {
|
||||||
let Ok(vk_fmt) = fourcc_to_vk(f) else {
|
let Ok(vk_fmt) = fourcc_to_vk(code) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Ok(props) = device.physical_device().format_properties(vk_fmt) else {
|
let Ok(props) = device.physical_device().format_properties(vk_fmt) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let mut fmt = DrmFormat {
|
|
||||||
fourcc: f,
|
for m in props
|
||||||
modifiers: props
|
|
||||||
.drm_format_modifier_properties
|
.drm_format_modifier_properties
|
||||||
.iter()
|
.iter()
|
||||||
// important bit: only allow single-plane
|
|
||||||
.filter(|m| m.drm_format_modifier_plane_count == 1)
|
.filter(|m| m.drm_format_modifier_plane_count == 1)
|
||||||
.map(|m| m.drm_format_modifier)
|
.map(|m| m.drm_format_modifier)
|
||||||
.collect(),
|
{
|
||||||
};
|
out_formats.push(DrmFormat {
|
||||||
fmt.modifiers.push(DRM_FORMAT_MOD_INVALID); // implicit modifiers support
|
code,
|
||||||
final_formats.push(fmt);
|
modifier: DrmModifier::from(m),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// accept implicit modifiers
|
||||||
|
out_formats.push(DrmFormat {
|
||||||
|
code,
|
||||||
|
modifier: DrmModifier::Invalid,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
log::debug!("Supported DRM formats:");
|
log::debug!("Supported DRM formats:");
|
||||||
for f in &final_formats {
|
for f in &out_formats {
|
||||||
log::debug!(" {} {:?}", f.fourcc, f.modifiers);
|
log::debug!(" {} {:?}", f.code, f.modifier);
|
||||||
}
|
}
|
||||||
final_formats
|
out_formats
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result<Format> {
|
pub fn fourcc_to_vk(fourcc: DrmFourcc) -> anyhow::Result<Format> {
|
||||||
match fourcc.value {
|
match fourcc {
|
||||||
DRM_FORMAT_ABGR8888 | DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM),
|
DrmFourcc::Abgr8888 | DrmFourcc::Xbgr8888 => Ok(Format::R8G8B8A8_UNORM),
|
||||||
DRM_FORMAT_ARGB8888 | DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM),
|
DrmFourcc::Argb8888 | DrmFourcc::Xrgb8888 => Ok(Format::B8G8R8A8_UNORM),
|
||||||
DRM_FORMAT_ABGR2101010 | DRM_FORMAT_XBGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32),
|
DrmFourcc::Abgr2101010 | DrmFourcc::Xbgr2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32),
|
||||||
_ => anyhow::bail!("Unsupported format {fourcc}"),
|
_ => anyhow::bail!("Unsupported format {fourcc}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use wgui::gfx::WGfx;
|
|||||||
|
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
use vulkano::instance::InstanceCreateFlags;
|
use vulkano::instance::InstanceCreateFlags;
|
||||||
use wlx_capture::frame::DrmFormat;
|
use wlx_capture::DrmFormat;
|
||||||
|
|
||||||
use crate::shaders::{frag_color, frag_grid, frag_screen, frag_srgb, vert_quad};
|
use crate::shaders::{frag_color, frag_grid, frag_screen, frag_srgb, vert_quad};
|
||||||
|
|
||||||
@@ -73,6 +73,7 @@ pub struct WGfxExtras {
|
|||||||
pub queue_capture: Option<Arc<Queue>>,
|
pub queue_capture: Option<Arc<Queue>>,
|
||||||
pub quad_verts: Vert2Buf,
|
pub quad_verts: Vert2Buf,
|
||||||
pub fallback_image: Arc<ImageView>,
|
pub fallback_image: Arc<ImageView>,
|
||||||
|
pub drm_device: Option<(i64, i64)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WGfxExtras {
|
impl WGfxExtras {
|
||||||
@@ -135,12 +136,23 @@ impl WGfxExtras {
|
|||||||
|
|
||||||
let fallback_image = ImageView::new_default(fallback_image)?;
|
let fallback_image = ImageView::new_default(fallback_image)?;
|
||||||
|
|
||||||
|
let p = gfx.device.physical_device().properties();
|
||||||
|
|
||||||
|
let drm_device = if let (Some(maj), Some(min)) = (p.render_major, p.render_minor) {
|
||||||
|
log::info!("DRM render device: {maj} {min}");
|
||||||
|
Some((maj, min))
|
||||||
|
} else {
|
||||||
|
log::warn!("No DRM device.");
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
shaders,
|
shaders,
|
||||||
drm_formats,
|
drm_formats,
|
||||||
queue_capture,
|
queue_capture,
|
||||||
quad_verts,
|
quad_verts,
|
||||||
fallback_image,
|
fallback_image,
|
||||||
|
drm_device,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,6 +283,13 @@ pub fn init_openxr_graphics(
|
|||||||
.ext_image_drm_format_modifier;
|
.ext_image_drm_format_modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if physical_device
|
||||||
|
.supported_extensions()
|
||||||
|
.ext_physical_device_drm
|
||||||
|
{
|
||||||
|
device_extensions.ext_physical_device_drm = true;
|
||||||
|
}
|
||||||
|
|
||||||
let device_extensions_raw = device_extensions
|
let device_extensions_raw = device_extensions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(name, enabled)| {
|
.filter_map(|(name, enabled)| {
|
||||||
@@ -432,6 +451,11 @@ pub fn init_openvr_graphics(
|
|||||||
my_extensions.ext_filter_cubic = true;
|
my_extensions.ext_filter_cubic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.supported_extensions().ext_physical_device_drm {
|
||||||
|
// needed for wayland_server
|
||||||
|
my_extensions.ext_physical_device_drm = true;
|
||||||
|
}
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Device exts for {}: {:?}",
|
"Device exts for {}: {:?}",
|
||||||
p.properties().device_name,
|
p.properties().device_name,
|
||||||
|
|||||||
99
wlx-overlay-s/src/ipc/events.rs
Normal file
99
wlx-overlay-s/src/ipc/events.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
use wayvr_ipc::packet_server;
|
||||||
|
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
|
use crate::{backend::wayvr, overlays::wayvr::WayVRData};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backend::{
|
||||||
|
self,
|
||||||
|
task::{InputTask, OverlayTask, TaskType},
|
||||||
|
},
|
||||||
|
ipc::signal::WayVRSignal,
|
||||||
|
state::AppState,
|
||||||
|
windowing::{OverlaySelector, manager::OverlayWindowManager},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
|
fn process_tick_tasks(
|
||||||
|
tick_tasks: Vec<backend::wayvr::TickTask>,
|
||||||
|
r_wayvr: &Rc<RefCell<WayVRData>>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
for tick_task in tick_tasks {
|
||||||
|
match tick_task {
|
||||||
|
backend::wayvr::TickTask::NewExternalProcess(request) => {
|
||||||
|
let mut wayvr = r_wayvr.borrow_mut();
|
||||||
|
|
||||||
|
log::info!("Registering external process with PID {}", request.pid);
|
||||||
|
|
||||||
|
wayvr.data.state.add_external_process(request.pid);
|
||||||
|
|
||||||
|
wayvr
|
||||||
|
.data
|
||||||
|
.state
|
||||||
|
.manager
|
||||||
|
.add_client(wayvr::client::WayVRClient {
|
||||||
|
client: request.client,
|
||||||
|
pid: request.pid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick_events<O>(
|
||||||
|
app: &mut AppState,
|
||||||
|
_overlays: &mut OverlayWindowManager<O>,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
O: Default,
|
||||||
|
{
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
|
let wayland_server = app.wayland_server.clone();
|
||||||
|
|
||||||
|
while let Some(signal) = app.wayvr_signals.read() {
|
||||||
|
match signal {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
|
WayVRSignal::BroadcastStateChanged(packet) => {
|
||||||
|
app.ipc_server
|
||||||
|
.broadcast(packet_server::PacketServer::WvrStateChanged(packet));
|
||||||
|
}
|
||||||
|
WayVRSignal::DeviceHaptics(device, haptics) => {
|
||||||
|
app.tasks
|
||||||
|
.enqueue(TaskType::Input(InputTask::Haptics { device, haptics }));
|
||||||
|
}
|
||||||
|
WayVRSignal::DropOverlay(overlay_id) => {
|
||||||
|
app.tasks
|
||||||
|
.enqueue(TaskType::Overlay(OverlayTask::Drop(OverlaySelector::Id(
|
||||||
|
overlay_id,
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
WayVRSignal::CustomTask(custom_task) => {
|
||||||
|
app.tasks
|
||||||
|
.enqueue(TaskType::Overlay(OverlayTask::ModifyPanel(custom_task)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
|
{
|
||||||
|
if let Some(wayland_server) = wayland_server {
|
||||||
|
let tick_tasks = wayland_server.borrow_mut().data.tick_events(app)?;
|
||||||
|
process_tick_tasks(tick_tasks, &wayland_server)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "wayvr"))]
|
||||||
|
{
|
||||||
|
use super::ipc_server::TickParams;
|
||||||
|
app.ipc_server.tick(&mut TickParams {
|
||||||
|
input_state: &app.input_state,
|
||||||
|
signals: &app.wayvr_signals,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
use crate::state::AppState;
|
#[cfg(feature = "wayvr")]
|
||||||
|
use crate::backend::wayvr::{self, WayVRState};
|
||||||
|
|
||||||
use super::{TickTask, WayVRSignal, display, process, window};
|
use crate::{
|
||||||
|
backend::input::InputState,
|
||||||
|
ipc::{event_queue::SyncEventQueue, signal::WayVRSignal},
|
||||||
|
};
|
||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use glam::Vec3A;
|
use glam::Vec3A;
|
||||||
use interprocess::local_socket::{self, ToNsName, traits::Listener};
|
use interprocess::local_socket::{self, ToNsName, traits::Listener};
|
||||||
@@ -71,9 +75,12 @@ fn read_payload(conn: &mut local_socket::Stream, size: u32) -> Option<Payload> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TickParams<'a> {
|
pub struct TickParams<'a> {
|
||||||
pub state: &'a mut super::WayVRState,
|
#[cfg(feature = "wayvr")]
|
||||||
pub tasks: &'a mut Vec<TickTask>,
|
pub wayland_state: &'a mut WayVRState,
|
||||||
pub app: &'a AppState,
|
#[cfg(feature = "wayvr")]
|
||||||
|
pub tasks: &'a mut Vec<wayvr::TickTask>,
|
||||||
|
pub signals: &'a SyncEventQueue<WayVRSignal>,
|
||||||
|
pub input_state: &'a InputState,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_args_vec(input: &str) -> Vec<&str> {
|
pub fn gen_args_vec(input: &str) -> Vec<&str> {
|
||||||
@@ -149,44 +156,11 @@ impl Connection {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_display_list(
|
|
||||||
&mut self,
|
|
||||||
params: &TickParams,
|
|
||||||
serial: ipc::Serial,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let list: Vec<packet_server::WvrDisplay> = params
|
|
||||||
.state
|
|
||||||
.displays
|
|
||||||
.vec
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(idx, opt_cell)| {
|
|
||||||
let Some(cell) = opt_cell else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let display = &cell.obj;
|
|
||||||
Some(display.as_packet(display::DisplayHandle::new(idx as u32, cell.generation)))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
send_packet(
|
|
||||||
&mut self.conn,
|
|
||||||
&ipc::data_encode(&PacketServer::WvrDisplayListResponse(
|
|
||||||
serial,
|
|
||||||
packet_server::WvrDisplayList { list },
|
|
||||||
)),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_wlx_input_state(
|
fn handle_wlx_input_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &TickParams,
|
params: &TickParams,
|
||||||
serial: ipc::Serial,
|
serial: ipc::Serial,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let input_state = ¶ms.app.input_state;
|
|
||||||
|
|
||||||
let to_arr = |vec: &Vec3A| -> [f32; 3] { [vec.x, vec.y, vec.z] };
|
let to_arr = |vec: &Vec3A| -> [f32; 3] { [vec.x, vec.y, vec.z] };
|
||||||
|
|
||||||
send_packet(
|
send_packet(
|
||||||
@@ -194,12 +168,12 @@ impl Connection {
|
|||||||
&ipc::data_encode(&PacketServer::WlxInputStateResponse(
|
&ipc::data_encode(&PacketServer::WlxInputStateResponse(
|
||||||
serial,
|
serial,
|
||||||
packet_server::WlxInputState {
|
packet_server::WlxInputState {
|
||||||
hmd_pos: to_arr(&input_state.hmd.translation),
|
hmd_pos: to_arr(¶ms.input_state.hmd.translation),
|
||||||
left: WlxInputStatePointer {
|
left: WlxInputStatePointer {
|
||||||
pos: to_arr(&input_state.pointers[0].raw_pose.translation),
|
pos: to_arr(¶ms.input_state.pointers[0].raw_pose.translation),
|
||||||
},
|
},
|
||||||
right: WlxInputStatePointer {
|
right: WlxInputStatePointer {
|
||||||
pos: to_arr(&input_state.pointers[0].raw_pose.translation),
|
pos: to_arr(¶ms.input_state.pointers[0].raw_pose.translation),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
@@ -208,148 +182,55 @@ impl Connection {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_display_create(
|
#[cfg(feature = "wayvr")]
|
||||||
|
fn handle_wvr_window_list(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
serial: ipc::Serial,
|
serial: ipc::Serial,
|
||||||
packet_params: packet_client::WvrDisplayCreateParams,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let display_handle = params.state.create_display(
|
|
||||||
packet_params.width,
|
|
||||||
packet_params.height,
|
|
||||||
&packet_params.name,
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
params
|
|
||||||
.tasks
|
|
||||||
.push(TickTask::NewDisplay(packet_params, Some(display_handle)));
|
|
||||||
|
|
||||||
send_packet(
|
|
||||||
&mut self.conn,
|
|
||||||
&ipc::data_encode(&PacketServer::WvrDisplayCreateResponse(
|
|
||||||
serial,
|
|
||||||
display_handle.as_packet(),
|
|
||||||
)),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_wvr_display_remove(
|
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
|
||||||
serial: ipc::Serial,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let res = params
|
|
||||||
.state
|
|
||||||
.destroy_display(display::DisplayHandle::from_packet(handle))
|
|
||||||
.map_err(|e| format!("{e:?}"));
|
|
||||||
|
|
||||||
send_packet(
|
|
||||||
&mut self.conn,
|
|
||||||
&ipc::data_encode(&PacketServer::WvrDisplayRemoveResponse(serial, res)),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_wvr_display_set_visible(
|
|
||||||
params: &mut TickParams,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
visible: bool,
|
|
||||||
) {
|
|
||||||
params.state.signals.send(WayVRSignal::DisplayVisibility(
|
|
||||||
display::DisplayHandle::from_packet(handle),
|
|
||||||
visible,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_wvr_display_set_window_layout(
|
|
||||||
params: &mut TickParams,
|
|
||||||
handle: packet_server::WvrDisplayHandle,
|
|
||||||
layout: packet_server::WvrDisplayWindowLayout,
|
|
||||||
) {
|
|
||||||
params.state.signals.send(WayVRSignal::DisplayWindowLayout(
|
|
||||||
display::DisplayHandle::from_packet(handle),
|
|
||||||
layout,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_wvr_display_window_list(
|
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
|
||||||
serial: ipc::Serial,
|
|
||||||
display_handle: packet_server::WvrDisplayHandle,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut send = |list: Option<packet_server::WvrWindowList>| -> anyhow::Result<()> {
|
let mut send = |list: Option<packet_server::WvrWindowList>| -> anyhow::Result<()> {
|
||||||
send_packet(
|
send_packet(
|
||||||
&mut self.conn,
|
&mut self.conn,
|
||||||
&ipc::data_encode(&PacketServer::WvrDisplayWindowListResponse(serial, list)),
|
&ipc::data_encode(&PacketServer::WvrWindowListResponse(serial, list)),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(display) = params
|
|
||||||
.state
|
|
||||||
.displays
|
|
||||||
.get(&display::DisplayHandle::from_packet(display_handle.clone()))
|
|
||||||
else {
|
|
||||||
return send(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
send(Some(packet_server::WvrWindowList {
|
send(Some(packet_server::WvrWindowList {
|
||||||
list: display
|
list: params
|
||||||
.displayed_windows
|
.wayland_state
|
||||||
.iter()
|
|
||||||
.filter_map(|disp_win| {
|
|
||||||
params
|
|
||||||
.state
|
|
||||||
.wm
|
.wm
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.windows
|
.windows
|
||||||
.get(&disp_win.window_handle)
|
.iter()
|
||||||
.map(|win| packet_server::WvrWindow {
|
.map(|(handle, win)| packet_server::WvrWindow {
|
||||||
handle: window::WindowHandle::as_packet(&disp_win.window_handle),
|
handle: wayvr::window::WindowHandle::as_packet(&handle),
|
||||||
process_handle: process::ProcessHandle::as_packet(
|
process_handle: wayvr::process::ProcessHandle::as_packet(&win.process),
|
||||||
&disp_win.process_handle,
|
|
||||||
),
|
|
||||||
pos_x: win.pos_x,
|
|
||||||
pos_y: win.pos_y,
|
|
||||||
size_x: win.size_x,
|
size_x: win.size_x,
|
||||||
size_y: win.size_y,
|
size_y: win.size_y,
|
||||||
visible: win.visible,
|
visible: win.visible,
|
||||||
display_handle: display_handle.clone(),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
fn handle_wvr_window_set_visible(
|
fn handle_wvr_window_set_visible(
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
handle: packet_server::WvrWindowHandle,
|
handle: packet_server::WvrWindowHandle,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
) {
|
) {
|
||||||
let to_resize = if let Some(window) = params
|
if let Some(window) = params
|
||||||
.state
|
.wayland_state
|
||||||
.wm
|
.wm
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.windows
|
.windows
|
||||||
.get_mut(&window::WindowHandle::from_packet(handle))
|
.get_mut(&wayvr::window::WindowHandle::from_packet(handle))
|
||||||
{
|
{
|
||||||
window.visible = visible;
|
window.visible = visible;
|
||||||
Some(window.display_handle)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(to_resize) = to_resize
|
|
||||||
&& let Some(display) = params.state.displays.get_mut(&to_resize)
|
|
||||||
{
|
|
||||||
display.reposition_windows();
|
|
||||||
display.trigger_rerender();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
fn handle_wvr_process_launch(
|
fn handle_wvr_process_launch(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
@@ -359,8 +240,7 @@ impl Connection {
|
|||||||
let args_vec = gen_args_vec(&packet_params.args);
|
let args_vec = gen_args_vec(&packet_params.args);
|
||||||
let env_vec = gen_env_vec(&packet_params.env);
|
let env_vec = gen_env_vec(&packet_params.env);
|
||||||
|
|
||||||
let res = params.state.spawn_process(
|
let res = params.wayland_state.spawn_process(
|
||||||
super::display::DisplayHandle::from_packet(packet_params.target_display),
|
|
||||||
&packet_params.exec,
|
&packet_params.exec,
|
||||||
&args_vec,
|
&args_vec,
|
||||||
&env_vec,
|
&env_vec,
|
||||||
@@ -378,34 +258,14 @@ impl Connection {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_display_get(
|
#[cfg(feature = "wayvr")]
|
||||||
&mut self,
|
|
||||||
params: &TickParams,
|
|
||||||
serial: ipc::Serial,
|
|
||||||
display_handle: packet_server::WvrDisplayHandle,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let native_handle = &display::DisplayHandle::from_packet(display_handle);
|
|
||||||
let disp = params
|
|
||||||
.state
|
|
||||||
.displays
|
|
||||||
.get(native_handle)
|
|
||||||
.map(|disp| disp.as_packet(*native_handle));
|
|
||||||
|
|
||||||
send_packet(
|
|
||||||
&mut self.conn,
|
|
||||||
&ipc::data_encode(&PacketServer::WvrDisplayGetResponse(serial, disp)),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_wvr_process_list(
|
fn handle_wvr_process_list(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &TickParams,
|
params: &TickParams,
|
||||||
serial: ipc::Serial,
|
serial: ipc::Serial,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let list: Vec<packet_server::WvrProcess> = params
|
let list: Vec<packet_server::WvrProcess> = params
|
||||||
.state
|
.wayland_state
|
||||||
.processes
|
.processes
|
||||||
.vec
|
.vec
|
||||||
.iter()
|
.iter()
|
||||||
@@ -415,7 +275,10 @@ impl Connection {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let process = &cell.obj;
|
let process = &cell.obj;
|
||||||
Some(process.to_packet(process::ProcessHandle::new(idx as u32, cell.generation)))
|
Some(process.to_packet(wayvr::process::ProcessHandle::new(
|
||||||
|
idx as u32,
|
||||||
|
cell.generation,
|
||||||
|
)))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -431,12 +294,13 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This request doesn't return anything to the client
|
// This request doesn't return anything to the client
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
fn handle_wvr_process_terminate(
|
fn handle_wvr_process_terminate(
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
process_handle: packet_server::WvrProcessHandle,
|
process_handle: packet_server::WvrProcessHandle,
|
||||||
) {
|
) {
|
||||||
let native_handle = &process::ProcessHandle::from_packet(process_handle);
|
let native_handle = &wayvr::process::ProcessHandle::from_packet(process_handle);
|
||||||
let process = params.state.processes.get_mut(native_handle);
|
let process = params.wayland_state.processes.get_mut(native_handle);
|
||||||
|
|
||||||
let Some(process) = process else {
|
let Some(process) = process else {
|
||||||
return;
|
return;
|
||||||
@@ -445,15 +309,16 @@ impl Connection {
|
|||||||
process.terminate();
|
process.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
fn handle_wvr_process_get(
|
fn handle_wvr_process_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &TickParams,
|
params: &TickParams,
|
||||||
serial: ipc::Serial,
|
serial: ipc::Serial,
|
||||||
process_handle: packet_server::WvrProcessHandle,
|
process_handle: packet_server::WvrProcessHandle,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let native_handle = &process::ProcessHandle::from_packet(process_handle);
|
let native_handle = &wayvr::process::ProcessHandle::from_packet(process_handle);
|
||||||
let process = params
|
let process = params
|
||||||
.state
|
.wayland_state
|
||||||
.processes
|
.processes
|
||||||
.get(native_handle)
|
.get(native_handle)
|
||||||
.map(|process| process.to_packet(*native_handle));
|
.map(|process| process.to_packet(*native_handle));
|
||||||
@@ -466,11 +331,13 @@ impl Connection {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wlx_haptics(
|
fn handle_wlx_device_haptics(
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
|
device: usize,
|
||||||
haptics_params: packet_client::WlxHapticsParams,
|
haptics_params: packet_client::WlxHapticsParams,
|
||||||
) {
|
) {
|
||||||
params.state.signals.send(super::WayVRSignal::Haptics(
|
params.signals.send(WayVRSignal::DeviceHaptics(
|
||||||
|
device,
|
||||||
crate::backend::input::Haptics {
|
crate::backend::input::Haptics {
|
||||||
duration: haptics_params.duration,
|
duration: haptics_params.duration,
|
||||||
frequency: haptics_params.frequency,
|
frequency: haptics_params.frequency,
|
||||||
@@ -486,9 +353,8 @@ impl Connection {
|
|||||||
use crate::backend::task::{ModifyPanelCommand, ModifyPanelTask};
|
use crate::backend::task::{ModifyPanelCommand, ModifyPanelTask};
|
||||||
|
|
||||||
params
|
params
|
||||||
.state
|
|
||||||
.signals
|
.signals
|
||||||
.send(super::WayVRSignal::CustomTask(ModifyPanelTask {
|
.send(WayVRSignal::CustomTask(ModifyPanelTask {
|
||||||
overlay: custom_params.overlay,
|
overlay: custom_params.overlay,
|
||||||
element: custom_params.element,
|
element: custom_params.element,
|
||||||
command: match custom_params.command {
|
command: match custom_params.command {
|
||||||
@@ -511,6 +377,9 @@ impl Connection {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: we should probably respond an error to the client in case if wayland server feature is disabled
|
||||||
|
// fix this after we're done with the webkit-based wayvr-dashboard
|
||||||
|
#[allow(unused_variables)]
|
||||||
fn process_payload(&mut self, params: &mut TickParams, payload: Payload) -> anyhow::Result<()> {
|
fn process_payload(&mut self, params: &mut TickParams, payload: Payload) -> anyhow::Result<()> {
|
||||||
let packet: PacketClient = ipc::data_decode(&payload)?;
|
let packet: PacketClient = ipc::data_decode(&payload)?;
|
||||||
|
|
||||||
@@ -524,44 +393,32 @@ impl Connection {
|
|||||||
PacketClient::WlxInputState(serial) => {
|
PacketClient::WlxInputState(serial) => {
|
||||||
self.handle_wlx_input_state(params, serial)?;
|
self.handle_wlx_input_state(params, serial)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrDisplayList(serial) => {
|
PacketClient::WvrWindowList(serial) => {
|
||||||
self.handle_wvr_display_list(params, serial)?;
|
#[cfg(feature = "wayvr")]
|
||||||
}
|
self.handle_wvr_window_list(params, serial)?;
|
||||||
PacketClient::WvrDisplayGet(serial, display_handle) => {
|
|
||||||
self.handle_wvr_display_get(params, serial, display_handle)?;
|
|
||||||
}
|
|
||||||
PacketClient::WvrDisplayRemove(serial, display_handle) => {
|
|
||||||
self.handle_wvr_display_remove(params, serial, display_handle)?;
|
|
||||||
}
|
|
||||||
PacketClient::WvrDisplaySetVisible(display_handle, visible) => {
|
|
||||||
Self::handle_wvr_display_set_visible(params, display_handle, visible);
|
|
||||||
}
|
|
||||||
PacketClient::WvrDisplaySetWindowLayout(display_handle, layout) => {
|
|
||||||
Self::handle_wvr_display_set_window_layout(params, display_handle, layout);
|
|
||||||
}
|
|
||||||
PacketClient::WvrDisplayWindowList(serial, display_handle) => {
|
|
||||||
self.handle_wvr_display_window_list(params, serial, display_handle)?;
|
|
||||||
}
|
}
|
||||||
PacketClient::WvrWindowSetVisible(window_handle, visible) => {
|
PacketClient::WvrWindowSetVisible(window_handle, visible) => {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
Self::handle_wvr_window_set_visible(params, window_handle, visible);
|
Self::handle_wvr_window_set_visible(params, window_handle, visible);
|
||||||
}
|
}
|
||||||
PacketClient::WvrProcessGet(serial, process_handle) => {
|
PacketClient::WvrProcessGet(serial, process_handle) => {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
self.handle_wvr_process_get(params, serial, process_handle)?;
|
self.handle_wvr_process_get(params, serial, process_handle)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrProcessList(serial) => {
|
PacketClient::WvrProcessList(serial) => {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
self.handle_wvr_process_list(params, serial)?;
|
self.handle_wvr_process_list(params, serial)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrProcessLaunch(serial, packet_params) => {
|
PacketClient::WvrProcessLaunch(serial, packet_params) => {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
self.handle_wvr_process_launch(params, serial, packet_params)?;
|
self.handle_wvr_process_launch(params, serial, packet_params)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrDisplayCreate(serial, packet_params) => {
|
|
||||||
self.handle_wvr_display_create(params, serial, packet_params)?;
|
|
||||||
}
|
|
||||||
PacketClient::WvrProcessTerminate(process_handle) => {
|
PacketClient::WvrProcessTerminate(process_handle) => {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
Self::handle_wvr_process_terminate(params, process_handle);
|
Self::handle_wvr_process_terminate(params, process_handle);
|
||||||
}
|
}
|
||||||
PacketClient::WlxHaptics(haptics_params) => {
|
PacketClient::WlxDeviceHaptics(device, haptics_params) => {
|
||||||
Self::handle_wlx_haptics(params, haptics_params);
|
Self::handle_wlx_device_haptics(params, device, haptics_params);
|
||||||
}
|
}
|
||||||
PacketClient::WlxModifyPanel(custom_params) => {
|
PacketClient::WlxModifyPanel(custom_params) => {
|
||||||
Self::handle_wlx_panel(params, custom_params);
|
Self::handle_wlx_panel(params, custom_params);
|
||||||
4
wlx-overlay-s/src/ipc/mod.rs
Normal file
4
wlx-overlay-s/src/ipc/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod event_queue;
|
||||||
|
pub mod events;
|
||||||
|
pub mod ipc_server;
|
||||||
|
pub mod signal;
|
||||||
8
wlx-overlay-s/src/ipc/signal.rs
Normal file
8
wlx-overlay-s/src/ipc/signal.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#[derive(Clone)]
|
||||||
|
pub enum WayVRSignal {
|
||||||
|
#[cfg(feature = "wayvr")]
|
||||||
|
BroadcastStateChanged(wayvr_ipc::packet_server::WvrStateChanged),
|
||||||
|
DeviceHaptics(usize, crate::backend::input::Haptics),
|
||||||
|
DropOverlay(crate::windowing::OverlayID),
|
||||||
|
CustomTask(crate::backend::task::ModifyPanelTask),
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ mod config;
|
|||||||
mod config_io;
|
mod config_io;
|
||||||
mod graphics;
|
mod graphics;
|
||||||
mod gui;
|
mod gui;
|
||||||
|
mod ipc;
|
||||||
mod overlays;
|
mod overlays;
|
||||||
mod shaders;
|
mod shaders;
|
||||||
mod state;
|
mod state;
|
||||||
|
|||||||
@@ -222,9 +222,13 @@ impl OverlayBackend for ScreenBackend {
|
|||||||
fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
|
fn render(&mut self, app: &mut AppState, rdr: &mut RenderResources) -> anyhow::Result<()> {
|
||||||
// want panic; must be some if should_render was not Unable
|
// want panic; must be some if should_render was not Unable
|
||||||
let capture = self.cur_frame.as_ref().unwrap();
|
let capture = self.cur_frame.as_ref().unwrap();
|
||||||
|
let image = capture.image.clone();
|
||||||
|
|
||||||
// want panic; must be Some if cur_frame is also Some
|
// want panic; must be Some if cur_frame is also Some
|
||||||
self.pipeline.as_mut().unwrap().render(&capture, app, rdr)?;
|
self.pipeline
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.render(image, capture.mouse.as_ref(), app, rdr)?;
|
||||||
self.capture.request_new_frame();
|
self.capture.request_new_frame();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ use wgui::gfx::{
|
|||||||
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
pipeline::{WGfxPipeline, WPipelineCreateInfo},
|
||||||
};
|
};
|
||||||
use wlx_capture::{
|
use wlx_capture::{
|
||||||
WlxCapture,
|
DrmFormat, WlxCapture,
|
||||||
frame::{self as wlx_frame, DrmFormat, FrameFormat, MouseMeta, Transform, WlxFrame},
|
frame::{self as wlx_frame, FrameFormat, MouseMeta, WlxFrame},
|
||||||
};
|
};
|
||||||
use wlx_common::{config::GeneralConfig, overlays::StereoMode};
|
use wlx_common::{config::GeneralConfig, overlays::StereoMode};
|
||||||
|
|
||||||
@@ -39,7 +39,8 @@ struct BufPass {
|
|||||||
buf_vert: Subbuffer<[Vert2Uv]>,
|
buf_vert: Subbuffer<[Vert2Uv]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct ScreenPipeline {
|
/// A render pipeline that supports mouse + stereo
|
||||||
|
pub struct ScreenPipeline {
|
||||||
mouse: BufPass,
|
mouse: BufPass,
|
||||||
pass: SmallVec<[BufPass; 2]>,
|
pass: SmallVec<[BufPass; 2]>,
|
||||||
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||||
@@ -49,11 +50,7 @@ pub(super) struct ScreenPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenPipeline {
|
impl ScreenPipeline {
|
||||||
pub(super) fn new(
|
pub fn new(meta: &FrameMeta, app: &mut AppState, stereo: StereoMode) -> anyhow::Result<Self> {
|
||||||
meta: &FrameMeta,
|
|
||||||
app: &mut AppState,
|
|
||||||
stereo: StereoMode,
|
|
||||||
) -> anyhow::Result<Self> {
|
|
||||||
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
||||||
|
|
||||||
let pipeline = app.gfx.create_pipeline(
|
let pipeline = app.gfx.create_pipeline(
|
||||||
@@ -198,13 +195,13 @@ impl ScreenPipeline {
|
|||||||
Ok(BufPass { pass, buf_vert })
|
Ok(BufPass { pass, buf_vert })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn render(
|
pub fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
capture: &WlxCaptureOut,
|
image: Arc<ImageView>,
|
||||||
|
mouse: Option<&MouseMeta>,
|
||||||
app: &mut AppState,
|
app: &mut AppState,
|
||||||
rdr: &mut RenderResources,
|
rdr: &mut RenderResources,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let view = ImageView::new_default(capture.image.clone())?;
|
|
||||||
self.buf_alpha.write()?[0] = rdr.alpha;
|
self.buf_alpha.write()?[0] = rdr.alpha;
|
||||||
|
|
||||||
for (eye, cmd_buf) in rdr.cmd_bufs.iter_mut().enumerate() {
|
for (eye, cmd_buf) in rdr.cmd_bufs.iter_mut().enumerate() {
|
||||||
@@ -212,11 +209,11 @@ impl ScreenPipeline {
|
|||||||
|
|
||||||
current
|
current
|
||||||
.pass
|
.pass
|
||||||
.update_sampler(0, view.clone(), app.gfx.texture_filter)?;
|
.update_sampler(0, image.clone(), app.gfx.texture_filter)?;
|
||||||
|
|
||||||
cmd_buf.run_ref(¤t.pass)?;
|
cmd_buf.run_ref(¤t.pass)?;
|
||||||
|
|
||||||
if let Some(mouse) = capture.mouse.as_ref() {
|
if let Some(mouse) = mouse.as_ref() {
|
||||||
let size = CURSOR_SIZE * self.extentf[1];
|
let size = CURSOR_SIZE * self.extentf[1];
|
||||||
let half_size = size * 0.5;
|
let half_size = size * 0.5;
|
||||||
|
|
||||||
@@ -325,10 +322,10 @@ impl WlxCaptureIn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WlxCaptureOut {
|
pub(super) struct WlxCaptureOut {
|
||||||
image: Arc<Image>,
|
pub(super) image: Arc<ImageView>,
|
||||||
format: FrameFormat,
|
pub(super) format: FrameFormat,
|
||||||
mouse: Option<MouseMeta>,
|
pub(super) mouse: Option<MouseMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlxCaptureOut {
|
impl WlxCaptureOut {
|
||||||
@@ -340,10 +337,6 @@ impl WlxCaptureOut {
|
|||||||
format: self.image.format(),
|
format: self.image.format(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) const fn get_transform(&self) -> Transform {
|
|
||||||
self.format.transform
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upload_image(
|
fn upload_image(
|
||||||
@@ -390,7 +383,7 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
let format = frame.format;
|
let format = frame.format;
|
||||||
match me.gfx.dmabuf_texture(frame) {
|
match me.gfx.dmabuf_texture(frame) {
|
||||||
Ok(image) => Some(WlxCaptureOut {
|
Ok(image) => Some(WlxCaptureOut {
|
||||||
image,
|
image: ImageView::new_default(image).ok()?,
|
||||||
format,
|
format,
|
||||||
mouse: None,
|
mouse: None,
|
||||||
}),
|
}),
|
||||||
@@ -406,7 +399,7 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let format = match fourcc_to_vk(frame.format.fourcc) {
|
let format = match fourcc_to_vk(frame.format.drm_format.code) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{}: {}", me.name, e);
|
log::error!("{}: {}", me.name, e);
|
||||||
@@ -439,7 +432,7 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
}?;
|
}?;
|
||||||
|
|
||||||
Some(WlxCaptureOut {
|
Some(WlxCaptureOut {
|
||||||
image,
|
image: ImageView::new_default(image).ok()?,
|
||||||
format: frame.format,
|
format: frame.format,
|
||||||
mouse: None,
|
mouse: None,
|
||||||
})
|
})
|
||||||
@@ -447,7 +440,7 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
WlxFrame::MemPtr(frame) => {
|
WlxFrame::MemPtr(frame) => {
|
||||||
log::trace!("{}: New MemPtr frame", me.name);
|
log::trace!("{}: New MemPtr frame", me.name);
|
||||||
|
|
||||||
let format = match fourcc_to_vk(frame.format.fourcc) {
|
let format = match fourcc_to_vk(frame.format.drm_format.code) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{}: {}", me.name, e);
|
log::error!("{}: {}", me.name, e);
|
||||||
@@ -459,7 +452,7 @@ pub(super) fn receive_callback(me: &WlxCaptureIn, frame: WlxFrame) -> Option<Wlx
|
|||||||
let image = upload_image(me, frame.format.width, frame.format.height, format, data)?;
|
let image = upload_image(me, frame.format.width, frame.format.height, format, data)?;
|
||||||
|
|
||||||
Some(WlxCaptureOut {
|
Some(WlxCaptureOut {
|
||||||
image,
|
image: ImageView::new_default(image).ok()?,
|
||||||
format: frame.format,
|
format: frame.format,
|
||||||
mouse: frame.mouse,
|
mouse: frame.mouse,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
mod capture;
|
pub mod capture;
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub mod mirror;
|
pub mod mirror;
|
||||||
#[cfg(feature = "pipewire")]
|
#[cfg(feature = "pipewire")]
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,11 +12,6 @@ version: 1
|
|||||||
# "software": Read pixel data to memory via glReadPixels() every time a content has been updated. Minor performance impact on large resolutions
|
# "software": Read pixel data to memory via glReadPixels() every time a content has been updated. Minor performance impact on large resolutions
|
||||||
blit_method: "dmabuf"
|
blit_method: "dmabuf"
|
||||||
|
|
||||||
# Set to true if you want to make Wyland server instantly available.
|
|
||||||
# By default, WayVR starts only when it's needed.
|
|
||||||
# (this option is primarily used for remote starting external processes and development purposes)
|
|
||||||
run_compositor_at_start: false
|
|
||||||
|
|
||||||
# Automatically close overlays with zero window count?
|
# Automatically close overlays with zero window count?
|
||||||
auto_hide: true
|
auto_hide: true
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use crate::{
|
|||||||
config_io::{self, get_config_file_path},
|
config_io::{self, get_config_file_path},
|
||||||
graphics::WGfxExtras,
|
graphics::WGfxExtras,
|
||||||
gui,
|
gui,
|
||||||
|
ipc::{event_queue::SyncEventQueue, ipc_server, signal::WayVRSignal},
|
||||||
subsystem::{audio::AudioOutput, dbus::DbusConnector, input::HidWrapper},
|
subsystem::{audio::AudioOutput, dbus::DbusConnector, input::HidWrapper},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,11 +54,14 @@ pub struct AppState {
|
|||||||
|
|
||||||
pub xr_backend: XrBackend,
|
pub xr_backend: XrBackend,
|
||||||
|
|
||||||
|
pub ipc_server: ipc_server::WayVRServer,
|
||||||
|
pub wayvr_signals: SyncEventQueue<WayVRSignal>,
|
||||||
|
|
||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
pub osc_sender: Option<OscSender>,
|
pub osc_sender: Option<OscSender>,
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
pub wayvr: Option<Rc<RefCell<WayVRData>>>, // Dynamically created if requested
|
pub wayland_server: Option<Rc<RefCell<WayVRData>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
@@ -71,17 +75,26 @@ impl AppState {
|
|||||||
let mut tasks = TaskContainer::new();
|
let mut tasks = TaskContainer::new();
|
||||||
|
|
||||||
let session = AppSession::load();
|
let session = AppSession::load();
|
||||||
|
let wayvr_signals = SyncEventQueue::new();
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
let wayvr = session
|
let wayland_server = session
|
||||||
.wayvr_config
|
.wayvr_config
|
||||||
.post_load(&session.config, &mut tasks)?;
|
.post_load(
|
||||||
|
gfx.clone(),
|
||||||
|
&gfx_extras,
|
||||||
|
&session.config,
|
||||||
|
&mut tasks,
|
||||||
|
wayvr_signals.clone(),
|
||||||
|
)
|
||||||
|
.inspect_err(|e| log::error!("Could not initialize wayland server: {e:?}"))
|
||||||
|
.ok();
|
||||||
|
|
||||||
let mut hid_provider = HidWrapper::new();
|
let mut hid_provider = HidWrapper::new();
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
if let Some(wayvr) = wayvr.as_ref() {
|
if let Some(wayland_server) = wayland_server.as_ref() {
|
||||||
hid_provider.set_wayvr(wayvr.clone());
|
hid_provider.set_wayvr(wayland_server.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
@@ -114,6 +127,8 @@ impl AppState {
|
|||||||
|
|
||||||
let dbus = DbusConnector::default();
|
let dbus = DbusConnector::default();
|
||||||
|
|
||||||
|
let ipc_server = ipc_server::WayVRServer::new()?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
session,
|
session,
|
||||||
tasks,
|
tasks,
|
||||||
@@ -135,30 +150,17 @@ impl AppState {
|
|||||||
)?,
|
)?,
|
||||||
dbus,
|
dbus,
|
||||||
xr_backend,
|
xr_backend,
|
||||||
|
ipc_server,
|
||||||
|
wayvr_signals,
|
||||||
|
|
||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
osc_sender,
|
osc_sender,
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
wayvr,
|
wayland_server,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn get_wayvr(&mut self) -> anyhow::Result<Rc<RefCell<WayVRData>>> {
|
|
||||||
if let Some(wvr) = &self.wayvr {
|
|
||||||
Ok(wvr.clone())
|
|
||||||
} else {
|
|
||||||
let wayvr = Rc::new(RefCell::new(WayVRData::new(
|
|
||||||
WayVRConfig::get_wayvr_config(&self.session.config, &self.session.wayvr_config)?,
|
|
||||||
)?));
|
|
||||||
self.hid_provider.set_wayvr(wayvr.clone());
|
|
||||||
self.wayvr = Some(wayvr.clone());
|
|
||||||
Ok(wayvr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_load_bytes(path: &str, fallback_data: &'static [u8]) -> &'static [u8] {
|
pub fn try_load_bytes(path: &str, fallback_data: &'static [u8]) -> &'static [u8] {
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
return fallback_data;
|
return fallback_data;
|
||||||
@@ -187,7 +189,7 @@ pub struct AppSession {
|
|||||||
pub config: GeneralConfig,
|
pub config: GeneralConfig,
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
pub wayvr_config: WayVRConfig,
|
pub wayvr_config: WayVRConfig, // TODO: rename to "wayland_server_config"
|
||||||
|
|
||||||
pub toast_topics: IdMap<ToastTopic, ToastDisplayMethod>,
|
pub toast_topics: IdMap<ToastTopic, ToastDisplayMethod>,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user