Linux DRM Entry Point#
/*!***************************************************************************
\File OpenGLESHelloAPI_LinuxDRM.cpp
\Title OpenGL ES 2.0 HelloAPI Tutorial
\Author PowerVR by Imagination, Developer Technology Team
\Copyright Copyright (c) Imagination Technologies Limited.
\Description Basic Tutorial that shows step-by-step how to initialise OpenGL ES 2.0, use it for drawing a triangle and terminate it.
Entry Point: main
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "OpenGLESHelloAPI.h"
#define DRIDEVNAME "/dev/dri/card0"
struct DRMVariables
{
unsigned int drmDisplayId;
int drmFile;
unsigned int drmCrtcId;
unsigned int drmConnectorId;
unsigned int drmEncoderId;
drmModeResPtr drmResources;
drmModeCrtcPtr drmCrtc;
drmModeEncoderPtr drmEncoder;
drmModeModeInfoPtr drmMode;
drmModeConnectorPtr drmConnector;
OpenGLESAPI helloAPI;
DRMVariables()
: drmDisplayId(0), drmFile(0), drmCrtcId(0), drmConnectorId(0), drmEncoderId(0), drmResources(NULL), drmCrtc(NULL), drmEncoder(NULL), drmMode(NULL), drmConnector(NULL)
{}
};
Helper function used in RenderScene.
struct SDrmFbWrapper
{
struct gbm_bo* psGbmBo;
unsigned int ui32FbId;
int i32Fd;
};
/*****************************************************************************
Helper Functions
*****************************************************************************/
static void pfnCallbackDrmFbDestroy(struct gbm_bo* bo, void* data)
{
struct SDrmFbWrapper* psFb = (struct SDrmFbWrapper*)data;
if (psFb->ui32FbId)
{
drmModeRmFB(psFb->i32Fd, psFb->ui32FbId);
}
delete psFb;
}
static void pfnCallbackDrmPageFlip(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
{
int* pi32WaitFlip = (int*)data;
*pi32WaitFlip = 0;
}
struct SDrmFbWrapper* DrmFbGetFromBo(DRMVariables& data, struct gbm_bo* bo)
{
struct SDrmFbWrapper* fb = (struct SDrmFbWrapper*)gbm_bo_get_user_data(bo);
uint32_t width, height, stride, handle;
int ret;
if (fb)
{
return fb;
}
fb = new struct SDrmFbWrapper;
fb->psGbmBo = bo;
fb->i32Fd = data.drmFile;
width = gbm_bo_get_width(bo);
height = gbm_bo_get_height(bo);
stride = gbm_bo_get_stride(bo);
handle = gbm_bo_get_handle(bo).u32;
ret = drmModeAddFB(data.drmFile, width, height, 24, 32, stride, handle, &fb->ui32FbId);
if (ret)
{
delete fb;
return NULL;
}
gbm_bo_set_user_data(bo, fb, pfnCallbackDrmFbDestroy);
return fb;
}
/*****************************************************************************
Application Functions
*****************************************************************************/
/*!***************************************************************************
\Function CreateNativeDisplay
\Output data Variables used for the windowing system
\Return Whether the function succeeded or not.
\Description Creates a native isplay for the application to render into.
*****************************************************************************/
bool CreateNativeDevice(DRMVariables& data)
{
/*
In the future it may be possible to get the drm device from udev.
By default just use card0.
*/
if ((data.drmFile = open(DRIDEVNAME, O_RDWR)) < 0)
{
printf("failed to open drm device %s : %s\n", DRIDEVNAME, strerror(errno));
return false;
}
data.drmResources = drmModeGetResources(data.drmFile);
if (!data.drmResources)
{
drmClose(data.drmFile);
printf("drmModeGetResources failed: %s\n", strerror(errno));
return false;
}
Find a connected connector.
unsigned int drmDisplayId = 0;
bool found = false;
for (int i = 0; i < data.drmResources->count_connectors; ++i)
{
data.drmConnector = drmModeGetConnector(data.drmFile, data.drmResources->connectors[i]);
if (data.drmConnector->connection != DRM_MODE_CONNECTED)
{
drmModeFreeConnector(data.drmConnector);
continue;
}
if (drmDisplayId == 0)
{
found = true;
break;
}
if (drmDisplayId == data.drmConnector->connector_id)
{
found = true;
break;
}
}
if (found == false)
{
drmModeFreeResources(data.drmResources);
drmClose(data.drmFile);
printf("No Connector found for requested device\n");
return false;
}
data.drmConnectorId = data.drmConnector->connector_id;
data.drmMode = &data.drmConnector->modes[0];
found = false;
for (int j = 0; j < data.drmResources->count_encoders; ++j)
{
data.drmEncoder = drmModeGetEncoder(data.drmFile, data.drmResources->encoders[j]);
if (data.drmEncoder->encoder_id == data.drmConnector->encoder_id)
{
found = true;
break;
}
drmModeFreeEncoder(data.drmEncoder);
}
if (!found)
{
drmModeFreeConnector(data.drmConnector);
drmModeFreeResources(data.drmResources);
drmClose(data.drmFile);
printf("No Encoder found for requested Connector\n");
return false;
}
data.drmEncoderId = data.drmEncoder->encoder_id;
data.drmCrtcId = data.drmEncoder->crtc_id;
for (int j = 0; j < data.drmResources->count_crtcs; ++j)
{
data.drmCrtc = drmModeGetCrtc(data.drmFile, data.drmResources->crtcs[j]);
if (data.drmCrtc->crtc_id == data.drmCrtcId)
{
break;
}
drmModeFreeCrtc(data.drmCrtc);
}
data.helloAPI._surfaceData.deviceContext = gbm_create_device(data.drmFile);
return true;
}
/*!***************************************************************************
\Function CreateNativeWindow
@Input data Variables used for the windowing system
\Return Whether the function succeeded or not.
\Description Creates a native window for the application to render into.
*****************************************************************************/
bool CreateNativeWindow(DRMVariables& data)
{
data.helloAPI._surfaceData.window =
gbm_surface_create(data.helloAPI._surfaceData.deviceContext, data.drmMode->hdisplay, data.drmMode->vdisplay, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
return true;
}
/*!***************************************************************************
\Function ReleaseWindowAndDisplay
@Input data Variables used for the windowing system
\Description Releases all resources allocated by the windowing system
*****************************************************************************/
void ReleaseNativeResources(DRMVariables& data)
{
gbm_surface_destroy(data.helloAPI._surfaceData.window);
gbm_device_destroy(data.helloAPI._surfaceData.deviceContext);
drmModeFreeCrtc(data.drmCrtc);
drmModeFreeEncoder(data.drmEncoder);
drmModeFreeConnector(data.drmConnector);
drmModeFreeResources(data.drmResources);
drmClose(data.drmFile);
}
/*!***************************************************************************
\Function main
@Input argc Number of arguments passed to the application, ignored.
@Input argv Command line strings passed to the application, ignored.
\Return Result code to send to the Operating System
\Description Main function of the program, executes other functions.
*****************************************************************************/
int main(int /*argc*/, char** /*argv*/)
{
Structure for the DRM variables.
DRMVariables data;
Get access to a native display.
CreateNativeDevice(data);
Setup the windowing system, create a window.
CreateNativeWindow(data);
data.helloAPI.initializeEGL();
data.helloAPI.initializeGLES();
Renders a triangle for 800 frames using the state setup in the previous function.
for (int i = 0; i < 800; ++i)
{
if (!data.helloAPI.drawFrame() || !data.helloAPI.swapEGLBuffers())
{
break;
}
Perform the flip.
struct gbm_bo* bo = gbm_surface_lock_front_buffer(data.helloAPI._surfaceData.window);
struct SDrmFbWrapper* fb = DrmFbGetFromBo(data, bo);
int ret = drmModeSetCrtc(data.drmFile, data.drmCrtcId, fb->ui32FbId, 0, 0, &data.drmConnectorId, 1, data.drmMode);
if (ret)
{
printf("display failed to set mode: %s\n", strerror(errno));
break;
}
}
data.helloAPI.releaseGLState();
data.helloAPI.releaseEGLState();
Release the windowing system resources.
ReleaseNativeResources(data);
Destroy the eglWindow.
return 0;
}