Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/khronos-egl/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/khronos-egl/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"CHANGELOG.md":"72e6058dddb110c7e70fb26e2f370b9958a5e03efdea048f62fb338807fbe7de","Cargo.lock":"99216196a89fb759029d053bdc1c32b4423295793a0f4dc5f4218626e7a29c21","Cargo.toml":"efbaf25a93c000f823abe977e272de2d43a35b1cfcbf0fc03d2df00631251871","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"613a096d04cd5ae2ab67acd09298ea30c7d7e89eabcc817249ea9b88f88470ae","build.rs":"54e6dd50d7b9f189b687b5f39b58131090004130a5d054614d3304a3912af96a","examples/load-minimal.rs":"a9bd9a34e2a30d189f878c5c2c1111e76c2fda70b10c284cf731c8cbfc921891","examples/wayland-dynamic.rs":"a7b32ca80fd124f4cf8cb7e6f2de6b0ca277f6619a5376b12e904c2ec1cc5a06","examples/wayland-static.rs":"b3f53b9ae1e5e639c9ee15485d16bd718cfd40f70635166318a224e337cee577","shell-wayland.nix":"ee9753492f0a7466b59ec23dff1c6d5c7a8178ec3dc1dd488964f1cb4859c44b","shell.nix":"1089d919bcbdf4afcd6f4403cfbe08a59253215398fdde34e6a4c62f70129f47","src/lib.rs":"7287d03b23a710f47f8cdaf2a82ed8a1c40af10737fb5a972a5fdf0600ef0b47"},"package":"8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"}
|
||||
58
third-party/vendor/khronos-egl/CHANGELOG.md
vendored
Normal file
58
third-party/vendor/khronos-egl/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# 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).
|
||||
|
||||
## [Unpublished]
|
||||
## [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<Dynamic<libloading::Library>>` 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<Display>` instead of `Display` in `query_string`.
|
||||
- More flexible dependencies versions.
|
||||
275
third-party/vendor/khronos-egl/Cargo.lock
generated
vendored
Normal file
275
third-party/vendor/khronos-egl/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
# 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 = "4.1.0"
|
||||
dependencies = [
|
||||
"gl",
|
||||
"libc",
|
||||
"libloading 0.7.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.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[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 = "xml-rs"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
||||
68
third-party/vendor/khronos-egl/Cargo.toml
vendored
Normal file
68
third-party/vendor/khronos-egl/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "khronos-egl"
|
||||
version = "4.1.0"
|
||||
authors = ["Timothée Haudebourg <author@haudebourg.net>", "Sean Kerr <sean@metatomic.io>"]
|
||||
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.7"
|
||||
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"]
|
||||
201
third-party/vendor/khronos-egl/LICENSE-APACHE
vendored
Normal file
201
third-party/vendor/khronos-egl/LICENSE-APACHE
vendored
Normal file
|
|
@ -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.
|
||||
23
third-party/vendor/khronos-egl/LICENSE-MIT
vendored
Normal file
23
third-party/vendor/khronos-egl/LICENSE-MIT
vendored
Normal file
|
|
@ -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.
|
||||
165
third-party/vendor/khronos-egl/README.md
vendored
Normal file
165
third-party/vendor/khronos-egl/README.md
vendored
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
# Rust bindings for EGL
|
||||
|
||||
<table><tr>
|
||||
<td><a href="https://docs.rs/khronos-egl">Documentation</a></td>
|
||||
<td><a href="https://crates.io/crates/khronos-egl">Crate informations</a></td>
|
||||
<td><a href="https://github.com/timothee-haudebourg/khronos-egl">Repository</a></td>
|
||||
</tr></table>
|
||||
|
||||
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<Dynamic<libloading::Library>>` as follows:
|
||||
|
||||
```rust
|
||||
let lib = libloading::Library::new("libEGL.so.1").expect("unable to find libEGL.so.1");
|
||||
let egl = unsafe { egl::DynamicInstance::<egl::EGL1_4>::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<egl::EGL1_4>`, 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::<egl::EGL1_5>() {
|
||||
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.
|
||||
12
third-party/vendor/khronos-egl/build.rs
vendored
Normal file
12
third-party/vendor/khronos-egl/build.rs
vendored
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
43
third-party/vendor/khronos-egl/examples/load-minimal.rs
vendored
Normal file
43
third-party/vendor/khronos-egl/examples/load-minimal.rs
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
extern crate gl;
|
||||
extern crate khronos_egl as egl;
|
||||
extern crate libloading;
|
||||
|
||||
use std::sync::Arc;
|
||||
use egl::{
|
||||
EGL1_2,
|
||||
EGL1_4
|
||||
};
|
||||
|
||||
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::<EGL1_2>() {
|
||||
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::<EGL1_4>() {
|
||||
Some(egl1_4) => {
|
||||
foo_with_1_4(egl1_4)
|
||||
},
|
||||
None => {
|
||||
foo_without_1_4(&minimal_egl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn foo_with_1_4<V: egl::api::EGL1_4>(_egl: &egl::Instance<V>) {
|
||||
println!("with 1.4");
|
||||
// do something that requires at least EGL 1.4.
|
||||
}
|
||||
|
||||
fn foo_without_1_4<V>(_egl: &egl::Instance<V>) {
|
||||
println!("without 1.4");
|
||||
// do something without any specific EGL version (other that 1.0).
|
||||
}
|
||||
348
third-party/vendor/khronos-egl/examples/wayland-dynamic.rs
vendored
Normal file
348
third-party/vendor/khronos-egl/examples/wayland-dynamic.rs
vendored
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
extern crate gl;
|
||||
extern crate khronos_egl as egl;
|
||||
extern crate wayland_client;
|
||||
extern crate wayland_egl;
|
||||
extern crate wayland_protocols;
|
||||
extern crate libloading;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::ptr;
|
||||
use std::ffi::CStr;
|
||||
use gl::types::{GLint, GLuint, GLchar, GLenum, GLboolean, GLvoid};
|
||||
|
||||
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<XdgWmBase>, 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<WlCompositor>,
|
||||
xdg: Main<XdgWmBase>,
|
||||
}
|
||||
|
||||
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<WlCompositor> = globals.instantiate_exact(1).unwrap();
|
||||
|
||||
// Xdg protocol.
|
||||
let xdg: Main<XdgWmBase> = 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 = 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<WlSurface>,
|
||||
initialized: AtomicBool
|
||||
}
|
||||
|
||||
fn create_surface(
|
||||
egl: &Arc<egl::DynamicInstance>,
|
||||
ctx: &DisplayConnection,
|
||||
egl_display: egl::Display,
|
||||
egl_context: egl::Context,
|
||||
egl_config: egl::Config,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Arc<Surface> {
|
||||
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<XdgSurface>, 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::<egl::EGL1_5>::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");
|
||||
}
|
||||
}
|
||||
344
third-party/vendor/khronos-egl/examples/wayland-static.rs
vendored
Normal file
344
third-party/vendor/khronos-egl/examples/wayland-static.rs
vendored
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
extern crate gl;
|
||||
extern crate khronos_egl as egl;
|
||||
extern crate wayland_client;
|
||||
extern crate wayland_egl;
|
||||
extern crate wayland_protocols;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::ptr;
|
||||
use std::ffi::CStr;
|
||||
use gl::types::{GLint, GLuint, GLchar, GLenum, GLboolean, GLvoid};
|
||||
use egl::API as egl;
|
||||
|
||||
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<XdgWmBase>, 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<WlCompositor>,
|
||||
xdg: Main<XdgWmBase>,
|
||||
}
|
||||
|
||||
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<WlCompositor> = globals.instantiate_exact(1).unwrap();
|
||||
|
||||
// Xdg protocol.
|
||||
let xdg: Main<XdgWmBase> = 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 = 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<WlSurface>,
|
||||
initialized: AtomicBool
|
||||
}
|
||||
|
||||
fn create_surface(
|
||||
ctx: &DisplayConnection,
|
||||
egl_display: egl::Display,
|
||||
egl_context: egl::Context,
|
||||
egl_config: egl::Config,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Arc<Surface> {
|
||||
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<XdgSurface>, 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");
|
||||
}
|
||||
}
|
||||
11
third-party/vendor/khronos-egl/shell-wayland.nix
vendored
Normal file
11
third-party/vendor/khronos-egl/shell-wayland.nix
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.gcc
|
||||
pkgs.libGL
|
||||
pkgs.pkg-config
|
||||
pkgs.wayland
|
||||
];
|
||||
LD_LIBRARY_PATH="${pkgs.libGL}/lib";
|
||||
}
|
||||
10
third-party/vendor/khronos-egl/shell.nix
vendored
Normal file
10
third-party/vendor/khronos-egl/shell.nix
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.gcc
|
||||
pkgs.libGL
|
||||
pkgs.pkg-config
|
||||
];
|
||||
LD_LIBRARY_PATH="${pkgs.libGL}/lib";
|
||||
}
|
||||
2363
third-party/vendor/khronos-egl/src/lib.rs
vendored
Normal file
2363
third-party/vendor/khronos-egl/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue