I did encounter the following problem when using GLEW with EGL/OpenGL/ROS on the JTX2 and could not find any helpful solution so far. As I’m quite new to working with the JTX2, it may well be that the solution might be easy and apparent. Nonetheless, help would be appreciated.
The relevant code involved is listed in the following.
display.cpp
#include "rebope/display.hpp"
#include <iostream>
namespace rebope {
Display::Display(int pbufferWidth, int pbufferHeight, const std::string& title) {
// Initialize EGL
eglDpy_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(eglDpy_ == EGL_NO_DISPLAY) {
std::cerr << "ERROR: EGL could not be initialized" << std::endl;
}
// Initialize an EGL display connection
// EGLint major and minor could be added
if (!eglInitialize(eglDpy_, 0, 0)) {
std::cerr << "ERROR: Could not start EGL display connection" << std::endl;
}
// Bind the API to OpenGL
eglBindAPI(EGL_OPENGL_API);
// Specify the required configuration attributes
EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_CONFORMANT, EGL_OPENGL_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_LUMINANCE_SIZE, 0,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 8,
EGL_LEVEL, 0,
EGL_BUFFER_SIZE, 24,
EGL_NONE
};
// Find a matching configuration
EGLint numCfg;
EGLConfig eglCfg;
if(eglChooseConfig(eglDpy_, configAttribs, &eglCfg, 1, &numCfg) != EGL_TRUE) {
std::cerr << "ERROR: Configuration selection failed" << std::endl;
}
// Specify buffer attributes
EGLint pbufferAttribs[] = {
EGL_WIDTH, pbufferWidth,
EGL_HEIGHT, pbufferHeight,
EGL_NONE
};
// Create a surface
eglSurf_ = eglCreatePbufferSurface(eglDpy_, eglCfg, pbufferAttribs);
if(eglSurf_ == EGL_NO_SURFACE) {
std::cerr << "ERROR: Surface could not be created" << std::endl;
}
// Create context and make it current
eglCtx_ = eglCreateContext(eglDpy_, eglCfg, EGL_NO_CONTEXT, NULL);
if(eglMakeCurrent(eglDpy_, eglSurf_, eglSurf_, eglCtx_) != EGL_TRUE) {
std::cerr << "ERROR: Display was not made current one" << std::endl;
}
// Initialize GLEW
GLenum err = glewInit();
if(err != GLEW_OK) {
std::cerr << "ERROR: GLEW failed to initialize: " << err << std::endl;
}
// Initialize CUDA/OpenGL devices
int deviceID = 0;
cudaSetDevice(deviceID);
cudaGLSetGLDevice(deviceID);
// Remove triangles without visual artifacts (for performance reasons)
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
// Bind buffer/Generate PBO
glGenBuffers(1,&glb::pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER,glb::pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, 4 * (pbufferWidth * pbufferHeight * sizeof(GLubyte)),NULL, GL_DYNAMIC_READ);
// Register buffer to CUDA memory
cudaGraphicsGLRegisterBuffer(&glb::pboRes, glb::pbo, cudaGraphicsRegisterFlagsReadOnly);
// Map to CUDA
cudaGraphicsMapResources(1, &glb::pboRes);
// Unbind buffer
glBindBuffer(GL_PIXEL_PACK_BUFFER,0);
// Obtain pointer
cudaGraphicsResourceGetMappedPointer(&glb::dptr, &glb::size, glb::pboRes);
}
void Display::clear(float r, float g, float b, float a) {
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Display::swapBuffer() {
// Note: eglSwapBuffers() has no effect on a PbufferSurface
if(eglSwapBuffers(eglDpy_,eglSurf_) != EGL_TRUE) {
std::cerr << "ERROR: Buffer swap failed" << std::endl;
}
}
Display::~Display() {
// Unmap and unregister the graphics resource
cudaGraphicsUnmapResources(1, &glb::pboRes);
cudaGraphicsUnregisterResource(glb::pboRes);
// Delete the PBO
glDeleteBuffers(1, &glb::pbo);
if(eglTerminate(eglDpy_) != EGL_TRUE) {
std::cout << "ERROR: Improper EGL termination" << std::endl;
}
}
}
display.hpp
#ifndef REBOPE_DISPLAY_H_
#define REBOPE_DISPLAY_H_
#include <EGL/egl.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include <cuda_runtime.h>
#include <cuda_gl_interop.h>
#include <string>
#include "rebope/global.hpp"
namespace rebope {
class Display {
public:
Display(int pbufferWidth, int pbufferHeight, const std::string& title);
void clear(float r, float g, float b, float a);
void swapBuffer();
virtual ~Display();
protected:
private:
void operator=(const Display& display) {}
Display(const Display& display) {}
// Private variables for rendering
EGLDisplay eglDpy_;
EGLSurface eglSurf_;
EGLContext eglCtx_;
};
}
#endif
Using this approach on a normal laptop with Ubuntu 16.04 works just fine. However, running the same part of the code on the JTX2 generates an error at…
// Initialize GLEW
GLenum err = glewInit();
if(err != GLEW_OK) {
std::cerr << "ERROR: GLEW failed to initialize: " << err << std::endl;
}
…with the error code “Missing GL version”. However, OpenGL should presumably already be available on the JTX2? Hence, I’m struggling to figure out the actual problem as well as an appropriate solution to fix it (even after an extended internet search). Suggestions would be very much appreciated!