How to Run an Opengl Application Installed on a Linux MAChine from My Windows MAChine

How can I run an OpenGL application installed on a linux machine from my windows machine?

Solution

I installed two pieces of software:

PuTTY

XMing-mesa The mesa part is important.

PuTTY configuration

Connection->Seconds Between Keepalives: 30
Connection->Enable TCP Keepalives: Yes

Connection->SSH->X11->Enable X11 forwarding: Yes
Connection->SSH->X11->X display location: localhost:0:0

Lauching

Run Xming which will put simply start a process and put an icon in your system tray.
Launch putty, pointing to your linux box, with the above configuration.
Run program

Hopefully, Success!

How to use OpenGL without a window manager in Linux?

You don't have to install Gnome or KDE. These are used to managed windows, and you can launch graphical applications without having a window manager.

Therefore, you'll have to install a X server. The X server is responsible of drawing things on your screen. Without X server, you can't launch graphical applications.

Once X has been installed, launch it, export your DISPLAY environment variable, and the rest is like writing an OpenGL application which runs full screen :-)

Force existing OpenGL application to render offscreen on a headless machine

Use Xvfb for your X server. The installation of Mesa deployed on any modern Linux distribution should automatically fall back to software rasterization if no supported GPU is found. You can take screenshots with any X11 screen grabber program; heck even ffmpeg -i x11grab will work.

OpenGL Without GUI


Is it possible to compile a program that uses the OpenGL libraries or directly uses the GPU driver to draw to the screen?

Yes. With the EGL API this has been formalized and works most well with NVidia GPUs and their proprietary drivers. NVidia has it described on their dev blog here https://devblogs.nvidia.com/egl-eye-opengl-visualization-without-x-server/

Essentially the steps are:

Create a OpenGL context for a PBuffer

#include <EGL/egl.h>

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
};

static const int pbufferWidth = 9;
static const int pbufferHeight = 9;

static const EGLint pbufferAttribs[] = {
EGL_WIDTH, pbufferWidth,
EGL_HEIGHT, pbufferHeight,
EGL_NONE,
};

int main(int argc, char *argv[])
{
// 1. Initialize EGL
EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);

EGLint major, minor;

eglInitialize(eglDpy, &major, &minor);

// 2. Select an appropriate configuration
EGLint numConfigs;
EGLConfig eglCfg;

eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs);

// 3. Create a surface
EGLSurface eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg,
pbufferAttribs);

// 4. Bind the API
eglBindAPI(EGL_OPENGL_API);

// 5. Create a context and make it current
EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT,
NULL);

eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx);

// from now on use your OpenGL context

// 6. Terminate EGL when finished
eglTerminate(eglDpy);
return 0;
}

and then go about the rest as per usual. Or you can even ditch the PBuffer completely and just use OpenGL manages resources, i.e. render to framebuffer objects. For that end you can omit creating the surface and just make the context current.

Here's an example for using EGL without display, no EGL surface, with OpenGL managed framebuffer.

#include <GL/glew.h>
#include <GL/glut.h>
#include <EGL/egl.h>

#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <math.h>
#include <stdio.h>

using namespace std;

namespace render
{
int width, height;
float aspect;

void init();
void display();

int const fbo_width = 512;
int const fbo_height = 512;

GLuint fb, color, depth;

void *dumpbuf;
int dumpbuf_fd;
};

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
};

int main(int argc, char *argv[])
{
// 1. Initialize EGL
EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);

EGLint major, minor;
eglInitialize(eglDpy, &major, &minor);

// 2. Select an appropriate configuration
EGLint numConfigs;
EGLConfig eglCfg;

eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs);

// 3. Bind the API
eglBindAPI(EGL_OPENGL_API);

// 3. Create a context and make it current
EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT,
NULL);

eglMakeCurrent(eglDpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglCtx);

glewInit();
// from now on use your OpenGL context
render::init();
render::display();

// 4. Terminate EGL when finished
eglTerminate(eglDpy);
return 0;
}

void CHECK_FRAMEBUFFER_STATUS()
{
GLenum status;
status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
switch(status) {
case GL_FRAMEBUFFER_COMPLETE:
break;

case GL_FRAMEBUFFER_UNSUPPORTED:
/* choose different formats */
break;

default:
/* programming error; will fail on all hardware */
throw "Framebuffer Error";
}
}

namespace render
{
float const light_dir[]={1,1,1,0};
float const light_color[]={1,0.95,0.9,1};

void init()
{
glGenFramebuffers(1, &fb);
glGenTextures(1, &color);
glGenRenderbuffers(1, &depth);

glBindFramebuffer(GL_FRAMEBUFFER, fb);

glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D( GL_TEXTURE_2D,
0,
GL_RGB8,
fbo_width, fbo_height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
NULL);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);

glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbo_width, fbo_height);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);

GLint red_bits, green_bits, blue_bits, alpha_bits;

glGetIntegerv(GL_RED_BITS, &red_bits);
glGetIntegerv(GL_GREEN_BITS, &green_bits);
glGetIntegerv(GL_BLUE_BITS, &blue_bits);
glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);

fprintf(stderr, "FBO format R%dG%dB%dA%d\n",
(int)red_bits,
(int)green_bits,
(int)blue_bits,
(int)alpha_bits );

CHECK_FRAMEBUFFER_STATUS();

dumpbuf_fd = open("/tmp/fbodump.rgb", O_CREAT|O_SYNC|O_RDWR, S_IRUSR|S_IWUSR);
assert(-1 != dumpbuf_fd);
dumpbuf = malloc(fbo_width*fbo_height*3);
assert(dumpbuf);
}

void render()
{
static float a=0, b=0, c=0;

glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, fb);

glViewport(0,0,fbo_width, fbo_height);

glClearColor(0,0,0,0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1, 1, -1, 1, -1, 1);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glBegin(GL_TRIANGLES);
glColor3f(1,0,0);
glVertex3f(1,0,0);

glColor3f(0,1,0);
glVertex3f(0,1,0);

glColor3f(0,0,1);
glVertex3f(0,0,1);
glEnd();

glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0,0,fbo_width,fbo_height,GL_RGB,GL_UNSIGNED_BYTE,dumpbuf);
lseek(dumpbuf_fd, SEEK_SET, 0);
write(dumpbuf_fd, dumpbuf, fbo_width*fbo_height*3);
}
}


Related Topics



Leave a reply



Submit