From fd8b343683df5a6f3ea29d261409ea5d7fdb1f23 Mon Sep 17 00:00:00 2001 From: lever1209 Date: Sun, 2 Feb 2025 10:22:00 -0400 Subject: [PATCH] using an opengl tutorial from glutin --- Cargo.lock | 624 +++++++++++++++++++++++++++-- Cargo.toml | 9 +- build.rs | 14 +- src/graphics_engines/opengl/mod.rs | 445 ++++++++++++++++++++ src/graphics_engines/vulkan/mod.rs | 2 +- src/linux.rs | 138 ++++--- 6 files changed, 1142 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 784fd19..7e5a25e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,30 @@ dependencies = [ "jni-sys", "libc", "log", - "ndk", + "ndk 0.8.0", "ndk-context", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.8.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk 0.9.0", + "ndk-context", + "ndk-sys 0.6.0+11769913", "num_enum", "thiserror 1.0.69", ] @@ -203,7 +224,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" dependencies = [ "block-sys", - "objc2", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", ] [[package]] @@ -258,13 +288,39 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.8.0", + "log", + "polling", + "rustix", + "slab", + "thiserror 1.0.69", +] + [[package]] name = "calloop-wayland-source" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ - "calloop", + "calloop 0.12.4", + "rustix", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop 0.13.0", "rustix", "wayland-backend", "wayland-client", @@ -305,6 +361,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + [[package]] name = "cgmath" version = "0.18.0" @@ -494,6 +559,52 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + +[[package]] +name = "drm" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" +dependencies = [ + "bitflags 2.8.0", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "libc", + "rustix", +] + +[[package]] +name = "drm-ffi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e41459d99a9b529845f6d2c909eb9adf3b6d2f82635ae40be8de0601726e8b" +dependencies = [ + "drm-sys", + "rustix", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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]] name = "equivalent" version = "1.0.1" @@ -612,6 +723,63 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glutin" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03642b8b0cce622392deb0ee3e88511f75df2daac806102597905c3ea1974848" +dependencies = [ + "bitflags 2.8.0", + "cfg_aliases 0.2.1", + "cgl", + "core-foundation", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "raw-window-handle", + "wayland-sys", + "windows-sys 0.52.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" +dependencies = [ + "cfg_aliases 0.2.1", + "glutin", + "raw-window-handle", + "winit 0.30.8", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2" +dependencies = [ + "gl_generator", + "windows-sys 0.52.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185" +dependencies = [ + "gl_generator", + "x11-dl", +] + [[package]] name = "glutin_wgl_sys" version = "0.6.1" @@ -711,9 +879,9 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" dependencies = [ - "block2", + "block2 0.3.0", "dispatch", - "objc2", + "objc2 0.4.1", ] [[package]] @@ -823,6 +991,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" + [[package]] name = "litrs" version = "0.4.1" @@ -907,6 +1081,10 @@ dependencies = [ "cgmath", "concat-idents", "ctrlc", + "drm", + "gl_generator", + "glutin", + "glutin-winit", "jobserver", "libc", "log", @@ -915,6 +1093,7 @@ dependencies = [ "objc", "png", "rand", + "raw-window-handle", "shaderc", "thiserror 2.0.11", "tobj", @@ -924,7 +1103,8 @@ dependencies = [ "vitasdk-sys", "vulkanalia", "wgpu", - "winit", + "winit 0.29.15", + "winit 0.30.8", ] [[package]] @@ -979,7 +1159,22 @@ dependencies = [ "bitflags 2.8.0", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.8.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", "thiserror 1.0.69", @@ -1000,6 +1195,15 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + [[package]] name = "nix" version = "0.29.0" @@ -1085,7 +1289,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ "objc-sys", - "objc2-encode", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode 4.1.0", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation", ] [[package]] @@ -1094,6 +1384,117 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "dispatch", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation", +] + [[package]] name = "objc_exception" version = "0.1.2" @@ -1186,6 +1587,26 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1334,6 +1755,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -1379,7 +1809,7 @@ dependencies = [ "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] @@ -1419,7 +1849,20 @@ dependencies = [ "ab_glyph", "log", "memmap2", - "smithay-client-toolkit", + "smithay-client-toolkit 0.18.1", + "tiny-skia", +] + +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit 0.19.2", "tiny-skia", ] @@ -1525,8 +1968,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ "bitflags 2.8.0", - "calloop", - "calloop-wayland-source", + "calloop 0.12.4", + "calloop-wayland-source 0.2.0", "cursor-icon", "libc", "log", @@ -1537,8 +1980,33 @@ dependencies = [ "wayland-client", "wayland-csd-frame", "wayland-cursor", - "wayland-protocols", - "wayland-protocols-wlr", + "wayland-protocols 0.31.2", + "wayland-protocols-wlr 0.2.0", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.8.0", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols 0.32.5", + "wayland-protocols-wlr 0.3.5", "wayland-scanner", "xkeysym", ] @@ -2032,6 +2500,18 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-plasma" version = "0.2.0" @@ -2041,7 +2521,20 @@ dependencies = [ "bitflags 2.8.0", "wayland-backend", "wayland-client", - "wayland-protocols", + "wayland-protocols 0.31.2", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.5", "wayland-scanner", ] @@ -2054,7 +2547,20 @@ dependencies = [ "bitflags 2.8.0", "wayland-backend", "wayland-client", - "wayland-protocols", + "wayland-protocols 0.31.2", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.5", "wayland-scanner", ] @@ -2101,6 +2607,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "wgpu" version = "24.0.0" @@ -2179,7 +2695,7 @@ dependencies = [ "log", "metal 0.31.0", "naga", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", "ordered-float", @@ -2526,11 +3042,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" dependencies = [ "ahash", - "android-activity", + "android-activity 0.5.2", "atomic-waker", "bitflags 2.8.0", "bytemuck", - "calloop", + "calloop 0.12.4", "cfg_aliases 0.1.1", "core-foundation", "core-graphics", @@ -2540,33 +3056,85 @@ dependencies = [ "libc", "log", "memmap2", - "ndk", - "ndk-sys", - "objc2", + "ndk 0.8.0", + "ndk-sys 0.5.0+25.2.9519653", + "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", "raw-window-handle", "redox_syscall 0.3.5", "rustix", - "sctk-adwaita", - "smithay-client-toolkit", + "sctk-adwaita 0.8.3", + "smithay-client-toolkit 0.18.1", "smol_str", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", "wayland-client", - "wayland-protocols", - "wayland-protocols-plasma", + "wayland-protocols 0.31.2", + "wayland-protocols-plasma 0.2.0", "web-sys", - "web-time", + "web-time 0.2.4", "windows-sys 0.48.0", "x11-dl", "x11rb", "xkbcommon-dl", ] +[[package]] +name = "winit" +version = "0.30.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" +dependencies = [ + "ahash", + "android-activity 0.6.0", + "atomic-waker", + "bitflags 2.8.0", + "block2 0.5.1", + "bytemuck", + "calloop 0.13.0", + "cfg_aliases 0.2.1", + "concurrent-queue", + "core-foundation", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk 0.9.0", + "objc2 0.5.2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix", + "sctk-adwaita 0.10.1", + "smithay-client-toolkit 0.19.2", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.5", + "wayland-protocols-plasma 0.3.5", + "web-sys", + "web-time 1.1.0", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" version = "0.6.24" diff --git a/Cargo.toml b/Cargo.toml index 063a712..e1d8096 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [] shaderc = "0.8.3" num_cpus = "1.16.0" jobserver = "0.1.32" +gl_generator = "0.14" [dependencies] tracing = { version = "0.1.41", features = [ @@ -60,12 +61,18 @@ png = "0.17.16" tobj = { version = "4.0.2", features = ["log"] } [target.'cfg(any(target_os = "windows",target_os = "linux",target_os = "macos"))'.dependencies] +glutin = "0.32.2" +glutin-winit = "0.5.0" +raw-window-handle = "0.6.2" +winit = { version = "0.30.0", features = ["rwh_06"] } +drm = "0.14.1" + vulkanalia = { version = "0.26.0", features = [ "libloading", "provisional", "window", ] } -winit = "0.29" # dont update, many many breaking changes with no guides +old_winit = { package = "winit", version = "0.29" } # dont update, many many breaking changes with no guides ctrlc = "3.4.5" tokio = { version = "1.43.0", features = ["full"] } diff --git a/build.rs b/build.rs index 5ba0e9e..b02d07d 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,4 @@ -// Requires crates: shaderc, num_cpus, jobserver +// Requires crates: shaderc, num_cpus, jobserver, gl_generator // This file is licensed to anyone who obtains a copy by lever1209 under the CC BY 4.0 license available here: https://creativecommons.org/licenses/by/4.0/ @@ -10,11 +10,23 @@ const COMPILED_SHADER_EXTENSION:&'static str = ".spv"; fn main() -> Result<(), Box> { println!("cargo:rerun-if-changed=build.rs"); + generate_opengl_bindings()?; + compile_shaders()?; Ok(()) } +fn generate_opengl_bindings() -> Result<(), Box> { + let dest = std::path::PathBuf::from(&std::env::var("OUT_DIR")?); + + let mut file = std::fs::File::create(dest.join("gl_bindings.rs"))?; + gl_generator::Registry::new(gl_generator::Api::Gles2, (3, 0), gl_generator::Profile::Core, gl_generator::Fallbacks::All, []) + .write_bindings(gl_generator::StructGenerator, &mut file)?; + + Ok(()) +} + fn compile_shaders() -> Result<(), Box> { println!("cargo:rerun-if-changed={SHADER_SRC_ROOT}"); diff --git a/src/graphics_engines/opengl/mod.rs b/src/graphics_engines/opengl/mod.rs index 8b13789..df0a2ec 100644 --- a/src/graphics_engines/opengl/mod.rs +++ b/src/graphics_engines/opengl/mod.rs @@ -1 +1,446 @@ +use std::error::Error; +use std::ffi::CStr; +use std::ffi::CString; +use std::num::NonZeroU32; +use std::ops::Deref; +use gl::types::GLfloat; +use raw_window_handle::HasWindowHandle; +use winit::application::ApplicationHandler; +use winit::event::KeyEvent; +use winit::event::WindowEvent; +use winit::event_loop::ActiveEventLoop; +use winit::keyboard::Key; +use winit::keyboard::NamedKey; +use winit::window::Window; +use winit::window::WindowAttributes; + +use glutin::config::Config; +use glutin::config::ConfigTemplateBuilder; +use glutin::config::GetGlConfig; +use glutin::context::ContextApi; +use glutin::context::ContextAttributesBuilder; +use glutin::context::NotCurrentContext; +use glutin::context::PossiblyCurrentContext; +use glutin::context::Version; +use glutin::display::GetGlDisplay; +use glutin::prelude::*; +use glutin::surface::Surface; +use glutin::surface::SwapInterval; +use glutin::surface::WindowSurface; + +use glutin_winit::DisplayBuilder; +use glutin_winit::GlWindow; + +pub mod gl { + #![allow(clippy::all)] + include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); + + pub use Gles2 as Gl; +} + +pub fn main(event_loop:winit::event_loop::EventLoop<()>) -> Result<(), Box> { + // The template will match only the configurations supporting rendering + // to windows. + // + // XXX We force transparency only on macOS, given that EGL on X11 doesn't + // have it, but we still want to show window. The macOS situation is like + // that, because we can query only one config at a time on it, but all + // normal platforms will return multiple configs, so we can find the config + // with transparency ourselves inside the `reduce`. + let template = ConfigTemplateBuilder::new().with_alpha_size(8).with_transparency(cfg!(target_os = "macos")); + + let display_builder = DisplayBuilder::new().with_window_attributes(Some(window_attributes())); + + let mut app = App::new(template, display_builder); + event_loop.run_app(&mut app)?; + + app.exit_state +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop:&ActiveEventLoop) { + let (window, gl_config) = match &self.gl_display { + // We just created the event loop, so initialize the display, pick the config, and + // create the context. + GlDisplayCreationState::Builder(display_builder) => { + let (window, gl_config) = match display_builder.clone().build(event_loop, self.template.clone(), gl_config_picker) { + Ok((window, gl_config)) => (window.unwrap(), gl_config), + Err(err) => { + self.exit_state = Err(err); + event_loop.exit(); + return; + }, + }; + + println!("Picked a config with {} samples", gl_config.num_samples()); + + // Mark the display as initialized to not recreate it on resume, since the + // display is valid until we explicitly destroy it. + self.gl_display = GlDisplayCreationState::Init; + + // Create gl context. + self.gl_context = Some(create_gl_context(&window, &gl_config).treat_as_possibly_current()); + + (window, gl_config) + }, + GlDisplayCreationState::Init => { + println!("Recreating window in `resumed`"); + // Pick the config which we already use for the context. + let gl_config = self.gl_context.as_ref().unwrap().config(); + match glutin_winit::finalize_window(event_loop, window_attributes(), &gl_config) { + Ok(window) => (window, gl_config), + Err(err) => { + self.exit_state = Err(err.into()); + event_loop.exit(); + return; + }, + } + }, + }; + + let attrs = window.build_surface_attributes(Default::default()).expect("Failed to build surface attributes"); + let gl_surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() }; + + // The context needs to be current for the Renderer to set up shaders and + // buffers. It also performs function loading, which needs a current context on + // WGL. + let gl_context = self.gl_context.as_ref().unwrap(); + gl_context.make_current(&gl_surface).unwrap(); + + self.renderer.get_or_insert_with(|| Renderer::new(&gl_config.display())); + + // Try setting vsync. + if let Err(res) = gl_surface.set_swap_interval(gl_context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())) { + eprintln!("Error setting vsync: {res:?}"); + } + + assert!(self.state.replace(AppState { gl_surface, window }).is_none()); + } + + fn suspended(&mut self, _event_loop:&ActiveEventLoop) { + // This event is only raised on Android, where the backing NativeWindow for a GL + // Surface can appear and disappear at any moment. + println!("Android window removed"); + + // Destroy the GL Surface and un-current the GL Context before ndk-glue releases + // the window back to the system. + self.state = None; + + // Make context not current. + self.gl_context = Some(self.gl_context.take().unwrap().make_not_current().unwrap().treat_as_possibly_current()); + } + + fn window_event(&mut self, event_loop:&ActiveEventLoop, _window_id:winit::window::WindowId, event:WindowEvent) { + match event { + WindowEvent::Resized(size) if size.width != 0 && size.height != 0 => { + // Some platforms like EGL require resizing GL surface to update the size + // Notable platforms here are Wayland and macOS, other don't require it + // and the function is no-op, but it's wise to resize it for portability + // reasons. + if let Some(AppState { gl_surface, window: _ }) = self.state.as_ref() { + let gl_context = self.gl_context.as_ref().unwrap(); + gl_surface.resize(gl_context, NonZeroU32::new(size.width).unwrap(), NonZeroU32::new(size.height).unwrap()); + + let renderer = self.renderer.as_ref().unwrap(); + renderer.resize(size.width as i32, size.height as i32); + } + }, + WindowEvent::CloseRequested | + WindowEvent::KeyboardInput { + event: KeyEvent { + logical_key: Key::Named(NamedKey::Escape), + .. + }, + .. + } => event_loop.exit(), + _ => (), + } + } + + fn exiting(&mut self, _event_loop:&ActiveEventLoop) { + // NOTE: The handling below is only needed due to nvidia on Wayland to not crash + // on exit due to nvidia driver touching the Wayland display from on + // `exit` hook. + let _gl_display = self.gl_context.take().unwrap().display(); + + // Clear the window. + self.state = None; + #[cfg(egl_backend)] + #[allow(irrefutable_let_patterns)] + if let glutin::display::Display::Egl(display) = _gl_display { + unsafe { + display.terminate(); + } + } + } + + fn about_to_wait(&mut self, _event_loop:&ActiveEventLoop) { + if let Some(AppState { gl_surface, window }) = self.state.as_ref() { + let gl_context = self.gl_context.as_ref().unwrap(); + let renderer = self.renderer.as_ref().unwrap(); + renderer.draw(); + window.request_redraw(); + + gl_surface.swap_buffers(gl_context).unwrap(); + } + } +} + +fn create_gl_context(window:&Window, gl_config:&Config) -> NotCurrentContext { + let raw_window_handle = window.window_handle().ok().map(|wh| wh.as_raw()); + + // The context creation part. + let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle); + + // Since glutin by default tries to create OpenGL core context, which may not be + // present we should try gles. + let fallback_context_attributes = ContextAttributesBuilder::new() + .with_context_api(ContextApi::Gles(None)) + .build(raw_window_handle); + + // There are also some old devices that support neither modern OpenGL nor GLES. + // To support these we can try and create a 2.1 context. + let legacy_context_attributes = ContextAttributesBuilder::new() + .with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1)))) + .build(raw_window_handle); + + // Reuse the uncurrented context from a suspended() call if it exists, otherwise + // this is the first time resumed() is called, where the context still + // has to be created. + let gl_display = gl_config.display(); + + unsafe { + gl_display.create_context(gl_config, &context_attributes).unwrap_or_else(|_| { + gl_display.create_context(gl_config, &fallback_context_attributes).unwrap_or_else(|_| { + gl_display + .create_context(gl_config, &legacy_context_attributes) + .expect("failed to create context") + }) + }) + } +} + +fn window_attributes() -> WindowAttributes { + Window::default_attributes() + .with_transparent(true) + .with_title("Glutin triangle gradient example (press Escape to exit)") +} + +enum GlDisplayCreationState { + /// The display was not build yet. + Builder(DisplayBuilder), + /// The display was already created for the application. + Init, +} + +struct App { + template: ConfigTemplateBuilder, + renderer: Option, + // NOTE: `AppState` carries the `Window`, thus it should be dropped after everything else. + state: Option, + gl_context:Option, + gl_display:GlDisplayCreationState, + exit_state:Result<(), Box>, +} + +impl App { + fn new(template:ConfigTemplateBuilder, display_builder:DisplayBuilder) -> Self { + Self { + template, + gl_display:GlDisplayCreationState::Builder(display_builder), + exit_state:Ok(()), + gl_context:None, + state:None, + renderer:None, + } + } +} + +struct AppState { + gl_surface:Surface, + // NOTE: Window should be dropped after all resources created using its + // raw-window-handle. + window: Window, +} + +// Find the config with the maximum number of samples, so our triangle will be +// smooth. +pub fn gl_config_picker(configs:Box+'_>) -> Config { + configs + .reduce(|accum, config| { + let transparency_check = config.supports_transparency().unwrap_or(false) & !accum.supports_transparency().unwrap_or(false); + + if transparency_check || config.num_samples() > accum.num_samples() { + config + } else { + accum + } + }) + .unwrap() +} + +pub struct Renderer { + program:gl::types::GLuint, + vao: gl::types::GLuint, + vbo: gl::types::GLuint, + gl: gl::Gl, +} + +impl Renderer { + pub fn new(gl_display:&D) -> Self { + unsafe { + let gl = gl::Gl::load_with(|symbol| { + let symbol = CString::new(symbol).unwrap(); + gl_display.get_proc_address(symbol.as_c_str()).cast() + }); + + if let Some(renderer) = get_gl_string(&gl, gl::RENDERER) { + println!("Running on {}", renderer.to_string_lossy()); + } + if let Some(version) = get_gl_string(&gl, gl::VERSION) { + println!("OpenGL Version {}", version.to_string_lossy()); + } + + if let Some(shaders_version) = get_gl_string(&gl, gl::SHADING_LANGUAGE_VERSION) { + println!("Shaders version on {}", shaders_version.to_string_lossy()); + } + + let vertex_shader = create_shader(&gl, gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE); + let fragment_shader = create_shader(&gl, gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE); + + let program = gl.CreateProgram(); + + gl.AttachShader(program, vertex_shader); + gl.AttachShader(program, fragment_shader); + + gl.LinkProgram(program); + + gl.UseProgram(program); + + gl.DeleteShader(vertex_shader); + gl.DeleteShader(fragment_shader); + + let mut vao = std::mem::zeroed(); + gl.GenVertexArrays(1, &mut vao); + gl.BindVertexArray(vao); + + let mut vbo = std::mem::zeroed(); + gl.GenBuffers(1, &mut vbo); + gl.BindBuffer(gl::ARRAY_BUFFER, vbo); + gl.BufferData( + gl::ARRAY_BUFFER, + (VERTEX_DATA.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, + VERTEX_DATA.as_ptr() as *const _, + gl::STATIC_DRAW, + ); + + let pos_attrib = gl.GetAttribLocation(program, b"position\0".as_ptr() as *const _); + let color_attrib = gl.GetAttribLocation(program, b"color\0".as_ptr() as *const _); + gl.VertexAttribPointer( + pos_attrib as gl::types::GLuint, + 2, + gl::FLOAT, + 0, + 5 * std::mem::size_of::() as gl::types::GLsizei, + std::ptr::null(), + ); + gl.VertexAttribPointer( + color_attrib as gl::types::GLuint, + 3, + gl::FLOAT, + 0, + 5 * std::mem::size_of::() as gl::types::GLsizei, + (2 * std::mem::size_of::()) as *const () as *const _, + ); + gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint); + gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint); + + Self { program, vao, vbo, gl } + } + } + + pub fn draw(&self) { self.draw_with_clear_color(0.1, 0.1, 0.1, 0.9) } + + pub fn draw_with_clear_color(&self, red:GLfloat, green:GLfloat, blue:GLfloat, alpha:GLfloat) { + unsafe { + self.gl.UseProgram(self.program); + + self.gl.BindVertexArray(self.vao); + self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo); + + self.gl.ClearColor(red, green, blue, alpha); + self.gl.Clear(gl::COLOR_BUFFER_BIT); + self.gl.DrawArrays(gl::TRIANGLES, 0, 3); + } + } + + pub fn resize(&self, width:i32, height:i32) { + unsafe { + self.gl.Viewport(0, 0, width, height); + } + } +} + +impl Deref for Renderer { + type Target = gl::Gl; + + fn deref(&self) -> &Self::Target { &self.gl } +} + +impl Drop for Renderer { + fn drop(&mut self) { + unsafe { + self.gl.DeleteProgram(self.program); + self.gl.DeleteBuffers(1, &self.vbo); + self.gl.DeleteVertexArrays(1, &self.vao); + } + } +} + +unsafe fn create_shader(gl:&gl::Gl, shader:gl::types::GLenum, source:&[u8]) -> gl::types::GLuint { + let shader = gl.CreateShader(shader); + gl.ShaderSource(shader, 1, [source.as_ptr().cast()].as_ptr(), std::ptr::null()); + gl.CompileShader(shader); + shader +} + +fn get_gl_string(gl:&gl::Gl, variant:gl::types::GLenum) -> Option<&'static CStr> { + unsafe { + let s = gl.GetString(variant); + (!s.is_null()).then(|| CStr::from_ptr(s.cast())) + } +} + +#[rustfmt::skip] +static VERTEX_DATA: [f32; 15] = [ + -0.5, -0.5, 1.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 1.0, 0.0, + 0.5, -0.5, 0.0, 0.0, 1.0, +]; + +const VERTEX_SHADER_SOURCE:&[u8] = b" +#version 100 +precision mediump float; + +attribute vec2 position; +attribute vec3 color; + +varying vec3 v_color; + +void main() { + gl_Position = vec4(position, 0.0, 1.0); + v_color = color; +} +\0"; + +const FRAGMENT_SHADER_SOURCE:&[u8] = b" +#version 100 +precision mediump float; + +varying vec3 v_color; + +void main() { + gl_FragColor = vec4(v_color, 1.0); +} +\0"; diff --git a/src/graphics_engines/vulkan/mod.rs b/src/graphics_engines/vulkan/mod.rs index aba203c..19fa374 100644 --- a/src/graphics_engines/vulkan/mod.rs +++ b/src/graphics_engines/vulkan/mod.rs @@ -29,7 +29,7 @@ use vulkanalia::vk::ExtDebugUtilsExtension; use vulkanalia::vk::KhrSurfaceExtension; use vulkanalia::vk::KhrSwapchainExtension; -use winit::window::Window; +use old_winit::window::Window; type Vec2f = cgmath::Vector2; type Vec3f = cgmath::Vector3; diff --git a/src/linux.rs b/src/linux.rs index be6d4d8..22c99c2 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1,19 +1,29 @@ +use std::process::exit; + use anyhow::Result; use log::*; use vulkanalia::prelude::v1_0::*; -use winit::dpi::LogicalSize; -use winit::event::Event; -use winit::event::WindowEvent; -use winit::event_loop::EventLoop; -use winit::window::WindowBuilder; +use old_winit::dpi::LogicalSize; +use old_winit::event::Event; +use old_winit::event::WindowEvent; +use old_winit::event_loop::EventLoop; +use old_winit::window::WindowBuilder; +use crate::graphics_engines; use crate::graphics_engines::vulkan::App; const WINDOW_TITLE:&'static str = "MineMod"; +const GRAPHICS_MODE:GMode = GMode::OpenGL; + +enum GMode { + Vulkan, + OpenGL, +} + pub fn main() -> Result<()> { super::init_logging(); @@ -26,69 +36,79 @@ pub fn main() -> Result<()> { }) .expect("Error setting Ctrl-C handler"); - info!("Initializing event loop and winit window instance."); + match GRAPHICS_MODE { + GMode::Vulkan => { + info!("Initializing event loop and winit window instance."); - // Window + // Window - let event_loop = EventLoop::new()?; - let window = WindowBuilder::new() - .with_title(WINDOW_TITLE) - .with_inner_size(LogicalSize::new(1024, 768)) - .build(&event_loop)?; + let event_loop = EventLoop::new()?; + let window = WindowBuilder::new() + .with_title(WINDOW_TITLE) + .with_inner_size(LogicalSize::new(1024, 768)) + .build(&event_loop)?; - info!("Creating app and starting event loop."); + info!("Creating app and starting event loop."); - // App + // App - let mut app = unsafe { App::create(&window)? }; - let mut minimized = false; + let mut app = unsafe { App::create(&window)? }; + let mut minimized = false; - let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); + let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); - event_loop.run(move |event, elwt| { - let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); + event_loop.run(move |event, elwt| { + let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); - if let Some(receiver) = shutdown_rx_guard.as_mut() { - if receiver.try_recv().is_ok() { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - return; - } - } - - match event { - // Request a redraw when all events were processed. - Event::AboutToWait => window.request_redraw(), - Event::WindowEvent { event, .. } => match event { - // Render a frame if our Vulkan app is not being destroyed. - WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { - unsafe { app.render(&window) }.unwrap(); - }, - WindowEvent::Resized(size) => - if size.width == 0 || size.height == 0 { - minimized = true; - } else { - minimized = false; - app.resized = true; - }, - // Destroy our Vulkan app. - WindowEvent::CloseRequested => { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); + if let Some(receiver) = shutdown_rx_guard.as_mut() { + if receiver.try_recv().is_ok() { + info!("Closing event loop and destroying Vulkan instance."); + elwt.exit(); + unsafe { + app.device.device_wait_idle().unwrap(); + app.destroy(); + } + return; } - }, - _ => {}, - }, - _ => {}, - } - })?; + } + + match event { + // Request a redraw when all events were processed. + Event::AboutToWait => window.request_redraw(), + Event::WindowEvent { event, .. } => match event { + // Render a frame if our Vulkan app is not being destroyed. + WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { + unsafe { app.render(&window) }.unwrap(); + }, + WindowEvent::Resized(size) => + if size.width == 0 || size.height == 0 { + minimized = true; + } else { + minimized = false; + app.resized = true; + }, + // Destroy our Vulkan app. + WindowEvent::CloseRequested => { + info!("Closing event loop and destroying Vulkan instance."); + elwt.exit(); + unsafe { + app.device.device_wait_idle().unwrap(); + app.destroy(); + } + }, + _ => {}, + }, + _ => {}, + } + })?; + }, + GMode::OpenGL => { + if let Err(error) = graphics_engines::opengl::main(winit::event_loop::EventLoop::new()?) { + error!("gl error {error}"); + exit(-1); + } + }, + } info!("Exiting program.");