From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/khronos-egl/.cargo-checksum.json | 1 + third_party/rust/khronos-egl/CHANGELOG.md | 73 + third_party/rust/khronos-egl/Cargo.lock | 341 +++ third_party/rust/khronos-egl/Cargo.toml | 82 + third_party/rust/khronos-egl/LICENSE-APACHE | 201 ++ third_party/rust/khronos-egl/LICENSE-MIT | 23 + third_party/rust/khronos-egl/README.md | 165 ++ third_party/rust/khronos-egl/build.rs | 12 + .../rust/khronos-egl/examples/load-minimal.rs | 36 + .../rust/khronos-egl/examples/wayland-dynamic.rs | 354 +++ .../rust/khronos-egl/examples/wayland-static.rs | 344 +++ third_party/rust/khronos-egl/shell-wayland.nix | 11 + third_party/rust/khronos-egl/shell.nix | 10 + third_party/rust/khronos-egl/src/lib.rs | 2652 ++++++++++++++++++++ 14 files changed, 4305 insertions(+) create mode 100644 third_party/rust/khronos-egl/.cargo-checksum.json create mode 100644 third_party/rust/khronos-egl/CHANGELOG.md create mode 100644 third_party/rust/khronos-egl/Cargo.lock create mode 100644 third_party/rust/khronos-egl/Cargo.toml create mode 100644 third_party/rust/khronos-egl/LICENSE-APACHE create mode 100644 third_party/rust/khronos-egl/LICENSE-MIT create mode 100644 third_party/rust/khronos-egl/README.md create mode 100644 third_party/rust/khronos-egl/build.rs create mode 100644 third_party/rust/khronos-egl/examples/load-minimal.rs create mode 100644 third_party/rust/khronos-egl/examples/wayland-dynamic.rs create mode 100644 third_party/rust/khronos-egl/examples/wayland-static.rs create mode 100644 third_party/rust/khronos-egl/shell-wayland.nix create mode 100644 third_party/rust/khronos-egl/shell.nix create mode 100644 third_party/rust/khronos-egl/src/lib.rs (limited to 'third_party/rust/khronos-egl') diff --git a/third_party/rust/khronos-egl/.cargo-checksum.json b/third_party/rust/khronos-egl/.cargo-checksum.json new file mode 100644 index 0000000000..6cb2c6379f --- /dev/null +++ b/third_party/rust/khronos-egl/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"44103a0f03beeb00ca47b2e5d46d2a99530535aa663aac23245b92c5cdc250fb","Cargo.lock":"10ce53d636ff39ba8af984a3b5ede1a82be1d8e2598596f5da4c04beceb00c03","Cargo.toml":"d22f46ec07e8a0a41e8c5cb14f38ad3fea398593c76fce9fb51c5280c12a0832","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"613a096d04cd5ae2ab67acd09298ea30c7d7e89eabcc817249ea9b88f88470ae","build.rs":"d932445d4ed5c9545f2ae99417c97090e842b0ef14d217cdb4cea6b75174b4fd","examples/load-minimal.rs":"fbb649443d9180591bdc8214234312cf8624f972d135106686c39cbf5937915c","examples/wayland-dynamic.rs":"84430463f77cc996878aee1c4851c1e5cfa94438d46872dcee8808e7c7a8a028","examples/wayland-static.rs":"d0bd87d2341c0aaeeddad8ebd21b7f80894504a0f957f02ddb1d8e613a69a9b8","shell-wayland.nix":"ee9753492f0a7466b59ec23dff1c6d5c7a8178ec3dc1dd488964f1cb4859c44b","shell.nix":"1089d919bcbdf4afcd6f4403cfbe08a59253215398fdde34e6a4c62f70129f47","src/lib.rs":"e081b066e99ee1e028d265c5e873fae605a0ad56bb039f0abf36b1e6645dfafe"},"package":"6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"} \ No newline at end of file diff --git a/third_party/rust/khronos-egl/CHANGELOG.md b/third_party/rust/khronos-egl/CHANGELOG.md new file mode 100644 index 0000000000..6c31fb8612 --- /dev/null +++ b/third_party/rust/khronos-egl/CHANGELOG.md @@ -0,0 +1,73 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [6.0.0] +### Changed +- `copy_buffers` is now unsafe. +- `get_display` is now unsafe. +- `get_platform_display` is now unsafe. +- `create_platform_window_surface` is now unsafe. +- `create_platform_pixmap_surface` is now unsafe. +### Fixed +- Fix `choose_config` & `get_config` undefined behavior when the input `configs` + vector is empty. (Fixes [#21](https://github.com/timothee-haudebourg/khronos-egl/issues/21)). +- Fix Windows build (Fixes [#23](https://github.com/timothee-haudebourg/khronos-egl/pull/23)). + +## [5.0.0] +### Changed +- Upgrade dependency `libloading`: ^0.7 -> ^0.8. + +## [4.1.0] +### Changed +- `load_required` and `load` now trying to load `libEGL.so.1` or `libEGL.so`. + +## [4.0.0] +### Added +- `no-pkg-config` feature. +### Changed +- Upgrade dependency `libloading`: ^0.6 -> ^0.7. +### Removed +- `nightly` feature hich is no longer needed since `const_fn` is stabilized. + +## [3.0.2] +### Changed +- One Linux, use the `RTLD_NODELETE` when loading the EGL library in `load_required_from_filename` and `load_from_filename`. + +## [3.0.1] +### Changed +- Load `libEGL.so.1` by default instead of `libEGL.so`. + +## [3.0.0] +### Changed +- Impl `Debug` for `Static`, `Dynamic` and `Instance`. +- Add a `DynamicInstance` type alias for `Instance>` with helper functions. +- Precise version selection. +- Dynamic cast between versions with `Dynamic::load`, `Dynamic::load_required` and the `Upcast`/`Downcast` traits. +- `DynamicInstance::downcast` and `IDynamicInstance::upcast`. + +## [3.0.0-beta] +### Changed +- Removed the `khronos` dependency. +- Dynamic linking: Add the `Api` trait and the `Instance` struct along with the `static` and `dynamic` features. +- The dependency to `pkg-config` is now optional, only required by the `static` feature. +- Add an optional dependency to `libloading`, only required by the `dynamic` feature. + +## [2.2.0] +### Added +- Fix #9: new function `get_config_count` to get the number of available frame buffer configurations. + +## [2.1.1] +### Changed +- Upgrade dependency `gl`: ^0.11 -> ^0.14 +- Upgrade dependency `wayland-client`: ^0.23 -> ^0.25 +- Upgrade dependency `wayland-protocols`: ^0.23 -> ^0.25 +- Upgrade dependency `wayland-egl`: ^0.23 -> ^0.25 + +## [2.1.0] +### Changed +- Fix #3: accept `Option` instead of `Display` in `query_string`. +- More flexible dependencies versions. diff --git a/third_party/rust/khronos-egl/Cargo.lock b/third_party/rust/khronos-egl/Cargo.lock new file mode 100644 index 0000000000..5042dbc1a0 --- /dev/null +++ b/third_party/rust/khronos-egl/Cargo.lock @@ -0,0 +1,341 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[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.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" +dependencies = [ + "libloading 0.6.7", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[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 = "khronos-egl" +version = "6.0.0" +dependencies = [ + "gl", + "libc", + "libloading 0.8.0", + "pkg-config", + "wayland-client", + "wayland-egl", + "wayland-protocols", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "libc" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad167a2f54e832b82dbe003a046280dceffe5227b5f79e08e363a29638cfddd" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "wayland-client" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbdbe01d03b2267809f3ed99495b37395387fde789e0f2ebb78e8b43f75b6d7" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480450f76717edd64ad04a4426280d737fc3d10a236b982df7b1aee19f0e2d56" +dependencies = [ + "nix", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-egl" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c653507447113c967a1aeee413699acb42d96d6302ec967c6d51930eae8aa7f5" +dependencies = [ + "wayland-client", + "wayland-sys", +] + +[[package]] +name = "wayland-protocols" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319a82b4d3054dd25acc32d9aee0f84fa95b63bc983fffe4703b6b8d47e01a30" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7010ba5767b3fcd350decc59055390b4ebe6bd1b9279a9feb1f1888987f1133d" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6793834e0c35d11fd96a97297abe03d37be627e1847da52e17d7e0e3b51cc099" +dependencies = [ + "dlib", + "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.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "xml-rs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" diff --git a/third_party/rust/khronos-egl/Cargo.toml b/third_party/rust/khronos-egl/Cargo.toml new file mode 100644 index 0000000000..2987708252 --- /dev/null +++ b/third_party/rust/khronos-egl/Cargo.toml @@ -0,0 +1,82 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "khronos-egl" +version = "6.0.0" +authors = [ + "Timothée Haudebourg ", + "Sean Kerr ", +] +build = "build.rs" +description = "Rust bindings for EGL" +documentation = "https://docs.rs/khronos-egl" +readme = "README.md" +keywords = [ + "egl", + "gl", + "khronos", + "opengl", +] +license = "MIT/Apache-2.0" +repository = "https://github.com/timothee-haudebourg/khronos-egl" + +[[example]] +name = "wayland-static" +required-features = ["static"] + +[[example]] +name = "wayland-dynamic" +required-features = ["dynamic"] + +[[example]] +name = "load-minimal" +required-features = [ + "dynamic", + "1_4", +] + +[dependencies.libc] +version = "^0.2" + +[dependencies.libloading] +version = "^0.8" +optional = true + +[dev-dependencies.gl] +version = "^0.14" + +[dev-dependencies.wayland-client] +version = "^0.28" + +[dev-dependencies.wayland-egl] +version = "^0.28" + +[dev-dependencies.wayland-protocols] +version = "^0.28" +features = ["client"] + +[build-dependencies.pkg-config] +version = "^0.3" +optional = true + +[features] +1_0 = [] +1_1 = ["1_0"] +1_2 = ["1_1"] +1_3 = ["1_2"] +1_4 = ["1_3"] +1_5 = ["1_4"] +default = ["1_5"] +dynamic = ["libloading"] +no-pkg-config = [] +static = ["pkg-config"] diff --git a/third_party/rust/khronos-egl/LICENSE-APACHE b/third_party/rust/khronos-egl/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/khronos-egl/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/rust/khronos-egl/LICENSE-MIT b/third_party/rust/khronos-egl/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/third_party/rust/khronos-egl/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/khronos-egl/README.md b/third_party/rust/khronos-egl/README.md new file mode 100644 index 0000000000..5abc2bb8e4 --- /dev/null +++ b/third_party/rust/khronos-egl/README.md @@ -0,0 +1,165 @@ +# Rust bindings for EGL + + + + + +
DocumentationCrate informationsRepository
+ +This crate provides a binding for the Khronos EGL 1.5 API. +It was originally a fork of the [egl](https://crates.io/crates/egl) crate, +which is left unmaintained. + +## Usage + +You can access the EGL API using an [`Instance`](https://docs.rs/khronos-egl/latest/khronos-egl/struct.Instance.html) +object defined by either statically linking with `libEGL.so.1` at compile time, +or dynamically loading the EGL library at runtime. + +### Static linking + +You must enable static linking using the `static` feature in your `Cargo.toml`: +```toml +khronos-egl = { version = ..., features = ["static"] } +``` + +This will add a dependency to the [`pkg-config`](https://crates.io/crates/pkg-config) crate, +necessary to find the EGL library at compile time. + +If you wish to disable linking EGL in this crate, and provide linking in +your crate instead, enable the `no-pkg-config` feature. +```toml +khronos-egl = {version = ..., features = ["static", "no-pkg-config"]} +``` + +Here is a simple example showing how to use this library to create an EGL context when static linking is enabled. + +```rust +extern crate khronos_egl as egl; + +fn main() -> Result<(), egl::Error> { + // Create an EGL API instance. + // The `egl::Static` API implementation is only available when the `static` feature is enabled. + let egl = egl::Instance::new(egl::Static); + + let wayland_display = wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + let display = egl.get_display(wayland_display.get_display_ptr() as *mut std::ffi::c_void).unwrap(); + egl.initialize(display)?; + + let attributes = [ + egl::RED_SIZE, 8, + egl::GREEN_SIZE, 8, + egl::BLUE_SIZE, 8, + egl::NONE + ]; + + let config = egl.choose_first_config(display, &attributes)?.expect("unable to find an appropriate ELG configuration"); + + let context_attributes = [ + egl::CONTEXT_MAJOR_VERSION, 4, + egl::CONTEXT_MINOR_VERSION, 0, + egl::CONTEXT_OPENGL_PROFILE_MASK, egl::CONTEXT_OPENGL_CORE_PROFILE_BIT, + egl::NONE + ]; + + egl.create_context(display, config, None, &context_attributes); + + Ok(()) +} +``` + +The creation of a `Display` instance is not detailed here since it depends on your display server. +It is created using the `get_display` function with a pointer to the display server connection handle. +For instance, if you are using the [wayland-client](https://crates.io/crates/wayland-client) crate, +you can get this pointer using the `Display::get_display_ptr` method. + +#### Static API Instance + +It may be bothering in some applications to pass the `Instance` to every fonction that needs to call the EGL API. +One workaround would be to define a static `Instance`, +which should be possible to define at compile time using static linking. +However this is not yet supported by the stable `rustc` compiler. +With the nightly compiler, +you can combine the `nightly` and `static` features so that this crate +can provide a static `Instance`, called `API` that can then be accessed everywhere. + +```rust +use egl::API as egl; +``` + +### Dynamic Linking + +Dynamic linking allows your application to accept multiple versions of EGL and be more flexible. +You must enable dynamic linking using the `dynamic` feature in your `Cargo.toml`: +```toml +khronos-egl = { version = ..., features = ["dynamic"] } +``` + +This will add a dependency to the [`libloading`](https://crates.io/crates/libloading) crate, +necessary to find the EGL library at runtime. +You can then load the EGL API into a `Instance>` as follows: + +```rust +let lib = libloading::Library::new("libEGL.so.1").expect("unable to find libEGL.so.1"); +let egl = unsafe { egl::DynamicInstance::::load_required_from(lib).expect("unable to load libEGL.so.1") }; +``` + +Here, `egl::EGL1_4` is used to specify what is the minimum required version of EGL that must be provided by `libEGL.so.1`. +This will return a `DynamicInstance`, however in that case where `libEGL.so.1` provides a more recent version of EGL, +you can still upcast ths instance to provide version specific features: +```rust +match egl.upcast::() { + Some(egl1_5) => { + // do something with EGL 1.5 + } + None => { + // do something with EGL 1.4 instead. + } +}; +``` + +### NixOS + +A `shell.nix` file is present for nix users to build the crate easily. +Just enter a new nix shell using the given configuration file, +and `cargo build` should work. +If you want to run the tests and examples you will need to use `shell-wayland.nix` instead +that will also load wayland since most of them depend on it. + +## Testing + +Most test and examples most be compiled with the `static` feature. + +## Troubleshooting + +### Static Linking with OpenGL ES + +When using OpenGL ES with `khronos-egl` with the `static` feature, +it is necessary to place a dummy extern at the top of your application which links libEGL first, then GLESv1/2. +This is because libEGL provides symbols required by GLESv1/2. +Here's how to work around this: + +```rust +#[link(name = "EGL")] +#[link(name = "GLESv2")] +extern {} +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +If the original `egl` crate was licensed only under the Apache 2.0 license, +I believe I have made enough breaking changes so that no relevant code from the +original code remains and the rest can be relicensed. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/third_party/rust/khronos-egl/build.rs b/third_party/rust/khronos-egl/build.rs new file mode 100644 index 0000000000..420a5fff90 --- /dev/null +++ b/third_party/rust/khronos-egl/build.rs @@ -0,0 +1,12 @@ +#[cfg(all(feature = "static", not(feature = "no-pkg-config")))] +extern crate pkg_config; + +fn main() { + #[cfg(all(feature = "static", not(feature = "no-pkg-config")))] + { + pkg_config::Config::new() + .atleast_version("1") + .probe("egl") + .unwrap(); + } +} diff --git a/third_party/rust/khronos-egl/examples/load-minimal.rs b/third_party/rust/khronos-egl/examples/load-minimal.rs new file mode 100644 index 0000000000..e3d5fc5c35 --- /dev/null +++ b/third_party/rust/khronos-egl/examples/load-minimal.rs @@ -0,0 +1,36 @@ +extern crate khronos_egl as egl; +use egl::{EGL1_2, EGL1_4}; +use std::sync::Arc; + +fn main() { + let minimal_egl = + unsafe { Arc::new(egl::DynamicInstance::load().expect("unable to load libEGL.so.1")) }; + + println!("EGL version is {}", minimal_egl.version()); + + // Select the rendering API. + if let Some(egl1_2) = minimal_egl.upcast::() { + println!("selecting API"); + egl1_2 + .bind_api(egl::OPENGL_API) + .expect("unable to select OpenGL API"); + } + + // Setup Open GL. + gl::load_with(|name| minimal_egl.get_proc_address(name).unwrap() as *const std::ffi::c_void); + + match minimal_egl.upcast::() { + Some(egl1_4) => foo_with_1_4(egl1_4), + None => foo_without_1_4(&minimal_egl), + } +} + +fn foo_with_1_4(_egl: &egl::Instance) { + println!("with 1.4"); + // do something that requires at least EGL 1.4. +} + +fn foo_without_1_4(_egl: &egl::Instance) { + println!("without 1.4"); + // do something without any specific EGL version (other that 1.0). +} diff --git a/third_party/rust/khronos-egl/examples/wayland-dynamic.rs b/third_party/rust/khronos-egl/examples/wayland-dynamic.rs new file mode 100644 index 0000000000..0021b718b7 --- /dev/null +++ b/third_party/rust/khronos-egl/examples/wayland-dynamic.rs @@ -0,0 +1,354 @@ +extern crate khronos_egl as egl; +use gl::types::{GLboolean, GLchar, GLenum, GLint, GLuint, GLvoid}; +use std::ffi::CStr; +use std::ptr; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +use wayland_client::{ + protocol::{wl_compositor::WlCompositor, wl_surface::WlSurface}, + DispatchData, Display, EventQueue, Main, +}; + +use wayland_protocols::xdg_shell::client::{ + xdg_surface::{self, XdgSurface}, + xdg_wm_base::{self, XdgWmBase}, +}; + +fn process_xdg_event(xdg: Main, event: xdg_wm_base::Event, _dd: DispatchData) { + use xdg_wm_base::Event::*; + + match event { + Ping { serial } => xdg.pong(serial), + _ => (), + } +} + +struct DisplayConnection { + display: Display, + event_queue: EventQueue, + compositor: Main, + xdg: Main, +} + +fn setup_wayland() -> DisplayConnection { + let display = + wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + let mut event_queue = display.create_event_queue(); + let attached_display = display.clone().attach(event_queue.token()); + + let globals = wayland_client::GlobalManager::new(&attached_display); + + // Roundtrip to retrieve the globals list + event_queue + .sync_roundtrip(&mut (), |_, _, _| unreachable!()) + .unwrap(); + + // Get the compositor. + let compositor: Main = globals.instantiate_exact(1).unwrap(); + + // Xdg protocol. + let xdg: Main = globals.instantiate_exact(1).unwrap(); + xdg.quick_assign(process_xdg_event); + + DisplayConnection { + display, + event_queue, + compositor, + xdg, + } +} + +fn setup_egl(egl: &egl::DynamicInstance, display: &Display) -> egl::Display { + let egl_display = unsafe { + egl.get_display(display.get_display_ptr() as *mut std::ffi::c_void) + .unwrap() + }; + + egl.initialize(egl_display).unwrap(); + egl_display +} + +fn create_context( + egl: &egl::DynamicInstance, + display: egl::Display, +) -> (egl::Context, egl::Config) { + let attributes = [ + egl::RED_SIZE, + 8, + egl::GREEN_SIZE, + 8, + egl::BLUE_SIZE, + 8, + egl::NONE, + ]; + + let config = egl + .choose_first_config(display, &attributes) + .expect("unable to choose an EGL configuration") + .expect("no EGL configuration found"); + + let context_attributes = [ + egl::CONTEXT_MAJOR_VERSION, + 4, + egl::CONTEXT_MINOR_VERSION, + 0, + egl::CONTEXT_OPENGL_PROFILE_MASK, + egl::CONTEXT_OPENGL_CORE_PROFILE_BIT, + egl::NONE, + ]; + + let context = egl + .create_context(display, config, None, &context_attributes) + .expect("unable to create an EGL context"); + + (context, config) +} + +struct Surface { + handle: Main, + initialized: AtomicBool, +} + +fn create_surface( + egl: &Arc, + ctx: &DisplayConnection, + egl_display: egl::Display, + egl_context: egl::Context, + egl_config: egl::Config, + width: i32, + height: i32, +) -> Arc { + let wl_surface = ctx.compositor.create_surface(); + let xdg_surface = ctx.xdg.get_xdg_surface(&wl_surface); + + let xdg_toplevel = xdg_surface.get_toplevel(); + xdg_toplevel.set_app_id("khronos-egl-test".to_string()); + xdg_toplevel.set_title("Test".to_string()); + + wl_surface.commit(); + ctx.display.flush().unwrap(); + + let surface = Arc::new(Surface { + handle: wl_surface, + initialized: AtomicBool::new(false), + }); + + let weak_surface = Arc::downgrade(&surface); + + let egl = egl.clone(); + xdg_surface.quick_assign( + move |xdg_surface: Main, event: xdg_surface::Event, _dd: DispatchData| { + use xdg_surface::Event::*; + + match event { + Configure { serial } => { + if let Some(surface) = weak_surface.upgrade() { + if !surface.initialized.swap(true, Ordering::Relaxed) { + let wl_egl_surface = + wayland_egl::WlEglSurface::new(&surface.handle, width, height); + + let egl_surface = unsafe { + egl.create_window_surface( + egl_display, + egl_config, + wl_egl_surface.ptr() as egl::NativeWindowType, + None, + ) + .expect("unable to create an EGL surface") + }; + + egl.make_current( + egl_display, + Some(egl_surface), + Some(egl_surface), + Some(egl_context), + ) + .expect("unable to bind the context"); + + render(); + + egl.swap_buffers(egl_display, egl_surface) + .expect("unable to post the surface content"); + + xdg_surface.ack_configure(serial); + } + } + } + _ => (), + } + }, + ); + + surface +} + +fn main() { + let egl = unsafe { + Arc::new( + egl::DynamicInstance::::load_required() + .expect("unable to load libEGL.so.1"), + ) + }; + + // Setup Open GL. + egl.bind_api(egl::OPENGL_API) + .expect("unable to select OpenGL API"); + gl::load_with(|name| egl.get_proc_address(name).unwrap() as *const std::ffi::c_void); + + // Setup the Wayland client. + let mut ctx = setup_wayland(); + + // Setup EGL. + let egl_display = setup_egl(&egl, &ctx.display); + let (egl_context, egl_config) = create_context(&egl, egl_display); + + // Create a surface. + // Note that it must be kept alive to the end of execution. + let _surface = create_surface(&egl, &ctx, egl_display, egl_context, egl_config, 800, 600); + + loop { + ctx.event_queue + .dispatch(&mut (), |_, _, _| { /* we ignore unfiltered messages */ }) + .unwrap(); + } +} + +const VERTEX: &'static [GLint; 8] = &[-1, -1, 1, -1, 1, 1, -1, 1]; + +const INDEXES: &'static [GLuint; 4] = &[0, 1, 2, 3]; + +const VERTEX_SHADER: &[u8] = b"#version 400 +in vec2 position; + +void main() { + gl_Position = vec4(position, 0.0f, 1.0f); +} +\0"; + +const FRAGMENT_SHADER: &[u8] = b"#version 400 +out vec4 color; + +void main() { + color = vec4(1.0f, 0.0f, 0.0f, 1.0f); +} +\0"; + +fn render() { + unsafe { + let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER); + check_gl_errors(); + let src = CStr::from_bytes_with_nul_unchecked(VERTEX_SHADER).as_ptr(); + gl::ShaderSource(vertex_shader, 1, (&[src]).as_ptr(), ptr::null()); + check_gl_errors(); + gl::CompileShader(vertex_shader); + check_shader_status(vertex_shader); + + let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER); + check_gl_errors(); + let src = CStr::from_bytes_with_nul_unchecked(FRAGMENT_SHADER).as_ptr(); + gl::ShaderSource(fragment_shader, 1, (&[src]).as_ptr(), ptr::null()); + check_gl_errors(); + gl::CompileShader(fragment_shader); + check_shader_status(fragment_shader); + + let program = gl::CreateProgram(); + check_gl_errors(); + gl::AttachShader(program, vertex_shader); + check_gl_errors(); + gl::AttachShader(program, fragment_shader); + check_gl_errors(); + gl::LinkProgram(program); + check_gl_errors(); + gl::UseProgram(program); + check_gl_errors(); + + let mut buffer = 0; + gl::GenBuffers(1, &mut buffer); + check_gl_errors(); + gl::BindBuffer(gl::ARRAY_BUFFER, buffer); + check_gl_errors(); + gl::BufferData( + gl::ARRAY_BUFFER, + 8 * 4, + VERTEX.as_ptr() as *const std::ffi::c_void, + gl::STATIC_DRAW, + ); + check_gl_errors(); + + let mut vertex_input = 0; + gl::GenVertexArrays(1, &mut vertex_input); + check_gl_errors(); + gl::BindVertexArray(vertex_input); + check_gl_errors(); + gl::EnableVertexAttribArray(0); + check_gl_errors(); + gl::VertexAttribPointer(0, 2, gl::INT, gl::FALSE as GLboolean, 0, 0 as *const GLvoid); + check_gl_errors(); + + let mut indexes = 0; + gl::GenBuffers(1, &mut indexes); + check_gl_errors(); + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexes); + check_gl_errors(); + gl::BufferData( + gl::ELEMENT_ARRAY_BUFFER, + 4 * 4, + INDEXES.as_ptr() as *const std::ffi::c_void, + gl::STATIC_DRAW, + ); + check_gl_errors(); + + gl::DrawElements(gl::TRIANGLE_FAN, 4, gl::UNSIGNED_INT, std::ptr::null()); + check_gl_errors(); + } +} + +fn format_error(e: GLenum) -> &'static str { + match e { + gl::NO_ERROR => "No error", + gl::INVALID_ENUM => "Invalid enum", + gl::INVALID_VALUE => "Invalid value", + gl::INVALID_OPERATION => "Invalid operation", + gl::INVALID_FRAMEBUFFER_OPERATION => "Invalid framebuffer operation", + gl::OUT_OF_MEMORY => "Out of memory", + gl::STACK_UNDERFLOW => "Stack underflow", + gl::STACK_OVERFLOW => "Stack overflow", + _ => "Unknown error", + } +} + +pub fn check_gl_errors() { + unsafe { + match gl::GetError() { + gl::NO_ERROR => (), + e => { + panic!("OpenGL error: {}", format_error(e)) + } + } + } +} + +unsafe fn check_shader_status(shader: GLuint) { + let mut status = gl::FALSE as GLint; + gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status); + if status != (gl::TRUE as GLint) { + let mut len = 0; + gl::GetProgramiv(shader, gl::INFO_LOG_LENGTH, &mut len); + if len > 0 { + let mut buf = Vec::with_capacity(len as usize); + buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character + gl::GetProgramInfoLog( + shader, + len, + ptr::null_mut(), + buf.as_mut_ptr() as *mut GLchar, + ); + + let log = String::from_utf8(buf).unwrap(); + eprintln!("shader compilation log:\n{}", log); + } + + panic!("shader compilation failed"); + } +} diff --git a/third_party/rust/khronos-egl/examples/wayland-static.rs b/third_party/rust/khronos-egl/examples/wayland-static.rs new file mode 100644 index 0000000000..c2029679ed --- /dev/null +++ b/third_party/rust/khronos-egl/examples/wayland-static.rs @@ -0,0 +1,344 @@ +extern crate khronos_egl as egl; + +use egl::API as egl; +use gl::types::{GLboolean, GLchar, GLenum, GLint, GLuint, GLvoid}; +use std::ffi::CStr; +use std::ptr; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +use wayland_client::{ + protocol::{wl_compositor::WlCompositor, wl_surface::WlSurface}, + DispatchData, Display, EventQueue, Main, +}; + +use wayland_protocols::xdg_shell::client::{ + xdg_surface::{self, XdgSurface}, + xdg_wm_base::{self, XdgWmBase}, +}; + +fn process_xdg_event(xdg: Main, event: xdg_wm_base::Event, _dd: DispatchData) { + use xdg_wm_base::Event::*; + + match event { + Ping { serial } => xdg.pong(serial), + _ => (), + } +} + +struct DisplayConnection { + display: Display, + event_queue: EventQueue, + compositor: Main, + xdg: Main, +} + +fn setup_wayland() -> DisplayConnection { + let display = + wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + let mut event_queue = display.create_event_queue(); + let attached_display = display.clone().attach(event_queue.token()); + + let globals = wayland_client::GlobalManager::new(&attached_display); + + // Roundtrip to retrieve the globals list + event_queue + .sync_roundtrip(&mut (), |_, _, _| unreachable!()) + .unwrap(); + + // Get the compositor. + let compositor: Main = globals.instantiate_exact(1).unwrap(); + + // Xdg protocol. + let xdg: Main = globals.instantiate_exact(1).unwrap(); + xdg.quick_assign(process_xdg_event); + + DisplayConnection { + display, + event_queue, + compositor, + xdg, + } +} + +fn setup_egl(display: &Display) -> egl::Display { + let egl_display = unsafe { + egl.get_display(display.get_display_ptr() as *mut std::ffi::c_void) + .unwrap() + }; + + egl.initialize(egl_display).unwrap(); + egl_display +} + +fn create_context(display: egl::Display) -> (egl::Context, egl::Config) { + let attributes = [ + egl::RED_SIZE, + 8, + egl::GREEN_SIZE, + 8, + egl::BLUE_SIZE, + 8, + egl::NONE, + ]; + + let config = egl + .choose_first_config(display, &attributes) + .expect("unable to choose an EGL configuration") + .expect("no EGL configuration found"); + + let context_attributes = [ + egl::CONTEXT_MAJOR_VERSION, + 4, + egl::CONTEXT_MINOR_VERSION, + 0, + egl::CONTEXT_OPENGL_PROFILE_MASK, + egl::CONTEXT_OPENGL_CORE_PROFILE_BIT, + egl::NONE, + ]; + + let context = egl + .create_context(display, config, None, &context_attributes) + .expect("unable to create an EGL context"); + + (context, config) +} + +struct Surface { + handle: Main, + initialized: AtomicBool, +} + +fn create_surface( + ctx: &DisplayConnection, + egl_display: egl::Display, + egl_context: egl::Context, + egl_config: egl::Config, + width: i32, + height: i32, +) -> Arc { + let wl_surface = ctx.compositor.create_surface(); + let xdg_surface = ctx.xdg.get_xdg_surface(&wl_surface); + + let xdg_toplevel = xdg_surface.get_toplevel(); + xdg_toplevel.set_app_id("khronos-egl-test".to_string()); + xdg_toplevel.set_title("Test".to_string()); + + wl_surface.commit(); + ctx.display.flush().unwrap(); + + let surface = Arc::new(Surface { + handle: wl_surface, + initialized: AtomicBool::new(false), + }); + + let weak_surface = Arc::downgrade(&surface); + + xdg_surface.quick_assign( + move |xdg_surface: Main, event: xdg_surface::Event, _dd: DispatchData| { + use xdg_surface::Event::*; + + match event { + Configure { serial } => { + if let Some(surface) = weak_surface.upgrade() { + if !surface.initialized.swap(true, Ordering::Relaxed) { + let wl_egl_surface = + wayland_egl::WlEglSurface::new(&surface.handle, width, height); + + let egl_surface = unsafe { + egl.create_window_surface( + egl_display, + egl_config, + wl_egl_surface.ptr() as egl::NativeWindowType, + None, + ) + .expect("unable to create an EGL surface") + }; + + egl.make_current( + egl_display, + Some(egl_surface), + Some(egl_surface), + Some(egl_context), + ) + .expect("unable to bind the context"); + + render(); + + egl.swap_buffers(egl_display, egl_surface) + .expect("unable to post the surface content"); + + xdg_surface.ack_configure(serial); + } + } + } + _ => (), + } + }, + ); + + surface +} + +fn main() { + // Setup Open GL. + egl.bind_api(egl::OPENGL_API) + .expect("unable to select OpenGL API"); + gl::load_with(|name| egl.get_proc_address(name).unwrap() as *const std::ffi::c_void); + + // Setup the Wayland client. + let mut ctx = setup_wayland(); + + // Setup EGL. + let egl_display = setup_egl(&ctx.display); + let (egl_context, egl_config) = create_context(egl_display); + + // Create a surface. + // Note that it must be kept alive to the end of execution. + let _surface = create_surface(&ctx, egl_display, egl_context, egl_config, 800, 600); + + loop { + ctx.event_queue + .dispatch(&mut (), |_, _, _| { /* we ignore unfiltered messages */ }) + .unwrap(); + } +} + +const VERTEX: &'static [GLint; 8] = &[-1, -1, 1, -1, 1, 1, -1, 1]; + +const INDEXES: &'static [GLuint; 4] = &[0, 1, 2, 3]; + +const VERTEX_SHADER: &[u8] = b"#version 400 +in vec2 position; + +void main() { + gl_Position = vec4(position, 0.0f, 1.0f); +} +\0"; + +const FRAGMENT_SHADER: &[u8] = b"#version 400 +out vec4 color; + +void main() { + color = vec4(1.0f, 0.0f, 0.0f, 1.0f); +} +\0"; + +fn render() { + unsafe { + let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER); + check_gl_errors(); + let src = CStr::from_bytes_with_nul_unchecked(VERTEX_SHADER).as_ptr(); + gl::ShaderSource(vertex_shader, 1, (&[src]).as_ptr(), ptr::null()); + check_gl_errors(); + gl::CompileShader(vertex_shader); + check_shader_status(vertex_shader); + + let fragment_shader = gl::CreateShader(gl::FRAGMENT_SHADER); + check_gl_errors(); + let src = CStr::from_bytes_with_nul_unchecked(FRAGMENT_SHADER).as_ptr(); + gl::ShaderSource(fragment_shader, 1, (&[src]).as_ptr(), ptr::null()); + check_gl_errors(); + gl::CompileShader(fragment_shader); + check_shader_status(fragment_shader); + + let program = gl::CreateProgram(); + check_gl_errors(); + gl::AttachShader(program, vertex_shader); + check_gl_errors(); + gl::AttachShader(program, fragment_shader); + check_gl_errors(); + gl::LinkProgram(program); + check_gl_errors(); + gl::UseProgram(program); + check_gl_errors(); + + let mut buffer = 0; + gl::GenBuffers(1, &mut buffer); + check_gl_errors(); + gl::BindBuffer(gl::ARRAY_BUFFER, buffer); + check_gl_errors(); + gl::BufferData( + gl::ARRAY_BUFFER, + 8 * 4, + VERTEX.as_ptr() as *const std::ffi::c_void, + gl::STATIC_DRAW, + ); + check_gl_errors(); + + let mut vertex_input = 0; + gl::GenVertexArrays(1, &mut vertex_input); + check_gl_errors(); + gl::BindVertexArray(vertex_input); + check_gl_errors(); + gl::EnableVertexAttribArray(0); + check_gl_errors(); + gl::VertexAttribPointer(0, 2, gl::INT, gl::FALSE as GLboolean, 0, 0 as *const GLvoid); + check_gl_errors(); + + let mut indexes = 0; + gl::GenBuffers(1, &mut indexes); + check_gl_errors(); + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indexes); + check_gl_errors(); + gl::BufferData( + gl::ELEMENT_ARRAY_BUFFER, + 4 * 4, + INDEXES.as_ptr() as *const std::ffi::c_void, + gl::STATIC_DRAW, + ); + check_gl_errors(); + + gl::DrawElements(gl::TRIANGLE_FAN, 4, gl::UNSIGNED_INT, std::ptr::null()); + check_gl_errors(); + } +} + +fn format_error(e: GLenum) -> &'static str { + match e { + gl::NO_ERROR => "No error", + gl::INVALID_ENUM => "Invalid enum", + gl::INVALID_VALUE => "Invalid value", + gl::INVALID_OPERATION => "Invalid operation", + gl::INVALID_FRAMEBUFFER_OPERATION => "Invalid framebuffer operation", + gl::OUT_OF_MEMORY => "Out of memory", + gl::STACK_UNDERFLOW => "Stack underflow", + gl::STACK_OVERFLOW => "Stack overflow", + _ => "Unknown error", + } +} + +pub fn check_gl_errors() { + unsafe { + match gl::GetError() { + gl::NO_ERROR => (), + e => { + panic!("OpenGL error: {}", format_error(e)) + } + } + } +} + +unsafe fn check_shader_status(shader: GLuint) { + let mut status = gl::FALSE as GLint; + gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status); + if status != (gl::TRUE as GLint) { + let mut len = 0; + gl::GetProgramiv(shader, gl::INFO_LOG_LENGTH, &mut len); + if len > 0 { + let mut buf = Vec::with_capacity(len as usize); + buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character + gl::GetProgramInfoLog( + shader, + len, + ptr::null_mut(), + buf.as_mut_ptr() as *mut GLchar, + ); + + let log = String::from_utf8(buf).unwrap(); + eprintln!("shader compilation log:\n{}", log); + } + + panic!("shader compilation failed"); + } +} diff --git a/third_party/rust/khronos-egl/shell-wayland.nix b/third_party/rust/khronos-egl/shell-wayland.nix new file mode 100644 index 0000000000..f681f91231 --- /dev/null +++ b/third_party/rust/khronos-egl/shell-wayland.nix @@ -0,0 +1,11 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = [ + pkgs.gcc + pkgs.libGL + pkgs.pkg-config + pkgs.wayland + ]; + LD_LIBRARY_PATH="${pkgs.libGL}/lib"; +} diff --git a/third_party/rust/khronos-egl/shell.nix b/third_party/rust/khronos-egl/shell.nix new file mode 100644 index 0000000000..bf6c1364df --- /dev/null +++ b/third_party/rust/khronos-egl/shell.nix @@ -0,0 +1,10 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = [ + pkgs.gcc + pkgs.libGL + pkgs.pkg-config + ]; + LD_LIBRARY_PATH="${pkgs.libGL}/lib"; +} \ No newline at end of file diff --git a/third_party/rust/khronos-egl/src/lib.rs b/third_party/rust/khronos-egl/src/lib.rs new file mode 100644 index 0000000000..a4f4a1a345 --- /dev/null +++ b/third_party/rust/khronos-egl/src/lib.rs @@ -0,0 +1,2652 @@ +//! This crate provides a binding for the Khronos EGL 1.5 API. +//! It was originally a fork of the [egl](https://crates.io/crates/egl) crate, +//! which is left unmaintained. +//! +//! ## Usage +//! +//! You can access the EGL API using an [`Instance`] +//! object defined by either statically linking with `libEGL.so.1` at compile time, +//! or dynamically loading the EGL library at runtime. +//! +//! ### Static linking +//! +//! You must enable static linking using the `static` feature in your `Cargo.toml`: +//! ```toml +//! khronos-egl = { version = ..., features = ["static"] } +//! ``` +//! +//! This will add a dependency to the [`pkg-config`](https://crates.io/crates/pkg-config) crate, +//! necessary to find the EGL library at compile time. +//! Here is a simple example showing how to use this library to create an EGL context when static linking is enabled. +//! +//! ```rust +//! extern crate khronos_egl as egl; +//! +//! fn main() -> Result<(), egl::Error> { +//! // Create an EGL API instance. +//! // The `egl::Static` API implementation is only available when the `static` feature is enabled. +//! let egl = egl::Instance::new(egl::Static); +//! +//! let wayland_display = wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); +//! let display = unsafe { egl.get_display(wayland_display.get_display_ptr() as *mut std::ffi::c_void) }.unwrap(); +//! egl.initialize(display)?; +//! +//! let attributes = [ +//! egl::RED_SIZE, 8, +//! egl::GREEN_SIZE, 8, +//! egl::BLUE_SIZE, 8, +//! egl::NONE +//! ]; +//! +//! let config = egl.choose_first_config(display, &attributes)?.expect("unable to find an appropriate ELG configuration"); +//! +//! let context_attributes = [ +//! egl::CONTEXT_MAJOR_VERSION, 4, +//! egl::CONTEXT_MINOR_VERSION, 0, +//! egl::CONTEXT_OPENGL_PROFILE_MASK, egl::CONTEXT_OPENGL_CORE_PROFILE_BIT, +//! egl::NONE +//! ]; +//! +//! egl.create_context(display, config, None, &context_attributes); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The creation of a `Display` instance is not detailed here since it depends on your display server. +//! It is created using the `get_display` function with a pointer to the display server connection handle. +//! For instance, if you are using the [wayland-client](https://crates.io/crates/wayland-client) crate, +//! you can get this pointer using the `Display::get_display_ptr` method. +//! +//! #### Static API Instance +//! +//! It may be bothering in some applications to pass the `Instance` to every fonction that needs to call the EGL API. +//! One workaround would be to define a static `Instance`, +//! which should be possible to define at compile time using static linking. +//! However this is not yet supported by the stable `rustc` compiler. +//! With the nightly compiler, +//! you can combine the `nightly` and `static` features so that this crate +//! can provide a static `Instance`, called `API` that can then be accessed everywhere. +//! +//! ``` +//! # extern crate khronos_egl as egl; +//! use egl::API as egl; +//! ``` +//! +//! ### Dynamic Linking +//! +//! Dynamic linking allows your application to accept multiple versions of EGL and be more flexible. +//! You must enable dynamic linking using the `dynamic` feature in your `Cargo.toml`: +//! ```toml +//! khronos-egl = { version = ..., features = ["dynamic"] } +//! ``` +//! +//! This will add a dependency to the [`libloading`](https://crates.io/crates/libloading) crate, +//! necessary to find the EGL library at runtime. +//! You can then load the EGL API into a `Instance>` as follows: +//! +//! ``` +//! # extern crate khronos_egl as egl; +//! let lib = unsafe { libloading::Library::new("libEGL.so.1") }.expect("unable to find libEGL.so.1"); +//! let egl = unsafe { egl::DynamicInstance::::load_required_from(lib) }.expect("unable to load libEGL.so.1"); +//! ``` +//! +//! Here, `egl::EGL1_4` is used to specify what is the minimum required version of EGL that must be provided by `libEGL.so.1`. +//! This will return a `DynamicInstance`, however in that case where `libEGL.so.1` provides a more recent version of EGL, +//! you can still upcast ths instance to provide version specific features: +//! ``` +//! # extern crate khronos_egl as egl; +//! # let lib = unsafe { libloading::Library::new("libEGL.so.1") }.expect("unable to find libEGL.so.1"); +//! # let egl = unsafe { egl::DynamicInstance::::load_required_from(lib) }.expect("unable to load libEGL.so.1"); +//! match egl.upcast::() { +//! Some(egl1_5) => { +//! // do something with EGL 1.5 +//! } +//! None => { +//! // do something with EGL 1.4 instead. +//! } +//! }; +//! ``` +//! +//! ## Troubleshooting +//! +//! ### Static Linking with OpenGL ES +//! +//! When using OpenGL ES with `khronos-egl` with the `static` feature, +//! it is necessary to place a dummy extern at the top of your application which links libEGL first, then GLESv1/2. +//! This is because libEGL provides symbols required by GLESv1/2. +//! Here's how to work around this: +//! +//! ``` +//! ##[link(name = "EGL")] +//! ##[link(name = "GLESv2")] +//! extern {} +//! ``` +#![allow(non_upper_case_globals)] +#![allow(non_snake_case)] + +extern crate libc; + +use std::convert::{TryFrom, TryInto}; +use std::ffi::CStr; +use std::ffi::CString; +use std::fmt; +use std::ptr; + +use libc::{c_char, c_uint, c_void}; + +/// EGL API provider. +pub trait Api { + /// Version of the provided EGL API. + fn version(&self) -> Version; +} + +pub trait Downcast { + fn downcast(&self) -> &V; +} + +impl Downcast for T { + fn downcast(&self) -> &T { + self + } +} + +pub trait Upcast { + fn upcast(&self) -> Option<&V>; +} + +impl Upcast for T { + fn upcast(&self) -> Option<&T> { + Some(self) + } +} + +/// EGL API instance. +/// +/// An instance wraps an interface to the EGL API and provide +/// rust-friendly access to it. +pub struct Instance { + api: T, +} + +impl Instance { + /// Cast the API. + #[inline(always)] + pub fn cast_into>(self) -> Instance { + Instance { + api: self.api.into(), + } + } + + /// Try to cast the API. + #[inline(always)] + pub fn try_cast_into>(self) -> Result, Instance> { + match self.api.try_into() { + Ok(t) => Ok(Instance { api: t }), + Err(e) => Err(Instance { api: e }), + } + } + + /// Returns the version of the provided EGL API. + #[inline(always)] + pub fn version(&self) -> Version + where + T: Api, + { + self.api.version() + } +} + +impl Instance { + #[inline(always)] + pub const fn new(api: T) -> Instance { + Instance { api } + } +} + +impl fmt::Debug for Instance { + #[inline(always)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Instance({:?})", self.api) + } +} + +impl From for Instance { + #[inline(always)] + fn from(t: T) -> Instance { + Instance::new(t) + } +} + +// ------------------------------------------------------------------------------------------------ +// EGL 1.0 +// ------------------------------------------------------------------------------------------------ + +#[cfg(feature = "1_0")] +mod egl1_0 { + use super::*; + + pub type Boolean = c_uint; + pub type Int = i32; + pub type Attrib = usize; + pub type EGLDisplay = *mut c_void; + pub type EGLConfig = *mut c_void; + pub type EGLContext = *mut c_void; + pub type EGLSurface = *mut c_void; + pub type NativeDisplayType = *mut c_void; + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct Display(EGLDisplay); + + impl Display { + /// Creates a new display from its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLDisplay` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLDisplay) -> Display { + Display(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLDisplay { + self.0 + } + } + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct Config(pub(crate) EGLConfig); + + impl Config { + /// Creates a new configuration form its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLConfig` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLConfig) -> Config { + Config(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLConfig { + self.0 + } + } + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct Context(pub(crate) EGLContext); + + impl Context { + /// Creates a new context form its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLContext` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLContext) -> Context { + Context(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLContext { + self.0 + } + } + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct Surface(EGLSurface); + + impl Surface { + /// Creates a new surface form its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLSurface` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLSurface) -> Surface { + Surface(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLSurface { + self.0 + } + } + + #[cfg(not(android))] + pub type NativePixmapType = *mut c_void; + + #[cfg(not(android))] + pub type NativeWindowType = *mut c_void; + + #[repr(C)] + #[cfg(android)] + struct android_native_window_t; + + #[repr(C)] + #[cfg(android)] + struct egl_native_pixmap_t; + + #[cfg(android)] + pub type NativePixmapType = *mut egl_native_pixmap_t; + + #[cfg(android)] + pub type NativeWindowType = *mut android_native_window_t; + + pub const ALPHA_SIZE: Int = 0x3021; + pub const BAD_ACCESS: Int = 0x3002; + pub const BAD_ALLOC: Int = 0x3003; + pub const BAD_ATTRIBUTE: Int = 0x3004; + pub const BAD_CONFIG: Int = 0x3005; + pub const BAD_CONTEXT: Int = 0x3006; + pub const BAD_CURRENT_SURFACE: Int = 0x3007; + pub const BAD_DISPLAY: Int = 0x3008; + pub const BAD_MATCH: Int = 0x3009; + pub const BAD_NATIVE_PIXMAP: Int = 0x300A; + pub const BAD_NATIVE_WINDOW: Int = 0x300B; + pub const BAD_PARAMETER: Int = 0x300C; + pub const BAD_SURFACE: Int = 0x300D; + pub const BLUE_SIZE: Int = 0x3022; + pub const BUFFER_SIZE: Int = 0x3020; + pub const CONFIG_CAVEAT: Int = 0x3027; + pub const CONFIG_ID: Int = 0x3028; + pub const CORE_NATIVE_ENGINE: Int = 0x305B; + pub const DEPTH_SIZE: Int = 0x3025; + pub const DONT_CARE: Int = -1; + pub const DRAW: Int = 0x3059; + pub const EXTENSIONS: Int = 0x3055; + pub const FALSE: Boolean = 0; + pub const GREEN_SIZE: Int = 0x3023; + pub const HEIGHT: Int = 0x3056; + pub const LARGEST_PBUFFER: Int = 0x3058; + pub const LEVEL: Int = 0x3029; + pub const MAX_PBUFFER_HEIGHT: Int = 0x302A; + pub const MAX_PBUFFER_PIXELS: Int = 0x302B; + pub const MAX_PBUFFER_WIDTH: Int = 0x302C; + pub const NATIVE_RENDERABLE: Int = 0x302D; + pub const NATIVE_VISUAL_ID: Int = 0x302E; + pub const NATIVE_VISUAL_TYPE: Int = 0x302F; + pub const NONE: Int = 0x3038; + pub const ATTRIB_NONE: Attrib = 0x3038; + pub const NON_CONFORMANT_CONFIG: Int = 0x3051; + pub const NOT_INITIALIZED: Int = 0x3001; + pub const NO_CONTEXT: EGLContext = 0 as EGLContext; + pub const NO_DISPLAY: EGLDisplay = 0 as EGLDisplay; + pub const NO_SURFACE: EGLSurface = 0 as EGLSurface; + pub const PBUFFER_BIT: Int = 0x0001; + pub const PIXMAP_BIT: Int = 0x0002; + pub const READ: Int = 0x305A; + pub const RED_SIZE: Int = 0x3024; + pub const SAMPLES: Int = 0x3031; + pub const SAMPLE_BUFFERS: Int = 0x3032; + pub const SLOW_CONFIG: Int = 0x3050; + pub const STENCIL_SIZE: Int = 0x3026; + pub const SUCCESS: Int = 0x3000; + pub const SURFACE_TYPE: Int = 0x3033; + pub const TRANSPARENT_BLUE_VALUE: Int = 0x3035; + pub const TRANSPARENT_GREEN_VALUE: Int = 0x3036; + pub const TRANSPARENT_RED_VALUE: Int = 0x3037; + pub const TRANSPARENT_RGB: Int = 0x3052; + pub const TRANSPARENT_TYPE: Int = 0x3034; + pub const TRUE: Boolean = 1; + pub const VENDOR: Int = 0x3053; + pub const VERSION: Int = 0x3054; + pub const WIDTH: Int = 0x3057; + pub const WINDOW_BIT: Int = 0x0004; + + /// EGL errors. + #[derive(Clone, Copy, PartialEq, Eq, Debug)] + pub enum Error { + /// EGL is not initialized, or could not be initialized, for the specified + /// EGL display connection. + NotInitialized, + + /// EGL cannot access a requested resource (for example a context is bound + /// in another thread). + BadAccess, + + /// EGL failed to allocate resources for the requested operation. + BadAlloc, + + /// An unrecognized attribute or attribute value was passed in the attribute + /// list. + BadAttribute, + + /// An Context argument does not name a valid EGL rendering context. + BadContext, + + /// An Config argument does not name a valid EGL frame buffer configuration. + BadConfig, + + /// The current surface of the calling thread is a window, pixel buffer or + /// pixmap that is no longer valid. + BadCurrentSurface, + + /// An Display argument does not name a valid EGL display connection. + BadDisplay, + + /// An Surface argument does not name a valid surface (window, pixel buffer + /// or pixmap) configured for GL rendering. + BadSurface, + + /// Arguments are inconsistent (for example, a valid context requires + /// buffers not supplied by a valid surface). + BadMatch, + + /// One or more argument values are invalid. + BadParameter, + + /// A NativePixmapType argument does not refer to a valid native pixmap. + BadNativePixmap, + + /// A NativeWindowType argument does not refer to a valid native window. + BadNativeWindow, + + /// A power management event has occurred. The application must destroy all + /// contexts and reinitialise OpenGL ES state and objects to continue + /// rendering. + ContextLost, + } + + impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } + } + + impl Error { + pub fn native(&self) -> Int { + use Error::*; + match self { + NotInitialized => NOT_INITIALIZED, + BadAccess => BAD_ACCESS, + BadAlloc => BAD_ALLOC, + BadAttribute => BAD_ATTRIBUTE, + BadContext => BAD_CONTEXT, + BadConfig => BAD_CONFIG, + BadCurrentSurface => BAD_CURRENT_SURFACE, + BadDisplay => BAD_DISPLAY, + BadSurface => BAD_SURFACE, + BadMatch => BAD_MATCH, + BadParameter => BAD_PARAMETER, + BadNativePixmap => BAD_NATIVE_PIXMAP, + BadNativeWindow => BAD_NATIVE_WINDOW, + ContextLost => CONTEXT_LOST, + } + } + + fn message(&self) -> &'static str { + use Error::*; + match self { + NotInitialized => "EGL is not initialized, or could not be initialized, for the specified EGL display connection.", + BadAccess => "EGL cannot access a requested resource (for example a context is bound in another thread.", + BadAlloc => "EGL failed to allocate resources for the requested operation.", + BadAttribute => "An unrecognized attribute or attribute value was passed in the attribute list.", + BadContext => "An Context argument does not name a valid EGL rendering context.", + BadConfig => "An Config argument does not name a valid EGL frame buffer configuration.", + BadCurrentSurface => "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid.", + BadDisplay => "An Display argument does not name a valid EGL display connection.", + BadSurface => "An Surface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering.", + BadMatch => "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface.", + BadParameter => "One or more argument values are invalid.", + BadNativePixmap => "A NativePixmapType argument does not refer to a valid native pixmap.", + BadNativeWindow => "A NativeWindowType argument does not refer to a valid native window.", + ContextLost => "A power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering." + } + } + } + + impl From for Int { + fn from(e: Error) -> Int { + e.native() + } + } + + impl TryFrom for Error { + type Error = Int; + + fn try_from(e: Int) -> Result { + use Error::*; + match e { + NOT_INITIALIZED => Ok(NotInitialized), + BAD_ACCESS => Ok(BadAccess), + BAD_ALLOC => Ok(BadAlloc), + BAD_ATTRIBUTE => Ok(BadAttribute), + BAD_CONTEXT => Ok(BadContext), + BAD_CONFIG => Ok(BadConfig), + BAD_CURRENT_SURFACE => Ok(BadCurrentSurface), + BAD_DISPLAY => Ok(BadDisplay), + BAD_SURFACE => Ok(BadSurface), + BAD_MATCH => Ok(BadMatch), + BAD_PARAMETER => Ok(BadParameter), + BAD_NATIVE_PIXMAP => Ok(BadNativePixmap), + BAD_NATIVE_WINDOW => Ok(BadNativeWindow), + CONTEXT_LOST => Ok(ContextLost), + _ => Err(e), + } + } + } + + impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.message().fmt(f) + } + } + + pub fn check_int_list(attrib_list: &[Int]) -> Result<(), Error> { + if attrib_list.last() == Some(&NONE) { + Ok(()) + } else { + Err(Error::BadParameter) + } + } + + pub fn check_attrib_list(attrib_list: &[Attrib]) -> Result<(), Error> { + if attrib_list.last() == Some(&ATTRIB_NONE) { + Ok(()) + } else { + Err(Error::BadParameter) + } + } + + impl Instance { + /// Return the number of EGL frame buffer configurations that atch specified + /// attributes. + /// + /// This will call `eglChooseConfig` without `null` as `configs` to get the + /// number of matching configurations. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + pub fn matching_config_count( + &self, + display: Display, + attrib_list: &[Int], + ) -> Result { + check_int_list(attrib_list)?; + unsafe { + let mut count = 0; + + if self.api.eglChooseConfig( + display.as_ptr(), + attrib_list.as_ptr(), + ptr::null_mut(), + 0, + &mut count, + ) == TRUE + { + Ok(count as usize) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return a list of EGL frame buffer configurations that match specified + /// attributes. + /// + /// This will write as many matching configurations in `configs` up to its + /// capacity. You can use the function [`matching_config_count`](Self::matching_config_count) to get the + /// exact number of configurations matching the specified attributes. + /// + /// ## Example + /// + /// ``` + /// # extern crate khronos_egl as egl; + /// # extern crate wayland_client; + /// # fn main() -> Result<(), egl::Error> { + /// # let egl = egl::Instance::new(egl::Static); + /// # let wayland_display = wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + /// # let display = unsafe { egl.get_display(wayland_display.get_display_ptr() as *mut std::ffi::c_void) }.unwrap(); + /// # egl.initialize(display)?; + /// # let attrib_list = [egl::RED_SIZE, 8, egl::GREEN_SIZE, 8, egl::BLUE_SIZE, 8, egl::NONE]; + /// // Get the number of matching configurations. + /// let count = egl.matching_config_count(display, &attrib_list)?; + /// + /// // Get the matching configurations. + /// let mut configs = Vec::with_capacity(count); + /// egl.choose_config(display, &attrib_list, &mut configs)?; + /// # Ok(()) + /// # } + /// ``` + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + pub fn choose_config( + &self, + display: Display, + attrib_list: &[Int], + configs: &mut Vec, + ) -> Result<(), Error> { + check_int_list(attrib_list)?; + + let capacity = configs.capacity(); + if capacity == 0 { + // When the input ptr is null (when capacity is 0), + // eglChooseConfig behaves differently and returns the number + // of configurations. + Ok(()) + } else { + unsafe { + let mut count = 0; + + if self.api.eglChooseConfig( + display.as_ptr(), + attrib_list.as_ptr(), + configs.as_mut_ptr() as *mut EGLConfig, + capacity.try_into().unwrap(), + &mut count, + ) == TRUE + { + configs.set_len(count as usize); + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + } + + /// Return the first EGL frame buffer configuration that match specified + /// attributes. + /// + /// This is an helper function that will call `choose_config` with a buffer of + /// size 1, which is equivalent to: + /// ``` + /// # extern crate khronos_egl as egl; + /// # extern crate wayland_client; + /// # fn main() -> Result<(), egl::Error> { + /// # let egl = egl::Instance::new(egl::Static); + /// # let wayland_display = wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + /// # let display = unsafe { egl.get_display(wayland_display.get_display_ptr() as *mut std::ffi::c_void) }.unwrap(); + /// # egl.initialize(display)?; + /// # let attrib_list = [egl::RED_SIZE, 8, egl::GREEN_SIZE, 8, egl::BLUE_SIZE, 8, egl::NONE]; + /// let mut configs = Vec::with_capacity(1); + /// egl.choose_config(display, &attrib_list, &mut configs)?; + /// configs.first(); + /// # Ok(()) + /// # } + /// ``` + pub fn choose_first_config( + &self, + display: Display, + attrib_list: &[Int], + ) -> Result, Error> { + let mut configs = Vec::with_capacity(1); + self.choose_config(display, attrib_list, &mut configs)?; + Ok(configs.first().copied()) + } + + /// Copy EGL surface color buffer to a native pixmap. + /// + /// # Safety + /// + /// `target` must be a valid pointer to a native pixmap that belongs + /// to the same platform as `display` and `surface`. + pub unsafe fn copy_buffers( + &self, + display: Display, + surface: Surface, + target: NativePixmapType, + ) -> Result<(), Error> { + unsafe { + if self + .api + .eglCopyBuffers(display.as_ptr(), surface.as_ptr(), target) + == TRUE + { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Create a new EGL rendering context. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + pub fn create_context( + &self, + display: Display, + config: Config, + share_context: Option, + attrib_list: &[Int], + ) -> Result { + check_int_list(attrib_list)?; + unsafe { + let share_context = match share_context { + Some(share_context) => share_context.as_ptr(), + None => NO_CONTEXT, + }; + + let context = self.api.eglCreateContext( + display.as_ptr(), + config.as_ptr(), + share_context, + attrib_list.as_ptr(), + ); + + if context != NO_CONTEXT { + Ok(Context(context)) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Create a new EGL pixel buffer surface. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + pub fn create_pbuffer_surface( + &self, + display: Display, + config: Config, + attrib_list: &[Int], + ) -> Result { + check_int_list(attrib_list)?; + unsafe { + let surface = self.api.eglCreatePbufferSurface( + display.as_ptr(), + config.as_ptr(), + attrib_list.as_ptr(), + ); + + if surface != NO_SURFACE { + Ok(Surface(surface)) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Create a new EGL offscreen surface. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + /// + /// # Safety + /// + /// This function may raise undefined behavior if the display and native + /// pixmap do not belong to the same platform. + pub unsafe fn create_pixmap_surface( + &self, + display: Display, + config: Config, + pixmap: NativePixmapType, + attrib_list: &[Int], + ) -> Result { + check_int_list(attrib_list)?; + let surface = self.api.eglCreatePixmapSurface( + display.as_ptr(), + config.as_ptr(), + pixmap, + attrib_list.as_ptr(), + ); + + if surface != NO_SURFACE { + Ok(Surface(surface)) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Create a new EGL window surface. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + /// + /// # Safety + /// + /// This function may raise undefined behavior if the display and native + /// window do not belong to the same platform. + pub unsafe fn create_window_surface( + &self, + display: Display, + config: Config, + window: NativeWindowType, + attrib_list: Option<&[Int]>, + ) -> Result { + let attrib_list = match attrib_list { + Some(attrib_list) => { + check_int_list(attrib_list)?; + attrib_list.as_ptr() + } + None => ptr::null(), + }; + + let surface = self.api.eglCreateWindowSurface( + display.as_ptr(), + config.as_ptr(), + window, + attrib_list, + ); + + if surface != NO_SURFACE { + Ok(Surface(surface)) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Destroy an EGL rendering context. + pub fn destroy_context(&self, display: Display, ctx: Context) -> Result<(), Error> { + unsafe { + if self.api.eglDestroyContext(display.as_ptr(), ctx.as_ptr()) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Destroy an EGL surface. + pub fn destroy_surface(&self, display: Display, surface: Surface) -> Result<(), Error> { + unsafe { + if self + .api + .eglDestroySurface(display.as_ptr(), surface.as_ptr()) + == TRUE + { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return information about an EGL frame buffer configuration. + pub fn get_config_attrib( + &self, + display: Display, + config: Config, + attribute: Int, + ) -> Result { + unsafe { + let mut value: Int = 0; + if self.api.eglGetConfigAttrib( + display.as_ptr(), + config.as_ptr(), + attribute, + &mut value, + ) == TRUE + { + Ok(value) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return the number of all frame buffer configurations. + /// + /// You can use it to setup the correct capacity for the configurations buffer in [`get_configs`](Self::get_configs). + /// + /// ## Example + /// ``` + /// # extern crate khronos_egl as egl; + /// # extern crate wayland_client; + /// # fn main() -> Result<(), egl::Error> { + /// # let egl = egl::Instance::new(egl::Static); + /// # let wayland_display = wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + /// # let display = unsafe { egl.get_display(wayland_display.get_display_ptr() as *mut std::ffi::c_void) }.unwrap(); + /// # egl.initialize(display)?; + /// let mut configs = Vec::with_capacity(egl.get_config_count(display)?); + /// egl.get_configs(display, &mut configs); + /// assert!(configs.len() > 0); + /// # Ok(()) + /// # } + /// ``` + pub fn get_config_count(&self, display: Display) -> Result { + unsafe { + let mut count = 0; + + if self + .api + .eglGetConfigs(display.as_ptr(), std::ptr::null_mut(), 0, &mut count) + == TRUE + { + Ok(count as usize) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Get the list of all EGL frame buffer configurations for a display. + /// + /// The configurations are added to the `configs` buffer, up to the buffer's capacity. + /// You can use [`get_config_count`](Self::get_config_count) to get the total number of available frame buffer configurations, + /// and setup the buffer's capacity accordingly. + /// + /// ## Example + /// ``` + /// # extern crate khronos_egl as egl; + /// # extern crate wayland_client; + /// # fn main() -> Result<(), egl::Error> { + /// # let egl = egl::Instance::new(egl::Static); + /// # let wayland_display = wayland_client::Display::connect_to_env().expect("unable to connect to the wayland server"); + /// # let display = unsafe { egl.get_display(wayland_display.get_display_ptr() as *mut std::ffi::c_void) }.unwrap(); + /// # egl.initialize(display)?; + /// let mut configs = Vec::with_capacity(egl.get_config_count(display)?); + /// egl.get_configs(display, &mut configs); + /// # Ok(()) + /// # } + /// ``` + pub fn get_configs( + &self, + display: Display, + configs: &mut Vec, + ) -> Result<(), Error> { + let capacity = configs.capacity(); + if capacity == 0 { + // When the input ptr is null (when capacity is 0), + // eglGetConfig behaves differently and returns the number + // of configurations. + Ok(()) + } else { + unsafe { + let mut count = 0; + + if self.api.eglGetConfigs( + display.as_ptr(), + configs.as_mut_ptr() as *mut EGLConfig, + capacity.try_into().unwrap(), + &mut count, + ) == TRUE + { + configs.set_len(count as usize); + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + } + + /// Return the display for the current EGL rendering context. + pub fn get_current_display(&self) -> Option { + unsafe { + let display = self.api.eglGetCurrentDisplay(); + + if display != NO_DISPLAY { + Some(Display(display)) + } else { + None + } + } + } + + /// Return the read or draw surface for the current EGL rendering context. + pub fn get_current_surface(&self, readdraw: Int) -> Option { + unsafe { + let surface = self.api.eglGetCurrentSurface(readdraw); + + if surface != NO_SURFACE { + Some(Surface(surface)) + } else { + None + } + } + } + + /// Return an EGL display connection. + /// + /// # Safety + /// + /// The `native_display` must be a valid pointer to the native display. + /// Valid values for platform are defined by EGL extensions, as are + /// requirements for native_display. For example, an extension + /// specification that defines support for the X11 platform may require + /// that native_display be a pointer to an X11 Display, and an extension + /// specification that defines support for the Microsoft Windows + /// platform may require that native_display be a pointer to a Windows + /// Device Context. + pub unsafe fn get_display(&self, display_id: NativeDisplayType) -> Option { + let display = self.api.eglGetDisplay(display_id); + + if display != NO_DISPLAY { + Some(Display(display)) + } else { + None + } + } + + /// Return error information. + /// + /// Return the error of the last called EGL function in the current thread, or + /// `None` if the error is set to `SUCCESS`. + /// + /// Note that since a call to `eglGetError` sets the error to `SUCCESS`, and + /// since this function is automatically called by any wrapper function + /// returning a `Result` when necessary, this function may only return `None` + /// from the point of view of a user. + pub fn get_error(&self) -> Option { + unsafe { + let e = self.api.eglGetError(); + if e == SUCCESS { + None + } else { + Some(e.try_into().unwrap()) + } + } + } + + /// Return a GL or an EGL extension function. + pub fn get_proc_address(&self, procname: &str) -> Option { + unsafe { + let string = CString::new(procname).unwrap(); + + let addr = self.api.eglGetProcAddress(string.as_ptr()); + if !(addr as *const ()).is_null() { + Some(addr) + } else { + None + } + } + } + + /// Initialize an EGL display connection. + pub fn initialize(&self, display: Display) -> Result<(Int, Int), Error> { + unsafe { + let mut major = 0; + let mut minor = 0; + + if self + .api + .eglInitialize(display.as_ptr(), &mut major, &mut minor) + == TRUE + { + Ok((major, minor)) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Attach an EGL rendering context to EGL surfaces. + pub fn make_current( + &self, + display: Display, + draw: Option, + read: Option, + ctx: Option, + ) -> Result<(), Error> { + unsafe { + let draw = match draw { + Some(draw) => draw.as_ptr(), + None => NO_SURFACE, + }; + let read = match read { + Some(read) => read.as_ptr(), + None => NO_SURFACE, + }; + let ctx = match ctx { + Some(ctx) => ctx.as_ptr(), + None => NO_CONTEXT, + }; + + if self.api.eglMakeCurrent(display.as_ptr(), draw, read, ctx) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return EGL rendering context information. + pub fn query_context( + &self, + display: Display, + ctx: Context, + attribute: Int, + ) -> Result { + unsafe { + let mut value = 0; + if self + .api + .eglQueryContext(display.as_ptr(), ctx.as_ptr(), attribute, &mut value) + == TRUE + { + Ok(value) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return a string describing properties of the EGL client or of an EGL display + /// connection. + pub fn query_string( + &self, + display: Option, + name: Int, + ) -> Result<&'static CStr, Error> { + unsafe { + let display_ptr = match display { + Some(display) => display.as_ptr(), + None => NO_DISPLAY, + }; + + let c_str = self.api.eglQueryString(display_ptr, name); + + if !c_str.is_null() { + Ok(CStr::from_ptr(c_str)) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return EGL surface information. + pub fn query_surface( + &self, + display: Display, + surface: Surface, + attribute: Int, + ) -> Result { + unsafe { + let mut value = 0; + if self.api.eglQuerySurface( + display.as_ptr(), + surface.as_ptr(), + attribute, + &mut value, + ) == TRUE + { + Ok(value) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Post EGL surface color buffer to a native window. + pub fn swap_buffers(&self, display: Display, surface: Surface) -> Result<(), Error> { + unsafe { + if self.api.eglSwapBuffers(display.as_ptr(), surface.as_ptr()) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Terminate an EGL display connection. + pub fn terminate(&self, display: Display) -> Result<(), Error> { + unsafe { + if self.api.eglTerminate(display.as_ptr()) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Complete GL execution prior to subsequent native rendering calls. + pub fn wait_gl(&self) -> Result<(), Error> { + unsafe { + if self.api.eglWaitGL() == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Complete native execution prior to subsequent GL rendering calls. + pub fn wait_native(&self, engine: Int) -> Result<(), Error> { + unsafe { + if self.api.eglWaitNative(engine) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + } +} + +#[cfg(feature = "1_0")] +pub use egl1_0::*; + +// ------------------------------------------------------------------------------------------------ +// EGL 1.1 +// ------------------------------------------------------------------------------------------------ + +#[cfg(feature = "1_1")] +mod egl1_1 { + use super::*; + + pub const BACK_BUFFER: Int = 0x3084; + pub const BIND_TO_TEXTURE_RGB: Int = 0x3039; + pub const BIND_TO_TEXTURE_RGBA: Int = 0x303A; + pub const CONTEXT_LOST: Int = 0x300E; + pub const MIN_SWAP_INTERVAL: Int = 0x303B; + pub const MAX_SWAP_INTERVAL: Int = 0x303C; + pub const MIPMAP_TEXTURE: Int = 0x3082; + pub const MIPMAP_LEVEL: Int = 0x3083; + pub const NO_TEXTURE: Int = 0x305C; + pub const TEXTURE_2D: Int = 0x305F; + pub const TEXTURE_FORMAT: Int = 0x3080; + pub const TEXTURE_RGB: Int = 0x305D; + pub const TEXTURE_RGBA: Int = 0x305E; + pub const TEXTURE_TARGET: Int = 0x3081; + + impl Instance { + /// Defines a two-dimensional texture image. + pub fn bind_tex_image( + &self, + display: Display, + surface: Surface, + buffer: Int, + ) -> Result<(), Error> { + unsafe { + if self + .api + .eglBindTexImage(display.as_ptr(), surface.as_ptr(), buffer) + == TRUE + { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Releases a color buffer that is being used as a texture. + pub fn release_tex_image( + &self, + display: Display, + surface: Surface, + buffer: Int, + ) -> Result<(), Error> { + unsafe { + if self + .api + .eglReleaseTexImage(display.as_ptr(), surface.as_ptr(), buffer) + == TRUE + { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Set an EGL surface attribute. + pub fn surface_attrib( + &self, + display: Display, + surface: Surface, + attribute: Int, + value: Int, + ) -> Result<(), Error> { + unsafe { + if self + .api + .eglSurfaceAttrib(display.as_ptr(), surface.as_ptr(), attribute, value) + == TRUE + { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Specifies the minimum number of video frame periods per buffer swap for the + /// window associated with the current context. + pub fn swap_interval(&self, display: Display, interval: Int) -> Result<(), Error> { + unsafe { + if self.api.eglSwapInterval(display.as_ptr(), interval) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + } +} + +#[cfg(feature = "1_1")] +pub use egl1_1::*; + +// ------------------------------------------------------------------------------------------------ +// EGL 1.2 +// ------------------------------------------------------------------------------------------------ + +#[cfg(feature = "1_2")] +mod egl1_2 { + use super::*; + + pub type Enum = c_uint; + pub type EGLClientBuffer = *mut c_void; + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct ClientBuffer(EGLClientBuffer); + + impl ClientBuffer { + /// Creates a new client buffer form its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLClientBuffer` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLClientBuffer) -> ClientBuffer { + ClientBuffer(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLClientBuffer { + self.0 + } + } + + pub const ALPHA_FORMAT: Int = 0x3088; + pub const ALPHA_FORMAT_NONPRE: Int = 0x308B; + pub const ALPHA_FORMAT_PRE: Int = 0x308C; + pub const ALPHA_MASK_SIZE: Int = 0x303E; + pub const BUFFER_PRESERVED: Int = 0x3094; + pub const BUFFER_DESTROYED: Int = 0x3095; + pub const CLIENT_APIS: Int = 0x308D; + pub const COLORSPACE: Int = 0x3087; + pub const COLORSPACE_sRGB: Int = 0x3089; + pub const COLORSPACE_LINEAR: Int = 0x308A; + pub const COLOR_BUFFER_TYPE: Int = 0x303F; + pub const CONTEXT_CLIENT_TYPE: Int = 0x3097; + pub const DISPLAY_SCALING: Int = 10000; + pub const HORIZONTAL_RESOLUTION: Int = 0x3090; + pub const LUMINANCE_BUFFER: Int = 0x308F; + pub const LUMINANCE_SIZE: Int = 0x303D; + pub const OPENGL_ES_BIT: Int = 0x0001; + pub const OPENVG_BIT: Int = 0x0002; + pub const OPENGL_ES_API: Enum = 0x30A0; + pub const OPENVG_API: Enum = 0x30A1; + pub const OPENVG_IMAGE: Int = 0x3096; + pub const PIXEL_ASPECT_RATIO: Int = 0x3092; + pub const RENDERABLE_TYPE: Int = 0x3040; + pub const RENDER_BUFFER: Int = 0x3086; + pub const RGB_BUFFER: Int = 0x308E; + pub const SINGLE_BUFFER: Int = 0x3085; + pub const SWAP_BEHAVIOR: Int = 0x3093; + pub const UNKNOWN: Int = -1; + pub const VERTICAL_RESOLUTION: Int = 0x3091; + + impl Instance { + /// Set the current rendering API. + pub fn bind_api(&self, api: Enum) -> Result<(), Error> { + unsafe { + if self.api.eglBindAPI(api) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Query the current rendering API. + pub fn query_api(&self) -> Enum { + unsafe { self.api.eglQueryAPI() } + } + + /// Create a new EGL pixel buffer surface bound to an OpenVG image. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `NONE`). + pub fn create_pbuffer_from_client_buffer( + &self, + display: Display, + buffer_type: Enum, + buffer: ClientBuffer, + config: Config, + attrib_list: &[Int], + ) -> Result { + check_int_list(attrib_list)?; + unsafe { + let surface = self.api.eglCreatePbufferFromClientBuffer( + display.as_ptr(), + buffer_type, + buffer.as_ptr(), + config.as_ptr(), + attrib_list.as_ptr(), + ); + + if surface != NO_SURFACE { + Ok(Surface::from_ptr(surface)) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Release EGL per-thread state. + pub fn release_thread(&self) -> Result<(), Error> { + unsafe { + if self.api.eglReleaseThread() == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Complete client API execution prior to subsequent native rendering calls. + pub fn wait_client(&self) -> Result<(), Error> { + unsafe { + if self.api.eglWaitClient() == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + } +} + +#[cfg(feature = "1_2")] +pub use egl1_2::*; + +// ------------------------------------------------------------------------------------------------ +// EGL 1.3 +// ------------------------------------------------------------------------------------------------ + +#[cfg(feature = "1_3")] +mod egl1_3 { + use super::*; + + pub const CONFORMANT: Int = 0x3042; + pub const CONTEXT_CLIENT_VERSION: Int = 0x3098; + pub const MATCH_NATIVE_PIXMAP: Int = 0x3041; + pub const OPENGL_ES2_BIT: Int = 0x0004; + pub const VG_ALPHA_FORMAT: Int = 0x3088; + pub const VG_ALPHA_FORMAT_NONPRE: Int = 0x308B; + pub const VG_ALPHA_FORMAT_PRE: Int = 0x308C; + pub const VG_ALPHA_FORMAT_PRE_BIT: Int = 0x0040; + pub const VG_COLORSPACE: Int = 0x3087; + pub const VG_COLORSPACE_sRGB: Int = 0x3089; + pub const VG_COLORSPACE_LINEAR: Int = 0x308A; + pub const VG_COLORSPACE_LINEAR_BIT: Int = 0x0020; +} + +#[cfg(feature = "1_3")] +pub use egl1_3::*; + +// ------------------------------------------------------------------------------------------------ +// EGL 1.4 +// ------------------------------------------------------------------------------------------------ + +#[cfg(feature = "1_4")] +mod egl1_4 { + use super::*; + + pub const DEFAULT_DISPLAY: NativeDisplayType = 0 as NativeDisplayType; + pub const MULTISAMPLE_RESOLVE_BOX_BIT: Int = 0x0200; + pub const MULTISAMPLE_RESOLVE: Int = 0x3099; + pub const MULTISAMPLE_RESOLVE_DEFAULT: Int = 0x309A; + pub const MULTISAMPLE_RESOLVE_BOX: Int = 0x309B; + pub const OPENGL_API: Enum = 0x30A2; + pub const OPENGL_BIT: Int = 0x0008; + pub const SWAP_BEHAVIOR_PRESERVED_BIT: Int = 0x0400; + + impl Instance { + /// Return the current EGL rendering context. + pub fn get_current_context(&self) -> Option { + unsafe { + let context = self.api.eglGetCurrentContext(); + + if context != NO_CONTEXT { + Some(Context(context)) + } else { + None + } + } + } + } +} + +#[cfg(feature = "1_4")] +pub use egl1_4::*; + +// ------------------------------------------------------------------------------------------------ +// EGL 1.5 +// ------------------------------------------------------------------------------------------------ + +#[cfg(feature = "1_5")] +mod egl1_5 { + use super::*; + + pub type Time = u64; + pub type EGLSync = *mut c_void; + pub type EGLImage = *mut c_void; + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct Sync(EGLSync); + + impl Sync { + /// Creates a new sync form its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLSync` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLSync) -> Sync { + Sync(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLSync { + self.0 + } + } + + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] + pub struct Image(EGLImage); + + impl Image { + /// Creates a new image form its EGL pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid `EGLImage` pointer. + #[inline] + pub unsafe fn from_ptr(ptr: EGLImage) -> Image { + Image(ptr) + } + + #[inline] + pub fn as_ptr(&self) -> EGLImage { + self.0 + } + } + + pub const CONTEXT_MAJOR_VERSION: Int = 0x3098; + pub const CONTEXT_MINOR_VERSION: Int = 0x30FB; + pub const CONTEXT_OPENGL_PROFILE_MASK: Int = 0x30FD; + pub const CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY: Int = 0x31BD; + pub const NO_RESET_NOTIFICATION: Int = 0x31BE; + pub const LOSE_CONTEXT_ON_RESET: Int = 0x31BF; + pub const CONTEXT_OPENGL_CORE_PROFILE_BIT: Int = 0x00000001; + pub const CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT: Int = 0x00000002; + pub const CONTEXT_OPENGL_DEBUG: Int = 0x31B0; + pub const CONTEXT_OPENGL_FORWARD_COMPATIBLE: Int = 0x31B1; + pub const CONTEXT_OPENGL_ROBUST_ACCESS: Int = 0x31B2; + pub const OPENGL_ES3_BIT: Int = 0x00000040; + pub const CL_EVENT_HANDLE: Int = 0x309C; + pub const SYNC_CL_EVENT: Int = 0x30FE; + pub const SYNC_CL_EVENT_COMPLETE: Int = 0x30FF; + pub const SYNC_PRIOR_COMMANDS_COMPLETE: Int = 0x30F0; + pub const SYNC_TYPE: Int = 0x30F7; + pub const SYNC_STATUS: Int = 0x30F1; + pub const SYNC_CONDITION: Int = 0x30F8; + pub const SIGNALED: Int = 0x30F2; + pub const UNSIGNALED: Int = 0x30F3; + pub const SYNC_FLUSH_COMMANDS_BIT: Int = 0x0001; + pub const FOREVER: u64 = 0xFFFFFFFFFFFFFFFFu64; + pub const TIMEOUT_EXPIRED: Int = 0x30F5; + pub const CONDITION_SATISFIED: Int = 0x30F6; + pub const NO_SYNC: EGLSync = 0 as EGLSync; + pub const SYNC_FENCE: Int = 0x30F9; + pub const GL_COLORSPACE: Int = 0x309D; + pub const GL_COLORSPACE_SRGB: Int = 0x3089; + pub const GL_COLORSPACE_LINEAR: Int = 0x308A; + pub const GL_RENDERBUFFER: Int = 0x30B9; + pub const GL_TEXTURE_2D: Int = 0x30B1; + pub const GL_TEXTURE_LEVEL: Int = 0x30BC; + pub const GL_TEXTURE_3D: Int = 0x30B2; + pub const GL_TEXTURE_ZOFFSET: Int = 0x30BD; + pub const GL_TEXTURE_CUBE_MAP_POSITIVE_X: Int = 0x30B3; + pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_X: Int = 0x30B4; + pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Y: Int = 0x30B5; + pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: Int = 0x30B6; + pub const GL_TEXTURE_CUBE_MAP_POSITIVE_Z: Int = 0x30B7; + pub const GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: Int = 0x30B8; + pub const IMAGE_PRESERVED: Int = 0x30D2; + pub const NO_IMAGE: EGLImage = 0 as EGLImage; + + impl Instance { + /// Create a new EGL sync object. + /// + /// Note that the constant `ATTRIB_NONE` which has the type `Attrib` can be used + /// instead of `NONE` to terminate the attribute list. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `ATTRIB_NONE`). + /// + /// # Safety + /// + /// When creating an OpenCL Event Sync Object, passing an invalid event + /// handle in `attrib_list` may result in undefined behavior up to and including program + /// termination. + pub unsafe fn create_sync( + &self, + display: Display, + ty: Enum, + attrib_list: &[Attrib], + ) -> Result { + check_attrib_list(attrib_list)?; + let sync = self + .api + .eglCreateSync(display.as_ptr(), ty, attrib_list.as_ptr()); + if sync != NO_SYNC { + Ok(Sync(sync)) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Destroy a sync object. + /// + /// # Safety + /// + /// If display does not match the display passed to eglCreateSync when + /// sync was created, the behaviour is undefined. + pub unsafe fn destroy_sync(&self, display: Display, sync: Sync) -> Result<(), Error> { + if self.api.eglDestroySync(display.as_ptr(), sync.as_ptr()) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Wait in the client for a sync object to be signalled. + /// + /// # Safety + /// + /// If `display` does not match the [`Display`] passed to [`create_sync`](Self::create_sync) + /// when `sync` was created, the behaviour is undefined. + pub unsafe fn client_wait_sync( + &self, + display: Display, + sync: Sync, + flags: Int, + timeout: Time, + ) -> Result { + let status = + self.api + .eglClientWaitSync(display.as_ptr(), sync.as_ptr(), flags, timeout); + if status != FALSE as Int { + Ok(status) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Return an attribute of a sync object. + /// + /// # Safety + /// + /// If `display` does not match the [`Display`] passed to [`create_sync`](Self::create_sync) + /// when `sync` was created, behavior is undefined. + pub unsafe fn get_sync_attrib( + &self, + display: Display, + sync: Sync, + attribute: Int, + ) -> Result { + let mut value = 0; + if self.api.eglGetSyncAttrib( + display.as_ptr(), + sync.as_ptr(), + attribute, + &mut value as *mut Attrib, + ) == TRUE + { + Ok(value) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Create a new Image object. + /// + /// Note that the constant `ATTRIB_NONE` which has the type `Attrib` can be used + /// instead of `NONE` to terminate the attribute list. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `ATTRIB_NONE`). + pub fn create_image( + &self, + display: Display, + ctx: Context, + target: Enum, + buffer: ClientBuffer, + attrib_list: &[Attrib], + ) -> Result { + check_attrib_list(attrib_list)?; + unsafe { + let image = self.api.eglCreateImage( + display.as_ptr(), + ctx.as_ptr(), + target, + buffer.as_ptr(), + attrib_list.as_ptr(), + ); + if image != NO_IMAGE { + Ok(Image(image)) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Destroy an Image object. + pub fn destroy_image(&self, display: Display, image: Image) -> Result<(), Error> { + unsafe { + if self.api.eglDestroyImage(display.as_ptr(), image.as_ptr()) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + + /// Return an EGL display connection. + /// + /// Note that the constant `ATTRIB_NONE` which has the type `Attrib` can be used + /// instead of `NONE` to terminate the attribute list. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `ATTRIB_NONE`). + /// + /// # Safety + /// + /// The `native_display` must be a valid pointer to the native display. + /// Valid values for platform are defined by EGL extensions, as are + /// requirements for native_display. For example, an extension + /// specification that defines support for the X11 platform may require + /// that native_display be a pointer to an X11 Display, and an extension + /// specification that defines support for the Microsoft Windows + /// platform may require that native_display be a pointer to a Windows + /// Device Context. + pub unsafe fn get_platform_display( + &self, + platform: Enum, + native_display: NativeDisplayType, + attrib_list: &[Attrib], + ) -> Result { + check_attrib_list(attrib_list)?; + + let display = + self.api + .eglGetPlatformDisplay(platform, native_display, attrib_list.as_ptr()); + if display != NO_DISPLAY { + Ok(Display::from_ptr(display)) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Create a new EGL on-screen rendering surface. + /// + /// Note that the constant `ATTRIB_NONE` which has the type `Attrib` can be used + /// instead of `NONE` to terminate the attribute list. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `ATTRIB_NONE`). + /// + /// # Safety + /// + /// The `native_window` must be a valid pointer to the native window + /// and must belong to the same platform as `display`. + /// EGL considers the returned EGLSurface as belonging to that same platform. + /// The EGL extension that defines the platform to which display belongs + /// also defines the requirements for the `native_window` parameter. + pub unsafe fn create_platform_window_surface( + &self, + display: Display, + config: Config, + native_window: NativeWindowType, + attrib_list: &[Attrib], + ) -> Result { + check_attrib_list(attrib_list)?; + + let surface = self.api.eglCreatePlatformWindowSurface( + display.as_ptr(), + config.as_ptr(), + native_window, + attrib_list.as_ptr(), + ); + if surface != NO_SURFACE { + Ok(Surface::from_ptr(surface)) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Create a new EGL offscreen surface. + /// + /// Note that the constant `ATTRIB_NONE` which has the type `Attrib` can be used + /// instead of `NONE` to terminate the attribute list. + /// + /// This will return a `BadParameter` error if `attrib_list` is not a valid + /// attributes list (if it does not terminate with `ATTRIB_NONE`). + /// + /// # Safety + /// + /// The `native_pixmap` must be a valid pointer to a native pixmap. + /// and must belong to the same platform as `display`. + /// EGL considers the returned EGLSurface as belonging to that same platform. + /// The EGL extension that defines the platform to which display belongs + /// also defines the requirements for the `native_pixmap` parameter. + pub unsafe fn create_platform_pixmap_surface( + &self, + display: Display, + config: Config, + native_pixmap: NativePixmapType, + attrib_list: &[Attrib], + ) -> Result { + check_attrib_list(attrib_list)?; + + let surface = self.api.eglCreatePlatformPixmapSurface( + display.as_ptr(), + config.as_ptr(), + native_pixmap, + attrib_list.as_ptr(), + ); + if surface != NO_SURFACE { + Ok(Surface::from_ptr(surface)) + } else { + Err(self.get_error().unwrap()) + } + } + + /// Wait in the server for a sync object to be signalled. + /// + /// This function is unsafe: if `display` does not match the [`Display`] passed to [`create_sync`](Self::create_sync) + /// when `sync` was created, the behavior is undefined. + pub fn wait_sync(&self, display: Display, sync: Sync, flags: Int) -> Result<(), Error> { + unsafe { + if self.api.eglWaitSync(display.as_ptr(), sync.as_ptr(), flags) == TRUE { + Ok(()) + } else { + Err(self.get_error().unwrap()) + } + } + } + } +} + +#[cfg(feature = "1_5")] +pub use egl1_5::*; + +// ------------------------------------------------------------------------------------------------- +// FFI +// ------------------------------------------------------------------------------------------------- + +macro_rules! api { + ($($id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* }),*) => { + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + pub enum Version { + $( + #[cfg(feature=$version)] + $id, + )* + } + + impl std::fmt::Display for Version { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + $( + #[cfg(feature=$version)] + Version::$id => write!(f, $version), + )* + } + } + } + + pub mod api { + use super::*; + + api!(@api_traits () () $($id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* })*); + } + + #[cfg(feature="static")] + mod ffi { + use libc::{c_char, c_void}; + + use super::{ + Attrib, Boolean, EGLClientBuffer, EGLConfig, EGLContext, EGLDisplay, EGLImage, EGLSurface, + EGLSync, Enum, Int, NativeDisplayType, NativePixmapType, NativeWindowType, Time, + }; + + $( + extern "system" { + $( + #[cfg(feature=$version)] + pub fn $name ($($arg : $atype ),* ) -> $rtype ; + )* + } + )* + } + + #[cfg(feature="static")] + /// Static EGL API interface. + /// + /// This type is only available when the `static` feature is enabled, + /// by statically linking the EGL library at compile time. + #[derive(Copy, Clone, Debug)] + pub struct Static; + + #[cfg(feature="static")] + impl Api for Static { + #[inline(always)] + fn version(&self) -> Version { + LATEST + } + } + + #[cfg(feature="static")] + pub static API: Instance = Instance::new(Static); + + #[cfg(feature="dynamic")] + extern crate libloading; + + api!(@dynamic_struct $($id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* })*); + api!(@api_types () $($id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* })*); + }; + (@dynamic_struct $($id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* })*) => { + #[cfg(feature="dynamic")] + #[derive(Debug)] + pub enum LoadError { + /// Something wrong happend while loading the library. + Library(L), + + /// The provided version does not meet the requirements. + InvalidVersion { + provided: Version, + required: Version + } + } + + #[cfg(feature="dynamic")] + impl std::error::Error for LoadError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + LoadError::Library(l) => Some(l), + _ => None + } + } + } + + #[cfg(feature="dynamic")] + impl std::fmt::Display for LoadError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + LoadError::Library(l) => write!(f, "Load error: {}", l), + LoadError::InvalidVersion { provided, required } => write!(f, "Invalid EGL API version (required {}, provided {})", required, provided) + } + } + } + + #[cfg(feature="dynamic")] + struct RawDynamic { + lib: L, + version: Version, + $( + $( + #[cfg(feature=$version)] + $name : std::mem::MaybeUninit $rtype>, + )* + )* + } + + #[cfg(feature="dynamic")] + impl RawDynamic { + #[inline(always)] + /// Returns the underlying EGL library. + pub fn library(&self) -> &L { + &self.lib + } + + #[inline(always)] + /// Returns the EGL version. + pub fn version(&self) -> Version { + self.version + } + + #[inline(always)] + /// Sets the EGL version. + pub unsafe fn set_version(&mut self, version: Version) { + self.version = version + } + + /// Wraps the given library but does not load the symbols. + pub unsafe fn unloaded(lib: L, version: Version) -> Self { + RawDynamic { + lib, + version, + $( + $( + #[cfg(feature=$version)] + $name : std::mem::MaybeUninit::uninit(), + )* + )* + } + } + } + + #[cfg(feature="dynamic")] + /// Dynamic EGL API interface. + /// + /// The first type parameter is the type of the underlying library handle. + /// The second `Dynamic` type parameter gives the EGL API version provided by the library. + /// + /// This type is only available when the `dynamic` feature is enabled. + /// In most cases, you may prefer to directly use the `DynamicInstance` type. + pub struct Dynamic { + raw: RawDynamic, + _api_version: std::marker::PhantomData + } + + #[cfg(feature="dynamic")] + impl Dynamic { + #[inline(always)] + /// Return the underlying EGL library. + pub fn library(&self) -> &L { + self.raw.library() + } + + /// Returns the provided EGL version. + pub fn version(&self) -> Version { + self.raw.version() + } + + /// Wraps the given library but does not load the symbols. + pub(crate) unsafe fn unloaded(lib: L, version: Version) -> Self { + Dynamic { + raw: RawDynamic::unloaded(lib, version), + _api_version: std::marker::PhantomData + } + } + } + + #[cfg(feature="dynamic")] + impl Api for Dynamic { + /// Returns the provided EGL version. + #[inline(always)] + fn version(&self) -> Version { + self.version() + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature="1_0")] + impl> Dynamic { + #[inline] + /// Load the EGL API symbols from the given library. + /// + /// This will load the most recent API provided by the library, + /// which is at least EGL 1.0. + /// You can check what version has actually been loaded using [`Dynamic::version`], + /// and/or convert to a more recent version using [`try_into`](TryInto::try_into). + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the input library complies to the EGL API. + pub unsafe fn load_from(lib: L) -> Result, libloading::Error> { + let mut result = Dynamic::unloaded(lib, Version::EGL1_0); + + $( + match $id::load_from(&mut result.raw) { + Ok(()) => result.raw.set_version(Version::$id), + Err(libloading::Error::DlSymUnknown) => { + if Version::$id == Version::EGL1_0 { + return Err(libloading::Error::DlSymUnknown) // we require at least EGL 1.0. + } else { + return Ok(result) + } + }, + Err(libloading::Error::DlSym { desc }) => { + if Version::$id == Version::EGL1_0 { + return Err(libloading::Error::DlSym { desc }) // we require at least EGL 1.0. + } else { + return Ok(result) + } + }, + Err(e) => return Err(e) + } + )* + + Ok(result) + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature="1_0")] + impl> Instance> { + #[inline(always)] + /// Create an EGL instance using the symbols provided by the given library. + /// + /// The most recent version of EGL provided by the given library is loaded. + /// You can check what version has actually been loaded using [`Instance::version`], + /// and/or convert to a more recent version using [`try_into`](TryInto::try_into). + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the input library complies to the EGL API. + pub unsafe fn load_from(lib: L) -> Result>, libloading::Error> { + Ok(Instance::new(Dynamic::::load_from(lib)?)) + } + } + + #[cfg(feature="dynamic")] + impl Instance> { + /// Cast the API. + #[inline(always)] + pub fn downcast(&self) -> &Instance> where Instance>: Downcast>> { + Downcast::downcast(self) + } + + /// Cast the API. + #[inline(always)] + pub fn upcast(&self) -> Option<&Instance>> where Instance>: Upcast>> { + Upcast::upcast(self) + } + } + + #[cfg(feature="dynamic")] + unsafe impl + Send, A: Send> Send for Dynamic {} + + #[cfg(feature="dynamic")] + unsafe impl + std::marker::Sync, A: std::marker::Sync> std::marker::Sync for Dynamic {} + + #[cfg(feature="dynamic")] + impl + fmt::Debug, A> fmt::Debug for Dynamic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Dynamic({:?})", self.library()) + } + } + }; + (@api_traits ( ) ( ) $id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* } $($t_id:ident : $t_version:literal { $(fn $t_name:ident ($($t_arg:ident : $t_atype:ty ),* ) -> $t_rtype:ty ;)* })*) => { + api!(@api_trait ( ) ( ) $id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* }); + api!(@api_traits ( $id : $version ) ( : $id ) $($t_id : $t_version { $(fn $t_name ($($t_arg : $t_atype ),* ) -> $t_rtype ;)* })*); + }; + (@api_traits ( $($pred:ident : $p_version:literal)+ ) ( $($deps:tt)+ ) $id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* } $($t_id:ident : $t_version:literal { $(fn $t_name:ident ($($t_arg:ident : $t_atype:ty ),* ) -> $t_rtype:ty ;)* })*) => { + api!(@api_trait ( $($pred : $p_version)* ) ( $($deps)* ) $id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* }); + api!(@api_traits ( $($pred : $version)* $id : $version ) ( $($deps)* + $id ) $($t_id : $t_version { $(fn $t_name ($($t_arg : $t_atype ),* ) -> $t_rtype ;)* })*); + }; + (@api_traits ( $($pred:ident : $p_version:literal)* ) ( $($deps:tt)* )) => { + // nothing + }; + (@api_trait ( $($pred:ident : $p_version:literal)* ) ( $($deps:tt)* ) $id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* }) => { + /// EGL API interface. + /// + /// An implementation of this trait can be used to create an [`Instance`]. + /// + /// This crate provides two implementation of this trait: + /// - [`Static`] which is available with the `static` feature enabled, + /// defined by statically linking to the EGL library at compile time. + /// - [`Dynamic`] which is available with the `dynamic` feature enabled, + /// defined by dynamically linking to the EGL library at runtime. + /// In this case, you may prefer to directly use the `DynamicInstance` type. + #[cfg(feature=$version)] + pub unsafe trait $id $($deps)* { + $( + unsafe fn $name (&self, $($arg : $atype ),* ) -> $rtype ; + )* + } + }; + (@api_types ( ) $id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* } $($t_id:ident : $t_version:literal { $(fn $t_name:ident ($($t_arg:ident : $t_atype:ty ),* ) -> $t_rtype:ty ;)* })*) => { + #[cfg(feature="dynamic")] + $( + #[cfg(not(feature=$t_version))] + )* + #[cfg(feature=$version)] + /// Latest available EGL version. + pub type Latest = $id; + + $( + #[cfg(not(feature=$t_version))] + )* + #[cfg(feature=$version)] + /// Latest available EGL version. + pub const LATEST: Version = Version::$id; + + api!(@api_type ( ) $id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* }); + api!(@api_types ( $id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* } ) $($t_id : $t_version { $(fn $t_name ($($t_arg : $t_atype ),* ) -> $t_rtype ;)* })*); + }; + (@api_types ( $($pred:ident : $p_version:literal { $(fn $p_name:ident ($($p_arg:ident : $p_atype:ty ),* ) -> $p_rtype:ty ;)* })+ ) $id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* } $($t_id:ident : $t_version:literal { $(fn $t_name:ident ($($t_arg:ident : $t_atype:ty ),* ) -> $t_rtype:ty ;)* })*) => { + #[cfg(feature="dynamic")] + $( + #[cfg(not(feature=$t_version))] + )* + #[cfg(feature=$version)] + /// Latest available EGL version. + pub type Latest = $id; + + $( + #[cfg(not(feature=$t_version))] + )* + #[cfg(feature=$version)] + /// Latest available EGL version. + pub const LATEST: Version = Version::$id; + + api!(@api_type ( $($pred : $p_version { $(fn $p_name ($($p_arg : $p_atype ),* ) -> $p_rtype ;)* })* ) $id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* }); + api!(@api_types ( $($pred : $p_version { $(fn $p_name ($($p_arg : $p_atype ),* ) -> $p_rtype ;)* })* $id : $version { $(fn $name ($($arg : $atype ),* ) -> $rtype ;)* } ) $($t_id : $t_version { $(fn $t_name ($($t_arg : $t_atype ),* ) -> $t_rtype ;)* })*); + }; + (@api_types ( $($pred:ident : $p_version:literal { $(fn $p_name:ident ($($p_arg:ident : $p_atype:ty ),* ) -> $p_rtype:ty ;)* })+ ) ) => { + #[cfg(feature="dynamic")] + #[cfg(feature="1_0")] + /// Alias for dynamically linked instances with the latest handled version of EGL. + pub type DynamicInstance = Instance>; + + #[cfg(feature="dynamic")] + #[cfg(feature="1_0")] + impl DynamicInstance { + #[inline(always)] + /// Create an EGL instance by finding and loading a dynamic library with the given filename. + /// + /// See [`Library::new`](libloading::Library::new) + /// for more details on how the `filename` argument is used. + /// + /// On Linux plateforms, the library is loaded with the `RTLD_NODELETE` flag. + /// See [#14](https://github.com/timothee-haudebourg/khronos-egl/issues/14) for more details. + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the input library complies to the EGL API. + pub unsafe fn load_from_filename>(filename: P) -> Result, libloading::Error> { + #[cfg(target_os = "linux")] + let lib: libloading::Library = { + // On Linux, load library with `RTLD_NOW | RTLD_NODELETE` to fix a SIGSEGV + // See https://github.com/timothee-haudebourg/khronos-egl/issues/14 for more details. + libloading::os::unix::Library::open(Some(filename), 0x2 | 0x1000)?.into() + }; + #[cfg(not(target_os = "linux"))] + let lib = libloading::Library::new(filename)?; + Self::load_from(lib) + } + + #[inline(always)] + /// Create an EGL instance by finding and loading the `libEGL.so.1` or `libEGL.so` library. + /// + /// This is equivalent to `DynamicInstance::load_from_filename("libEGL.so.1")`. + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the found library complies to the EGL API. + pub unsafe fn load() -> Result, libloading::Error> { + Self::load_from_filename("libEGL.so.1").or(Self::load_from_filename("libEGL.so")) + } + } + }; + (@api_type ( $($pred:ident : $p_version:literal { $(fn $p_name:ident ($($p_arg:ident : $p_atype:ty ),* ) -> $p_rtype:ty ;)* })* ) $id:ident : $version:literal { $(fn $name:ident ($($arg:ident : $atype:ty ),* ) -> $rtype:ty ;)* }) => { + #[cfg(feature="static")] + #[cfg(feature=$version)] + unsafe impl api::$id for Static { + $( + #[inline(always)] + unsafe fn $name(&self, $($arg : $atype),*) -> $rtype { + ffi::$name($($arg),*) + } + )* + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + /// EGL version type. + /// + /// Used by [`Dynamic`] to statically know the EGL API version provided by the library. + pub struct $id; + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl $id { + #[allow(unused_variables)] + unsafe fn load_from>(raw: &mut RawDynamic) -> Result<(), libloading::Error> { + let lib = raw.lib.borrow(); + + $( + let name = stringify!($name).as_bytes(); + let symbol = lib.get:: $rtype>(name)?; + #[cfg(unix)] + let ptr = (&symbol.into_raw().into_raw()) as *const *mut _ as *const unsafe extern "system" fn($($atype ),*) -> $rtype; + #[cfg(windows)] + let ptr = (&symbol.into_raw().into_raw()) as *const _ as *const unsafe extern "system" fn($($atype ),*) -> $rtype; + assert!(!ptr.is_null()); + raw.$name = std::mem::MaybeUninit::new(*ptr); + )* + + Ok(()) + } + } + + $( + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + unsafe impl> api::$pred for Dynamic { + $( + #[inline(always)] + unsafe fn $p_name(&self, $($p_arg : $p_atype),*) -> $p_rtype { + (self.raw.$p_name.assume_init())($($p_arg),*) + } + )* + } + )* + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + unsafe impl> api::$id for Dynamic { + $( + #[inline(always)] + unsafe fn $name(&self, $($arg : $atype),*) -> $rtype { + (self.raw.$name.assume_init())($($arg),*) + } + )* + } + + $( + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> TryFrom> for Dynamic { + type Error = Dynamic; + + fn try_from(other: Dynamic) -> Result> { + if other.version() >= Version::$id { + Ok(Dynamic { + raw: other.raw, + _api_version: std::marker::PhantomData + }) + } else { + Err(other) + } + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> From> for Dynamic { + fn from(other: Dynamic) -> Self { + Dynamic { + raw: other.raw, + _api_version: std::marker::PhantomData + } + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> AsRef> for Dynamic { + fn as_ref(&self) -> &Dynamic { + unsafe { std::mem::transmute(self) } // this is safe because both types have the same repr. + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> Downcast> for Dynamic { + fn downcast(&self) -> &Dynamic { + unsafe { std::mem::transmute(self) } // this is safe because both types have the same repr. + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> Downcast>> for Instance> { + fn downcast(&self) -> &Instance> { + unsafe { std::mem::transmute(self) } // this is safe because both types have the same repr. + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> Upcast> for Dynamic { + fn upcast(&self) -> Option<&Dynamic> { + if self.version() >= Version::$id { + Some(unsafe { std::mem::transmute(self) }) // this is safe because both types have the same repr. + } else { + None + } + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> Upcast>> for Instance> { + fn upcast(&self) -> Option<&Instance>> { + if self.version() >= Version::$id { + Some(unsafe { std::mem::transmute(self) }) // this is safe because both types have the same repr. + } else { + None + } + } + } + )* + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> Dynamic { + #[inline] + /// Load the EGL API symbols from the given library. + /// + /// The second `Dynamic` type parameter gives the EGL API version expected to be provided by the library. + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the input library complies to the EGL API. + pub unsafe fn load_required(lib: L) -> Result, LoadError> { + match Dynamic::::load_from(lib) { + Ok(dynamic) => { + let provided = dynamic.version(); + match dynamic.try_into() { + Ok(t) => Ok(t), + Err(_) => Err(LoadError::InvalidVersion { + provided, + required: Version::$id + }) + } + }, + Err(e) => Err(LoadError::Library(e)) + } + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl> Instance> { + #[inline(always)] + /// Create an EGL instance using the symbols provided by the given library. + /// This function fails if the EGL library does not provide the minimum required version given by the type parameter. + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the input library complies to the EGL API. + pub unsafe fn load_required_from(lib: L) -> Result>, LoadError> { + Ok(Instance::new(Dynamic::::load_required(lib)?)) + } + } + + #[cfg(feature="dynamic")] + #[cfg(feature=$version)] + impl DynamicInstance<$id> { + #[inline(always)] + /// Create an EGL instance by finding and loading a dynamic library with the given filename. + /// This function fails if the EGL library does not provide the minimum required version given by the type parameter. + /// + /// See [`Library::new`](libloading::Library::new) + /// for more details on how the `filename` argument is used. + /// + /// On Linux plateforms, the library is loaded with the `RTLD_NODELETE` flag. + /// See [#14](https://github.com/timothee-haudebourg/khronos-egl/issues/14) for more details. + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the input library complies to the EGL API. + pub unsafe fn load_required_from_filename>(filename: P) -> Result, LoadError> { + #[cfg(target_os = "linux")] + let lib: libloading::Library = { + // On Linux, load library with `RTLD_NOW | RTLD_NODELETE` to fix a SIGSEGV + // See https://github.com/timothee-haudebourg/khronos-egl/issues/14 for more details. + libloading::os::unix::Library::open(Some(filename), 0x2 | 0x1000).map_err(LoadError::Library)?.into() + }; + #[cfg(not(target_os = "linux"))] + let lib = libloading::Library::new(filename).map_err(LoadError::Library)?; + Self::load_required_from(lib) + } + + #[inline(always)] + /// Create an EGL instance by finding and loading the `libEGL.so.1` or `libEGL.so` library. + /// This function fails if the EGL library does not provide the minimum required version given by the type parameter. + /// + /// This is equivalent to `DynamicInstance::load_required_from_filename("libEGL.so.1")`. + /// + /// ## Safety + /// This is fundamentally unsafe since there are no guaranties the found library complies to the EGL API. + pub unsafe fn load_required() -> Result, LoadError> { + Self::load_required_from_filename("libEGL.so.1").or(Self::load_required_from_filename("libEGL.so")) + } + } + } +} + +api! { + EGL1_0 : "1_0" { + fn eglChooseConfig( + display: EGLDisplay, + attrib_list: *const Int, + configs: *mut EGLConfig, + config_size: Int, + num_config: *mut Int + ) -> Boolean; + fn eglCopyBuffers( + display: EGLDisplay, + surface: EGLSurface, + target: NativePixmapType + ) -> Boolean; + fn eglCreateContext( + display: EGLDisplay, + config: EGLConfig, + share_context: EGLContext, + attrib_list: *const Int + ) -> EGLContext; + fn eglCreatePbufferSurface( + display: EGLDisplay, + config: EGLConfig, + attrib_list: *const Int + ) -> EGLSurface; + fn eglCreatePixmapSurface( + display: EGLDisplay, + config: EGLConfig, + pixmap: NativePixmapType, + attrib_list: *const Int + ) -> EGLSurface; + fn eglCreateWindowSurface( + display: EGLDisplay, + config: EGLConfig, + win: NativeWindowType, + attrib_list: *const Int + ) -> EGLSurface; + fn eglDestroyContext(display: EGLDisplay, ctx: EGLContext) -> Boolean; + fn eglDestroySurface(display: EGLDisplay, surface: EGLSurface) -> Boolean; + fn eglGetConfigAttrib( + display: EGLDisplay, + config: EGLConfig, + attribute: Int, + value: *mut Int + ) -> Boolean; + fn eglGetConfigs( + display: EGLDisplay, + configs: *mut EGLConfig, + config_size: Int, + num_config: *mut Int + ) -> Boolean; + fn eglGetCurrentDisplay() -> EGLDisplay; + fn eglGetCurrentSurface(readdraw: Int) -> EGLSurface; + fn eglGetDisplay(display_id: NativeDisplayType) -> EGLDisplay; + fn eglGetError() -> Int; + fn eglGetProcAddress(procname: *const c_char) -> extern "system" fn(); + fn eglInitialize(display: EGLDisplay, major: *mut Int, minor: *mut Int) -> Boolean; + fn eglMakeCurrent( + display: EGLDisplay, + draw: EGLSurface, + read: EGLSurface, + ctx: EGLContext + ) -> Boolean; + fn eglQueryContext( + display: EGLDisplay, + ctx: EGLContext, + attribute: Int, + value: *mut Int + ) -> Boolean; + fn eglQueryString(display: EGLDisplay, name: Int) -> *const c_char; + fn eglQuerySurface( + display: EGLDisplay, + surface: EGLSurface, + attribute: Int, + value: *mut Int + ) -> Boolean; + fn eglSwapBuffers(display: EGLDisplay, surface: EGLSurface) -> Boolean; + fn eglTerminate(display: EGLDisplay) -> Boolean; + fn eglWaitGL() -> Boolean; + fn eglWaitNative(engine: Int) -> Boolean; + }, + + EGL1_1 : "1_1" { + fn eglBindTexImage(display: EGLDisplay, surface: EGLSurface, buffer: Int) -> Boolean; + fn eglReleaseTexImage(display: EGLDisplay, surface: EGLSurface, buffer: Int) -> Boolean; + fn eglSurfaceAttrib( + display: EGLDisplay, + surface: EGLSurface, + attribute: Int, + value: Int + ) -> Boolean; + fn eglSwapInterval(display: EGLDisplay, interval: Int) -> Boolean; + }, + + EGL1_2 : "1_2" { + fn eglBindAPI(api: Enum) -> Boolean; + fn eglQueryAPI() -> Enum; + fn eglCreatePbufferFromClientBuffer( + display: EGLDisplay, + buftype: Enum, + buffer: EGLClientBuffer, + config: EGLConfig, + attrib_list: *const Int + ) -> EGLSurface; + fn eglReleaseThread() -> Boolean; + fn eglWaitClient() -> Boolean; + }, + + EGL1_3 : "1_3" { + // nothing. + }, + + EGL1_4 : "1_4" { + fn eglGetCurrentContext() -> EGLContext; + }, + + EGL1_5 : "1_5" { + fn eglCreateSync(display: EGLDisplay, type_: Enum, attrib_list: *const Attrib) -> EGLSync; + fn eglDestroySync(display: EGLDisplay, sync: EGLSync) -> Boolean; + fn eglClientWaitSync(display: EGLDisplay, sync: EGLSync, flags: Int, timeout: Time) -> Int; + fn eglGetSyncAttrib( + display: EGLDisplay, + sync: EGLSync, + attribute: Int, + value: *mut Attrib + ) -> Boolean; + fn eglCreateImage( + display: EGLDisplay, + ctx: EGLContext, + target: Enum, + buffer: EGLClientBuffer, + attrib_list: *const Attrib + ) -> EGLImage; + fn eglDestroyImage(display: EGLDisplay, image: EGLImage) -> Boolean; + fn eglGetPlatformDisplay( + platform: Enum, + native_display: *mut c_void, + attrib_list: *const Attrib + ) -> EGLDisplay; + fn eglCreatePlatformWindowSurface( + display: EGLDisplay, + config: EGLConfig, + native_window: *mut c_void, + attrib_list: *const Attrib + ) -> EGLSurface; + fn eglCreatePlatformPixmapSurface( + display: EGLDisplay, + config: EGLConfig, + native_pixmap: *mut c_void, + attrib_list: *const Attrib + ) -> EGLSurface; + fn eglWaitSync(display: EGLDisplay, sync: EGLSync, flags: Int) -> Boolean; + } +} -- cgit v1.2.3