diff mbox

[Branch,~glmark2-dev/glmark2/trunk] Rev 257: Merge of lp:~glmark2-dev/glmark2/canvas-drm-rebranch

Message ID 20121218154518.12819.83747.launchpad@ackee.canonical.com
State Accepted
Headers show

Commit Message

Jesse Barker Dec. 18, 2012, 3:45 p.m. UTC
Merge authors:
  Jesse Barker (jesse-barker)
Related merge proposals:
  https://code.launchpad.net/~glmark2-dev/glmark2/canvas-drm-rebranch/+merge/138605
  proposed by: Jesse Barker (jesse-barker)
  review: Approve - Alexandros Frantzis (afrantzis)
  review: Resubmit - Jesse Barker (jesse-barker)
------------------------------------------------------------
revno: 257 [merge]
committer: Jesse Barker <jesse.barker@linaro.org>
branch nick: trunk
timestamp: Tue 2012-12-18 07:42:46 -0800
message:
  Merge of lp:~glmark2-dev/glmark2/canvas-drm-rebranch
  
  Adds CanvasDRM, which uses GBM and KMS APIs to manage surfaces and modesetting,
  respectively.  Allows glmark2 to run on a console and take over the framebuffer
  directly (no window/display manager).
added:
  src/canvas-drm.cpp
  src/canvas-drm.h
modified:
  INSTALL
  src/main.cpp
  src/wscript_build
  wscript


--
lp:glmark2
https://code.launchpad.net/~glmark2-dev/glmark2/trunk

You are subscribed to branch lp:glmark2.
To unsubscribe from this branch go to https://code.launchpad.net/~glmark2-dev/glmark2/trunk/+edit-subscription
diff mbox

Patch

=== modified file 'INSTALL'
--- INSTALL	2011-01-25 15:07:17 +0000
+++ INSTALL	2012-12-06 21:29:19 +0000
@@ -2,7 +2,7 @@ 
 
 To configure glmark2 use:
 
-$ ./waf configure [--enable-gl --enable-glesv2 --data-path=DATA_PATH --prefix=PREFIX]
+$ ./waf configure [--enable-gl --enable-glesv2 --enable-gl-drm --enable-glesv2-drm --data-path=DATA_PATH --prefix=PREFIX]
 
 To build use:
 

=== added file 'src/canvas-drm.cpp'
--- src/canvas-drm.cpp	1970-01-01 00:00:00 +0000
+++ src/canvas-drm.cpp	2012-12-17 22:48:52 +0000
@@ -0,0 +1,587 @@ 
+//
+// Copyright Š 2012 Linaro Limited
+//
+// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+//
+// glmark2 is free software: you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// glmark2.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Authors:
+//  Simon Que 
+//  Jesse Barker
+//
+#include "canvas-drm.h"
+#include "log.h"
+#include "options.h"
+#include "util.h"
+
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+
+#include <fstream>
+#include <sstream>
+#include <list>
+
+/******************
+ * Public methods *
+ ******************/
+
+bool
+CanvasDRM::reset()
+{
+    if (!reset_context())
+        return false;
+
+    if (!make_current())
+        return false;
+
+    if (!supports_gl2()) {
+        Log::error("Glmark2 needs OpenGL(ES) version >= 2.0 to run"
+                   " (but version string is: '%s')!\n",
+                   glGetString(GL_VERSION));
+        return false;
+    }
+
+    glViewport(0, 0, width_, height_);
+    glEnable(GL_DEPTH_TEST);
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_CULL_FACE);
+    glCullFace(GL_BACK);
+
+    clear();
+    egl_.swap();
+
+    if (!drm_.reset()) {
+        return false;
+    }
+
+    return true;
+}
+
+void
+DRMState::fb_destroy_callback(gbm_bo* bo, void* data)
+{
+    DRMFBState* fb = reinterpret_cast<DRMFBState*>(data);
+    if (fb && fb->fb_id) {
+        drmModeRmFB(fb->fd, fb->fb_id);
+    }
+    delete fb;
+    gbm_device* dev = gbm_bo_get_device(bo);
+    Log::debug("Got GBM device handle %p from buffer object\n", dev);
+}
+
+DRMFBState*
+DRMState::fb_get_from_bo(gbm_bo* bo)
+{
+    DRMFBState* fb = reinterpret_cast<DRMFBState*>(gbm_bo_get_user_data(bo));
+    if (fb) {
+        return fb;
+    }
+
+    unsigned int width = gbm_bo_get_width(bo);
+    unsigned int height = gbm_bo_get_height(bo);
+    unsigned int stride = gbm_bo_get_stride(bo);
+    unsigned int handle = gbm_bo_get_handle(bo).u32;
+    unsigned int fb_id(0);
+    int status = drmModeAddFB(fd_, width, height, 24, 32, stride, handle, &fb_id);
+    if (status < 0) {
+        Log::error("Failed to create FB: %d\n", status);
+        return 0;
+    }
+
+    fb = new DRMFBState();
+    fb->fd = fd_;
+    fb->bo = bo;
+    fb->fb_id = fb_id;
+
+    gbm_bo_set_user_data(bo, fb, fb_destroy_callback);
+    return fb;
+}
+
+bool
+DRMState::init_gbm()
+{
+    dev_ = gbm_create_device(fd_);
+    if (!dev_) {
+        Log::error("Failed to create GBM device\n");
+        return false;
+    }
+
+    surface_ = gbm_surface_create(dev_, mode_->hdisplay, mode_->vdisplay,
+                                  GBM_FORMAT_XRGB8888,
+                                  GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+    if (!surface_) {
+        Log::error("Failed to create GBM surface\n");
+        return false;
+    }
+
+    return true;
+}
+
+bool
+DRMState::init()
+{
+    // TODO: Replace this with something that explicitly probes for the loaded
+    // driver (udev?).
+    static const char* drm_modules[] = {
+        "i915",
+        "nouveau",
+        "radeon",
+        "vmgfx",
+        "omapdrm",
+        "exynos"
+    };
+
+    unsigned int num_modules(sizeof(drm_modules)/sizeof(drm_modules[0]));
+    for (unsigned int m = 0; m < num_modules; m++) {
+        fd_ = drmOpen(drm_modules[m], 0);
+        if (fd_ < 0) {
+            Log::debug("Failed to open DRM module '%s'\n", drm_modules[m]);
+            continue;
+        }
+        Log::debug("Opened DRM module '%s'\n", drm_modules[m]);
+        break;
+    }
+
+    if (fd_ < 0) {
+        Log::error("Failed to find a suitable DRM device\n");
+        return false;
+    }
+
+    resources_ = drmModeGetResources(fd_);
+    if (!resources_) {
+        Log::error("drmModeGetResources failed\n");
+        return false;
+    }
+
+    // Find a connected connector
+    for (int c = 0; c < resources_->count_connectors; c++) {
+        connector_ = drmModeGetConnector(fd_, resources_->connectors[c]);
+        if (DRM_MODE_CONNECTED == connector_->connection) {
+            break;
+        }
+        drmModeFreeConnector(connector_);
+        connector_ = 0;
+    }
+
+    if (!connector_) {
+        Log::error("Failed to find a suitable connector\n");
+        return false;
+    }
+
+    // Find the best resolution (we will always operate full-screen).
+    unsigned int bestArea(0);
+    for (int m = 0; m < connector_->count_modes; m++) {
+        drmModeModeInfo* curMode = &connector_->modes[m];
+        unsigned int curArea = curMode->hdisplay * curMode->vdisplay;
+        if (curArea > bestArea) {
+            mode_ = curMode;
+            bestArea = curArea;
+        }
+    }
+
+    if (!mode_) {
+        Log::error("Failed to find a suitable mode\n");
+        return false;
+    }
+
+    // Find a suitable encoder
+    for (int e = 0; e < resources_->count_encoders; e++) {
+        encoder_ = drmModeGetEncoder(fd_, resources_->encoders[e]);
+        if (encoder_ && encoder_->encoder_id == connector_->encoder_id) {
+            break;
+        }
+        drmModeFreeEncoder(encoder_);
+        encoder_ = 0;
+    }
+
+    if (!encoder_) {
+        Log::error("Failed to find a suitable encoder\n");
+        return false;
+    }
+
+    if (!init_gbm()) {
+        return false;
+    }
+
+    crtc_ = drmModeGetCrtc(fd_, encoder_->crtc_id);
+    if (!crtc_) {
+        Log::error("Failed to get current CRTC\n");
+        return false;
+    }
+
+    signal(SIGINT, &DRMState::quit_handler);
+
+    return true;
+}
+
+bool
+DRMState::reset()
+{
+    if (bo_) {
+        gbm_surface_release_buffer(surface_, bo_);
+    }
+
+    bo_ = gbm_surface_lock_front_buffer(surface_);
+    fb_ = fb_get_from_bo(bo_);
+
+    int status = drmModeSetCrtc(fd_, encoder_->crtc_id, fb_->fb_id, 0, 0,
+                                &connector_->connector_id, 1, mode_);
+    if (status < 0) {
+        Log::error("Failed to set CRTC: %d\n", status);
+        return false;
+    }
+
+    return true;
+}
+
+
+bool DRMState::should_quit_ = false;
+
+void
+DRMState::quit_handler(int signo)
+{
+    Log::debug("Got SIGINT (%d).\n", signo);
+    should_quit_ = true;
+}
+void
+DRMState::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
+{
+    unsigned int* waiting = reinterpret_cast<unsigned int*>(data);
+    *waiting = 0;
+    // Deal with unused parameters
+    static_cast<void>(fd);
+    static_cast<void>(frame);
+    static_cast<void>(sec);
+    static_cast<void>(usec);
+}
+
+void
+DRMState::do_flip()
+{
+    gbm_bo* next = gbm_surface_lock_front_buffer(surface_);
+    fb_ = fb_get_from_bo(next);
+    unsigned int waiting(1);
+    int status = drmModePageFlip(fd_, encoder_->crtc_id, fb_->fb_id,
+                                 DRM_MODE_PAGE_FLIP_EVENT, &waiting);
+    if (status < 0) {
+        Log::error("Failed to enqueue page flip: %d\n", status);
+        return;
+    }
+
+    fd_set fds;
+    FD_ZERO(&fds);
+    FD_SET(fd_, &fds);
+    drmEventContext evCtx;
+    evCtx.version = DRM_EVENT_CONTEXT_VERSION;
+    evCtx.page_flip_handler = page_flip_handler;
+
+    while (waiting) {
+        status = select(fd_ + 1, &fds, 0, 0, 0);
+        if (status < 0) {
+            // Most of the time, select() will return an error because the
+            // user pressed Ctrl-C.  So, only print out a message in debug
+            // mode, and just check for the likely condition and release
+            // the current buffer object before getting out.
+            Log::debug("Error in select\n");
+            if (should_quit()) {
+                gbm_surface_release_buffer(surface_, bo_);
+                bo_ = next;
+            }
+            return;
+        }
+        drmHandleEvent(fd_, &evCtx);
+    }
+
+    gbm_surface_release_buffer(surface_, bo_);
+    bo_ = next;
+}
+
+void
+DRMState::cleanup()
+{
+    // Restore CRTC state if necessary
+    if (crtc_) {
+        int status = drmModeSetCrtc(fd_, crtc_->crtc_id, crtc_->buffer_id,
+                                    crtc_->x, crtc_->y, &connector_->connector_id,
+                                    1, &crtc_->mode);
+        if (status < 0) {
+            Log::error("Failed to restore original CRTC: %d\n", status);
+        }
+        drmModeFreeCrtc(crtc_);
+        crtc_ = 0;
+    }
+    if (surface_) {
+        gbm_surface_destroy(surface_);
+        surface_ = 0;
+    }
+    if (dev_) {
+        gbm_device_destroy(dev_);
+        dev_ = 0;
+    }
+    if (connector_) {
+        drmModeFreeConnector(connector_);
+        connector_ = 0;
+    }
+    if (encoder_) {
+        drmModeFreeEncoder(encoder_);
+        encoder_ = 0;
+    }
+    if (resources_) {
+        drmModeFreeResources(resources_);
+        resources_ = 0;
+    }
+    if (fd_ > 0) {
+        drmClose(fd_);
+    }
+    fd_ = 0;
+    mode_ = 0;
+}
+
+bool
+CanvasDRM::init()
+{
+    Log::info("NOTE: The DRM canvas is still experimental and its behavior\n");
+    Log::info("      is subject to change as GBM and modesetting behavior\n");
+    Log::info("      evolves\n");
+
+    if (!drm_.init()) {
+        Log::error("Failed to initialize the DRM canvas\n");
+        drm_.cleanup();
+        return false;
+    }
+
+    width_ = drm_.mode_width();
+    height_ = drm_.mode_height();
+    resize_no_viewport(width_, height_);
+
+    if (!egl_.init_display(drm_.device(), visual_config_)) {
+        return false;
+    }
+    if (!egl_.init_surface(drm_.surface())) {
+        return false;
+    }
+    if (!egl_.valid()) {
+        return false;
+    }
+
+    return reset();
+}
+
+
+CanvasDRM::~CanvasDRM()
+{
+    drm_.cleanup();
+}
+
+void
+CanvasDRM::visible(bool /* visible */)
+{
+}
+
+void
+CanvasDRM::clear()
+{
+    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
+#if USE_GL
+    glClearDepth(1.0f);
+#elif USE_GLESv2
+    glClearDepthf(1.0f);
+#endif
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void
+CanvasDRM::update()
+{
+    Options::FrameEnd m = Options::frame_end;
+
+    if (m == Options::FrameEndDefault) {
+        if (offscreen_)
+            m = Options::FrameEndFinish;
+        else
+            m = Options::FrameEndSwap;
+    }
+
+    switch(m) {
+        case Options::FrameEndSwap:
+            swap_buffers();
+            break;
+        case Options::FrameEndFinish:
+            glFinish();
+            break;
+        case Options::FrameEndReadPixels:
+            read_pixel(width_ / 2, height_ / 2);
+            break;
+        case Options::FrameEndNone:
+        default:
+            break;
+    }
+}
+
+void
+CanvasDRM::print_info()
+{
+    make_current();
+
+    std::stringstream ss;
+    ss << "    OpenGL Information" << std::endl;
+    ss << "    GL_VENDOR:     " << glGetString(GL_VENDOR) << std::endl;
+    ss << "    GL_RENDERER:   " << glGetString(GL_RENDERER) << std::endl;
+    ss << "    GL_VERSION:    " << glGetString(GL_VERSION) << std::endl;
+    Log::info("%s", ss.str().c_str());
+}
+
+Canvas::Pixel
+CanvasDRM::read_pixel(int x, int y)
+{
+    uint8_t pixel[4];
+    glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
+    return Canvas::Pixel(pixel[0], pixel[1], pixel[2], pixel[3]);
+}
+
+void
+CanvasDRM::write_to_file(std::string &filename)
+{
+    char *pixels = new char[width_ * height_ * 4];
+
+    for (int i = 0; i < height_; i++) {
+        glReadPixels(0, i, width_, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+                     &pixels[(height_ - i - 1) * width_ * 4]);
+    }
+
+    std::ofstream output (filename.c_str(), std::ios::out | std::ios::binary);
+    output.write(pixels, 4 * width_ * height_);
+
+    delete [] pixels;
+}
+
+bool
+CanvasDRM::should_quit()
+{
+    return drm_.should_quit();
+}
+
+void
+CanvasDRM::resize(int width, int height)
+{
+    resize_no_viewport(width, height);
+    glViewport(0, 0, width_, height_);
+}
+
+/*********************
+ * Protected methods *
+ *********************/
+
+bool
+CanvasDRM::supports_gl2()
+{
+    std::string gl_version_str(
+        reinterpret_cast<const char*>(glGetString(GL_VERSION)));
+    int gl_major = 0;
+
+    size_t point_pos(gl_version_str.find('.'));
+
+    if (point_pos != std::string::npos) {
+        point_pos--;
+
+        size_t start_pos(gl_version_str.rfind(' ', point_pos));
+        if (start_pos == std::string::npos)
+            start_pos = 0;
+        else
+            start_pos++;
+
+        gl_major = Util::fromString<int>(
+                gl_version_str.substr(start_pos, point_pos - start_pos + 1)
+                );
+    }
+
+    return gl_major >= 2;
+}
+
+bool
+CanvasDRM::make_current()
+{
+    if (!egl_.valid()) {
+        Log::error("CanvasDRM: Invalid EGL state\n");
+        return false;
+    }
+
+    init_gl_extensions();
+
+    return true;
+}
+
+bool
+CanvasDRM::reset_context()
+{
+    return egl_.reset();
+}
+
+void
+CanvasDRM::swap_buffers()
+{
+    egl_.swap();
+    drm_.do_flip();
+}
+
+void
+CanvasDRM::init_gl_extensions()
+{
+#if USE_GLESv2
+    /*
+     * Parse the extensions we care about from the extension string.
+     * Don't even bother to get function pointers until we know the
+     * extension is present.
+     */
+    std::string extString;
+    const char* exts =
+        reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+    if (exts)
+        extString = exts;
+
+    if (extString.find("GL_OES_mapbuffer") != std::string::npos) {
+        GLExtensions::MapBuffer = reinterpret_cast<PFNGLMAPBUFFEROESPROC>(
+            eglGetProcAddress("glMapBufferOES"));
+        GLExtensions::UnmapBuffer = reinterpret_cast<PFNGLUNMAPBUFFEROESPROC>(
+            eglGetProcAddress("glUnmapBufferOES"));
+    }
+#elif USE_GL
+    GLExtensions::MapBuffer = glMapBuffer;
+    GLExtensions::UnmapBuffer = glUnmapBuffer;
+#endif
+}
+
+
+/*******************
+ * Private methods *
+ *******************/
+
+void
+CanvasDRM::resize_no_viewport(int width, int height)
+{
+    width_ = drm_.mode_width();
+    height_ = drm_.mode_height();
+
+    if (!width_)
+        width_ = width;
+    if (!height_)
+        height_ = height;
+
+    projection_ =
+        LibMatrix::Mat4::perspective(60.0, width_ / static_cast<float>(height_),
+                                     1.0, 1024.0);
+}

=== added file 'src/canvas-drm.h'
--- src/canvas-drm.h	1970-01-01 00:00:00 +0000
+++ src/canvas-drm.h	2012-12-17 19:11:54 +0000
@@ -0,0 +1,132 @@ 
+//
+// Copyright Š 2012 Linaro Limited
+//
+// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+//
+// glmark2 is free software: you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your option) any later
+// version.
+//
+// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// glmark2.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Authors:
+//  Simon Que 
+//  Jesse Barker
+//
+#ifndef GLMARK2_CANVAS_DRM_H_
+#define GLMARK2_CANVAS_DRM_H_
+
+#include <cstring>
+#include <gbm.h>
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "canvas.h"
+#include "egl-state.h"
+
+struct DRMFBState
+{
+    int fd;
+    gbm_bo* bo;
+    uint32_t fb_id;
+};
+
+class DRMState
+{
+    static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
+                                  unsigned int usec, void* data);
+    static void fb_destroy_callback(gbm_bo* bo, void* data);
+    static void quit_handler(int signum);
+    static bool should_quit_;
+    DRMFBState* fb_get_from_bo(gbm_bo* bo);
+    bool init_gbm();
+    int fd_;
+    drmModeRes* resources_;
+    drmModeConnector* connector_;
+    drmModeEncoder* encoder_;
+    drmModeCrtcPtr crtc_;
+    drmModeModeInfo* mode_;
+    gbm_device* dev_;
+    gbm_surface* surface_;
+    gbm_bo* bo_;
+    DRMFBState* fb_;
+
+public:
+    DRMState() :
+        fd_(0),
+        resources_(0),
+        connector_(0),
+        encoder_(0),
+        mode_(0),
+        dev_(0),
+        surface_(0),
+        bo_(0),
+        fb_(0) {}
+    ~DRMState() { cleanup(); }
+    void cleanup();
+    bool init();
+    bool reset();
+    void do_flip();
+    bool should_quit() const { return should_quit_; }
+    gbm_device* device() const { return dev_; }
+    gbm_surface* surface() const { return surface_; }
+    unsigned int mode_width() const
+    { 
+        if (mode_) {
+            return mode_->hdisplay;
+        }
+        return 0;
+    }
+    unsigned int mode_height() const
+    {
+        if (mode_) {
+            return mode_->vdisplay;
+        }
+        return 0;
+    }
+};
+
+/**
+ * Canvas for direct rendering with EGL.
+ */
+class CanvasDRM: public Canvas
+{
+public:
+    CanvasDRM(int width, int height) :
+        Canvas(width, height) {}
+    ~CanvasDRM();
+
+    virtual bool init();
+    virtual bool reset();
+    virtual void visible(bool visible);
+    virtual void clear();
+    virtual void update();
+    virtual void print_info();
+    virtual Pixel read_pixel(int x, int y);
+    virtual void write_to_file(std::string &filename);
+    virtual bool should_quit();
+    virtual void resize(int width, int height);
+
+protected:
+    virtual bool make_current();
+    virtual bool reset_context();
+    virtual void swap_buffers();
+    virtual bool supports_gl2();
+
+private:
+    DRMState drm_;
+    EGLState egl_;
+
+    void resize_no_viewport(int width, int height);
+    void init_gl_extensions();
+};
+
+#endif

=== modified file 'src/main.cpp'
--- src/main.cpp	2012-12-07 19:57:44 +0000
+++ src/main.cpp	2012-12-18 15:42:46 +0000
@@ -35,7 +35,9 @@ 
 #include <iostream>
 #include <fstream>
 
-#if USE_GL
+#if USE_DRM
+#include "canvas-drm.h"
+#elif USE_GL
 #include "canvas-x11-glx.h"
 #elif USE_GLESv2
 #include "canvas-x11-egl.h"
@@ -180,7 +182,9 @@ 
     }
 
     // Create the canvas
-#if USE_GL
+#if USE_DRM
+    CanvasDRM canvas(Options::size.first, Options::size.second);
+#elif USE_GL
     CanvasX11GLX canvas(Options::size.first, Options::size.second);
 #elif USE_GLESv2
     CanvasX11EGL canvas(Options::size.first, Options::size.second);

=== modified file 'src/wscript_build'
--- src/wscript_build	2012-11-13 16:53:41 +0000
+++ src/wscript_build	2012-12-06 21:29:19 +0000
@@ -4,6 +4,8 @@ 
                                             f.name.find('egl-') == -1]
 gl_sources = ['canvas-x11.cpp', 'canvas-x11-glx.cpp']
 glesv2_sources = ['canvas-x11.cpp', 'canvas-x11-egl.cpp', 'egl-state.cpp']
+gl_drm_sources = ['canvas-drm.cpp', 'egl-state.cpp']
+glesv2_drm_sources = ['canvas-drm.cpp', 'egl-state.cpp']
 libmatrix_sources = [f for f in bld.path.ant_glob('libmatrix/*.cc')
                      if not f.name.endswith('test.cc')]
 includes = ['.', 'scene-ideas', 'scene-terrain']
@@ -47,3 +49,44 @@ 
         includes     = includes,
         defines      = ['USE_GLESv2', 'USE_EXCEPTIONS']
         )
+
+if bld.env.USE_GL_DRM:
+    bld(
+        features = ['cxx', 'cxxstlib'],
+        source   = libmatrix_sources,
+        target   = 'matrix-drm',
+        lib      = ['m'],
+        includes = ['.'],
+        export_includes = 'libmatrix',
+        defines  = ['USE_DRM', '__GBM__', 'USE_GL', 'USE_EXCEPTIONS']
+        )
+    bld(
+        features     = ['cxx', 'cprogram'],
+        source       = common_sources + gl_drm_sources,
+        target       = 'glmark2-drm',
+        use          = ['egl', 'gl', 'matrix-drm', 'libpng12', 'drm', 'gbm'],
+        lib          = ['m', 'jpeg', 'dl'],
+        includes     = includes,
+        defines      = ['USE_DRM', '__GBM__', 'USE_GL']
+        )
+
+if bld.env.USE_GLESv2_DRM:
+    bld(
+        features = ['cxx', 'cxxstlib'],
+        source   = libmatrix_sources,
+        target   = 'matrix-es2-drm',
+        lib      = ['m'],
+        includes = ['.'],
+        export_includes = 'libmatrix',
+        defines  = ['USE_DRM', '__GBM__', 'USE_GLESv2', 'USE_EXCEPTIONS']
+        )
+    bld(
+        features     = ['cxx', 'cprogram'],
+        source       = common_sources + glesv2_drm_sources,
+        target       = 'glmark2-es2-drm',
+        use          = ['egl', 'glesv2', 'matrix-es2-drm', 'libpng12', 'drm',
+                        'gbm'],
+        lib          = ['m', 'jpeg', 'dl'],
+        includes     = includes,
+        defines      = ['USE_DRM', '__GBM__', 'USE_GLESv2']
+        )

=== modified file 'wscript'
--- wscript	2012-11-26 19:29:33 +0000
+++ wscript	2012-12-06 21:29:19 +0000
@@ -20,6 +20,11 @@ 
                    default = False, help='build using OpenGL 2.0')
     opt.add_option('--enable-glesv2', action='store_true', dest = 'glesv2',
                    default = False, help='build using OpenGL ES 2.0')
+    opt.add_option('--enable-gl-drm', action='store_true', dest = 'gl_drm',
+                   default = False, help='build using OpenGL 2.0 without X')
+    opt.add_option('--enable-glesv2-drm', action='store_true',
+                   dest = 'glesv2_drm',
+                   default = False, help='build using OpenGL ES 2.0 without X')
     opt.add_option('--no-debug', action='store_false', dest = 'debug',
                    default = True, help='disable compiler debug information')
     opt.add_option('--no-opt', action='store_false', dest = 'opt',
@@ -30,8 +35,10 @@ 
                    help='path to additional data (models, shaders, textures)')
 
 def configure(ctx):
-    if not Options.options.gl and not Options.options.glesv2:
-        ctx.fatal("You must configure using at least one of --enable-gl, --enable-glesv2")
+    if not Options.options.gl and not Options.options.glesv2 and \
+       not Options.options.gl_drm and not Options.options.glesv2_drm:
+        ctx.fatal("You must configure using at least one of --enable-gl, " +
+                  "--enable-glesv2, --enable-gl-drm, --enable-glesv2-drm")
 
     ctx.check_tool('gnu_dirs')
     ctx.check_tool('compiler_cc')
@@ -54,15 +61,22 @@ 
                       uselib = uselib, mandatory = True)
 
     # Check required packages
-    req_pkgs = [('x11', 'x11'), ('libpng12', 'libpng12')]
+    req_pkgs = [('libpng12', 'libpng12')]
     for (pkg, uselib) in req_pkgs:
         ctx.check_cfg(package = pkg, uselib_store = uselib,
                       args = '--cflags --libs', mandatory = True)
 
     # Check optional packages
-    opt_pkgs = [('gl', 'gl', Options.options.gl),
-                ('egl', 'egl', Options.options.glesv2),
-                ('glesv2', 'glesv2', Options.options.glesv2)]
+    opt_pkgs = [('x11', 'x11', Options.options.gl or Options.options.glesv2),
+                ('gl', 'gl', Options.options.gl or Options.options.gl_drm),
+                ('egl', 'egl', Options.options.glesv2 or
+                               Options.options.glesv2_drm),
+                ('glesv2', 'glesv2', Options.options.glesv2 or
+                                     Options.options.glesv2_drm),
+                ('libdrm','drm', Options.options.gl_drm or
+                                 Options.options.glesv2_drm),
+                ('gbm','gbm', Options.options.gl_drm or
+                              Options.options.glesv2_drm)]
     for (pkg, uselib, mandatory) in opt_pkgs:
         ctx.check_cfg(package = pkg, uselib_store = uselib,
                       args = '--cflags --libs', mandatory = mandatory)
@@ -94,6 +108,8 @@ 
 
     ctx.env.USE_GL = Options.options.gl
     ctx.env.USE_GLESv2 = Options.options.glesv2
+    ctx.env.USE_GL_DRM = Options.options.gl_drm
+    ctx.env.USE_GLESv2_DRM = Options.options.glesv2_drm
 
     ctx.msg("Prefix", ctx.env.PREFIX, color = 'PINK')
     ctx.msg("Data path", data_path, color = 'PINK')
@@ -101,9 +117,13 @@ 
             color = 'PINK');
     if ctx.env.HAVE_EXTRAS:
         ctx.msg("Extras path", Options.options.extras_path, color = 'PINK')
-    ctx.msg("Building GL2 version", "Yes" if ctx.env.USE_GL else "No",
-            color = 'PINK')
-    ctx.msg("Building GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No",
+    ctx.msg("Building X11 GL2 version", "Yes" if ctx.env.USE_GL else "No",
+            color = 'PINK')
+    ctx.msg("Building X11 GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No",
+            color = 'PINK')
+    ctx.msg("Building DRM GL2 version", "Yes" if ctx.env.USE_GL_DRM else "No",
+            color = 'PINK')
+    ctx.msg("Building DRM GLESv2 version", "Yes" if ctx.env.USE_GLESv2_DRM else "No",
             color = 'PINK')
 
 def build(ctx):