https://github.com/erlangsters/egl-1.5
EGL 1.5 binding for the BEAM (Erlang and Elixir).
https://github.com/erlangsters/egl-1.5
beam binding egl elixir erlang erlangsters
Last synced: about 2 months ago
JSON representation
EGL 1.5 binding for the BEAM (Erlang and Elixir).
- Host: GitHub
- URL: https://github.com/erlangsters/egl-1.5
- Owner: erlangsters
- License: mit
- Created: 2024-09-24T16:35:23.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2025-08-20T09:35:29.000Z (10 months ago)
- Last Synced: 2025-08-20T11:30:49.385Z (10 months ago)
- Topics: beam, binding, egl, elixir, erlang, erlangsters
- Language: Erlang
- Homepage: https://about.erlangsters.org
- Size: 58.6 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# EGL 1.5 binding for the BEAM
:construction: It's still in development and a first beta version will be
available shortly. The master branch will be rewound!
[](https://github.com/erlangsters/egl-1.5)



[](https://github.com/erlangsters/egl-1.5/actions/workflows/workflow.yml)
[](http://erlangsters.github.io/egl-1.5/)
The binding of [EGL 1.5](https://registry.khronos.org/EGL/sdk/docs/man/) for the
Erlang and Elixir programming language. It comes with a set of OpenGL bindings
which are designed to work with it.
- OpenGL: [3.3](https://github.com/erlangsters/opengl-3.3) |
[4.1](https://github.com/erlangsters/opengl-4.1) |
[4.6](https://github.com/erlangsters/opengl-4.6)
- OpenGL ES: [2.0](https://github.com/erlangsters/opengl-es-2.0) |
[3.0](https://github.com/erlangsters/opengl-es-3.0) |
[3.1](https://github.com/erlangsters/opengl-es-3.1) |
[3.2](https://github.com/erlangsters/opengl-es-3.2)
Unlike the OpenGL bindings, this binding is not generated and written by hand
instead. The OpenGL bindings are generated by the OpenGL binding
[generator](https://github.com/erlangsters/opengl-x.y-generator).
> Note that EGL version 1.5 is the last and final version. It's the reason why
> the 1.5 suffix is added to the repository name. In fact, no binding for
> version 1.4 and earlier ever existed. The API of this binding is set in
> stone.
Any OpenGL developer knows that the API is not thread-safe and an active OpenGL
context must be active. Given the BEAM executes code on arbitrary OS threads,
read how the EGL binding solves [thread safety](#threads-safety).
Also, you will typically use ANGLE on macOS and Windows.
Written by the Erlangsters [community](https://about.erlangsters.org/) and
released under the MIT [license](https://opensource.org/license/mit).
## Getting started
It would not make sense to use EGL without OpenGL, therefore, first pick an
OpenGL binding to work with, and update `rebar.config` accordingly.
```erlang
{deps, [
{egl, {git, "https://github.com/erlangsters/egl-1.5.git", {tag, "master"}}}
{gl, {git, "https://github.com/erlangsters/opengl-4.6.git", {tag, "master"}}}
]}.
```
> Note that it will trigger the compilation of NIF modules which requires you
> to have a compiler and the EGL and OpenGL libraries installed on your system.
> It's heavily platform-dependent and therefore instructions cannot be provided
> easily, however, the [Github workflow](.github/workflows/workflow.yml) should
> be a good starting point.
> If you're using macOS or Windows, you will want to use [ANGLE](https://github.com/google/angle) which you're placing in discoverable paths. XXX: Update Makefile to use env vars.
Then use the following snippet of code to get you started.
```erlang
Display = egl:get_display(default_display),
{ok, _} = egl:initialize(Display),
egl:bind_api(opengl_api).
ConfigAttribs = [
{surface_type, [window_bit]},
{renderable_type, [opengl_bit]}
],
{ok, Configs} = egl:choose_config(Display, ConfigAttribs),
ContextAttribs = [
{context_major_version, 3}
],
{ok, Context} = egl:create_context(Display, Config, no_context, ContextAttribs),
egl:make_current(Display, no_surface, no_surface, Context),
{ok, Version} = gl:get_string(version).
io:format("OpenGL version: ~s~n", [Version]).
```
> The API is unsafe meaning that it does not guard against mis-use of the EGL
> API. For instance, each EGL context that are created should be destroyed
> only once.
From there, you will need two things. First, understanding the
[API mapping](#api-mapping) (to know how a piece of C code using EGL translates
to Erlang or Elixir), then understanding [thread-safety](#threads-safety) (how
the concept of OpenGL contexts apply at the BEAM level).
Additionally, for much more advanced use, you may want to learn how to
[interpolate](#interpolation) with the binding to provide a native window
handle, or execute batches of OpenGL commands more efficiently.
## API mapping
This is a binding to a C API that has been slightly adapted to feel more
natural when used in Erlang and Elixir.
However, rest assured, your existing EGL knowledge applies entirely because the
changes are minor and trivial. With the API reference, you should have
everything you need.
If you run into difficulties, check the API mapping document for details on how
functions and types are mapped.
Additionally, the test suite in this repository serves as a useful reference
for practical examples of EGL functions in action.
## Threads safety
If you're an OpenGL developer, it should come without a surprise that all
OpenGL commands operate in a context. The OpenGL context must be bound (or
active) in the current OS thread before a command can be executed. Furthermore,
you also know that there can only be one active context per OS thread at a
time, and conversely, binding a context can potentially make an active context
on another OS thread inactive.
The key word is **OS thread**.
Now, as an Erlang or Elixir developer, you also know that the BEAM does not
expose OS threads directly and instead layer on top of it. At the BEAM level we
work with a higher-level concept called BEAM processes, and all code is
executed on whichever OS thread the BEAM deems appropriate.
The key word is **BEAM process**.
It's a conundrum that seems to make working with OpenGL in the BEAM impossible.
Fortunately, there is a solution. To solve this problem, the EGL binding spawns
an additional OS thread per BEAM process that has an active OpenGL context. The
OpenGL commands are then scheduled to run on those OS threads.
Because it effectively map BEAM processes to OS threads, the result is that you
can work **exactly** like if a BEAM process was equal to a OS thread.
It's as simple as that.
It also means that there is no magic. All thread-safety concerns (and their
associated complexity) still apply in your code. The only difference is that
it's easier to write concurrent code in Erlang and Elixir.
For a more comprehensive explanation of the employed technique to solve the
thread-safety, consult this [document](/docs/thread-safety.md).
## NIF interpolation
The EGL binding is responsible for re-arranging the execution of OpenGL
commands in correct OS threads in order to make OpenGL on the BEAM even
possible. In fact, the OpenGL bindings rely directly on the EGL binding to do
that job.
However, if you need to execute OpenGL commands yourself, perhaps for
optimization purpose, such as sending them in batches, you can use the C API of
the EGL binding to do it. Just like the OpenGL bindings do. This [document](/docs/native-window-handle.md)
should tell you everything you need to know.
Also, if you happen to be writing some sort of low-level platform-specific
NIF modules that need to work with the EGL binding, this
[document](/docs/opengl-context-executor.md) will teach you how to do it.