Search code examples
openglxserveregl

Unable to use EGL without X Server on Ubuntu


I'd like to open the OpenGL context without X Server on Ubuntu 16.04. with the nvidia 390.48 driver. I am able to reproduce the results using the official documentation on https://devblogs.nvidia.com/egl-eye-opengl-visualization-without-x-server/ .

I now want to create a frame buffer object.

I have tried to use the following code adapted from https://github.com/parallel-forall/code-samples/blob/master/posts/egl_OpenGl_without_Xserver/tinyegl.cc

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#ifdef USE_EGL_GET_DISPLAY
#include <EGL/egl.h>
#else
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif

#ifdef USE_EGL_SURFACE
#include <GL/gl.h>
#else
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#endif

//ID for FBO and RBO
unsigned int FboID[1], RboID[1];

static const int pbufferWidth = 9, pbufferHeight = 9;

int main(int argc, char *argv[])
{

EGLDisplay display;
EGLContext context;

// 1. Initialize EGL
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
        fprintf(stderr, "Error! Failed to eglGetDisplay\n");
        return false;
}
EGLint major, minor;
EGLBoolean eglStatus = eglInitialize(display, &major, &minor);
if (eglStatus == EGL_FALSE) {
        fprintf(stderr, "Error! Failed to eglInitialize\n");
        return false;
}
fprintf(stderr, "EGL Version %d . %d\n", major, minor);

// 2. Choose config
static const EGLint configAttribs[] = {
        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_RED_SIZE, 8,
        EGL_DEPTH_SIZE, 8,
        EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
        EGL_NONE
};
EGLint numConfigs;
EGLConfig eglCfg;
eglStatus = eglChooseConfig(display, configAttribs, &eglCfg, 1, &numConfigs);
if (eglStatus == EGL_FALSE) {
        fprintf(stderr, "Error! Failed to eglChooseConfig\n");
        return false;
}
// 3. Create surface
const EGLint pbufferAttribs[] = {
        EGL_WIDTH, pbufferWidth,
        EGL_HEIGHT, pbufferHeight,
        EGL_NONE
};
EGLSurface surface = eglCreatePbufferSurface(display, eglCfg, pbufferAttribs);
if (surface == EGL_NO_SURFACE) {
        fprintf(stderr, "Error! Failed to eglCreatePbufferSurface\n");
        return false;
}
// 4. Bind API(OpenGL)
eglStatus = eglBindAPI(EGL_OPENGL_API);
if (eglStatus == EGL_FALSE) {
        fprintf(stderr, "Error! Failed to eglBindAPI\n");
        return false;
}
// 5.Create context and make it current
context = eglCreateContext(display, eglCfg, EGL_NO_CONTEXT, NULL);
if (context == EGL_NO_CONTEXT) {
        fprintf(stderr, "Error! Failed to eglCreateContext\n");
        return false;
}
eglStatus = eglMakeCurrent(display, surface, surface, context);
if (eglStatus == EGL_FALSE) {
        fprintf(stderr, "Error! Failed to eglMakeCurrent\n");
        return false;
}
// manually create the OpenGL buffers and textures: A  framebuffer object with associated
// texture and depth buffers.
// create a 2D texture as the color buffer
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D,  texId);
glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA8,  pbufferWidth, pbufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);    

// create a renderbuffer for storing the depth component
GLuint rbId;
glGenRenderbuffers(1, &rbId);
glBindRenderbuffer(GL_RENDERBUFFER, rbId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, pbufferWidth, pbufferHeight);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

// create the framebuffer and attach the texture (color buffer) and the renderbuffer (depth buffer)
GLuint fbId;
glGenFramebuffers(1, &fbId);
glBindFramebuffer(GL_FRAMEBUFFER, fbId);    

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbId);

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
            fprintf(stderr, "Error! status = %d\n", status);
}

eglTerminate(display);
return 0;
}

but it seems like the status of GL_FRAMEBUFFER does not turn to "complete"

Compile command:

g++ main.cc -lEGL  -lGL

Does any one have an idea to fix this or alternative method to create frame buffer object?


Solution

  • According to NVIDIA's blog, you need to link libOpenGL.so instead of libGL.so.

    g++ tinyegl.cc -o tinyegl -lEGL /usr/lib/nvidia-390/libOpenGL.so
    

    I'm not sure, but "-lOpenGL" is not working. So, need to use /usr/lib/{nvidia-driver-path}/libOpenGL.so