Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support OpenGL on EGL and allow headless context creation #3110

Merged
merged 2 commits into from
Jun 23, 2023

Conversation

issam3105
Copy link
Contributor

@issam3105 issam3105 commented Jun 15, 2023

I require support for headless rendering in order to conduct graphic unit tests on Ubuntu headless machines.
This solution works on both headless and non-headless machines, regardless of whether they have a GPU or not.
In cases where a GPU is not available, it should utilize the Mesa LLVMpipe software rendering approach along with the xvfb-run command.

|| BX_PLATFORM_RPI \
|| BX_PLATFORM_WINDOWS \
) )
#ifndef BGFX_USE_EGL
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this wrapped into ifndef? User should not be providing this by compiler options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, the logic was to use EGL when using GLES and use the native backend (such as GLX, WGL, etc.) when using GL. Now, allowing EGL for GL as well introduces a choice. On platforms that support both the native backend and EGL, there needs to be a way to configure which one to use at compile time.

Alternatively, we could consider using EGL consistently across all platforms. However, we might not be ready to replace the other backends systematically, so having the ability to choose between the original native backend and EGL
(i compile with BGFX_USE_EGL=1 BGFX_USE_GLX=0)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes it too complicated... I think EGL should stay GLES only.

Can you focus your PR only on: "allow headless context creation"?

Copy link
Contributor

@goodartistscopy goodartistscopy Jun 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, I'm working with @issam3105 on this.

As said, our context is CI and headless* linux servers, the main goal is to get away from GLX (can't be headless). Linux GLES support seems good, so GL is indeed not actually very important.
We'll get back to the drawing board on the PR to just focus on the headless part.

(*headless meaning no display server; might have a GPU still, but sometimes not even, using mesa sw rendering)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(*headless meaning no display server; might have a GPU still, but sometimes not even, using mesa sw rendering)

Yeah. Headless is useful.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll create a new PR with what I've been working on. Feel free to shoot it down.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sjnewbury EGL instead of GLX is fine. Just focus your PR to have minimal changes to achieve that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkaradzic Okay, I'll create a PR with just the EGL by default changes and separate the work to get Wayland working to a different PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once EGL is used, bgfx doesn't have to care what's behind it: thanks to EGL external platform system, one can use either display server specific surfaces (x11/wayland window handles) or "unmapped" GBM windows (as the name does not imply, those are offscreen).
Unfortunately, nvidia's GBM support is still sketchy, one must use pbuffers on the "device platform" instead. I'd like to come up with a better way to pass that information to bgfx. This patch assumes that if the window handle is NULL, a pbuffer is created, but there is no interface to define it's size (I believe it'll default to 0x0).

Copy link
Contributor

@goodartistscopy goodartistscopy Jun 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkaradzic

But I don't have Wayland on Linux Mint / Cinnamon (and I don't intend to switch from it).

would you mind sharing the output of 'eglinfo' on your system ?

@sjnewbury
Copy link

@issam3105, @goodartistscopy do you mind if I merge your changes into my PR? If that's okay, I'll rebase your commit on top of mine.

@issam3105
Copy link
Contributor Author

issam3105 commented Jun 19, 2023

@issam3105, @goodartistscopy do you mind if I merge your changes into my PR? If that's okay, I'll rebase your commit on top of mine.

@sjnewbury Sure, we don't mind. If there are going to be a lot of changes at once in your PR, you can just do the "EGL by default" part. Once your PR is merged, I will rebase this PR to include the latest changes.

@issam3105 issam3105 force-pushed the fix_egl branch 2 times, most recently from 64632d9 to a0c085e Compare June 19, 2023 15:15
@issam3105
Copy link
Contributor Author

@bkaradzic to streamline the process, I have made the necessary changes in this PR to incorporate the "headless" aspect. Once @sjnewbury's PR to use EGL by default is merged, I will submit another PR to support OpenGL.

if(NULL == _nwh)
{
// Create an EGL pbuffer surface
m_surface = eglCreatePbufferSurface(m_display, _config, NULL);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't import this function for BGFX_USE_GL_DYNAMIC_LIB case.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also ideally if we can skip any surface, since it never will be visible, nor can be accessed in any other way, it would be great to skip it.

If skipping is not possible it should be minimal dimensions.

Copy link
Contributor

@goodartistscopy goodartistscopy Jun 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the EGL_KHR_surfaceless_context extension is supported, it's indeed possible to have m_surface = EGL_NO_SURFACE.

However the context is now without a default framebuffer, which will break apps that don't setup FBOs or readback from the default one. Keeping those functional is interesting in a CI context.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However the context is now without a default framebuffer, which will break apps that don't setup FBOs or readback from the default one. Keeping those functional is interesting in a CI context.

Actually that's good point, there should be some way to detect/validate that there is headless setup, and that user should not write into backbuffer.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some users are morons (based on years of experience with this project), so they will setup headless and then expect they see something... Therefore assert should give them a hint that headless means no backbuffer / default window.


EGLint attrs[] =
{
EGL_RENDERABLE_TYPE, (gles >= 30) ? EGL_OPENGL_ES3_BIT_KHR : EGL_OPENGL_ES2_BIT,

EGL_SURFACE_TYPE, headless ? EGL_PBUFFER_BIT : EGL_WINDOW_BIT,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it possible to be surfaceless in headless mode?

Copy link
Contributor

@goodartistscopy goodartistscopy Jun 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you can be surfaceless in headless or non headless, if the selected platform exposes the functionality. (but see my comment above)

@bkaradzic
Copy link
Owner

Also if you have instructions how should I test EGL (regular and headless) on Linux. That would help me determine if GLX is still needed.

@goodartistscopy
Copy link
Contributor

goodartistscopy commented Jun 23, 2023

My EGL experiments so far have included:

  • My Fedora workstation running the proprietary nvidia drivers
  • 2 local Ubuntu Server VMs (one 20.04 LTS, one 22.04 LTS)
  • 2 EC2 instances both running ubuntu 20.04. One with an nvidia GPU and one without (emulates a dummy Cirrus video adapter though).

Ubuntu Server does not ship any display manager by default.

I use QEMU for the local VM (via the "Gnome Boxes" software), and I can tweak the configuration file to change the display adapter that is exposed to the VM (see here). When set to vga=none, the VM is truly headless, and can only be accessed through ssh.

EGL (1.5 or 1.4 + EGL_KHR_platform_base) exposes different native platforms through which to retrieve a display connection and associate native surfaces to contexts. On Linux those are:

  • GBM: this is MESA's infrastructure, also recently supported by nvidia, that allows to create surfaces not related to X11 or Wayland. Even though they are offscreen, they are labelled "windows" [1]. They can be mapped to display through the DRM/KMS kernel API.
  • X11 / Wayland: this uses native surfaces and connections to the respective display server (similar to GLX)
  • surfaceless: this is a platform with no native surfaces (it exposes only pbuffers). AFAIU except from this distinction it's very similar to GBM in practice. [2]
  • device: this platform allows to enumerate all the devices in the system and use a particular one (similarly to what Vulkan can do). Mesa inserts into the list a "software device" that will use one of their software rasterizer (llvmpipe/swrast).

When using the normal EGL function to create surfaces, an imlementation defined platform is used, but with MESA it can be controlled with the EGL_PLATFORM environment variable (e.g. EGL_PLATFORM=surfaceless).

On a given system this information can be retrieved with the eglinfo command, but I strongly suggest building it from the sources, because the one from the distro packages is outdated and does not always give complete information. It is part of the mesa/demos project.

Even on a headless system MESA requires a minimal DRM setup to be able to initialize the GBM platform. That is a device like /dev/dri/card0 must exist. I found that using the vkms module (sudo modprobe vkms) is enough to populate this (might also need to add yourself to the video group).

[1] strangely on nvidia GBM exposes pbuffers as well
[2] I initially confused the EGL_MESA_platform_surfaceless platform with the EGL_KHR_surfaceless_context extension that allows to make a context active without binding it to any surface (eglMakeCurrent(ctx, EGL_NO_SURFACE, EGL_SURFACE, EGL_NO_CONTEXT) is allowed). The latter can theoretically be available on any platform.

@issam3105
Copy link
Contributor Author

issam3105 commented Jun 23, 2023

Also if you have instructions how should I test EGL (regular and headless) on Linux. That would help me determine if GLX is still needed.

In order to perform EGL testing on Linux, the following steps are required:

  • Compile the code with BGFX_CONFIG_RENDERER_OPENGLES=30 flag.
  • In the examples, set the following parameters in the bgfx::Init structure:
    init.type = bgfx::RendererType::OpenGLES;

For the headless mode you need to

  • Modify the entry.h file by removing the window-related code.
  • In the examples
    init.platformData.nwh = nullptr;
    init.platformData.ndt = nullptr;
  • ReadBack the FB or the buffer and save it to a png

The headless part of the code has not been tested with the bgfx examples.

@bkaradzic
Copy link
Owner

Compile the code with BGFX_CONFIG_RENDERER_OPENGLES=30 flag.

Ah, I was thinking OpenGL via EGL.

@issam3105
Copy link
Contributor Author

issam3105 commented Jun 23, 2023

Ah, I was thinking OpenGL via EGL.

I am currently awaiting the PR from @sjnewbury, which aims to incorporate EGL instead of GLX for OpenGL support. If the PR does not get merged, I will need to modify the render_gl.h file to forcefully enable the use of EGL by setting BGFX_USE_EGL.
I made specific modifications to this PR that focus only on the headless functionality after your comment

Can you focus your PR only on: "allow headless context creation"?

@bkaradzic
Copy link
Owner

So headless EGL looks fine.

@goodartistscopy if you have time you should add support for https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_surfaceless_context.txt.

@bkaradzic bkaradzic merged commit 47345a3 into bkaradzic:master Jun 23, 2023
@bkaradzic
Copy link
Owner

@goodartistscopy I deleted GL support for Apple's platforms, since it's deprecated forever already. This will simplify switch to EGL.

mipek pushed a commit to mipek/bgfx that referenced this pull request Mar 2, 2024
…3110)

* allow headless context creation using EGL

* Fixed dynamic lib import

---------

Co-authored-by: Dahmen issam <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants