Reputation: 473
I want to use OpenGL rendering without X, with google i find it: http://dvdhrm.wordpress.com/2012/08/11/kmscon-linux-kmsdrm-based-virtual-console/ there says that it is possible. I should use DRM and EGL. EGL can create opengl context but requires a NativeWindow. DRM probably will provide me NativeWindow, is not it? Should i use KMS? I know that i must have open source video driver. I want exactly OpenGL context, but not OpenGL ES (Linux). Maybe, someone knows tutorial or example code?
Upvotes: 17
Views: 13816
Reputation: 956
First things first.
sudo chmod 666 /dev/dri/card0
is plain wrong. For so many reasons. Next part
sudo adduser $user video
is hidden evil. Although it might be better if you run a dedicated X server and have a connection on a second screen. But you say you not plan to use X server. Anyway, the idea is to isolate your GPU computations as much as possible.
If you do computing on GPU, why not try to use something specific? Like cuda
, or better openmp
?
The answer
You should use EXT_client_extensions, EXT_platform_base and EXT_device_enumeration from EGL
.
Pseudocode:
#include <egl>
if(b_egl_client_extensions != true) {
return FALSE;
}
fn_q_devices = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
fn_get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
if(b_device_platform_extensions != true) {
return FALSE;
}
if(0 == fn_q_devices(666, devices, &n_devices)){
return FALSE;
}
dpy = fn_get_platform_display(EGL_PLATFORM_DEVICE_EXT, devices[0], 0);
if(EGL_NO_DISPLAY == dpy){
return FALSE;
}
if(0 == eglInitialize(dpy, &egl_v_maj, &egl_v_min)){
return FALSE;
}
Upvotes: 0
Reputation: 324
I'm a bit late to the party, but you might want to give SRM (Simple Rendering Manager) a shot. It's a C library (I made) that abstracts away all the DRM/KMS complexities, so you can focus on the OpenGL ES 2.0 part of your application. Here's a basic example that simply changes the color of all connected displays with glClear():
#include <SRMCore.h>
#include <SRMDevice.h>
#include <SRMListener.h>
#include <SRMConnector.h>
#include <SRMConnectorMode.h>
#include <SRMBuffer.h>
#include <SRMList.h>
#include <SRMLog.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <math.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
float color = 0.f;
/* Opens a DRM device */
static int openRestricted(const char *path, int flags, void *userData)
{
SRM_UNUSED(userData);
// Here something like libseat could be used instead
return open(path, flags);
}
/* Closes a DRM device */
static void closeRestricted(int fd, void *userData)
{
SRM_UNUSED(userData);
close(fd);
}
static SRMInterface srmInterface =
{
.openRestricted = &openRestricted,
.closeRestricted = &closeRestricted
};
static void initializeGL(SRMConnector *connector, void *userData)
{
SRM_UNUSED(userData);
/* You must not do any drawing here as it won't make it to
* the screen. */
SRMConnectorMode *mode = srmConnectorGetCurrentMode(connector);
glViewport(0,
0,
srmConnectorModeGetWidth(mode),
srmConnectorModeGetHeight(mode));
// Schedule a repaint (this eventually calls paintGL() later, not directly)
srmConnectorRepaint(connector);
}
static void paintGL(SRMConnector *connector, void *userData)
{
SRM_UNUSED(userData);
glClearColor((sinf(color) + 1.f) / 2.f,
(sinf(color * 0.5f) + 1.f) / 2.f,
(sinf(color * 0.25f) + 1.f) / 2.f,
1.f);
color += 0.01f;
if (color > M_PI*4.f)
color = 0.f;
glClear(GL_COLOR_BUFFER_BIT);
srmConnectorRepaint(connector);
}
static void resizeGL(SRMConnector *connector, void *userData)
{
/* You must not do any drawing here as it won't make it to
* the screen.
* This is called when the connector changes its current mode,
* set with srmConnectorSetMode() */
// Reuse initializeGL() as it only sets the viewport
initializeGL(connector, userData);
}
static void pageFlipped(SRMConnector *connector, void *userData)
{
SRM_UNUSED(connector);
SRM_UNUSED(userData);
/* You must not do any drawing here as it won't make it to
* the screen.
* This is called when the last rendered frame is now being
* displayed on screen.
* Google v-sync for more info. */
}
static void uninitializeGL(SRMConnector *connector, void *userData)
{
SRM_UNUSED(connector);
SRM_UNUSED(userData);
/* You must not do any drawing here as it won't make it to
* the screen.
* Here you should free any resource created on initializeGL()
* like shaders, programs, textures, etc. */
}
static SRMConnectorInterface connectorInterface =
{
.initializeGL = &initializeGL,
.paintGL = &paintGL,
.resizeGL = &resizeGL,
.pageFlipped = &pageFlipped,
.uninitializeGL = &uninitializeGL
};
static void connectorPluggedEventHandler(SRMListener *listener, SRMConnector *connector)
{
SRM_UNUSED(listener);
/* This is called when a new connector is avaliable (E.g. Plugging an HDMI display). */
/* Got a new connector, let's render on it */
if (!srmConnectorInitialize(connector, &connectorInterface, NULL))
SRMError("[srm-basic] Failed to initialize connector %s.",
srmConnectorGetModel(connector));
}
static void connectorUnpluggedEventHandler(SRMListener *listener, SRMConnector *connector)
{
SRM_UNUSED(listener);
SRM_UNUSED(connector);
/* This is called when a connector is no longer avaliable (E.g. Unplugging an HDMI display). */
/* The connnector is automatically uninitialized after this event (if initialized)
* so calling srmConnectorUninitialize() is a no-op. */
}
int main(void)
{
setenv("SRM_DEBUG", "4", 1);
setenv("SRM_EGL_DEBUG", "4", 1);
SRMCore *core = srmCoreCreate(&srmInterface, NULL);
if (!core)
{
SRMFatal("[srm-basic] Failed to initialize SRM core.");
return 1;
}
// Subscribe to Udev events
SRMListener *connectorPluggedEventListener = srmCoreAddConnectorPluggedEventListener(core, &connectorPluggedEventHandler, NULL);
SRMListener *connectorUnpluggedEventListener = srmCoreAddConnectorUnpluggedEventListener(core, &connectorUnpluggedEventHandler, NULL);
// Find and initialize avaliable connectors
// Loop each GPU (device)
SRMListForeach (deviceIt, srmCoreGetDevices(core))
{
SRMDevice *device = srmListItemGetData(deviceIt);
// Loop each GPU connector (screen)
SRMListForeach (connectorIt, srmDeviceGetConnectors(device))
{
SRMConnector *connector = srmListItemGetData(connectorIt);
if (srmConnectorIsConnected(connector))
{
if (!srmConnectorInitialize(connector, &connectorInterface, NULL))
SRMError("[srm-basic] Failed to initialize connector %s.",
srmConnectorGetModel(connector));
}
}
}
while (1)
{
/* Udev monitor poll DRM devices/connectors hotplugging events (-1 disables timeout).
* To get a pollable FD use srmCoreGetMonitorFD() */
if (srmCoreProccessMonitor(core, -1) < 0)
break;
}
/* Unsubscribe to DRM events
*
* These listeners are automatically destroyed when calling srmCoreDestroy()
* so there is no need to free them manually.
* This is here just to show how to unsubscribe to events on the fly. */
srmListenerDestroy(connectorPluggedEventListener);
srmListenerDestroy(connectorUnpluggedEventListener);
// Finish SRM
srmCoreDestroy(core);
return 0;
}
Additionally, it offers several other features, including the handy ability for automatic texture sharing across GPUs from a single allocation.
Upvotes: 1
Reputation: 1632
Yes, you need kms stack (example). Here is a simple example under linux, it use OpenGL es, But the step to have it working against OpenGL api are simple.
In the egl attribs set EGL_RENRERABLE_TYPE
to EGL_OPENGL_BIT
And tell egl which api to bind to:
eglBindAPI(EGL_OPENGL_API);
Be sure to have latest kernel drivers and mesa-dev
, libdrm-dev
, libgbm-dev
. This pieces of code is portable on android, it's just not so easy to have default android graphic stack silenced.
note: I had trouble with 32bit version, but still don't know why. those libs are actively developed, so not sure it wasn't a bug.
*note2: depending on your GLSL version, float precision is supported or not.
precision mediump float;
note3: if you have permision failure with /dev/dri/card0
, grant it with:
sudo chmod 666 /dev/dri/card0
or add current user to video
group with
sudo adduser $user video
you may also setguid for your executable with group set to video. (maybe best option)
Upvotes: 24