diff --git a/Cargo.lock b/Cargo.lock index 2ac859fc..cbc3c475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -418,6 +418,36 @@ dependencies = [ "libc", ] +[[package]] +name = "gl" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404" +dependencies = [ + "gl_generator", +] + +[[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]] +name = "gl_loader" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32d96dd5f881490e537041d5532320812ba096097f07fccb4626578da0b99d3" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "glob" version = "0.3.1" @@ -530,6 +560,22 @@ dependencies = [ "wasm-bindgen", ] +[[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]] name = "lazy_static" version = "1.4.0" @@ -1061,6 +1107,16 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-egl" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355f652e5a24ae02d2ad536c8fc2d3dcc6c2bd635027cd6103a193e7d75eeda2" +dependencies = [ + "wayland-backend", + "wayland-sys", +] + [[package]] name = "wayland-protocols" version = "0.31.2" @@ -1124,6 +1180,23 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "waymirror-egl" +version = "0.1.0" +dependencies = [ + "gl", + "gl_loader", + "khronos-egl", + "libwayshot", + "thiserror", + "tracing", + "tracing-subscriber", + "wayland-backend", + "wayland-client", + "wayland-egl", + "wayland-protocols", +] + [[package]] name = "wayshot" version = "1.3.2-dev" @@ -1267,6 +1340,12 @@ dependencies = [ "wayland-protocols-wlr", ] +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 4979f4eb..b13e9351 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["wayshot", "libwayshot"] +members = ["wayshot", "libwayshot","libwayshot/examples/waymirror-egl"] [workspace.package] authors = ["Shinyzenith "] diff --git a/libwayshot/examples/waymirror-egl/.gitignore b/libwayshot/examples/waymirror-egl/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/.gitignore @@ -0,0 +1 @@ +/target diff --git a/libwayshot/examples/waymirror-egl/Cargo.lock b/libwayshot/examples/waymirror-egl/Cargo.lock new file mode 100644 index 00000000..310b1996 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/Cargo.lock @@ -0,0 +1,517 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "gl" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404" +dependencies = [ + "gl_generator", +] + +[[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]] +name = "gl_loader" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32d96dd5f881490e537041d5532320812ba096097f07fccb4626578da0b99d3" +dependencies = [ + "cc", + "libc", +] + +[[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]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustix" +version = "0.38.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "wayland-backend" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" +dependencies = [ + "bitflags", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-egl" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355f652e5a24ae02d2ad536c8fc2d3dcc6c2bd635027cd6103a193e7d75eeda2" +dependencies = [ + "wayland-backend", + "wayland-sys", +] + +[[package]] +name = "wayland-egl-ctx" +version = "0.1.0" +dependencies = [ + "gl", + "gl_loader", + "khronos-egl", + "thiserror", + "tracing", + "tracing-subscriber", + "wayland-backend", + "wayland-client", + "wayland-egl", + "wayland-protocols", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" diff --git a/libwayshot/examples/waymirror-egl/Cargo.toml b/libwayshot/examples/waymirror-egl/Cargo.toml new file mode 100644 index 00000000..9dd6fd39 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "waymirror-egl" +version = "0.1.0" +edition = "2021" + +[dependencies] +gl = "0.14.0" +gl_loader = "0.1.2" +khronos-egl = { version = "6.0.0", features = ["static"] } +thiserror = "1.0.58" +tracing = "0.1.40" +tracing-subscriber = "0.3.18" +wayland-backend = { version = "0.3.3", features = ["client_system"] } +wayland-client = { version = "0.31.2" } +wayland-egl = { version = "0.32.0" } +wayland-protocols = { version = "0.31.2", features = ["client"] } +libwayshot={path="../.."} \ No newline at end of file diff --git a/libwayshot/examples/waymirror-egl/README.md b/libwayshot/examples/waymirror-egl/README.md new file mode 100644 index 00000000..ad3b0d01 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/README.md @@ -0,0 +1,7 @@ +# wayland-egl-ctx + +Example wayland xdg window driven using egl + +# TODO + +- [x] Get GL calls to work diff --git a/libwayshot/examples/waymirror-egl/src/dispatch.rs b/libwayshot/examples/waymirror-egl/src/dispatch.rs new file mode 100644 index 00000000..2e3f38f8 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/dispatch.rs @@ -0,0 +1,131 @@ +use crate::state::WaylandEGLState; +use wayland_client::{ + delegate_noop, + protocol::{wl_compositor, wl_registry, wl_surface}, + Connection, Dispatch, QueueHandle, +}; +use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}; + +impl Dispatch for WaylandEGLState { + #[tracing::instrument(skip(registry, queue_handle, state), ret, level = "trace")] + fn event( + state: &mut Self, + registry: &wl_registry::WlRegistry, + event: wl_registry::Event, + _: &(), + _: &Connection, + queue_handle: &QueueHandle, + ) { + if let wl_registry::Event::Global { + name, + interface, + version, + } = event + { + match interface.as_str() { + "xdg_wm_base" => { + state.xdg_wm_base = Some(registry.bind::( + name, + version, + queue_handle, + (), + )); + } + "wl_compositor" => { + state.wl_compositor = Some(registry.bind::( + name, + version, + queue_handle, + (), + )); + } + _ => {} + } + } + } +} + +impl Dispatch for WaylandEGLState { + #[tracing::instrument(skip(xdg_wm_base), ret, level = "trace")] + fn event( + _: &mut Self, + xdg_wm_base: &xdg_wm_base::XdgWmBase, + event: xdg_wm_base::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + if let xdg_wm_base::Event::Ping { serial } = event { + xdg_wm_base.pong(serial); + } + } +} + +impl Dispatch for WaylandEGLState { + #[tracing::instrument(skip(xdg_surface), ret, level = "trace")] + fn event( + _: &mut Self, + xdg_surface: &xdg_surface::XdgSurface, + event: xdg_surface::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + if let xdg_surface::Event::Configure { serial } = event { + xdg_surface.ack_configure(serial); + } + } +} + +impl Dispatch for WaylandEGLState { + #[tracing::instrument(skip(), ret, level = "trace")] + fn event( + state: &mut Self, + _: &xdg_toplevel::XdgToplevel, + event: xdg_toplevel::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + xdg_toplevel::Event::Configure { width, height, .. } => { + if width == 0 || height == 0 { + return; // We do not respect this configure + } + + if state.width != width || state.height != height { + state.width = width; + state.height = height; + + state + .egl_window + .clone() + .unwrap() + .resize(state.width, state.height, 0, 0); + + unsafe { + gl::Viewport(0, 0, state.width, state.height); + } + state.wl_surface.clone().unwrap().commit(); + } + } + xdg_toplevel::Event::Close {} => { + state.running = false; + } + _ => {} + } + } +} + +impl Dispatch for WaylandEGLState { + fn event( + _state: &mut Self, + _proxy: &wl_surface::WlSurface, + _event: ::Event, + _data: &(), + _conn: &Connection, + _qhandle: &QueueHandle, + ) { + } +} +delegate_noop!(WaylandEGLState: wl_compositor::WlCompositor); diff --git a/libwayshot/examples/waymirror-egl/src/error.rs b/libwayshot/examples/waymirror-egl/src/error.rs new file mode 100644 index 00000000..1860cc85 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/error.rs @@ -0,0 +1,22 @@ +use std::result; +use thiserror::Error; + +pub type Result = result::Result; + +#[derive(Error, Debug)] +pub enum WaylandEGLStateError { + #[error("xdg_wm_base global missing")] + XdgWmBaseMissing, + + #[error("wl_compositor global missing")] + WlCompositorMissing, + + #[error("Shader compilation failed")] + GLShaderCompileFailed, + + #[error("Failed to create gl program")] + GLCreateProgramFailed, + + #[error("Failed to link gl program")] + GLLinkProgramFailed, +} diff --git a/libwayshot/examples/waymirror-egl/src/main.rs b/libwayshot/examples/waymirror-egl/src/main.rs new file mode 100644 index 00000000..34aed15b --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/main.rs @@ -0,0 +1,66 @@ +mod dispatch; +mod error; +mod state; +mod utils; + +use error::Result; +use state::WaylandEGLState; +use std::str::FromStr; + +pub fn main() -> Result<(), Box> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::from_str("trace")?) + .with_writer(std::io::stderr) + .init(); + + let mut state = WaylandEGLState::new()?; + let mut event_queue = state.wl_connection.new_event_queue(); + + let queue_handle = event_queue.handle(); + let _registry = state.wl_display.get_registry(&queue_handle, ()); + + event_queue.roundtrip(&mut state)?; + state.validate_globals()?; + + state.wl_surface = Some( + state + .wl_compositor + .as_ref() + .unwrap() + .create_surface(&queue_handle, ()), + ); + + state.xdg_surface = Some(state.xdg_wm_base.clone().unwrap().get_xdg_surface( + &state.wl_surface.clone().unwrap(), + &queue_handle, + (), + )); + state.xdg_toplevel = Some( + state + .xdg_surface + .clone() + .unwrap() + .get_toplevel(&queue_handle, ()), + ); + state + .xdg_toplevel + .clone() + .unwrap() + .set_title(state.title.clone()); + state.wl_surface.clone().unwrap().commit(); + + state.init_egl()?; + while state.running { + event_queue.dispatch_pending(&mut state)?; + + state.draw(); + state + .egl + .swap_buffers(state.egl_display.unwrap(), state.egl_surface.unwrap())?; + + tracing::event!(tracing::Level::DEBUG, "eglSwapBuffers called"); + } + state.deinit()?; + + Ok(()) +} diff --git a/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl b/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl new file mode 100644 index 00000000..165f300a --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/shaders/frag.glsl @@ -0,0 +1,8 @@ +#version 300 es + +precision mediump float; +out vec4 FragColor; + +void main() { + FragColor = vec4 ( 1.0, 0.2, 0.0, 1.0 ); +} diff --git a/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl b/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl new file mode 100644 index 00000000..7523d9c2 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/shaders/vert.glsl @@ -0,0 +1,7 @@ +#version 300 es + +layout(location = 0) in vec3 aPos; + +void main() { + gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); +} diff --git a/libwayshot/examples/waymirror-egl/src/state.rs b/libwayshot/examples/waymirror-egl/src/state.rs new file mode 100644 index 00000000..505e5741 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/state.rs @@ -0,0 +1,332 @@ +use crate::error::{Result, WaylandEGLStateError}; +use crate::utils::load_shader; + +use libwayshot::WayshotConnection; + +use gl::types::GLuint; +use khronos_egl::{self as egl, Attrib}; +use std::os::fd::AsRawFd; +use std::{ffi::c_void, rc::Rc}; +use wayland_client::{ + protocol::{wl_compositor, wl_display::WlDisplay, wl_surface::WlSurface}, + ConnectError, Connection, Proxy, +}; +use wayland_egl::WlEglSurface; +use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}; + +#[derive(Debug)] +pub struct WaylandEGLState { + pub width: i32, + pub height: i32, + pub running: bool, + pub title: String, + + pub wl_connection: Connection, + pub wl_display: WlDisplay, + pub wl_surface: Option, + + pub egl: egl::Instance, + pub egl_window: Option>, + pub egl_display: Option, + pub egl_surface: Option, + pub egl_context: Option, + pub egl_image: Option, + + pub gl_program: GLuint, + + pub xdg_wm_base: Option, + pub xdg_surface: Option, + pub xdg_toplevel: Option, + pub wl_compositor: Option, + + wayshot: WayshotConnection, +} + +impl WaylandEGLState { + #[tracing::instrument] + pub fn new() -> Result { + let server_connection = Connection::connect_to_env()?; + Ok(Self { + width: 320, + height: 240, + running: true, + title: "Nya".into(), + + wl_connection: server_connection.clone(), + wl_display: server_connection.display(), + wl_surface: None, + + egl: egl::Instance::new(egl::Static), + egl_window: None, + egl_display: None, + egl_surface: None, + egl_context: None, + egl_image: None, + gl_program: 0, + + xdg_wm_base: None, + xdg_surface: None, + xdg_toplevel: None, + wl_compositor: None, + wayshot: WayshotConnection::from_connection_with_dmabuf(server_connection).unwrap(), + }) + } + + pub fn deinit(&self) -> Result<(), Box> { + unsafe { + gl::DeleteProgram(self.gl_program); + } + + self.egl + .destroy_surface(self.egl_display.unwrap(), self.egl_surface.unwrap())?; + self.egl + .destroy_context(self.egl_display.unwrap(), self.egl_context.unwrap())?; + + self.xdg_surface.clone().unwrap().destroy(); + self.wl_surface.clone().unwrap().destroy(); + + Ok(()) + } + + pub fn init_egl(&mut self) -> Result<(), Box> { + // Init gl + gl_loader::init_gl(); + gl::load_with(|s| gl_loader::get_proc_address(s) as *const _); + + self.egl_window = Some(Rc::new(WlEglSurface::new( + self.wl_surface.clone().unwrap().id(), + self.width, + self.height, + )?)); + + self.egl_display = Some( + unsafe { + self.egl + .get_display(self.wl_display.id().as_ptr() as *mut c_void) + } + .unwrap(), + ); + + self.egl.initialize(self.egl_display.unwrap())?; + + let attributes = [ + egl::SURFACE_TYPE, + egl::WINDOW_BIT, + egl::RENDERABLE_TYPE, + egl::OPENGL_ES2_BIT, + egl::RED_SIZE, + 8, + egl::GREEN_SIZE, + 8, + egl::BLUE_SIZE, + 8, + egl::ALPHA_SIZE, + 8, + egl::NONE, + ]; + + let config = self + .egl + .choose_first_config(self.egl_display.unwrap(), &attributes)? + .expect("unable to find an appropriate EGL configuration"); + + self.egl_surface = Some(unsafe { + self.egl.create_window_surface( + self.egl_display.unwrap(), + config, + self.egl_window.clone().unwrap().ptr() as egl::NativeWindowType, + None, + )? + }); + + let context_attributes = [egl::CONTEXT_CLIENT_VERSION, 2, egl::NONE, egl::NONE]; + self.egl_context = Some(self.egl.create_context( + self.egl_display.unwrap(), + config, + None, + &context_attributes, + )?); + + self.egl.make_current( + self.egl_display.unwrap(), + self.egl_surface, + self.egl_surface, + self.egl_context, + )?; + + self.init_program()?; + let (frame_format, _guard, bo) = self + .wayshot + .capture_output_frame_dmabuf(true, &self.wayshot.get_all_outputs()[0].wl_output, None) + .unwrap(); + let modifier: u64 = dbg!(bo.modifier().unwrap().into()); + let image_attribs = [ + egl::WIDTH as Attrib, + frame_format.size.width as Attrib, + egl::HEIGHT as Attrib, + frame_format.size.height as Attrib, + 0x3271, //EGL_LINUX_DRM_FOURCC_EXT + bo.format().unwrap() as Attrib, + 0x3272, //EGL_DMA_BUF_PLANE0_FD_EXT + dbg!(bo.fd_for_plane(0).unwrap().as_raw_fd()) as Attrib, + 0x3273, + bo.offset(0).unwrap() as Attrib, + 0x3274, //EGL_DMA_BUF_PLANE0_PITCH_EXT + bo.stride_for_plane(0).unwrap() as Attrib, + 0x3443, //EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + (modifier as u32 & u32::MAX) as Attrib, + 0x3444, //EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + (modifier >> 32) as Attrib, + egl::ATTRIB_NONE, + ]; + dbg!(image_attribs, image_attribs.len()); + unsafe { + let egl_create_image_khr: fn( + display: khronos_egl::EGLDisplay, + ctx: khronos_egl::EGLContext, + target: khronos_egl::Enum, + buffer: khronos_egl::EGLClientBuffer, + attrib_list: *const Attrib, + ) -> khronos_egl::EGLImage = std::mem::transmute(dbg!(self + .egl + .get_proc_address("eglCreateImageKHR") + .unwrap())); + let image = egl_create_image_khr( + self.egl_display.unwrap().as_ptr(), + egl::NO_CONTEXT as *mut c_void, + 0x3270, + std::ptr::null_mut(), + image_attribs.as_ptr(), + ); + dbg!(image, self.egl.get_error().unwrap()); + assert_ne!(image, 0 as *mut c_void); + } + // self.egl_image = Some(unsafe { + // self.egl + // .create_image( + // self.egl_display.unwrap(), + // khronos_egl::Context::from_ptr(egl::NO_CONTEXT), + // 0x3270, // EGL_LINUX_DMA_BUF_EXT + // ClientBuffer::from_ptr(std::ptr::null_mut()), //NULL + // &image_attribs, + // ) + // .unwrap() + // }); + + Ok(()) + } + + fn init_program(&mut self) -> Result<()> { + let vert_shader = load_shader( + gl::VERTEX_SHADER, + include_str!("./shaders/vert.glsl").into(), + ) + .unwrap(); + + let frag_shader = load_shader( + gl::FRAGMENT_SHADER, + include_str!("./shaders/frag.glsl").into(), + ) + .unwrap(); + + unsafe { + self.gl_program = gl::CreateProgram(); + } + + if self.gl_program == 0 { + tracing::event!(tracing::Level::ERROR, "glCreateProgramFailed!"); + return Err(WaylandEGLStateError::GLCreateProgramFailed); + } + + unsafe { + gl::AttachShader(self.gl_program, vert_shader); + gl::AttachShader(self.gl_program, frag_shader); + + gl::LinkProgram(self.gl_program); + } + + let mut linked: gl::types::GLint = 1; + unsafe { gl::GetProgramiv(self.gl_program, gl::LINK_STATUS, &mut linked as *mut i32) } + + if linked > 0 { + tracing::event!(tracing::Level::INFO, "Successfully linked the program!"); + } else { + return Err(WaylandEGLStateError::GLLinkProgramFailed); + } + let vertices: [gl::types::GLfloat; 12] = [ + 0.9, 0.9, 0.0, // top right + 0.9, -0.9, 0.0, // bottom right + -0.9, -0.9, 0.0, // bottom left + -0.9, 0.9, 0.0, // top left + ]; + let indices: [gl::types::GLint; 6] = [ + 0, 1, 3, // first Triangle + 1, 2, 3, // second Triangle + ]; + let mut vbo: GLuint = 0; + let mut vao: GLuint = 0; + let mut ebo: GLuint = 0; + unsafe { + gl::GenVertexArrays(1, &mut vao as *mut u32); + gl::GenBuffers(1, &mut vbo as *mut u32); + gl::GenBuffers(1, &mut ebo as *mut u32); + dbg!(vbo, vao, ebo); + gl::BindVertexArray(vao); + + gl::BindBuffer(gl::ARRAY_BUFFER, vbo); + gl::BufferData( + gl::ARRAY_BUFFER, + (vertices.len() * std::mem::size_of::()) + as gl::types::GLsizeiptr, + &vertices[0] as *const f32 as *const c_void, + gl::STATIC_DRAW, + ); + + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo); + gl::BufferData( + gl::ELEMENT_ARRAY_BUFFER, + (indices.len() * std::mem::size_of::()) + as gl::types::GLsizeiptr, + &indices[0] as *const i32 as *const c_void, + gl::STATIC_DRAW, + ); + + gl::VertexAttribPointer( + 0, + 3, + gl::FLOAT, + gl::FALSE, + 3 * std::mem::size_of::() as gl::types::GLint, + 0 as *const c_void, + ); + gl::EnableVertexAttribArray(0); + gl::BindBuffer(gl::ARRAY_BUFFER, 0); + + //gl::BindVertexArray(0); + } + Ok(()) + } + + pub fn draw(&self) { + unsafe { + gl::ClearColor(1.0, 1.0, 0.0, 1.0); + gl::Clear(gl::COLOR_BUFFER_BIT); + + gl::UseProgram(self.gl_program); + + //gl::BindVertexArray(1); + gl::DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_INT, 0 as *const c_void); + dbg!(gl::GetError()); + } + } + + pub fn validate_globals(&self) -> Result<()> { + if self.xdg_wm_base.is_none() { + return Err(WaylandEGLStateError::XdgWmBaseMissing); + } else if self.wl_compositor.is_none() { + return Err(WaylandEGLStateError::WlCompositorMissing); + } + + Ok(()) + } +} diff --git a/libwayshot/examples/waymirror-egl/src/utils.rs b/libwayshot/examples/waymirror-egl/src/utils.rs new file mode 100644 index 00000000..e532e2d3 --- /dev/null +++ b/libwayshot/examples/waymirror-egl/src/utils.rs @@ -0,0 +1,31 @@ +use crate::error::{Result, WaylandEGLStateError}; +use gl::types::{GLenum, GLint, GLuint}; +use std::{ffi::CString, ptr}; + +pub fn load_shader(shader_type: GLenum, src: String) -> Result { + unsafe { + let shader: GLuint = gl::CreateShader(shader_type); + + if shader == 0 { + return Err(WaylandEGLStateError::GLShaderCompileFailed); + } + + let src_c_str = CString::new(src.as_bytes()).unwrap(); + gl::ShaderSource(shader, 1, &src_c_str.as_ptr(), ptr::null()); + + //gl::ShaderSource(shader, 1, &src_c_str.as_ptr(), std::ptr::null()); + + gl::CompileShader(shader); + + let mut status: GLint = 1; + gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status as *mut i32); + + if status > 0 { + tracing::event!(tracing::Level::INFO, "Shader compile successfull!",); + } else { + return Err(WaylandEGLStateError::GLShaderCompileFailed); + } + + Ok(shader) + } +}