I get error "libEGL warning: Not allowed to force software rendering when API explicitly selects a hardware device error".
I locate the error in the code below:
EGLDisplay display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[render_device], NULL);
// eglGetError() return EGL_SUCCESS
eglInitialize(display, &major, &minor); // this line failed and print the error information above
The computer is a server and has no display, does it matters? If so, how can I solve this and render images from meshes on a computer without display?
I am sure that libEGL exists on my computer and compatible to the gpu and driver. If replacing above code with:
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(...)
then everything goes fine. However the output implies that it links to a mesa implementation:
libEGL warning: DRI3: failed to query the version
libEGL warning: DRI2: failed to authenticate
Loaded EGL 1.4 after reload.
GL_VENDOR=VMware, Inc.
GL_RENDERER=llvmpipe (LLVM 10.0.0, 256 bits)
GL_VERSION=3.1 Mesa 20.0.8
GL_SHADING_LANGUAGE_VERSION=1.40
From the hint of error report, I guess the former version specifies a gpu to do the job while the latter one don't, but I want is to let gpu to render. How can I tell egl not to use software rendering?
// Copyright (c) 2020 NVIDIA Corporation. All rights reserved.
// This work is licensed under the NVIDIA Source Code License - Non-commercial. Full
// text can be found in LICENSE.md
//g++ glad/egl.c glad/gl.c egl.cpp -I glad -lpthread -ldl
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <glad/egl.h>
#include <glad/gl.h>
struct EGLInternalData2 {
bool m_isInitialized;
int m_windowWidth;
int m_windowHeight;
int m_renderDevice;
EGLBoolean success;
EGLint num_configs;
EGLConfig egl_config;
EGLSurface egl_surface;
EGLContext egl_context;
EGLDisplay egl_display;
EGLInternalData2()
: m_isInitialized(false),
m_windowWidth(0),
m_windowHeight(0) {}
};
int main(int argc, char ** argv){
int m_windowWidth;
int m_windowHeight;
int m_renderDevice;
EGLBoolean success;
EGLint num_configs;
EGLConfig egl_config;
EGLSurface egl_surface;
EGLContext egl_context;
EGLDisplay egl_display;
m_windowWidth = 256;
m_windowHeight = 256;
m_renderDevice = -1;
EGLint egl_config_attribs[] = {EGL_RED_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_DEPTH_SIZE,
8,
EGL_SURFACE_TYPE,
EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_BIT,
EGL_NONE};
EGLint egl_pbuffer_attribs[] = {
EGL_WIDTH, m_windowWidth, EGL_HEIGHT, m_windowHeight,
EGL_NONE,
};
EGLInternalData2* m_data = new EGLInternalData2();
// Load EGL functions
int egl_version = gladLoaderLoadEGL(NULL);
if(!egl_version) {
fprintf(stderr, "failed to EGL with glad.\n");
exit(EXIT_FAILURE);
};
// Query EGL Devices
const int max_devices = 32;
EGLDeviceEXT egl_devices[max_devices];
EGLint num_devices = 0;
EGLint egl_error = eglGetError();
if (!eglQueryDevicesEXT(max_devices, egl_devices, &num_devices) ||
egl_error != EGL_SUCCESS) {
printf("eglQueryDevicesEXT Failed.\n");
m_data->egl_display = EGL_NO_DISPLAY;
}
printf("number of devices found %d\n", num_devices);
m_data->m_renderDevice = atoi(argv[1]);
// Set display
EGLDisplay display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT,
egl_devices[m_data->m_renderDevice], NULL);
//EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (eglGetError() == EGL_SUCCESS && display != EGL_NO_DISPLAY) {
int major = 0, minor = 0;
EGLBoolean initialized = eglInitialize(display, &major, &minor);
if (eglGetError() == EGL_SUCCESS && initialized == EGL_TRUE) {
m_data->egl_display = display;
}
}
if (!eglInitialize(m_data->egl_display, NULL, NULL)) {
fprintf(stderr, "Unable to initialize EGL\n");
exit(EXIT_FAILURE);
}
egl_version = gladLoaderLoadEGL(m_data->egl_display);
if (!egl_version) {
fprintf(stderr, "Unable to reload EGL.\n");
exit(EXIT_FAILURE);
}
printf("Loaded EGL %d.%d after reload.\n", GLAD_VERSION_MAJOR(egl_version),
GLAD_VERSION_MINOR(egl_version));
m_data->success = eglBindAPI(EGL_OPENGL_API);
if (!m_data->success) {
// TODO: Properly handle this error (requires change to default window
// API to change return on all window types to bool).
fprintf(stderr, "Failed to bind OpenGL API.\n");
exit(EXIT_FAILURE);
}
m_data->success =
eglChooseConfig(m_data->egl_display, egl_config_attribs,
&m_data->egl_config, 1, &m_data->num_configs);
if (!m_data->success) {
// TODO: Properly handle this error (requires change to default window
// API to change return on all window types to bool).
fprintf(stderr, "Failed to choose config (eglError: %d)\n", eglGetError());
exit(EXIT_FAILURE);
}
if (m_data->num_configs != 1) {
fprintf(stderr, "Didn't get exactly one config, but %d\n", m_data->num_configs);
exit(EXIT_FAILURE);
}
m_data->egl_surface = eglCreatePbufferSurface(
m_data->egl_display, m_data->egl_config, egl_pbuffer_attribs);
if (m_data->egl_surface == EGL_NO_SURFACE) {
fprintf(stderr, "Unable to create EGL surface (eglError: %d)\n", eglGetError());
exit(EXIT_FAILURE);
}
m_data->egl_context = eglCreateContext(
m_data->egl_display, m_data->egl_config, EGL_NO_CONTEXT, NULL);
if (!m_data->egl_context) {
fprintf(stderr, "Unable to create EGL context (eglError: %d)\n",eglGetError());
exit(EXIT_FAILURE);
}
m_data->success =
eglMakeCurrent(m_data->egl_display, m_data->egl_surface, m_data->egl_surface,
m_data->egl_context);
if (!m_data->success) {
fprintf(stderr, "Failed to make context current (eglError: %d)\n", eglGetError());
exit(EXIT_FAILURE);
}
if (!gladLoadGL(eglGetProcAddress)) {
fprintf(stderr, "failed to load GL with glad.\n");
exit(EXIT_FAILURE);
}
const GLubyte* ven = glGetString(GL_VENDOR);
printf("GL_VENDOR=%s\n", ven);
const GLubyte* ren = glGetString(GL_RENDERER);
printf("GL_RENDERER=%s\n", ren);
const GLubyte* ver = glGetString(GL_VERSION);
printf("GL_VERSION=%s\n", ver);
const GLubyte* sl = glGetString(GL_SHADING_LANGUAGE_VERSION);
printf("GL_SHADING_LANGUAGE_VERSION=%s\n", sl);
return 0;
}
Environment:
ssh connection to server.
server os: ubuntu18.
ldconfig -p | grep -i EGL
:
libwayland-egl.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libwayland-egl.so.1
libwayland-egl.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libwayland-egl.so
libnvidia-eglcore.so.470.141.03 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libnvidia-eglcore.so.470.141.03
libnvidia-eglcore.so.470.141.03 (libc6) => /usr/lib/i386-linux-gnu/libnvidia-eglcore.so.470.141.03
libEGL_nvidia.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libEGL_nvidia.so.0
libEGL_nvidia.so.0 (libc6) => /usr/lib/i386-linux-gnu/libEGL_nvidia.so.0
libEGL_mesa.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libEGL_mesa.so.0
libEGL.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libEGL.so.1
libEGL.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libEGL.so
glxinfo | grep "OpenGL"
:
OpenGL vendor string: NVIDIA Corporation
OpenGL renderer string: NVIDIA GeForce RTX 2080 Ti/PCIe/SSE2
OpenGL core profile version string: 4.6.0 NVIDIA 470.141.03
OpenGL core profile shading language version string: 4.60 NVIDIA
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL core profile extensions:
OpenGL version string: 4.6.0 NVIDIA 470.141.03
OpenGL shading language version string: 4.60 NVIDIA
OpenGL context flags: (none)
OpenGL profile mask: (none)
OpenGL extensions:
OpenGL ES profile version string: OpenGL ES 3.2 NVIDIA 470.141.03
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
OpenGL ES profile extensions:
I finally find out how to solve this. In short, add configuration file for nvidia driver to /usr/share/glvnd/egl_vendor.d
according to NVIDIA's libglvnd icd documentation.
Longer answer:
There are two vendor versions of libegl on my server(mesa and nvidia). The behavior of /usr/lib/x86_64-linux-gnu/libEGL.so
is nothing but consult glvnd to decide which version to use.
eglGetPlatformDisplayEXT
tries to render using gpu. Since the configuration file for nvidia is lost, glvnd can only find mesa to do the job but mesa libegl can only do software rendering, which is what the error msg "libEGL warning: Not allowed to force software rendering when API explicitly selects a hardware device error"
means I guess.
So just add configuration file to enable glvnd to find the libegl of nvidia solves this problem. I find the cause of the problem by using strace
to analyze the program as mentioned in here.
Note: I'm not familiar with opengl tech-stack and the information above is not guaranteed to be correct.